(quoted-printable-decode-region): Don't error out on
[gnus] / lisp / nnmail.el
index 214bbcd..32ead27 100644 (file)
@@ -1,5 +1,5 @@
 ;;; nnmail.el --- mail support functions for the Gnus mail backends
-;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
+;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
 ;;        Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
@@ -28,6 +28,7 @@
 
 (eval-when-compile (require 'cl))
 
+(require 'gnus)                                ; for macro gnus-kill-buffer, at least
 (require 'nnheader)
 (require 'message)
 (require 'custom)
@@ -36,9 +37,8 @@
 (require 'mm-util)
 
 (eval-and-compile
-  (autoload 'gnus-error "gnus-util")
-  (autoload 'gnus-buffer-live-p "gnus-util")
-  (autoload 'gnus-add-buffer "gnus"))
+  (autoload 'gnus-add-buffer "gnus")
+  (autoload 'gnus-kill-buffer "gnus"))
 
 (defgroup nnmail nil
   "Reading mail with Gnus."
@@ -167,10 +167,10 @@ can also be `immediate' and `never'."
 
 (defcustom nnmail-expiry-wait-function nil
   "Variable that holds function to specify how old articles should be before they are expired.
-  The function will be called with the name of the group that the
-expiry is to be performed in, and it should return an integer that
-says how many days an article can be stored before it is considered
-\"old\".  It can also return the values `never' and `immediate'.
+The function will be called with the name of the group that the expiry
+is to be performed in, and it should return an integer that says how
+many days an article can be stored before it is considered \"old\".
+It can also return the values `never' and `immediate'.
 
 Eg.:
 
@@ -350,6 +350,11 @@ discarded after running the split process."
   :group 'nnmail-split
   :type 'hook)
 
+(defcustom nnmail-spool-hook nil
+  "*A hook called when a new article is spooled."
+  :group 'nnmail
+  :type 'hook)
+
 (defcustom nnmail-large-newsgroup 50
   "*The number of the articles which indicates a large newsgroup or nil.
 If the number of the articles is greater than the value, verbose
@@ -498,6 +503,14 @@ parameter.  It should return nil, `warn' or `delete'."
   :group 'nnmail
   :type 'boolean)
 
+(defcustom nnmail-split-fancy-match-partial-words nil
+  "Whether to match partial words when fancy splitting.
+Normally, regexes given in `nnmail-split-fancy' are implicitly surrounded
+by \"\\<...\\>\".  If this is true, they are not implicitly surrounded by
+anything."
+  :group 'nnmail
+  :type 'boolean)
+
 ;;; Internal variables.
 
 (defvar nnmail-article-buffer " *nnmail incoming*"
@@ -538,7 +551,7 @@ parameter.  It should return nil, `warn' or `delete'."
   "Coding system used in reading inbox")
 
 (defvar nnmail-pathname-coding-system nil
-  "*Coding system for pathname.")
+  "*Coding system for file name.")
 
 (defun nnmail-find-file (file)
   "Insert FILE in server buffer safely."
@@ -555,7 +568,7 @@ parameter.  It should return nil, `warn' or `delete'."
       (file-error nil))))
 
 (defun nnmail-group-pathname (group dir &optional file)
-  "Make pathname for GROUP."
+  "Make file name for GROUP."
   (concat
    (let ((dir (file-name-as-directory (expand-file-name dir))))
      (setq group (nnheader-replace-duplicate-chars-in-string
@@ -786,7 +799,9 @@ If SOURCE is a directory spec, try to return the group name component."
     (if (not (and (re-search-forward "^From " nil t)
                  (goto-char (match-beginning 0))))
        ;; Possibly wrong format?
-       (error "Error, unknown mail format! (Possibly corrupted.)")
+       (error "Error, unknown mail format! (Possibly corrupted %s `%s'.)"
+              (if (buffer-file-name) "file" "buffer")
+              (or (buffer-file-name) (buffer-name)))
       ;; Carry on until the bitter end.
       (while (not (eobp))
        (setq start (point)
@@ -883,8 +898,8 @@ If SOURCE is a directory spec, try to return the group name component."
         start
         (if (search-forward "\n\n" nil t)
             (1- (point))
-        ;; This will never happen, but just to be on the safe side --
-      ;; if there is no head-body delimiter, we search a bit manually.
+          ;; This will never happen, but just to be on the safe side --
+          ;; if there is no head-body delimiter, we search a bit manually.
           (while (and (looking-at "From \\|[^ \t]+:")
                       (not (eobp)))
             (forward-line 1))
@@ -930,7 +945,7 @@ If SOURCE is a directory spec, try to return the group name component."
      (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.
+       ;; if there is no head-body delimiter, we search a bit manually.
        (while (and (looking-at "From \\|[^ \t]+:")
                   (not (eobp)))
         (forward-line 1))
@@ -996,8 +1011,7 @@ FUNC will be called with the buffer narrowed to each mail."
 FUNC will be called with the group name to determine the article number."
   (let ((methods (or nnmail-split-methods '(("bogus" ""))))
        (obuf (current-buffer))
-       (beg (point-min))
-       end group-art method grp)
+       group-art method grp)
     (if (and (sequencep methods)
             (= (length methods) 1))
        ;; If there is only just one group to put everything in, we
@@ -1006,13 +1020,17 @@ FUNC will be called with the group name to determine the article number."
              (list (cons (caar methods) (funcall func (caar methods)))))
       ;; We do actual comparison.
       (save-excursion
-       ;; Find headers.
-       (goto-char beg)
-       (setq end (if (search-forward "\n\n" nil t) (point) (point-max)))
+       ;; Copy the article into the work buffer.
        (set-buffer nntp-server-buffer)
        (erase-buffer)
-       ;; Copy the headers into the work buffer.
-       (insert-buffer-substring obuf beg end)
+       (insert-buffer-substring obuf)
+       ;; Narrow to headers.
+       (narrow-to-region
+        (goto-char (point-min))
+        (if (search-forward "\n\n" nil t)
+            (point)
+          (point-max)))
+       (goto-char (point-min))
        ;; Decode MIME headers and charsets.
        (when nnmail-mail-splitting-decodes
          (let ((mail-parse-charset nnmail-mail-splitting-charset))
@@ -1029,7 +1047,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) (progn (end-of-line) (point))))
+           (delete-region (point) (gnus-point-at-eol)))
          (forward-line 1))
        ;; Allow washing.
        (goto-char (point-min))
@@ -1104,6 +1122,7 @@ FUNC will be called with the group name to determine the article number."
            (goto-char (point-min))
            (gnus-configure-windows 'split-trace)
            (set-buffer restore)))
+       (widen)
        ;; See whether the split methods returned `junk'.
        (if (equal group-art '(junk))
            nil
@@ -1176,7 +1195,8 @@ Return the number of characters in the body."
              nil t)
        (delete-region (match-beginning 2) (match-end 0))
        (beginning-of-line))
-      (when (re-search-forward "^Subject: +\\(\\(R[Ee]: +\\)+\\)R[Ee]: +" nil t)
+      (when (re-search-forward "^Subject: +\\(\\(R[Ee]: +\\)+\\)R[Ee]: +"
+                              nil t)
        (delete-region (match-beginning 1) (match-end 1))
        (beginning-of-line)))))
 
@@ -1270,6 +1290,8 @@ See the documentation for the variable `nnmail-split-fancy' for details."
 
      ;; Builtin : operation.
      ((eq (car split) ':)
+      (when nnmail-split-tracing
+       (push split nnmail-split-trace))
       (nnmail-split-it (save-excursion (eval (cdr split)))))
 
      ;; Builtin ! operation.
@@ -1320,7 +1342,7 @@ See the documentation for the variable `nnmail-split-fancy' for details."
                ;; correct match positions.
                (re-search-backward value start-of-value))
              (dolist (sp (nnmail-split-it (car split-rest)))
-               (unless (memq sp split-result)
+               (unless (member sp split-result)
                  (push sp split-result))))))
        split-result))
 
@@ -1328,8 +1350,9 @@ See the documentation for the variable `nnmail-split-fancy' for details."
      (t
       (let* ((field (nth 0 split))
             (value (nth 1 split))
-            partial-front regexp
-            partial-rear  regexp)
+            partial-front
+            partial-rear
+            regexp)
        (if (symbolp value)
            (setq value (cdr (assq value nnmail-split-abbrev-alist))))
        (if (and (>= (length value) 2)
@@ -1341,6 +1364,9 @@ See the documentation for the variable `nnmail-split-fancy' for details."
                 (string= ".*" (substring value -2)))
            (setq value (substring value 0 -2)
                  partial-rear ""))
+       (when nnmail-split-fancy-match-partial-words
+         (setq partial-front ""
+               partial-rear ""))
        (setq regexp (concat "^\\(\\("
                             (if (symbolp field)
                                 (cdr (assq field nnmail-split-abbrev-alist))
@@ -1465,13 +1491,15 @@ See the documentation for the variable `nnmail-split-fancy' for details."
                           nnmail-message-id-cache-file nil 'silent)
       (set-buffer-modified-p nil)
       (setq nnmail-cache-buffer nil)
-      (kill-buffer (current-buffer)))))
+      (gnus-kill-buffer (current-buffer)))))
 
 ;; Compiler directives.
 (defvar group)
 (defvar group-art-list)
 (defvar group-art)
 (defun nnmail-cache-insert (id grp)
+  (run-hook-with-args 'nnmail-spool-hook 
+                     id grp)
   (when nnmail-treat-duplicates
     ;; Store some information about the group this message is written
     ;; to.  This is passed in as the grp argument -- all locations this
@@ -1497,12 +1525,16 @@ See the documentation for the variable `nnmail-split-fancy' for details."
 (defun nnmail-cache-primary-mail-backend ()
   (let ((be-list (cons gnus-select-method gnus-secondary-select-methods))
        (be nil)
-       (res nil))
+       (res nil)
+        (get-new-mail nil))
     (while (and (null res) be-list)
       (setq be (car be-list))
       (setq be-list (cdr be-list))
       (when (and (gnus-method-option-p be 'respool)
-                (eval (intern (format "%s-get-new-mail" (car be)))))
+                 (setq get-new-mail
+                       (intern (format "%s-get-new-mail" (car be))))
+                 (boundp get-new-mail)
+                (symbol-value get-new-mail))
        (setq res be)))
     res))
 
@@ -1518,15 +1550,14 @@ 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)
-                           (progn (end-of-line) (point))))))))
+         (buffer-substring (point) (gnus-point-at-eol)))))))
 
 ;; Function for nnmail-split-fancy: look up all references in the
 ;; cache and if a match is found, return that group.
 (defun nnmail-split-fancy-with-parent ()
   "Split this message into the same group as its parent.
 This function can be used as an entry in `nnmail-split-fancy', for
-example like this: (: nnmail-split-fancy)
+example like this: (: nnmail-split-fancy-with-parent)
 For a message to be split, it looks for the parent message in the
 References or In-Reply-To header and then looks in the message id
 cache file (given by the variable `nnmail-message-id-cache-file') to
@@ -1746,7 +1777,11 @@ See the Info node `(gnus)Fancy Mail Splitting' for more details."
     (when (nnheader-functionp target)
       (setq target (funcall target group)))
     (unless (eq target 'delete)
-      (gnus-request-accept-article target nil nil t))))
+      (when (or (gnus-request-group target)
+               (gnus-request-create-group target))
+       (let ((group-art (gnus-request-accept-article target nil nil t)))
+         (when (consp group-art)
+           (gnus-group-mark-article-read target (cdr group-art))))))))
 
 (defun nnmail-fancy-expiry-target (group)
   "Returns a target expiry group determined by `nnmail-fancy-expiry-targets'."
@@ -1870,7 +1905,7 @@ See the Info node `(gnus)Fancy Mail Splitting' for more details."
   "Remove all instances of GROUP from `nnmail-split-history'."
   (let ((history nnmail-split-history))
     (while history
-      (setcar history (gnus-delete-if (lambda (e) (string= (car e) group))
+      (setcar history (gnus-remove-if (lambda (e) (string= (car e) group))
                                      (car history)))
       (pop history))
     (setq nnmail-split-history (delq nil nnmail-split-history))))