;;; nnmail.el --- mail support functions for the Gnus mail backends
-;; Copyright (C) 1995,96,97 Free Software Foundation, Inc.
+;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
+;; Free Software Foundation, Inc.
-;; Author: Lars Magne Ingebrigtsen <larsi@ifi.uio.no>
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
;; Keywords: news, mail
;; This file is part of GNU Emacs.
(eval-when-compile (require 'cl))
(require 'nnheader)
-(require 'timezone)
(require 'message)
(require 'custom)
+(require 'gnus-util)
+(require 'mail-source)
+(require 'mm-util)
(eval-and-compile
- (autoload 'gnus-error "gnus-util"))
+ (autoload 'gnus-error "gnus-util")
+ (autoload 'gnus-buffer-live-p "gnus-util")
+ (autoload 'gnus-add-buffer "gnus"))
(defgroup nnmail nil
"Reading mail with Gnus."
"Various mail options."
:group 'nnmail)
-(defcustom nnmail-split-methods
- '(("mail.misc" ""))
- "Incoming mail will be split according to this variable.
+(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
\"4ad-l\" mailing list, one group for junk mail and one for everything
(setq nnmail-split-methods
'((\"mail.4ad\" \"From:.*4ad\")
- (\"mail.junk\" \"From:.*Lars\\\\|Subject:.*buy\")
- (\"mail.misc\" \"\")))
+ (\"mail.junk\" \"From:.*Lars\\\\|Subject:.*buy\")
+ (\"mail.misc\" \"\")))
As you can see, this variable is a list of lists, where the first
element in each \"rule\" is the name of the group (which, by the way,
This variable can also have a function as its value."
:group 'nnmail-split
- :type '(choice (repeat :tag "Alist" (group (string :tag "Name") regexp))
+ :type '(choice (repeat :tag "Alist" (group (string :tag "Name")
+ (choice regexp function)))
(function-item nnmail-split-fancy)
(function :tag "Other")))
:group 'nnmail-split
:type 'boolean)
+(defcustom nnmail-split-fancy-with-parent-ignore-groups nil
+ "Regexp that matches group names to be ignored when applying
+`nnmail-split-fancy-with-parent'. This can also be a list of regexps."
+ :group 'nnmail-split
+ :type '(choice (const :tag "none" nil)
+ (regexp :value ".*")
+ (repeat :value (".*") regexp)))
+
+(defcustom nnmail-cache-ignore-groups nil
+ "Regexp that matches group names to be ignored when inserting message
+ids into the cache (`nnmail-cache-insert'). This can also be a list
+of regexps."
+ :group 'nnmail-split
+ :type '(choice (const :tag "none" nil)
+ (regexp :value ".*")
+ (repeat :value (".*") regexp)))
+
;; Added by gord@enci.ucalgary.ca (Gordon Matzigkeit).
(defcustom nnmail-keep-last-article nil
"If non-nil, nnmail will never delete/move a group's last article.
can also be `immediate' and `never'."
:group 'nnmail-expire
:type '(choice (const immediate)
- (integer :tag "days")
+ (number :tag "days")
(const never)))
(defcustom nnmail-expiry-wait-function nil
\(setq nnmail-expiry-wait-function
(lambda (newsgroup)
- (cond ((string-match \"private\" newsgroup) 31)
- ((string-match \"junk\" newsgroup) 1)
+ (cond ((string-match \"private\" newsgroup) 31)
+ ((string-match \"junk\" newsgroup) 1)
((string-match \"important\" newsgroup) 'never)
(t 7))))"
:group 'nnmail-expire
:type '(choice (const :tag "nnmail-expiry-wait" nil)
(function :format "%v" nnmail-)))
+(defcustom nnmail-expiry-target 'delete
+ "*Variable that says where expired messages should end up.
+The default value is `delete' (which says to delete the messages),
+but it can also be a string or a function. If it is a string, expired
+messages end up in that group. If it is a function, the function is
+called in a buffer narrowed to the message in question. The function
+receives one argument, the name of the group the message comes from.
+The return value should be `delete' or a group name (a string)."
+ :version "21.1"
+ :group 'nnmail-expire
+ :type '(choice (const delete)
+ (function :format "%v" nnmail-)
+ string))
+
+(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
+`nnmail-expiry-target' is set to the function
+`nnmail-fancy-expiry-target' and HEADER of the article matches REGEXP,
+the message will be expired to a group determined by invoking
+`format-time-string' with TARGET used as the format string and the
+time extracted from the articles' Date header (if missing the current
+time is used).
+
+In the special cases that HEADER is the symbol `to-from', the regexp
+will try to match against both the From and the To header.
+
+Example:
+
+\(setq nnmail-fancy-expiry-targets
+ '((to-from \"boss\" \"nnfolder:Work\")
+ (\"Subject\" \"IMPORTANT\" \"nnfolder:IMPORTANT.%Y.%b\")
+ (\"from\" \".*\" \"nnfolder:Archive-%Y\")))
+
+In this case, articles containing the string \"boss\" in the To or the
+From header will be expired to the group \"nnfolder:Work\";
+articles containing the sting \"IMPORTANT\" in the Subject header will
+be expired to the group \"nnfolder:IMPORTANT.YYYY.MMM\"; and
+everything else will be expired to \"nnfolder:Archive-YYYY\"."
+ :group 'nnmail-expire
+ :type '(repeat (list (choice :tag "Match against"
+ (string :tag "Header")
+ (const to-from))
+ 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."
+ "If non-nil, put Message-IDs of Gcc'd articles into the duplicate cache.
+If non-nil, also update the cache when copy or move articles."
:group 'nnmail
:type 'boolean)
-(defcustom nnmail-spool-file
- (or (getenv "MAIL")
- (concat "/usr/spool/mail/" (user-login-name)))
- "Where the mail backends will look for incoming mail.
-This variable is \"/usr/spool/mail/$user\" by default.
-If this variable is nil, no mail backends will read incoming mail.
-If this variable is a list, all files mentioned in this list will be
-used as incoming mailboxes.
-If this variable is a directory (i. e., it's name ends with a \"/\"),
-treat all files in that directory as incoming spool files."
- :group 'nnmail-files
- :type 'file)
-
-(defcustom nnmail-crash-box "~/.gnus-crash-box"
- "File where Gnus will store mail while processing it."
+(defcustom nnmail-spool-file '((file))
+ "*Where the mail backends will look for incoming mail.
+This variable is a list of mail source specifiers.
+This variable is obsolete; `mail-sources' should be used instead."
:group 'nnmail-files
- :type 'file)
+ :type 'sexp)
-(defcustom nnmail-use-procmail nil
- "*If non-nil, the mail backends will look in `nnmail-procmail-directory' for spool files.
-The file(s) in `nnmail-spool-file' will also be read."
+(defcustom nnmail-resplit-incoming nil
+ "*If non-nil, re-split incoming procmail sorted mail."
:group 'nnmail-procmail
:type 'boolean)
-(defcustom nnmail-procmail-directory "~/incoming/"
- "*When using procmail (and the like), incoming mail is put in this directory.
-The Gnus mail backends will read the mail from this directory."
- :group 'nnmail-procmail
- :type 'directory)
-
-(defcustom nnmail-procmail-suffix "\\.spool"
- "*Suffix of files created by procmail (and the like).
-This variable might be a suffix-regexp to match the suffixes of
-several files - eg. \".spool[0-9]*\"."
- :group 'nnmail-procmail
- :type 'regexp)
-
-(defcustom nnmail-resplit-incoming nil
- "*If non-nil, re-split incoming procmail sorted mail."
+(defcustom nnmail-scan-directory-mail-source-once nil
+ "*If non-nil, scan all incoming procmail sorted mails once.
+It scans low-level sorted spools even when not required."
+ :version "21.1"
:group 'nnmail-procmail
:type 'boolean)
:type 'function)
(defcustom nnmail-crosspost-link-function
- (if (string-match "windows-nt\\|emx" (format "%s" system-type))
+ (if (string-match "windows-nt\\|emx" (symbol-name system-type))
'copy-file
'add-name-to-file)
- "Function called to create a copy of a file.
+ "*Function called to create a copy of a file.
This is `add-name-to-file' by default, which means that crossposts
will use hard links. If your file system doesn't allow hard
links, you could set this variable to `copy-file' instead."
(function-item copy-file)
(function :tag "Other")))
-(defcustom nnmail-movemail-program "movemail"
- "*A command to be executed to move mail from the inbox.
-The default is \"movemail\".
-
-This can also be a function. In that case, the function will be
-called with two parameters -- the name of the INBOX file, and the file
-to be moved to."
- :group 'nnmail-files
- :group 'nnmail-retrieve
- :type 'string)
-
-(defcustom nnmail-pop-password-required nil
- "*Non-nil if a password is required when reading mail using POP."
- :group 'nnmail-retrieve
- :type 'boolean)
-
(defcustom nnmail-read-incoming-hook
(if (eq system-type 'windows-nt)
'(nnheader-ms-strip-cr)
nil)
- "Hook that will be run after the incoming mail has been transferred.
-The incoming mail is moved from `nnmail-spool-file' (which normally is
+ "*Hook that will be run after the incoming mail has been transferred.
+The incoming mail is moved from the specified spool file (which normally is
something like \"/usr/spool/mail/$user\") to the user's home
directory. This hook is called after the incoming mail box has been
emptied, and can be used to call any mail box programs you have
Eg.
\(add-hook 'nnmail-read-incoming-hook
- (lambda ()
- (start-process \"mailsend\" nil
- \"/local/bin/mailsend\" \"read\" \"mbox\")))
+ (lambda ()
+ (call-process \"/local/bin/mailsend\" nil nil nil
+ \"read\" nnmail-spool-file)))
If you have xwatch running, this will alert it that mail has been
read.
:group 'nnmail-prepare
:type 'hook)
-;; Suggested by Erik Selberg <speed@cs.washington.edu>.
(defcustom nnmail-prepare-incoming-hook nil
"Hook called before treating incoming mail.
The hook is run in a buffer with all the new, incoming mail."
This can also be a list of regexps."
:group 'nnmail-prepare
:type '(choice (const :tag "none" nil)
- regexp
- (repeat regexp)))
+ (regexp :value ".*")
+ (repeat :value (".*") regexp)))
(defcustom nnmail-pre-get-new-mail-hook nil
"Hook called just before starting to handle new incoming mail."
:group 'nnmail-split
:type 'hook)
-;; Suggested by Mejia Pablo J <pjm9806@usl.edu>.
-(defcustom nnmail-tmp-directory nil
- "*If non-nil, use this directory for temporary storage.
-Used when reading incoming mail."
- :group 'nnmail-files
- :group 'nnmail-retrieve
- :type '(choice (const :tag "default" nil)
- (directory :format "%v")))
-
(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.
To enable this, set `nnmail-split-methods' to `nnmail-split-fancy'.
-The format is this variable is SPLIT, where SPLIT can be one of
+The format of this variable is SPLIT, where SPLIT can be one of
the following:
GROUP: Mail will be stored in GROUP (a string).
-\(FIELD VALUE SPLIT): If the message field FIELD (a regexp) contains
- VALUE (a regexp), store the messages as specified by SPLIT.
+\(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,
+ otherwise process SPLIT. Multiple RESTRICTs add up, further
+ restricting the possibility of processing SPLIT.
\(| SPLIT...): Process each SPLIT expression until one of them matches.
A SPLIT expression is said to match if it will cause the mail
the buffer containing the message headers. The return value FUNCTION
should be a split, which is then recursively processed.
+\(! FUNCTION SPLIT): Call FUNCTION with the result of SPLIT. The
+ return value FUNCTION should be a split, which is then recursively
+ processed.
+
+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...))
+
FIELD must match a complete field name. VALUE must match a complete
word according to the `nnmail-split-fancy-syntax-table' syntax table.
You can use \".*\" in the regexps to match partial field names or words.
;; Other mailing lists...
(any \"procmail@informatik\\\\.rwth-aachen\\\\.de\" \"procmail.list\")
(any \"SmartList@informatik\\\\.rwth-aachen\\\\.de\" \"SmartList.list\")
+ ;; Both lists below have the same suffix, so prevent
+ ;; cross-posting to mkpkg.list of messages posted only to
+ ;; the bugs- list, but allow cross-posting when the
+ ;; message was really cross-posted.
+ (any \"bugs-mypackage@somewhere\" \"mypkg.bugs\")
+ (any \"mypackage@somewhere\" - \"bugs-mypackage\" \"mypkg.list\")
+ ;;
;; People...
(any \"larsi@ifi\\\\.uio\\\\.no\" \"people.Lars Magne Ingebrigtsen\"))
;; Unmatched mail goes to the catch all group.
(from . "from\\|sender\\|resent-from")
(nato . "to\\|cc\\|resent-to\\|resent-cc")
(naany . "from\\|to\\|cc\\|sender\\|resent-from\\|resent-to\\|resent-cc"))
- "Alist of abbreviations allowed in `nnmail-split-fancy'."
+ "*Alist of abbreviations allowed in `nnmail-split-fancy'."
:group 'nnmail-split
:type '(repeat (cons :format "%v" symbol regexp)))
-(defcustom nnmail-delete-incoming t
- "*If non-nil, the mail backends will delete incoming files after
-splitting."
- :group 'nnmail-retrieve
- :type 'boolean)
-
(defcustom nnmail-message-id-cache-length 1000
"*The approximate number of Message-IDs nnmail will keep in its cache.
If this variable is nil, no checking on duplicate messages will be
(defcustom nnmail-treat-duplicates 'warn
"*If non-nil, nnmail keep a cache of Message-IDs to discover mail duplicates.
-Three values are legal: nil, which means that nnmail is not to keep a
+Three values are valid: nil, which means that nnmail is not to keep a
Message-ID cache; `warn', which means that nnmail should insert extra
headers to warn the user about the duplication (this is the default);
and `delete', which means that nnmail will delete duplicated mails.
(const warn)
(const delete)))
+(defcustom nnmail-extra-headers '(To Newsgroups)
+ "*Extra headers to parse."
+ :version "21.1"
+ :group 'nnmail
+ :type '(repeat symbol))
+
+(defcustom nnmail-split-header-length-limit 512
+ "Header lines longer than this limit are excluded from the split function."
+ :version "21.1"
+ :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 nil
+ "Whether the nnmail splitting functionality should MIME decode headers."
+ :group 'nnmail
+ :type 'boolean)
+
;;; Interna