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