home *** CD-ROM | disk | FTP | other *** search
/ DP Tool Club 31 / CDASC_31_1996_juillet_aout.iso / vrac_os2 / e31el3.zip / EMACS / 19.31 / LISP / RMAILOUT.EL < prev    next >
Lisp/Scheme  |  1996-01-20  |  12KB  |  323 lines

  1. ;;; rmailout.el --- "RMAIL" mail reader for Emacs: output message to a file.
  2.  
  3. ;; Copyright (C) 1985, 1987, 1993, 1994 Free Software Foundation, Inc.
  4.  
  5. ;; Maintainer: FSF
  6. ;; Keywords: mail
  7.  
  8. ;; This file is part of GNU Emacs.
  9.  
  10. ;; GNU Emacs is free software; you can redistribute it and/or modify
  11. ;; it under the terms of the GNU General Public License as published by
  12. ;; the Free Software Foundation; either version 2, or (at your option)
  13. ;; any later version.
  14.  
  15. ;; GNU Emacs is distributed in the hope that it will be useful,
  16. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18. ;; GNU General Public License for more details.
  19.  
  20. ;; You should have received a copy of the GNU General Public License
  21. ;; along with GNU Emacs; see the file COPYING.  If not, write to the
  22. ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  23. ;; Boston, MA 02111-1307, USA.
  24.  
  25. ;;; Code:
  26.  
  27. (require 'rmail)
  28.  
  29. ;; Temporary until Emacs always has this variable.
  30. (defvar rmail-delete-after-output nil
  31.   "*Non-nil means automatically delete a message that is copied to a file.")
  32.  
  33. (defvar rmail-output-file-alist nil
  34.   "*Alist matching regexps to suggested output Rmail files.
  35. This is a list of elements of the form (REGEXP . NAME-EXP).
  36. The suggestion is taken if REGEXP matches anywhere in the message buffer.
  37. NAME-EXP may be a string constant giving the file name to use,
  38. or more generally it may be any kind of expression that returns
  39. a file name as a string.")
  40.  
  41. ;;; There are functions elsewhere in Emacs that use this function; check
  42. ;;; them out before you change the calling method.
  43. (defun rmail-output-to-rmail-file (file-name &optional count)
  44.   "Append the current message to an Rmail file named FILE-NAME.
  45. If the file does not exist, ask if it should be created.
  46. If file is being visited, the message is appended to the Emacs
  47. buffer visiting that file.
  48. If the file exists and is not an Rmail file, 
  49. the message is appended in inbox format.
  50.  
  51. The default file name comes from `rmail-default-rmail-file',
  52. which is updated to the name you use in this command.
  53.  
  54. A prefix argument N says to output N consecutive messages
  55. starting with the current one.  Deleted messages are skipped and don't count."
  56.   (interactive
  57.    (let ((default-file
  58.        (let (answer tail)
  59.          (setq tail rmail-output-file-alist)
  60.          ;; Suggest a file based on a pattern match.
  61.          (while (and tail (not answer))
  62.            (save-excursion
  63.          (goto-char (point-min))
  64.          (if (re-search-forward (car (car tail)) nil t)
  65.              (setq answer (eval (cdr (car tail)))))
  66.          (setq tail (cdr tail))))
  67.          ;; If not suggestions, use same file as last time.
  68.          (or answer rmail-default-rmail-file))))
  69.      (list (setq rmail-default-rmail-file
  70.          (let ((read-file
  71.             (read-file-name
  72.              (concat "Output message to Rmail file: (default "
  73.                  (file-name-nondirectory default-file)
  74.                  ") ")
  75.              (file-name-directory default-file)
  76.              default-file)))
  77.            (if (file-directory-p read-file)
  78.                (expand-file-name (file-name-nondirectory default-file)
  79.                      read-file)
  80.              (expand-file-name
  81.               (or read-file default-file)
  82.               (file-name-directory default-file)))))
  83.        (prefix-numeric-value current-prefix-arg))))
  84.   (or count (setq count 1))
  85.   (setq file-name
  86.     (expand-file-name file-name
  87.               (file-name-directory rmail-default-rmail-file)))
  88.   (if (and (file-readable-p file-name) (not (mail-file-babyl-p file-name)))
  89.       (rmail-output file-name count)
  90.     (rmail-maybe-set-message-counters)
  91.     (setq file-name (abbreviate-file-name file-name))
  92.     (or (get-file-buffer file-name)
  93.     (file-exists-p file-name)
  94.     (if (yes-or-no-p
  95.          (concat "\"" file-name "\" does not exist, create it? "))
  96.         (let ((file-buffer (create-file-buffer file-name)))
  97.           (save-excursion
  98.         (set-buffer file-buffer)
  99.         (rmail-insert-rmail-file-header)
  100.         (let ((require-final-newline nil))
  101.           (write-region (point-min) (point-max) file-name t 1)))
  102.           (kill-buffer file-buffer))
  103.       (error "Output file does not exist")))
  104.     (while (> count 0)
  105.       (let (redelete)
  106.     (unwind-protect
  107.         (progn
  108.           ;; Temporarily turn off Deleted attribute.
  109.           ;; Do this outside the save-restriction, since it would
  110.           ;; shift the place in the buffer where the visible text starts.
  111.           (if (rmail-message-deleted-p rmail-current-message)
  112.           (progn (setq redelete t)
  113.              (rmail-set-attribute "deleted" nil)))
  114.           (save-restriction
  115.         (widen)
  116.         ;; Decide whether to append to a file or to an Emacs buffer.
  117.         (save-excursion
  118.           (let ((buf (get-file-buffer file-name))
  119.             (cur (current-buffer))
  120.             (beg (1+ (rmail-msgbeg rmail-current-message)))
  121.             (end (1+ (rmail-msgend rmail-current-message))))
  122.             (if (not buf)
  123.             ;; Output to a file.
  124.             (if rmail-fields-not-to-output
  125.                 ;; Delete some fields while we output.
  126.                 (let ((obuf (current-buffer)))
  127.                   (set-buffer (get-buffer-create " rmail-out-temp"))
  128.                   (insert-buffer-substring obuf beg end)
  129.                   (rmail-delete-unwanted-fields)
  130.                   (append-to-file (point-min) (point-max) file-name)
  131.                   (set-buffer obuf)
  132.                   (kill-buffer (get-buffer " rmail-out-temp")))
  133.               (append-to-file beg end file-name))
  134.               (if (eq buf (current-buffer))
  135.               (error "Can't output message to same file it's already in"))
  136.               ;; File has been visited, in buffer BUF.
  137.               (set-buffer buf)
  138.               (let ((buffer-read-only nil)
  139.                 (msg (and (boundp 'rmail-current-message)
  140.                       rmail-current-message)))
  141.             ;; If MSG is non-nil, buffer is in RMAIL mode.
  142.             (if msg
  143.                 (progn
  144.                   ;; Turn on auto save mode, if it's off in this
  145.                   ;; buffer but enabled by default.
  146.                   (and (not buffer-auto-save-file-name)
  147.                    auto-save-default
  148.                    (auto-save-mode t))
  149.                   (rmail-maybe-set-message-counters)
  150.                   (widen)
  151.                   (narrow-to-region (point-max) (point-max))
  152.                   (insert-buffer-substring cur beg end)
  153.                   (goto-char (point-min))
  154.                   (widen)
  155.                   (search-backward "\n\^_")
  156.                   (narrow-to-region (point) (point-max))
  157.                   (rmail-delete-unwanted-fields)
  158.                   (rmail-count-new-messages t)
  159.                   (if (rmail-summary-exists)
  160.                   (rmail-select-summary
  161.                     (rmail-update-summary)))
  162.                   (rmail-show-message msg))
  163.         ;; Output file not in rmail mode => just insert at the end.
  164.         (narrow-to-region (point-min) (1+ (buffer-size)))
  165.         (goto-char (point-max))
  166.         (insert-buffer-substring cur beg end)
  167.         (rmail-delete-unwanted-fields)))))))
  168.           (rmail-set-attribute "filed" t))
  169.       (if redelete (rmail-set-attribute "deleted" t))))
  170.       (setq count (1- count))
  171.       (if rmail-delete-after-output
  172.       (rmail-delete-forward)
  173.     (if (> count 0)
  174.         (rmail-next-undeleted-message 1))))))
  175.  
  176. (defvar rmail-fields-not-to-output nil
  177.   "*Regexp describing fields to exclude when outputting a message to a file.")
  178.  
  179. ;; Delete from the buffer header fields we don't want output.
  180. ;; NOT-RMAIL if t means this buffer does not have the full header
  181. ;; and *** EOOH *** that a message in an Rmail file has.
  182. (defun rmail-delete-unwanted-fields (&optional not-rmail)
  183.   (if rmail-fields-not-to-output 
  184.       (save-excursion
  185.     (goto-char (point-min))
  186.     ;; Find the end of the header.
  187.     (if (and (or not-rmail (search-forward "\n*** EOOH ***\n" nil t))
  188.          (search-forward "\n\n" nil t))
  189.         (let ((end (point-marker)))
  190.           (goto-char (point-min))
  191.           (while (re-search-forward rmail-fields-not-to-output end t)
  192.         (beginning-of-line)
  193.         (delete-region (point)
  194.                    (progn (forward-line 1) (point)))))))))
  195.  
  196. ;;; There are functions elsewhere in Emacs that use this function; check
  197. ;;; them out before you change the calling method.
  198. (defun rmail-output (file-name &optional count noattribute from-gnus)
  199.   "Append this message to system-inbox-format mail file named FILE-NAME.
  200. A prefix argument N says to output N consecutive messages
  201. starting with the current one.  Deleted messages are skipped and don't count.
  202. When called from lisp code, N may be omitted.
  203.  
  204. If the pruned message header is shown on the current message, then
  205. messages will be appended with pruned headers; otherwise, messages
  206. will be appended with their original headers.
  207.  
  208. The default file name comes from `rmail-default-file',
  209. which is updated to the name you use in this command.
  210.  
  211. The optional third argument NOATTRIBUTE, if non-nil, says not
  212. to set the `filed' attribute, and not to display a message.
  213.  
  214. The optional fourth argument FROM-GNUS is set when called from GNUS."
  215.   (interactive
  216.    (let ((default-file
  217.        (let (answer tail)
  218.          (setq tail rmail-output-file-alist)
  219.          ;; Suggest a file based on a pattern match.
  220.          (while (and tail (not answer))
  221.            (save-excursion
  222.          (goto-char (point-min))
  223.          (if (re-search-forward (car (car tail)) nil t)
  224.              (setq answer (eval (cdr (car tail)))))
  225.          (setq tail (cdr tail))))
  226.          ;; If not suggestions, use same file as last time.
  227.          (or answer rmail-default-file))))
  228.      (list (setq rmail-default-file
  229.          (let ((read-file
  230.             (read-file-name
  231.              (concat "Output message to Unix mail file: (default "
  232.                  (file-name-nondirectory default-file)
  233.                  ") ")
  234.              (file-name-directory default-file)
  235.              default-file)))
  236.            (if (file-directory-p read-file)
  237.                (expand-file-name (file-name-nondirectory default-file)
  238.                      read-file)
  239.              (expand-file-name
  240.               (or read-file default-file)
  241.               (file-name-directory default-file)))))
  242.        (prefix-numeric-value current-prefix-arg))))
  243.   (or count (setq count 1))
  244.   (setq file-name
  245.     (expand-file-name file-name
  246.               (and rmail-default-file
  247.                    (file-name-directory rmail-default-file))))
  248.   (if (and (file-readable-p file-name) (mail-file-babyl-p file-name))
  249.       (rmail-output-to-rmail-file file-name count)
  250.     (let ((orig-count count)
  251.       (rmailbuf (current-buffer))
  252.       (case-fold-search t)
  253.       (tembuf (get-buffer-create " rmail-output"))
  254.       (original-headers-p
  255.        (and (not from-gnus)
  256.         (save-excursion 
  257.           (save-restriction
  258.             (narrow-to-region (rmail-msgbeg rmail-current-message) (point-max))
  259.             (goto-char (point-min))
  260.             (forward-line 1)
  261.             (= (following-char) ?0)))))
  262.       header-beginning
  263.       mail-from)
  264.       (while (> count 0)
  265.     (or from-gnus
  266.         (setq mail-from
  267.           (save-excursion
  268.             (save-restriction
  269.               (widen)
  270.               (goto-char (rmail-msgbeg rmail-current-message))
  271.               (setq header-beginning (point))
  272.               (search-forward "\n*** EOOH ***\n")
  273.               (narrow-to-region header-beginning (point))
  274.               (mail-fetch-field "Mail-From")))))
  275.     (save-excursion
  276.       (set-buffer tembuf)
  277.       (erase-buffer)
  278.       (insert-buffer-substring rmailbuf)
  279.       (rmail-delete-unwanted-fields t)
  280.       (insert "\n")
  281.       (goto-char (point-min))
  282.       (if mail-from
  283.           (insert mail-from "\n")
  284.         (insert "From "
  285.             (mail-strip-quoted-names (or (mail-fetch-field "from")
  286.                          (mail-fetch-field "really-from")
  287.                          (mail-fetch-field "sender")
  288.                          "unknown"))
  289.             " " (current-time-string) "\n"))
  290.       ;; ``Quote'' "\nFrom " as "\n>From "
  291.       ;;  (note that this isn't really quoting, as there is no requirement
  292.       ;;   that "\n[>]+From " be quoted in the same transparent way.)
  293.       (let ((case-fold-search nil))
  294.         (while (search-forward "\nFrom " nil t)
  295.           (forward-char -5)
  296.           (insert ?>)))
  297.       (write-region (point-min) (point-max) file-name t
  298.             (if noattribute 'nomsg)))
  299.     (or noattribute
  300.         (if (equal major-mode 'rmail-mode)
  301.         (rmail-set-attribute "filed" t)))
  302.     (setq count (1- count))
  303.     (or from-gnus
  304.         (let ((next-message-p
  305.            (if rmail-delete-after-output
  306.                (rmail-delete-forward)
  307.              (if (> count 0)
  308.              (rmail-next-undeleted-message 1))))
  309.           (num-appended (- orig-count count)))
  310.           (if (and next-message-p original-headers-p)
  311.           (rmail-toggle-header))
  312.           (if (and (> count 0) (not next-message-p))
  313.           (progn 
  314.             (error
  315.              (save-excursion
  316.                (set-buffer rmailbuf)
  317.                (format "Only %d message%s appended" num-appended
  318.                    (if (= num-appended 1) "" "s"))))
  319.             (setq count 0))))))
  320.       (kill-buffer tembuf))))
  321.  
  322. ;;; rmailout.el ends here
  323.