Synch to No Gnus 200601190601.
[elisp/gnus.git-] / lisp / nnmail.el
index 2e5d87a..355508c 100644 (file)
@@ -1,6 +1,7 @@
 ;;; nnmail.el --- mail support functions for the Gnus mail backends
-;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
-;;        Free Software Foundation, Inc.
+
+;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
+;;   2004, 2005 Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; Keywords: news, mail
@@ -19,8 +20,8 @@
 
 ;; You should have received a copy of the GNU General Public License
 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
-;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
+;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
 
 ;;; Commentary:
 
@@ -31,7 +32,6 @@
 (require 'gnus)                                ; for macro gnus-kill-buffer, at least
 (require 'nnheader)
 (require 'message)
-(require 'custom)
 (require 'gnus-util)
 (require 'mail-source)
 
@@ -48,7 +48,7 @@
   :group 'nnmail)
 
 (defgroup nnmail-prepare nil
-  "Preparing (or mangling) new mail after retrival."
+  "Preparing (or mangling) new mail after retrieval."
   :group 'nnmail)
 
 (defgroup nnmail-duplicate nil
@@ -118,6 +118,7 @@ If nil, the first match found will be used."
 (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."
+  :version "22.1"
   :group 'nnmail-split
   :type '(choice (const :tag "none" nil)
                 (regexp :value ".*")
@@ -126,6 +127,7 @@ This can also be a list of regexps."
 (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."
+  :version "22.1"
   :group 'nnmail-split
   :type '(choice (const :tag "none" nil)
                 (regexp :value ".*")
@@ -223,6 +225,7 @@ 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\"."
+  :version "22.1"
   :group 'nnmail-expire
   :type '(repeat (list (choice :tag "Match against"
                               (string :tag "Header")
@@ -351,6 +354,7 @@ discarded after running the split process."
 
 (defcustom nnmail-spool-hook nil
   "*A hook called when a new article is spooled."
+  :version "22.1"
   :group 'nnmail
   :type 'hook)
 
@@ -365,14 +369,14 @@ messages will be shown to indicate the current status."
 (define-widget 'nnmail-lazy 'default
   "Base widget for recursive datastructures.
 
-This is copy of the `lazy' widget in Emacs 21.4 provided for compatibility."
+This is copy of the `lazy' widget in Emacs 22.1 provided for compatibility."
   :format "%{%t%}: %v"
   :convert-widget 'widget-value-convert-widget
   :value-create (lambda (widget)
                   (let ((value (widget-get widget :value))
                         (type (widget-get widget :type)))
-                    (widget-put widget :children 
-                                (list (widget-create-child-value 
+                    (widget-put widget :children
+                                (list (widget-create-child-value
                                        widget (widget-convert type) value)))))
   :value-delete 'widget-children-value-delete
   :value-get (lambda (widget)
@@ -381,12 +385,8 @@ This is copy of the `lazy' widget in Emacs 21.4 provided for compatibility."
                   (widget-apply (car (widget-get widget :children))
                                 :value-inline))
   :default-get (lambda (widget)
-                 ;;(widget-default-get
-                 ;; (widget-convert (widget-get widget :type))))
-                ;; `widget-default-get' isn't available in Mule 2.
-                (let ((w (widget-convert (widget-get widget :type))))
-                  (or (widget-get w :value)
-                      (widget-apply w :default-get))))
+                 (widget-default-get
+                  (widget-convert (widget-get widget :type))))
   :match (lambda (widget value)
            (widget-apply (widget-convert (widget-get widget :type))
                          :match value))
@@ -408,7 +408,7 @@ This is copy of the `lazy' widget in Emacs 21.4 provided for compatibility."
                       (list :tag "Function with fixed arguments (:)"
                             :value (:)
                             (const :format "" :value :)
-                            function 
+                            function
                             (editable-list :inline t (sexp :tag "Arg"))
                             )
                       (list :tag "Function with split arguments (!)"
@@ -416,11 +416,11 @@ This is copy of the `lazy' widget in Emacs 21.4 provided for compatibility."
                             (const :format "" !)
                             function
                             (editable-list :inline t nnmail-split-fancy))
-                      (list :tag "Field match" 
-                            (choice :tag "Field" 
+                      (list :tag "Field match"
+                            (choice :tag "Field"
                                     regexp symbol)
                             (choice :tag "Match"
-                                    regexp 
+                                    regexp
                                     (symbol :value mail))
                             (repeat :inline t
                                     :tag "Restrictions"
@@ -470,7 +470,7 @@ 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.
 
-FIELD and VALUE can also be lisp symbols, in that case they are expanded
+FIELD and VALUE can also be Lisp symbols, in that case they are expanded
 as specified in `nnmail-split-abbrev-alist'.
 
 GROUP can contain \\& and \\N which will substitute from matching
@@ -553,7 +553,7 @@ parameter.  It should return nil, `warn' or `delete'."
   :group 'nnmail
   :type '(repeat symbol))
 
-(defcustom nnmail-split-header-length-limit 512
+(defcustom nnmail-split-header-length-limit 2048
   "Header lines longer than this limit are excluded from the split function."
   :version "21.1"
   :group 'nnmail
@@ -561,11 +561,13 @@ parameter.  It should return nil, `warn' or `delete'."
 
 (defcustom nnmail-mail-splitting-charset nil
   "Default charset to be used when splitting incoming mail."
+  :version "22.1"
   :group 'nnmail
   :type 'symbol)
 
 (defcustom nnmail-mail-splitting-decodes t
   "Whether the nnmail splitting functionality should MIME decode headers."
+  :version "22.1"
   :group 'nnmail
   :type 'boolean)
 
@@ -575,6 +577,15 @@ Normally, regexes given in `nnmail-split-fancy' are implicitly surrounded
 by \"\\=\\<...\\>\".  If this variable is true, they are not implicitly\
  surrounded
 by anything."
+  :version "22.1"
+  :group 'nnmail
+  :type 'boolean)
+
+(defcustom nnmail-split-lowercase-expanded t
+  "Whether to lowercase expanded entries (i.e. \\N) when splitting mails.
+This avoids the creation of multiple groups when users send to an address
+using different case (i.e. mailing-list@domain vs Mailing-List@Domain)."
+  :version "22.1"
   :group 'nnmail
   :type 'boolean)
 
@@ -622,8 +633,7 @@ by anything."
        (after-insert-file-functions nil))
     (condition-case ()
        (let ((auto-mode-alist (nnheader-auto-mode-alist))
-             (file-name-coding-system nnmail-pathname-coding-system)
-             (pathname-coding-system nnmail-pathname-coding-system))
+             (file-name-coding-system nnmail-pathname-coding-system))
          (insert-file-contents-as-coding-system
           nnmail-file-coding-system file)
          t)
@@ -671,7 +681,7 @@ nn*-request-list should have been called before calling this function."
     (while (not (eobp))
       (condition-case err
          (progn
-           (narrow-to-region (point) (gnus-point-at-eol))
+           (narrow-to-region (point) (point-at-eol))
            (setq group (read buffer))
            (unless (stringp group)
              (setq group (symbol-name group)))
@@ -689,8 +699,7 @@ nn*-request-list should have been called before calling this function."
 
 (defun nnmail-save-active (group-assoc file-name)
   "Save GROUP-ASSOC in ACTIVE-FILE."
-  (let ((coding-system-for-write nnmail-active-file-coding-system)
-       (output-coding-system nnmail-active-file-coding-system))
+  (let ((coding-system-for-write nnmail-active-file-coding-system))
     (when file-name
       (with-temp-file file-name
        (nnmail-generate-active group-assoc)))))
@@ -759,7 +768,7 @@ If SOURCE is a directory spec, try to return the group name component."
       (if (not (save-excursion
                 (and (re-search-backward
                       "^Content-Length:[ \t]*\\([0-9]+\\)" start t)
-                     (setq content-length (string-to-int
+                     (setq content-length (string-to-number
                                            (buffer-substring
                                             (match-beginning 1)
                                             (match-end 1))))
@@ -896,7 +905,7 @@ If SOURCE is a directory spec, try to return the group name component."
        (if (not (re-search-forward
                  "^Content-Length:[ \t]*\\([0-9]+\\)" nil t))
            (setq content-length nil)
-         (setq content-length (string-to-int (match-string 1)))
+         (setq content-length (string-to-number (match-string 1)))
          ;; We destroy the header, since none of the backends ever
          ;; use it, and we do not want to confuse other mailers by
          ;; having a (possibly) faulty header.
@@ -1110,7 +1119,7 @@ FUNC will be called with the group name to determine the article number."
        (while (not (eobp))
          (unless (< (move-to-column nnmail-split-header-length-limit)
                     nnmail-split-header-length-limit)
-           (delete-region (point) (gnus-point-at-eol)))
+           (delete-region (point) (point-at-eol)))
          (forward-line 1))
        ;; Allow washing.
        (goto-char (point-min))
@@ -1131,7 +1140,7 @@ FUNC will be called with the group name to determine the article number."
                       5 "Error in `nnmail-split-methods'; using `bogus' mail group")
                      (sit-for 1)
                      '("bogus")))))
-             (setq split (gnus-remove-duplicates split))
+             (setq split (mm-delete-duplicates split))
              ;; The article may be "cross-posted" to `junk'.  What
              ;; to do?  Just remove the `junk' spec.  Don't really
              ;; see anything else to do...
@@ -1312,12 +1321,8 @@ to actually put the message in the right group."
 (defun nnmail-split-fancy ()
   "Fancy splitting method.
 See the documentation for the variable `nnmail-split-fancy' for details."
-  (let ((syntab (syntax-table)))
-    (unwind-protect
-       (progn
-         (set-syntax-table nnmail-split-fancy-syntax-table)
-         (nnmail-split-it nnmail-split-fancy))
-      (set-syntax-table syntab))))
+  (with-syntax-table nnmail-split-fancy-syntax-table
+    (nnmail-split-it nnmail-split-fancy)))
 
 (defvar nnmail-split-cache nil)
 ;; Alist of split expressions their equivalent regexps.
@@ -1474,7 +1479,10 @@ See the documentation for the variable `nnmail-split-fancy' for details."
              (setq N 0)
            (setq N (- c ?0)))
          (when (match-beginning N)
-           (push (buffer-substring (match-beginning N) (match-end N))
+           (push (if nnmail-split-lowercase-expanded
+                     (downcase (buffer-substring (match-beginning N)
+                                                 (match-end N)))
+                   (buffer-substring (match-beginning N) (match-end N)))
                  expanded))))
       (setq pos (1+ pos)))
     (if did-expand
@@ -1567,7 +1575,7 @@ See the documentation for the variable `nnmail-split-fancy' for details."
   (when (stringp id)
     ;; this will handle cases like `B r' where the group is nil
     (let ((grp (or grp gnus-newsgroup-name "UNKNOWN")))
-      (run-hook-with-args 'nnmail-spool-hook 
+      (run-hook-with-args 'nnmail-spool-hook
                          id grp subject sender))
     (when nnmail-treat-duplicates
       ;; Store some information about the group this message is written
@@ -1590,7 +1598,7 @@ See the documentation for the variable `nnmail-split-fancy' for details."
              (unless (and regexp (string-match regexp grp))
                (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))
        (be nil)
@@ -1619,7 +1627,7 @@ See the documentation for the variable `nnmail-split-fancy' for details."
        (skip-chars-forward "^\n\r\t")
        (unless (looking-at "[\r\n]")
          (forward-char 1)
-         (buffer-substring (point) (gnus-point-at-eol)))))))
+         (buffer-substring (point) (point-at-eol)))))))
 
 ;; Function for nnmail-split-fancy: look up all references in the
 ;; cache and if a match is found, return that group.
@@ -1858,9 +1866,15 @@ See the Info node `(gnus)Fancy Mail Splitting' for more details."
         (case-fold-search nil)
         (from (or (message-fetch-field "from") ""))
         (to (or (message-fetch-field "to") ""))
-        (date (date-to-time
-               (or (message-fetch-field "date") (current-time-string))))
+        (date (message-fetch-field "date"))
         (target 'delete))
+    (setq date (if date
+                  (condition-case err
+                      (date-to-time date)
+                    (error
+                     (message "%s" (error-message-string err))
+                     (current-time)))
+                (current-time)))
     (dolist (regexp-target-pair (reverse nnmail-fancy-expiry-targets) target)
       (setq header (car regexp-target-pair))
       (cond
@@ -1889,8 +1903,7 @@ See the Info node `(gnus)Fancy Mail Splitting' for more details."
 
 (defun nnmail-write-region (start end filename &optional append visit lockname)
   "Do a `write-region', and then set the file modes."
-  (let ((file-name-coding-system nnmail-pathname-coding-system)
-       (pathname-coding-system nnmail-pathname-coding-system))
+  (let ((file-name-coding-system nnmail-pathname-coding-system))
     (write-region-as-coding-system
      nnmail-file-coding-system start end filename append visit lockname)
     (set-file-modes filename nnmail-default-file-modes)))
@@ -1962,14 +1975,12 @@ See the Info node `(gnus)Fancy Mail Splitting' for more details."
   (with-output-to-temp-buffer "*nnmail split history*"
     (with-current-buffer standard-output
       (fundamental-mode))              ; for Emacs 20.4+
-    (let ((history nnmail-split-history)
-         elem)
-      (while (setq elem (pop history))
+      (dolist (elem nnmail-split-history)
        (princ (mapconcat (lambda (ga)
                            (concat (car ga) ":" (int-to-string (cdr ga))))
                          elem
                          ", "))
-       (princ "\n")))))
+       (princ "\n"))))
 
 (defun nnmail-purge-split-history (group)
   "Remove all instances of GROUP from `nnmail-split-history'."