*** empty log message ***
[gnus] / lisp / nnmail.el
index d1b0a18..5c0cd70 100644 (file)
@@ -1,5 +1,5 @@
 ;;; nnmail.el --- mail support functions for the Gnus mail backends
-;; Copyright (C) 1995,96 Free Software Foundation, Inc.
+;; Copyright (C) 1995,96,97,98 Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@ifi.uio.no>
 ;; Keywords: news, mail
 
 ;;; Code:
 
+(eval-when-compile (require 'cl))
+
 (require 'nnheader)
 (require 'timezone)
 (require 'message)
-(eval-when-compile (require 'cl))
 (require 'custom)
 
-(defgroup gnus-mail nil
-  "Mailreading.."
+(eval-and-compile
+  (autoload 'gnus-error "gnus-util")
+  (autoload 'gnus-buffer-live-p "gnus-util")
+  (autoload 'gnus-encode-coding-string "gnus-ems"))
+
+(defgroup nnmail nil
+  "Reading mail with Gnus."
   :group 'gnus)
 
+(defgroup nnmail-retrieve nil
+  "Retrieving new mail."
+  :group 'nnmail)
+
+(defgroup nnmail-prepare nil
+  "Preparing (or mangling) new mail after retrival."
+  :group 'nnmail)
+
+(defgroup nnmail-duplicate nil
+  "Handling of duplicate mail messages."
+  :group 'nnmail)
+
+(defgroup nnmail-split nil
+  "Organizing the incomming mail in folders."
+  :group 'nnmail)
+
+(defgroup nnmail-files nil
+  "Mail files."
+  :group 'gnus-files
+  :group 'nnmail)
+
+(defgroup nnmail-expire nil
+  "Expiring old mail."
+  :group 'nnmail)
+
+(defgroup nnmail-procmail nil
+  "Interfacing with procmail and other mail agents."
+  :group 'nnmail)
+
+(defgroup nnmail-various nil
+  "Various mail options."
+  :group 'nnmail)
+
 (defcustom nnmail-split-methods
   '(("mail.misc" ""))
-  "Incoming mail will be split according to this variable.
+  "*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
@@ -62,7 +101,7 @@ mail belongs in that group.
 The last element should always have \"\" as the regexp.
 
 This variable can also have a function as its value."
-  :group 'gnus-mail
+  :group 'nnmail-split
   :type '(choice (repeat :tag "Alist" (group (string :tag "Name") regexp))
                 (function-item nnmail-split-fancy)
                 (function :tag "Other")))
@@ -71,27 +110,30 @@ This variable can also have a function as its value."
 (defcustom nnmail-crosspost t
   "If non-nil, do crossposting if several split methods match the mail.
 If nil, the first match found will be used."
-  :group 'gnus-mail
+  :group 'nnmail-split
   :type 'boolean)
 
 ;; Added by gord@enci.ucalgary.ca (Gordon Matzigkeit).
 (defcustom nnmail-keep-last-article nil
-  "If non-nil, nnmail will never delete the last expired article in a directory.  
+  "If non-nil, nnmail will never delete/move a group's last article.
+It can be marked expirable, so it will be deleted when it is no longer last.
+
 You may need to set this variable if other programs are putting
 new mail into folder numbers that Gnus has marked as expired."
-  :group 'gnus-mail
+  :group 'nnmail-procmail
+  :group 'nnmail-various
   :type 'boolean)
 
 (defcustom nnmail-use-long-file-names nil
   "If non-nil the mail backends will use long file and directory names.
 If nil, groups like \"mail.misc\" will end up in directories like
 \"mail/misc/\"."
-  :group 'gnus-mail
+  :group 'nnmail-files
   :type 'boolean)
 
 (defcustom nnmail-default-file-modes 384
   "Set the mode bits of all new mail files to this integer."
-  :group 'gnus-mail
+  :group 'nnmail-files
   :type 'integer)
 
 (defcustom nnmail-expiry-wait 7
@@ -99,7 +141,7 @@ If nil, groups like \"mail.misc\" will end up in directories like
 This variable can either be a number (which will be interpreted as a
 number of days) -- this doesn't have to be an integer.  This variable
 can also be `immediate' and `never'."
-  :group 'gnus-mail
+  :group 'nnmail-expire
   :type '(choice (const immediate)
                 (integer :tag "days")
                 (const never)))
@@ -119,63 +161,71 @@ Eg.:
               ((string-match \"junk\" newsgroup) 1)
              ((string-match \"important\" newsgroup) 'never)
              (t 7))))"
-  :group 'gnus-mail
+  :group 'nnmail-expire
   :type '(choice (const :tag "nnmail-expiry-wait" nil)
                 (function :format "%v" nnmail-)))
 
-(defcustom nnmail-spool-file 
+(defcustom nnmail-cache-accepted-message-ids nil
+  "If non-nil, put Message-IDs of Gcc'd articles into the duplicate cache."
+  :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.
+  "*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 'gnus-mail
+  :group 'nnmail-files
   :type 'file)
 
 (defcustom nnmail-crash-box "~/.gnus-crash-box"
   "File where Gnus will store mail while processing it."
-  :group 'gnus-mail
+  :group 'nnmail-files
   :type 'file)
 
 (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."
-  :group 'gnus-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 'gnus-mail
+  :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 'gnus-mail
+  :group 'nnmail-procmail
   :type 'regexp)
 
 (defcustom nnmail-resplit-incoming nil
   "*If non-nil, re-split incoming procmail sorted mail."
-  :group 'gnus-mail
+  :group 'nnmail-procmail
   :type 'boolean)
 
 (defcustom nnmail-delete-file-function 'delete-file
   "Function called to delete files in some mail backends."
-  :group 'gnus-mail
+  :group 'nnmail-files
   :type 'function)
 
-(defcustom nnmail-crosspost-link-function 'add-name-to-file
-  "Function called to create a copy of a file.
+(defcustom nnmail-crosspost-link-function
+  (if (string-match "windows-nt\\|emx" (format "%s" system-type))
+      'copy-file
+    'add-name-to-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."
-  :group 'gnus-mail
+  :group 'nnmail-files
   :type '(radio (function-item add-name-to-file)
                (function-item copy-file)
                (function :tag "Other")))
@@ -187,19 +237,20 @@ 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 'gnus-mail
+  :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 'gnus-mail
+  :group 'nnmail-retrieve
   :type 'boolean)
 
-(defcustom nnmail-read-incoming-hook 
+(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.
+  "*Hook that will be run after the incoming mail has been transferred.
 The incoming mail is moved from `nnmail-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
@@ -208,13 +259,13 @@ running (\"xwatch\", etc.)
 
 Eg.
 
-\(add-hook 'nnmail-read-incoming-hook 
+\(add-hook 'nnmail-read-incoming-hook
           (lambda ()
-            (start-process \"mailsend\" nil 
+            (start-process \"mailsend\" nil
                            \"/local/bin/mailsend\" \"read\" \"mbox\")))
 
 If you have xwatch running, this will alert it that mail has been
-read.  
+read.
 
 If you use `display-time', you could use something like this:
 
@@ -224,43 +275,44 @@ If you use `display-time', you could use something like this:
            ;; the flag that says you have mail.
            (when (eq (process-status \"display-time\") 'run)
              (display-time-filter display-time-process \"\"))))"
-  :group 'gnus-mail
+  :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."
-  :group 'gnus-mail
+  :group 'nnmail-prepare
   :type 'hook)
 
 (defcustom nnmail-prepare-incoming-header-hook nil
   "Hook called narrowed to the headers of each message.
 This can be used to remove excessive spaces (and stuff like
 that) from the headers before splitting and saving the messages."
-  :group 'gnus-mail
+  :group 'nnmail-prepare
   :type 'hook)
 
 (defcustom nnmail-prepare-incoming-message-hook nil
   "Hook called narrowed to each message."
-  :group 'gnus-mail
+  :group 'nnmail-prepare
   :type 'hook)
 
 (defcustom nnmail-list-identifiers nil
-  "Regexp that match list identifiers to be removed.
+  "Regexp that matches list identifiers to be removed.
 This can also be a list of regexps."
-  :group 'gnus-mail
-  :type '(choice regexp
-                (repeat regexp)))
+  :group 'nnmail-prepare
+  :type '(choice (const :tag "none" nil)
+                (regexp :value ".*")
+                (repeat :value (".*") regexp)))
 
 (defcustom nnmail-pre-get-new-mail-hook nil
   "Hook called just before starting to handle new incoming mail."
-  :group 'gnus-mail
+  :group 'nnmail-retrieve
   :type 'hook)
 
 (defcustom nnmail-post-get-new-mail-hook nil
   "Hook called just after finishing handling new incoming mail."
-  :group 'gnus-mail
+  :group 'nnmail-retrieve
   :type 'hook)
 
 (defcustom nnmail-split-hook nil
@@ -268,13 +320,15 @@ This can also be a list of regexps."
 The functions in this hook are free to modify the buffer
 contents in any way they choose -- the buffer contents are
 discarded after running the split process."
-  :group 'gnus-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 when reading incoming mail."
-  :group 'gnus-mail
+  "*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")))
 
@@ -282,7 +336,7 @@ discarded after running the split process."
   "*The number of the articles which indicates a large newsgroup.
 If the number of the articles is greater than the value, verbose
 messages will be shown to indicate the current status."
-  :group 'gnus-mail
+  :group 'nnmail-various
   :type 'integer)
 
 (defcustom nnmail-split-fancy "mail.misc"
@@ -292,14 +346,14 @@ 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 following:
 
-GROUP: Mail will be stored in GROUP (a string).  
+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.
 
 \(| SPLIT...): Process each SPLIT expression until one of them matches.
   A SPLIT expression is said to match if it will cause the mail
-  message to be stored in one or more groups.  
+  message to be stored in one or more groups.
 
 \(& SPLIT...): Process each SPLIT expression.
 
@@ -309,7 +363,7 @@ GROUP: Mail will be stored in GROUP (a string).
 
 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.
+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
 as specified in `nnmail-split-abbrev-alist'.
@@ -338,34 +392,39 @@ Example:
             (any \"larsi@ifi\\\\.uio\\\\.no\" \"people.Lars Magne Ingebrigtsen\"))
          ;; Unmatched mail goes to the catch all group.
          \"misc.misc\"))"
-  :group 'gnus-mail
+  :group 'nnmail-split
   ;; Sigh!
   :type 'sexp)
 
 (defcustom nnmail-split-abbrev-alist
   '((any . "from\\|to\\|cc\\|sender\\|apparently-to\\|resent-from\\|resent-to\\|resent-cc")
-    (mail . "mailer-daemon\\|postmaster\\|uucp"))
-  "Alist of abbreviations allowed in `nnmail-split-fancy'."
-  :group 'gnus-mail
+    (mail . "mailer-daemon\\|postmaster\\|uucp")
+    (to . "to\\|cc\\|apparently-to\\|resent-to\\|resent-cc")
+    (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'."
+  :group 'nnmail-split
   :type '(repeat (cons :format "%v" symbol regexp)))
 
 (defcustom nnmail-delete-incoming nil
   "*If non-nil, the mail backends will delete incoming files after
 splitting."
-  :group 'gnus-mail
+  :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
 performed."
-  :group 'gnus-mail
+  :group 'nnmail-duplicate
   :type '(choice (const :tag "disable" nil)
                 (integer :format "%v")))
 
 (defcustom nnmail-message-id-cache-file "~/.nnmail-cache"
   "*The file name of the nnmail Message-ID cache."
-  :group 'gnus-mail
+  :group 'nnmail-duplicate
+  :group 'nnmail-files
   :type 'file)
 
 (defcustom nnmail-treat-duplicates 'warn
@@ -378,7 +437,7 @@ and `delete', which means that nnmail will delete duplicated mails.
 This variable can also be a function.  It will be called from a buffer
 narrowed to the article in question with the Message-ID as a
 parameter.  It should return nil, `warn' or `delete'."
-  :group 'gnus-mail
+  :group 'nnmail-duplicate
   :type '(choice (const :tag "off" nil)
                 (const warn)
                 (const delete)))
@@ -388,6 +447,8 @@ parameter.  It should return nil, `warn' or `delete'."
 (defvar nnmail-split-history nil
   "List of group/article elements that say where the previous split put messages.")
 
+(defvar nnmail-current-spool nil)
+
 (defvar nnmail-pop-password nil
   "*Password to use when reading mail from a POP server, if required.")
 
@@ -417,6 +478,9 @@ parameter.  It should return nil, `warn' or `delete'."
 (defun nnmail-request-post (&optional server)
   (mail-send-and-exit nil))
 
+(defvar nnmail-file-coding-system 'raw-text
+  "Coding system used in nnmail.")
+
 (defun nnmail-find-file (file)
   "Insert FILE in server buffer safely."
   (set-buffer nntp-server-buffer)
@@ -424,21 +488,33 @@ parameter.  It should return nil, `warn' or `delete'."
   (let ((format-alist nil)
         (after-insert-file-functions nil))
     (condition-case ()
-       (progn (insert-file-contents file) t)
+       (let ((coding-system-for-read nnmail-file-coding-system)
+             (pathname-coding-system 'binary))
+         (insert-file-contents file)
+         t)
       (file-error nil))))
 
+(defvar nnmail-pathname-coding-system
+  'iso-8859-1
+  "*Coding system for pathname.")
+
 (defun nnmail-group-pathname (group dir &optional file)
   "Make pathname for GROUP."
   (concat
    (let ((dir (file-name-as-directory (expand-file-name dir))))
+     (setq group (nnheader-translate-file-chars group))
      ;; If this directory exists, we use it directly.
-     (if (or nnmail-use-long-file-names 
+     (if (or nnmail-use-long-file-names
             (file-directory-p (concat dir group)))
         (concat dir group "/")
        ;; If not, we translate dots into slashes.
-       (concat dir (nnheader-replace-chars-in-string group ?. ?/) "/")))
+       (concat dir
+              (gnus-encode-coding-string
+               (nnheader-replace-chars-in-string group ?. ?/)
+               nnmail-pathname-coding-system)
+              "/")))
    (or file "")))
-  
+
 (defun nnmail-date-to-time (date)
   "Convert DATE into time."
   (condition-case ()
@@ -450,7 +526,8 @@ parameter.  It should return nil, `warn' or `delete'."
                       (list
                        (aref t1 2) (aref t1 1) (aref t1 0)
                        (aref d1 2) (aref d1 1) (aref d1 0)
-                       (aref d1 4)))))
+                       (number-to-string
+                        (* 60 (timezone-zone-to-minute (aref d1 4))))))))
     ;; If we get an error, then we just return a 0 time.
     (error (list 0 0))))
 
@@ -484,18 +561,17 @@ parameter.  It should return nil, `warn' or `delete'."
 (defun nnmail-move-inbox (inbox)
   "Move INBOX to `nnmail-crash-box'."
   (if (not (file-writable-p nnmail-crash-box))
-      (gnus-error 1 "Can't write to crash box %s.  Not moving mail."
+      (gnus-error 1 "Can't write to crash box %s.  Not moving mail"
                  nnmail-crash-box)
     ;; If the crash box exists and is empty, we delete it.
     (when (and (file-exists-p nnmail-crash-box)
               (zerop (nnheader-file-size (file-truename nnmail-crash-box))))
       (delete-file nnmail-crash-box))
-    (let ((inbox (file-truename (expand-file-name inbox)))
-         (tofile (file-truename (expand-file-name nnmail-crash-box)))
-         movemail popmail errors)
-      (if (setq popmail (string-match
-                        "^po:" (file-name-nondirectory inbox)))
-         (setq inbox (file-name-nondirectory inbox))
+    (let ((tofile (file-truename (expand-file-name nnmail-crash-box)))
+         (popmail (string-match "^po:" inbox))
+         movemail errors result)
+      (unless popmail
+       (setq inbox (file-truename (expand-file-name inbox)))
        (setq movemail t)
        ;; On some systems, /usr/spool/mail/foo is a directory
        ;; and the actual inbox is /usr/spool/mail/foo/foo.
@@ -506,14 +582,16 @@ parameter.  It should return nil, `warn' or `delete'."
          nil
        (if popmail
            (progn
-             (setq nnmail-internal-password nnmail-pop-password)
+             (when (and nnmail-pop-password
+                        (not nnmail-internal-password))
+               (setq nnmail-internal-password nnmail-pop-password))
              (when (and nnmail-pop-password-required
-                        (not nnmail-pop-password))
+                        (not nnmail-internal-password))
                (setq nnmail-internal-password
                      (nnmail-read-passwd
                       (format "Password for %s: "
                               (substring inbox (+ popmail 3))))))
-             (message "Getting mail from post office ..."))
+             (message "Getting mail from the post office..."))
          (when (or (and (file-exists-p tofile)
                         (/= 0 (nnheader-file-size tofile)))
                    (and (file-exists-p inbox)
@@ -521,7 +599,7 @@ parameter.  It should return nil, `warn' or `delete'."
            (message "Getting mail from %s..." inbox)))
        ;; Set TOFILE if have not already done so, and
        ;; rename or copy the file INBOX to TOFILE if and as appropriate.
-       (cond 
+       (cond
         ((file-exists-p tofile)
          ;; The crash box exists already.
          t)
@@ -537,23 +615,34 @@ parameter.  It should return nil, `warn' or `delete'."
              (save-excursion
                (setq errors (generate-new-buffer " *nnmail loss*"))
                (buffer-disable-undo errors)
-               (let ((default-directory "/"))
-                 (if (nnheader-functionp nnmail-movemail-program)
-                     (funcall nnmail-movemail-program inbox tofile)
-                   (apply 
-                    'call-process
-                    (append
-                     (list
-                      (expand-file-name nnmail-movemail-program
-                                        exec-directory)
-                      nil errors nil inbox tofile)
-                     (when nnmail-internal-password
-                       (list nnmail-internal-password))))))
-               (if (not (buffer-modified-p errors))
+               (if (nnheader-functionp nnmail-movemail-program)
+                   (condition-case err
+                       (progn
+                         (funcall nnmail-movemail-program inbox tofile)
+                         (setq result 0))
+                     (error
+                      (save-excursion
+                        (set-buffer errors)
+                        (insert (prin1-to-string err))
+                        (setq result 255))))
+                 (let ((default-directory "/"))
+                   (setq result
+                         (apply
+                          'call-process
+                          (append
+                           (list
+                            (expand-file-name
+                             nnmail-movemail-program exec-directory)
+                            nil errors nil inbox tofile)
+                           (when nnmail-internal-password
+                             (list nnmail-internal-password)))))))
+               (if (and (not (buffer-modified-p errors))
+                        (zerop result))
                    ;; No output => movemail won
                    (progn
                      (unless popmail
-                       (set-file-modes tofile nnmail-default-file-modes))
+                       (when (file-exists-p tofile)
+                         (set-file-modes tofile nnmail-default-file-modes)))
                      (push inbox nnmail-moved-inboxes))
                  (set-buffer errors)
                  ;; There may be a warning about older revisions.  We
@@ -562,7 +651,8 @@ parameter.  It should return nil, `warn' or `delete'."
                  (if (search-forward "older revision" nil t)
                      (progn
                        (unless popmail
-                         (set-file-modes tofile nnmail-default-file-modes))
+                         (when (file-exists-p tofile)
+                           (set-file-modes tofile nnmail-default-file-modes)))
                        (push inbox nnmail-moved-inboxes))
                    ;; Probably a real error.
                    (subst-char-in-region (point-min) (point-max) ?\n ?\  )
@@ -573,8 +663,8 @@ parameter.  It should return nil, `warn' or `delete'."
                    (when (looking-at "movemail: ")
                      (delete-region (point-min) (match-end 0)))
                    (unless (yes-or-no-p
-                            (format "movemail: %s.  Continue? "
-                                    (buffer-string)))
+                            (format "movemail: %s (%d return).  Continue? "
+                                    (buffer-string) result))
                      (error "%s" (buffer-string)))
                    (setq tofile nil)))))))
        (message "Getting mail from %s...done" inbox)
@@ -591,7 +681,7 @@ nn*-request-list should have been called before calling this function."
     (save-excursion
       (set-buffer nntp-server-buffer)
       (goto-char (point-min))
-      (while (re-search-forward 
+      (while (re-search-forward
              "^\\([^ \t]+\\)[ \t]+\\([0-9]+\\)[ \t]+\\([0-9]+\\)" nil t)
        ;; We create an alist with `(GROUP (LOW . HIGH))' elements.
        (push (list (match-string 1)
@@ -600,11 +690,16 @@ nn*-request-list should have been called before calling this function."
              group-assoc)))
     group-assoc))
 
+(defvar nnmail-active-file-coding-system
+  'iso-8859-1
+  "*Coding system for active file.")
+
 (defun nnmail-save-active (group-assoc file-name)
   "Save GROUP-ASSOC in ACTIVE-FILE."
-  (when file-name
-    (nnheader-temp-write file-name
-      (nnmail-generate-active group-assoc))))
+  (let ((coding-system-for-write nnmail-active-file-coding-system))
+    (when file-name
+      (nnheader-temp-write file-name
+       (nnmail-generate-active group-assoc)))))
 
 (defun nnmail-generate-active (alist)
   "Generate an active file from group-alist ALIST."
@@ -630,7 +725,7 @@ is a spool.  If not using procmail, return GROUP."
          (let ((procmail-group (substring (expand-file-name file)
                                           (match-beginning 1)
                                           (match-end 1))))
-           (if group 
+           (if group
                (if (string-equal group procmail-group)
                    group
                  nil)
@@ -641,8 +736,8 @@ is a spool.  If not using procmail, return GROUP."
 (defun nnmail-process-babyl-mail-format (func artnum-func)
   (let ((case-fold-search t)
        start message-id content-length do-search end)
-    (goto-char (point-min))
     (while (not (eobp))
+      (goto-char (point-min))
       (re-search-forward
        "\f\n0, *unseen,+\n\\(\\*\\*\\* EOOH \\*\\*\\*\n\\)?" nil t)
       (goto-char (match-end 0))
@@ -655,16 +750,21 @@ is a spool.  If not using procmail, return GROUP."
             (search-forward-regexp "^[^:]*\\( .*\\|\\)$" nil t)
             (search-forward "\1f\f"))
         (point)))
+      ;; Unquote the ">From " line, if any.
+      (goto-char (point-min))
+      (when (looking-at ">From ")
+       (replace-match "X-From-Line: ") )
       (run-hooks 'nnmail-prepare-incoming-header-hook)
-      (widen)
+      (goto-char (point-max))
       ;; Find the Message-ID header.
       (save-excursion
-       (if (re-search-backward "^Message-ID:[ \t]*\\(<[^>]*>\\)" nil t)
+       (if (re-search-backward
+            "^Message-ID[ \t]*:[ \n\t]*\\(<[^>]*>\\)" nil t)
            (setq message-id (buffer-substring (match-beginning 1)
                                               (match-end 1)))
          ;; There is no Message-ID here, so we create one.
          (save-excursion
-           (when (re-search-backward "^Message-ID:" nil t)
+           (when (re-search-backward "^Message-ID[ \t]*:" nil t)
              (beginning-of-line)
              (insert "Original-")))
          (forward-line -1)
@@ -672,10 +772,10 @@ is a spool.  If not using procmail, return GROUP."
                  "\n")))
       ;; Look for a Content-Length header.
       (if (not (save-excursion
-                (and (re-search-backward 
+                (and (re-search-backward
                       "^Content-Length:[ \t]*\\([0-9]+\\)" start t)
                      (setq content-length (string-to-int
-                                           (buffer-substring 
+                                           (buffer-substring
                                             (match-beginning 1)
                                             (match-end 1))))
                      ;; We destroy the header, since none of
@@ -684,6 +784,7 @@ is a spool.  If not using procmail, return GROUP."
                      ;; a (possibly) faulty header.
                      (progn (insert "X-") t))))
          (setq do-search t)
+       (widen)
        (if (or (= (+ (point) content-length) (point-max))
                (save-excursion
                  (goto-char (+ (point) content-length))
@@ -692,8 +793,9 @@ is a spool.  If not using procmail, return GROUP."
              (goto-char (+ (point) content-length))
              (setq do-search nil))
          (setq do-search t)))
+      (widen)
       ;; Go to the beginning of the next article - or to the end
-      ;; of the buffer.  
+      ;; of the buffer.
       (when do-search
        (if (re-search-forward "^\1f" nil t)
            (goto-char (match-beginning 0))
@@ -707,7 +809,7 @@ is a spool.  If not using procmail, return GROUP."
          (setq end (point-max))))
       (goto-char end))))
 
-(defun nnmail-search-unix-mail-delim ()
+(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
   ;; brain-dead Unix mbox format:
@@ -729,9 +831,9 @@ is a spool.  If not using procmail, return GROUP."
                           (= (following-char) ?\n)))
                     (save-excursion
                       (forward-line 1)
-                      (while (looking-at ">From ")
+                      (while (looking-at ">From \\|From ")
                         (forward-line 1))
-                      (looking-at "[^ \t:]+[ \t]*:")))
+                      (looking-at "[^ \n\t:]+[ \n\t]*:")))
            (setq found 'yes)))))
     (beginning-of-line)
     (eq found 'yes)))
@@ -758,9 +860,9 @@ is a spool.  If not using procmail, return GROUP."
                           (= (following-char) ?\n)))
                     (save-excursion
                       (forward-line 1)
-                      (while (looking-at ">From ")
+                      (while (looking-at ">From \\|From ")
                         (forward-line 1))
-                      (looking-at "[^ \t:]+[ \t]*:")))
+                      (looking-at "[^ \n\t:]+[ \n\t]*:")))
            (setq found 'yes)))))
     (beginning-of-line)
     (eq found 'yes)))
@@ -772,28 +874,30 @@ is a spool.  If not using procmail, return GROUP."
     (if (not (and (re-search-forward "^From " nil t)
                  (goto-char (match-beginning 0))))
        ;; Possibly wrong format?
-       (error "Error, unknown mail format! (Possibly corrupted.)")
+       (progn
+         (pop-to-buffer (find-file-noselect nnmail-current-spool))
+         (error "Error, unknown mail format! (Possibly corrupted.)"))
       ;; Carry on until the bitter end.
       (while (not (eobp))
        (setq start (point)
              end nil)
        ;; Find the end of the head.
        (narrow-to-region
-        start 
+        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.
           (while (and (looking-at "From \\|[^ \t]+:")
                       (not (eobp)))
-            (forward-line 1)
-            (point))))
+            (forward-line 1))
+          (point)))
        ;; Find the Message-ID header.
        (goto-char (point-min))
-       (if (re-search-forward "^Message-ID:[ \t]*\\(<[^>]+>\\)" nil t)
+       (if (re-search-forward "^Message-ID[ \t]*:[ \n\t]*\\(<[^>]+>\\)" nil t)
            (setq message-id (match-string 1))
          (save-excursion
-           (when (re-search-forward "^Message-ID:" nil t)
+           (when (re-search-forward "^Message-ID[ \t]*:" nil t)
              (beginning-of-line)
              (insert "Original-")))
          ;; There is no Message-ID here, so we create one.
@@ -805,7 +909,7 @@ is a spool.  If not using procmail, return GROUP."
                  "^Content-Length:[ \t]*\\([0-9]+\\)" nil t))
            (setq content-length nil)
          (setq content-length (string-to-int (match-string 1)))
-         ;; We destroy the header, since none of the backends ever 
+         ;; 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.
          (beginning-of-line)
@@ -835,7 +939,7 @@ is a spool.  If not using procmail, return GROUP."
                (t (setq end nil))))
        (if end
            (goto-char end)
-         ;; No Content-Length, so we find the beginning of the next 
+         ;; No Content-Length, so we find the beginning of the next
          ;; article or the end of the buffer.
          (goto-char head-end)
          (or (nnmail-search-unix-mail-delim)
@@ -857,28 +961,30 @@ is a spool.  If not using procmail, return GROUP."
     (if (not (and (re-search-forward delim nil t)
                  (forward-line 1)))
        ;; Possibly wrong format?
-       (error "Error, unknown mail format! (Possibly corrupted.)")
+       (progn
+         (pop-to-buffer (find-file-noselect nnmail-current-spool))
+         (error "Error, unknown mail format! (Possibly corrupted.)"))
       ;; Carry on until the bitter end.
       (while (not (eobp))
        (setq start (point))
        ;; Find the end of the head.
        (narrow-to-region
-        start 
+        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.
           (while (and (looking-at "From \\|[^ \t]+:")
                       (not (eobp)))
-            (forward-line 1)
-            (point))))
+            (forward-line 1))
+          (point)))
        ;; Find the Message-ID header.
        (goto-char (point-min))
-       (if (re-search-forward "^Message-ID:[ \t]*\\(<[^>]+>\\)" nil t)
+       (if (re-search-forward "^Message-ID[ \t]*:[ \n\t]*\\(<[^>]+>\\)" nil t)
            (setq message-id (match-string 1))
          ;; There is no Message-ID here, so we create one.
          (save-excursion
-           (when (re-search-backward "^Message-ID:" nil t)
+           (when (re-search-backward "^Message-ID[ \t]*:" nil t)
              (beginning-of-line)
              (insert "Original-")))
          (forward-line 1)
@@ -923,7 +1029,7 @@ FUNC will be called with the buffer narrowed to each mail."
        (save-excursion (run-hooks 'nnmail-prepare-incoming-hook))
        ;; Handle both babyl, MMDF and unix mail formats, since movemail will
        ;; use the former when fetching from a mailbox, the latter when
-       ;; fetches from a file.
+       ;; fetching from a file.
        (cond ((or (looking-at "\^L")
                   (looking-at "BABYL OPTIONS:"))
               (nnmail-process-babyl-mail-format func artnum-func))
@@ -935,15 +1041,15 @@ FUNC will be called with the buffer narrowed to each mail."
        (funcall exit-func))
       (kill-buffer (current-buffer)))))
 
-;; Mail crossposts suggested by Brian Edmonds <edmonds@cs.ubc.ca>. 
 (defun nnmail-article-group (func)
   "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)
        (obuf (current-buffer))
        (beg (point-min))
-       end group-art method)
-    (if (and (sequencep methods) (= (length methods) 1))
+       end group-art method regrepp)
+    (if (and (sequencep methods)
+            (= (length methods) 1))
        ;; If there is only just one group to put everything in, we
        ;; just return a list with just this one method in.
        (setq group-art
@@ -967,47 +1073,71 @@ FUNC will be called with the group name to determine the article number."
                 (fboundp nnmail-split-methods))
            (let ((split
                   (condition-case nil
+                      ;; `nnmail-split-methods' is a function, so we
+                      ;; just call this function here and use the
+                      ;; result.
                       (or (funcall nnmail-split-methods)
                           '("bogus"))
                     (error
-                     (message 
+                     (message
                       "Error in `nnmail-split-methods'; using `bogus' mail group")
                      (sit-for 1)
                      '("bogus")))))
-             (unless (equal split '(junk))
-               ;; `nnmail-split-methods' is a function, so we just call 
-               ;; this function here and use the result.
+             (setq split (remove-duplicates split :test 'equal))
+             ;; The article may be "cross-posted" to `junk'.  What
+             ;; to do?  Just remove the `junk' spec.  Don't really
+             ;; see anything else to do...
+             (let (elem)
+               (while (setq elem (car (memq 'junk split)))
+                 (setq split (delq elem split))))
+             (when split
                (setq group-art
                      (mapcar
                       (lambda (group) (cons group (funcall func group)))
                       split))))
          ;; Go through the split methods to find a match.
-         (while (and methods (or nnmail-crosspost (not group-art)))
+         (while (and methods
+                     (or nnmail-crosspost
+                         (not group-art)))
            (goto-char (point-max))
-           (setq method (pop methods))
+           (setq method (pop methods)
+                 regrepp nil)
            (if (or methods
                    (not (equal "" (nth 1 method))))
                (when (and
                       (ignore-errors
                         (if (stringp (nth 1 method))
-                            (re-search-backward (cadr method) nil t)
+                            (progn
+                              (setq regrepp
+                                    (string-match "\\\\[0-9&]" (car method)))
+                              (re-search-backward (cadr method) nil t))
                           ;; Function to say whether this is a match.
                           (funcall (nth 1 method) (car method))))
-                      ;; Don't enter the article into the same 
+                      ;; Don't enter the article into the same
                       ;; group twice.
                       (not (assoc (car method) group-art)))
-                 (push (cons (car method) (funcall func (car method)))
+                 (push (cons (if regrepp
+                                 (replace-match
+                                  (car method) nil nil (car method))
+                               (car method))
+                             (funcall func (car method)))
                        group-art))
-             ;; This is the final group, which is used as a 
+             ;; This is the final group, which is used as a
              ;; catch-all.
              (unless group-art
-               (setq group-art 
+               (setq group-art
                      (list (cons (car method)
                                  (funcall func (car method)))))))))
        ;; See whether the split methods returned `junk'.
        (if (equal group-art '(junk))
            nil
-         (nreverse (delq 'junk group-art)))))))
+         ;; The article may be "cross-posted" to `junk'.  What
+         ;; to do?  Just remove the `junk' spec.  Don't really
+         ;; see anything else to do...
+         (let (elem)
+           (while (setq elem (car (memq 'junk group-art)))
+             (setq group-art (delq elem group-art)))
+           (nreverse group-art)))))))
 
 (defun nnmail-insert-lines ()
   "Insert how many lines there are in the body of the mail.
@@ -1037,7 +1167,10 @@ Return the number of characters in the body."
                       (progn (forward-line 1) (point))))
       (insert (format "Xref: %s" (system-name)))
       (while group-alist
-       (insert (format " %s:%d" (caar group-alist) (cdar group-alist)))
+       (insert (format " %s:%d"
+                       (gnus-encode-coding-string (caar group-alist)
+                                             nnmail-pathname-coding-system)
+                       (cdar group-alist)))
        (setq group-alist (cdr group-alist)))
       (insert "\n"))))
 
@@ -1047,7 +1180,7 @@ Return the number of characters in the body."
   "Remove excessive whitespace from all headers."
   (goto-char (point-min))
   (while (re-search-forward "^\\([^ :]+: \\) +" nil t)
-    (replace-match "\\1" t t)))
+    (replace-match "\\1" t)))
 
 (defun nnmail-remove-list-identifiers ()
   "Remove list identifiers from Subject headers."
@@ -1056,7 +1189,7 @@ Return the number of characters in the body."
     (when regexp
       (goto-char (point-min))
       (when (re-search-forward
-            (concat "Subject: +\\(Re: +\\)?\\(" regexp "\\) *")
+            (concat "^Subject: +\\(Re: +\\)?\\(" regexp "\\) *")
             nil t)
        (delete-region (match-beginning 2) (match-end 0))))))
 
@@ -1066,7 +1199,6 @@ Return the number of characters in the body."
 
 ;;; Utility functions
 
-;; Written by byer@mv.us.adobe.com (Scott Byer).
 (defun nnmail-make-complex-temp-name (prefix)
   (let ((newname (make-temp-name prefix))
        (newprefix prefix))
@@ -1119,7 +1251,7 @@ See the documentation for the variable `nnmail-split-fancy' for documentation."
 
    ;; Builtin : operation.
    ((eq (car split) ':)
-    (nnmail-split-it (eval (cdr split))))
+    (nnmail-split-it (save-excursion (eval (cdr split)))))
 
    ;; Check the cache for the regexp for this split.
    ;; FIX FIX FIX could avoid calling assq twice here
@@ -1206,15 +1338,15 @@ See the documentation for the variable `nnmail-split-fancy' for documentation."
   (if (null nnmail-spool-file)
       ;; No spool file whatsoever.
       nil
-    (let* ((procmails 
+    (let* ((procmails
            ;; If procmail is used to get incoming mail, the files
            ;; are stored in this directory.
            (and (file-exists-p nnmail-procmail-directory)
                 (or (eq nnmail-spool-file 'procmail)
                     nnmail-use-procmail)
-                (directory-files 
-                 nnmail-procmail-directory 
-                 t (concat (if group (concat "^" group) "")
+                (directory-files
+                 nnmail-procmail-directory
+                 t (concat (if group (concat "^" (regexp-quote group)) "")
                            nnmail-procmail-suffix "$"))))
           (p procmails)
           (crash (when (and (file-exists-p nnmail-crash-box)
@@ -1223,13 +1355,13 @@ See the documentation for the variable `nnmail-split-fancy' for documentation."
                                0))
                    (list nnmail-crash-box))))
       ;; Remove any directories that inadvertently match the procmail
-      ;; suffix, which might happen if the suffix is "". 
+      ;; suffix, which might happen if the suffix is "".
       (while p
        (when (file-directory-p (car p))
          (setq procmails (delete (car p) procmails)))
        (setq p (cdr p)))
       ;; Return the list of spools.
-      (append 
+      (append
        crash
        (cond ((and group
                   (or (eq nnmail-spool-file 'procmail)
@@ -1241,44 +1373,45 @@ See the documentation for the variable `nnmail-split-fancy' for documentation."
              nil)
             ((listp nnmail-spool-file)
              (nconc
-              (apply 
+              (apply
                'nconc
-               (mapcar 
+               (mapcar
                 (lambda (file)
-                  (if (file-directory-p file)
+                  (if (and (not (string-match "^po:" file))
+                           (file-directory-p file))
                       (nnheader-directory-regular-files file)
                     (list file)))
                 nnmail-spool-file))
               procmails))
-            ((and (stringp nnmail-spool-file)
-                  (not (file-directory-p nnmail-spool-file)))
-             (cons nnmail-spool-file procmails))
-            ((and (stringp nnmail-spool-file)
-                  (file-directory-p nnmail-spool-file))
-             (nconc
-              (nnheader-directory-regular-files nnmail-spool-file)
-              procmails))
+            ((stringp nnmail-spool-file)
+             (if (and (not (string-match "^po:" nnmail-spool-file))
+                      (file-directory-p nnmail-spool-file))
+                 (nconc
+                  (nnheader-directory-regular-files nnmail-spool-file)
+                  procmails)
+               (cons nnmail-spool-file procmails)))
             ((eq nnmail-spool-file 'pop)
              (cons (format "po:%s" (user-login-name)) procmails))
             (t
              procmails))))))
 
-;; Activate a backend only if it isn't already activated. 
-;; If FORCE, re-read the active file even if the backend is 
+;; Activate a backend only if it isn't already activated.
+;; If FORCE, re-read the active file even if the backend is
 ;; already activated.
 (defun nnmail-activate (backend &optional force)
+  (nnheader-init-server-buffer)
   (let (file timestamp file-time)
     (if (or (not (symbol-value (intern (format "%s-group-alist" backend))))
            force
            (and (setq file (ignore-errors
-                             (symbol-value (intern (format "%s-active-file" 
+                             (symbol-value (intern (format "%s-active-file"
                                                            backend)))))
                 (setq file-time (nth 5 (file-attributes file)))
                 (or (not
                      (setq timestamp
                            (condition-case ()
                                (symbol-value (intern
-                                              (format "%s-active-timestamp" 
+                                              (format "%s-active-timestamp"
                                                       backend)))
                              (error 'none))))
                     (not (consp timestamp))
@@ -1288,20 +1421,9 @@ See the documentation for the variable `nnmail-split-fancy' for documentation."
                          (> (nth 1 file-time) (nth 1 timestamp))))))
        (save-excursion
          (or (eq timestamp 'none)
-             (set (intern (format "%s-active-timestamp" backend)) 
-;;; dmoore@ucsd.edu 25.10.96
-;;; it's not always the case that current-time
-;;; does correspond to changes in the file's time.  So just compare
-;;; the file's new time against its own previous time.
-;;;               (current-time)
-                  file-time
-                  ))
-         (funcall (intern (format "%s-request-list" backend)))
-;;; dmoore@ucsd.edu 25.10.96
-;;; BACKEND-request-list already does this itself!
-;;;      (set (intern (format "%s-group-alist" backend)) 
-;;;           (nnmail-get-active))
-         ))
+             (set (intern (format "%s-active-timestamp" backend))
+                  file-time))
+         (funcall (intern (format "%s-request-list" backend)))))
     t))
 
 (defun nnmail-message-id ()
@@ -1319,8 +1441,8 @@ See the documentation for the variable `nnmail-split-fancy' for documentation."
               (buffer-name nnmail-cache-buffer)))
       ()                               ; The buffer is open.
     (save-excursion
-      (set-buffer 
-       (setq nnmail-cache-buffer 
+      (set-buffer
+       (setq nnmail-cache-buffer
             (get-buffer-create " *nnmail message-id cache*")))
       (buffer-disable-undo (current-buffer))
       (when (file-exists-p nnmail-message-id-cache-file)
@@ -1349,11 +1471,12 @@ See the documentation for the variable `nnmail-split-fancy' for documentation."
                           nnmail-message-id-cache-file nil 'silent)
       (set-buffer-modified-p nil)
       (setq nnmail-cache-buffer nil)
-      ;;(kill-buffer (current-buffer))
-      )))
+      (kill-buffer (current-buffer)))))
 
 (defun nnmail-cache-insert (id)
   (when nnmail-treat-duplicates
+    (unless (gnus-buffer-live-p nnmail-cache-buffer)
+      (nnmail-cache-open))
     (save-excursion
       (set-buffer nnmail-cache-buffer)
       (goto-char (point-max))
@@ -1366,6 +1489,12 @@ See the documentation for the variable `nnmail-split-fancy' for documentation."
       (goto-char (point-max))
       (search-backward id nil t))))
 
+(defun nnmail-fetch-field (header)
+  (save-excursion
+    (save-restriction
+      (message-narrow-to-head)
+      (message-fetch-field header))))
+
 (defun nnmail-check-duplication (message-id func artnum-func)
   (run-hooks 'nnmail-prepare-incoming-message-hook)
   ;; If this is a duplicate message, then we do not save it.
@@ -1390,17 +1519,12 @@ See the documentation for the variable `nnmail-split-fancy' for documentation."
       (setq group-art nil))
      ((eq action 'warn)
       ;; We insert a warning.
-      (let ((case-fold-search t)
-           (newid (nnmail-message-id)))
+      (let ((case-fold-search t))
        (goto-char (point-min))
-       (when (re-search-forward "^message-id:" nil t)
-         (beginning-of-line)
-         (insert "Original-"))
+       (re-search-forward "^message-id[ \t]*:" nil t)
        (beginning-of-line)
-       (insert 
-        "Message-ID: " newid "\n"
+       (insert
         "Gnus-Warning: This is a duplicate of message " message-id "\n")
-       (nnmail-cache-insert newid)
        (funcall func (setq group-art
                            (nreverse (nnmail-article-group artnum-func))))))
      (t
@@ -1421,12 +1545,9 @@ See the documentation for the variable `nnmail-split-fancy' for documentation."
 (defun nnmail-get-new-mail (method exit-func temp
                                   &optional group spool-func)
   "Read new incoming mail."
-  ;; Nix out the previous split history.
-  (unless group
-    (setq nnmail-split-history nil))
   (let* ((spools (nnmail-get-spool-files group))
         (group-in group)
-        incoming incomings spool)
+        nnmail-current-spool incoming incomings spool)
     (when (and (nnmail-get-value "%s-get-new-mail" method)
               nnmail-spool-file)
       ;; We first activate all the groups.
@@ -1443,32 +1564,36 @@ See the documentation for the variable `nnmail-split-fancy' for documentation."
        ;; spool, or the file exists.  We can't check for the
        ;; existence of POPped mail.
        (when (or (string-match "^po:" spool)
-                 (and (file-exists-p spool)
+                 (and (file-exists-p (file-truename spool))
                       (> (nnheader-file-size (file-truename spool)) 0)))
          (nnheader-message 3 "%s: Reading incoming mail..." method)
          (when (and (nnmail-move-inbox spool)
                     (file-exists-p nnmail-crash-box))
+           (setq nnmail-current-spool spool)
            ;; There is new mail.  We first find out if all this mail
            ;; is supposed to go to some specific group.
            (setq group (nnmail-get-split-group spool group-in))
            ;; We split the mail
-           (nnmail-split-incoming 
+           (nnmail-split-incoming
             nnmail-crash-box (intern (format "%s-save-mail" method))
             spool-func group (intern (format "%s-active-number" method)))
-           ;; Check whether the inbox is to be moved to the special tmp dir. 
+           ;; Check whether the inbox is to be moved to the special tmp dir.
            (setq incoming
-                 (nnmail-make-complex-temp-name 
-                  (expand-file-name 
+                 (nnmail-make-complex-temp-name
+                  (expand-file-name
                    (if nnmail-tmp-directory
-                       (concat 
+                       (concat
                         (file-name-as-directory nnmail-tmp-directory)
-                        (file-name-nondirectory (concat temp "Incoming")))
-                     (concat temp "Incoming")))))
+                        (file-name-nondirectory
+                         (concat (file-name-as-directory temp) "Incoming")))
+                     (concat (file-name-as-directory temp) "Incoming")))))
+           (unless (file-exists-p (file-name-directory incoming))
+             (make-directory (file-name-directory incoming) t))
            (rename-file nnmail-crash-box incoming t)
            (push incoming incomings))))
-      ;; If we did indeed read any incoming spools, we save all info. 
+      ;; If we did indeed read any incoming spools, we save all info.
       (when incomings
-       (nnmail-save-active 
+       (nnmail-save-active
         (nnmail-get-value "%s-group-alist" method)
         (nnmail-get-value "%s-active-file" method))
        (when exit-func
@@ -1521,7 +1646,8 @@ If ARGS, PROMPT is used as an argument to `format'."
     (unless nnmail-read-passwd
       (if (load "passwd" t)
          (setq nnmail-read-passwd 'read-passwd)
-       (autoload 'ange-ftp-read-passwd "ange-ftp")
+       (unless (fboundp 'ange-ftp-read-passwd)
+         (autoload 'ange-ftp-read-passwd "ange-ftp"))
        (setq nnmail-read-passwd 'ange-ftp-read-passwd)))
     (funcall nnmail-read-passwd prompt)))
 
@@ -1530,13 +1656,15 @@ If ARGS, PROMPT is used as an argument to `format'."
   (save-restriction
     (message-narrow-to-head)
     (let ((case-fold-search t))
-      (unless (re-search-forward "^Message-ID:" nil t)
+      (unless (re-search-forward "^Message-ID[ \t]*:" nil t)
        (insert "Message-ID: " (nnmail-message-id) "\n")))))
 
 (defun nnmail-write-region (start end filename &optional append visit lockname)
   "Do a `write-region', and then set the file modes."
-  (write-region start end filename append visit lockname)
-  (set-file-modes filename nnmail-default-file-modes))
+  (let ((coding-system-for-write nnmail-file-coding-system)
+       (pathname-coding-system 'binary))
+    (write-region start end filename append visit lockname)
+    (set-file-modes filename nnmail-default-file-modes)))
 
 ;;;
 ;;; Status functions
@@ -1612,6 +1740,16 @@ If ARGS, PROMPT is used as an argument to `format'."
                          ", "))
        (princ "\n")))))
 
+(defun nnmail-purge-split-history (group)
+  "Remove all instances of GROUP from `nnmail-split-history'."
+  (let ((history nnmail-split-history)
+       prev)
+    (while history
+      (setcar history (delete-if (lambda (e) (string= (car e) group))
+                                (car history)))
+      (pop history))
+    (setq nnmail-split-history (delq nil nnmail-split-history))))
+
 (defun nnmail-new-mail-p (group)
   "Say whether GROUP has new mail."
   (let ((his nnmail-split-history)
@@ -1621,9 +1759,18 @@ If ARGS, PROMPT is used as an argument to `format'."
        (setq found t
              his nil)))
     found))
-       
+
+(eval-and-compile
+  (autoload 'pop3-movemail "pop3"))
+
+(defun nnmail-pop3-movemail (inbox crashbox)
+  "Function to move mail from INBOX on a pop3 server to file CRASHBOX."
+  (let ((pop3-maildrop
+         (substring inbox (match-end (string-match "^po:" inbox)))))
+    (pop3-movemail crashbox)))
+
 (run-hooks 'nnmail-load-hook)
-           
+
 (provide 'nnmail)
 
 ;;; nnmail.el ends here