]> code.delx.au - gnu-emacs/blobdiff - lisp/mail/rmail.el
*** empty log message ***
[gnu-emacs] / lisp / mail / rmail.el
index 426c6eb4cc4ae56b13aacbce0446ec8a08b69b7d..f9cd3914770e8ec46afaed571f887134ee5be5af 100644 (file)
@@ -1,11 +1,15 @@
-;; "RMAIL" mail reader for Emacs.
-;; Copyright (C) 1985, 1986, 1987, 1988 Free Software Foundation, Inc.
+;;; rmail.el --- main code of "RMAIL" mail reader for Emacs.
+
+;; Copyright (C) 1985, 1986, 1987, 1988, 1991, 1992 Free Software Foundation, Inc.
+
+;; Maintainer: FSF
+;; Keywords: mail
 
 ;; This file is part of GNU Emacs.
 
 ;; GNU Emacs is free software; you can redistribute it and/or modify
 ;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 1, or (at your option)
+;; the Free Software Foundation; either version 2, or (at your option)
 ;; any later version.
 
 ;; GNU Emacs is distributed in the hope that it will be useful,
@@ -17,6 +21,7 @@
 ;; along with GNU Emacs; see the file COPYING.  If not, write to
 ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 
+;;; Code:
 
 ;; Souped up by shane@mit-ajax based on ideas of rlk@athena.mit.edu
 ;;   New features include attribute and keyword support, message
