comparison 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
comparison
equal deleted inserted replaced
-1:000000000000 0:376386a54a3c
1 ;; REPORTMAIL: Display time and load in mode line of Emacs.
2 ;; Originally time.el in the emacs distribution.
3 ;; Mods by BCP, DCP, and JWZ to display incoming mail.
4 ;;
5 ;; Copyright (C) 1985, 1986, 1987 Free Software Foundation, Inc.
6
7 ;; This file is part of GNU Emacs.
8
9 ;; GNU Emacs is distributed in the hope that it will be useful,
10 ;; but WITHOUT ANY WARRANTY. No author or distributor
11 ;; accepts responsibility to anyone for the consequences of using it
12 ;; or for whether it serves any particular purpose or works at all,
13 ;; unless he says so in writing. Refer to the GNU Emacs General Public
14 ;; License for full details.
15
16 ;; Everyone is granted permission to copy, modify and redistribute
17 ;; GNU Emacs, but only under the conditions described in the
18 ;; GNU Emacs General Public License. A copy of this license is
19 ;; supposed to have been given to you along with GNU Emacs so you
20 ;; can know your rights and responsibilities. It should be in a
21 ;; file named COPYING. Among other things, the copyright notice
22 ;; and this notice must be preserved on all copies.
23
24 ;;; Synched up with: Not in FSF.
25 ;;; #### Appears to duplicate time.el. Perhaps should be nuked.
26
27 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
28 ;
29 ; Installation
30 ; ------------
31 ;
32 ; To use reportmail, add the following to your .emacs file:
33 ;
34 ; (load-library "reportmail")
35 ;
36 ; ;; Edit this list as appropriate
37 ; (setq display-time-my-addresses
38 ; '("Benjamin.Pierce" "bcp" "Benjamin Pierce" "Benjamin C. Pierce"))
39 ;
40 ; ;; By default, mail arrival is reported with a message but no beep
41 ; (setq display-time-mail-ring-bell t)
42 ;
43 ; (display-time)
44 ;
45 ; When new mail arrives, a brief blurb about it will be displayed in the
46 ; mode line, and a more verbose message will be printed in the echo area.
47 ; But unlike most echo-area messages, this message will not go away at
48 ; the next keystroke - it doesn't go away until the next extended-command
49 ; is used. This is cool because that means you won't miss seeing the
50 ; subject of the newly-arrived mail because you happened to be typing when
51 ; it arrived.
52 ;
53 ; But if you set the variable `display-time-flush-echo-area' to t, then this
54 ; message will be cleared every `display-time-interval' seconds. This means
55 ; the message will be around for at most 30 seconds or so, which you may
56 ; prefer.
57 ;
58 ; Site Configuration
59 ; ------------------
60 ;
61 ; The variables display-time-incoming-mail-file and
62 ; display-time-message-separator identify the location and format of
63 ; your waiting messages. If you are in the CMU SCS environment, or
64 ; are on a generic BSD unix system, this code should work right away.
65 ; Otherwise, you might need to modify the values of these to make things
66 ; work.
67 ;
68 ; Junk Mail
69 ; ---------
70 ;
71 ; The reportmail package has a notion of "junk mail," which can be used to
72 ; reduce the frequency of irritating interruptions by reporting only the
73 ; arrival of messages that seem to be interesting. If you're on a lot
74 ; of high-volume mailing lists, this can be quite convenient. To use
75 ; this facility, add something like the following to your .emacs file:
76 ;
77 ; ;; The value of this variable is a list of lists, where the first
78 ; ;; element in each list is the name of a header field and the
79 ; ;; remaining elements are various elements of the value of this
80 ; ;; header field that signal the junkiness of a message.
81 ; (setq display-time-junk-mail-checklist
82 ; '(("From" "bcp" "Benjamin Pierce" "Benjamin.Pierce"
83 ; "Mail Delivery Subsystem" "network" "daemon@bartok")
84 ; ("To" "sml-request" "sml-redistribution-request"
85 ; "scheme" "TeXhax-Distribution-list")
86 ; ("Resent-From" "Benjamin.Pierce")
87 ; ("Sender" "WRITERS" "Haskell" "Electronic Music Digest" "NEW-LIST")))
88 ;
89 ; By default, the entries in this list are matched exactly as
90 ; substrings of the given header fields. If an entry begins with
91 ; the character ^ it will be matched as a regular expression. If the
92 ; variable display-time-match-using-regexps is set, then all entries
93 ; will be matched as regular expressions.
94 ;
95 ; Note that elements of display-time-my-addresses are NOT automatically
96 ; included in display-time-junk-mail-checklist. If you want mail from
97 ; yourself to be considered junkmail, you must add your addresses to
98 ; display-time-junk-mail-checklist too.
99 ;
100 ;
101 ; Xbiff Interface
102 ; ---------------
103 ;
104 ; If you normally keep your emacs window iconified, reportmail can
105 ; maintain an xbiff or xbiff++ display as well. The xbiff window will only
106 ; be highlighted when non-junk mail is waiting to be read. For example:
107 ;
108 ; (if window-system-version
109 ; (setq display-time-use-xbiff t))
110 ; (setq display-time-xbiff-arg-list '("-update" "30" "-geometry" "+0+0"))
111 ; (setq display-time-xbiff-program "xbiff++")
112 ;
113 ; Other
114 ; -----
115 ;
116 ; There are several other user-customization variables that you may wish
117 ; to modify. These are documented below.
118
119
120 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
121 ;
122 ; HISTORY
123 ;
124 ; 19 dec 93 Jamie Zawinski <jwz@netscape.com>
125 ; Protected it from edits of the *reportmail* buffer; made the process
126 ; filters not interfere with the match data.
127 ;
128 ; 15 dec 93 Jamie Zawinski <jwz@netscape.com>
129 ; Kyle renamed timer.el to itimer.el; made this use the new names.
130 ;
131 ; 27 aug 93 Jamie Zawinski <jwz@netscape.com>
132 ; Use mail-extr to parse addresses if it is loadable.
133 ;
134 ; 15 oct 92 Benjamin Pierce (bcp@cs.cmu.edu)
135 ; Merged recent changes
136 ;
137 ; 14 oct 92 Jamie Zawinski <jwz@netscape.com>
138 ; Added support for xbiff++.
139 ;
140 ; 17 sep 92 Benjamin Pierce (bcp@cs.cmu.edu)
141 ; Improvements to message display code.
142 ;
143 ; 15 sep 92 Benjamin Pierce (bcp@cs.cmu.edu)
144 ; Minor bug fixes.
145 ;
146 ; 1 may 92 Jamie Zawinski <jwz@netscape.com>
147 ; Converted to work with Kyle Jones' timer.el package.
148 ;
149 ; 3 may 91 Jamie Zawinski <jwz@netscape.com>
150 ; Made the display-time-sentinel make a fuss when the process dies.
151 ;
152 ; 26 mar 91 Jamie Zawinski <jwz@netscape.com>
153 ; Merged with BCP's latest posted version
154 ;
155 ; 5 mar 91 Jamie Zawinski <jwz@netscape.com>
156 ; Added compatibility with Emacs 18.57.
157 ;
158 ; 25 Jan 91 Benjamin Pierce (bcp@cs.cmu.edu)
159 ; Added facility for regular-expression matching of junk-mail
160 ; checklist. Set inhibit-local-variables to t inside of
161 ; display-time-process-new-mail to prevent letterbombs
162 ; (suggested by jwz).
163 ;
164 ; 15 feb 91 Jamie Zawinski <jwz@netscape.com>
165 ; Made the values of display-time-message-separator and
166 ; display-time-incoming-mail-file be initialized when this code
167 ; starts, instead of forcing the user to do it. This means that
168 ; this code can safely be dumped with emacs. Also, it now notices
169 ; when it's at CMU, and defaults to something reasonable. Removed
170 ; display-time-wait-hard, because I learned how to make echo-area
171 ; messages be persistent (not go away at the first key). I wish
172 ; GC messages didn't destroy it, though...
173 ;
174 ; 20 Dec 90 Jamie Zawinski <jwz@netscape.com>
175 ; Added new variables: display-time-no-file-means-no-mail,
176 ; display-time-wait-hard, and display-time-junk-mail-ring-bell.
177 ; Made display-time-message-separator be compared case-insensitively.
178 ; Made the junk-mail checklist use a member-search rather than a
179 ; prefix-search.
180 ;
181 ; 22 Jul 90 Benjamin Pierce (bcp@cs.cmu.edu)
182 ; Added support for debugging.
183 ;
184 ; 19 Jul 90 Benjamin Pierce (bcp@cs.cmu.edu)
185 ; Improved user documentation and eliminated known CMU dependencies.
186 ;
187 ; 13 Jul 90 Mark Leone (mleone@cs.cmu.edu)
188 ; Added display-time-use-xbiff option. Various layout changes.
189 ;
190 ; 20 May 90 Benjamin Pierce (bcp@proof)
191 ; Fixed a bug that occasionally caused fields to be extracted
192 ; from the wrong buffer.
193 ;
194 ; 14 May 90 Benjamin Pierce (bcp@proof)
195 ; Added concept of junk mail and ability to display message
196 ; recipient in addition to sender and subject. (Major internal
197 ; reorganization was needed to implement this cleanly.)
198 ;
199 ; 18 Nov 89 Benjamin Pierce (bcp@proof)
200 ; Fixed to work when display-time is called with
201 ; global-mode-string not a list
202 ;
203 ; 15 Jan 89 David Plaut (dcp@k)
204 ; Added ability to discard load from displayed string
205 ;
206 ; To use: (setq display-time-load nil)
207 ;
208 ; Added facility for reporting incoming mail (modeled after gosmacs
209 ; reportmail.ml package written by Benjamin Pierce).
210
211 (require 'itimer) ; this is xemacs, so why conditionalize?
212 (require 'mail-extr)
213
214 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
215 ;;; User Variables ;;;
216 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
217
218 (defvar display-time-announce-mail t
219 "*Toggles whether name of mail sender is displayed in mode line.")
220
221 (defvar display-time-announce-junk-mail-too nil
222 "*When non-NIL, announce incoming junk mail as well as interesting mail")
223
224 (defvar display-time-time t
225 "*Toggles whether the time is displayed.")
226
227 (defvar display-time-load nil
228 "*Toggles whether machine load is displayed.")
229
230 (defvar display-time-day-and-date nil
231 "*Toggles whether day and date are displayed.")
232
233 (defvar display-time-mail-ring-bell nil
234 "*Toggles whether bell is rung on mail arrival.")
235
236 (defvar display-time-junk-mail-ring-bell nil
237 "*Toggles whether bell is rung on junk mail arrival.
238 If display-time-mail-ring-bell is nil, this variable is ignored.")
239
240 (defvar display-time-my-addresses nil
241 "*Report the addressee of incoming mail in the message announcement,
242 unless it appears in this list (See also display-time-match-using-regexps.)")
243 ;; For example:
244 ;; (setq display-time-my-addresses
245 ;; '("Benjamin.Pierce" "bcp" "Benjamin Pierce" "Benjamin C. Pierce"))
246
247 (defvar display-time-junk-mail-checklist nil
248 "*A list of lists of strings. In each sublist, the first component is the
249 name of a message field and the rest are values that flag a piece of
250 junk mail. If an entry begins with the character ^ it is matched as
251 a regular expression rather than an exact prefix of the given header
252 field. (See also display-time-match-using-regexps.)
253
254 Note: elements of display-time-my-addresses are NOT automatically
255 included in display-time-junk-mail-checklist")
256 ;; For example:
257 ;; (setq display-time-junk-mail-checklist
258 ;; '(("From" "bcp" "Benjamin Pierce" "Benjamin.Pierce"
259 ;; "Mail Delivery Subsystem" "network" "daemon@bartok")
260 ;; ("To" "sml-request" "sml-redistribution-request" "computermusic"
261 ;; "scheme" "TeXhax-Distribution-list")
262 ;; ("Resent-From" "Benjamin.Pierce")
263 ;; ("Sender" "WRITERS" "Haskell" "Electronic Music Digest" "NEW-LIST")))
264
265 (defvar display-time-match-using-regexps nil "*When non-nil, elements of
266 display-time-junk-mail-checklist and display-time-my-addresses are matched
267 as regular expressions instead of literal prefixes of header fields.")
268
269 (defvar display-time-max-from-length 35
270 "*Truncate sender name to this length in mail announcements")
271
272 (defvar display-time-max-to-length 11
273 "*Truncate addressee name to this length in mail announcements")
274
275 (defvar display-time-interval 30
276 "*Seconds between updates of time in the mode line. Also used
277 as interval for checking incoming mail.")
278
279 (defvar display-time-no-file-means-no-mail t
280 "*Set this to T if you are on a system which deletes your mail-spool file
281 when there is no new mail.")
282
283 (defvar display-time-incoming-mail-file nil
284 "*User's incoming mail file. Default is value of environment variable MAIL,
285 if set; otherwise /usr/spool/mail/$USER is used.")
286
287 (defvar display-time-message-separator nil)
288
289 (defvar display-time-flush-echo-area nil
290 "*If true, then display-time's echo-area message will be
291 automatically cleared when display-time-interval has expired.")
292
293 (defvar display-time-use-xbiff nil
294 "*If set, display-time uses xbiff to announce new mail.")
295
296 (defvar display-time-xbiff-program "xbiff") ; xbiff++ if you're cool
297
298 (defvar display-time-xbiff-arg-list nil
299 "*List of arguments passed to xbiff. Useful for setting geometry, etc.")
300 ;;; For example:
301 ;;; (setq display-time-xbiff-arg-list '("-update" "30" "-geometry" "+0+0"))
302
303 (defvar display-time-mail-arrived-file nil
304 "New mail announcements saved in this file if xbiff used. Deleted when
305 mail is read. Xbiff is used to monitor existence of this file.
306 This file will contain the headers (and only the headers) of all of the
307 messages in your inbox. If you do not wish this to be readable by others,
308 you should name a file here which is in a protected directory. Protecting
309 the file itself is not sufficient, because the file gets deleted and
310 recreated, and emacs does not make it easy to create protected files.")
311
312 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
313 ;;; Internal Variables ;;;
314 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
315
316 (defvar display-time-loadst-process nil
317 "The process providing time, load, and mail info.")
318
319 (defvar display-time-xbiff-process nil
320 "The xbiff process used to announce incoming mail.")
321
322 (defvar display-time-string nil
323 "Time displayed in mode line")
324
325 (defvar display-time-mail-buffer-name "*reportmail*"
326 "Name of buffer used for announcing mail.")
327
328 (defvar display-time-may-need-to-reset t
329 "Set to NIL when display-time-total-reset has not been called
330 since the last time we changed from having mail in the queue to an empty
331 queue.")
332
333 (defvar display-time-debugging nil
334 "*When non-NIL, reportmail records various status information
335 as it's working.")
336
337 (defvar display-time-debugging-delay nil
338 "*When non-nil and display-time-debugging is set, sit for this
339 long after displaying each debugging message in mode line")
340
341 (defvar display-time-debugging-buffer "*Reportmail-Debugging*"
342 "Status messages are appended here.")
343
344 (defvar display-time-max-debug-info 20000
345 "Maximum size of debugging buffer")
346
347 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
348 ;;; Macros ;;;
349 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
350
351 (defmacro display-time-del-file (filename)
352 (list 'if (list 'file-exists-p filename) (list 'delete-file filename)))
353
354 (defmacro display-time-debug (mesg &rest args)
355 (list
356 'if 'display-time-debugging
357 (list 'display-time-debug-mesg
358 (append (list 'format mesg) args))))
359
360 (defun display-time-init ()
361 ;; If the mail-file isn't set, figure it out.
362 (or display-time-incoming-mail-file
363 (setq display-time-incoming-mail-file
364 (or (getenv "MAIL")
365 (let ((user-name (or (getenv "USER") (user-login-name))))
366 (and user-name
367 (cond ((file-directory-p "/usr/spool/mail/") ; bsd
368 (concat "/usr/spool/mail/" user-name))
369 ((file-directory-p "/var/mail/") ; sysv
370 (concat "/usr/spool/mail/" user-name)))))
371 "")))
372 ;; If the message-separator isn't set, set it to "From " unless
373 ;; the local hostname ends in ".CMU.EDU", where "^C" is used.
374 (or display-time-message-separator
375 (setq display-time-message-separator
376 (let ((case-fold-search t))
377 (if (string-match "\\.cmu\\.edu" (system-name))
378 "\^C"
379 "From "))))
380 ;; if this isn't set, these are probably right...
381 (or display-time-my-addresses
382 (setq display-time-my-addresses
383 (list (user-full-name) (user-login-name))))
384 ;;
385 (or display-time-mail-arrived-file
386 (setq display-time-mail-arrived-file
387 (expand-file-name ".mail-arrived" (getenv "HOME"))))
388 )
389
390 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
391 ;;; Time Display ;;;
392 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
393
394 (defun display-time-kill ()
395 "Kill all display-time processes. Done automatically if display-time
396 is re-invoked."
397 (interactive)
398 (display-time-debug "display-time-kill")
399 (if display-time-loadst-process (delete-process display-time-loadst-process))
400 (if display-time-xbiff-process (delete-process display-time-xbiff-process))
401 )
402
403 (defun display-time ()
404 "Displays current time, date, load level, and incoming mail status in
405 mode line of each buffer (if corresponding user variables are set)."
406 (interactive)
407 (display-time-debug "display-time")
408 (display-time-init)
409 (let ((process-connection-type nil)) ; UIUCDCS mod
410 (save-excursion
411 (display-time-kill)
412 (if (or (string-equal "" display-time-incoming-mail-file)
413 (and (not display-time-no-file-means-no-mail)
414 (not (file-exists-p display-time-incoming-mail-file))))
415 (progn
416 (message "Reportmail: mail spool file \"%s\" not found"
417 display-time-incoming-mail-file)
418 (sit-for 1)
419 (beep)))
420 (if (not global-mode-string) (setq global-mode-string '("")))
421 (if (not (listp global-mode-string))
422 (setq global-mode-string (list global-mode-string " ")))
423 (if (not (memq 'display-time-string global-mode-string))
424 (setq global-mode-string
425 (append global-mode-string '(display-time-string))))
426 (setq display-time-string "time and load")
427
428 (let ((old (get-itimer "display-time")))
429 (if old (delete-itimer old))
430 (start-itimer "display-time" 'display-time-timer-function
431 display-time-interval display-time-interval)
432 (display-time-timer-function))
433
434 (if display-time-use-xbiff
435 (progn
436 (display-time-del-file display-time-mail-arrived-file)
437 (setq display-time-xbiff-process
438 (apply 'start-process "display-time-xbiff" nil
439 display-time-xbiff-program
440 "-file" display-time-mail-arrived-file
441 display-time-xbiff-arg-list))
442 (process-kill-without-query display-time-xbiff-process)
443 (sit-for 1) ; Need time to see if xbiff fails.
444 (if (/= 0 (process-exit-status display-time-xbiff-process))
445 (error "Display time: xbiff failed. Check xbiff-arg-list"))))))
446 (display-time-total-reset))
447
448 (defun display-time-timer-function ()
449 ;; was: (defun display-time-filter-18-57 (proc string) ; args are ignored
450 ;; but we're not supporting version 18 here and I'm trimming excess
451 (save-match-data
452 (display-time-debug "display-time-timer-function")
453 (if display-time-flush-echo-area
454 (progn
455 (display-time-debug "flush echo area")
456 (display-time-message "")))
457 (let ((mailp (and (file-exists-p display-time-incoming-mail-file)
458 (not (eq 0 (nth 7 (file-attributes
459 display-time-incoming-mail-file)))))))
460 (if display-time-announce-mail
461 (if mailp
462 (display-time-process-new-mail)
463 (display-time-total-reset)))
464 ;; Format the mode line time display
465 (let ((time-string (if mailp
466 (if display-time-announce-mail
467 display-time-mail-modeline
468 "Mail "))))
469 (if display-time-time
470 (let* ((time (current-time-string))
471 (hour (read (substring time 11 13)))
472 (pm (>= hour 12)))
473 (if (> hour 12) (setq hour (- hour 12)))
474 (if (= hour 0) (setq hour 12))
475 (setq time-string
476 (concat time-string
477 (format "%d" hour) (substring time 13 16)
478 (if pm "pm " "am ")))))
479 (if display-time-day-and-date
480 (setq time-string
481 (concat time-string
482 (substring (current-time-string) 0 11))))
483 (if display-time-load
484 (setq time-string
485 (concat time-string
486 (condition-case ()
487 (let* ((la (car (load-average)))
488 (load (if (zerop la)
489 nil
490 (format "%03d" la))))
491 (if load
492 (concat (substring load 0 -2)
493 "." (substring load -2))
494 ""))
495 (error "load-error"))
496 " ")))
497 ;; Install the new time for display.
498 (setq display-time-string time-string)
499 (force-mode-line-update t)))))
500
501 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
502 ;;; Mail processing ;;;
503 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
504
505 (defvar display-time-mail-who-from ""
506 "Short-form name of sender of last piece of interesting unread mail")
507
508 (defvar display-time-mail-modeline ""
509 "Terse mail announcement (displayed in modeline)")
510
511 (defvar display-time-previous-mail-buffer-max 1
512 "The length of the mail buffer the last time we looked at it")
513
514 (defvar display-time-msg-count 0
515 "How many interesting messages have arrived")
516
517 (defvar display-time-junk-msg-count 0
518 "How many junk messages have arrived")
519
520 (defvar display-time-last-message nil) ; enormous hack
521
522
523 ;; A test procedure for trying out new display-time features
524 ;(defun display-time-test ()
525 ; (interactive)
526 ; (display-time-reset-mail-processing)
527 ; (display-time-process-new-mail))
528
529 (defun display-time-manual-reset ()
530 "Utility function to be called externally to make reportmail notice
531 that things may have changed."
532 (display-time-debug "Manual reset")
533 (display-time-timer-function))
534
535 (defun display-time-total-reset ()
536 (display-time-debug "display-time-total-reset")
537 (if display-time-may-need-to-reset
538 (progn
539 (setq display-time-may-need-to-reset nil)
540 (display-time-debug "Resetting mail processing")
541 (let ((mail-buffer (get-buffer display-time-mail-buffer-name)))
542 (cond (mail-buffer
543 ;; unmodify it before killing it in case it has accidentally
544 ;; been typed in to.
545 (save-excursion
546 (set-buffer mail-buffer)
547 (set-buffer-modified-p nil))
548 (kill-buffer mail-buffer))))
549 (if display-time-use-xbiff
550 ;; This function is only called when no mail is in the spool.
551 ;; Hence we should delete the mail-arrived file.
552 (display-time-del-file display-time-mail-arrived-file))
553 (display-time-reset)
554 )))
555
556 (defun display-time-reset ()
557 (display-time-debug "display-time-reset")
558 (setq display-time-msg-count 0)
559 (setq display-time-junk-msg-count 0)
560 (setq display-time-mail-who-from "Junk mail")
561 (setq display-time-mail-modeline "")
562 (setq display-time-previous-mail-buffer-max 1)
563 (display-time-message "") ; clear the echo-area.
564 )
565
566 (defun display-time-process-new-mail ()
567 (setq display-time-may-need-to-reset t)
568 (let ((mail-buffer (get-buffer display-time-mail-buffer-name))
569 (inhibit-local-variables t)
570 (enable-local-variables nil))
571 (if (not (and mail-buffer (verify-visited-file-modtime mail-buffer)))
572 (save-window-excursion
573 (save-excursion
574 (display-time-debug "Spool file has changed... rereading...")
575 (cond (mail-buffer
576 ;; unmodify it before killing it in case it has accidentally
577 ;; been typed in to.
578 (save-excursion
579 (set-buffer mail-buffer)
580 (set-buffer-modified-p nil))
581 (kill-buffer mail-buffer))))
582 ;; Change to pop-to-buffer when we're debugging:
583 (set-buffer (get-buffer-create display-time-mail-buffer-name))
584 (buffer-disable-undo (current-buffer))
585 (erase-buffer)
586 (condition-case nil
587 ;; I wish we didn't have to mark the buffer as visiting the file,
588 ;; since that interferes with the user's ability to use find-file
589 ;; on their spool file, but there's no way to simulate what
590 ;; verify-visited-file-modtime does. Lose lose.
591 (let ((buffer-read-only nil))
592 (insert-file-contents display-time-incoming-mail-file t))
593 (file-error nil))
594 ;; this buffer belongs to us; hands off.
595 (setq buffer-read-only t)
596 (display-time-process-mail-buffer)))))
597
598 (defun display-time-process-mail-buffer ()
599 (if (< display-time-previous-mail-buffer-max (point-max))
600 (let ((case-fold-search nil))
601 (goto-char display-time-previous-mail-buffer-max)
602 (if (not (looking-at
603 (regexp-quote display-time-message-separator)))
604 (display-time-reset)))
605 (display-time-reset))
606 (goto-char display-time-previous-mail-buffer-max)
607 (if display-time-use-xbiff
608 (save-excursion
609 (set-buffer (get-buffer-create " *reportmail-tmp*"))
610 (erase-buffer)))
611 (let ((case-fold-search nil)
612 (start (point))
613 end junkp ring-bell)
614 (while (not (eobp))
615 (if (search-forward (concat "\n" display-time-message-separator)
616 nil 'end)
617 (setq end (1+ (match-beginning 0)))
618 (setq end (point-max)))
619 (narrow-to-region start end)
620 (setq junkp (display-time-process-this-message))
621 (if (and display-time-mail-ring-bell (not ring-bell))
622 (setq ring-bell (if junkp display-time-junk-mail-ring-bell t)))
623 (widen)
624 (goto-char (if (= end (point-max)) (point-max) (1+ end)))
625 (setq start end))
626
627 (if ring-bell
628 (if (string-match "XEmacs" emacs-version)
629 (beep nil 'reportmail)
630 (beep))))
631
632 (if display-time-use-xbiff
633 (save-excursion
634 (set-buffer (get-buffer-create " *reportmail-tmp*"))
635 (if (zerop (buffer-size))
636 nil
637 (write-region (point-min) (point-max)
638 display-time-mail-arrived-file
639 t 'nomsg)
640 (erase-buffer)
641 ; ;; there's no way to get append-to-file to not dump the message
642 ; ;; "Wrote file ..." in the echo area, so re-write the last message
643 ; ;; we intended to write.
644 ; (if display-time-last-message
645 ; (display-time-message "%s" display-time-last-message))
646 )))
647
648 (setq display-time-previous-mail-buffer-max (point-max)))
649
650 (defun display-time-process-this-message ()
651 (display-time-debug "display-time-process-this-message")
652 (let ((junk-p (display-time-junk-message)))
653 (if junk-p
654 (display-time-process-junk-message)
655 (display-time-process-good-message))
656 ;; Update mode line contents
657 (setq display-time-mail-modeline
658 (concat "[" (display-time-format-msg-count)
659 display-time-mail-who-from
660 "] "))
661 (display-time-debug "New mode line: %s " display-time-mail-modeline)
662 junk-p))
663
664 (defun display-time-junk-message ()
665 "Check to see whether this message is interesting"
666
667 (display-time-debug "Comparing current message to junk mail checklist")
668
669 (let ((checklist display-time-junk-mail-checklist)
670 (junk nil))
671 (while (and checklist (not junk))
672 (if (display-time-member
673 (display-time-get-field (car (car checklist)))
674 (cdr (car checklist)))
675 (setq junk t)
676 (setq checklist (cdr checklist))))
677 junk))
678
679 (defun display-time-message (&rest message-args)
680 (let ((str (apply 'format message-args))
681 (in-echo-area-already (eq (selected-window) (minibuffer-window))))
682 (setq display-time-last-message str)
683 ;; don't stomp the echo-area-buffer if reading from the minibuffer now.
684 (display-time-debug "display-time-message (%s)" str)
685 (if (not in-echo-area-already)
686 (save-excursion
687 (save-window-excursion
688 (display-time-debug "Overwriting echo area with message")
689 (select-window (minibuffer-window))
690 (delete-region (point-min) (point-max))
691 (insert str))))
692 ;; if we're reading from the echo-area, and all we were going to do is
693 ;; clear the thing, like, don't bother, that's annoying.
694 (if (and in-echo-area-already (string= "" str))
695 nil
696 ;; XEmacs version fix
697 (if (and (string= str "") (not (string-match "^18" emacs-version)))
698 (message nil)
699 (message "%s" str)))))
700
701 (defun display-time-process-good-message ()
702 (display-time-debug "Formatting message announcement (good message)")
703
704 ;; Update the message counter
705 (setq display-time-msg-count (+ display-time-msg-count 1))
706
707 ;; Format components of announcement
708 (let* ((subject (display-time-get-field "Subject" ""))
709 (from (display-time-get-field "From" ""))
710 (to (display-time-get-field "To" ""))
711 (print-subject (if (string= subject "")
712 ""
713 (concat " (" subject ")")))
714 (print-from (display-time-truncate from display-time-max-from-length))
715 (short-from (display-time-truncate
716 (display-time-extract-short-addr from) 25))
717 (print-to (if (display-time-member to display-time-my-addresses)
718 ""
719 (display-time-truncate
720 (display-time-extract-short-addr to)
721 display-time-max-to-length))))
722
723 ;; Announce message
724 (let ((msg (concat
725 (display-time-format-msg-count)
726 "Mail "
727 (if (string= print-to "") ""
728 (concat "to " print-to " "))
729 "from " print-from
730 print-subject)))
731 (if display-time-use-xbiff
732 (save-excursion
733 (let* ((tmp-buf (get-buffer-create " *reportmail-tmp*"))
734 (buf (current-buffer))
735 (start (point-min))
736 (end (save-excursion
737 (goto-char start)
738 (search-forward "\n\n" nil 0)
739 (point))))
740 (set-buffer tmp-buf)
741 (goto-char (point-max))
742 (insert-buffer-substring buf start end)
743 (insert "\n\n")
744 )))
745 (display-time-debug "Message: %s" msg)
746 (display-time-message "%s" msg))
747 ;; Update mode line information
748 (setq display-time-mail-who-from short-from)))
749
750 (defun display-time-process-junk-message ()
751 (display-time-debug "Formatting message announcement (junk message)")
752
753 ;; Update the message counter
754 (setq display-time-junk-msg-count (+ display-time-junk-msg-count 1))
755
756 ;; Format components of announcement
757 (let* ((subject (display-time-get-field "Subject" ""))
758 (from (display-time-get-field "From" ""))
759 (to (display-time-get-field "To" ""))
760 (print-subject (if (string= subject "")
761 ""
762 (concat " (" subject ")")))
763 (print-from (display-time-truncate from display-time-max-from-length))
764 (print-to (if (display-time-member to display-time-my-addresses)
765 ""
766 (display-time-truncate
767 (display-time-extract-short-addr to)
768 display-time-max-to-length))))
769
770 ;; Announce message
771 (if display-time-announce-junk-mail-too
772 (let ((msg (concat
773 (display-time-format-msg-count)
774 "Junk Mail "
775 (if (string= print-to "") ""
776 (concat "to " print-to " "))
777 "from " print-from
778 print-subject)))
779 (display-time-message "%s" msg)
780 (display-time-debug "Message: %s" msg)))))
781
782 (defun display-time-format-msg-count ()
783 (if (> (+ display-time-msg-count display-time-junk-msg-count) 1)
784 (concat
785 (int-to-string display-time-msg-count)
786 (if (> display-time-junk-msg-count 0)
787 (concat "(" (int-to-string display-time-junk-msg-count) ")"))
788 ": ")
789 ""))
790
791 (defun display-time-get-field (field &optional default)
792 (cond ((not (equal (buffer-name) display-time-mail-buffer-name))
793 (beep)
794 (message "reportmail bug: processing buffer %s, not %s"
795 (buffer-name)
796 display-time-mail-buffer-name)
797 (sit-for 2)))
798 (goto-char (point-min))
799 (let* ((case-fold-search t)
800 (result
801 (if (re-search-forward (concat "^" field ":[ |\C-i]*") nil t)
802 (let ((start (point)))
803 (end-of-line)
804 (while (looking-at "\n[ \t]")
805 (forward-line 1)
806 (end-of-line))
807 (buffer-substring start (point)))
808 (or default "<unknown>"))))
809 (display-time-debug "value of %s field is %s" field result)
810 result))
811
812 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
813 ;;; Auxilliary Functions ;;;
814 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
815
816 (defun display-time-member (e l)
817 "Is string E matched by an element of list L?
818 When an element of L begins with ^, match it as a regexp. Otherwise,
819 ignore case and match exactly. If display-time-match-using-regexps is
820 non-nil, always match using regexps."
821 (let ((done nil)
822 (result nil))
823 (while (not done)
824 (cond
825 ((null l) (setq done t))
826 ((or display-time-match-using-regexps (= (elt (car l) 0) ?^))
827 (if (string-match (car l) e)
828 (setq result l done t)
829 (setq l (cdr l))))
830 ((string-match (regexp-quote (downcase (car l))) (downcase e))
831 (setq result l done t))
832 (t
833 (setq l (cdr l)))))
834 result))
835
836 (defun display-time-truncate (s max)
837 (if (and s (>= (length s) max))
838 (concat (substring s 0 max) "\\")
839 s))
840
841 (defun display-time-extract-short-addr (long-addr)
842 (let ((result (and (fboundp 'mail-extract-address-components)
843 (mail-extract-address-components long-addr))))
844 (or (nth 0 result) ; hairily extracted real name
845 (let ((name "\\([A-Za-z0-9-_+\\. ]+\\)"))
846 (setq long-addr (or (nth 2 result) long-addr))
847 (if (or
848 ;; David Plaut <dcp@CS.CMU.EDU> -> David Plaut
849 ;; (doesn't happen if mail-extr loaded)
850 (string-match (concat name "[ | ]+<.+>") long-addr)
851
852 ;; anything (David Plaut) anything -> David Plaut
853 ;; (doesn't happen if mail-extr loaded)
854 (string-match ".+(\\(.+\\)).*" long-addr)
855
856 ;; plaut%address.bitnet@vma.cc.cmu.edu -> plaut
857 (string-match (concat name "%.+@.+") long-addr)
858
859 ;; random!uucp!addresses!dcp@uu.relay.net -> dcp
860 (string-match (concat ".*!" name "@.+") long-addr)
861
862 ;; David.Plaut@CS.CMU.EDU -> David.Plaut
863 (string-match (concat name "@.+") long-addr)
864 )
865 (substring long-addr (match-beginning 1) (match-end 1))
866 long-addr)))))
867
868 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
869 ;;; Debugging Support ;;;
870 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
871
872 (defvar display-time-debugging-messages nil
873 "When non-NIL, reportmail displays status messages in real time.")
874
875 (defun display-time-debug-mesg (mesg)
876 (save-match-data
877 (if display-time-debugging-messages
878 (progn
879 (message "Reportmail: %s" mesg)
880 (sit-for 1)
881 ))
882 (save-excursion
883 (save-window-excursion
884 (set-buffer (get-buffer-create display-time-debugging-buffer))
885 (goto-char (point-max))
886 (insert (substring (current-time-string) 11 16) " " mesg "\n")
887 ;; Make sure the debugging buffer doesn't get out of hand
888 (if (> (point-max) display-time-max-debug-info)
889 (delete-region (point-min)
890 (- (point-max) display-time-max-debug-info)))))
891 (if display-time-debugging-delay
892 (progn (message "Reportmail: %s" mesg)
893 (sit-for display-time-debugging-delay)))))
894
895 (provide 'reportmail)