Tell about server setup.
[gnus] / lisp / mml1991.el
1 ;;; mml1991.el --- Old PGP message format (RFC 1991) support for MML
2
3 ;; Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
4 ;;   2007, 2008, 2009, 2010  Free Software Foundation, Inc.
5
6 ;; Author: Sascha Lüdecke <sascha@meta-x.de>,
7 ;;      Simon Josefsson <simon@josefsson.org> (Mailcrypt interface, Gnus glue)
8 ;; Keywords PGP
9
10 ;; This file is part of GNU Emacs.
11
12 ;; GNU Emacs is free software: you can redistribute it and/or modify
13 ;; it under the terms of the GNU General Public License as published by
14 ;; the Free Software Foundation, either version 3 of the License, or
15 ;; (at your option) any later version.
16
17 ;; GNU Emacs is distributed in the hope that it will be useful,
18 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 ;; GNU General Public License for more details.
21
22 ;; You should have received a copy of the GNU General Public License
23 ;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
24
25 ;;; Commentary:
26
27 ;;; Code:
28
29 ;; For Emacs < 22.2.
30 (eval-and-compile
31   (unless (fboundp 'declare-function) (defmacro declare-function (&rest r)))
32
33   (if (locate-library "password-cache")
34       (require 'password-cache)
35     (require 'password)))
36
37 (eval-when-compile
38   (require 'cl)
39   (require 'mm-util))
40
41 (require 'mm-encode)
42 (require 'mml-sec)
43
44 (defvar mc-pgp-always-sign)
45
46 (autoload 'quoted-printable-decode-region "qp")
47 (autoload 'quoted-printable-encode-region "qp")
48
49 (autoload 'mm-decode-content-transfer-encoding "mm-bodies")
50 (autoload 'mm-encode-content-transfer-encoding "mm-bodies")
51 (autoload 'message-options-get "message")
52 (autoload 'message-options-set "message")
53
54 (defvar mml1991-use mml2015-use
55   "The package used for PGP.")
56
57 (defvar mml1991-function-alist
58   '((mailcrypt mml1991-mailcrypt-sign
59                mml1991-mailcrypt-encrypt)
60     (gpg mml1991-gpg-sign
61          mml1991-gpg-encrypt)
62     (pgg mml1991-pgg-sign
63          mml1991-pgg-encrypt)
64     (epg mml1991-epg-sign
65          mml1991-epg-encrypt))
66   "Alist of PGP functions.")
67
68 (defvar mml1991-verbose mml-secure-verbose
69   "If non-nil, ask the user about the current operation more verbosely.")
70
71 (defvar mml1991-cache-passphrase mml-secure-cache-passphrase
72   "If t, cache passphrase.")
73
74 (defvar mml1991-passphrase-cache-expiry mml-secure-passphrase-cache-expiry
75   "How many seconds the passphrase is cached.
76 Whether the passphrase is cached at all is controlled by
77 `mml1991-cache-passphrase'.")
78
79 (defvar mml1991-signers nil
80   "A list of your own key ID which will be used to sign a message.")
81
82 (defvar mml1991-encrypt-to-self nil
83   "If t, add your own key ID to recipient list when encryption.")
84
85 ;;; mailcrypt wrapper
86
87 (autoload 'mc-sign-generic "mc-toplev")
88
89 (defvar mml1991-decrypt-function 'mailcrypt-decrypt)
90 (defvar mml1991-verify-function 'mailcrypt-verify)
91
92 (defun mml1991-mailcrypt-sign (cont)
93   (let ((text (current-buffer))
94         headers signature
95         (result-buffer (get-buffer-create "*GPG Result*")))
96     ;; Save MIME Content[^ ]+: headers from signing
97     (goto-char (point-min))
98     (while (looking-at "^Content[^ ]+:") (forward-line))
99     (unless (bobp)
100       (setq headers (buffer-string))
101       (delete-region (point-min) (point)))
102     (goto-char (point-max))
103     (unless (bolp)
104       (insert "\n"))
105     (quoted-printable-decode-region (point-min) (point-max))
106     (with-temp-buffer
107       (setq signature (current-buffer))
108       (insert-buffer-substring text)
109       (unless (mc-sign-generic (message-options-get 'message-sender)
110                                nil nil nil nil)
111         (unless (> (point-max) (point-min))
112           (pop-to-buffer result-buffer)
113           (error "Sign error")))
114       (goto-char (point-min))
115       (while (re-search-forward "\r+$" nil t)
116         (replace-match "" t t))
117       (quoted-printable-encode-region (point-min) (point-max))
118       (set-buffer text)
119       (delete-region (point-min) (point-max))
120       (if headers (insert headers))
121       (insert "\n")
122       (insert-buffer-substring signature)
123       (goto-char (point-max)))))
124
125 (declare-function mc-encrypt-generic "ext:mc-toplev"
126                   (&optional recipients scheme start end from sign))
127
128 (defun mml1991-mailcrypt-encrypt (cont &optional sign)
129   (let ((text (current-buffer))
130         (mc-pgp-always-sign
131          (or mc-pgp-always-sign
132              sign
133              (eq t (or (message-options-get 'message-sign-encrypt)
134                        (message-options-set
135                         'message-sign-encrypt
136                         (or (y-or-n-p "Sign the message? ")
137                             'not))))
138              'never))
139         cipher
140         (result-buffer (get-buffer-create "*GPG Result*")))
141     ;; Strip MIME Content[^ ]: headers since it will be ASCII ARMORED
142     (goto-char (point-min))
143     (while (looking-at "^Content[^ ]+:") (forward-line))
144     (unless (bobp)
145       (delete-region (point-min) (point)))
146     (mm-with-unibyte-current-buffer
147       (with-temp-buffer
148         (setq cipher (current-buffer))
149         (insert-buffer-substring text)
150         (unless (mc-encrypt-generic
151                  (or
152                   (message-options-get 'message-recipients)
153                   (message-options-set 'message-recipients
154                                        (read-string "Recipients: ")))
155                  nil
156                  (point-min) (point-max)
157                  (message-options-get 'message-sender)
158                  'sign)
159           (unless (> (point-max) (point-min))
160             (pop-to-buffer result-buffer)
161             (error "Encrypt error")))
162         (goto-char (point-min))
163         (while (re-search-forward "\r+$" nil t)
164           (replace-match "" t t))
165         (set-buffer text)
166         (delete-region (point-min) (point-max))
167         ;;(insert "Content-Type: application/pgp-encrypted\n\n")
168         ;;(insert "Version: 1\n\n")
169         (insert "\n")
170         (insert-buffer-substring cipher)
171         (goto-char (point-max))))))
172
173 ;;; gpg wrapper
174
175 (autoload 'gpg-sign-cleartext "gpg")
176
177 (declare-function gpg-sign-encrypt "ext:gpg"
178                   (plaintext ciphertext result recipients &optional
179                              passphrase sign-with-key armor textmode))
180 (declare-function gpg-encrypt "ext:gpg"
181                   (plaintext ciphertext result recipients &optional
182                              passphrase armor textmode))
183
184 (defun mml1991-gpg-sign (cont)
185   (let ((text (current-buffer))
186         headers signature
187         (result-buffer (get-buffer-create "*GPG Result*")))
188     ;; Save MIME Content[^ ]+: headers from signing
189     (goto-char (point-min))
190     (while (looking-at "^Content[^ ]+:") (forward-line))
191     (unless (bobp)
192       (setq headers (buffer-string))
193       (delete-region (point-min) (point)))
194     (goto-char (point-max))
195     (unless (bolp)
196       (insert "\n"))
197     (quoted-printable-decode-region (point-min) (point-max))
198     (with-temp-buffer
199       (unless (gpg-sign-cleartext text (setq signature (current-buffer))
200                                   result-buffer
201                                   nil
202                                   (message-options-get 'message-sender))
203         (unless (> (point-max) (point-min))
204           (pop-to-buffer result-buffer)
205           (error "Sign error")))
206       (goto-char (point-min))
207       (while (re-search-forward "\r+$" nil t)
208         (replace-match "" t t))
209       (quoted-printable-encode-region (point-min) (point-max))
210       (set-buffer text)
211       (delete-region (point-min) (point-max))
212       (if headers (insert headers))
213       (insert "\n")
214       (insert-buffer-substring signature)
215       (goto-char (point-max)))))
216
217 (defun mml1991-gpg-encrypt (cont &optional sign)
218   (let ((text (current-buffer))
219         cipher
220         (result-buffer (get-buffer-create "*GPG Result*")))
221     ;; Strip MIME Content[^ ]: headers since it will be ASCII ARMORED
222     (goto-char (point-min))
223     (while (looking-at "^Content[^ ]+:") (forward-line))
224     (unless (bobp)
225       (delete-region (point-min) (point)))
226     (mm-with-unibyte-current-buffer
227       (with-temp-buffer
228         (flet ((gpg-encrypt-func
229                 (sign plaintext ciphertext result recipients &optional
230                       passphrase sign-with-key armor textmode)
231                 (if sign
232                     (gpg-sign-encrypt
233                      plaintext ciphertext result recipients passphrase
234                      sign-with-key armor textmode)
235                   (gpg-encrypt
236                    plaintext ciphertext result recipients passphrase
237                    armor textmode))))
238           (unless (gpg-encrypt-func
239                    sign
240                    text (setq cipher (current-buffer))
241                    result-buffer
242                    (split-string
243                     (or
244                      (message-options-get 'message-recipients)
245                      (message-options-set 'message-recipients
246                                           (read-string "Recipients: ")))
247                     "[ \f\t\n\r\v,]+")
248                    nil
249                    (message-options-get 'message-sender)
250                    t t) ; armor & textmode
251             (unless (> (point-max) (point-min))
252               (pop-to-buffer result-buffer)
253               (error "Encrypt error"))))
254         (goto-char (point-min))
255         (while (re-search-forward "\r+$" nil t)
256           (replace-match "" t t))
257         (set-buffer text)
258         (delete-region (point-min) (point-max))
259         ;;(insert "Content-Type: application/pgp-encrypted\n\n")
260         ;;(insert "Version: 1\n\n")
261         (insert "\n")
262         (insert-buffer-substring cipher)
263         (goto-char (point-max))))))
264
265 ;; pgg wrapper
266
267 (defvar pgg-default-user-id)
268 (defvar pgg-errors-buffer)
269 (defvar pgg-output-buffer)
270
271 (defun mml1991-pgg-sign (cont)
272   (let ((pgg-text-mode t)
273         (pgg-default-user-id (or (message-options-get 'mml-sender)
274                                  pgg-default-user-id))
275         headers cte)
276     ;; Don't sign headers.
277     (goto-char (point-min))
278     (when (re-search-forward "^$" nil t)
279       (setq headers (buffer-substring (point-min) (point)))
280       (save-restriction
281         (narrow-to-region (point-min) (point))
282         (setq cte (mail-fetch-field "content-transfer-encoding")))
283       (forward-line 1)
284       (delete-region (point-min) (point))
285       (when cte
286         (setq cte (intern (downcase cte)))
287         (mm-decode-content-transfer-encoding cte)))
288     (unless (pgg-sign-region (point-min) (point-max) t)
289       (pop-to-buffer pgg-errors-buffer)
290       (error "Encrypt error"))
291     (delete-region (point-min) (point-max))
292     (mm-with-unibyte-current-buffer
293       (insert-buffer-substring pgg-output-buffer)
294       (goto-char (point-min))
295       (while (re-search-forward "\r+$" nil t)
296         (replace-match "" t t))
297       (when cte
298         (mm-encode-content-transfer-encoding cte))
299       (goto-char (point-min))
300       (when headers
301         (insert headers))
302       (insert "\n"))
303     t))
304
305 (defun mml1991-pgg-encrypt (cont &optional sign)
306   (goto-char (point-min))
307   (when (re-search-forward "^$" nil t)
308     (let ((cte (save-restriction
309                  (narrow-to-region (point-min) (point))
310                  (mail-fetch-field "content-transfer-encoding"))))
311       ;; Strip MIME headers since it will be ASCII armored.
312       (forward-line 1)
313       (delete-region (point-min) (point))
314       (when cte
315         (mm-decode-content-transfer-encoding (intern (downcase cte))))))
316   (unless (let ((pgg-text-mode t))
317             (pgg-encrypt-region
318              (point-min) (point-max)
319              (split-string
320               (or
321                (message-options-get 'message-recipients)
322                (message-options-set 'message-recipients
323                                     (read-string "Recipients: ")))
324               "[ \f\t\n\r\v,]+")
325              sign))
326     (pop-to-buffer pgg-errors-buffer)
327     (error "Encrypt error"))
328   (delete-region (point-min) (point-max))
329   (insert "\n")
330   (insert-buffer-substring pgg-output-buffer)
331   t)
332
333 ;; epg wrapper
334
335 (defvar epg-user-id-alist)
336
337 (autoload 'epg-make-context "epg")
338 (autoload 'epg-passphrase-callback-function "epg")
339 (autoload 'epa-select-keys "epa")
340 (autoload 'epg-list-keys "epg")
341 (autoload 'epg-context-set-armor "epg")
342 (autoload 'epg-context-set-textmode "epg")
343 (autoload 'epg-context-set-signers "epg")
344 (autoload 'epg-context-set-passphrase-callback "epg")
345 (autoload 'epg-sign-string "epg")
346 (autoload 'epg-encrypt-string "epg")
347 (autoload 'epg-configuration "epg-config")
348 (autoload 'epg-expand-group "epg-config")
349
350 (defvar mml1991-epg-secret-key-id-list nil)
351
352 (defun mml1991-epg-passphrase-callback (context key-id ignore)
353   (if (eq key-id 'SYM)
354       (epg-passphrase-callback-function context key-id nil)
355     (let* ((entry (assoc key-id epg-user-id-alist))
356            (passphrase
357             (password-read
358              (format "GnuPG passphrase for %s: "
359                      (if entry
360                          (cdr entry)
361                        key-id))
362              (if (eq key-id 'PIN)
363                  "PIN"
364                key-id))))
365       (when passphrase
366         (let ((password-cache-expiry mml1991-passphrase-cache-expiry))
367           (password-cache-add key-id passphrase))
368         (setq mml1991-epg-secret-key-id-list
369               (cons key-id mml1991-epg-secret-key-id-list))
370         (copy-sequence passphrase)))))
371
372 (defun mml1991-epg-sign (cont)
373   (let ((context (epg-make-context))
374         headers cte signers signature)
375     (if (eq mm-sign-option 'guided)
376         (setq signers (epa-select-keys context "Select keys for signing.
377 If no one is selected, default secret key is used.  "
378                                        mml1991-signers t))
379       (if mml1991-signers
380           (setq signers (mapcar (lambda (name)
381                                   (car (epg-list-keys context name t)))
382                                 mml1991-signers))))
383     (epg-context-set-armor context t)
384     (epg-context-set-textmode context t)
385     (epg-context-set-signers context signers)
386     (if mml1991-cache-passphrase
387         (epg-context-set-passphrase-callback
388          context
389          #'mml1991-epg-passphrase-callback))
390     ;; Don't sign headers.
391     (goto-char (point-min))
392     (when (re-search-forward "^$" nil t)
393       (setq headers (buffer-substring (point-min) (point)))
394       (save-restriction
395         (narrow-to-region (point-min) (point))
396         (setq cte (mail-fetch-field "content-transfer-encoding")))
397       (forward-line 1)
398       (delete-region (point-min) (point))
399       (when cte
400         (setq cte (intern (downcase cte)))
401         (mm-decode-content-transfer-encoding cte)))
402     (condition-case error
403         (setq signature (epg-sign-string context (buffer-string) 'clear)
404               mml1991-epg-secret-key-id-list nil)
405       (error
406        (while mml1991-epg-secret-key-id-list
407          (password-cache-remove (car mml1991-epg-secret-key-id-list))
408          (setq mml1991-epg-secret-key-id-list
409                (cdr mml1991-epg-secret-key-id-list)))
410        (signal (car error) (cdr error))))
411     (delete-region (point-min) (point-max))
412     (mm-with-unibyte-current-buffer
413       (insert signature)
414       (goto-char (point-min))
415       (while (re-search-forward "\r+$" nil t)
416         (replace-match "" t t))
417       (when cte
418         (mm-encode-content-transfer-encoding cte))
419       (goto-char (point-min))
420       (when headers
421         (insert headers))
422       (insert "\n"))
423     t))
424
425 (defun mml1991-epg-encrypt (cont &optional sign)
426   (goto-char (point-min))
427   (when (re-search-forward "^$" nil t)
428     (let ((cte (save-restriction
429                  (narrow-to-region (point-min) (point))
430                  (mail-fetch-field "content-transfer-encoding"))))
431       ;; Strip MIME headers since it will be ASCII armored.
432       (forward-line 1)
433       (delete-region (point-min) (point))
434       (when cte
435         (mm-decode-content-transfer-encoding (intern (downcase cte))))))
436   (let ((context (epg-make-context))
437         (recipients
438          (if (message-options-get 'message-recipients)
439              (split-string
440               (message-options-get 'message-recipients)
441               "[ \f\t\n\r\v,]+")))
442         cipher signers config)
443     ;; We should remove this check if epg-0.0.6 is released.
444     (if (and (condition-case nil
445                  (require 'epg-config)
446                (error))
447              (functionp #'epg-expand-group))
448         (setq config (epg-configuration)
449               recipients
450               (apply #'nconc
451                      (mapcar (lambda (recipient)
452                                (or (epg-expand-group config recipient)
453                                    (list recipient)))
454                              recipients))))
455     (if (eq mm-encrypt-option 'guided)
456         (setq recipients
457               (epa-select-keys context "Select recipients for encryption.
458 If no one is selected, symmetric encryption will be performed.  "
459                                recipients))
460       (setq recipients
461             (delq nil (mapcar (lambda (name)
462                                 (car (epg-list-keys context name)))
463                               recipients))))
464     (if mml1991-encrypt-to-self
465         (if mml1991-signers
466             (setq recipients
467                   (nconc recipients
468                          (mapcar (lambda (name)
469                                    (car (epg-list-keys context name)))
470                                  mml1991-signers)))
471           (error "mml1991-signers not set")))
472     (when sign
473       (if (eq mm-sign-option 'guided)
474           (setq signers (epa-select-keys context "Select keys for signing.
475 If no one is selected, default secret key is used.  "
476                                          mml1991-signers t))
477         (if mml1991-signers
478             (setq signers (mapcar (lambda (name)
479                                     (car (epg-list-keys context name t)))
480                                   mml1991-signers))))
481       (epg-context-set-signers context signers))
482     (epg-context-set-armor context t)
483     (epg-context-set-textmode context t)
484     (if mml1991-cache-passphrase
485         (epg-context-set-passphrase-callback
486          context
487          #'mml1991-epg-passphrase-callback))
488     (condition-case error
489         (setq cipher
490               (epg-encrypt-string context (buffer-string) recipients sign)
491               mml1991-epg-secret-key-id-list nil)
492       (error
493        (while mml1991-epg-secret-key-id-list
494          (password-cache-remove (car mml1991-epg-secret-key-id-list))
495          (setq mml1991-epg-secret-key-id-list
496                (cdr mml1991-epg-secret-key-id-list)))
497        (signal (car error) (cdr error))))
498     (delete-region (point-min) (point-max))
499     (insert "\n" cipher))
500   t)
501
502 ;;;###autoload
503 (defun mml1991-encrypt (cont &optional sign)
504   (let ((func (nth 2 (assq mml1991-use mml1991-function-alist))))
505     (if func
506         (funcall func cont sign)
507       (error "Cannot find encrypt function"))))
508
509 ;;;###autoload
510 (defun mml1991-sign (cont)
511   (let ((func (nth 1 (assq mml1991-use mml1991-function-alist))))
512     (if func
513         (funcall func cont)
514       (error "Cannot find sign function"))))
515
516 (provide 'mml1991)
517
518 ;; Local Variables:
519 ;; coding: iso-8859-1
520 ;; End:
521
522 ;; arch-tag: e542be18-ab28-4393-9b33-97fe9cf30706
523 ;;; mml1991.el ends here