Refactor mml-smime.el, mml1991.el, mml2015.el
[gnus] / lisp / mm-archive.el
1 ;;; mm-archive.el --- Functions for parsing archive files as MIME
2
3 ;; Copyright (C) 2012-2016 Free Software Foundation, Inc.
4
5 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
6 ;; This file is part of GNU Emacs.
7
8 ;; GNU Emacs is free software: you can redistribute it and/or modify
9 ;; it under the terms of the GNU General Public License as published by
10 ;; the Free Software Foundation, either version 3 of the License, or
11 ;; (at your option) any later version.
12
13 ;; GNU Emacs is distributed in the hope that it will be useful,
14 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 ;; GNU General Public License for more details.
17
18 ;; You should have received a copy of the GNU General Public License
19 ;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
20
21 ;;; Commentary:
22
23 ;;; Code:
24
25 (require 'mm-decode)
26 (autoload 'gnus-recursive-directory-files "gnus-util")
27 (autoload 'mailcap-extension-to-mime "mailcap")
28
29 (defvar mm-archive-decoders
30   '(("application/ms-tnef" t "tnef" "-f" "-" "-C")
31     ("application/zip" nil "unzip" "-j" "-x" "%f" "-d")
32     ("application/x-gtar-compressed" nil "tar" "xzf" "-" "-C")
33     ("application/x-tar" nil "tar" "xf" "-" "-C")))
34
35 (defun mm-archive-decoders () mm-archive-decoders)
36
37 (defun mm-dissect-archive (handle)
38   (let ((decoder (cddr (assoc (car (mm-handle-type handle))
39                               mm-archive-decoders)))
40         (dir (mm-make-temp-file
41               (expand-file-name "emm." mm-tmp-directory) 'dir)))
42     (set-file-modes dir #o700)
43     (unwind-protect
44         (progn
45           (mm-with-unibyte-buffer
46             (mm-insert-part handle)
47             (if (member "%f" decoder)
48                 (let ((file (expand-file-name "mail.zip" dir)))
49                   (write-region (point-min) (point-max) file nil 'silent)
50                   (setq decoder (copy-sequence decoder))
51                   (setcar (member "%f" decoder) file)
52                   (apply 'call-process (car decoder) nil nil nil
53                          (append (cdr decoder) (list dir)))
54                   (delete-file file))
55               (apply 'call-process-region (point-min) (point-max) (car decoder)
56                      nil (get-buffer-create "*tnef*")
57                      nil (append (cdr decoder) (list dir)))))
58           `("multipart/mixed"
59             ,handle
60             ,@(mm-archive-list-files (gnus-recursive-directory-files dir))))
61       (delete-directory dir t))))
62
63 (defun mm-archive-list-files (files)
64   (let ((handles nil)
65         type disposition)
66     (dolist (file files)
67       (with-temp-buffer
68         (when (string-match "\\.\\([^.]+\\)$" file)
69           (setq type (mailcap-extension-to-mime (match-string 1 file))))
70         (unless type
71           (setq type "application/octet-stream"))
72         (setq disposition
73               (if (string-match "^image/\\|^text/" type)
74                   "inline"
75                 "attachment"))
76         (insert (format "Content-type: %s\n" type))
77         (insert "Content-Transfer-Encoding: 8bit\n\n")
78         (insert-file-contents file)
79         (push
80          (mm-make-handle (mm-copy-to-buffer)
81                          (list type)
82                          '8bit nil
83                          `(,disposition (filename . ,file))
84                          nil nil nil)
85          handles)))
86     handles))
87
88 (defun mm-archive-dissect-and-inline (handle)
89   (let ((start (point-marker)))
90     (save-restriction
91       (narrow-to-region (point) (point))
92       (dolist (handle (cddr (mm-dissect-archive handle)))
93         (goto-char (point-max))
94         (mm-display-inline handle))
95       (goto-char (point-max))
96       (mm-handle-set-undisplayer
97        handle
98        `(lambda ()
99           (let ((inhibit-read-only t)
100                 (end ,(point-marker)))
101             (remove-images ,start end)
102             (delete-region ,start end)))))))
103
104 (provide 'mm-archive)
105
106 ;; mm-archive.el ends here