(latexenc-find-file-coding-system): Don't inherit the EOL part of the
[emacs.git] / lisp / gnus / mm-uu.el
blob5152d7138fb7c3620ae83e9f0db8d7e1c007c288
1 ;;; mm-uu.el --- Return uu stuff as mm handles
2 ;; Copyright (c) 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
4 ;; Author: Shenghuo Zhu <zsh@cs.rochester.edu>
5 ;; Keywords: postscript uudecode binhex shar forward gnatsweb pgp
7 ;; This file is part of GNU Emacs.
9 ;; GNU Emacs is free software; you can redistribute it and/or modify
10 ;; it under the terms of the GNU General Public License as published by
11 ;; the Free Software Foundation; either version 2, or (at your option)
12 ;; any later version.
14 ;; GNU Emacs is distributed in the hope that it will be useful,
15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 ;; GNU General Public License for more details.
19 ;; You should have received a copy of the GNU General Public License
20 ;; along with GNU Emacs; see the file COPYING. If not, write to the
21 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 ;; Boston, MA 02111-1307, USA.
24 ;;; Commentary:
26 ;;; Code:
28 (eval-when-compile (require 'cl))
29 (require 'mail-parse)
30 (require 'nnheader)
31 (require 'mm-decode)
32 (require 'mailcap)
33 (require 'mml2015)
35 (autoload 'uudecode-decode-region "uudecode")
36 (autoload 'uudecode-decode-region-external "uudecode")
37 (autoload 'uudecode-decode-region-internal "uudecode")
39 (autoload 'binhex-decode-region "binhex")
40 (autoload 'binhex-decode-region-external "binhex")
41 (autoload 'binhex-decode-region-internal "binhex")
43 (autoload 'yenc-decode-region "yenc")
44 (autoload 'yenc-extract-filename "yenc")
46 (defcustom mm-uu-decode-function 'uudecode-decode-region
47 "*Function to uudecode.
48 Internal function is done in Lisp by default, therefore decoding may
49 appear to be horribly slow. You can make Gnus use an external
50 decoder, such as uudecode."
51 :type '(choice
52 (function-item :tag "Auto detect" uudecode-decode-region)
53 (function-item :tag "Internal" uudecode-decode-region-internal)
54 (function-item :tag "External" uudecode-decode-region-external))
55 :group 'gnus-article-mime)
57 (defcustom mm-uu-binhex-decode-function 'binhex-decode-region
58 "*Function to binhex decode.
59 Internal function is done in elisp by default, therefore decoding may
60 appear to be horribly slow . You can make Gnus use the external Unix
61 decoder, such as hexbin."
62 :type '(choice (function-item :tag "Auto detect" binhex-decode-region)
63 (function-item :tag "Internal" binhex-decode-region-internal)
64 (function-item :tag "External" binhex-decode-region-external))
65 :group 'gnus-article-mime)
67 (defvar mm-uu-yenc-decode-function 'yenc-decode-region)
69 (defvar mm-uu-pgp-beginning-signature
70 "^-----BEGIN PGP SIGNATURE-----")
72 (defvar mm-uu-beginning-regexp nil)
74 (defvar mm-dissect-disposition "inline"
75 "The default disposition of uu parts.
76 This can be either \"inline\" or \"attachment\".")
78 (defvar mm-uu-emacs-sources-regexp "gnu\\.emacs\\.sources"
79 "The regexp of Emacs sources groups.")
81 (defcustom mm-uu-diff-groups-regexp "gnus\\.commits"
82 "*Regexp matching diff groups."
83 :version "22.1"
84 :type 'regexp
85 :group 'gnus-article-mime)
87 (defvar mm-uu-type-alist
88 '((postscript
89 "^%!PS-"
90 "^%%EOF$"
91 mm-uu-postscript-extract
92 nil)
93 (uu
94 "^begin[ \t]+0?[0-7][0-7][0-7][ \t]+"
95 "^end[ \t]*$"
96 mm-uu-uu-extract
97 mm-uu-uu-filename)
98 (binhex
99 "^:...............................................................$"
100 ":$"
101 mm-uu-binhex-extract
103 mm-uu-binhex-filename)
104 (yenc
105 "^=ybegin.*size=[0-9]+.*name=.*$"
106 "^=yend.*size=[0-9]+"
107 mm-uu-yenc-extract
108 mm-uu-yenc-filename)
109 (shar
110 "^#! */bin/sh"
111 "^exit 0$"
112 mm-uu-shar-extract)
113 (forward
114 ;;; Thanks to Edward J. Sabol <sabol@alderaan.gsfc.nasa.gov> and
115 ;;; Peter von der Ah\'e <pahe@daimi.au.dk>
116 "^-+ \\(Start of \\)?Forwarded message"
117 "^-+ End \\(of \\)?forwarded message"
118 mm-uu-forward-extract
120 mm-uu-forward-test)
121 (gnatsweb
122 "^----gnatsweb-attachment----"
124 mm-uu-gnatsweb-extract)
125 (pgp-signed
126 "^-----BEGIN PGP SIGNED MESSAGE-----"
127 "^-----END PGP SIGNATURE-----"
128 mm-uu-pgp-signed-extract
130 nil)
131 (pgp-encrypted
132 "^-----BEGIN PGP MESSAGE-----"
133 "^-----END PGP MESSAGE-----"
134 mm-uu-pgp-encrypted-extract
136 nil)
137 (pgp-key
138 "^-----BEGIN PGP PUBLIC KEY BLOCK-----"
139 "^-----END PGP PUBLIC KEY BLOCK-----"
140 mm-uu-pgp-key-extract
141 mm-uu-gpg-key-skip-to-last
142 nil)
143 (emacs-sources
144 "^;;;?[ \t]*[^ \t]+\\.el[ \t]*--"
145 "^;;;?[ \t]*\\([^ \t]+\\.el\\)[ \t]+ends here"
146 mm-uu-emacs-sources-extract
148 mm-uu-emacs-sources-test)
149 (diff
150 "^Index: "
152 mm-uu-diff-extract
154 mm-uu-diff-test)))
156 (defcustom mm-uu-configure-list '((shar . disabled))
157 "A list of mm-uu configuration.
158 To disable dissecting shar codes, for instance, add
159 `(shar . disabled)' to this list."
160 :type 'alist
161 :options (mapcar (lambda (entry)
162 (list (car entry) '(const disabled)))
163 mm-uu-type-alist)
164 :group 'gnus-article-mime)
166 ;; functions
168 (defsubst mm-uu-type (entry)
169 (car entry))
171 (defsubst mm-uu-beginning-regexp (entry)
172 (nth 1 entry))
174 (defsubst mm-uu-end-regexp (entry)
175 (nth 2 entry))
177 (defsubst mm-uu-function-extract (entry)
178 (nth 3 entry))
180 (defsubst mm-uu-function-1 (entry)
181 (nth 4 entry))
183 (defsubst mm-uu-function-2 (entry)
184 (nth 5 entry))
186 (defun mm-uu-copy-to-buffer (&optional from to)
187 "Copy the contents of the current buffer to a fresh buffer.
188 Return that buffer."
189 (save-excursion
190 (let ((obuf (current-buffer))
191 (coding-system
192 ;; Might not exist in non-MULE XEmacs
193 (when (boundp 'buffer-file-coding-system)
194 buffer-file-coding-system)))
195 (set-buffer (generate-new-buffer " *mm-uu*"))
196 (setq buffer-file-coding-system coding-system)
197 (insert-buffer-substring obuf from to)
198 (current-buffer))))
200 (defun mm-uu-configure-p (key val)
201 (member (cons key val) mm-uu-configure-list))
203 (defun mm-uu-configure (&optional symbol value)
204 (if symbol (set-default symbol value))
205 (setq mm-uu-beginning-regexp nil)
206 (mapcar (lambda (entry)
207 (if (mm-uu-configure-p (mm-uu-type entry) 'disabled)
209 (setq mm-uu-beginning-regexp
210 (concat mm-uu-beginning-regexp
211 (if mm-uu-beginning-regexp "\\|")
212 (mm-uu-beginning-regexp entry)))))
213 mm-uu-type-alist))
215 (mm-uu-configure)
217 (eval-when-compile
218 (defvar file-name)
219 (defvar start-point)
220 (defvar end-point)
221 (defvar entry))
223 (defun mm-uu-uu-filename ()
224 (if (looking-at ".+")
225 (setq file-name
226 (let ((nnheader-file-name-translation-alist
227 '((?/ . ?,) (?\ . ?_) (?* . ?_) (?$ . ?_))))
228 (nnheader-translate-file-chars (match-string 0))))))
230 (defun mm-uu-binhex-filename ()
231 (setq file-name
232 (ignore-errors
233 (binhex-decode-region start-point end-point t))))
235 (defun mm-uu-yenc-filename ()
236 (goto-char start-point)
237 (setq file-name
238 (ignore-errors
239 (yenc-extract-filename))))
241 (defun mm-uu-forward-test ()
242 (save-excursion
243 (goto-char start-point)
244 (forward-line)
245 (looking-at "[\r\n]*[a-zA-Z][a-zA-Z0-9-]*:")))
247 (defun mm-uu-postscript-extract ()
248 (mm-make-handle (mm-uu-copy-to-buffer start-point end-point)
249 '("application/postscript")))
251 (defun mm-uu-emacs-sources-extract ()
252 (mm-make-handle (mm-uu-copy-to-buffer start-point end-point)
253 '("application/emacs-lisp")
254 nil nil
255 (list mm-dissect-disposition
256 (cons 'filename file-name))))
258 (eval-when-compile
259 (defvar gnus-newsgroup-name))
261 (defun mm-uu-emacs-sources-test ()
262 (setq file-name (match-string 1))
263 (and gnus-newsgroup-name
264 mm-uu-emacs-sources-regexp
265 (string-match mm-uu-emacs-sources-regexp gnus-newsgroup-name)))
267 (defun mm-uu-diff-extract ()
268 (mm-make-handle (mm-uu-copy-to-buffer start-point end-point)
269 '("text/x-patch")))
271 (defun mm-uu-diff-test ()
272 (and gnus-newsgroup-name
273 mm-uu-diff-groups-regexp
274 (string-match mm-uu-diff-groups-regexp gnus-newsgroup-name)))
276 (defun mm-uu-forward-extract ()
277 (mm-make-handle (mm-uu-copy-to-buffer
278 (progn (goto-char start-point) (forward-line) (point))
279 (progn (goto-char end-point) (forward-line -1) (point)))
280 '("message/rfc822" (charset . gnus-decoded))))
282 (defun mm-uu-uu-extract ()
283 (mm-make-handle (mm-uu-copy-to-buffer start-point end-point)
284 (list (or (and file-name
285 (string-match "\\.[^\\.]+$"
286 file-name)
287 (mailcap-extension-to-mime
288 (match-string 0 file-name)))
289 "application/octet-stream"))
290 'x-uuencode nil
291 (if (and file-name (not (equal file-name "")))
292 (list mm-dissect-disposition
293 (cons 'filename file-name)))))
295 (defun mm-uu-binhex-extract ()
296 (mm-make-handle (mm-uu-copy-to-buffer start-point end-point)
297 (list (or (and file-name
298 (string-match "\\.[^\\.]+$" file-name)
299 (mailcap-extension-to-mime
300 (match-string 0 file-name)))
301 "application/octet-stream"))
302 'x-binhex nil
303 (if (and file-name (not (equal file-name "")))
304 (list mm-dissect-disposition
305 (cons 'filename file-name)))))
307 (defun mm-uu-yenc-extract ()
308 (mm-make-handle (mm-uu-copy-to-buffer start-point end-point)
309 (list (or (and file-name
310 (string-match "\\.[^\\.]+$" file-name)
311 (mailcap-extension-to-mime
312 (match-string 0 file-name)))
313 "application/octet-stream"))
314 'x-yenc nil
315 (if (and file-name (not (equal file-name "")))
316 (list mm-dissect-disposition
317 (cons 'filename file-name)))))
320 (defun mm-uu-shar-extract ()
321 (mm-make-handle (mm-uu-copy-to-buffer start-point end-point)
322 '("application/x-shar")))
324 (defun mm-uu-gnatsweb-extract ()
325 (save-restriction
326 (goto-char start-point)
327 (forward-line)
328 (narrow-to-region (point) end-point)
329 (mm-dissect-buffer t)))
331 (defun mm-uu-pgp-signed-test (&rest rest)
332 (and
333 mml2015-use
334 (mml2015-clear-verify-function)
335 (cond
336 ((eq mm-verify-option 'never) nil)
337 ((eq mm-verify-option 'always) t)
338 ((eq mm-verify-option 'known) t)
339 (t (y-or-n-p "Verify pgp signed part? ")))))
341 (eval-when-compile
342 (defvar gnus-newsgroup-charset))
344 (defun mm-uu-pgp-signed-extract-1 (handles ctl)
345 (let ((buf (mm-uu-copy-to-buffer (point-min) (point-max))))
346 (with-current-buffer buf
347 (if (mm-uu-pgp-signed-test)
348 (progn
349 (mml2015-clean-buffer)
350 (let ((coding-system-for-write (or gnus-newsgroup-charset
351 'iso-8859-1)))
352 (funcall (mml2015-clear-verify-function))))
353 (when (and mml2015-use (null (mml2015-clear-verify-function)))
354 (mm-set-handle-multipart-parameter
355 mm-security-handle 'gnus-details
356 (format "Clear verification not supported by `%s'.\n" mml2015-use))))
357 (goto-char (point-min))
358 (if (search-forward "\n\n" nil t)
359 (delete-region (point-min) (point)))
360 (if (re-search-forward mm-uu-pgp-beginning-signature nil t)
361 (delete-region (match-beginning 0) (point-max)))
362 (goto-char (point-min))
363 (while (re-search-forward "^- " nil t)
364 (replace-match "" t t)
365 (forward-line 1)))
366 (list (mm-make-handle buf '("text/plain" (charset . gnus-decoded))))))
368 (defun mm-uu-pgp-signed-extract ()
369 (let ((mm-security-handle (list (format "multipart/signed"))))
370 (mm-set-handle-multipart-parameter
371 mm-security-handle 'protocol "application/x-gnus-pgp-signature")
372 (save-restriction
373 (narrow-to-region start-point end-point)
374 (add-text-properties 0 (length (car mm-security-handle))
375 (list 'buffer (mm-uu-copy-to-buffer))
376 (car mm-security-handle))
377 (setcdr mm-security-handle
378 (mm-uu-pgp-signed-extract-1 nil
379 mm-security-handle)))
380 mm-security-handle))
382 (defun mm-uu-pgp-encrypted-test (&rest rest)
383 (and
384 mml2015-use
385 (mml2015-clear-decrypt-function)
386 (cond
387 ((eq mm-decrypt-option 'never) nil)
388 ((eq mm-decrypt-option 'always) t)
389 ((eq mm-decrypt-option 'known) t)
390 (t (y-or-n-p "Decrypt pgp encrypted part? ")))))
392 (defun mm-uu-pgp-encrypted-extract-1 (handles ctl)
393 (let ((buf (mm-uu-copy-to-buffer (point-min) (point-max))))
394 (if (mm-uu-pgp-encrypted-test)
395 (with-current-buffer buf
396 (mml2015-clean-buffer)
397 (funcall (mml2015-clear-decrypt-function))))
398 (list
399 (mm-make-handle buf
400 '("text/plain" (charset . gnus-decoded))))))
402 (defun mm-uu-pgp-encrypted-extract ()
403 (let ((mm-security-handle (list (format "multipart/encrypted"))))
404 (mm-set-handle-multipart-parameter
405 mm-security-handle 'protocol "application/x-gnus-pgp-encrypted")
406 (save-restriction
407 (narrow-to-region start-point end-point)
408 (add-text-properties 0 (length (car mm-security-handle))
409 (list 'buffer (mm-uu-copy-to-buffer))
410 (car mm-security-handle))
411 (setcdr mm-security-handle
412 (mm-uu-pgp-encrypted-extract-1 nil
413 mm-security-handle)))
414 mm-security-handle))
416 (defun mm-uu-gpg-key-skip-to-last ()
417 (let ((point (point))
418 (end-regexp (mm-uu-end-regexp entry))
419 (beginning-regexp (mm-uu-beginning-regexp entry)))
420 (when (and end-regexp
421 (not (mm-uu-configure-p (mm-uu-type entry) 'disabled)))
422 (while (re-search-forward end-regexp nil t)
423 (skip-chars-forward " \t\n\r")
424 (if (looking-at beginning-regexp)
425 (setq point (match-end 0)))))
426 (goto-char point)))
428 (defun mm-uu-pgp-key-extract ()
429 (let ((buf (mm-uu-copy-to-buffer start-point end-point)))
430 (mm-make-handle buf
431 '("application/pgp-keys"))))
433 ;;;###autoload
434 (defun mm-uu-dissect ()
435 "Dissect the current buffer and return a list of uu handles."
436 (let ((case-fold-search t)
437 text-start start-point end-point file-name result
438 text-plain-type entry func)
439 (save-excursion
440 (goto-char (point-min))
441 (cond
442 ((looking-at "\n")
443 (forward-line))
444 ((search-forward "\n\n" nil t)
446 (t (goto-char (point-max))))
447 ;;; gnus-decoded is a fake charset, which means no further
448 ;;; decoding.
449 (setq text-start (point)
450 text-plain-type '("text/plain" (charset . gnus-decoded)))
451 (while (re-search-forward mm-uu-beginning-regexp nil t)
452 (setq start-point (match-beginning 0))
453 (let ((alist mm-uu-type-alist)
454 (beginning-regexp (match-string 0)))
455 (while (not entry)
456 (if (string-match (mm-uu-beginning-regexp (car alist))
457 beginning-regexp)
458 (setq entry (car alist))
459 (pop alist))))
460 (if (setq func (mm-uu-function-1 entry))
461 (funcall func))
462 (forward-line);; in case of failure
463 (when (and (not (mm-uu-configure-p (mm-uu-type entry) 'disabled))
464 (let ((end-regexp (mm-uu-end-regexp entry)))
465 (if (not end-regexp)
466 (or (setq end-point (point-max)) t)
467 (prog1
468 (re-search-forward end-regexp nil t)
469 (forward-line)
470 (setq end-point (point)))))
471 (or (not (setq func (mm-uu-function-2 entry)))
472 (funcall func)))
473 (if (and (> start-point text-start)
474 (progn
475 (goto-char text-start)
476 (re-search-forward "." start-point t)))
477 (push
478 (mm-make-handle (mm-uu-copy-to-buffer text-start start-point)
479 text-plain-type)
480 result))
481 (push
482 (funcall (mm-uu-function-extract entry))
483 result)
484 (goto-char (setq text-start end-point))))
485 (when result
486 (if (and (> (point-max) (1+ text-start))
487 (save-excursion
488 (goto-char text-start)
489 (re-search-forward "." nil t)))
490 (push
491 (mm-make-handle (mm-uu-copy-to-buffer text-start (point-max))
492 text-plain-type)
493 result))
494 (setq result (cons "multipart/mixed" (nreverse result))))
495 result)))
497 (provide 'mm-uu)
499 ;;; arch-tag: 7db076bf-53db-4320-aa19-ca76a1d2ab2c
500 ;;; mm-uu.el ends here