@@ -24,8 +29,6 @@
 ;;   expunging by dispatch table, sticky options for file commands.
 
 (require 'mail-utils)
-(provide 'rmail)
-
 ; These variables now declared paths.el
 ;(defvar rmail-spool-directory "/usr/spool/mail/"
 ;  "This is the name of the directory used by the system mailer for\n\
@@ -100,6 +103,13 @@ Called with region narrowed to unformatted header.")
 (defvar rmail-last-multi-labels nil)
 (defvar rmail-last-file nil)
 (defvar rmail-last-rmail-file nil)
+
+;;; Regexp matching the delimiter of messages in UNIX mail format
+;;; (UNIX From lines), minus the initial ^.  Note that if you change
+;;; this expression, you must change the code in rmail-nuke-pinhead-header
+;;; that knows the exact ordering of the \\( \\) subexpressions.
+(defvar rmail-unix-mail-delimiter
+  "From \\([^ \n]*\\(\\|\".*\"[^ \n]*\\)\\)  ?\\([^ \n]*\\) \\([^ ]*\\) *\\([0-9]*\\) \\([0-9:]*\\)\\( ?[A-Z]?[A-Z][A-Z]T\\( DST\\)?\\| ?[-+]?[0-9][0-9][0-9][0-9]\\|\\) [0-9][0-9]\\([0-9]*\\) *\\(remote from [^\n]*\\)?\n" nil)
 \f
 ;;;; *** Rmail Mode ***
 
@@ -251,6 +261,7 @@ Note:    it means the file has no messages in it.\n\^_")))
   (define-key rmail-mode-map "\e\C-m" 'rmail-retry-failure)
   (define-key rmail-mode-map "c" 'rmail-continue)
   (define-key rmail-mode-map "f" 'rmail-forward)
+  (define-key rmail-mode-map "\er" 'rmail-search-backwards)
   (define-key rmail-mode-map "\es" 'rmail-search)
   (define-key rmail-mode-map "<" 'rmail-first-message)
   (define-key rmail-mode-map ">" 'rmail-last-message)
@@ -358,9 +369,7 @@ Instead, these commands are available:
   (setq rmail-inbox-list (rmail-parse-file-inboxes))
   (make-local-variable 'rmail-keywords)
   ;; this gets generated as needed
-  (setq rmail-keywords nil)
-  (make-local-variable 'save-buffers-skip)
-  (setq save-buffers-skip t))
+  (setq rmail-keywords nil))
 
 ;; Handle M-x revert-buffer done in an rmail-mode buffer.
 (defun rmail-revert (arg noconfirm)
@@ -507,7 +516,10 @@ argument causes us to read a file name and use that file as the inbox."
     (while files
       (setq file (expand-file-name (substitute-in-file-name (car files)))
            ;;>> un*x specific <<
-           tofile (concat file "~"))
+           ;; The "+" used to be "~", which is an extremely poor choice;
+           ;; it might accidentally be deleted when space is low
+           ;; (as happened to me!).
+           tofile (concat file "+"))
       ;; If getting from mail spool directory,
       ;; use movemail to move rather than just renaming,
       ;; so as to interlock with the mailer.
@@ -582,20 +594,29 @@ argument causes us to read a file name and use that file as the inbox."
 ;; the  rmail-break-forwarded-messages  feature is not implemented
 (defun rmail-convert-to-babyl-format ()
   (let ((count 0) start
-       (case-fold-search nil))
+       (case-fold-search nil)
+       (invalid-input-resync
+        (function (lambda ()
+                    (message "Invalid Babyl format in inbox!")
+                    (sit-for 1)
+                    ;; Try to get back in sync with a real message.
+                    (if (re-search-forward
+                         (concat mmdf-delim1 "\\|^From") nil t)
+                        (beginning-of-line)
+                      (goto-char (point-max)))))))
     (goto-char (point-min))
     (save-restriction
       (while (not (eobp))
        (cond ((looking-at "BABYL OPTIONS:");Babyl header
-              (search-forward "\n\^_")
-              (delete-region (point-min) (point)))
+              (if (search-forward "\n\^_" nil t)
+                  ;; If we find the proper terminator, delete through there.
+                  (delete-region (point-min) (point))
+                (funcall invalid-input-resync)
+                (delete-region (point-min) (point))))
              ;; Babyl format message
              ((looking-at "\^L")
               (or (search-forward "\n\^_" nil t)
-                  (progn
-                    (message "Invalid Babyl format in inbox!")
-                    (sit-for 1)
-                    (goto-char (point-max))))
+                  (funcall invalid-input-resync))
               (setq count (1+ count))
               ;; Make sure there is no extra white space after the ^_
               ;; at the end of the message.
@@ -629,9 +650,8 @@ argument causes us to read a file name and use that file as the inbox."
               (rmail-nuke-pinhead-header)
               (if (re-search-forward
                    (concat "^[\^_]?\\("
-                           "From [^ \n]*\\(\\|\".*\"[^ \n]*\\)  ?[^ \n]* [^ \n]* *"
-                           "[0-9]* [0-9:]*\\( ?[A-Z]?[A-Z][A-Z]T\\| ?[-+]?[0-9][0-9][0-9][0-9]\\|\\) " ; EDT, -0500
-                           "19[0-9]* *\\(remote from [^\n]*\\)?$\\|"
+                           rmail-unix-mail-delimiter
+                           "\\|"
                            mmdf-delim1 "\\|"
                            "^BABYL OPTIONS:\\|"
                            "\^L\n[01],\\)") nil t)
@@ -676,8 +696,7 @@ argument causes us to read a file name and use that file as the inbox."
          (setq has-date (and (search-forward "\nDate:" nil t) (point)))
          (goto-char start))
        (let ((case-fold-search nil))
-         (if (re-search-forward
-              "^From \\([^ ]*\\(\\|\".*\"[^ ]*\\)\\)  ?\\([^ ]*\\) \\([^ ]*\\) *\\([0-9]*\\) \\([0-9:]*\\)\\( ?[A-Z]?[A-Z][A-Z]T\\| ?[-+]?[0-9][0-9][0-9][0-9]\\|\\) 19\\([0-9]*\\) *\\(remote from [^\n]*\\)?\n" nil t)
+         (if (re-search-forward (concat "^" rmail-unix-mail-delimiter) nil t)
              (replace-match
                (concat
                  "Mail-from: \\&"
@@ -687,8 +706,8 @@ argument causes us to read a file name and use that file as the inbox."
                      ""
                    ;; If no time zone specified, assume est.
                    (if (= (match-beginning 7) (match-end 7))
-                       "Date: \\3, \\5 \\4 \\8 \\6 EST\n"
-                       "Date: \\3, \\5 \\4 \\8 \\6\\7\n"))
+                       "Date: \\3, \\5 \\4 \\9 \\6 EST\n"
+                       "Date: \\3, \\5 \\4 \\9 \\6\\7\n"))
                  ;; Keep and reformat the sender if we don't
                  ;; have a From: field.
                  (if has-from
@@ -871,7 +890,7 @@ again afterward.
 FUNCTION may not change the visible text of the message, but it may
 change the invisible header text."
   (save-excursion
-    (let ((obeg (- (point-max) (point-min)))
+    (let ((obeg (- (point-max) (point-min))))
       (unwind-protect
          (progn
            (narrow-to-region (rmail-msgbeg rmail-current-message)
@@ -883,7 +902,7 @@ change the invisible header text."
        ;; before that restriction is restored.
        ;; Here we assume that changes made by FUNCTION
        ;; occur before the visible region of the message.
-       (narrow-to-region (- (point-max) obeg) (point-max)))))))
+       (narrow-to-region (- (point-max) obeg) (point-max))))))
 
 (defun rmail-forget-messages ()
   (unwind-protect
@@ -1054,9 +1073,9 @@ or backward if N is negative."
     (if (/= lastwin rmail-current-message)
        (rmail-show-message lastwin))
     (if (< n 0)
-       (error "No previous nondeleted message"))
+       (message "No previous nondeleted message"))
     (if (> n 0)
-       (error "No following nondeleted message"))))
+       (message "No following nondeleted message"))))
 
 (defun rmail-previous-undeleted-message (n)
   "Show previous non-deleted message.
@@ -1090,11 +1109,11 @@ or forward if N is negative."
     (if (>= where (rmail-msgbeg high)) high low)))
 
 (defvar rmail-search-last-regexp nil)
-(defun rmail-search (regexp &optional reversep)
+(defun rmail-search (regexp &optional n)
   "Show message containing next match for REGEXP.
-Search in reverse (earlier messages) with non-nil second arg REVERSEP.
-Interactively, empty argument means use same regexp used last time,
-and reverse search is specified by a negative numeric arg."
+Prefix argument gives repeat count; negative argument means search
+backwards (through earlier messages).
+Interactively, empty argument means use same regexp used last time."
   (interactive
     (let* ((reversep (< (prefix-numeric-value current-prefix-arg) 0))
           (prompt
@@ -1110,29 +1129,34 @@ and reverse search is specified by a negative numeric arg."
             (setq rmail-search-last-regexp regexp))
            ((not rmail-search-last-regexp)
             (error "No previous Rmail search string")))
-      (list rmail-search-last-regexp reversep)))
+      (list rmail-search-last-regexp
+           (prefix-numeric-value current-prefix-arg))))
+  (or n (setq n 1))
   (message "%sRmail search for %s..."
-          (if reversep "Reverse " "")
+          (if (< n 0) "Reverse " "")
           regexp)
   (rmail-maybe-set-message-counters)
   (let ((omin (point-min))
        (omax (point-max))
        (opoint (point))
        win
+       (reversep (< n 0))
        (msg rmail-current-message))
     (unwind-protect
        (progn
          (widen)
-         ;; Check messages one by one, advancing message number up or down
-         ;; but searching forward through each message.
-         (if reversep
-             (while (and (null win) (> msg 1))
-               (goto-char (rmail-msgbeg (setq msg (1- msg))))
-               (setq win (re-search-forward
-                          regexp (rmail-msgend msg) t)))
-           (while (and (null win) (< msg rmail-total-messages))
-             (goto-char (rmail-msgbeg (setq msg (1+ msg))))
-             (setq win (re-search-forward regexp (rmail-msgend msg) t)))))
+         (while (/= n 0)
+           ;; Check messages one by one, advancing message number up or down
+           ;; but searching forward through each message.
+           (if reversep
+               (while (and (null win) (> msg 1))
+                 (goto-char (rmail-msgbeg (setq msg (1- msg))))
+                 (setq win (re-search-forward
+                            regexp (rmail-msgend msg) t)))
+             (while (and (null win) (< msg rmail-total-messages))
+               (goto-char (rmail-msgbeg (setq msg (1+ msg))))
+               (setq win (re-search-forward regexp (rmail-msgend msg) t))))
+           (setq n (+ n (if reversep 1 -1)))))
       (if win
          (progn
            ;; If this is a reverse search and we found a message,
@@ -1153,6 +1177,30 @@ and reverse search is specified by a negative numeric arg."
        (ding)
        (message "Search failed: %s" regexp)))))
 
+(defun rmail-search-backwards (regexp &optional n)
+  "Show message containing previous match for REGEXP.
+Prefix argument gives repeat count; negative argument means search
+forward (through later messages).
+Interactively, empty argument means use same regexp used last time."
+  (interactive
+    (let* ((reversep (>= (prefix-numeric-value current-prefix-arg) 0))
+          (prompt
+           (concat (if reversep "Reverse " "") "Rmail search (regexp): "))
+          regexp)
+      (if rmail-search-last-regexp
+         (setq prompt (concat prompt
+                              "(default "
+                              rmail-search-last-regexp
+                              ") ")))
+      (setq regexp (read-string prompt))
+      (cond ((not (equal regexp ""))
+            (setq rmail-search-last-regexp regexp))
+           ((not rmail-search-last-regexp)
+            (error "No previous Rmail search string")))
+      (list rmail-search-last-regexp
+           (prefix-numeric-value current-prefix-arg))))
+  (rmail-search regexp (- (or n -1))))
+
 ;; Show the first message which has the `unseen' attribute.
 (defun rmail-first-unseen-message ()
   (let ((current 1)
@@ -1160,9 +1208,9 @@ and reverse search is specified by a negative numeric arg."
     (save-restriction
       (widen)
       (while (and (not found) (< current rmail-total-messages))
-       (setq current (1+ current))
        (if (rmail-message-labels-p current ", ?\\(unseen\\),")
-           (setq found current))))
+           (setq found current))
+       (setq current (1+ current))))
     (if found
        (rmail-show-message found))))
 \f
@@ -1195,17 +1243,10 @@ and reverse search is specified by a negative numeric arg."
 (defun rmail-delete-forward (&optional backward)
   "Delete this message and move to next nondeleted one.
 Deleted messages stay in the file until the \\[rmail-expunge] command is given.
-With prefix argument, delete and move backward.  If there is no nondeleted
-message to move to in the preferred or specified direction, move in the
-other direction."
+With prefix argument, delete and move backward."
   (interactive "P")
   (rmail-set-attribute "deleted" t)
-  (condition-case ()
-      (rmail-next-undeleted-message (if backward -1 1))
-    (error
-     (condition-case ()
-        (rmail-previous-undeleted-message (if backward -1 1))
-       (error nil)))))
+  (rmail-next-undeleted-message (if backward -1 1)))
 
 (defun rmail-delete-backward ()
   "Delete this message and move to previous nondeleted one.
@@ -1598,3 +1639,7 @@ buffer visiting that file."
   "Break up a digest message into its constituent messages.
 Leaves original message, deleted, before the undigestified messages."
   t)
+
+(provide 'rmail)
+
+;;; rmail.el ends here