home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / languages / elisp / patches / auto-filer.patch < prev    next >
Encoding:
Text File  |  1991-12-21  |  11.8 KB  |  324 lines

  1. ; Newsgroups: gnu.emacs.sources
  2. ; Path: dg-rtp!uunet!uunet!cis.ohio-state.edu!uvm-gen.uvm.edu!wollman
  3. ; From: wollman@uvm-gen.uvm.edu
  4. ; Subject: A new, improved mail auto-filer
  5. ; Organization: Source only  Discussion and requests in gnu.emacs.help.
  6. ; Date: Mon, 9 Dec 1991 20:09:12 GMT
  7. ; This message contains patches which will modify sendmail.el,
  8. ; loaddefs.el (yes, you will have to re-dump your Emacs, although you
  9. ; could get around it by putting these into sendmail instead), and
  10. ; vm-save.el, with path-names like the way I have my GNU sources set up.
  11. ; (You can always leave the -p off and let patch prompt you for the
  12. ; exact file name...)
  13.  
  14. ; These patches, put together, install a more intelligent, more
  15. ; customizable, auto-filer for sendmail mode, and modify VM to use the
  16. ; same (so that you don't have to write everything twice).  Modification
  17. ; of other mail and news systems to use the new saver should be quite
  18. ; straightforward: simply call (mail-find-auto-save HEADER) where HEADER
  19. ; is the (string) value of some appropriate header file---I use To: in
  20. ; sendmail and From: or To: (whichever is present) in VM.  The return
  21. ; value is a list of folders to which the message should be saved, or
  22. ; nil if nothing appropriate was found.
  23. ; The actual system used to determine where to file what is completely
  24. ; user-customizable (in fact, if the user doesn't customize anything,
  25. ; then the behavior will be just as it was before).  Here are some
  26. ; samples from my .emacs file:
  27.  
  28. ;; LCD Archive Entry:
  29. ;; auto-filer|Garrett Wollman|wollman@uvm-gen.uvm.edu
  30. ;; |Patche to improve mail auto-filing
  31. ;; |91-12-09||~/patches/auto-filer.patch.Z|
  32.  
  33. ;;
  34. ;; This tells VM to use the new auto-filer.  If this is inetgrated
  35. ;; into Emacs (as I would love to see happen), \(.*\)-auto-save should
  36. ;; probably be changed to \1-auto-file, to avoid confusion.  I got a
  37. ;; bit confused myself, at some points.
  38. ;;
  39. (setq vm-use-mail-auto-save t)
  40.  
  41. ;;
  42. ;; set up mail auto-filing
  43. ;;
  44. ;; This works somewhat like, but much better than, the auto-save
  45. ;; feature in the Elm mailer, which is where I'm coming from as a
  46. ;; a new convert to VM and sendmail.
  47. ;;
  48.  
  49. ;; the folders of last resort
  50. (setq mail-auto-save-default (list "~/Mail/misc"))
  51.  
  52. ;;
  53. ;; Note that the keys in this alist are *regexps*.  The function
  54. ;; mail-regex-assq in sendmail.el is a prime target for
  55. ;; optimization.
  56. ;;
  57. (setq mail-auto-save-alist '(("Tom\\.Emerson" "~/Mail/tree")
  58.                  ("Tim\\.Raymond" "~/Mail/raymond")
  59.                  ("Internet\\.Drafts" "~/Mail/ietf")
  60.                  ("Steve\\.Ackerman" "~/Mail/steve")))
  61.  
  62. ;;
  63. ;; Basic logic... if we already have a mailbox for mail from to-name,
  64. ;; then use that.  Otherwise, if the message looks like it is coming
  65. ;; from inside UVM, save it in the mailbox uvm-folk.  Then we punt
  66. ;; back to mail-find-auto-save, which will do the default.
  67. ;;
  68. (defun my-mail-saver (to-name)
  69.   (if (> (length to-name) 0)
  70.       (let* ((off (string-match "@" to-name))
  71.          (prospective (concat (expand-file-name "~/Mail/")
  72.                   (substring to-name 0 off))))
  73.     (if (file-exists-p prospective)
  74.         (list prospective)
  75.       (if (string-match "^[^!@%]+$" to-name)
  76.           (list "~/Mail/uvm-folk")
  77.         (if (string-match "uvm.edu"
  78.                   (substring to-name off nil))
  79.         (list "~/Mail/uvm-folk")))))))
  80.  
  81. (setq mail-auto-save-hook 'my-mail-saver)
  82.  
  83.  
  84. - ----------------------------------------
  85. Some other notes:
  86.  
  87. If you include a line like
  88. [no save]
  89. in your message, it won't be saved by sendmail; this has no effect in
  90. VM, where saving is presumed to be a voluntary action anyway.  This is
  91. also like in Elm.
  92.  
  93. The function mail-first-address, provided by my good friend Tom
  94. Emerson, works for most reasonable addresses, but like anything in
  95. RFC-822 land, it can probably be confused by pathological cases
  96. involving quotation.  Since most people don't do such mean things to
  97. their addresses, I'm not worrying about it.
  98.  
  99. mail-regex-assq should be re-written to operate iteratively, as
  100. suggested in the Lisp Reference Manual.  It should also be re-named
  101. regex-assq and added to the standard lisp routines which are dumped
  102. with Emacs.  (Allow me to take this moment to plug Ange-ftp; it really
  103. is so useful that you should dump it with your Emacs, and don't care
  104. how much pure space it eats up.  I dump both ange-ftp and calc.el (the
  105. "main" module of calc-mode), and it requires about 280k of pure space
  106. on an RS/6000, but I think that it's worth it.)
  107.  
  108. I've been using this system for about two weeks now, and it works
  109. great for me, with the exception that VM loses the "~/" during saves,
  110. which eventually causes it to go into an infinite loop if you don't
  111. add it back, while manually over-riding the suggested location.  I
  112. probably need to put a (save-foo ...) form around the VM code below,
  113. but it's only a minor irritation.  Perhaps someday I'll figure out
  114. what's really going on down there.
  115.  
  116. Questions, comments, suggestions, code, etc. should be sent to
  117. wollman@UVM.EDU.
  118.  
  119. Now for the diffs...
  120. - ------------------------------------------------------------
  121.  
  122. Index: emacs-18.57/lisp/loaddefs.el
  123. - --- loaddefs.el~    Wed Jan  9 17:01:26 1991
  124. +++ loaddefs.el    Thu Nov 28 22:36:24 1991
  125. @@ -1126,6 +1126,24 @@
  126.  Alias of mail address aliases,
  127.  or t meaning should be initialized from .mailrc.")
  128.  
  129. +;;
  130. +;; mail-auto-save variables - GW
  131. +;;
  132. +(defvar mail-auto-save-alist nil "\
  133. +*An associative list of regexps and file names used to automatically
  134. +save outgoing messages into specific folders.  The key is an un-anchored
  135. +regular expression, and the value is a list of folders.")
  136. +
  137. +(defvar mail-auto-save-hook nil "\
  138. +*A function which is called during auto-save after mail-auto-save-alist
  139. +is queried.  It is passed one argument, the value of the From: field.
  140. +Technically, this does not quite count as a hook, so anyone who can think
  141. +of a better name is welcome to change it.")
  142. +
  143. +(defvar mail-auto-save-default nil "\
  144. +*This variable contains a list of folders to which mail is automatically saved
  145. +as a last resort by mail-do-auto-save.")
  146. +
  147.  (autoload 'mail-other-window "sendmail"
  148.    "\
  149.  Like `mail' command, but display mail buffer in another window."
  150.  
  151. Index: emacs-18.57/lisp/sendmail.el
  152. - --- sendmail.el.orig    Wed Jan  9 17:04:09 1991
  153. +++ sendmail.el    Mon Dec  2 13:16:16 1991
  154. @@ -17,8 +17,14 @@
  155.  ;; along with GNU Emacs; see the file COPYING.  If not, write to
  156.  ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  157.  
  158. +;; Modifications by Garrett Wollman to provide Elm-like automatic outbound
  159. +;; mail-filing, based on either mail-auto-save-alist or mail-auto-save-hook,
  160. +;; if the user has defined them.
  161.  
  162. +;; The function "mail-first-address" was written by Tom Emerson <tree@uvm.edu>
  163. +
  164.  (provide 'sendmail)
  165. +(require 'mail-utils)            ; needed for auto-saving
  166.  
  167.  ;(defconst mail-self-blind nil
  168.  ;  "Non-nil means insert BCC to self in messages to be sent.
  169. @@ -209,6 +215,7 @@
  170.          (goto-char (point-min))
  171.          (if (re-search-forward "^FCC:" delimline t)
  172.          (mail-do-fcc delimline))
  173. +        (mail-do-auto-save delimline) ;GW
  174.          ;; If there is a From and no Sender, put it a Sender.
  175.          (goto-char (point-min))
  176.          (and (re-search-forward "^From:"  delimline t)
  177. @@ -302,6 +309,105 @@
  178.      (setq fcc-list (cdr fcc-list))))
  179.      (kill-buffer tembuf)))
  180.  
  181. +;;
  182. +;; This function based on mail-do-fcc, but it grabs the first "To" name
  183. +;; and passes that through mail-find-auto-save to figure out which file
  184. +;; to append to.
  185. +;;
  186. +(defun mail-do-auto-save (header-end)
  187. +  (let (fcc-list
  188. +    (rmailbuf (current-buffer))
  189. +    (tembuf (generate-new-buffer " rmail output"))
  190. +    (case-fold-search t))
  191. +    (save-excursion
  192. +      (goto-char (point-min))
  193. +      (if (re-search-forward "^To:[ \t]*" header-end t)
  194. +      (let ((adr (mail-first-address (mail-strip-quoted-names
  195. +                      (mail-fetch-field "To")))))
  196. +        (setq fcc-list (mail-find-auto-save adr))))
  197. +      (goto-char (marker-position header-end))
  198. +
  199. +      ; if we specified "[no save]" somewhere in the message,
  200. +      ; then don't save it.  This is not quite elm's behavior,
  201. +      ; but it is close enough for most people.
  202. +      (if (re-search-forward "^\\[no save\\]" nil t)
  203. +      (setq fcc-list nil))
  204. +      (set-buffer tembuf)
  205. +      (erase-buffer)
  206. +      (insert "\nFrom " (user-login-name) " "
  207. +          (current-time-string) "\n")
  208. +      (insert-buffer-substring rmailbuf)
  209. +      ;; Make sure messages are separated.
  210. +      (goto-char (point-max))
  211. +      (insert ?\n)
  212. +      (goto-char 2)
  213. +      ;; ``Quote'' "^From " as ">From "
  214. +      ;;  (note that this isn't really quoting, as there is no requirement
  215. +      ;;   that "^[>]+From " be quoted in the same transparent way.)
  216. +      (let ((case-fold-search nil))
  217. +    (while (search-forward "\nFrom " nil t)
  218. +      (forward-char -5)
  219. +      (insert ?>)))
  220. +      (while fcc-list
  221. +    (let ((buffer (get-file-buffer (car fcc-list))))
  222. +      (if buffer
  223. +          ;; File is present in a buffer => append to that buffer.
  224. +          (let ((curbuf (current-buffer))
  225. +            (beg (point-min)) (end (point-max)))
  226. +        (save-excursion
  227. +          (set-buffer buffer)
  228. +          (goto-char (point-max))
  229. +          (insert-buffer-substring curbuf beg end)))
  230. +        ;; Else append to the file directly.
  231. +        (write-region (point-min) (point-max) (car fcc-list) t)))
  232. +    (setq fcc-list (cdr fcc-list))))
  233. +    (kill-buffer tembuf)))
  234. +
  235. +;;
  236. +;; mail-find-auto-save looks at the argument string and tries
  237. +;; to find a way to auto-save it.
  238. +;;
  239. +(defun mail-find-auto-save (to-field)
  240. +  "Try to find a reasonable place to auto-save a message to TO-FIELD.
  241. +This function first checks mail-auto-save-alist, then it tries calling
  242. +mail-auto-save-hook, and then it returns the value of mail-auto-save-default."
  243. +  (if to-field
  244. +      (let ((one-try (mail-regex-assq to-field mail-auto-save-alist)))
  245. +    (if (null one-try)
  246. +        (or (null mail-auto-save-hook)
  247. +        (setq one-try
  248. +              (apply mail-auto-save-hook
  249. +                 (list to-field)))))
  250. +    (if (null one-try)
  251. +        (setq one-try mail-auto-save-default))
  252. +    one-try)
  253. +    nil))
  254. +
  255. +;;
  256. +;; mail-regex-assq is like assq, but uses string-match as the testing
  257. +;; predicate
  258. +;;
  259. +(defun mail-regex-assq (key alist)
  260. +  "Acts like assq, but using string-match as the key-comparison predicate."
  261. +  (if (null alist)
  262. +      nil
  263. +    (if (string-match (car (car alist)) key)
  264. +    (cdr (car alist))
  265. +      (mail-regex-assq key (cdr alist)))))
  266. +
  267. +
  268. +;;; This function written by Tom Emerson...
  269. +;;; Given a string containing a group of comma separated addresses
  270. +;;; (such as that returned by mail-fetch-field) the following
  271. +;;; function returns the first address in the list.
  272. +(defun mail-first-address (addresses)
  273. +  (let* ((clean (substring addresses 
  274. +               (or (string-match "[^ \t]" addresses) 0)))
  275. +     (pos (string-match "[ \t]*,[ \t]*" clean)))
  276. +    (if (not pos) clean
  277. +      (substring clean 0 pos))))
  278. +
  279. +
  280.  (defun mail-to ()
  281.    "Move point to end of To-field."
  282.    (interactive)
  283.  
  284. Index: vm-4.41/vm-save.el
  285. - --- vm-save.el.orig    Fri Nov 29 01:05:56 1991
  286. +++ vm-save.el    Mon Dec  2 12:44:16 1991
  287. @@ -15,8 +15,15 @@
  288.  ;;; along with this program; if not, write to the Free Software
  289.  ;;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  290.  
  291. +;; changes by Garrett Wollman to use mail-find-auto-save if
  292. +;; vm-use-mail-auto-save is defined
  293. +
  294.  (require 'vm)
  295.  
  296. +(defvar vm-use-mail-auto-save nil "\
  297. +Tells VM to use the auto-save routine built into our version of
  298. +sendmail for selecting which buffer to save messages in.")
  299. +
  300.  ;; (match-data) returns the match data as MARKERS, often corrupting
  301.  ;; it in the process due to buffer narrowing, and the fact that buffers are
  302.  ;; indexed from 1 while strings are indexed from 0. :-(
  303. @@ -28,6 +35,18 @@
  304.                 '(0 1 2 3 4 5 6 7 8 9)))))
  305.  
  306.  (defun vm-auto-select-folder (mp)
  307. +  (if vm-use-mail-auto-save
  308. +      (progn
  309. +    (require 'sendmail)
  310. +    (new-vm-auto-select-folder mp))
  311. +    (old-vm-auto-select-folder mp)))
  312. +
  313. +(defun new-vm-auto-select-folder (mp)
  314. +  (car-safe (mail-find-auto-save
  315. +         (or (vm-get-header-contents (car mp) "From")
  316. +         (vm-get-header-contents (car mp) "To")))))
  317. +
  318. +(defun old-vm-auto-select-folder (mp)
  319.    (condition-case ()
  320.        (catch 'match
  321.      (let (header alist tuple-list)
  322.