2525a2de9f9d816f348ca8b5125d34964c197f33
[gnus] / contrib / rfc2015.el
1 ;;; rfc2015.el --- MIME Security with Pretty Good Privacy (PGP)
2 ;; Copyright (c) 2000 Free Software Foundation, Inc.
3
4 ;; Author: Shenghuo Zhu <zsh@cs.rochester.edu>
5 ;; Keywords: PGP MIME
6
7 ;; This file is a part of GNU Emacs.
8
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
11 ;; by the Free Software Foundation; either version 2, or (at your
12 ;; option) any later version.
13
14 ;; GNU Emacs is distributed in the hope that it will be useful, but
15 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 ;; General Public License for more details.
18
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.
23
24 ;;; Commentary:
25
26 ;; Installation: put the following statement in ~/.gnus:
27 ;;    (rfc2015-setup)
28 ;; You may have to make sure that the directory where this file lives
29 ;; is mentioned in `load-path'.
30 ;; 
31 ;; Insert an attribute, postprocess=pgp-sign (or pgp-encrypt), into
32 ;; the mml tag to be signed (or encrypted).
33
34 ;;; Code:
35
36 (defvar rfc2015-decrypt-function 'mailcrypt-decrypt)
37 (defvar rfc2015-verify-function 'mailcrypt-verify)
38
39 (defun rfc2015-decrypt (handle)
40   (let (child)
41     (cond 
42      ((setq child (mm-find-part-by-type (cdr handle) 
43                                         "application/octet-stream"))
44       (let (handles result)
45         (with-temp-buffer
46           (mm-insert-part child)
47           (setq result (funcall rfc2015-decrypt-function))
48           (unless (car result)
49             (error "Decrypting error."))
50           (setq handles (mm-dissect-buffer t)))
51         (setq gnus-article-mime-handles
52               (append (if (listp (car gnus-article-mime-handles))
53                           gnus-article-mime-handles
54                         (list gnus-article-mime-handles))
55                       (if (listp (car handles))
56                           handles
57                         (list handles))))
58         (gnus-mime-display-part handles)))
59      (t
60       (if (y-or-n-p "Corrupted pgp-encrypted part. Abort?" )
61           (error "Corrupted pgp-encrypted part.")
62         (gnus-mime-display-mixed (cdr handle)))))))
63
64 ;; FIXME: mm-dissect-buffer loses information of micalg and the
65 ;; original header of signed part.
66
67 (defun rfc2015-verify (handle)
68   (if (y-or-n-p "Verify signed part?" )
69       (let (child result hash)
70         (with-temp-buffer
71           (unless (setq child (mm-find-part-by-type 
72                                (cdr handle) "application/pgp-signature" t))
73             (error "Corrupted pgp-signature part."))
74           (insert "-----BEGIN PGP SIGNED MESSAGE-----\n")
75           (insert (format "Hash: %s\n\n" (read-string "Hash: " "SHA1")))
76           (mm-insert-part child)
77           (goto-char (point-max))
78           (unless (bolp)
79             (insert "\n"))
80           (unless (setq child (mm-find-part-by-type 
81                                (cdr handle) "application/pgp-signature"))
82             (error "Corrupted pgp-signature part."))
83           (mm-insert-part child)
84           (setq result (funcall rfc2015-verify-function))
85           (unless result
86             (error "Verify error.")))))
87   (gnus-mime-display-part 
88    (mm-find-part-by-type 
89     (cdr handle) "application/pgp-signature" t)))
90
91 (defvar rfc2015-mailcrypt-prefix 0)
92
93 (defun rfc2015-mailcrypt-sign (cont)
94   (mailcrypt-sign rfc2015-mailcrypt-prefix)
95   (let ((boundary 
96          (funcall mml-boundary-function (incf mml-multipart-number)))
97         (scheme-alist (funcall (or mc-default-scheme 
98                                    (cdr (car mc-schemes)))))
99         hash)
100     (goto-char (point-min))
101     (unless (re-search-forward (cdr (assq 'signed-begin-line scheme-alist)))
102       (error "Cannot find signed begin line." ))
103     (goto-char (match-beginning 0))
104     (forward-line 1)
105     (unless (looking-at "Hash:[ \t]*\\([a-zA-Z0-9]+\\)")
106       (error "Cannot not find PGP hash." ))
107     (setq hash (match-string 1))
108     (unless (re-search-forward "^$" nil t)
109       (error "Cannot not find PGP message." ))
110     (forward-line 1)
111     (delete-region (point-min) (point))
112     (insert (format "Content-Type: multipart/signed; boundary=\"%s\";\n"
113                     boundary))
114     (insert (format "\tmicalg=pgp-%s; protocol=\"application/pgp-signature\"\n"
115                     hash))
116     (insert "\n")
117     (insert (format "--%s\n" boundary))
118     (unless (re-search-forward (cdr (assq 'signed-end-line scheme-alist)))
119       (error "Cannot find signature part." ))
120     (goto-char (match-beginning 0))
121     (unless (re-search-backward "^-+BEGIN" nil t)
122       (error "Cannot find signature part." ))
123     (goto-char (match-beginning 0))
124     (insert (format "--%s\n" boundary))
125     (insert "Content-Type: application/pgp-signature\n\n")
126     (goto-char (point-max))
127     (insert (format "--%s--\n" boundary))
128     (goto-char (point-max))))
129
130 (defun rfc2015-mailcrypt-encrypt (cont)
131   ;; FIXME:
132   ;; You have to input the receiptant.
133   (mailcrypt-encrypt rfc2015-mailcrypt-prefix)
134   (let ((boundary 
135          (funcall mml-boundary-function (incf mml-multipart-number))))
136     (goto-char (point-min))
137     (insert (format "Content-Type: multipart/encrypted; boundary=\"%s\";\n"
138                     boundary))
139     (insert "\tprotocol=\"application/pgp-encrypted\"\n\n")
140     (insert (format "--%s\n" boundary))
141     (insert "Content-Type: application/pgp-encrypted\n\n")
142     (insert "Version: 1\n\n")
143     (insert (format "--%s\n" boundary))
144     (insert "Content-Type: application/octet-stream\n\n")
145     (goto-char (point-max))
146     (insert (format "--%s--\n" boundary))
147     (goto-char (point-max))))
148
149 ;; The following code might be moved into mml.el or gnus-art.el.
150
151 (defvar mml-postprocess-alist
152   '(("pgp-sign" . rfc2015-mailcrypt-sign)
153     ("pgp-encrypt" . rfc2015-mailcrypt-encrypt))
154   "Alist of postprocess functions.")
155
156 (defun mml-postprocess (cont)
157   (let ((pp (cdr (or (assq 'postprocess cont)
158                      (assq 'pp cont))))
159         item)
160     (if (and pp (setq item (assoc pp mml-postprocess-alist)))
161         (funcall (cdr item) cont))))
162
163 (defun rfc2015-setup ()
164   (setq mml-generate-mime-postprocess-function 'mml-postprocess)
165 ;  (push '("multipart/signed" . rfc2015-verify)
166 ;       gnus-mime-multipart-functions)
167   (push '("multipart/encrypted" . rfc2015-decrypt)
168         gnus-mime-multipart-functions))
169
170 ;; The following code might be moved into mm-decode.el.
171
172 (defun mm-find-part-by-type (handles type &optional notp) 
173   (let (handle)
174     (while handles
175       (if (if notp
176               (not (equal (mm-handle-media-type (car handles)) type))
177             (equal (mm-handle-media-type (car handles)) type))
178           (setq handle (car handles)
179                 handles nil))
180       (setq handles (cdr handles)))
181     handle))
182
183 (provide 'rfc2015)
184
185 ;;; rfc2015.el ends here