;;; nnmail.el --- mail support functions for the Gnus mail backends
-;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001
+;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
;; Free Software Foundation, Inc.
;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
"Various mail options."
:group 'nnmail)
-(defcustom nnmail-split-methods
- '(("mail.misc" ""))
+(defcustom nnmail-split-methods '(("mail.misc" ""))
"*Incoming mail will be split according to this variable.
If you'd like, for instance, one mail group for mail from the
(function :format "%v" nnmail-)
string))
-(defcustom nnmail-fancy-expiry-targets nil
+(defcustom nnmail-fancy-expiry-targets nil
"Determine expiry target based on articles using fancy techniques.
This is a list of (\"HEADER\" \"REGEXP\" \"TARGET\") entries. If
:type '(repeat (list (choice :tag "Match against"
(string :tag "Header")
(const to-from))
- regexp
- (string :tag "Target group format string"))))
+ regexp
+ (string :tag "Target group format string"))))
(defcustom nnmail-cache-accepted-message-ids nil
"If non-nil, put Message-IDs of Gcc'd articles into the duplicate cache.
:type 'hook)
(defcustom nnmail-large-newsgroup 50
- "*The number of the articles which indicates a large newsgroup.
+ "*The number of the articles which indicates a large newsgroup or nil.
If the number of the articles is greater than the value, verbose
messages will be shown to indicate the current status."
:group 'nnmail-various
- :type 'integer)
+ :type '(choice (const :tag "infinite" nil)
+ (number :tag "count")))
(defcustom nnmail-split-fancy "mail.misc"
"Incoming mail can be split according to this fancy variable.
\(FIELD VALUE [- RESTRICT [- RESTRICT [...]]] SPLIT): If the message
field FIELD (a regexp) contains VALUE (a regexp), store the messages
as specified by SPLIT. If RESTRICT (a regexp) matches some string
- after FIELD and before the end of the matched VALUE, return NIL,
+ after FIELD and before the end of the matched VALUE, return nil,
otherwise process SPLIT. Multiple RESTRICTs add up, further
restricting the possibility of processing SPLIT.
junk: Mail will be deleted. Use with care! Do not submerge in water!
Example:
(setq nnmail-split-fancy
- '(| (\"Subject\" \"MAKE MONEY FAST\" junk)
- ...other.rules.omitted...))
+ '(| (\"Subject\" \"MAKE MONEY FAST\" junk)
+ ...other.rules.omitted...))
FIELD must match a complete field name. VALUE must match a complete
word according to the `nnmail-split-fancy-syntax-table' syntax table.
(const warn)
(const delete)))
-(defcustom nnmail-extra-headers nil
+(defcustom nnmail-extra-headers '(To Newsgroups)
"*Extra headers to parse."
:version "21.1"
:group 'nnmail
:group 'nnmail
:type 'integer)
+(defcustom nnmail-mail-splitting-charset nil
+ "Default charset to be used when splitting incoming mail."
+ :group 'nnmail
+ :type 'symbol)
+
+(defcustom nnmail-mail-splitting-decodes t
+ "Whether the nnmail splitting functionality should MIME decode headers."
+ :group 'nnmail
+ :type 'boolean)
+
;;; Internal variables.
(defvar nnmail-article-buffer " *nnmail incoming*"
(defsubst nnmail-search-unix-mail-delim ()
"Put point at the beginning of the next Unix mbox message."
- ;; Algorithm used to find the the next article in the
+ ;; Algorithm used to find the next article in the
;; brain-dead Unix mbox format:
;;
;; 1) Search for "^From ".
(defun nnmail-search-unix-mail-delim-backward ()
"Put point at the beginning of the current Unix mbox message."
- ;; Algorithm used to find the the next article in the
+ ;; Algorithm used to find the next article in the
;; brain-dead Unix mbox format:
;;
;; 1) Search for "^From ".
start
(if (search-forward "\n\n" nil t)
(1- (point))
- ;; This will never happen, but just to be on the safe side --
- ;; if there is no head-body delimiter, we search a bit manually.
+ ;; This will never happen, but just to be on the safe side --
+ ;; if there is no head-body delimiter, we search a bit manually.
(while (and (looking-at "From \\|[^ \t]+:")
(not (eobp)))
(forward-line 1))
(goto-char (point-max))
(widen)
(setq head-end (point))
- ;; We try the Content-Length value. The idea: skip over the header
- ;; separator, then check what happens content-length bytes into the
- ;; message body. This should be either the end ot the buffer, the
- ;; message separator or a blank line followed by the separator.
- ;; The blank line should probably be deleted. If neither of the
- ;; three is met, the content-length header is probably invalid.
+ ;; We try the Content-Length value. The idea: skip over the header
+ ;; separator, then check what happens content-length bytes into the
+ ;; message body. This should be either the end ot the buffer, the
+ ;; message separator or a blank line followed by the separator.
+ ;; The blank line should probably be deleted. If neither of the
+ ;; three is met, the content-length header is probably invalid.
(when content-length
(forward-line 1)
(setq skip (+ (point) content-length))
(defun nnmail-article-group (func &optional trace)
"Look at the headers and return an alist of groups that match.
FUNC will be called with the group name to determine the article number."
- (let ((methods nnmail-split-methods)
+ (let ((methods (or nnmail-split-methods '(("bogus" ""))))
(obuf (current-buffer))
(beg (point-min))
end group-art method grp)
(erase-buffer)
;; Copy the headers into the work buffer.
(insert-buffer-substring obuf beg end)
+ ;; Decode MIME headers and charsets.
+ (when nnmail-mail-splitting-decodes
+ (let ((mail-parse-charset nnmail-mail-splitting-charset))
+ (mail-decode-encoded-word-region (point-min) (point-max))))
;; Fold continuation lines.
(goto-char (point-min))
(while (re-search-forward "\\(\r?\n[ \t]+\\)+" nil t)
(or (funcall nnmail-split-methods)
'("bogus"))
(error
- (nnheader-message 5
- "Error in `nnmail-split-methods'; using `bogus' mail group")
+ (nnheader-message
+ 5 "Error in `nnmail-split-methods'; using `bogus' mail group")
(sit-for 1)
'("bogus")))))
(setq split (gnus-remove-duplicates split))
(funcall func (car method)))))))))
;; Produce a trace if non-empty.
(when (and trace nnmail-split-trace)
- (let ((trace (nreverse nnmail-split-trace))
- (restore (current-buffer)))
+ (let ((restore (current-buffer)))
(nnheader-set-temp-buffer "*Split Trace*")
(gnus-add-buffer)
- (while trace
- (insert (car trace) "\n")
- (setq trace (cdr trace)))
+ (dolist (trace (nreverse nnmail-split-trace))
+ (prin1 trace (current-buffer))
+ (insert "\n"))
(goto-char (point-min))
(gnus-configure-windows 'split-trace)
(set-buffer restore)))
;; A group name. Do the \& and \N subs into the string.
((stringp split)
(when nnmail-split-tracing
- (push (format "\"%s\"" split) nnmail-split-trace))
+ (push split nnmail-split-trace))
(list (nnmail-expand-newtext split)))
;; Junk the message.
(while (and (goto-char end-point)
(re-search-backward (cdr cached-pair) nil t))
(when nnmail-split-tracing
- (push (cdr cached-pair) nnmail-split-trace))
+ (push split nnmail-split-trace))
(let ((split-rest (cddr split))
(end (match-end 0))
- ;; The searched regexp is \(\(FIELD\).*\)\(VALUE\). So,
- ;; start-of-value is the the point just before the
- ;; beginning of the value, whereas after-header-name is
- ;; the point just after the field name.
+ ;; The searched regexp is \(\(FIELD\).*\)\(VALUE\).
+ ;; So, start-of-value is the point just before the
+ ;; beginning of the value, whereas after-header-name
+ ;; is the point just after the field name.
(start-of-value (match-end 1))
(after-header-name (match-end 2)))
;; Start the next search just before the beginning of the
(let ((value (nth 1 split)))
(if (symbolp value)
(setq value (cdr (assq value nnmail-split-abbrev-alist))))
- ;; Someone might want to do a \N sub on this match, so get the
+ ;; Someone might want to do a \N sub on this match, so get the
;; correct match positions.
(re-search-backward value start-of-value))
(dolist (sp (nnmail-split-it (car split-rest)))
(defvar group)
(defvar group-art-list)
(defvar group-art)
-(defun nnmail-cache-insert (id)
+(defun nnmail-cache-insert (id grp)
(when nnmail-treat-duplicates
;; Store some information about the group this message is written
- ;; to. This function might have been called from various places.
- ;; Sometimes, a function up in the calling sequence has an
- ;; argument GROUP which is bound to a string, the group name. At
- ;; other times, there is a function up in the calling sequence
- ;; which has an argument GROUP-ART which is a list of pairs, and
- ;; the car of a pair is a group name. Should we check that the
- ;; length of the list is equal to 1? -- kai
- (let ((g nil))
- (cond ((and (boundp 'group) group)
- (setq g group))
- ((and (boundp 'group-art-list) group-art-list
- (listp group-art-list))
- (setq g (caar group-art-list)))
- ((and (boundp 'group-art) group-art (listp group-art))
- (setq g (caar group-art)))
- (t (setq g "")))
- (unless (gnus-buffer-live-p nnmail-cache-buffer)
- (nnmail-cache-open))
- (save-excursion
- (set-buffer nnmail-cache-buffer)
- (goto-char (point-max))
- (if (and g (not (string= "" g))
- (gnus-methods-equal-p gnus-command-method
- (nnmail-cache-primary-mail-backend)))
- (insert id "\t" g "\n")
- (insert id "\n"))))))
+ ;; to. This is passed in as the grp argument -- all locations this
+ ;; has been called from have been checked and the group is available.
+ ;; The only ambiguous case is nnmail-check-duplication which will only
+ ;; pass the first (of possibly >1) group which matches. -Josh
+ (unless (gnus-buffer-live-p nnmail-cache-buffer)
+ (nnmail-cache-open))
+ (save-excursion
+ (set-buffer nnmail-cache-buffer)
+ (goto-char (point-max))
+ (if (and grp (not (string= "" grp))
+ (gnus-methods-equal-p gnus-command-method
+ (nnmail-cache-primary-mail-backend)))
+ (insert id "\t" grp "\n")
+ (insert id "\n")))))
(defun nnmail-cache-primary-mail-backend ()
(let ((be-list (cons gnus-select-method gnus-secondary-select-methods))
((not duplication)
(funcall func (setq group-art
(nreverse (nnmail-article-group artnum-func))))
- (nnmail-cache-insert message-id))
+ (nnmail-cache-insert message-id (caar group-art)))
((eq action 'delete)
(setq group-art nil))
((eq action 'warn)