Mercurial > hg > xemacs-beta
diff lisp/packages/reportmail.el @ 0:376386a54a3c r19-14
Import from CVS: tag r19-14
author | cvs |
---|---|
date | Mon, 13 Aug 2007 08:45:50 +0200 |
parents | |
children | 4103f0995bd7 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lisp/packages/reportmail.el Mon Aug 13 08:45:50 2007 +0200 @@ -0,0 +1,895 @@ +;; REPORTMAIL: Display time and load in mode line of Emacs. +;; Originally time.el in the emacs distribution. +;; Mods by BCP, DCP, and JWZ to display incoming mail. +;; +;; Copyright (C) 1985, 1986, 1987 Free Software Foundation, Inc. + +;; This file is part of GNU Emacs. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY. No author or distributor +;; accepts responsibility to anyone for the consequences of using it +;; or for whether it serves any particular purpose or works at all, +;; unless he says so in writing. Refer to the GNU Emacs General Public +;; License for full details. + +;; Everyone is granted permission to copy, modify and redistribute +;; GNU Emacs, but only under the conditions described in the +;; GNU Emacs General Public License. A copy of this license is +;; supposed to have been given to you along with GNU Emacs so you +;; can know your rights and responsibilities. It should be in a +;; file named COPYING. Among other things, the copyright notice +;; and this notice must be preserved on all copies. + +;;; Synched up with: Not in FSF. +;;; #### Appears to duplicate time.el. Perhaps should be nuked. + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; +; Installation +; ------------ +; +; To use reportmail, add the following to your .emacs file: +; +; (load-library "reportmail") +; +; ;; Edit this list as appropriate +; (setq display-time-my-addresses +; '("Benjamin.Pierce" "bcp" "Benjamin Pierce" "Benjamin C. Pierce")) +; +; ;; By default, mail arrival is reported with a message but no beep +; (setq display-time-mail-ring-bell t) +; +; (display-time) +; +; When new mail arrives, a brief blurb about it will be displayed in the +; mode line, and a more verbose message will be printed in the echo area. +; But unlike most echo-area messages, this message will not go away at +; the next keystroke - it doesn't go away until the next extended-command +; is used. This is cool because that means you won't miss seeing the +; subject of the newly-arrived mail because you happened to be typing when +; it arrived. +; +; But if you set the variable `display-time-flush-echo-area' to t, then this +; message will be cleared every `display-time-interval' seconds. This means +; the message will be around for at most 30 seconds or so, which you may +; prefer. +; +; Site Configuration +; ------------------ +; +; The variables display-time-incoming-mail-file and +; display-time-message-separator identify the location and format of +; your waiting messages. If you are in the CMU SCS environment, or +; are on a generic BSD unix system, this code should work right away. +; Otherwise, you might need to modify the values of these to make things +; work. +; +; Junk Mail +; --------- +; +; The reportmail package has a notion of "junk mail," which can be used to +; reduce the frequency of irritating interruptions by reporting only the +; arrival of messages that seem to be interesting. If you're on a lot +; of high-volume mailing lists, this can be quite convenient. To use +; this facility, add something like the following to your .emacs file: +; +; ;; The value of this variable is a list of lists, where the first +; ;; element in each list is the name of a header field and the +; ;; remaining elements are various elements of the value of this +; ;; header field that signal the junkiness of a message. +; (setq display-time-junk-mail-checklist +; '(("From" "bcp" "Benjamin Pierce" "Benjamin.Pierce" +; "Mail Delivery Subsystem" "network" "daemon@bartok") +; ("To" "sml-request" "sml-redistribution-request" +; "scheme" "TeXhax-Distribution-list") +; ("Resent-From" "Benjamin.Pierce") +; ("Sender" "WRITERS" "Haskell" "Electronic Music Digest" "NEW-LIST"))) +; +; By default, the entries in this list are matched exactly as +; substrings of the given header fields. If an entry begins with +; the character ^ it will be matched as a regular expression. If the +; variable display-time-match-using-regexps is set, then all entries +; will be matched as regular expressions. +; +; Note that elements of display-time-my-addresses are NOT automatically +; included in display-time-junk-mail-checklist. If you want mail from +; yourself to be considered junkmail, you must add your addresses to +; display-time-junk-mail-checklist too. +; +; +; Xbiff Interface +; --------------- +; +; If you normally keep your emacs window iconified, reportmail can +; maintain an xbiff or xbiff++ display as well. The xbiff window will only +; be highlighted when non-junk mail is waiting to be read. For example: +; +; (if window-system-version +; (setq display-time-use-xbiff t)) +; (setq display-time-xbiff-arg-list '("-update" "30" "-geometry" "+0+0")) +; (setq display-time-xbiff-program "xbiff++") +; +; Other +; ----- +; +; There are several other user-customization variables that you may wish +; to modify. These are documented below. + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; +; HISTORY +; +; 19 dec 93 Jamie Zawinski <jwz@netscape.com> +; Protected it from edits of the *reportmail* buffer; made the process +; filters not interfere with the match data. +; +; 15 dec 93 Jamie Zawinski <jwz@netscape.com> +; Kyle renamed timer.el to itimer.el; made this use the new names. +; +; 27 aug 93 Jamie Zawinski <jwz@netscape.com> +; Use mail-extr to parse addresses if it is loadable. +; +; 15 oct 92 Benjamin Pierce (bcp@cs.cmu.edu) +; Merged recent changes +; +; 14 oct 92 Jamie Zawinski <jwz@netscape.com> +; Added support for xbiff++. +; +; 17 sep 92 Benjamin Pierce (bcp@cs.cmu.edu) +; Improvements to message display code. +; +; 15 sep 92 Benjamin Pierce (bcp@cs.cmu.edu) +; Minor bug fixes. +; +; 1 may 92 Jamie Zawinski <jwz@netscape.com> +; Converted to work with Kyle Jones' timer.el package. +; +; 3 may 91 Jamie Zawinski <jwz@netscape.com> +; Made the display-time-sentinel make a fuss when the process dies. +; +; 26 mar 91 Jamie Zawinski <jwz@netscape.com> +; Merged with BCP's latest posted version +; +; 5 mar 91 Jamie Zawinski <jwz@netscape.com> +; Added compatibility with Emacs 18.57. +; +; 25 Jan 91 Benjamin Pierce (bcp@cs.cmu.edu) +; Added facility for regular-expression matching of junk-mail +; checklist. Set inhibit-local-variables to t inside of +; display-time-process-new-mail to prevent letterbombs +; (suggested by jwz). +; +; 15 feb 91 Jamie Zawinski <jwz@netscape.com> +; Made the values of display-time-message-separator and +; display-time-incoming-mail-file be initialized when this code +; starts, instead of forcing the user to do it. This means that +; this code can safely be dumped with emacs. Also, it now notices +; when it's at CMU, and defaults to something reasonable. Removed +; display-time-wait-hard, because I learned how to make echo-area +; messages be persistent (not go away at the first key). I wish +; GC messages didn't destroy it, though... +; +; 20 Dec 90 Jamie Zawinski <jwz@netscape.com> +; Added new variables: display-time-no-file-means-no-mail, +; display-time-wait-hard, and display-time-junk-mail-ring-bell. +; Made display-time-message-separator be compared case-insensitively. +; Made the junk-mail checklist use a member-search rather than a +; prefix-search. +; +; 22 Jul 90 Benjamin Pierce (bcp@cs.cmu.edu) +; Added support for debugging. +; +; 19 Jul 90 Benjamin Pierce (bcp@cs.cmu.edu) +; Improved user documentation and eliminated known CMU dependencies. +; +; 13 Jul 90 Mark Leone (mleone@cs.cmu.edu) +; Added display-time-use-xbiff option. Various layout changes. +; +; 20 May 90 Benjamin Pierce (bcp@proof) +; Fixed a bug that occasionally caused fields to be extracted +; from the wrong buffer. +; +; 14 May 90 Benjamin Pierce (bcp@proof) +; Added concept of junk mail and ability to display message +; recipient in addition to sender and subject. (Major internal +; reorganization was needed to implement this cleanly.) +; +; 18 Nov 89 Benjamin Pierce (bcp@proof) +; Fixed to work when display-time is called with +; global-mode-string not a list +; +; 15 Jan 89 David Plaut (dcp@k) +; Added ability to discard load from displayed string +; +; To use: (setq display-time-load nil) +; +; Added facility for reporting incoming mail (modeled after gosmacs +; reportmail.ml package written by Benjamin Pierce). + +(require 'itimer) ; this is xemacs, so why conditionalize? +(require 'mail-extr) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; User Variables ;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defvar display-time-announce-mail t + "*Toggles whether name of mail sender is displayed in mode line.") + +(defvar display-time-announce-junk-mail-too nil + "*When non-NIL, announce incoming junk mail as well as interesting mail") + +(defvar display-time-time t + "*Toggles whether the time is displayed.") + +(defvar display-time-load nil + "*Toggles whether machine load is displayed.") + +(defvar display-time-day-and-date nil + "*Toggles whether day and date are displayed.") + +(defvar display-time-mail-ring-bell nil + "*Toggles whether bell is rung on mail arrival.") + +(defvar display-time-junk-mail-ring-bell nil + "*Toggles whether bell is rung on junk mail arrival. +If display-time-mail-ring-bell is nil, this variable is ignored.") + +(defvar display-time-my-addresses nil + "*Report the addressee of incoming mail in the message announcement, +unless it appears in this list (See also display-time-match-using-regexps.)") +;; For example: +;; (setq display-time-my-addresses +;; '("Benjamin.Pierce" "bcp" "Benjamin Pierce" "Benjamin C. Pierce")) + +(defvar display-time-junk-mail-checklist nil + "*A list of lists of strings. In each sublist, the first component is the +name of a message field and the rest are values that flag a piece of +junk mail. If an entry begins with the character ^ it is matched as +a regular expression rather than an exact prefix of the given header +field. (See also display-time-match-using-regexps.) + +Note: elements of display-time-my-addresses are NOT automatically + included in display-time-junk-mail-checklist") +;; For example: +;; (setq display-time-junk-mail-checklist +;; '(("From" "bcp" "Benjamin Pierce" "Benjamin.Pierce" +;; "Mail Delivery Subsystem" "network" "daemon@bartok") +;; ("To" "sml-request" "sml-redistribution-request" "computermusic" +;; "scheme" "TeXhax-Distribution-list") +;; ("Resent-From" "Benjamin.Pierce") +;; ("Sender" "WRITERS" "Haskell" "Electronic Music Digest" "NEW-LIST"))) + +(defvar display-time-match-using-regexps nil "*When non-nil, elements of +display-time-junk-mail-checklist and display-time-my-addresses are matched +as regular expressions instead of literal prefixes of header fields.") + +(defvar display-time-max-from-length 35 + "*Truncate sender name to this length in mail announcements") + +(defvar display-time-max-to-length 11 + "*Truncate addressee name to this length in mail announcements") + +(defvar display-time-interval 30 + "*Seconds between updates of time in the mode line. Also used +as interval for checking incoming mail.") + +(defvar display-time-no-file-means-no-mail t + "*Set this to T if you are on a system which deletes your mail-spool file +when there is no new mail.") + +(defvar display-time-incoming-mail-file nil + "*User's incoming mail file. Default is value of environment variable MAIL, +if set; otherwise /usr/spool/mail/$USER is used.") + +(defvar display-time-message-separator nil) + +(defvar display-time-flush-echo-area nil + "*If true, then display-time's echo-area message will be +automatically cleared when display-time-interval has expired.") + +(defvar display-time-use-xbiff nil + "*If set, display-time uses xbiff to announce new mail.") + +(defvar display-time-xbiff-program "xbiff") ; xbiff++ if you're cool + +(defvar display-time-xbiff-arg-list nil + "*List of arguments passed to xbiff. Useful for setting geometry, etc.") +;;; For example: +;;; (setq display-time-xbiff-arg-list '("-update" "30" "-geometry" "+0+0")) + +(defvar display-time-mail-arrived-file nil + "New mail announcements saved in this file if xbiff used. Deleted when +mail is read. Xbiff is used to monitor existence of this file. +This file will contain the headers (and only the headers) of all of the +messages in your inbox. If you do not wish this to be readable by others, +you should name a file here which is in a protected directory. Protecting +the file itself is not sufficient, because the file gets deleted and +recreated, and emacs does not make it easy to create protected files.") + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Internal Variables ;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defvar display-time-loadst-process nil + "The process providing time, load, and mail info.") + +(defvar display-time-xbiff-process nil + "The xbiff process used to announce incoming mail.") + +(defvar display-time-string nil + "Time displayed in mode line") + +(defvar display-time-mail-buffer-name "*reportmail*" + "Name of buffer used for announcing mail.") + +(defvar display-time-may-need-to-reset t + "Set to NIL when display-time-total-reset has not been called +since the last time we changed from having mail in the queue to an empty +queue.") + +(defvar display-time-debugging nil + "*When non-NIL, reportmail records various status information +as it's working.") + +(defvar display-time-debugging-delay nil + "*When non-nil and display-time-debugging is set, sit for this +long after displaying each debugging message in mode line") + +(defvar display-time-debugging-buffer "*Reportmail-Debugging*" + "Status messages are appended here.") + +(defvar display-time-max-debug-info 20000 + "Maximum size of debugging buffer") + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Macros ;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defmacro display-time-del-file (filename) + (list 'if (list 'file-exists-p filename) (list 'delete-file filename))) + +(defmacro display-time-debug (mesg &rest args) + (list + 'if 'display-time-debugging + (list 'display-time-debug-mesg + (append (list 'format mesg) args)))) + +(defun display-time-init () + ;; If the mail-file isn't set, figure it out. + (or display-time-incoming-mail-file + (setq display-time-incoming-mail-file + (or (getenv "MAIL") + (let ((user-name (or (getenv "USER") (user-login-name)))) + (and user-name + (cond ((file-directory-p "/usr/spool/mail/") ; bsd + (concat "/usr/spool/mail/" user-name)) + ((file-directory-p "/var/mail/") ; sysv + (concat "/usr/spool/mail/" user-name))))) + ""))) + ;; If the message-separator isn't set, set it to "From " unless + ;; the local hostname ends in ".CMU.EDU", where "^C" is used. + (or display-time-message-separator + (setq display-time-message-separator + (let ((case-fold-search t)) + (if (string-match "\\.cmu\\.edu" (system-name)) + "\^C" + "From ")))) + ;; if this isn't set, these are probably right... + (or display-time-my-addresses + (setq display-time-my-addresses + (list (user-full-name) (user-login-name)))) + ;; + (or display-time-mail-arrived-file + (setq display-time-mail-arrived-file + (expand-file-name ".mail-arrived" (getenv "HOME")))) + ) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Time Display ;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun display-time-kill () + "Kill all display-time processes. Done automatically if display-time +is re-invoked." + (interactive) + (display-time-debug "display-time-kill") + (if display-time-loadst-process (delete-process display-time-loadst-process)) + (if display-time-xbiff-process (delete-process display-time-xbiff-process)) +) + +(defun display-time () + "Displays current time, date, load level, and incoming mail status in +mode line of each buffer (if corresponding user variables are set)." + (interactive) + (display-time-debug "display-time") + (display-time-init) + (let ((process-connection-type nil)) ; UIUCDCS mod + (save-excursion + (display-time-kill) + (if (or (string-equal "" display-time-incoming-mail-file) + (and (not display-time-no-file-means-no-mail) + (not (file-exists-p display-time-incoming-mail-file)))) + (progn + (message "Reportmail: mail spool file \"%s\" not found" + display-time-incoming-mail-file) + (sit-for 1) + (beep))) + (if (not global-mode-string) (setq global-mode-string '(""))) + (if (not (listp global-mode-string)) + (setq global-mode-string (list global-mode-string " "))) + (if (not (memq 'display-time-string global-mode-string)) + (setq global-mode-string + (append global-mode-string '(display-time-string)))) + (setq display-time-string "time and load") + + (let ((old (get-itimer "display-time"))) + (if old (delete-itimer old)) + (start-itimer "display-time" 'display-time-timer-function + display-time-interval display-time-interval) + (display-time-timer-function)) + + (if display-time-use-xbiff + (progn + (display-time-del-file display-time-mail-arrived-file) + (setq display-time-xbiff-process + (apply 'start-process "display-time-xbiff" nil + display-time-xbiff-program + "-file" display-time-mail-arrived-file + display-time-xbiff-arg-list)) + (process-kill-without-query display-time-xbiff-process) + (sit-for 1) ; Need time to see if xbiff fails. + (if (/= 0 (process-exit-status display-time-xbiff-process)) + (error "Display time: xbiff failed. Check xbiff-arg-list")))))) + (display-time-total-reset)) + +(defun display-time-timer-function () + ;; was: (defun display-time-filter-18-57 (proc string) ; args are ignored + ;; but we're not supporting version 18 here and I'm trimming excess + (save-match-data + (display-time-debug "display-time-timer-function") + (if display-time-flush-echo-area + (progn + (display-time-debug "flush echo area") + (display-time-message ""))) + (let ((mailp (and (file-exists-p display-time-incoming-mail-file) + (not (eq 0 (nth 7 (file-attributes + display-time-incoming-mail-file))))))) + (if display-time-announce-mail + (if mailp + (display-time-process-new-mail) + (display-time-total-reset))) + ;; Format the mode line time display + (let ((time-string (if mailp + (if display-time-announce-mail + display-time-mail-modeline + "Mail ")))) + (if display-time-time + (let* ((time (current-time-string)) + (hour (read (substring time 11 13))) + (pm (>= hour 12))) + (if (> hour 12) (setq hour (- hour 12))) + (if (= hour 0) (setq hour 12)) + (setq time-string + (concat time-string + (format "%d" hour) (substring time 13 16) + (if pm "pm " "am "))))) + (if display-time-day-and-date + (setq time-string + (concat time-string + (substring (current-time-string) 0 11)))) + (if display-time-load + (setq time-string + (concat time-string + (condition-case () + (let* ((la (car (load-average))) + (load (if (zerop la) + nil + (format "%03d" la)))) + (if load + (concat (substring load 0 -2) + "." (substring load -2)) + "")) + (error "load-error")) + " "))) + ;; Install the new time for display. + (setq display-time-string time-string) + (force-mode-line-update t))))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Mail processing ;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defvar display-time-mail-who-from "" + "Short-form name of sender of last piece of interesting unread mail") + +(defvar display-time-mail-modeline "" + "Terse mail announcement (displayed in modeline)") + +(defvar display-time-previous-mail-buffer-max 1 + "The length of the mail buffer the last time we looked at it") + +(defvar display-time-msg-count 0 + "How many interesting messages have arrived") + +(defvar display-time-junk-msg-count 0 + "How many junk messages have arrived") + +(defvar display-time-last-message nil) ; enormous hack + + +;; A test procedure for trying out new display-time features +;(defun display-time-test () +; (interactive) +; (display-time-reset-mail-processing) +; (display-time-process-new-mail)) + +(defun display-time-manual-reset () + "Utility function to be called externally to make reportmail notice +that things may have changed." + (display-time-debug "Manual reset") + (display-time-timer-function)) + +(defun display-time-total-reset () + (display-time-debug "display-time-total-reset") + (if display-time-may-need-to-reset + (progn + (setq display-time-may-need-to-reset nil) + (display-time-debug "Resetting mail processing") + (let ((mail-buffer (get-buffer display-time-mail-buffer-name))) + (cond (mail-buffer + ;; unmodify it before killing it in case it has accidentally + ;; been typed in to. + (save-excursion + (set-buffer mail-buffer) + (set-buffer-modified-p nil)) + (kill-buffer mail-buffer)))) + (if display-time-use-xbiff + ;; This function is only called when no mail is in the spool. + ;; Hence we should delete the mail-arrived file. + (display-time-del-file display-time-mail-arrived-file)) + (display-time-reset) + ))) + +(defun display-time-reset () + (display-time-debug "display-time-reset") + (setq display-time-msg-count 0) + (setq display-time-junk-msg-count 0) + (setq display-time-mail-who-from "Junk mail") + (setq display-time-mail-modeline "") + (setq display-time-previous-mail-buffer-max 1) + (display-time-message "") ; clear the echo-area. + ) + +(defun display-time-process-new-mail () + (setq display-time-may-need-to-reset t) + (let ((mail-buffer (get-buffer display-time-mail-buffer-name)) + (inhibit-local-variables t) + (enable-local-variables nil)) + (if (not (and mail-buffer (verify-visited-file-modtime mail-buffer))) + (save-window-excursion + (save-excursion + (display-time-debug "Spool file has changed... rereading...") + (cond (mail-buffer + ;; unmodify it before killing it in case it has accidentally + ;; been typed in to. + (save-excursion + (set-buffer mail-buffer) + (set-buffer-modified-p nil)) + (kill-buffer mail-buffer)))) + ;; Change to pop-to-buffer when we're debugging: + (set-buffer (get-buffer-create display-time-mail-buffer-name)) + (buffer-disable-undo (current-buffer)) + (erase-buffer) + (condition-case nil + ;; I wish we didn't have to mark the buffer as visiting the file, + ;; since that interferes with the user's ability to use find-file + ;; on their spool file, but there's no way to simulate what + ;; verify-visited-file-modtime does. Lose lose. + (let ((buffer-read-only nil)) + (insert-file-contents display-time-incoming-mail-file t)) + (file-error nil)) + ;; this buffer belongs to us; hands off. + (setq buffer-read-only t) + (display-time-process-mail-buffer))))) + +(defun display-time-process-mail-buffer () + (if (< display-time-previous-mail-buffer-max (point-max)) + (let ((case-fold-search nil)) + (goto-char display-time-previous-mail-buffer-max) + (if (not (looking-at + (regexp-quote display-time-message-separator))) + (display-time-reset))) + (display-time-reset)) + (goto-char display-time-previous-mail-buffer-max) + (if display-time-use-xbiff + (save-excursion + (set-buffer (get-buffer-create " *reportmail-tmp*")) + (erase-buffer))) + (let ((case-fold-search nil) + (start (point)) + end junkp ring-bell) + (while (not (eobp)) + (if (search-forward (concat "\n" display-time-message-separator) + nil 'end) + (setq end (1+ (match-beginning 0))) + (setq end (point-max))) + (narrow-to-region start end) + (setq junkp (display-time-process-this-message)) + (if (and display-time-mail-ring-bell (not ring-bell)) + (setq ring-bell (if junkp display-time-junk-mail-ring-bell t))) + (widen) + (goto-char (if (= end (point-max)) (point-max) (1+ end))) + (setq start end)) + + (if ring-bell + (if (string-match "XEmacs" emacs-version) + (beep nil 'reportmail) + (beep)))) + + (if display-time-use-xbiff + (save-excursion + (set-buffer (get-buffer-create " *reportmail-tmp*")) + (if (zerop (buffer-size)) + nil + (write-region (point-min) (point-max) + display-time-mail-arrived-file + t 'nomsg) + (erase-buffer) +; ;; there's no way to get append-to-file to not dump the message +; ;; "Wrote file ..." in the echo area, so re-write the last message +; ;; we intended to write. +; (if display-time-last-message +; (display-time-message "%s" display-time-last-message)) + ))) + + (setq display-time-previous-mail-buffer-max (point-max))) + +(defun display-time-process-this-message () + (display-time-debug "display-time-process-this-message") + (let ((junk-p (display-time-junk-message))) + (if junk-p + (display-time-process-junk-message) + (display-time-process-good-message)) + ;; Update mode line contents + (setq display-time-mail-modeline + (concat "[" (display-time-format-msg-count) + display-time-mail-who-from + "] ")) + (display-time-debug "New mode line: %s " display-time-mail-modeline) + junk-p)) + +(defun display-time-junk-message () + "Check to see whether this message is interesting" + + (display-time-debug "Comparing current message to junk mail checklist") + + (let ((checklist display-time-junk-mail-checklist) + (junk nil)) + (while (and checklist (not junk)) + (if (display-time-member + (display-time-get-field (car (car checklist))) + (cdr (car checklist))) + (setq junk t) + (setq checklist (cdr checklist)))) + junk)) + +(defun display-time-message (&rest message-args) + (let ((str (apply 'format message-args)) + (in-echo-area-already (eq (selected-window) (minibuffer-window)))) + (setq display-time-last-message str) + ;; don't stomp the echo-area-buffer if reading from the minibuffer now. + (display-time-debug "display-time-message (%s)" str) + (if (not in-echo-area-already) + (save-excursion + (save-window-excursion + (display-time-debug "Overwriting echo area with message") + (select-window (minibuffer-window)) + (delete-region (point-min) (point-max)) + (insert str)))) + ;; if we're reading from the echo-area, and all we were going to do is + ;; clear the thing, like, don't bother, that's annoying. + (if (and in-echo-area-already (string= "" str)) + nil + ;; XEmacs version fix + (if (and (string= str "") (not (string-match "^18" emacs-version))) + (message nil) + (message "%s" str))))) + +(defun display-time-process-good-message () + (display-time-debug "Formatting message announcement (good message)") + + ;; Update the message counter + (setq display-time-msg-count (+ display-time-msg-count 1)) + + ;; Format components of announcement + (let* ((subject (display-time-get-field "Subject" "")) + (from (display-time-get-field "From" "")) + (to (display-time-get-field "To" "")) + (print-subject (if (string= subject "") + "" + (concat " (" subject ")"))) + (print-from (display-time-truncate from display-time-max-from-length)) + (short-from (display-time-truncate + (display-time-extract-short-addr from) 25)) + (print-to (if (display-time-member to display-time-my-addresses) + "" + (display-time-truncate + (display-time-extract-short-addr to) + display-time-max-to-length)))) + + ;; Announce message + (let ((msg (concat + (display-time-format-msg-count) + "Mail " + (if (string= print-to "") "" + (concat "to " print-to " ")) + "from " print-from + print-subject))) + (if display-time-use-xbiff + (save-excursion + (let* ((tmp-buf (get-buffer-create " *reportmail-tmp*")) + (buf (current-buffer)) + (start (point-min)) + (end (save-excursion + (goto-char start) + (search-forward "\n\n" nil 0) + (point)))) + (set-buffer tmp-buf) + (goto-char (point-max)) + (insert-buffer-substring buf start end) + (insert "\n\n") + ))) + (display-time-debug "Message: %s" msg) + (display-time-message "%s" msg)) + ;; Update mode line information + (setq display-time-mail-who-from short-from))) + +(defun display-time-process-junk-message () + (display-time-debug "Formatting message announcement (junk message)") + + ;; Update the message counter + (setq display-time-junk-msg-count (+ display-time-junk-msg-count 1)) + + ;; Format components of announcement + (let* ((subject (display-time-get-field "Subject" "")) + (from (display-time-get-field "From" "")) + (to (display-time-get-field "To" "")) + (print-subject (if (string= subject "") + "" + (concat " (" subject ")"))) + (print-from (display-time-truncate from display-time-max-from-length)) + (print-to (if (display-time-member to display-time-my-addresses) + "" + (display-time-truncate + (display-time-extract-short-addr to) + display-time-max-to-length)))) + + ;; Announce message + (if display-time-announce-junk-mail-too + (let ((msg (concat + (display-time-format-msg-count) + "Junk Mail " + (if (string= print-to "") "" + (concat "to " print-to " ")) + "from " print-from + print-subject))) + (display-time-message "%s" msg) + (display-time-debug "Message: %s" msg))))) + +(defun display-time-format-msg-count () + (if (> (+ display-time-msg-count display-time-junk-msg-count) 1) + (concat + (int-to-string display-time-msg-count) + (if (> display-time-junk-msg-count 0) + (concat "(" (int-to-string display-time-junk-msg-count) ")")) + ": ") + "")) + +(defun display-time-get-field (field &optional default) + (cond ((not (equal (buffer-name) display-time-mail-buffer-name)) + (beep) + (message "reportmail bug: processing buffer %s, not %s" + (buffer-name) + display-time-mail-buffer-name) + (sit-for 2))) + (goto-char (point-min)) + (let* ((case-fold-search t) + (result + (if (re-search-forward (concat "^" field ":[ |\C-i]*") nil t) + (let ((start (point))) + (end-of-line) + (while (looking-at "\n[ \t]") + (forward-line 1) + (end-of-line)) + (buffer-substring start (point))) + (or default "<unknown>")))) + (display-time-debug "value of %s field is %s" field result) + result)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Auxilliary Functions ;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun display-time-member (e l) + "Is string E matched by an element of list L? +When an element of L begins with ^, match it as a regexp. Otherwise, +ignore case and match exactly. If display-time-match-using-regexps is +non-nil, always match using regexps." + (let ((done nil) + (result nil)) + (while (not done) + (cond + ((null l) (setq done t)) + ((or display-time-match-using-regexps (= (elt (car l) 0) ?^)) + (if (string-match (car l) e) + (setq result l done t) + (setq l (cdr l)))) + ((string-match (regexp-quote (downcase (car l))) (downcase e)) + (setq result l done t)) + (t + (setq l (cdr l))))) + result)) + +(defun display-time-truncate (s max) + (if (and s (>= (length s) max)) + (concat (substring s 0 max) "\\") + s)) + +(defun display-time-extract-short-addr (long-addr) + (let ((result (and (fboundp 'mail-extract-address-components) + (mail-extract-address-components long-addr)))) + (or (nth 0 result) ; hairily extracted real name + (let ((name "\\([A-Za-z0-9-_+\\. ]+\\)")) + (setq long-addr (or (nth 2 result) long-addr)) + (if (or + ;; David Plaut <dcp@CS.CMU.EDU> -> David Plaut + ;; (doesn't happen if mail-extr loaded) + (string-match (concat name "[ | ]+<.+>") long-addr) + + ;; anything (David Plaut) anything -> David Plaut + ;; (doesn't happen if mail-extr loaded) + (string-match ".+(\\(.+\\)).*" long-addr) + + ;; plaut%address.bitnet@vma.cc.cmu.edu -> plaut + (string-match (concat name "%.+@.+") long-addr) + + ;; random!uucp!addresses!dcp@uu.relay.net -> dcp + (string-match (concat ".*!" name "@.+") long-addr) + + ;; David.Plaut@CS.CMU.EDU -> David.Plaut + (string-match (concat name "@.+") long-addr) + ) + (substring long-addr (match-beginning 1) (match-end 1)) + long-addr))))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Debugging Support ;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defvar display-time-debugging-messages nil + "When non-NIL, reportmail displays status messages in real time.") + +(defun display-time-debug-mesg (mesg) + (save-match-data + (if display-time-debugging-messages + (progn + (message "Reportmail: %s" mesg) + (sit-for 1) + )) + (save-excursion + (save-window-excursion + (set-buffer (get-buffer-create display-time-debugging-buffer)) + (goto-char (point-max)) + (insert (substring (current-time-string) 11 16) " " mesg "\n") + ;; Make sure the debugging buffer doesn't get out of hand + (if (> (point-max) display-time-max-debug-info) + (delete-region (point-min) + (- (point-max) display-time-max-debug-info))))) + (if display-time-debugging-delay + (progn (message "Reportmail: %s" mesg) + (sit-for display-time-debugging-delay))))) + +(provide 'reportmail)