Fix sectrioning errors in files.texi.
[emacs.git] / lisp / mh-e / mh-scan.el
blob07d33368511e25a06fda1fcda15b373864e72fd0
1 ;;; mh-scan.el --- MH-E scan line constants and utilities
3 ;; Copyright (C) 1993, 1995, 1997,
4 ;; 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
6 ;; Author: Bill Wohler <wohler@newt.com>
7 ;; Maintainer: Bill Wohler <wohler@newt.com>
8 ;; Keywords: mail
9 ;; See: mh-e.el
11 ;; This file is part of GNU Emacs.
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 3, or (at your option)
16 ;; any later version.
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.
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.
28 ;;; Commentary:
30 ;; This file contains constants and a few functions for interpreting
31 ;; scan lines.
33 ;;; Change Log:
35 ;;; Code:
37 (require 'mh-e)
41 ;;; Scan Formats
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.
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.
64 This string is passed to the scan program via the -format
65 argument. This format is identical to the default except that
66 additional hints for fontification have been added to the fifth
67 column (remember that in Emacs, the first column is 0).
69 The values of the fifth column, in priority order, are: \"-\" if
70 the message has been replied to, t if an address on the To: line
71 matches one of the mailboxes of the current user, \"c\" if the Cc:
72 line matches, \"b\" if the Bcc: line matches, and \"n\" if a
73 non-empty Newsgroups: header is present.")
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.
90 This string is passed to the scan program via the -format arg.
91 This format is identical to the default except that additional
92 hints for fontification have been added to the fifth
93 column (remember that in Emacs, the first column is 0).
95 The values of the fifth column, in priority order, are: \"-\" if
96 the message has been replied to, t if an address on the To: field
97 matches one of the mailboxes of the current user, \"c\" if the Cc:
98 field matches, \"b\" if the Bcc: field matches, and \"n\" if a
99 non-empty Newsgroups: field is present.")
103 ;;; Regular Expressions
105 ;; Alphabetical.
107 (defvar mh-scan-body-regexp "\\(<<\\([^\n]+\\)?\\)"
108 "This regular expression matches the message body fragment.
110 Note that the default setting of `mh-folder-font-lock-keywords'
111 expects this expression to contain at least one parenthesized
112 expression which matches the body text as in the default of
113 \"\\\\(<<\\\\([^\\n]+\\\\)?\\\\)\". If this regular expression is
114 not correct, the body fragment will not be highlighted with the
115 face `mh-folder-body'.")
117 (defvar mh-scan-cur-msg-number-regexp "^\\( *[0-9]+\\+\\).*"
118 "This regular expression matches the current message.
120 It must match from the beginning of the line. Note that the
121 default setting of `mh-folder-font-lock-keywords' expects this
122 expression to contain at least one parenthesized expression which
123 matches the message number as in the default of
125 \"^\\\\( *[0-9]+\\\\+\\\\).*\".
127 This expression includes the leading space and current message
128 marker \"+\" within the parenthesis since it looks better to
129 highlight these items as well. The highlighting is done with the
130 face `mh-folder-cur-msg-number'. This regular expression should
131 be correct as it is needed by non-fontification functions. See
132 also `mh-note-cur'.")
134 (defvar mh-scan-date-regexp "\\([0-9][0-9]/[0-9][0-9]\\)"
135 "This regular expression matches a valid date.
137 It must not be anchored to the beginning or the end of the line.
138 Note that the default setting of `mh-folder-font-lock-keywords'
139 expects this expression to contain only one parenthesized
140 expression which matches the date field as in the default of
141 \"\\\\([0-9][0-9]/[0-9][0-9]\\\\)\"}. If this regular expression
142 is not correct, the date will not be highlighted with the face
143 `mh-folder-date'.")
145 (defvar mh-scan-deleted-msg-regexp "^\\( *[0-9]+\\)D"
146 "This regular expression matches deleted messages.
148 It must match from the beginning of the line. Note that the
149 default setting of `mh-folder-font-lock-keywords' expects this
150 expression to contain at least one parenthesized expression which
151 matches the message number as in the default of
153 \"^\\\\( *[0-9]+\\\\)D\".
155 This expression includes the leading space within the parenthesis
156 since it looks better to highlight it as well. The highlighting
157 is done with the face `mh-folder-deleted'. This regular
158 expression should be correct as it is needed by non-fontification
159 functions. See also `mh-note-deleted'.")
161 (defvar mh-scan-good-msg-regexp "^\\( *[0-9]+\\)[^D^0-9]"
162 "This regular expression matches \"good\" messages.
164 It must match from the beginning of the line. Note that the
165 default setting of `mh-folder-font-lock-keywords' expects this
166 expression to contain at least one parenthesized expression which
167 matches the message number as in the default of
169 \"^\\\\( *[0-9]+\\\\)[^D^0-9]\".
171 This expression includes the leading space within the parenthesis
172 since it looks better to highlight it as well. The highlighting
173 is done with the face `mh-folder-msg-number'. This regular
174 expression should be correct as it is needed by non-fontification
175 functions.")
177 (defvar mh-scan-msg-format-regexp "%\\([0-9]*\\)(msg)"
178 "This regular expression finds the message number width in a scan format.
180 Note that the message number must be placed in a parenthesized
181 expression as in the default of \"%\\\\([0-9]*\\\\)(msg)\". This
182 variable is only consulted if `mh-scan-format-file' is set to
183 \"Use MH-E scan Format\".")
185 (defvar mh-scan-msg-format-string "%d"
186 "This is a format string for width of the message number in a scan format.
188 Use \"0%d\" for zero-filled message numbers. This variable is only
189 consulted if `mh-scan-format-file' is set to \"Use MH-E scan
190 Format\".")
192 (defvar mh-scan-msg-number-regexp "^ *\\([0-9]+\\)"
193 "This regular expression extracts the message number.
195 It must match from the beginning of the line. Note that the
196 message number must be placed in a parenthesized expression as in
197 the default of \"^ *\\\\([0-9]+\\\\)\".")
199 (defvar mh-scan-msg-overflow-regexp "^[?0-9][0-9]"
200 "This regular expression matches overflowed message numbers.")
202 (defvar mh-scan-msg-search-regexp "^[^0-9]*%d[^0-9]"
203 "This regular expression matches a particular message.
205 It is a format string; use \"%d\" to represent the location of the
206 message number within the expression as in the default of
207 \"^[^0-9]*%d[^0-9]\".")
209 (defvar mh-scan-rcpt-regexp "\\(To:\\)\\(..............\\)"
210 "This regular expression specifies the recipient in messages you sent.
212 Note that the default setting of `mh-folder-font-lock-keywords'
213 expects this expression to contain two parenthesized expressions.
214 The first is expected to match the \"To:\" that the default scan
215 format file generates. The second is expected to match the
216 recipient's name as in the default of
217 \"\\\\(To:\\\\)\\\\(..............\\\\)\". If this regular
218 expression is not correct, the \"To:\" string will not be
219 highlighted with the face `mh-folder-to' and the recipient will
220 not be highlighted with the face `mh-folder-address'")
222 (defvar mh-scan-refiled-msg-regexp "^\\( *[0-9]+\\)\\^"
223 "This regular expression matches refiled messages.
225 It must match from the beginning of the line. Note that the
226 default setting of `mh-folder-font-lock-keywords' expects this
227 expression to contain at least one parenthesized expression which
228 matches the message number as in the default of
230 \"^\\\\( *[0-9]+\\\\)\\\\^\".
232 This expression includes the leading space within the parenthesis
233 since it looks better to highlight it as well. The highlighting
234 is done with the face `mh-folder-refiled'. This regular
235 expression should be correct as it is needed by non-fontification
236 functions. See also `mh-note-refiled'.")
238 (defvar mh-scan-sent-to-me-sender-regexp
239 "^ *[0-9]+.\\([bct]\\).....[ ]*\\(..................\\)"
240 "This regular expression matches messages sent to us.
242 Note that the default setting of `mh-folder-font-lock-keywords'
243 expects this expression to contain at least two parenthesized
244 expressions. The first should match the fontification hint (see
245 `mh-scan-format-nmh') and the second should match the user name
246 as in the default of
248 ^ *[0-9]+.\\\\([bct]\\\\).....[ ]*\\\\(..................\\\\)
250 If this regular expression is not correct, the notation hints
251 will not be highlighted with the face
252 `mh-mh-folder-sent-to-me-hint' and the sender will not be
253 highlighted with the face `mh-folder-sent-to-me-sender'.")
255 (defvar mh-scan-subject-regexp
256 "^ *[0-9]+........[ ]*...................\\([Rr][Ee]\\(\\[[0-9]+\\]\\)?:\\s-*\\)*\\([^<\n]*\\)"
257 "This regular expression matches the subject.
259 It must match from the beginning of the line. Note that the
260 default setting of `mh-folder-font-lock-keywords' expects this
261 expression to contain at least three parenthesized expressions.
262 The first is expected to match the \"Re:\" string, if any, and is
263 highlighted with the face `mh-folder-followup'. The second
264 matches an optional bracketed number after \"Re:\", such as in
265 \"Re[2]:\" (and is thus a sub-expression of the first expression)
266 and the third is expected to match the subject line itself which
267 is highlighted with the face `mh-folder-subject'. For example,
268 the default (broken on multiple lines for readability) is
270 ^ *[0-9]+........[ ]*...................
271 \\\\([Rr][Ee]\\\\(\\\\\\=[[0-9]+\\\\]\\\\)?:\\\\s-*\\\\)*
272 \\\\([^<\\n]*\\\\)
274 This regular expression should be correct as it is needed by
275 non-fontification functions.")
277 (defvar mh-scan-valid-regexp "^ *[0-9]"
278 "This regular expression describes a valid scan line.
280 This is used to eliminate error messages that are occasionally
281 produced by \"inc\".")
285 ;;; Widths, Offsets and Columns
287 (defvar mh-cmd-note 4
288 "Column for notations.
290 This variable should be set with the function `mh-set-cmd-note'.
291 This variable may be updated dynamically if
292 `mh-adaptive-cmd-note-flag' is on.
294 Note that columns in Emacs start with 0.")
295 (make-variable-buffer-local 'mh-cmd-note)
297 (defvar mh-scan-cmd-note-width 1
298 "Number of columns consumed by the cmd-note field in `mh-scan-format'.
300 This column will have one of the values: \" \", \"D\", \"^\", \"+\" and
301 where \" \" is the default value,
303 \"D\" is the `mh-note-deleted' character,
304 \"^\" is the `mh-note-refiled' character, and
305 \"+\" is the `mh-note-cur' character.")
307 (defvar mh-scan-destination-width 1
308 "Number of columns consumed by the destination field in `mh-scan-format'.
310 This column will have one of \" \", \"%\", \"-\", \"t\", \"c\", \"b\", or \"n\"
311 in it.
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.")
321 (defvar mh-scan-date-width 5
322 "Number of columns consumed by the date field in `mh-scan-format'.
323 This column will typically be of the form mm/dd.")
325 (defvar mh-scan-date-flag-width 1
326 "Number of columns consumed to flag (in)valid dates in `mh-scan-format'.
327 This column will have \" \" for valid and \"*\" for invalid or
328 missing dates.")
330 (defvar mh-scan-from-mbox-width 17
331 "Number of columns consumed with the \"From:\" line in `mh-scan-format'.
332 This column will have a friendly name or e-mail address of the
333 originator, or a \"To: address\" for outgoing e-mail messages.")
335 (defvar mh-scan-from-mbox-sep-width 2
336 "Number of columns consumed by whitespace after from-mbox in `mh-scan-format'.
337 This column will only ever have spaces in it.")
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.")
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.")
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.")
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.")
365 ;;; Notation
367 ;; Alphabetical.
369 (defvar mh-note-cur ?+
370 "The current message (in MH, not in MH-E) is marked by this character.
371 See also `mh-scan-cur-msg-number-regexp'.")
373 (defvar mh-note-copied ?C
374 "Messages that have been copied are marked by this character.")
376 (defvar mh-note-deleted ?D
377 "Messages that have been deleted are marked by this character.
378 See also `mh-scan-deleted-msg-regexp'.")
380 (defvar mh-note-dist ?R
381 "Messages that have been redistributed are marked by this character.")
383 (defvar mh-note-forw ?F
384 "Messages that have been forwarded are marked by this character.")
386 (defvar mh-note-printed ?P
387 "Messages that have been printed are marked by this character.")
389 (defvar mh-note-refiled ?^
390 "Messages that have been refiled are marked by this character.
391 See also `mh-scan-refiled-msg-regexp'.")
393 (defvar mh-note-repl ?-
394 "Messages that have been replied to are marked by this character.")
396 (defvar mh-note-seq ?%
397 "Messages in a user-defined sequence are marked by this character.
399 Messages in the \"search\" sequence are marked by this character as
400 well.")
404 ;;; Utilities
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)
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)
416 ;;;###mh-autoload
417 (defun mh-set-cmd-note (column)
418 "Set `mh-cmd-note' to COLUMN.
419 Note that columns in Emacs start with 0."
420 (setq mh-cmd-note column))
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))))
434 (defun mh-update-scan-format (fmt width)
435 "Return a scan format with the (msg) width in the FMT replaced with WIDTH.
437 The message number width portion of the format is discovered
438 using `mh-scan-msg-format-regexp'. Its replacement is controlled
439 with `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))
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))
467 ;;;###mh-autoload
468 (defun mh-msg-num-width-to-column (width)
469 "Return the column for notations given message number WIDTH.
470 Note that columns in Emacs start with 0.
472 If `mh-scan-format-file' is set to \"Use MH-E scan Format\" this
473 means that either `mh-scan-format-mh' or `mh-scan-format-nmh' are
474 in use. This function therefore assumes that the first column is
475 empty (to provide room for the cursor), the following WIDTH
476 columns contain the message number, and the column for notations
477 comes 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\"")))
483 (provide 'mh-scan)
485 ;; Local Variables:
486 ;; indent-tabs-mode: nil
487 ;; sentence-end-double-space: nil
488 ;; End:
490 ;; arch-tag: 5ab35d46-101e-443b-a2b6-5a908cf97528
491 ;;; mh-scan.el ends here