Mercurial > emacs
comparison lisp/mail/rmail.el @ 101916:85a6bf6279eb
(rmail-automatic-folder-directives): Doc fix.
(rmail-current-message, rmail-total-messages)
(rmail-message-vector, rmail-deleted-vector): Add doc strings.
(rmail-duplicate-message): Doc fix.
(rmail-get-header-1, rmail-set-header-1, rmail-set-attribute-1):
New functions.
(rmail-get-header, rmail-set-header, rmail-set-attribute):
Use rmail-apply-in-message.
(rmail-message-attr-p): Use rmail-get-header, hence no longer requires
unswapped-ness.
(rmail-get-attr-names): Check for missing or corrupt attribute headers.
(rmail-auto-file): Set the filed attribute, rather than explicitly not
doing so. (Bug#2231)
author | Glenn Morris <rgm@gnu.org> |
---|---|
date | Tue, 10 Feb 2009 03:33:27 +0000 |
parents | 5cd64f3517f3 |
children | 7e12da77ac12 |
comparison
equal
deleted
inserted
replaced
101915:091a8cf73243 | 101916:85a6bf6279eb |
---|---|
496 REGEXP is an expression to match in the preceeding specified FIELD. | 496 REGEXP is an expression to match in the preceeding specified FIELD. |
497 FIELD/REGEXP pairs continue in the list. | 497 FIELD/REGEXP pairs continue in the list. |
498 | 498 |
499 examples: | 499 examples: |
500 (\"/dev/null\" \"from\" \"@spam.com\") ; delete all mail from spam.com | 500 (\"/dev/null\" \"from\" \"@spam.com\") ; delete all mail from spam.com |
501 (\"RMS\" \"from\" \"rms@\") ; save all mail from RMS." | 501 (\"RMS\" \"from\" \"rms@\") ; save all mail from RMS. |
502 | |
503 Note that this is only applied in the folder specifed by `rmail-file-name'." | |
502 :group 'rmail | 504 :group 'rmail |
503 :version "21.1" | 505 :version "21.1" |
504 :type '(repeat (sexp :tag "Directive"))) | 506 :type '(repeat (sexp :tag "Directive"))) |
505 | 507 |
506 (defvar rmail-reply-prefix "Re: " | 508 (defvar rmail-reply-prefix "Re: " |
527 In a summary buffer, this holds the RMAIL buffer it is a summary for.") | 529 In a summary buffer, this holds the RMAIL buffer it is a summary for.") |
528 (put 'rmail-buffer 'permanent-local t) | 530 (put 'rmail-buffer 'permanent-local t) |
529 | 531 |
530 ;; Message counters and markers. Deleted flags. | 532 ;; Message counters and markers. Deleted flags. |
531 | 533 |
532 (defvar rmail-current-message nil) | 534 (defvar rmail-current-message nil |
535 "Integer specifying the message currently being displayed in this folder.") | |
533 (put 'rmail-current-message 'permanent-local t) | 536 (put 'rmail-current-message 'permanent-local t) |
534 | 537 |
535 (defvar rmail-total-messages nil) | 538 (defvar rmail-total-messages nil |
539 "Integer specifying the total number of messages in this folder. | |
540 Includes deleted messages.") | |
536 (put 'rmail-total-messages 'permanent-local t) | 541 (put 'rmail-total-messages 'permanent-local t) |
537 | 542 |
538 (defvar rmail-message-vector nil) | 543 (defvar rmail-message-vector nil |
544 "Vector of markers specifying the start and end of each message. | |
545 Element N and N+1 specify the start and end of message N.") | |
539 (put 'rmail-message-vector 'permanent-local t) | 546 (put 'rmail-message-vector 'permanent-local t) |
540 | 547 |
541 (defvar rmail-deleted-vector nil) | 548 (defvar rmail-deleted-vector nil |
549 "A string of length `rmail-total-messages' plus one. | |
550 Character N is either a space or \"D\", according to whether | |
551 message N is deleted or not.") | |
542 (put 'rmail-deleted-vector 'permanent-local t) | 552 (put 'rmail-deleted-vector 'permanent-local t) |
543 | 553 |
544 (defvar rmail-msgref-vector nil | 554 (defvar rmail-msgref-vector nil |
545 "In an Rmail buffer, a vector whose Nth element is a list (N). | 555 "In an Rmail buffer, a vector whose Nth element is a list (N). |
546 When expunging renumbers messages, these lists are modified | 556 When expunging renumbers messages, these lists are modified |
1442 (bury-buffer rmail-summary-buffer))) | 1452 (bury-buffer rmail-summary-buffer))) |
1443 (quit-window))) | 1453 (quit-window))) |
1444 | 1454 |
1445 (defun rmail-duplicate-message () | 1455 (defun rmail-duplicate-message () |
1446 "Create a duplicated copy of the current message. | 1456 "Create a duplicated copy of the current message. |
1447 The duplicate copy goes into the Rmail file just after the | 1457 The duplicate copy goes into the Rmail file just after the original." |
1448 original copy." | |
1449 (interactive) | |
1450 ;; If we are in a summary buffer, switch to the Rmail buffer. | 1458 ;; If we are in a summary buffer, switch to the Rmail buffer. |
1459 ;; FIXME simpler to swap the contents, not the buffers? | |
1451 (set-buffer rmail-buffer) | 1460 (set-buffer rmail-buffer) |
1452 (let ((buff (current-buffer)) | 1461 (let ((buff (current-buffer)) |
1453 (n rmail-current-message) | 1462 (n rmail-current-message) |
1454 (beg (rmail-msgbeg rmail-current-message)) | 1463 (beg (rmail-msgbeg rmail-current-message)) |
1455 (end (rmail-msgend rmail-current-message))) | 1464 (end (rmail-msgend rmail-current-message))) |
1456 (if (rmail-buffers-swapped-p) (set-buffer rmail-view-buffer)) | 1465 (if (rmail-buffers-swapped-p) (set-buffer rmail-view-buffer)) |
1457 (widen) | 1466 (widen) |
1458 (let ((buffer-read-only nil) | 1467 (let ((buffer-read-only nil) |
1459 (string (buffer-substring-no-properties beg end))) | 1468 (string (buffer-substring-no-properties beg end))) |
1460 (goto-char end) | 1469 (goto-char end) |
1461 (insert string)) | 1470 (insert string)) |
1462 (set-buffer buff) | 1471 (set-buffer buff) |
1463 (rmail-swap-buffers-maybe) | 1472 (rmail-swap-buffers-maybe) |
1708 "Process new messages for spam." | 1717 "Process new messages for spam." |
1709 (let* ((old-messages (- rmail-total-messages new-message-count)) | 1718 (let* ((old-messages (- rmail-total-messages new-message-count)) |
1710 (rsf-number-of-spam 0) | 1719 (rsf-number-of-spam 0) |
1711 (rsf-scanned-message-number (1+ old-messages)) | 1720 (rsf-scanned-message-number (1+ old-messages)) |
1712 ;; save deletion flags of old messages: vector starts at zero | 1721 ;; save deletion flags of old messages: vector starts at zero |
1713 ;; (is one longer that no of messages), therefore take 1+ | 1722 ;; (is one longer than no of messages), therefore take 1+ |
1714 ;; old-messages | 1723 ;; old-messages |
1715 (save-deleted (substring rmail-deleted-vector 0 (1+ old-messages))) | 1724 (save-deleted (substring rmail-deleted-vector 0 (1+ old-messages))) |
1716 blurb) | 1725 blurb) |
1717 ;; set all messages to undeleted | 1726 ;; set all messages to undeleted |
1718 (setq rmail-deleted-vector (make-string (1+ rmail-total-messages) ?\ )) | 1727 (setq rmail-deleted-vector (make-string (1+ rmail-total-messages) ?\ )) |
1986 (if (search-forward "\n\nFrom " nil 'move) | 1995 (if (search-forward "\n\nFrom " nil 'move) |
1987 (forward-char -5)) | 1996 (forward-char -5)) |
1988 (setq start (point)))) | 1997 (setq start (point)))) |
1989 count)))) | 1998 count)))) |
1990 | 1999 |
2000 (defun rmail-get-header-1 (name) | |
2001 "Subroutine of `rmail-get-header'. | |
2002 Narrow to header, call `mail-fetch-field' to find header NAME." | |
2003 (if (search-forward "\n\n" nil t) | |
2004 (progn | |
2005 (narrow-to-region (point-min) (point)) | |
2006 (mail-fetch-field name)) | |
2007 (rmail-error-bad-format))) | |
2008 | |
1991 (defun rmail-get-header (name &optional msgnum) | 2009 (defun rmail-get-header (name &optional msgnum) |
1992 "Return the value of message header NAME, nil if it has none. | 2010 "Return the value of message header NAME, nil if it has none. |
1993 MSGNUM specifies the message number to get it from. | 2011 MSGNUM specifies the message number to get it from. |
1994 If MSGNUM is nil, use the current message." | 2012 If MSGNUM is nil, use the current message." |
1995 (with-current-buffer rmail-buffer | 2013 (rmail-apply-in-message msgnum 'rmail-get-header-1 name)) |
1996 (or msgnum (setq msgnum rmail-current-message)) | 2014 |
1997 (when (> msgnum 0) | 2015 (defun rmail-set-header-1 (name value) |
1998 (let (msgbeg end) | 2016 "Subroutine of `rmail-set-header'. |
1999 (setq msgbeg (rmail-msgbeg msgnum)) | 2017 Narrow to header, set header NAME to VALUE, replacing existing if present." |
2000 ;; All access to the buffer's local variables is now finished... | 2018 (if (search-forward "\n\n" nil t) |
2001 (save-excursion | 2019 (progn |
2002 ;; ... so it is ok to go to a different buffer. | 2020 (forward-char -1) |
2003 (if (rmail-buffers-swapped-p) (set-buffer rmail-view-buffer)) | 2021 (narrow-to-region (point-min) (point)) |
2004 (save-excursion | 2022 (goto-char (point-min)) |
2005 (save-restriction | 2023 (if (re-search-forward (concat "^" (regexp-quote name) ":") nil 'move) |
2006 (widen) | 2024 (progn |
2007 (goto-char msgbeg) | 2025 (delete-region (point) (line-end-position)) |
2008 (setq end (search-forward "\n\n" nil t)) | 2026 (insert " " value)) |
2009 (if end | 2027 (insert name ": " value "\n"))) |
2010 (progn | 2028 (rmail-error-bad-format))) |
2011 (narrow-to-region msgbeg end) | |
2012 (mail-fetch-field name)) | |
2013 (rmail-error-bad-format msgnum))))))))) | |
2014 | 2029 |
2015 (defun rmail-set-header (name &optional msgnum value) | 2030 (defun rmail-set-header (name &optional msgnum value) |
2016 "Store VALUE in message header NAME, nil if it has none. | 2031 "Store VALUE in message header NAME, nil if it has none. |
2017 MSGNUM specifies the message number to operate on. | 2032 MSGNUM specifies the message number to operate on. |
2018 If MSGNUM is nil, use the current message." | 2033 If MSGNUM is nil, use the current message." |
2019 (with-current-buffer rmail-buffer | 2034 (rmail-apply-in-message msgnum 'rmail-set-header-1 name value) |
2020 (or msgnum (setq msgnum rmail-current-message)) | 2035 ;; Ensure header changes get saved. |
2021 (when (> msgnum 0) | 2036 ;; (Note replacing a header with an identical copy modifies.) |
2022 (let (msgbeg end) | 2037 (with-current-buffer rmail-buffer (set-buffer-modified-p t))) |
2023 (setq msgbeg (rmail-msgbeg msgnum)) | 2038 |
2024 ;; All access to the buffer's local variables is now finished... | |
2025 (save-excursion | |
2026 ;; ... so it is ok to go to a different buffer. | |
2027 (if (rmail-buffers-swapped-p) (set-buffer rmail-view-buffer)) | |
2028 (save-excursion | |
2029 (save-restriction | |
2030 (widen) | |
2031 (goto-char msgbeg) | |
2032 (setq end (search-forward "\n\n" nil t)) | |
2033 (if end (setq end (1- end))) | |
2034 (if end | |
2035 (progn | |
2036 (narrow-to-region msgbeg end) | |
2037 (goto-char msgbeg) | |
2038 (if (re-search-forward (concat "^" | |
2039 (regexp-quote name) | |
2040 ":") | |
2041 nil t) | |
2042 (progn | |
2043 (delete-region (point) (line-end-position)) | |
2044 (insert " " value)) | |
2045 (goto-char end) | |
2046 (insert name ": " value "\n"))) | |
2047 (rmail-error-bad-format msgnum))))) | |
2048 ;; Ensure header changes get saved. | |
2049 (if end (set-buffer-modified-p t)))))) | |
2050 | 2039 |
2051 ;;;; *** Rmail Attributes and Keywords *** | 2040 ;;;; *** Rmail Attributes and Keywords *** |
2052 | 2041 |
2053 (defun rmail-get-attr-names (&optional msg) | 2042 (defun rmail-get-attr-names (&optional msg) |
2054 "Return the message attributes in a comma separated string. | 2043 "Return the message attributes in a comma separated string. |
2055 MSG specifies the message number to get it from. | 2044 MSG specifies the message number to get it from. |
2056 If MSG is nil, use the current message." | 2045 If MSG is nil, use the current message." |
2057 (let ((value (rmail-get-header rmail-attribute-header msg)) | 2046 (let ((value (rmail-get-header rmail-attribute-header msg)) |
2047 (nmax (length rmail-attr-array)) | |
2058 result temp) | 2048 result temp) |
2059 (dotimes (index (length value)) | 2049 (when value |
2060 (setq temp (and (not (= ?- (aref value index))) | 2050 (unless (= (length value) nmax) |
2061 (nth 1 (aref rmail-attr-array index))) | 2051 (error "Corrupt attribute header in message")) |
2062 result | 2052 (dotimes (index nmax) |
2063 (cond | 2053 (setq temp (and (not (= ?- (aref value index))) |
2064 ((and temp result) (format "%s, %s" result temp)) | 2054 (nth 1 (aref rmail-attr-array index))) |
2065 (temp temp) | 2055 result |
2066 (t result)))) | 2056 (cond |
2067 result)) | 2057 ((and temp result) (format "%s, %s" result temp)) |
2058 (temp temp) | |
2059 (t result)))) | |
2060 result))) | |
2068 | 2061 |
2069 (defun rmail-get-keywords (&optional msg) | 2062 (defun rmail-get-keywords (&optional msg) |
2070 "Return the message keywords in a comma separated string. | 2063 "Return the message keywords in a comma separated string. |
2071 MSG, if non-nil, identifies the message number to use. | 2064 MSG, if non-nil, identifies the message number to use. |
2072 If nil, that means the current message." | 2065 If nil, that means the current message." |
2114 (cond | 2107 (cond |
2115 ((numberp state) state) | 2108 ((numberp state) state) |
2116 ((not state) ?-) | 2109 ((not state) ?-) |
2117 (t (nth 0 (aref rmail-attr-array attr))))) | 2110 (t (nth 0 (aref rmail-attr-array attr))))) |
2118 | 2111 |
2112 (defun rmail-set-attribute-1 (attr state) | |
2113 "Subroutine of `rmail-set-attribute'. | |
2114 Set Rmail attribute ATTR to STATE in `rmail-attribute-header', | |
2115 creating the header if necessary. Returns non-nil if a | |
2116 significant attribute change was made." | |
2117 (let ((limit (search-forward "\n\n" nil t)) | |
2118 (value (rmail-get-attr-value attr state)) | |
2119 (inhibit-read-only t) | |
2120 altered) | |
2121 (goto-char (point-min)) | |
2122 (if (search-forward (concat rmail-attribute-header ": ") limit t) | |
2123 ;; If this message already records attributes, just change the | |
2124 ;; value for this one. | |
2125 (let ((missing (- (+ (point) attr) (line-end-position)))) | |
2126 ;; Position point at this attribute, adding attributes if necessary. | |
2127 (if (> missing 0) | |
2128 (progn | |
2129 (end-of-line) | |
2130 (insert-char ?- missing) | |
2131 (backward-char 1)) | |
2132 (forward-char attr)) | |
2133 ;; Change this attribute. | |
2134 (when (/= value (char-after)) | |
2135 (setq altered t) | |
2136 (delete-char 1) | |
2137 (insert value))) | |
2138 ;; Otherwise add a header line to record the attributes and set | |
2139 ;; all but this one to no. | |
2140 (let ((header-value "--------")) | |
2141 (aset header-value attr value) | |
2142 (goto-char (if limit (1- limit) (point-max))) | |
2143 (setq altered (/= value ?-)) | |
2144 (insert rmail-attribute-header ": " header-value "\n"))) | |
2145 altered)) | |
2146 | |
2119 (defun rmail-set-attribute (attr state &optional msgnum) | 2147 (defun rmail-set-attribute (attr state &optional msgnum) |
2120 "Turn an attribute of a message on or off according to STATE. | 2148 "Turn an attribute of a message on or off according to STATE. |
2121 STATE is either nil or the character (numeric) value associated | 2149 STATE is either nil or the character (numeric) value associated |
2122 with the state (nil represents off and non-nil represents on). | 2150 with the state (nil represents off and non-nil represents on). |
2123 ATTR is the index of the attribute. MSGNUM is message number to | 2151 ATTR is the index of the attribute. MSGNUM is message number to |
2124 change; nil means current message." | 2152 change; nil means current message." |
2125 (with-current-buffer rmail-buffer | 2153 (with-current-buffer rmail-buffer |
2126 (let ((value (rmail-get-attr-value attr state)) | 2154 (or msgnum (setq msgnum rmail-current-message)) |
2127 (inhibit-read-only t) | 2155 (when (> msgnum 0) |
2128 limit | 2156 ;; The "deleted" attribute is also stored in a special vector so |
2129 altered | 2157 ;; update that too. |
2130 msgbeg) | 2158 (if (= attr rmail-deleted-attr-index) |
2131 (or msgnum (setq msgnum rmail-current-message)) | 2159 (rmail-set-message-deleted-p msgnum state)) |
2132 (when (> msgnum 0) | 2160 (if (prog1 |
2133 ;; The "deleted" attribute is also stored in a special vector | 2161 (rmail-apply-in-message msgnum 'rmail-set-attribute-1 attr state) |
2134 ;; so update that too. | 2162 (if (= msgnum rmail-current-message) |
2135 (if (= attr rmail-deleted-attr-index) | 2163 (rmail-display-labels))) |
2136 (rmail-set-message-deleted-p msgnum state)) | 2164 ;; If we made a significant change in an attribute, mark |
2137 (setq msgbeg (rmail-msgbeg msgnum)) | 2165 ;; rmail-buffer modified, so it will be (1) saved and (2) |
2138 | 2166 ;; displayed in the mode line. |
2139 ;; All access to the buffer's local variables is now finished... | 2167 (set-buffer-modified-p t))))) |
2140 (unwind-protect | |
2141 (save-excursion | |
2142 ;; ... so it is ok to go to a different buffer. | |
2143 (if (rmail-buffers-swapped-p) (set-buffer rmail-view-buffer)) | |
2144 (save-excursion | |
2145 (save-restriction | |
2146 (widen) | |
2147 ;; Determine if the current state is the desired state. | |
2148 (goto-char msgbeg) | |
2149 (save-excursion | |
2150 (setq limit (search-forward "\n\n" nil t))) | |
2151 (if (search-forward (concat rmail-attribute-header ": ") limit t) | |
2152 ;; If this message already records attributes, | |
2153 ;; just change the value for this one. | |
2154 (let ((missing (- (+ (point) attr) (line-end-position)))) | |
2155 ;; Position point at this attribute, | |
2156 ;; adding attributes if necessary. | |
2157 (if (> missing 0) | |
2158 (progn | |
2159 (end-of-line) | |
2160 (insert-char ?- missing) | |
2161 (backward-char 1)) | |
2162 (forward-char attr)) | |
2163 ;; Change this attribute. | |
2164 (when (/= value (char-after)) | |
2165 (setq altered t) | |
2166 (delete-char 1) | |
2167 (insert value))) | |
2168 ;; Otherwise add a header line to record the attributes | |
2169 ;; and set all but this one to no. | |
2170 (let ((header-value "--------")) | |
2171 (aset header-value attr value) | |
2172 (goto-char (if limit (- limit 1) (point-max))) | |
2173 (setq altered (/= value ?-)) | |
2174 (insert rmail-attribute-header ": " header-value "\n")))))) | |
2175 (if (= msgnum rmail-current-message) | |
2176 (rmail-display-labels)))) | |
2177 ;; If we made a significant change in an attribute, | |
2178 ;; mark rmail-buffer modified, so it will be (1) saved | |
2179 ;; and (2) displayed in the mode line. | |
2180 (if altered | |
2181 (set-buffer-modified-p t))))) | |
2182 | 2168 |
2183 (defun rmail-message-attr-p (msg attrs) | 2169 (defun rmail-message-attr-p (msg attrs) |
2184 "Return t if the attributes header for message MSG matches regexp ATTRS. | 2170 "Return t if the attributes header for message MSG matches regexp ATTRS." |
2185 This function assumes the Rmail buffer is unswapped." | 2171 (let ((value (rmail-get-header rmail-attribute-header msg))) |
2186 (save-excursion | 2172 (and value (string-match attrs value)))) |
2187 (save-restriction | |
2188 (let ((start (rmail-msgbeg msg)) | |
2189 limit) | |
2190 (widen) | |
2191 (goto-char start) | |
2192 (setq limit (search-forward "\n\n" (rmail-msgend msg) t)) | |
2193 (goto-char start) | |
2194 (and limit | |
2195 (search-forward (concat rmail-attribute-header ": ") limit t) | |
2196 (looking-at attrs)))))) | |
2197 | 2173 |
2198 (defun rmail-message-unseen-p (msgnum) | 2174 (defun rmail-message-unseen-p (msgnum) |
2199 "Test the unseen attribute for message MSGNUM. | 2175 "Test the unseen attribute for message MSGNUM. |
2200 Return non-nil if the unseen attribute is set, nil otherwise." | 2176 Return non-nil if the unseen attribute is set, nil otherwise." |
2201 (rmail-message-attr-p msgnum "......U")) | 2177 (rmail-message-attr-p msgnum "......U")) |
2226 (setq msgend (rmail-msgend msgnum)) | 2202 (setq msgend (rmail-msgend msgnum)) |
2227 ;; All access to the rmail-buffer's local variables is now finished... | 2203 ;; All access to the rmail-buffer's local variables is now finished... |
2228 (save-excursion | 2204 (save-excursion |
2229 ;; ... so it is ok to go to a different buffer. | 2205 ;; ... so it is ok to go to a different buffer. |
2230 (if (rmail-buffers-swapped-p) (set-buffer rmail-view-buffer)) | 2206 (if (rmail-buffers-swapped-p) (set-buffer rmail-view-buffer)) |
2231 (save-excursion | 2207 (save-excursion |
2232 (save-restriction | 2208 (save-restriction |
2233 (widen) | 2209 (widen) |
2234 (goto-char msgbeg) | 2210 (goto-char msgbeg) |
2235 (narrow-to-region msgbeg msgend) | 2211 (narrow-to-region msgbeg msgend) |
2236 (apply function args)))))))) | 2212 (apply function args)))))))) |
2237 | 2213 |
2214 ;; Unused (save for commented out code in rmailedit.el). | |
2238 (defun rmail-widen-to-current-msgbeg (function) | 2215 (defun rmail-widen-to-current-msgbeg (function) |
2239 "Call FUNCTION with point at start of internal data of current message. | 2216 "Call FUNCTION with point at start of internal data of current message. |
2240 Assumes that bounds were previously narrowed to display the message in Rmail. | 2217 Assumes that bounds were previously narrowed to display the message in Rmail. |
2241 The bounds are widened enough to move point where desired, then narrowed | 2218 The bounds are widened enough to move point where desired, then narrowed |
2242 again afterward. | 2219 again afterward. |
2803 (if (null directive-loop) | 2780 (if (null directive-loop) |
2804 (if (null folder) | 2781 (if (null folder) |
2805 (rmail-delete-forward) | 2782 (rmail-delete-forward) |
2806 (if (string= "/dev/null" folder) | 2783 (if (string= "/dev/null" folder) |
2807 (rmail-delete-message) | 2784 (rmail-delete-message) |
2808 (rmail-output folder 1 t) | 2785 (rmail-output folder 1) |
2809 (setq d nil)))) | 2786 (setq d nil)))) |
2810 (setq d (cdr d)))))) | 2787 (setq d (cdr d)))))) |
2811 | 2788 |
2812 ;; Simple message motion commands. | 2789 ;; Simple message motion commands. |
2813 | 2790 |