Mercurial > emacs
comparison lisp/pgg.el @ 66383:c82982d6cbc4
Moved pgg*.el files from lisp/gnus to lisp.
author | Eli Zaretskii <eliz@gnu.org> |
---|---|
date | Mon, 24 Oct 2005 09:46:27 +0000 |
parents | |
children | 20539524a670 |
comparison
equal
deleted
inserted
replaced
66382:9e9e3aac0fda | 66383:c82982d6cbc4 |
---|---|
1 ;;; pgg.el --- glue for the various PGP implementations. | |
2 | |
3 ;; Copyright (C) 1999, 2000, 2002, 2003, 2004, | |
4 ;; 2005 Free Software Foundation, Inc. | |
5 | |
6 ;; Author: Daiki Ueno <ueno@unixuser.org> | |
7 ;; Created: 1999/10/28 | |
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 2, or (at your option) | |
15 ;; 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; see the file COPYING. If not, write to the | |
24 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | |
25 ;; Boston, MA 02110-1301, USA. | |
26 | |
27 ;;; Commentary: | |
28 | |
29 ;;; Code: | |
30 | |
31 (require 'pgg-def) | |
32 (require 'pgg-parse) | |
33 (autoload 'run-at-time "timer") | |
34 | |
35 ;; Don't merge these two `eval-when-compile's. | |
36 (eval-when-compile | |
37 (require 'cl)) | |
38 | |
39 ;;; @ utility functions | |
40 ;;; | |
41 | |
42 (defun pgg-invoke (func scheme &rest args) | |
43 (progn | |
44 (require (intern (format "pgg-%s" scheme))) | |
45 (apply 'funcall (intern (format "pgg-%s-%s" scheme func)) args))) | |
46 | |
47 (put 'pgg-save-coding-system 'lisp-indent-function 2) | |
48 | |
49 (defmacro pgg-save-coding-system (start end &rest body) | |
50 `(if (interactive-p) | |
51 (let ((buffer (current-buffer))) | |
52 (with-temp-buffer | |
53 (let (buffer-undo-list) | |
54 (insert-buffer-substring buffer ,start ,end) | |
55 (encode-coding-region (point-min)(point-max) | |
56 buffer-file-coding-system) | |
57 (prog1 (save-excursion ,@body) | |
58 (push nil buffer-undo-list) | |
59 (ignore-errors (undo)))))) | |
60 (save-restriction | |
61 (narrow-to-region ,start ,end) | |
62 ,@body))) | |
63 | |
64 (defun pgg-temp-buffer-show-function (buffer) | |
65 (let ((window (or (get-buffer-window buffer 'visible) | |
66 (split-window-vertically)))) | |
67 (set-window-buffer window buffer) | |
68 (shrink-window-if-larger-than-buffer window))) | |
69 | |
70 (defun pgg-display-output-buffer (start end status) | |
71 (if status | |
72 (progn | |
73 (delete-region start end) | |
74 (insert-buffer-substring pgg-output-buffer) | |
75 (decode-coding-region start (point) buffer-file-coding-system)) | |
76 (let ((temp-buffer-show-function | |
77 (function pgg-temp-buffer-show-function))) | |
78 (with-output-to-temp-buffer pgg-echo-buffer | |
79 (set-buffer standard-output) | |
80 (insert-buffer-substring pgg-errors-buffer))))) | |
81 | |
82 (defvar pgg-passphrase-cache (make-vector 7 0)) | |
83 | |
84 (defun pgg-read-passphrase (prompt &optional key) | |
85 (or (and pgg-cache-passphrase | |
86 key (setq key (pgg-truncate-key-identifier key)) | |
87 (symbol-value (intern-soft key pgg-passphrase-cache))) | |
88 (read-passwd prompt))) | |
89 | |
90 (eval-when-compile | |
91 (defmacro pgg-run-at-time-1 (time repeat function args) | |
92 (when (featurep 'xemacs) | |
93 (if (condition-case nil | |
94 (let ((delete-itimer 'delete-itimer) | |
95 (itimer-driver-start 'itimer-driver-start) | |
96 (itimer-value 'itimer-value) | |
97 (start-itimer 'start-itimer)) | |
98 (unless (or (symbol-value 'itimer-process) | |
99 (symbol-value 'itimer-timer)) | |
100 (funcall itimer-driver-start)) | |
101 ;; Check whether there is a bug to which the difference of | |
102 ;; the present time and the time when the itimer driver was | |
103 ;; woken up is subtracted from the initial itimer value. | |
104 (let* ((inhibit-quit t) | |
105 (ctime (current-time)) | |
106 (itimer-timer-last-wakeup | |
107 (prog1 | |
108 ctime | |
109 (setcar ctime (1- (car ctime))))) | |
110 (itimer-list nil) | |
111 (itimer (funcall start-itimer "pgg-run-at-time" | |
112 'ignore 5))) | |
113 (sleep-for 0.1) ;; Accept the timeout interrupt. | |
114 (prog1 | |
115 (> (funcall itimer-value itimer) 0) | |
116 (funcall delete-itimer itimer)))) | |
117 (error nil)) | |
118 `(let ((time ,time)) | |
119 (apply #'start-itimer "pgg-run-at-time" | |
120 ,function (if time (max time 1e-9) 1e-9) | |
121 ,repeat nil t ,args))) | |
122 `(let ((time ,time) | |
123 (itimers (list nil))) | |
124 (setcar | |
125 itimers | |
126 (apply #'start-itimer "pgg-run-at-time" | |
127 (lambda (itimers repeat function &rest args) | |
128 (let ((itimer (car itimers))) | |
129 (if repeat | |
130 (progn | |
131 (set-itimer-function | |
132 itimer | |
133 (lambda (itimer repeat function &rest args) | |
134 (set-itimer-restart itimer repeat) | |
135 (set-itimer-function itimer function) | |
136 (set-itimer-function-arguments itimer args) | |
137 (apply function args))) | |
138 (set-itimer-function-arguments | |
139 itimer | |
140 (append (list itimer repeat function) args))) | |
141 (set-itimer-function | |
142 itimer | |
143 (lambda (itimer function &rest args) | |
144 (delete-itimer itimer) | |
145 (apply function args))) | |
146 (set-itimer-function-arguments | |
147 itimer | |
148 (append (list itimer function) args))))) | |
149 1e-9 (if time (max time 1e-9) 1e-9) | |
150 nil t itimers ,repeat ,function ,args)))))) | |
151 | |
152 (eval-and-compile | |
153 (if (featurep 'xemacs) | |
154 (defun pgg-run-at-time (time repeat function &rest args) | |
155 "Emulating function run as `run-at-time'. | |
156 TIME should be nil meaning now, or a number of seconds from now. | |
157 Return an itimer object which can be used in either `delete-itimer' | |
158 or `cancel-timer'." | |
159 (pgg-run-at-time-1 time repeat function args)) | |
160 (defalias 'pgg-run-at-time 'run-at-time))) | |
161 | |
162 (defun pgg-add-passphrase-cache (key passphrase) | |
163 (setq key (pgg-truncate-key-identifier key)) | |
164 (set (intern key pgg-passphrase-cache) | |
165 passphrase) | |
166 (pgg-run-at-time pgg-passphrase-cache-expiry nil | |
167 #'pgg-remove-passphrase-cache | |
168 key)) | |
169 | |
170 (defun pgg-remove-passphrase-cache (key) | |
171 (let ((passphrase (symbol-value (intern-soft key pgg-passphrase-cache)))) | |
172 (when passphrase | |
173 (fillarray passphrase ?_) | |
174 (unintern key pgg-passphrase-cache)))) | |
175 | |
176 (defmacro pgg-convert-lbt-region (start end lbt) | |
177 `(let ((pgg-conversion-end (set-marker (make-marker) ,end))) | |
178 (goto-char ,start) | |
179 (case ,lbt | |
180 (CRLF | |
181 (while (progn | |
182 (end-of-line) | |
183 (> (marker-position pgg-conversion-end) (point))) | |
184 (insert "\r") | |
185 (forward-line 1))) | |
186 (LF | |
187 (while (re-search-forward "\r$" pgg-conversion-end t) | |
188 (replace-match "")))))) | |
189 | |
190 (put 'pgg-as-lbt 'lisp-indent-function 3) | |
191 | |
192 (defmacro pgg-as-lbt (start end lbt &rest body) | |
193 `(let ((inhibit-read-only t) | |
194 buffer-read-only | |
195 buffer-undo-list) | |
196 (pgg-convert-lbt-region ,start ,end ,lbt) | |
197 (let ((,end (point))) | |
198 ,@body) | |
199 (push nil buffer-undo-list) | |
200 (ignore-errors (undo)))) | |
201 | |
202 (put 'pgg-process-when-success 'lisp-indent-function 0) | |
203 | |
204 (defmacro pgg-process-when-success (&rest body) | |
205 `(with-current-buffer pgg-output-buffer | |
206 (if (zerop (buffer-size)) nil ,@body t))) | |
207 | |
208 (defalias 'pgg-make-temp-file | |
209 (if (fboundp 'make-temp-file) | |
210 'make-temp-file | |
211 (lambda (prefix &optional dir-flag) | |
212 (let ((file (expand-file-name | |
213 (make-temp-name prefix) | |
214 (if (fboundp 'temp-directory) | |
215 (temp-directory) | |
216 temporary-file-directory)))) | |
217 (if dir-flag | |
218 (make-directory file)) | |
219 file)))) | |
220 | |
221 ;;; @ interface functions | |
222 ;;; | |
223 | |
224 ;;;###autoload | |
225 (defun pgg-encrypt-region (start end rcpts &optional sign) | |
226 "Encrypt the current region between START and END for RCPTS. | |
227 If optional argument SIGN is non-nil, do a combined sign and encrypt." | |
228 (interactive | |
229 (list (region-beginning)(region-end) | |
230 (split-string (read-string "Recipients: ") "[ \t,]+"))) | |
231 (let ((status | |
232 (pgg-save-coding-system start end | |
233 (pgg-invoke "encrypt-region" (or pgg-scheme pgg-default-scheme) | |
234 (point-min) (point-max) rcpts sign)))) | |
235 (when (interactive-p) | |
236 (pgg-display-output-buffer start end status)) | |
237 status)) | |
238 | |
239 ;;;###autoload | |
240 (defun pgg-encrypt (rcpts &optional sign start end) | |
241 "Encrypt the current buffer for RCPTS. | |
242 If optional argument SIGN is non-nil, do a combined sign and encrypt. | |
243 If optional arguments START and END are specified, only encrypt within | |
244 the region." | |
245 (interactive (list (split-string (read-string "Recipients: ") "[ \t,]+"))) | |
246 (let* ((start (or start (point-min))) | |
247 (end (or end (point-max))) | |
248 (status (pgg-encrypt-region start end rcpts sign))) | |
249 (when (interactive-p) | |
250 (pgg-display-output-buffer start end status)) | |
251 status)) | |
252 | |
253 ;;;###autoload | |
254 (defun pgg-decrypt-region (start end) | |
255 "Decrypt the current region between START and END." | |
256 (interactive "r") | |
257 (let* ((buf (current-buffer)) | |
258 (status | |
259 (pgg-save-coding-system start end | |
260 (pgg-invoke "decrypt-region" (or pgg-scheme pgg-default-scheme) | |
261 (point-min) (point-max))))) | |
262 (when (interactive-p) | |
263 (pgg-display-output-buffer start end status)) | |
264 status)) | |
265 | |
266 ;;;###autoload | |
267 (defun pgg-decrypt (&optional start end) | |
268 "Decrypt the current buffer. | |
269 If optional arguments START and END are specified, only decrypt within | |
270 the region." | |
271 (interactive "") | |
272 (let* ((start (or start (point-min))) | |
273 (end (or end (point-max))) | |
274 (status (pgg-decrypt-region start end))) | |
275 (when (interactive-p) | |
276 (pgg-display-output-buffer start end status)) | |
277 status)) | |
278 | |
279 ;;;###autoload | |
280 (defun pgg-sign-region (start end &optional cleartext) | |
281 "Make the signature from text between START and END. | |
282 If the optional 3rd argument CLEARTEXT is non-nil, it does not create | |
283 a detached signature. | |
284 If this function is called interactively, CLEARTEXT is enabled | |
285 and the the output is displayed." | |
286 (interactive "r") | |
287 (let ((status (pgg-save-coding-system start end | |
288 (pgg-invoke "sign-region" (or pgg-scheme pgg-default-scheme) | |
289 (point-min) (point-max) | |
290 (or (interactive-p) cleartext))))) | |
291 (when (interactive-p) | |
292 (pgg-display-output-buffer start end status)) | |
293 status)) | |
294 | |
295 ;;;###autoload | |
296 (defun pgg-sign (&optional cleartext start end) | |
297 "Sign the current buffer. | |
298 If the optional argument CLEARTEXT is non-nil, it does not create a | |
299 detached signature. | |
300 If optional arguments START and END are specified, only sign data | |
301 within the region. | |
302 If this function is called interactively, CLEARTEXT is enabled | |
303 and the the output is displayed." | |
304 (interactive "") | |
305 (let* ((start (or start (point-min))) | |
306 (end (or end (point-max))) | |
307 (status (pgg-sign-region start end (or (interactive-p) cleartext)))) | |
308 (when (interactive-p) | |
309 (pgg-display-output-buffer start end status)) | |
310 status)) | |
311 | |
312 ;;;###autoload | |
313 (defun pgg-verify-region (start end &optional signature fetch) | |
314 "Verify the current region between START and END. | |
315 If the optional 3rd argument SIGNATURE is non-nil, it is treated as | |
316 the detached signature of the current region. | |
317 | |
318 If the optional 4th argument FETCH is non-nil, we attempt to fetch the | |
319 signer's public key from `pgg-default-keyserver-address'." | |
320 (interactive "r") | |
321 (let* ((packet | |
322 (if (null signature) nil | |
323 (with-temp-buffer | |
324 (buffer-disable-undo) | |
325 (if (fboundp 'set-buffer-multibyte) | |
326 (set-buffer-multibyte nil)) | |
327 (insert-file-contents signature) | |
328 (cdr (assq 2 (pgg-decode-armor-region | |
329 (point-min)(point-max))))))) | |
330 (key (cdr (assq 'key-identifier packet))) | |
331 status keyserver) | |
332 (and (stringp key) | |
333 pgg-query-keyserver | |
334 (setq key (concat "0x" (pgg-truncate-key-identifier key))) | |
335 (null (pgg-lookup-key key)) | |
336 (or fetch (interactive-p)) | |
337 (y-or-n-p (format "Key %s not found; attempt to fetch? " key)) | |
338 (setq keyserver | |
339 (or (cdr (assq 'preferred-key-server packet)) | |
340 pgg-default-keyserver-address)) | |
341 (pgg-fetch-key keyserver key)) | |
342 (setq status | |
343 (pgg-save-coding-system start end | |
344 (pgg-invoke "verify-region" (or pgg-scheme pgg-default-scheme) | |
345 (point-min) (point-max) signature))) | |
346 (when (interactive-p) | |
347 (let ((temp-buffer-show-function | |
348 (function pgg-temp-buffer-show-function))) | |
349 (with-output-to-temp-buffer pgg-echo-buffer | |
350 (set-buffer standard-output) | |
351 (insert-buffer-substring (if status pgg-output-buffer | |
352 pgg-errors-buffer))))) | |
353 status)) | |
354 | |
355 ;;;###autoload | |
356 (defun pgg-verify (&optional signature fetch start end) | |
357 "Verify the current buffer. | |
358 If the optional argument SIGNATURE is non-nil, it is treated as | |
359 the detached signature of the current region. | |
360 If the optional argument FETCH is non-nil, we attempt to fetch the | |
361 signer's public key from `pgg-default-keyserver-address'. | |
362 If optional arguments START and END are specified, only verify data | |
363 within the region." | |
364 (interactive "") | |
365 (let* ((start (or start (point-min))) | |
366 (end (or end (point-max))) | |
367 (status (pgg-verify-region start end signature fetch))) | |
368 (when (interactive-p) | |
369 (let ((temp-buffer-show-function | |
370 (function pgg-temp-buffer-show-function))) | |
371 (with-output-to-temp-buffer pgg-echo-buffer | |
372 (set-buffer standard-output) | |
373 (insert-buffer-substring (if status pgg-output-buffer | |
374 pgg-errors-buffer))))) | |
375 status)) | |
376 | |
377 ;;;###autoload | |
378 (defun pgg-insert-key () | |
379 "Insert the ASCII armored public key." | |
380 (interactive) | |
381 (pgg-invoke "insert-key" (or pgg-scheme pgg-default-scheme))) | |
382 | |
383 ;;;###autoload | |
384 (defun pgg-snarf-keys-region (start end) | |
385 "Import public keys in the current region between START and END." | |
386 (interactive "r") | |
387 (pgg-save-coding-system start end | |
388 (pgg-invoke "snarf-keys-region" (or pgg-scheme pgg-default-scheme) | |
389 start end))) | |
390 | |
391 ;;;###autoload | |
392 (defun pgg-snarf-keys () | |
393 "Import public keys in the current buffer." | |
394 (interactive "") | |
395 (pgg-snarf-keys-region (point-min) (point-max))) | |
396 | |
397 (defun pgg-lookup-key (string &optional type) | |
398 (pgg-invoke "lookup-key" (or pgg-scheme pgg-default-scheme) string type)) | |
399 | |
400 (defvar pgg-insert-url-function (function pgg-insert-url-with-w3)) | |
401 | |
402 (defun pgg-insert-url-with-w3 (url) | |
403 (ignore-errors | |
404 (require 'url) | |
405 (let (buffer-file-name) | |
406 (url-insert-file-contents url)))) | |
407 | |
408 (defvar pgg-insert-url-extra-arguments nil) | |
409 (defvar pgg-insert-url-program nil) | |
410 | |
411 (defun pgg-insert-url-with-program (url) | |
412 (let ((args (copy-sequence pgg-insert-url-extra-arguments)) | |
413 process) | |
414 (insert | |
415 (with-temp-buffer | |
416 (setq process | |
417 (apply #'start-process " *PGG url*" (current-buffer) | |
418 pgg-insert-url-program (nconc args (list url)))) | |
419 (set-process-sentinel process #'ignore) | |
420 (while (eq 'run (process-status process)) | |
421 (accept-process-output process 5)) | |
422 (delete-process process) | |
423 (if (and process (eq 'run (process-status process))) | |
424 (interrupt-process process)) | |
425 (buffer-string))))) | |
426 | |
427 (defun pgg-fetch-key (keyserver key) | |
428 "Attempt to fetch a KEY from KEYSERVER for addition to PGP or GnuPG keyring." | |
429 (with-current-buffer (get-buffer-create pgg-output-buffer) | |
430 (buffer-disable-undo) | |
431 (erase-buffer) | |
432 (let ((proto (if (string-match "^[a-zA-Z\\+\\.\\\\-]+:" keyserver) | |
433 (substring keyserver 0 (1- (match-end 0)))))) | |
434 (save-excursion | |
435 (funcall pgg-insert-url-function | |
436 (if proto keyserver | |
437 (format "http://%s:11371/pks/lookup?op=get&search=%s" | |
438 keyserver key)))) | |
439 (when (re-search-forward "^-+BEGIN" nil 'last) | |
440 (delete-region (point-min) (match-beginning 0)) | |
441 (when (re-search-forward "^-+END" nil t) | |
442 (delete-region (progn (end-of-line) (point)) | |
443 (point-max))) | |
444 (insert "\n") | |
445 (with-temp-buffer | |
446 (insert-buffer-substring pgg-output-buffer) | |
447 (pgg-snarf-keys-region (point-min)(point-max))))))) | |
448 | |
449 | |
450 (provide 'pgg) | |
451 | |
452 ;;; arch-tag: 9cc705dd-1e6a-4c90-8dce-c3561f9a2cf4 | |
453 ;;; pgg.el ends here |