diff options
| author | Richard M. Stallman | 2008-12-29 19:12:22 +0000 |
|---|---|---|
| committer | Richard M. Stallman | 2008-12-29 19:12:22 +0000 |
| commit | 5921f0a48cc137ff342ddfdd25b3bdec18c0baca (patch) | |
| tree | c159e83408c7daad6a2226ee6f5b0f2525b8dd09 | |
| parent | e3021fe7dbe7a4bbbe9b4c9433c0f01f64cdcef3 (diff) | |
| download | emacs-5921f0a48cc137ff342ddfdd25b3bdec18c0baca.tar.gz emacs-5921f0a48cc137ff342ddfdd25b3bdec18c0baca.zip | |
(pmail-output-decode-coding): New variable.
(pmail-delete-unwanted-fields): Greatly simplified.
(pmail-output-as-babyl): New function.
(pmail-convert-to-babyl-format): Considerably simplified:
assume just one message and don't worry about Content-Type.
(pmail-output-as-mbox): New function.
(pmail-output): Total rewrite.
(pmail-output-as-seen): New command.
(pmail-output-read-pmail-file-name): Function deleted.
(pmail-output-to-babyl-file): Function deleted.
(pmail-output-body-to-file): Don't set an attribute.
| -rw-r--r-- | lisp/mail/pmailout.el | 691 |
1 files changed, 307 insertions, 384 deletions
diff --git a/lisp/mail/pmailout.el b/lisp/mail/pmailout.el index ad00211d012..2d459453b2f 100644 --- a/lisp/mail/pmailout.el +++ b/lisp/mail/pmailout.el | |||
| @@ -29,6 +29,13 @@ | |||
| 29 | (provide 'pmailout) | 29 | (provide 'pmailout) |
| 30 | 30 | ||
| 31 | ;;;###autoload | 31 | ;;;###autoload |
| 32 | (defcustom pmail-output-decode-coding nil | ||
| 33 | "*If non-nil, do coding system decoding when outputting message as Babyl." | ||
| 34 | :type '(choice (const :tag "on" t) | ||
| 35 | (const :tag "off" nil)) | ||
| 36 | :group 'pmail) | ||
| 37 | |||
| 38 | ;;;###autoload | ||
| 32 | (defcustom pmail-output-file-alist nil | 39 | (defcustom pmail-output-file-alist nil |
| 33 | "*Alist matching regexps to suggested output Pmail files. | 40 | "*Alist matching regexps to suggested output Pmail files. |
| 34 | This is a list of elements of the form (REGEXP . NAME-EXP). | 41 | This is a list of elements of the form (REGEXP . NAME-EXP). |
| @@ -42,39 +49,6 @@ a file name as a string." | |||
| 42 | sexp))) | 49 | sexp))) |
| 43 | :group 'pmail-output) | 50 | :group 'pmail-output) |
| 44 | 51 | ||
| 45 | (defun pmail-output-read-pmail-file-name () | ||
| 46 | "Read the file name to use for `pmail-output-to-babyl-file'. | ||
| 47 | Set `pmail-default-pmail-file' to this name as well as returning it." | ||
| 48 | (let ((default-file | ||
| 49 | (let (answer tail) | ||
| 50 | (setq tail pmail-output-file-alist) | ||
| 51 | ;; Suggest a file based on a pattern match. | ||
| 52 | (while (and tail (not answer)) | ||
| 53 | (save-excursion | ||
| 54 | (set-buffer pmail-buffer) | ||
| 55 | (goto-char (point-min)) | ||
| 56 | (if (re-search-forward (car (car tail)) nil t) | ||
| 57 | (setq answer (eval (cdr (car tail))))) | ||
| 58 | (setq tail (cdr tail)))) | ||
| 59 | ;; If no suggestions, use same file as last time. | ||
| 60 | (expand-file-name (or answer pmail-default-pmail-file))))) | ||
| 61 | (let ((read-file | ||
| 62 | (expand-file-name | ||
| 63 | (read-file-name | ||
| 64 | (concat "Output message to Pmail file (default " | ||
| 65 | (file-name-nondirectory default-file) | ||
| 66 | "): ") | ||
| 67 | (file-name-directory default-file) | ||
| 68 | (abbreviate-file-name default-file)) | ||
| 69 | (file-name-directory default-file)))) | ||
| 70 | ;; If the user enters just a directory, | ||
| 71 | ;; use the name within that directory chosen by the default. | ||
| 72 | (setq pmail-default-pmail-file | ||
| 73 | (if (file-directory-p read-file) | ||
| 74 | (expand-file-name (file-name-nondirectory default-file) | ||
| 75 | read-file) | ||
| 76 | read-file))))) | ||
| 77 | |||
| 78 | (defun pmail-output-read-file-name () | 52 | (defun pmail-output-read-file-name () |
| 79 | "Read the file name to use for `pmail-output'. | 53 | "Read the file name to use for `pmail-output'. |
| 80 | Set `pmail-default-file' to this name as well as returning it." | 54 | Set `pmail-default-file' to this name as well as returning it." |
| @@ -93,7 +67,7 @@ Set `pmail-default-file' to this name as well as returning it." | |||
| 93 | (let ((read-file | 67 | (let ((read-file |
| 94 | (expand-file-name | 68 | (expand-file-name |
| 95 | (read-file-name | 69 | (read-file-name |
| 96 | (concat "Output message to Unix mail file (default " | 70 | (concat "Output message to mail file (default " |
| 97 | (file-name-nondirectory default-file) | 71 | (file-name-nondirectory default-file) |
| 98 | "): ") | 72 | "): ") |
| 99 | (file-name-directory default-file) | 73 | (file-name-directory default-file) |
| @@ -107,244 +81,137 @@ Set `pmail-default-file' to this name as well as returning it." | |||
| 107 | (or read-file (file-name-nondirectory default-file)) | 81 | (or read-file (file-name-nondirectory default-file)) |
| 108 | (file-name-directory default-file))))))) | 82 | (file-name-directory default-file))))))) |
| 109 | 83 | ||
| 110 | (declare-function pmail-update-summary "pmailsum" (&rest ignore)) | ||
| 111 | |||
| 112 | ;;; There are functions elsewhere in Emacs that use this function; | ||
| 113 | ;;; look at them before you change the calling method. | ||
| 114 | ;;;###autoload | 84 | ;;;###autoload |
| 115 | (defun pmail-output-to-babyl-file (file-name &optional count stay) | 85 | (defcustom pmail-fields-not-to-output nil |
| 116 | "Append the current message to a Babyl file named FILE-NAME. | 86 | "*Regexp describing fields to exclude when outputting a message to a file." |
| 117 | If the file does not exist, ask if it should be created. | 87 | :type '(choice (const :tag "None" nil) |
| 118 | If file is being visited, the message is appended to the Emacs | 88 | regexp) |
| 119 | buffer visiting that file. | 89 | :group 'pmail-output) |
| 120 | If the file exists and is not a Babyl file, the message is | ||
| 121 | appended in inbox format, the same way `pmail-output' does it. | ||
| 122 | |||
| 123 | The default file name comes from `pmail-default-pmail-file', | ||
| 124 | which is updated to the name you use in this command. | ||
| 125 | 90 | ||
| 126 | A prefix argument COUNT says to output that many consecutive messages, | 91 | ;; Delete from the buffer header fields we don't want output. |
| 127 | starting with the current one. Deleted messages are skipped and don't count. | 92 | ;; Buffer should be pre-narrowed to the header. |
| 93 | ;; PRESERVE is a regexp for fields NEVER to delete. | ||
| 94 | (defun pmail-delete-unwanted-fields (preserve) | ||
| 95 | (if pmail-fields-not-to-output | ||
| 96 | (save-excursion | ||
| 97 | (goto-char (point-min)) | ||
| 98 | (while (re-search-forward pmail-fields-not-to-output nil t) | ||
| 99 | (beginning-of-line) | ||
| 100 | (unless (looking-at preserve) | ||
| 101 | (delete-region (point) | ||
| 102 | (progn (forward-line 1) (point)))))))) | ||
| 103 | |||
| 104 | (defun pmail-output-as-babyl (file-name nomsg) | ||
| 105 | "Convert the current buffer's text to Babyl and output to FILE-NAME. | ||
| 106 | It alters the current buffer's text, so it should be a temp buffer." | ||
| 107 | (let ((coding-system-for-write | ||
| 108 | 'emacs-mule-unix)) | ||
| 109 | (save-restriction | ||
| 110 | (goto-char (point-min)) | ||
| 111 | (search-forward "\n\n" nil 'move) | ||
| 112 | (narrow-to-region (point-min) (point)) | ||
| 113 | (if pmail-fields-not-to-output | ||
| 114 | (pmail-delete-unwanted-fields nil))) | ||
| 128 | 115 | ||
| 129 | If the optional argument STAY is non-nil, then leave the last filed | 116 | ;; Convert to Babyl format. |
| 130 | message up instead of moving forward to the next non-deleted message." | 117 | (pmail-convert-to-babyl-format) |
| 131 | (interactive | 118 | ;; Write it into the file. |
| 132 | (list (pmail-output-read-pmail-file-name) | 119 | (write-region (point-min) (point-max) file-name t nomsg))) |
| 133 | (prefix-numeric-value current-prefix-arg))) | ||
| 134 | (or count (setq count 1)) | ||
| 135 | (setq file-name | ||
| 136 | (expand-file-name file-name | ||
| 137 | (file-name-directory pmail-default-pmail-file))) | ||
| 138 | (if (and (file-readable-p file-name) (not (mail-file-babyl-p file-name))) | ||
| 139 | (pmail-output file-name count) | ||
| 140 | (pmail-maybe-set-message-counters) | ||
| 141 | (setq file-name (abbreviate-file-name file-name)) | ||
| 142 | (or (find-buffer-visiting file-name) | ||
| 143 | (file-exists-p file-name) | ||
| 144 | (if (yes-or-no-p | ||
| 145 | (concat "\"" file-name "\" does not exist, create it? ")) | ||
| 146 | (let ((file-buffer (create-file-buffer file-name))) | ||
| 147 | (save-excursion | ||
| 148 | (set-buffer file-buffer) | ||
| 149 | (let ((buffer-read-only nil)) | ||
| 150 | (insert "BABYL OPTIONS: -*- pmail -*- | ||
| 151 | Version: 5 | ||
| 152 | Labels: | ||
| 153 | Note: This is the header of an pmail file. | ||
| 154 | Note: If you are seeing it in pmail, | ||
| 155 | Note: it means the file has no messages in it.\n\^_")) | ||
| 156 | (let ((require-final-newline nil) | ||
| 157 | (coding-system-for-write | ||
| 158 | (or pmail-file-coding-system | ||
| 159 | 'emacs-mule-unix))) | ||
| 160 | (write-region (point-min) (point-max) file-name t 1))) | ||
| 161 | (kill-buffer file-buffer)) | ||
| 162 | (error "Output file does not exist"))) | ||
| 163 | (while (> count 0) | ||
| 164 | (let (redelete) | ||
| 165 | (unwind-protect | ||
| 166 | (progn | ||
| 167 | (set-buffer pmail-buffer) | ||
| 168 | ;; Temporarily turn off Deleted attribute. | ||
| 169 | ;; Do this outside the save-restriction, since it would | ||
| 170 | ;; shift the place in the buffer where the visible text starts. | ||
| 171 | (if (pmail-message-deleted-p pmail-current-message) | ||
| 172 | (progn (setq redelete t) | ||
| 173 | (pmail-set-attribute pmail-deleted-attr-index nil))) | ||
| 174 | (let ((coding-system-for-write | ||
| 175 | (or pmail-file-coding-system | ||
| 176 | 'emacs-mule-unix)) | ||
| 177 | cur beg end) | ||
| 178 | (pmail-swap-buffers-maybe) | ||
| 179 | (setq cur (current-buffer)) | ||
| 180 | (save-restriction | ||
| 181 | (save-excursion | ||
| 182 | (widen) | ||
| 183 | (setq beg (pmail-msgbeg pmail-current-message) | ||
| 184 | end (pmail-msgend pmail-current-message)) | ||
| 185 | ;; Output to a file. | ||
| 186 | (set-buffer (get-buffer-create " pmail-out-temp")) | ||
| 187 | (insert-buffer-substring cur beg end) | ||
| 188 | (if pmail-fields-not-to-output | ||
| 189 | (pmail-delete-unwanted-fields)) | ||
| 190 | ;; Convert to Babyl format. | ||
| 191 | (pmail-convert-to-babyl-format) | ||
| 192 | (append-to-file (point-min) (point-max) file-name) | ||
| 193 | (set-buffer cur) | ||
| 194 | (kill-buffer (get-buffer " pmail-out-temp"))))) | ||
| 195 | (pmail-set-attribute pmail-filed-attr-index t)) | ||
| 196 | (if redelete (pmail-set-attribute pmail-deleted-attr-index t)))) | ||
| 197 | (setq count (1- count)) | ||
| 198 | (if pmail-delete-after-output | ||
| 199 | (unless (if (and (= count 0) stay) | ||
| 200 | (pmail-delete-message) | ||
| 201 | (pmail-delete-forward)) | ||
| 202 | (setq count 0)) | ||
| 203 | (if (> count 0) | ||
| 204 | (unless (if (not stay) | ||
| 205 | (pmail-next-undeleted-message 1)) | ||
| 206 | (setq count 0)))))) | ||
| 207 | (pmail-show-message)) | ||
| 208 | |||
| 209 | (defalias 'pmail-output-to-pmail-file 'pmail-output-to-babyl-file) | ||
| 210 | 120 | ||
| 211 | (defun pmail-convert-to-babyl-format () | 121 | (defun pmail-convert-to-babyl-format () |
| 212 | (let ((count 0) start | 122 | (let ((count 0) (start (point-min)) |
| 213 | (case-fold-search nil) | 123 | (case-fold-search nil) |
| 214 | (buffer-undo-list t)) | 124 | (buffer-undo-list t)) |
| 215 | (goto-char (point-min)) | 125 | (goto-char (point-min)) |
| 216 | (save-restriction | 126 | (save-restriction |
| 217 | (while (not (eobp)) | 127 | (unless (looking-at "^From ") |
| 218 | (setq start (point)) | 128 | (error "Invalid mbox message")) |
| 219 | (unless (looking-at "^From ") | 129 | (insert "\^L\n0, unseen,,\n*** EOOH ***\n") |
| 220 | (error "Invalid mbox message")) | 130 | (pmail-nuke-pinhead-header) |
| 221 | (insert "\^L\n0, unseen,,\n*** EOOH ***\n") | 131 | ;; Decode base64 or quoted printable contents, Rmail style. |
| 222 | (pmail-nuke-pinhead-header) | 132 | (let* ((header-end (save-excursion |
| 223 | ;; If this message has a Content-Length field, | 133 | (and (re-search-forward "\n\n" nil t) |
| 224 | ;; skip to the end of the contents. | 134 | (1- (point))))) |
| 225 | (let* ((header-end (save-excursion | 135 | (case-fold-search t) |
| 226 | (and (re-search-forward "\n\n" nil t) | 136 | (quoted-printable-header-field-end |
| 227 | (1- (point))))) | ||
| 228 | (case-fold-search t) | ||
| 229 | (quoted-printable-header-field-end | ||
| 230 | (save-excursion | ||
| 231 | (re-search-forward | ||
| 232 | "^content-transfer-encoding:\\(\n?[\t ]\\)*quoted-printable\\(\n?[\t ]\\)*" | ||
| 233 | header-end t))) | ||
| 234 | (base64-header-field-end | ||
| 235 | (and | ||
| 236 | ;; Don't decode non-text data. | ||
| 237 | (save-excursion | ||
| 238 | (re-search-forward | ||
| 239 | "^content-type:\\(\n?[\t ]\\)\\(text\\|message\\)/" | ||
| 240 | header-end t)) | ||
| 241 | (save-excursion | ||
| 242 | (re-search-forward | ||
| 243 | "^content-transfer-encoding:\\(\n?[\t ]\\)*base64\\(\n?[\t ]\\)*" | ||
| 244 | header-end t)))) | ||
| 245 | (size | ||
| 246 | ;; Get the numeric value from the Content-Length field. | ||
| 247 | (save-excursion | ||
| 248 | ;; Back up to end of prev line, | ||
| 249 | ;; in case the Content-Length field comes first. | ||
| 250 | (forward-char -1) | ||
| 251 | (and (search-forward "\ncontent-length: " | ||
| 252 | header-end t) | ||
| 253 | (let ((beg (point)) | ||
| 254 | (eol (progn (end-of-line) (point)))) | ||
| 255 | (string-to-number (buffer-substring beg eol))))))) | ||
| 256 | (and size | ||
| 257 | (if (and (natnump size) | ||
| 258 | (<= (+ header-end size) (point-max)) | ||
| 259 | ;; Make sure this would put us at a position | ||
| 260 | ;; that we could continue from. | ||
| 261 | (save-excursion | ||
| 262 | (goto-char (+ header-end size)) | ||
| 263 | (skip-chars-forward "\n") | ||
| 264 | (or (eobp) | ||
| 265 | (and (looking-at "BABYL OPTIONS:") | ||
| 266 | (search-forward "\n\^_" nil t)) | ||
| 267 | (and (looking-at "\^L") | ||
| 268 | (search-forward "\n\^_" nil t)) | ||
| 269 | (let ((case-fold-search t)) | ||
| 270 | (looking-at pmail-mmdf-delim1)) | ||
| 271 | (looking-at "From ")))) | ||
| 272 | (goto-char (+ header-end size)) | ||
| 273 | (message "Ignoring invalid Content-Length field") | ||
| 274 | (sit-for 1 0 t))) | ||
| 275 | (if (let ((case-fold-search nil)) | ||
| 276 | (re-search-forward | ||
| 277 | (concat "^[\^_]?\\(" | ||
| 278 | pmail-unix-mail-delimiter | ||
| 279 | "\\|" | ||
| 280 | pmail-mmdf-delim1 "\\|" | ||
| 281 | "^BABYL OPTIONS:\\|" | ||
| 282 | "\^L\n[01],\\)") nil t)) | ||
| 283 | (goto-char (match-beginning 1)) | ||
| 284 | (goto-char (point-max))) | ||
| 285 | (setq count (1+ count)) | ||
| 286 | (if quoted-printable-header-field-end | ||
| 287 | (save-excursion | 137 | (save-excursion |
| 288 | (unless (mail-unquote-printable-region | 138 | (re-search-forward |
| 289 | header-end (point) nil t t) | 139 | "^content-transfer-encoding:\\(\n?[\t ]\\)*quoted-printable\\(\n?[\t ]\\)*" |
| 290 | (message "Malformed MIME quoted-printable message")) | 140 | header-end t))) |
| 291 | ;; Change "quoted-printable" to "8bit", | 141 | (base64-header-field-end |
| 292 | ;; to reflect the decoding we just did. | 142 | (and |
| 293 | (goto-char quoted-printable-header-field-end) | 143 | ;; Don't decode non-text data. |
| 144 | (save-excursion | ||
| 145 | (re-search-forward | ||
| 146 | "^content-type:\\(\n?[\t ]\\)\\(text\\|message\\)/" | ||
| 147 | header-end t)) | ||
| 148 | (save-excursion | ||
| 149 | (re-search-forward | ||
| 150 | "^content-transfer-encoding:\\(\n?[\t ]\\)*base64\\(\n?[\t ]\\)*" | ||
| 151 | header-end t))))) | ||
| 152 | |||
| 153 | (goto-char (point-max)) | ||
| 154 | (if quoted-printable-header-field-end | ||
| 155 | (save-excursion | ||
| 156 | (unless (mail-unquote-printable-region | ||
| 157 | header-end (point) nil t t) | ||
| 158 | (message "Malformed MIME quoted-printable message")) | ||
| 159 | ;; Change "quoted-printable" to "8bit", | ||
| 160 | ;; to reflect the decoding we just did. | ||
| 161 | (goto-char quoted-printable-header-field-end) | ||
| 162 | (delete-region (point) (search-backward ":")) | ||
| 163 | (insert ": 8bit"))) | ||
| 164 | (if base64-header-field-end | ||
| 165 | (save-excursion | ||
| 166 | (when (condition-case nil | ||
| 167 | (progn | ||
| 168 | (base64-decode-region | ||
| 169 | (1+ header-end) | ||
| 170 | (save-excursion | ||
| 171 | ;; Prevent base64-decode-region | ||
| 172 | ;; from removing newline characters. | ||
| 173 | (skip-chars-backward "\n\t ") | ||
| 174 | (point))) | ||
| 175 | t) | ||
| 176 | (error nil)) | ||
| 177 | ;; Change "base64" to "8bit", to reflect the | ||
| 178 | ;; decoding we just did. | ||
| 179 | (goto-char base64-header-field-end) | ||
| 294 | (delete-region (point) (search-backward ":")) | 180 | (delete-region (point) (search-backward ":")) |
| 295 | (insert ": 8bit"))) | 181 | (insert ": 8bit"))))) |
| 296 | (if base64-header-field-end | 182 | ;; Transform anything within the message text |
| 297 | (save-excursion | 183 | ;; that might appear to be the end of a Babyl-format message. |
| 298 | (when (condition-case nil | 184 | (save-excursion |
| 299 | (progn | 185 | (save-restriction |
| 300 | (base64-decode-region | 186 | (narrow-to-region start (point)) |
| 301 | (1+ header-end) | 187 | (goto-char (point-min)) |
| 302 | (save-excursion | 188 | (while (search-forward "\n\^_" nil t) ; single char |
| 303 | ;; Prevent base64-decode-region | 189 | (replace-match "\n^_")))) ; 2 chars: "^" and "_" |
| 304 | ;; from removing newline characters. | 190 | ;; This is for malformed messages that don't end in newline. |
| 305 | (skip-chars-backward "\n\t ") | 191 | ;; There shouldn't be any, but some users say occasionally |
| 306 | (point))) | 192 | ;; there are some. |
| 307 | t) | 193 | (or (bolp) (newline)) |
| 308 | (error nil)) | 194 | (insert ?\^_) |
| 309 | ;; Change "base64" to "8bit", to reflect the | 195 | (setq last-coding-system-used nil) |
| 310 | ;; decoding we just did. | 196 | ;; Decode coding system, following specs in the message header, |
| 311 | (goto-char base64-header-field-end) | 197 | ;; and record what coding system was decoded. |
| 312 | (delete-region (point) (search-backward ":")) | 198 | (if pmail-output-decode-coding |
| 313 | (insert ": 8bit"))))) | 199 | (let ((mime-charset |
| 314 | (save-excursion | 200 | (if (save-excursion |
| 315 | (save-restriction | 201 | (goto-char start) |
| 316 | (narrow-to-region start (point)) | 202 | (search-forward "\n\n" nil t) |
| 317 | (goto-char (point-min)) | 203 | (let ((case-fold-search t)) |
| 318 | (while (search-forward "\n\^_" nil t) ; single char | 204 | (re-search-backward |
| 319 | (replace-match "\n^_")))) ; 2 chars: "^" and "_" | 205 | pmail-mime-charset-pattern |
| 320 | ;; This is for malformed messages that don't end in newline. | 206 | start t))) |
| 321 | ;; There shouldn't be any, but some users say occasionally | 207 | (intern (downcase (match-string 1)))))) |
| 322 | ;; there are some. | 208 | (pmail-decode-region start (point) mime-charset))) |
| 323 | (or (bolp) (newline)) | 209 | (save-excursion |
| 324 | (insert ?\^_) | 210 | (goto-char start) |
| 325 | (setq last-coding-system-used nil) | 211 | (forward-line 3) |
| 326 | (or pmail-enable-mime | 212 | (insert "X-Coding-System: " |
| 327 | (not pmail-enable-multibyte) | 213 | (symbol-name last-coding-system-used) |
| 328 | (let ((mime-charset | 214 | "\n"))))) |
| 329 | (if (and pmail-decode-mime-charset | ||
| 330 | (save-excursion | ||
| 331 | (goto-char start) | ||
| 332 | (search-forward "\n\n" nil t) | ||
| 333 | (let ((case-fold-search t)) | ||
| 334 | (re-search-backward | ||
| 335 | pmail-mime-charset-pattern | ||
| 336 | start t)))) | ||
| 337 | (intern (downcase (match-string 1)))))) | ||
| 338 | (pmail-decode-region start (point) mime-charset))) | ||
| 339 | (save-excursion | ||
| 340 | (goto-char start) | ||
| 341 | (forward-line 3) | ||
| 342 | (insert "X-Coding-System: " | ||
| 343 | (symbol-name last-coding-system-used) | ||
| 344 | "\n")) | ||
| 345 | (narrow-to-region (point) (point-max)) | ||
| 346 | (and (= 0 (% count 10)) | ||
| 347 | (message "Converting to Babyl format...%d" count)))))) | ||
| 348 | 215 | ||
| 349 | ;; Delete the "From ..." line, creating various other headers with | 216 | ;; Delete the "From ..." line, creating various other headers with |
| 350 | ;; information from it if they don't already exist. Now puts the | 217 | ;; information from it if they don't already exist. Now puts the |
| @@ -398,31 +265,54 @@ Note: it means the file has no messages in it.\n\^_")) | |||
| 398 | "" | 265 | "" |
| 399 | "From: \\1\n")) | 266 | "From: \\1\n")) |
| 400 | t))))))) | 267 | t))))))) |
| 268 | |||
| 269 | (defun pmail-output-as-mbox (file-name nomsg) | ||
| 270 | "Convert the current buffer's text to mbox Babyl and output to FILE-NAME. | ||
| 271 | It alters the current buffer's text, so it should be a temp buffer." | ||
| 272 | (let ((case-fold-search t) | ||
| 273 | mail-from mime-version content-type) | ||
| 401 | 274 | ||
| 402 | ;;;###autoload | 275 | ;; Preserve the Mail-From and MIME-Version fields |
| 403 | (defcustom pmail-fields-not-to-output nil | 276 | ;; even if they have been pruned. |
| 404 | "*Regexp describing fields to exclude when outputting a message to a file." | 277 | (search-forward "\n\n" nil 'move) |
| 405 | :type '(choice (const :tag "None" nil) | 278 | (narrow-to-region (point-min) (point)) |
| 406 | regexp) | ||
| 407 | :group 'pmail-output) | ||
| 408 | 279 | ||
| 409 | ;; Delete from the buffer header fields we don't want output. | 280 | (pmail-delete-unwanted-fields |
| 410 | ;; NOT-PMAIL if t means this buffer does not have the full header | 281 | (if pmail-enable-mime "Mail-From" |
| 411 | ;; and *** EOOH *** that a message in an Pmail file has. | 282 | "Mail-From\\|MIME-Version\\|Content-type")) |
| 412 | (defun pmail-delete-unwanted-fields (&optional not-pmail) | ||
| 413 | (if pmail-fields-not-to-output | ||
| 414 | (save-excursion | ||
| 415 | (goto-char (point-min)) | ||
| 416 | ;; Find the end of the header. | ||
| 417 | (if (and (or not-pmail (search-forward "\n*** EOOH ***\n" nil t)) | ||
| 418 | (search-forward "\n\n" nil t)) | ||
| 419 | (let ((end (point-marker))) | ||
| 420 | (goto-char (point-min)) | ||
| 421 | (while (re-search-forward pmail-fields-not-to-output end t) | ||
| 422 | (beginning-of-line) | ||
| 423 | (delete-region (point) | ||
| 424 | (progn (forward-line 1) (point))))))))) | ||
| 425 | 283 | ||
| 284 | (widen) | ||
| 285 | |||
| 286 | ;; Make sure message ends with blank line. | ||
| 287 | (goto-char (point-max)) | ||
| 288 | (unless (bolp) | ||
| 289 | (insert "\n")) | ||
| 290 | (unless (looking-back "\n\n") | ||
| 291 | (insert "\n")) | ||
| 292 | |||
| 293 | ;; Generate a From line from other header fields | ||
| 294 | ;; if necessary. | ||
| 295 | (goto-char (point-min)) | ||
| 296 | (unless (looking-at "From ") | ||
| 297 | (insert "From " | ||
| 298 | (mail-strip-quoted-names | ||
| 299 | (save-excursion | ||
| 300 | (save-restriction | ||
| 301 | (goto-char (point-min)) | ||
| 302 | (narrow-to-region | ||
| 303 | (point) | ||
| 304 | (or (search-forward "\n\n" nil) | ||
| 305 | (point-max))) | ||
| 306 | (or (mail-fetch-field "from") | ||
| 307 | (mail-fetch-field "really-from") | ||
| 308 | (mail-fetch-field "sender") | ||
| 309 | "unknown")))) | ||
| 310 | " " (current-time-string) "\n")) | ||
| 311 | |||
| 312 | (let ((coding-system-for-write | ||
| 313 | 'raw-text-unix)) | ||
| 314 | (write-region (point-min) (point-max) file-name t nomsg)))) | ||
| 315 | |||
| 426 | ;;; There are functions elsewhere in Emacs that use this function; | 316 | ;;; There are functions elsewhere in Emacs that use this function; |
| 427 | ;;; look at them before you change the calling method. | 317 | ;;; look at them before you change the calling method. |
| 428 | ;;;###autoload | 318 | ;;;###autoload |
| @@ -430,11 +320,9 @@ Note: it means the file has no messages in it.\n\^_")) | |||
| 430 | "Append this message to system-inbox-format mail file named FILE-NAME. | 320 | "Append this message to system-inbox-format mail file named FILE-NAME. |
| 431 | A prefix argument COUNT says to output that many consecutive messages, | 321 | A prefix argument COUNT says to output that many consecutive messages, |
| 432 | starting with the current one. Deleted messages are skipped and don't count. | 322 | starting with the current one. Deleted messages are skipped and don't count. |
| 433 | When called from lisp code, COUNT may be omitted and defaults to 1. | 323 | When called from Lisp code, COUNT may be omitted and defaults to 1. |
| 434 | 324 | ||
| 435 | If the pruned message header is shown on the current message, then | 325 | This outputs the complete message header even the display is pruned. |
| 436 | messages will be appended with pruned headers; otherwise, messages | ||
| 437 | will be appended with their original headers. | ||
| 438 | 326 | ||
| 439 | The default file name comes from `pmail-default-file', | 327 | The default file name comes from `pmail-default-file', |
| 440 | which is updated to the name you use in this command. | 328 | which is updated to the name you use in this command. |
| @@ -451,104 +339,141 @@ The optional fourth argument FROM-GNUS is set when called from GNUS." | |||
| 451 | (expand-file-name file-name | 339 | (expand-file-name file-name |
| 452 | (and pmail-default-file | 340 | (and pmail-default-file |
| 453 | (file-name-directory pmail-default-file)))) | 341 | (file-name-directory pmail-default-file)))) |
| 454 | (if (and (file-readable-p file-name) (mail-file-babyl-p file-name)) | 342 | (set-buffer pmail-buffer) |
| 455 | (pmail-output-to-babyl-file file-name count) | 343 | |
| 456 | (set-buffer pmail-buffer) | 344 | ;; Warn about creating new file. |
| 457 | (let ((orig-count count) | 345 | (or (find-buffer-visiting file-name) |
| 458 | (pmailbuf pmail-buffer) | 346 | (file-exists-p file-name) |
| 459 | (case-fold-search t) | 347 | (yes-or-no-p |
| 460 | (tembuf (get-buffer-create " pmail-output")) | 348 | (concat "\"" file-name "\" does not exist, create it? ")) |
| 461 | header-beginning | 349 | (error "Output file does not exist")) |
| 462 | mail-from mime-version content-type) | 350 | |
| 463 | (while (> count 0) | 351 | (let ((orig-count count) |
| 464 | ;; Preserve the Mail-From and MIME-Version fields | 352 | (case-fold-search t) |
| 465 | ;; even if they have been pruned. | 353 | (tembuf (get-buffer-create " pmail-output")) |
| 466 | (or from-gnus | 354 | (babyl-format |
| 355 | (and (file-readable-p file-name) (mail-file-babyl-p file-name)))) | ||
| 356 | |||
| 357 | (unwind-protect | ||
| 358 | (while (> count 0) | ||
| 359 | (with-current-buffer pmail-buffer | ||
| 360 | (let (cur beg end) | ||
| 361 | (setq beg (pmail-msgbeg pmail-current-message) | ||
| 362 | end (pmail-msgend pmail-current-message)) | ||
| 363 | ;; All access to the buffer's local variables is now finished... | ||
| 364 | (save-excursion | ||
| 365 | ;; ... so it is ok to go to a different buffer. | ||
| 366 | (if (pmail-buffers-swapped-p) (set-buffer pmail-view-buffer)) | ||
| 367 | (setq cur (current-buffer)) | ||
| 368 | (save-restriction | ||
| 369 | (widen) | ||
| 370 | (with-current-buffer tembuf | ||
| 371 | (insert-buffer-substring cur beg end) | ||
| 372 | ;; Convert the text to one format or another and output. | ||
| 373 | (if babyl-format | ||
| 374 | (pmail-output-as-babyl file-name (if noattribute 'nomsg)) | ||
| 375 | (pmail-output-as-mbox file-name | ||
| 376 | (if noattribute 'nomsg)))))))) | ||
| 377 | |||
| 378 | ;; Mark message as "filed". | ||
| 379 | (unless noattribute | ||
| 380 | (pmail-set-attribute pmail-filed-attr-index t)) | ||
| 381 | |||
| 382 | (setq count (1- count)) | ||
| 383 | |||
| 384 | (or from-gnus | ||
| 385 | (let ((next-message-p | ||
| 386 | (if pmail-delete-after-output | ||
| 387 | (pmail-delete-forward) | ||
| 388 | (if (> count 0) | ||
| 389 | (pmail-next-undeleted-message 1)))) | ||
| 390 | (num-appended (- orig-count count))) | ||
| 391 | (if (and (> count 0) (not next-message-p)) | ||
| 392 | (error "Only %d message%s appended" num-appended | ||
| 393 | (if (= num-appended 1) "" "s")))))) | ||
| 394 | (kill-buffer tembuf)))) | ||
| 395 | |||
| 396 | (defun pmail-output-as-seen (file-name &optional count noattribute from-gnus) | ||
| 397 | "Append this message to system-inbox-format mail file named FILE-NAME. | ||
| 398 | A prefix argument COUNT says to output that many consecutive messages, | ||
| 399 | starting with the current one. Deleted messages are skipped and don't count. | ||
| 400 | When called from Lisp code, COUNT may be omitted and defaults to 1. | ||
| 401 | |||
| 402 | This outputs the message header as you see it. | ||
| 403 | |||
| 404 | The default file name comes from `pmail-default-file', | ||
| 405 | which is updated to the name you use in this command. | ||
| 406 | |||
| 407 | The optional third argument NOATTRIBUTE, if non-nil, says not | ||
| 408 | to set the `filed' attribute, and not to display a message. | ||
| 409 | |||
| 410 | The optional fourth argument FROM-GNUS is set when called from GNUS." | ||
| 411 | (interactive | ||
| 412 | (list (pmail-output-read-file-name) | ||
| 413 | (prefix-numeric-value current-prefix-arg))) | ||
| 414 | (or count (setq count 1)) | ||
| 415 | (setq file-name | ||
| 416 | (expand-file-name file-name | ||
| 417 | (and pmail-default-file | ||
| 418 | (file-name-directory pmail-default-file)))) | ||
| 419 | (set-buffer pmail-buffer) | ||
| 420 | |||
| 421 | ;; Warn about creating new file. | ||
| 422 | (or (find-buffer-visiting file-name) | ||
| 423 | (file-exists-p file-name) | ||
| 424 | (yes-or-no-p | ||
| 425 | (concat "\"" file-name "\" does not exist, create it? ")) | ||
| 426 | (error "Output file does not exist")) | ||
| 427 | |||
| 428 | (if (and (file-readable-p file-name) (mail-file-babyl-p file-name)) | ||
| 429 | (error "Cannot output `as seen' to a Babyl file")) | ||
| 430 | |||
| 431 | (let ((orig-count count) | ||
| 432 | (case-fold-search t) | ||
| 433 | (tembuf (get-buffer-create " pmail-output"))) | ||
| 434 | |||
| 435 | (unwind-protect | ||
| 436 | (while (> count 0) | ||
| 437 | (let (cur beg end) | ||
| 438 | ;; If operating from whole-mbox buffer, get message bounds. | ||
| 439 | (if (not (pmail-buffers-swapped-p)) | ||
| 440 | (setq beg (pmail-msgbeg pmail-current-message) | ||
| 441 | end (pmail-msgend pmail-current-message))) | ||
| 442 | ;; All access to the buffer's local variables is now finished... | ||
| 467 | (save-excursion | 443 | (save-excursion |
| 444 | (setq cur (current-buffer)) | ||
| 468 | (save-restriction | 445 | (save-restriction |
| 469 | (goto-char (if (pmail-buffers-swapped-p) | 446 | (widen) |
| 470 | (point-min) | 447 | ;; If operating from the view buffer, get the bounds. |
| 471 | (pmail-msgbeg pmail-current-message))) | 448 | (unless beg |
| 472 | (setq header-beginning (point)) | 449 | (setq beg (point-min) |
| 473 | (search-forward "\n\n" nil 'move) | 450 | end (point-max))) |
| 474 | (narrow-to-region header-beginning (point)) | 451 | |
| 475 | (setq mail-from (mail-fetch-field "Mail-From")) | 452 | (with-current-buffer tembuf |
| 476 | (unless pmail-enable-mime | 453 | (insert-buffer-substring cur beg end) |
| 477 | (setq mime-version (mail-fetch-field "MIME-Version") | 454 | ;; Convert the text to one format or another and output. |
| 478 | content-type (mail-fetch-field "Content-type")))))) | 455 | (pmail-output-as-mbox file-name |
| 479 | (save-excursion | 456 | (if noattribute 'nomsg)))))) |
| 480 | (set-buffer tembuf) | 457 | |
| 481 | (erase-buffer) | 458 | ;; Mark message as "filed". |
| 482 | (insert-buffer-substring pmailbuf) | 459 | (unless noattribute |
| 483 | (save-excursion | 460 | (pmail-set-attribute pmail-filed-attr-index t)) |
| 484 | (goto-char (min (point-min) (- (point-max) 2))) | 461 | |
| 485 | (unless (looking-at "\n\n") | 462 | (setq count (1- count)) |
| 486 | (goto-char (point-max)) | 463 | |
| 487 | (insert "\n\n"))) | 464 | (or from-gnus |
| 488 | (when pmail-enable-mime | 465 | (let ((next-message-p |
| 489 | (goto-char (point-min)) | 466 | (if pmail-delete-after-output |
| 490 | (forward-line 2) | 467 | (pmail-delete-forward) |
| 491 | (delete-region (point-min) (point)) | 468 | (if (> count 0) |
| 492 | (search-forward "\n\n") | 469 | (pmail-next-undeleted-message 1)))) |
| 493 | (delete-region (match-beginning 0) | 470 | (num-appended (- orig-count count))) |
| 494 | (if (search-forward "\n\n") | 471 | (if (and (> count 0) (not next-message-p)) |
| 495 | (1- (match-end 0)))) | 472 | (error "Only %d message%s appended" num-appended |
| 496 | (setq buffer-file-coding-system (or pmail-file-coding-system | 473 | (if (= num-appended 1) "" "s")))))) |
| 497 | 'raw-text))) | ||
| 498 | (pmail-delete-unwanted-fields t) | ||
| 499 | (or (bolp) (insert "\n")) | ||
| 500 | (goto-char (point-min)) | ||
| 501 | (if mail-from | ||
| 502 | (insert mail-from "\n") | ||
| 503 | (insert "From " | ||
| 504 | (mail-strip-quoted-names | ||
| 505 | (save-excursion | ||
| 506 | (save-restriction | ||
| 507 | (goto-char (point-min)) | ||
| 508 | (narrow-to-region | ||
| 509 | (point) | ||
| 510 | (or (search-forward "\n\n" nil) | ||
| 511 | (point-max))) | ||
| 512 | (or (mail-fetch-field "from") | ||
| 513 | (mail-fetch-field "really-from") | ||
| 514 | (mail-fetch-field "sender") | ||
| 515 | "unknown")))) | ||
| 516 | " " (current-time-string) "\n")) | ||
| 517 | (when mime-version | ||
| 518 | (insert "MIME-Version: " mime-version) | ||
| 519 | ;; Some malformed MIME messages set content-type to nil. | ||
| 520 | (when content-type | ||
| 521 | (insert "\nContent-type: " content-type "\n"))) | ||
| 522 | ;; ``Quote'' "\nFrom " as "\n>From " | ||
| 523 | ;; (note that this isn't really quoting, as there is no requirement | ||
| 524 | ;; that "\n[>]+From " be quoted in the same transparent way.) | ||
| 525 | (let ((case-fold-search nil)) | ||
| 526 | (while (search-forward "\nFrom " nil t) | ||
| 527 | (forward-char -5) | ||
| 528 | (insert ?>))) | ||
| 529 | (write-region (point-min) (point-max) file-name t | ||
| 530 | (if noattribute 'nomsg))) | ||
| 531 | (or noattribute | ||
| 532 | (if (equal major-mode 'pmail-mode) | ||
| 533 | (pmail-set-attribute pmail-filed-attr-index t))) | ||
| 534 | (setq count (1- count)) | ||
| 535 | (or from-gnus | ||
| 536 | (let ((next-message-p | ||
| 537 | (if pmail-delete-after-output | ||
| 538 | (pmail-delete-forward) | ||
| 539 | (if (> count 0) | ||
| 540 | (pmail-next-undeleted-message 1)))) | ||
| 541 | (num-appended (- orig-count count))) | ||
| 542 | (if (and (> count 0) (not next-message-p)) | ||
| 543 | (progn | ||
| 544 | (error "%s" | ||
| 545 | (save-excursion | ||
| 546 | (set-buffer pmailbuf) | ||
| 547 | (format "Only %d message%s appended" num-appended | ||
| 548 | (if (= num-appended 1) "" "s")))) | ||
| 549 | (setq count 0)))))) | ||
| 550 | (kill-buffer tembuf)))) | 474 | (kill-buffer tembuf)))) |
| 551 | 475 | ||
| 476 | |||
| 552 | ;;;###autoload | 477 | ;;;###autoload |
| 553 | (defun pmail-output-body-to-file (file-name) | 478 | (defun pmail-output-body-to-file (file-name) |
| 554 | "Write this message body to the file FILE-NAME. | 479 | "Write this message body to the file FILE-NAME. |
| @@ -573,9 +498,7 @@ FILE-NAME defaults, interactively, from the Subject field of the message." | |||
| 573 | (and (file-exists-p file-name) | 498 | (and (file-exists-p file-name) |
| 574 | (not (y-or-n-p (format "File %s exists; overwrite? " file-name))) | 499 | (not (y-or-n-p (format "File %s exists; overwrite? " file-name))) |
| 575 | (error "Operation aborted")) | 500 | (error "Operation aborted")) |
| 576 | (write-region (point) (point-max) file-name) | 501 | (write-region (point) (point-max) file-name)) |
| 577 | (if (equal major-mode 'pmail-mode) | ||
| 578 | (pmail-set-attribute pmail-stored-attr-index t))) | ||
| 579 | (if pmail-delete-after-output | 502 | (if pmail-delete-after-output |
| 580 | (pmail-delete-forward))) | 503 | (pmail-delete-forward))) |
| 581 | 504 | ||