1;;; mh-scan.el --- MH-E scan line constants and utilities 2 3;; Copyright (C) 1993, 1995, 1997, 4;; 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. 5 6;; Author: Bill Wohler <wohler@newt.com> 7;; Maintainer: Bill Wohler <wohler@newt.com> 8;; Keywords: mail 9;; See: mh-e.el 10 11;; This file is part of GNU Emacs. 12 13;; GNU Emacs is free software; you can redistribute it and/or modify 14;; it under the terms of the GNU General Public License as published by 15;; the Free Software Foundation; either version 2, or (at your option) 16;; any later version. 17 18;; GNU Emacs is distributed in the hope that it will be useful, 19;; but WITHOUT ANY WARRANTY; without even the implied warranty of 20;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21;; GNU General Public License for more details. 22 23;; You should have received a copy of the GNU General Public License 24;; along with GNU Emacs; see the file COPYING. If not, write to the 25;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 26;; Boston, MA 02110-1301, USA. 27 28;;; Commentary: 29 30;; This file contains constants and a few functions for interpreting 31;; scan lines. 32 33;;; Change Log: 34 35;;; Code: 36 37(require 'mh-e) 38 39 40 41;;; Scan Formats 42 43;; The following scan formats are passed to the scan program if the setting of 44;; `mh-scan-format-file' is t. They are identical except the later one makes 45;; use of the nmh `decode' function to decode RFC 2047 encodings. If you just 46;; want to change the column of the notations, use the `mh-set-cmd-note' 47;; function. 48 49(defvar mh-scan-format-mh 50 (concat 51 "%4(msg)" 52 "%<(cur)+%| %>" 53 "%<{replied}-" 54 "%?(nonnull(comp{to}))%<(mymbox{to})t%>" 55 "%?(nonnull(comp{cc}))%<(mymbox{cc})c%>" 56 "%?(nonnull(comp{bcc}))%<(mymbox{bcc})b%>" 57 "%?(nonnull(comp{newsgroups}))n%>" 58 "%<(zero) %>" 59 "%02(mon{date})/%02(mday{date})%<{date} %|*%>" 60 "%<(mymbox{from})%<{to}To:%14(friendly{to})%>%>" 61 "%<(zero)%17(friendly{from})%> " 62 "%{subject}%<{body}<<%{body}%>") 63 "*Scan format string for MH. 64This string is passed to the scan program via the -format 65argument. This format is identical to the default except that 66additional hints for fontification have been added to the fifth 67column (remember that in Emacs, the first column is 0). 68 69The values of the fifth column, in priority order, are: \"-\" if 70the message has been replied to, t if an address on the To: line 71matches one of the mailboxes of the current user, \"c\" if the Cc: 72line matches, \"b\" if the Bcc: line matches, and \"n\" if a 73non-empty Newsgroups: header is present.") 74 75(defvar mh-scan-format-nmh 76 (concat 77 "%4(msg)" 78 "%<(cur)+%| %>" 79 "%<{replied}-" 80 "%?(nonnull(comp{to}))%<(mymbox{to})t%>" 81 "%?(nonnull(comp{cc}))%<(mymbox{cc})c%>" 82 "%?(nonnull(comp{bcc}))%<(mymbox{bcc})b%>" 83 "%?(nonnull(comp{newsgroups}))n%>" 84 "%<(zero) %>" 85 "%02(mon{date})/%02(mday{date})%<{date} %|*%>" 86 "%<(mymbox{from})%<{to}To:%14(decode(friendly{to}))%>%>" 87 "%<(zero)%17(decode(friendly{from}))%> " 88 "%(decode{subject})%<{body}<<%{body}%>") 89 "*Scan format string for nmh. 90This string is passed to the scan program via the -format arg. 91This format is identical to the default except that additional 92hints for fontification have been added to the fifth 93column (remember that in Emacs, the first column is 0). 94 95The values of the fifth column, in priority order, are: \"-\" if 96the message has been replied to, t if an address on the To: field 97matches one of the mailboxes of the current user, \"c\" if the Cc: 98field matches, \"b\" if the Bcc: field matches, and \"n\" if a 99non-empty Newsgroups: field is present.") 100 101 102 103;;; Regular Expressions 104 105;; Alphabetical. 106 107(defvar mh-scan-body-regexp "\\(<<\\([^\n]+\\)?\\)" 108 "This regular expression matches the message body fragment. 109 110Note that the default setting of `mh-folder-font-lock-keywords' 111expects this expression to contain at least one parenthesized 112expression which matches the body text as in the default of 113\"\\\\(<<\\\\([^\\n]+\\\\)?\\\\)\". If this regular expression is 114not correct, the body fragment will not be highlighted with the 115face `mh-folder-body'.") 116 117(defvar mh-scan-cur-msg-number-regexp "^\\( *[0-9]+\\+\\).*" 118 "This regular expression matches the current message. 119 120It must match from the beginning of the line. Note that the 121default setting of `mh-folder-font-lock-keywords' expects this 122expression to contain at least one parenthesized expression which 123matches the message number as in the default of 124 125 \"^\\\\( *[0-9]+\\\\+\\\\).*\". 126 127This expression includes the leading space and current message 128marker \"+\" within the parenthesis since it looks better to 129highlight these items as well. The highlighting is done with the 130face `mh-folder-cur-msg-number'. This regular expression should 131be correct as it is needed by non-fontification functions. See 132also `mh-note-cur'.") 133 134(defvar mh-scan-date-regexp "\\([0-9][0-9]/[0-9][0-9]\\)" 135 "This regular expression matches a valid date. 136 137It must not be anchored to the beginning or the end of the line. 138Note that the default setting of `mh-folder-font-lock-keywords' 139expects this expression to contain only one parenthesized 140expression which matches the date field as in the default of 141\"\\\\([0-9][0-9]/[0-9][0-9]\\\\)\"}. If this regular expression 142is not correct, the date will not be highlighted with the face 143`mh-folder-date'.") 144 145(defvar mh-scan-deleted-msg-regexp "^\\( *[0-9]+\\)D" 146 "This regular expression matches deleted messages. 147 148It must match from the beginning of the line. Note that the 149default setting of `mh-folder-font-lock-keywords' expects this 150expression to contain at least one parenthesized expression which 151matches the message number as in the default of 152 153 \"^\\\\( *[0-9]+\\\\)D\". 154 155This expression includes the leading space within the parenthesis 156since it looks better to highlight it as well. The highlighting 157is done with the face `mh-folder-deleted'. This regular 158expression should be correct as it is needed by non-fontification 159functions. See also `mh-note-deleted'.") 160 161(defvar mh-scan-good-msg-regexp "^\\( *[0-9]+\\)[^D^0-9]" 162 "This regular expression matches \"good\" messages. 163 164It must match from the beginning of the line. Note that the 165default setting of `mh-folder-font-lock-keywords' expects this 166expression to contain at least one parenthesized expression which 167matches the message number as in the default of 168 169 \"^\\\\( *[0-9]+\\\\)[^D^0-9]\". 170 171This expression includes the leading space within the parenthesis 172since it looks better to highlight it as well. The highlighting 173is done with the face `mh-folder-msg-number'. This regular 174expression should be correct as it is needed by non-fontification 175functions.") 176 177(defvar mh-scan-msg-format-regexp "%\\([0-9]*\\)(msg)" 178 "This regular expression finds the message number width in a scan format. 179 180Note that the message number must be placed in a parenthesized 181expression as in the default of \"%\\\\([0-9]*\\\\)(msg)\". This 182variable is only consulted if `mh-scan-format-file' is set to 183\"Use MH-E scan Format\".") 184 185(defvar mh-scan-msg-format-string "%d" 186 "This is a format string for width of the message number in a scan format. 187 188Use \"0%d\" for zero-filled message numbers. This variable is only 189consulted if `mh-scan-format-file' is set to \"Use MH-E scan 190Format\".") 191 192(defvar mh-scan-msg-number-regexp "^ *\\([0-9]+\\)" 193 "This regular expression extracts the message number. 194 195It must match from the beginning of the line. Note that the 196message number must be placed in a parenthesized expression as in 197the default of \"^ *\\\\([0-9]+\\\\)\".") 198 199(defvar mh-scan-msg-overflow-regexp "^[?0-9][0-9]" 200 "This regular expression matches overflowed message numbers.") 201 202(defvar mh-scan-msg-search-regexp "^[^0-9]*%d[^0-9]" 203 "This regular expression matches a particular message. 204 205It is a format string; use \"%d\" to represent the location of the 206message number within the expression as in the default of 207\"^[^0-9]*%d[^0-9]\".") 208 209(defvar mh-scan-rcpt-regexp "\\(To:\\)\\(..............\\)" 210 "This regular expression specifies the recipient in messages you sent. 211 212Note that the default setting of `mh-folder-font-lock-keywords' 213expects this expression to contain two parenthesized expressions. 214The first is expected to match the \"To:\" that the default scan 215format file generates. The second is expected to match the 216recipient's name as in the default of 217\"\\\\(To:\\\\)\\\\(..............\\\\)\". If this regular 218expression is not correct, the \"To:\" string will not be 219highlighted with the face `mh-folder-to' and the recipient will 220not be highlighted with the face `mh-folder-address'") 221 222(defvar mh-scan-refiled-msg-regexp "^\\( *[0-9]+\\)\\^" 223 "This regular expression matches refiled messages. 224 225It must match from the beginning of the line. Note that the 226default setting of `mh-folder-font-lock-keywords' expects this 227expression to contain at least one parenthesized expression which 228matches the message number as in the default of 229 230 \"^\\\\( *[0-9]+\\\\)\\\\^\". 231 232This expression includes the leading space within the parenthesis 233since it looks better to highlight it as well. The highlighting 234is done with the face `mh-folder-refiled'. This regular 235expression should be correct as it is needed by non-fontification 236functions. See also `mh-note-refiled'.") 237 238(defvar mh-scan-sent-to-me-sender-regexp 239 "^ *[0-9]+.\\([bct]\\).....[ ]*\\(..................\\)" 240 "This regular expression matches messages sent to us. 241 242Note that the default setting of `mh-folder-font-lock-keywords' 243expects this expression to contain at least two parenthesized 244expressions. The first should match the fontification hint (see 245`mh-scan-format-nmh') and the second should match the user name 246as in the default of 247 248 ^ *[0-9]+.\\\\([bct]\\\\).....[ ]*\\\\(..................\\\\) 249 250If this regular expression is not correct, the notation hints 251will not be highlighted with the face 252`mh-mh-folder-sent-to-me-hint' and the sender will not be 253highlighted with the face `mh-folder-sent-to-me-sender'.") 254 255(defvar mh-scan-subject-regexp 256 "^ *[0-9]+........[ ]*...................\\([Rr][Ee]\\(\\[[0-9]+\\]\\)?:\\s-*\\)*\\([^<\n]*\\)" 257 "This regular expression matches the subject. 258 259It must match from the beginning of the line. Note that the 260default setting of `mh-folder-font-lock-keywords' expects this 261expression to contain at least three parenthesized expressions. 262The first is expected to match the \"Re:\" string, if any, and is 263highlighted with the face `mh-folder-followup'. The second 264matches an optional bracketed number after \"Re:\", such as in 265\"Re[2]:\" (and is thus a sub-expression of the first expression) 266and the third is expected to match the subject line itself which 267is highlighted with the face `mh-folder-subject'. For example, 268the default (broken on multiple lines for readability) is 269 270 ^ *[0-9]+........[ ]*................... 271 \\\\([Rr][Ee]\\\\(\\\\\\=[[0-9]+\\\\]\\\\)?:\\\\s-*\\\\)* 272 \\\\([^<\\n]*\\\\) 273 274This regular expression should be correct as it is needed by 275non-fontification functions.") 276 277(defvar mh-scan-valid-regexp "^ *[0-9]" 278 "This regular expression describes a valid scan line. 279 280This is used to eliminate error messages that are occasionally 281produced by \"inc\".") 282 283 284 285;;; Widths, Offsets and Columns 286 287(defvar mh-cmd-note 4 288 "Column for notations. 289 290This variable should be set with the function `mh-set-cmd-note'. 291This variable may be updated dynamically if 292`mh-adaptive-cmd-note-flag' is on. 293 294Note that columns in Emacs start with 0.") 295(make-variable-buffer-local 'mh-cmd-note) 296 297(defvar mh-scan-cmd-note-width 1 298 "Number of columns consumed by the cmd-note field in `mh-scan-format'. 299 300This column will have one of the values: \" \", \"D\", \"^\", \"+\" and 301where \" \" is the default value, 302 303 \"D\" is the `mh-note-deleted' character, 304 \"^\" is the `mh-note-refiled' character, and 305 \"+\" is the `mh-note-cur' character.") 306 307(defvar mh-scan-destination-width 1 308 "Number of columns consumed by the destination field in `mh-scan-format'. 309 310This column will have one of \" \", \"%\", \"-\", \"t\", \"c\", \"b\", or \"n\" 311in it. 312 313 \" \" blank space is the default character. 314 \"%\" indicates that the message in in a named MH sequence. 315 \"-\" indicates that the message has been annotated with a replied field. 316 \"t\" indicates that the message contains mymbox in the To: field. 317 \"c\" indicates that the message contains mymbox in the Cc: field. 318 \"b\" indicates that the message contains mymbox in the Bcc: field. 319 \"n\" indicates that the message contains a Newsgroups: field.") 320 321(defvar mh-scan-date-width 5 322 "Number of columns consumed by the date field in `mh-scan-format'. 323This column will typically be of the form mm/dd.") 324 325(defvar mh-scan-date-flag-width 1 326 "Number of columns consumed to flag (in)valid dates in `mh-scan-format'. 327This column will have \" \" for valid and \"*\" for invalid or 328missing dates.") 329 330(defvar mh-scan-from-mbox-width 17 331 "Number of columns consumed with the \"From:\" line in `mh-scan-format'. 332This column will have a friendly name or e-mail address of the 333originator, or a \"To: address\" for outgoing e-mail messages.") 334 335(defvar mh-scan-from-mbox-sep-width 2 336 "Number of columns consumed by whitespace after from-mbox in `mh-scan-format'. 337This column will only ever have spaces in it.") 338 339(defvar mh-scan-field-destination-offset 340 (+ mh-scan-cmd-note-width) 341 "The offset from the `mh-cmd-note' for the destination column.") 342 343(defvar mh-scan-field-from-start-offset 344 (+ mh-scan-cmd-note-width 345 mh-scan-destination-width 346 mh-scan-date-width 347 mh-scan-date-flag-width) 348 "The offset from the `mh-cmd-note' to find the start of \"From:\" address.") 349 350(defvar mh-scan-field-from-end-offset 351 (+ mh-scan-field-from-start-offset mh-scan-from-mbox-width) 352 "The offset from the `mh-cmd-note' to find the end of \"From:\" address.") 353 354(defvar mh-scan-field-subject-start-offset 355 (+ mh-scan-cmd-note-width 356 mh-scan-destination-width 357 mh-scan-date-width 358 mh-scan-date-flag-width 359 mh-scan-from-mbox-width 360 mh-scan-from-mbox-sep-width) 361 "The offset from the `mh-cmd-note' to find the start of the subject.") 362 363 364 365;;; Notation 366 367;; Alphabetical. 368 369(defvar mh-note-cur ?+ 370 "The current message (in MH, not in MH-E) is marked by this character. 371See also `mh-scan-cur-msg-number-regexp'.") 372 373(defvar mh-note-copied ?C 374 "Messages that have been copied are marked by this character.") 375 376(defvar mh-note-deleted ?D 377 "Messages that have been deleted are marked by this character. 378See also `mh-scan-deleted-msg-regexp'.") 379 380(defvar mh-note-dist ?R 381 "Messages that have been redistributed are marked by this character.") 382 383(defvar mh-note-forw ?F 384 "Messages that have been forwarded are marked by this character.") 385 386(defvar mh-note-printed ?P 387 "Messages that have been printed are marked by this character.") 388 389(defvar mh-note-refiled ?^ 390 "Messages that have been refiled are marked by this character. 391See also `mh-scan-refiled-msg-regexp'.") 392 393(defvar mh-note-repl ?- 394 "Messages that have been replied to are marked by this character.") 395 396(defvar mh-note-seq ?% 397 "Messages in a user-defined sequence are marked by this character. 398 399Messages in the \"search\" sequence are marked by this character as 400well.") 401 402 403 404;;; Utilities 405 406;;;###mh-autoload 407(defun mh-scan-msg-number-regexp () 408 "Return value of variable `mh-scan-msg-number-regexp'." 409 mh-scan-msg-number-regexp) 410 411;;;###mh-autoload 412(defun mh-scan-msg-search-regexp () 413 "Return value of variable `mh-scan-msg-search-regexp'." 414 mh-scan-msg-search-regexp) 415 416;;;###mh-autoload 417(defun mh-set-cmd-note (column) 418 "Set `mh-cmd-note' to COLUMN. 419Note that columns in Emacs start with 0." 420 (setq mh-cmd-note column)) 421 422;;;###mh-autoload 423(defun mh-scan-format () 424 "Return the output format argument for the scan program." 425 (if (equal mh-scan-format-file t) 426 (list "-format" (if (mh-variant-p 'nmh 'mu-mh) 427 (list (mh-update-scan-format 428 mh-scan-format-nmh mh-cmd-note)) 429 (list (mh-update-scan-format 430 mh-scan-format-mh mh-cmd-note)))) 431 (if (not (equal mh-scan-format-file nil)) 432 (list "-form" mh-scan-format-file)))) 433 434(defun mh-update-scan-format (fmt width) 435 "Return a scan format with the (msg) width in the FMT replaced with WIDTH. 436 437The message number width portion of the format is discovered 438using `mh-scan-msg-format-regexp'. Its replacement is controlled 439with `mh-scan-msg-format-string'." 440 (or (and 441 (string-match mh-scan-msg-format-regexp fmt) 442 (let ((begin (match-beginning 1)) 443 (end (match-end 1))) 444 (concat (substring fmt 0 begin) 445 (format mh-scan-msg-format-string width) 446 (substring fmt end)))) 447 fmt)) 448 449;;;###mh-autoload 450(defun mh-msg-num-width (folder) 451 "Return the width of the largest message number in this FOLDER." 452 (or mh-progs (mh-find-path)) 453 (let ((tmp-buffer (get-buffer-create mh-temp-buffer)) 454 (width 0)) 455 (save-excursion 456 (set-buffer tmp-buffer) 457 (erase-buffer) 458 (apply 'call-process 459 (expand-file-name mh-scan-prog mh-progs) nil '(t nil) nil 460 (list folder "last" "-format" "%(msg)")) 461 (goto-char (point-min)) 462 (if (re-search-forward mh-scan-msg-number-regexp nil 0 1) 463 (setq width (length (buffer-substring 464 (match-beginning 1) (match-end 1)))))) 465 width)) 466 467;;;###mh-autoload 468(defun mh-msg-num-width-to-column (width) 469 "Return the column for notations given message number WIDTH. 470Note that columns in Emacs start with 0. 471 472If `mh-scan-format-file' is set to \"Use MH-E scan Format\" this 473means that either `mh-scan-format-mh' or `mh-scan-format-nmh' are 474in use. This function therefore assumes that the first column is 475empty (to provide room for the cursor), the following WIDTH 476columns contain the message number, and the column for notations 477comes after that." 478 (if (eq mh-scan-format-file t) 479 (max (1+ width) 2) 480 (error "%s %s" "Can't call `mh-msg-num-width-to-column' when" 481 "`mh-scan-format-file' is not set to \"Use MH-E scan Format\""))) 482 483(provide 'mh-scan) 484 485;; Local Variables: 486;; indent-tabs-mode: nil 487;; sentence-end-double-space: nil 488;; End: 489 490;; arch-tag: 5ab35d46-101e-443b-a2b6-5a908cf97528 491;;; mh-scan.el ends here 492