home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / gnu / lucid / lemacs-19.6 / lisp / packages / reportmail.el < prev    next >
Encoding:
Text File  |  1992-12-31  |  34.3 KB  |  935 lines

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