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