*** empty log message ***
[gnus] / lisp / nnmail.el
index fa93388..b65dad2 100644 (file)
@@ -74,7 +74,7 @@ new mail into folder numbers that Gnus has marked as expired.")
 If nil, groups like \"mail.misc\" will end up in directories like
 \"mail/misc/\".")
 
-(defvar nnmail-default-file-modes ?\600
+(defvar nnmail-default-file-modes 384
   "Set the mode bits of all new mail files to this integer.")
 
 (defvar nnmail-expiry-wait 7
@@ -106,7 +106,9 @@ Eg.:
 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.")
+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.")
 
 (defvar nnmail-crash-box "~/.gnus-crash-box"
   "*File where Gnus will store mail while processing it.")
@@ -158,7 +160,7 @@ running (\"xwatch\", etc.)
 Eg.
 
 \(add-hook 'nnmail-read-incoming-hook 
-          (lambda () 
+          (lambda ()
             (start-process \"mailsend\" nil 
                            \"/local/bin/mailsend\" \"read\" \"mbox\")))
 
@@ -171,8 +173,8 @@ If you use `display-time', you could use something like this:
          (lambda ()
            ;; Update the displayed time, since that will clear out
            ;; the flag that says you have mail.
-           (if (eq (process-status \"display-time\") 'run)
-               (display-time-filter display-time-process \"\"))))") 
+           (when (eq (process-status \"display-time\") 'run)
+             (display-time-filter display-time-process \"\"))))")
 
 (when (eq system-type 'windows-nt)
   (add-hook 'nnmail-prepare-incoming-hook 'nnheader-ms-strip-cr))
@@ -347,15 +349,18 @@ parameter.  It should return nil, `warn' or `delete'.")
   
 (defun nnmail-date-to-time (date)
   "Convert DATE into time."
-  (let* ((d1 (timezone-parse-date date))
-        (t1 (timezone-parse-time (aref d1 3))))
-    (apply 'encode-time
-          (mapcar (lambda (el)
-                    (and el (string-to-number el)))
-                  (list
-                   (aref t1 2) (aref t1 1) (aref t1 0)
-                   (aref d1 2) (aref d1 1) (aref d1 0)
-                   (aref d1 4))))))
+  (condition-case ()
+      (let* ((d1 (timezone-parse-date date))
+            (t1 (timezone-parse-time (aref d1 3))))
+       (apply 'encode-time
+              (mapcar (lambda (el)
+                        (and el (string-to-number el)))
+                      (list
+                       (aref t1 2) (aref t1 1) (aref t1 0)
+                       (aref d1 2) (aref d1 1) (aref d1 0)
+                       (aref d1 4)))))
+    ;; If we get an error, then we just return a 0 time.
+    (error (list 0 0))))
 
 (defun nnmail-time-less (t1 t2)
   "Say whether time T1 is less than time T2."
@@ -367,7 +372,7 @@ parameter.  It should return nil, `warn' or `delete'.")
   "Convert DAYS into time."
   (let* ((seconds (* 1.0 days 60 60 24))
         (rest (expt 2 16))
-        (ms (condition-case nil (round (/ seconds rest)) 
+        (ms (condition-case nil (round (/ seconds rest))
               (range-error (expt 2 16)))))
     (list ms (condition-case nil (round (- seconds (* ms rest)))
               (range-error (expt 2 16))))))
@@ -378,7 +383,8 @@ parameter.  It should return nil, `warn' or `delete'.")
     ;; Convert date strings to internal time.
     (setq time (nnmail-date-to-time time)))
   (let* ((current (current-time))
-        (rest (if (< (nth 1 current) (nth 1 time)) (expt 2 16))))
+        (rest (when (< (nth 1 current) (nth 1 time))
+                (expt 2 16))))
     (list (- (+ (car current) (if rest -1 0)) (car time))
          (- (+ (or rest 0) (nth 1 current)) (nth 1 time)))))
 
@@ -394,7 +400,8 @@ parameter.  It should return nil, `warn' or `delete'.")
       ;; If getting from mail spool directory,
       ;; use movemail to move rather than just renaming,
       ;; so as to interlock with the mailer.
-      (unless (setq popmail (string-match "^po:" (file-name-nondirectory inbox)))
+      (unless (setq popmail (string-match
+                            "^po:" (file-name-nondirectory inbox)))
        (setq movemail t))
       (when popmail 
        (setq inbox (file-name-nondirectory inbox)))
@@ -408,7 +415,8 @@ parameter.  It should return nil, `warn' or `delete'.")
        (if popmail
            (progn
              (setq nnmail-internal-password nnmail-pop-password)
-             (when (and nnmail-pop-password-required (not nnmail-pop-password))
+             (when (and nnmail-pop-password-required
+                        (not nnmail-pop-password))
                (setq nnmail-internal-password
                      (nnmail-read-passwd
                       (format "Password for %s: "
@@ -457,7 +465,8 @@ parameter.  It should return nil, `warn' or `delete'.")
                     'call-process
                     (append
                      (list
-                      (expand-file-name nnmail-movemail-program exec-directory)
+                      (expand-file-name nnmail-movemail-program
+                                        exec-directory)
                       nil errors nil inbox tofile)
                      (when nnmail-internal-password
                        (list nnmail-internal-password))))))
@@ -514,20 +523,16 @@ 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."
   (when file-name
-    (let (group)
-      (save-excursion
-       (set-buffer (get-buffer-create " *nnmail active*"))
-       (buffer-disable-undo (current-buffer))
-       (erase-buffer)
-       (while group-assoc
-         (setq group (pop group-assoc))
-         (insert (format "%s %d %d y\n" (car group) (cdadr group) 
-                         (caadr group))))
-       (unless (file-exists-p (file-name-directory file-name))
-         (make-directory (file-name-directory file-name) t))
-       (nnmail-write-region
-        1 (point-max) (expand-file-name file-name) nil 'nomesg)
-       (kill-buffer (current-buffer))))))
+    (nnheader-temp-write file-name
+      (nnmail-generate-active group-assoc))))
+
+(defun nnmail-generate-active (alist)
+  "Generate an active file from group-alist ALIST."
+  (erase-buffer)
+  (let (group)
+    (while (setq group (pop alist))
+      (insert (format "%s %d %d y\n" (car group) (cdadr group)
+                     (caadr group))))))
 
 (defun nnmail-get-split-group (file group)
   "Find out whether this FILE is to be split into GROUP only.
@@ -623,26 +628,35 @@ is a spool.  If not using procmail, return GROUP."
       (goto-char end))))
 
 (defun nnmail-search-unix-mail-delim ()
-  "Put point at the beginning of the next message."
-  (let ((case-fold-search t)
-       (delim (concat "^" message-unix-mail-delimiter))
+  "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:
+  ;;
+  ;; 1) Search for "^From ".
+  ;; 2) If we find it, then see whether the previous
+  ;;    line is blank and the next line looks like a header.
+  ;; Then it's possible that this is a mail delim, and we use it.
+  (let ((case-fold-search nil)
        found)
     (while (not found)
-      (if (re-search-forward delim nil t)
-         (when (or (looking-at "[^\n :]+ *:")
-                   (looking-at delim)
-                   (looking-at (concat ">" message-unix-mail-delimiter)))
-           (forward-line -1)
-           (setq found 'yes))
-       (setq found 'no)))
+      (if (not (re-search-forward "^From " nil t))
+         (setq found 'no)
+       (beginning-of-line)
+       (when (and (or (bobp)
+                      (save-excursion
+                        (forward-line -1)
+                        (= (following-char) ?\n)))
+                  (save-excursion
+                    (forward-line 1)
+                    (looking-at "[^ \t:]+[ \t]*:")))
+         (setq found 'yes))))
     (eq found 'yes)))
 
 (defun nnmail-process-unix-mail-format (func artnum-func)
-  (let ((case-fold-search t)
-       (delim (concat "^" message-unix-mail-delimiter))
+  (let ((case-fold-search nil)
        start message-id content-length end skip head-end)
     (goto-char (point-min))
-    (if (not (and (re-search-forward delim nil t)
+    (if (not (and (re-search-forward "^From " nil t)
                  (goto-char (match-beginning 0))))
        ;; Possibly wrong format?
        (error "Error, unknown mail format! (Possibly corrupted.)")
@@ -701,10 +715,9 @@ is a spool.  If not using procmail, return GROUP."
          (cond ((or (= skip (point-max))
                     (= (1+ skip) (point-max)))
                 (setq end (point-max)))
-               ((looking-at delim)
+               ((looking-at "From ")
                 (setq end skip))
-               ((looking-at
-                 (concat "[ \t]*\n\\(" delim "\\)"))
+               ((looking-at "[ \t]*\n\\(From \\)")
                 (setq end (match-beginning 1)))
                (t (setq end nil))))
        (if end
@@ -805,7 +818,8 @@ FUNC will be called with the buffer narrowed to each mail."
               (nnmail-process-mmdf-mail-format func artnum-func))
              (t
               (nnmail-process-unix-mail-format func artnum-func))))
-      (if exit-func (funcall exit-func))
+      (when exit-func
+       (funcall exit-func))
       (kill-buffer (current-buffer)))))
 
 ;; Mail crossposts suggested by Brian Edmonds <edmonds@cs.ubc.ca>. 
@@ -858,7 +872,7 @@ FUNC will be called with the group name to determine the article number."
            (if (or methods
                    (not (equal "" (nth 1 method))))
                (when (and
-                      (condition-case () 
+                      (condition-case ()
                           (if (stringp (nth 1 method))
                               (re-search-backward (cadr method) nil t)
                             ;; Function to say whether this is a match.
@@ -867,13 +881,13 @@ FUNC will be called with the group name to determine the article number."
                       ;; 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 (car method) (funcall func (car method)))
                        group-art))
              ;; This is the final group, which is used as a 
              ;; catch-all.
              (unless group-art
                (setq group-art 
-                     (list (cons (car method) 
+                     (list (cons (car method)
                                  (funcall func (car method)))))))))
        ;; See whether the split methods returned `junk'.
        (if (equal group-art '(junk))
@@ -886,7 +900,7 @@ Return the number of characters in the body."
   (let (lines chars)
     (save-excursion
       (goto-char (point-min))
-      (when (search-forward "\n\n" nil t) 
+      (when (search-forward "\n\n" nil t)
        (setq chars (- (point-max) (point)))
        (setq lines (count-lines (point) (point-max)))
        (forward-char -1)
@@ -901,10 +915,10 @@ Return the number of characters in the body."
   "Insert an Xref line based on the (group . article) alist."
   (save-excursion
     (goto-char (point-min))
-    (when (search-forward "\n\n" nil t) 
+    (when (search-forward "\n\n" nil t)
       (forward-char -1)
       (when (re-search-backward "^Xref: " nil t)
-       (delete-region (match-beginning 0) 
+       (delete-region (match-beginning 0)
                       (progn (forward-line 1) (point))))
       (insert (format "Xref: %s" (system-name)))
       (while group-alist
@@ -981,8 +995,8 @@ See the documentation for the variable `nnmail-split-fancy' for documentation."
    ((assq split nnmail-split-cache)
     ;; A compiled match expression.
     (goto-char (point-max))
-    (if (re-search-backward (cdr (assq split nnmail-split-cache)) nil t)
-       (nnmail-split-it (nth 2 split))))
+    (when (re-search-backward (cdr (assq split nnmail-split-cache)) nil t)
+      (nnmail-split-it (nth 2 split))))
    (t
     ;; An uncompiled match.
     (let* ((field (nth 0 split))
@@ -996,11 +1010,10 @@ See the documentation for the variable `nnmail-split-fancy' for documentation."
                               (cdr (assq value nnmail-split-abbrev-alist))
                             value)
                           "\\)\\>")))
-      (setq nnmail-split-cache 
-           (cons (cons split regexp) nnmail-split-cache))
+      (push (cons split regexp) nnmail-split-cache)
       (goto-char (point-max))
-      (if (re-search-backward regexp nil t)
-         (nnmail-split-it (nth 2 split)))))))
+      (when (re-search-backward regexp nil t)
+       (nnmail-split-it (nth 2 split)))))))
 
 ;; Get a list of spool files to read.
 (defun nnmail-get-spool-files (&optional group)
@@ -1020,7 +1033,8 @@ See the documentation for the variable `nnmail-split-fancy' for documentation."
           (p procmails)
           (crash (when (and (file-exists-p nnmail-crash-box)
                             (> (nnheader-file-size
-                                (file-truename nnmail-crash-box)) 0))
+                                (file-truename nnmail-crash-box))
+                               0))
                    (list nnmail-crash-box))))
       ;; Remove any directories that inadvertently match the procmail
       ;; suffix, which might happen if the suffix is "". 
@@ -1040,9 +1054,24 @@ See the documentation for the variable `nnmail-split-fancy' for documentation."
                   (eq nnmail-spool-file 'procmail))
              nil)
             ((listp nnmail-spool-file)
-             (append nnmail-spool-file procmails))
-            ((stringp nnmail-spool-file)
+             (nconc
+              (apply 
+               'nconc
+               (mapcar 
+                (lambda (file)
+                  (if (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))
             ((eq nnmail-spool-file 'pop)
              (cons (format "po:%s" (user-login-name)) procmails))
             (t
@@ -1075,10 +1104,19 @@ See the documentation for the variable `nnmail-split-fancy' for documentation."
        (save-excursion
          (or (eq timestamp 'none)
              (set (intern (format "%s-active-timestamp" backend)) 
-                  (current-time)))
+;;; 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)))
-         (set (intern (format "%s-group-alist" backend)) 
-              (nnmail-get-active))))
+;;; dmoore@ucsd.edu 25.10.96
+;;; BACKEND-request-list already does this itself!
+;;;      (set (intern (format "%s-group-alist" backend)) 
+;;;           (nnmail-get-active))
+         ))
     t))
 
 (defun nnmail-message-id ()
@@ -1100,8 +1138,8 @@ See the documentation for the variable `nnmail-split-fancy' for documentation."
        (setq nnmail-cache-buffer 
             (get-buffer-create " *nnmail message-id cache*")))
       (buffer-disable-undo (current-buffer))
-      (and (file-exists-p nnmail-message-id-cache-file)
-          (insert-file-contents nnmail-message-id-cache-file))
+      (when (file-exists-p nnmail-message-id-cache-file)
+       (insert-file-contents nnmail-message-id-cache-file))
       (set-buffer-modified-p nil)
       (current-buffer))))
 
@@ -1114,10 +1152,10 @@ See the documentation for the variable `nnmail-split-fancy' for documentation."
       (set-buffer nnmail-cache-buffer)
       ;; Weed out the excess number of Message-IDs.
       (goto-char (point-max))
-      (and (search-backward "\n" nil t nnmail-message-id-cache-length)
-          (progn
-            (beginning-of-line)
-            (delete-region (point-min) (point))))
+      (when (search-backward "\n" nil t nnmail-message-id-cache-length)
+       (progn
+         (beginning-of-line)
+         (delete-region (point-min) (point))))
       ;; Save the buffer.
       (or (file-exists-p (file-name-directory nnmail-message-id-cache-file))
          (make-directory (file-name-directory nnmail-message-id-cache-file)
@@ -1147,6 +1185,7 @@ See the documentation for the variable `nnmail-split-fancy' for documentation."
   (run-hooks 'nnmail-prepare-incoming-message-hook)
   ;; If this is a duplicate message, then we do not save it.
   (let* ((duplication (nnmail-cache-id-exists-p message-id))
+        (case-fold-search t)
         (action (when duplication
                   (cond
                    ((memq nnmail-treat-duplicates '(warn delete))
@@ -1198,7 +1237,8 @@ See the documentation for the variable `nnmail-split-fancy' for documentation."
                                   &optional group spool-func)
   "Read new incoming mail."
   ;; Nix out the previous split history.
-  (setq nnmail-split-history nil)
+  (unless group
+    (setq nnmail-split-history nil))
   (let* ((spools (nnmail-get-spool-files group))
         (group-in group)
         incoming incomings spool)
@@ -1228,7 +1268,7 @@ See the documentation for the variable `nnmail-split-fancy' for documentation."
            (setq group (nnmail-get-split-group spool group-in))
            ;; We split the mail
            (nnmail-split-incoming 
-            nnmail-crash-box (intern (format "%s-save-mail" method)) 
+            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. 
            (setq incoming
@@ -1286,13 +1326,19 @@ See the documentation for the variable `nnmail-split-fancy' for documentation."
             (nnmail-time-less days (nnmail-time-since time)))))))
 
 (defvar nnmail-read-passwd nil)
-(defun nnmail-read-passwd (prompt)
-  (unless nnmail-read-passwd
-    (if (load "passwd" t)
-       (setq nnmail-read-passwd 'read-passwd)
-      (autoload 'ange-ftp-read-passwd "ange-ftp")
-      (setq nnmail-read-passwd 'ange-ftp-read-passwd)))
-  (funcall nnmail-read-passwd prompt))
+(defun nnmail-read-passwd (prompt &rest args)
+  "Read a password using PROMPT.
+If ARGS, PROMPT is used as an argument to `format'."
+  (let ((prompt
+        (if args
+            (apply 'format prompt args)
+          prompt)))
+    (unless nnmail-read-passwd
+      (if (load "passwd" t)
+         (setq nnmail-read-passwd 'read-passwd)
+       (autoload 'ange-ftp-read-passwd "ange-ftp")
+       (setq nnmail-read-passwd 'ange-ftp-read-passwd)))
+    (funcall nnmail-read-passwd prompt)))
 
 (defun nnmail-check-syntax ()
   "Check (and modify) the syntax of the message in the current buffer."
@@ -1383,6 +1429,16 @@ See the documentation for the variable `nnmail-split-fancy' for documentation."
                         ", ")
              "\n"))
     (goto-char (point-min))))
+
+(defun nnmail-new-mail-p (group)
+  "Say whether GROUP has new mail."
+  (let ((his nnmail-split-history)
+       found)
+    (while his
+      (when (assoc group (pop his))
+       (setq found t
+             his nil)))
+    found))
        
 (run-hooks 'nnmail-load-hook)