]> git.donarmstrong.com Git - lib.git/blob - emacs_el/tiny-tools/tiny/tinypgp.el
add tiny-tools
[lib.git] / emacs_el / tiny-tools / tiny / tinypgp.el
1 ;;; tinypgp.el --- PGP minor mode, remailing, keyring management
2
3 ;; This file is not part of Emacs
4
5 ;;{{{ Id
6
7 ;; Copyright (C)    1996-2007 Jari Aalto
8 ;; Keywords:        extensions
9 ;; Author:          Jari Aalto
10 ;; Maintainer:      Jari Aalto
11 ;;
12 ;; To get information on this program, call M-x tinypgp-version.
13 ;; Look at the code with folding.el
14
15 ;; COPYRIGHT NOTICE
16 ;;
17 ;; This program is free software; you can redistribute it and/or modify it
18 ;; under the terms of the GNU General Public License as published by the Free
19 ;; Software Foundation; either version 2 of the License, or (at your option)
20 ;; any later version.
21 ;;
22 ;; This program is distributed in the hope that it will be useful, but
23 ;; WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
24 ;; or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
25 ;; for more details.
26 ;; This file is not part of Emacs
27
28 ;;}}}
29 ;;{{{ Install
30
31 ;;; Install:
32
33 ;; ....................................................... &t-install ...
34 ;;
35 ;;  THIS FILE IS UNMAINTAINED - AND NOT WORKING IN ANY WAY
36 ;;
37 ;;  Put this file on your Emacs-Lisp load path, add following into your
38 ;;  ~/.emacs startup file.
39 ;;
40 ;;      (require 'tinypgp)
41 ;;
42 ;;  or use this; your ~/.emacs loads quicker
43 ;;
44 ;;      (autoload 'tinypgp-mode                 "tinypgp" "" t)
45 ;;      (autoload 'turn-on-tinypgp-mode         "tinypgp" "" t)
46 ;;      (autoload 'turn-off-tinypgp-mode        "tinypgp" "" t)
47 ;;      (autoload 'tinypgp-install              "tinypgp" "" t)
48 ;;
49 ;;      (add-hook 'message-mode-hook      'turn-on-tinypgp-mode)
50 ;;      (add-hook 'mail-mode-hook         'turn-on-tinypgp-mode)
51 ;;      (add-hook 'rmail-mode-hook        'turn-on-tinypgp-mode)
52 ;;      (add-hook 'vm-mode-hook           'turn-on-tinypgp-mode)
53 ;;      (add-hook 'gnus-startup-hook      'tinypgp-install)
54 ;;      (add-hook 'gnus-article-edit-mode 'turn-on-tinypgp-mode)
55 ;;
56 ;;  Put your customizations to separate file and add this.
57 ;;
58 ;;   (setq tinypgp-:load-hook
59 ;;     '(lambda () (require 'rc-tinypgp  "~/elisp/rc/emacs-rc-tinypgp")))
60 ;;
61 ;;  to automatically sign all your outgoing mail, add this to your .emacs
62 ;;  For more personal signing, see manual
63 ;;
64 ;;      (add-hook 'mail-send-hook    'tinypgp-sign-mail-auto-mode-on)
65 ;;      (add-hook 'message-send-hook 'tinypgp-sign-mail-auto-mode-on)
66 ;;
67 ;;  Suggested mode binding, "m" prefix for all minor mode toggles.
68 ;;  If these are occupied, then choose some other bindings.
69 ;;
70 ;;      ;; note, Mailcrypt's prefix key is C-c / which is also
71 ;;      ;; this package's prefix key unless you use the setq below.
72 ;;      ;;
73 ;;      ;; Personally I like the "-" because it's easier to reach than "/"
74 ;;      ;; in my keyboard.
75 ;;      ;;
76 ;;      (setq tinypgp-:mode-prefix-key    "\C-c-")
77 ;;      (global-set-key "\C-cm-"        'tinypgp-mode)
78 ;;      (global-set-key "\C-cm'"        'tinypgp-key-mode)
79 ;;
80 ;;  See the end of file for additional examples.
81 ;;  If you want to contact maintainer, always use this function
82 ;;
83 ;;      M-x tinypgp-submit-bug-report       -- send feedback or bug report
84
85 ;;}}}
86 ;;{{{ Documentation
87
88 ;; ..................................................... &t-commentary ...
89 ;;; Commentary:
90
91 ;;}}}
92
93 ;;; History:
94
95 ;;; Code:
96
97 ;;{{{ setup: require
98
99 ;;; ......................................................... &require ...
100
101 (require 'tinylib)
102 (require 'tinylibmail)
103 (require 'mail-utils)
104
105 (eval-when-compile
106   (ti::package-use-dynamic-compilation)
107   (require 'advice))
108
109 (eval-and-compile
110
111   (message "\
112   ** tinypgp.el: Notice dated 2000-02-10
113      THIS FILE IS NOT CURRENTLY MAINTAINED. You can expect that the pgp
114      interface is non-functional and compiling this file gives errors.")
115
116   (when (and (ti::win32-p)
117              (ti::nil-p (getenv "PGPPATH")))
118     (error "TinyPgp: environment variable PGPPATH not set for secring.*"))
119
120   (ti::package-package-require-timer)
121
122   (autoload 'rmail-edit-current-message         "rmailedit" t t)
123   (autoload 'rmail-cease-edit                   "rmailedit" t t)
124   (autoload 'rmail-add-label                    "rmailkwd")
125   (autoload 'rmail-kill-label                   "rmailkwd")
126
127   (defvar vm-frame-per-edit t)          ;See vm-vars.el
128   (autoload 'vm-edit-message                    "vm-edit" t t)
129   (autoload 'vm-edit-message-end                "vm-edit" t t)
130   (autoload 'vm-delete-message-labels           "vm-undo" t t)
131   (autoload 'vm-add-message-labels              "vm-undo" t t)
132   (autoload 'vm-update-summary-and-mode-line    "vm" t t)
133
134   (defvar mail-send-hook nil)
135   (defvar mail-mode-hook nil)
136
137   (defvar message-mode-hook nil)
138   (autoload 'message-send-and-exit              "message")
139
140   (autoload 'mail-send-and-exit                 "sendmail")
141   (autoload 'mail-setup                         "sendmail")
142   (autoload 'mail-do-fcc                        "sendmail")
143
144   (autoload 'adelete                            "assoc")
145
146   ;; TM mime available at
147   ;; ftp://ftp.jaist.ac.jp:/pub/GNU/elisp/mime/
148
149   (defvar   mime/editor-mode-flag nil)
150   (autoload 'mime-editor/exit                       "tm-edit")
151   (autoload 'mime-editor/enclose-signed-region      "tm-edit")
152   (autoload 'mime-editor/enclose-encrypted-region   "tm-edit")
153   (autoload 'mime-viewer/quit                       "tm-view")
154
155   (autoload 'timi-mail                              "tinymail")
156
157   (autoload 'bbdb-search-simple                     "bbdb")
158   (autoload 'bbdb-record-getprop                    "bbdb")
159
160   (autoload 'gnus-inews-do-gcc                      "gnus-msg")
161   (autoload 'gnus-summary-edit-article              "gnus-sum" t t)
162   (autoload 'gnus-article-edit-done                 "gnus-art" t t)
163
164   ;;  The expect code is needed only in Pgp 5.x
165   ;;  Only if that backend is used the expect.el is loaded.
166
167   (autoload 'expect-make-info                     "expect" nil nil)
168   (autoload 'expect-info-process                  "expect" nil nil 'macro)
169   (autoload 'expect-info-message                  "expect" nil nil 'macro)
170   (autoload 'expect-info-point                    "expect" nil nil 'macro)
171   (autoload 'expect-info-set-point                "expect" nil nil 'macro)
172   (autoload 'expect-info-sentinels                "expect" nil nil 'macro)
173   (autoload 'expect-info-set-sentinels            "expect" nil nil 'macro)
174   (autoload 'expect-info-timer                    "expect" nil nil 'macro)
175   (autoload 'expect-info-set-timer                "expect" nil nil 'macro)
176   (autoload 'expect-info-queries                  "expect" nil nil 'macro)
177   (autoload 'expect-info-set-queries              "expect" nil nil 'macro)
178   (autoload 'expect-find-info                     "expect" nil nil 'macro)
179   (autoload 'with-expect                          "expect" nil nil 'macro)
180   (autoload 'expect-start-process                 "expect" nil nil)
181   (autoload 'with-expect-asynchronous             "expect" nil nil 'macro)
182   (autoload 'expect                               "expect" nil nil 'macro)
183   (autoload 'expect-cond                          "expect" nil nil 'macro)
184   (autoload 'expect-exit                          "expect" nil nil 'macro)
185   (autoload 'expect-send                          "expect" nil nil 'macro)
186   (autoload 'expect-setup                         "expect" nil nil)
187   (autoload 'expect-shutdown                      "expect" nil nil)
188   (autoload 'expect-kill                          "expect" nil nil)
189   (autoload 'expect-wait                          "expect" nil nil)
190   (autoload 'expect-1                             "expect" nil nil)
191   (autoload 'expect-exit-1                        "expect" nil nil)
192   (autoload 'expect-filter                        "expect" nil nil)
193   (autoload 'expect-sentinel                      "expect" nil nil)
194   (autoload 'expect-find-event                    "expect" nil nil)
195   (autoload 'expect-setup-timer                   "expect" nil nil)
196   (autoload 'expect-cancel-timer                  "expect" nil nil)
197
198   ;;  When file is byte compiled, the expand-file-name might eventually
199   ;;  call this function, so let emacs know where it is.
200
201   (autoload 'ange-ftp-real-expand-file-name         "ange-ftp" t t))
202
203 ;;; ......................................................... &v-group ...
204
205 (defgroup TinyPgp nil
206   "Emacs PGP and Remailer interface.
207
208         TinyPgp is intended to be a 2nd generation Emacs PGP interface
209         and it supports all major pgp commands from inside
210         emacs. Remailing and anonymous account handling in different
211         servers is included."
212
213   :link '(url-link
214           :tag "Keyserver home"
215           "http://geronimo.uit.no/cc/tjenester/PGP/servruit.eng.html")
216
217   :link '(url-link
218           :tag "Pgp mailing list"
219           "http://pgp.rivertown.net/")
220
221   :link '(url-link
222           :tag "Norway's keyserver"
223           "http://www.ifi.uio.no/pgp/")
224
225   :link '(url-link
226           :tag "Remailer Faq (Galactus)"
227           "http://www.stack.urc.tue.nl/~galactus/remailers/")
228
229   :link '(url-link
230           :tag "PGP faq alt.security.pgp"
231           "ftp://ftp.prairienet.org/pub/providers/pgp/pgpfaq.txt")
232
233   :link '(url-link
234           :tag "X-Pgp header specififacion"
235           "ftp://cs.uta.fi/pub/ssjaaa/pgp-xhd.html")
236
237   :link '(url-link
238           :tag "TinyPgp Manu page"
239           "ftp://cs.uta.fi/pub/ssjaaa/tinypgp.html")
240
241   :prefix "tinypgp-:"
242   :group 'extensions)
243
244 ;;; .................................................... &v-group-mode ...
245
246 (defgroup tinypgp-mode-definitions nil
247   "Mode names, menu names and prefix key settings."
248   :prefix "tinypgp-:"
249   :group  'TinyPgp)
250
251 (defgroup tinypgp-mode nil
252   "Options that directly address basic PGP commands in minor modes."
253   :prefix "tinypgp-:"
254   :group  'TinyPgp)
255
256 (defgroup tinypgp-header nil
257   "Options that deal with Email message headers."
258   :prefix "tinypgp-:"
259   :group  'TinyPgp)
260
261 (defgroup tinypgp-file nil
262   "Files used when communicating with PGP. You shouldn't rename these.
263 Do not add any extension to files, because PGP itself may append extension
264 .asc or .pgp or .bak. change only directory location.
265
266 When you load the package first time the directory name is initialized
267 from `tinypgp-:file-directory' or if it is nil a wild guess will be taken
268 See function documentation `tinypgp-path' for details.
269 "
270   :prefix "tinypgp-:"
271   :group  'TinyPgp)
272
273 (defgroup tinypgp-hook nil
274   "Variables where you can put your own functions."
275   :prefix "tinypgp-:"
276   :group  'TinyPgp)
277
278 (defgroup tinypgp-function nil
279   "Variables where you can put your own functions."
280   :prefix "tinypgp-:"
281   :group  'TinyPgp)
282
283 (defgroup tinypgp-pgp nil
284   "Options that relate to PGP executable and shell envinronment."
285   :prefix "tinypgp-:"
286   :group  'TinyPgp)
287
288 ;;; .................................................... &v-group-misc ...
289
290 (defgroup tinypgp-interface nil
291   "Variables to configure connections to outside world (ftp, http, email)"
292   :prefix "tinypgp-:"
293   :group  'TinyPgp)
294
295 (defgroup tinypgp-remail nil
296   "Remailer interface settings."
297   :prefix "tinypgp-:r"
298   :group  'TinyPgp)
299
300 (defgroup tinypgp-remail-hook nil
301   "Remailer interface hooks."
302   :prefix "tinypgp-:r"
303   :group  'tinypgp-remail)
304
305 (defgroup tinypgp-nymserver nil
306   "Anonymous service (paid) anon.nymserver.com settings.
307 Similar to anon.penet.fi, which has been closed permanently."
308
309   :link '(url-link
310           :tag "Nymserver main page"
311           "http://www.nymserver.com")
312
313   :link '(url-link
314           :tag "Nymserver html doc (a bit old)"
315           "ftp://cs.uta.fi/pub/ssjaaa/nymserv.html")
316
317   :prefix "tinypgp-:r"
318   :group  'TinyPgp)
319
320 (defgroup tinypgp-newnym nil
321   "Anonymous PGP service newnym type remailers."
322
323   :link '(url-link
324           :tag "Nym help page"
325           "http://www.stack.nl/~galactus/remailers/nym.html")
326
327   :prefix "tinypgp-:r"
328   :group  'TinyPgp)
329
330 ;;}}}
331 ;;{{{ setup: predefined functions
332
333 (defcustom tinypgp-:file-directory nil
334   "*Directory where to store temporary files. Must not be public; like /tmp/.
335 You should store files under your private directory. If this variable
336 is nil; then `tinypgp-path' guesses the right location for you. See function
337 documentations for more."
338   :type  'directory
339   :group 'tinypgp-file)
340
341 ;;; ----------------------------------------------------------------------
342 ;;; Define this function becore it is used in variables.
343 ;;;
344
345 (eval-and-compile
346
347   (defun tinypgp-expand-file-name (file &optional type)
348     "Expand file under correct OS. TYPE overrides: 'unix 'win32."
349     (cond
350      ((and (ti::win32-p)
351            (eq type 'unix))
352       (save-match-data
353         (ti::file-name-forward-slashes-cygwin (expand-file-name file))))
354      ((or (ti::win32-p)
355           (eq type 'win32))
356       (save-match-data
357         (ti::file-name-backward-slashes (expand-file-name file))))
358      (t
359       (expand-file-name file))))
360
361   (defun tinypgp-path (file &optional try-paths)
362     "Add path to FILE with TRY-PATHS. See also `tinypgp-:file-directory'.
363 Search list is:
364
365     `tinypgp-:file-directory'
366     PGPPATH
367     ~/.pgp/
368     ~/
369
370 If FILE already includes path, do nothing."
371     (let* (path)
372       (or (stringp file)
373           (error "FILE is missing."))
374
375       (if (string-match "[~/]" (substring file 0 1))
376           (tinypgp-expand-file-name file) ;Already had path
377         (dolist (try (or try-paths
378                          (list tinypgp-:file-directory
379                                (getenv "PGPPATH")
380                                "~/.pgp/"
381                                "~/")))
382           (when try
383             (setq try (ti::string-verify-ends try "/"))
384             (when (file-directory-p try)
385               (setq path try)
386               (return))))
387         (if (not (file-exists-p path))
388             (error "Can't find path %s" path))
389         (tinypgp-expand-file-name (concat path file))))))
390
391 ;;; ----------------------------------------------------------------------
392 ;;;
393
394 (eval-and-compile
395
396   (defun tinypgp-binary-get-version (&optional ret-type call-shell)
397     "Return version number of current pgp.
398
399 Input:
400
401   RET-TYPE      How the information is returned.
402                 If this is nil then return STRING.
403                 If this is non-nil then return 'us (2.6.2) or
404                 'international (2.6.3i)
405
406   CALL-SHELL    if nil, then look variable `tinypgp-:pgp-binary'.
407                 If there is no variable or it is not string, then
408                 call shell to find out pgp exe's version number
409
410 Return:
411
412   string        See RET-TYPE
413   symbol"
414     (let (ret)
415       (if (and (null call-shell)
416                (boundp 'tinypgp-:pgp-binary)
417                (setq ret (get 'tinypgp-:pgp-binary 'version)))
418           nil                           ;ret already set
419         (setq ret (ti::mail-pgp-exe-version-string)))
420
421       (if (and ret-type (stringp ret))
422           (if (string-match "i" ret)
423               (setq ret 'international)
424             (setq ret 'us)))
425       ret)))
426
427 ;;}}}
428 ;;{{{ setup: version
429
430 ;;; ...................................................... &vp-version ...
431 ;;; the version information is needed in the variable definitions later.
432
433 (eval-and-compile
434   (defconst tinypgp-:version-id
435     "$Id: tinypgp.el,v 2.57 2007/05/07 10:50:10 jaalto Exp $"
436     "Latest modification time and version number.")
437   (defun tinypgp-version-number ()
438     "Return version number as string."
439     (ti::string-match "\\([0-9]+\\.[0-9]+\\)" 1 tinypgp-:version-id)))
440
441 ;;; ----------------------------------------------------------------------
442 ;;;
443
444 (defun tinypgp-version (&optional arg)
445   "Show version information. ARG instruct to print message in echo area only."
446   (interactive "P")
447   (ti::package-version-info "tinypgp.el" arg))
448
449 ;;; ----------------------------------------------------------------------
450 ;;;
451
452 (defun tinypgp-version-message ()
453   "Display version."
454   (interactive)
455   (message tinypgp-:version-id))
456
457 ;;}}}
458 ;;{{{ setup: hooks
459
460 ;; ......................................................... &v-hooks ...
461
462 (defcustom tinypgp-:load-hook nil
463   "*Hook that is run when package is loaded."
464   :type  'hook
465   :group 'tinypgp-hook)
466
467 (defcustom tinypgp-:mode-hook nil
468   "*Hook run when minor mode is turned on."
469   :type  'hook
470   :group 'tinypgp-hook)
471
472 (defcustom tinypgp-:key-mode-hook nil
473   "*Hook run when minor mode is turned on."
474   :type  'hook
475   :group 'tinypgp-hook)
476
477 (defcustom tinypgp-:summary-mode-hook nil
478   "*Hook run when minor mode is turned on."
479   :type  'hook
480   :group 'tinypgp-hook)
481
482 (defcustom tinypgp-:mail-send-hook-list
483   '(mail-send-hook
484     message-send-hook
485     mh-before-send-letter-hook)
486   "*List of hooks that are called by Mail agents before sending mail."
487   :type  'hook
488   :group 'tinypgp-hook)
489
490 (defcustom tinypgp-:turn-on-hook-list
491   '(mail-mode-hook
492     rmail-mode-hook
493     vm-mode-hook
494     message-mode-hook
495     gnus-article-mode-hook              ; When selecting the article.
496     gnus-article-edit-mode-hook
497     news-reply-mode-hook                ; 'f' key reply, GNUS 4 only
498     mh-letter-mode-hook
499     mh-show-mode-hook)
500   "*List of hooks where to install pgp mode.
501 Call `add-hook' only inside `tinypgp-:load-hook', because the defvar
502 installs many default hooks."
503   :type  'hook
504   :group 'tinypgp-hook)
505
506 (defcustom tinypgp-:sig-from-header-hook nil
507   "*Hook run at the end of `tinypgp-pgp-move-sig-from-header' function.
508 If there is no PGP header, hook is not called."
509   :type  'hook
510   :group 'tinypgp-hook)
511
512 (defcustom tinypgp-:sig-to-header-hook nil
513   "*Hook run at the end of `tinypgp-signature-move-to-header function' function.
514 If there is no PGP header, hook is not called."
515   :type  'hook
516   :group 'tinypgp-hook)
517
518 (defcustom tinypgp-:sign-loose-info-hook nil
519   "*Hook run when the `tinypgp-sign-loose-info' function has completed."
520   :type  'hook
521   :group 'tinypgp-hook)
522
523 (defcustom tinypgp-:define-keys-hook nil
524   "*List of functions to define all keys and menus."
525   :type  'hook
526   :group 'tinypgp-hook)
527
528 (defcustom tinypgp-:key-mode-define-keys-hook nil
529   "*List of functions to define all keys and menus."
530   :type  'hook
531   :group 'tinypgp-hook)
532
533 (defcustom tinypgp-:summary-mode-define-keys-hook nil
534   "*List of functions to define all keys and menus."
535   :type  'hook
536   :group 'tinypgp-hook)
537
538 (defcustom tinypgp-:newnym-mode-define-keys-hook nil
539   "*List of functions to define all keys and menus."
540   :type  'hook
541   :group 'tinypgp-hook)
542
543 (defvar tinypgp-:do-command-region-before-hook nil
544   "Hook run in tmp buffer where containing data for pgp.
545 The PGP shell command is at this point stored into variable
546 `tinypgp-:last-pgp-exe-command'.
547
548 Note:
549
550   If function in this hook returns non-nil, the rest of the functions are
551   not called.
552
553 Call arguments:
554
555   cmd msg res-str")
556
557 (defvar tinypgp-:do-command-region-after-hook nil
558   "Hook run in tmp buffer after the PGP shell command has completed.
559
560 Note:
561
562   If function in this hook returns non-nil, the rest of the functions are
563   not called.
564
565 Call arguments:
566   cmd msg res-str")
567
568 (defvar tinypgp-:cmd-macro-before-hook nil
569   "Hook which run before the pgp sequence initiates in current buffer.
570 See function `tinypgp-cmd-macro' for arguments.
571
572 Note:
573
574   First function that returns non-nil terminates running the
575   rest of the functions. User functions must be at the end of hook
576   (use add-hook's 3rd parameter)
577
578 Call arguments:
579
580   cmd user msg string")
581
582 (defvar tinypgp-:cmd-macro-after-hook nil
583   "Hook which run after the pgp sequence has been completed.
584 See function `tinypgp-cmd-macro' for arguments.
585
586 Note:
587
588   First function that returns non-nil terminates running the
589   rest of the functions. User functions must be at the end of hook
590   (use add-hook's 3rd 'append parameter)
591
592 Call arguments:
593
594   cmd user msg string
595
596 Call Note:
597
598   if the CMD is 'cancel, then the function in this hook must not
599   do any modification, but only restore any state that may have
600   been opened in the *before* hook. (Eg. closing rmail-edit-mode).
601   The 'cancel indicates that `error' command is about to be called soon.")
602
603 (defcustom tinypgp-:verify-before-hook nil
604   "*Hook run before verify function is called.
605 Every function in the hook is called with 2 args: region-beg region-end
606 The function should return non-nil if it doesn't want to allow other
607 functions in the hook to continue."
608   :type  'hook
609   :group 'tinypgp-hook)
610
611 (defcustom tinypgp-:verify-after-hook nil
612   "*Hook run when verify function is done.
613
614 Note:
615
616   First function that returns non-nil terminates running the
617   rest of the functions.
618
619 Call arguments:
620
621   region-beg region-end verify-string-ret-val."
622   :type  'hook
623   :group 'tinypgp-hook)
624
625 (defcustom tinypgp-:read-email-after-hook '(tinypgp-email-substitution-default)
626   "*This hook is called after email address list has been read.
627 The list is used e.g. for decrypting the message to multiple
628 users.
629
630 It may be desiradble to change some email address to something else;
631 supposes that you're sending encrypted message to foo2@site.com, but
632 you have key from him only that refers to email foo1@site.com. If you
633 try to encrypt according to \"To: foo2@site.com\" you get PGP error,
634 because there is no such key in the active keyring. That's why
635 you modify list and change the foo2@site.com to foo1@site.com.
636
637 Call arguments:
638
639   email-list or string
640
641 Function should return:
642
643   list                  ,original list if no changes.
644   modified list"
645   :type  'hook
646   :group 'tinypgp-hook)
647
648 (defcustom tinypgp-:insert-file-sign-base64-hook
649   'ti::process-tar-zip-view-maybe-command
650   "*Hook to run before the file is inserted to current point.
651 There is default function to this hook for tar/zip files, which inserts
652 the file listing into the buffer.
653
654 Note:
655
656   If some function return non-nil the rest of the functions are not run.
657   The buffer is temporary buffer for inserted data where hook is run,
658   point sits at `point-min' and buffer holds the base64 signed file.
659
660 Call arguments:
661
662   string : filename"
663   :type  'hook
664   :group 'tinypgp-hook)
665
666 (defcustom tinypgp-:auto-action-before-hook nil
667   "*Hook run before `tinypgp-auto-action' processes anything."
668   :type  'hook
669   :group 'tinypgp-hook)
670
671 (defcustom tinypgp-:auto-action-defeat-hook '(tinypgp-auto-action-defeat-p)
672   "*If any the functions return non-nil, the auto action is defeated.
673 Called from `tinypgp-auto-action'. The default function
674 `tinypgp-auto-action-defeat-p' inhibits processing MIME messages."
675   :type  'hook
676   :group 'tinypgp-hook)
677
678 ;;; .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. others . .
679
680 (defcustom tinypgp-:finger-discard-email-hook
681   '(tinypgp-finger-discard-by-regexp)
682   "*This hook is called before finger spawned to fetch public key.
683 You should discard any email addresses that refer to your account.
684
685 Default function:
686   `tinypgp-finger-discard-by-regexp'
687   --> uses variable `tinypgp-:finger-discard-by-regexp'
688
689 Function call arguments:
690
691   string or list of strings '(email email ..)
692
693 Function should return:
694
695   modified list or string
696   nil                       ,do not finger anything.
697
698 Example code, which is also the idea of default function:
699
700   (add-hook 'tinypgp-:finger-discard-email-hook
701             'my-tinypgp-finger-discard-email)
702
703   (setq my-:tinypgp-me \"me.surname@\\|myOtherAccount@foo\\|3rd@bix.com\")
704
705   (defun my-tinypgp-finger-discard-email (string-or-list)
706     ;;  Discard addresses that point to me
707     (require 'tinylibm)
708     (let (ret)
709       (mapcar
710        (function
711         (lambda (x)
712           (if (not (string-match my-:tinypgp-me x))
713               (push x ret))))
714        ;; convert string to list if needed.
715        (ti::list-make string-or-list))
716       ret))"
717   :type  'hook
718   :group 'tinypgp-hook)
719
720 (defcustom tinypgp-:find-by-guess-hook nil
721   "*Functions called to find public key and keyring.
722
723 Notes:
724
725   First function that return non-nil terminates calling other
726   function in the hook
727
728   PLEASE THINK CAREFULLY WHICH IS THE FIND ORDER, if you
729   use your own function; use add-hook's 3rd parameter to
730   add your methods last in the hook.
731
732 Function call arguments:
733
734   string        usually email address(key id)
735
736 Function should return:
737
738   string        (filename) keyring where the key is available
739   nil"
740   :type  'hook
741   :group 'tinypgp-hook)
742
743 (defcustom tinypgp-:auto-action-encrypt-ok-hook  nil
744   "*Hook to determine if sending auto encrypted mail is ok.
745 This hook is called only if some recipent matches
746 `tinypgp-:auto-action-encrypt-regexp'
747
748 Function call arguments:
749
750   flag
751   list          list of To and Cc recipients.
752
753 Function should return:
754
755   boolean       non-nil says that encrypting is ok"
756   :type  'hook
757   :group 'tinypgp-hook)
758
759 ;;; ...................................................... &v-function ...
760 ;;; These are not in defcustom. Experts user know what to look
761 ;;; for from source code if they need to change these.
762
763 (defcustom tinypgp-:encrypt-after-function  'tinypgp-encrypt-add-remailer-tag
764   "Function run after the buffer is encrypted.
765 The default function `tinypgp-encrypt-add-remailer-tag' adds the
766 'Encrypted: PGP' tag to the beginning of encryopted block. It is needed
767 when the message is sent to remailer.
768
769 If you put your function inside this, be sure that you supply that tag
770 if you're writing message to remailer.
771
772   ::
773   Encrypted: PGP
774
775   -----BEGIN PGP MESSAGE-----
776   ...
777
778 Function call arguments:
779   none
780
781 Function should return:
782
783   none
784
785 Function call point
786
787   at the beginnning of message"
788   :type  'function
789   :group 'tinypgp-pgp)
790
791 (defcustom tinypgp-:filter-email-function 'tinypgp-mail-abbrevs-filter
792   "*Function to filter out unwanted mailabbrevs.
793 When making the completion list of email address out of the
794 mail-abbrev table, the obarray may contain some _old_, unwanted, or
795 invalid email addresses. Perhaps you just don't want to have all
796 email addresses for PGP encryption: that's what this filter
797 function is for.
798
799 Call arguments:
800
801   list      list of email addresses.
802
803 Return value:
804
805   list      list of valid email addresses.")
806   :type  'function
807   :group 'tinypgp-pgp
808
809 (defcustom tinypgp-:verify-message-function nil
810   "*Function called to print the verify status.
811 This function is called with one argument: STRING, when verify status
812 is displayed. For example; sometimes PGP could display
813
814     Good signature from user \"0f00bc000\".
815
816 Which isn't quite enlightling. By supplying your own function you
817 can check cases like this and convert the message into something
818 more meaningful.
819
820 Example:
821
822     (setq tinypgp-:verify-message-function 'my-tinypgp-verify-message)
823
824     (defun my-tinypgp-verify-message  (str)
825       \"Display more meaningful message\"
826       (let* ((pfx \"Good signature from: \"))
827         (cond
828          ((string-match \"0f00bc095\" str)
829           (setq str (concat pfx \"Foo Bar\"))))
830         (message str)))"
831   :type  'function
832   :group 'tinypgp-pgp)
833
834 (defcustom tinypgp-:pgp-encrypted-p-function 'tinypgp-pgp-encrypted-p-default
835   "*Function to return PGP data type for message.
836 When you call `tinypgp-decrypt-mail' interactively, the
837 PGP type is asked. However, you can automate the type checking if you
838 know the type of PGP data.
839
840 The default function `tinypgp-pgp-encrypted-p-default' check the CTB bits
841 and return correct type.
842
843 Function arguments:
844
845   none
846
847 Function should return:
848
849   string        'pgp', 'base64', 'conventional' or nil"
850   :type  'function
851   :group 'tinypgp-pgp)
852
853 (defcustom tinypgp-:pgp-decrypt-arg-function
854   'tinypgp-decrypt-arg-function
855   "*How to Honour variable `tinypgp-:decrypt-arg-interpretation'.
856 The default function `tinypgp-decrypt-arg-function' treats writable and read
857 only buffers differently."
858   :type  'function
859   :group 'tinypgp-pgp)
860
861 (defcustom tinypgp-:pgp-command-compose-function nil
862   "*Hook to run after pgp executable command has been composed.
863 If this hook doesn't modify the command, it should return CMD untouched.
864
865 function args:
866
867   cmd      string
868
869 Should return:
870
871   cmd      string"
872   :type  'function
873   :group 'tinypgp-pgp)
874
875 (defcustom tinypgp-:secring-crypt-function 'tinypgp-crypt-do-with-pgp
876   "*Function to crypt the secring.
877
878 Default values available:
879
880   'tinypgp-crypt-do-with-pgp
881   'tinypgp-crypt-do-with-crypt   ;; not recommended
882
883 Function args:
884
885   from          source file
886   to            destination file
887   password      TO crypted by using this
888
889 Notes
890
891   Function should detect by looking FROM file if it is already
892   in encrypted format and convert it to back to regular file.
893   Kinda flip-flop. It should also signal error and terminate if
894   wrong password were used for opening the file (that is, if it
895   is possible to determine that condition)"
896   :type  'function
897   :group 'tinypgp-pgp)
898
899 (defcustom tinypgp-:encrypt-with-function nil
900   "*When message is encrypted, this function return additional keyIds.
901
902 For example if you want to encrypt all messages to yourself but only
903 when they are not sent to remailers, then you could use this setup.
904 All messages would be then readable by you also.
905
906   (setq tinypgp-:encrypt-with-function  'my-tinypgp-encrypt-with)
907
908   (defun my-tinypgp-encrypt-with ()
909      (unless (ti::re-search-check \"remail\")
910         ;;  Or your explicit PGP keyID if the name is not unique enough
911         (list tinypgp-:user-primary)))
912
913 Function args:
914
915  none
916
917 Should return:
918
919   list of additional keyIds (strings) used in encryption or nil."
920   :type  'function
921   :group 'tinypgp-pgp)
922
923 ;;; .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. ..  remailer . .
924
925 (defcustom tinypgp-:r-post-before-hook nil
926   "*Hook run before post is converted into Anon format."
927   :type  'hook
928   :group 'tinypgp-remail-hook)
929
930 (defcustom tinypgp-:r-post-after-hook nil
931   "*Hook run after post is converted into Anon format."
932   :type 'hook
933   :group 'tinypgp-remail-hook)
934
935 (defcustom tinypgp-:nymserver-post-hook nil
936   "*Hook run after `tinypgp-nymserver-post' function finishes."
937   :type  'hook
938   :group 'tinypgp-nymserver)
939
940 (defcustom tinypgp-:r-init-hook nil
941   "*Hook run after the remailer support has been initialised.
942 See `tinypgp-r-init'."
943   :type  'hook
944   :group 'tinypgp-remail-hook)
945
946 (defcustom tinypgp-:r-get-list-hook nil
947   "*Hook run after the Levien list file is inserted into temporary buffer.
948 This is your chance to check and modify the Remailer Levien list.
949 See `tinypgp-r-get-list'."
950   :type  'hook
951   :group 'tinypgp-remail-hook)
952
953 ;;}}}
954 ;;{{{ setup: mode variables
955
956 ;;; .......................................................... &v-mode ...
957
958 (defvar tinypgp-mode nil
959   "Minor mode variable.")
960
961 (make-variable-buffer-local 'tinypgp-mode)
962
963 (defvar tinypgp-:mode-name nil
964   "Minor mode name.
965 This is not a user variable because the string is modified dynamically.")
966 (make-variable-buffer-local 'tinypgp-:mode-name)
967
968 (defcustom tinypgp-:mode-menu-name "TPgp"
969   "*Menu name for pgp mode."
970   :type 'string
971   :group 'tinypgp-mode-definitions)
972
973 (defvar tinypgp-:mode-map nil
974   "Minor mode map.")
975
976 (defvar tinypgp-:mode-menu nil
977   "Menu for mode.")
978
979 (defcustom tinypgp-:mode-prefix-key "\C-c/"
980   "*Key map prefix."
981   :type  '(string :tag "Key sequence")
982   :group 'tinypgp-mode-definitions)
983
984 ;;; ................................................ &v-key-management ...
985
986 (defvar tinypgp-key-mode nil
987   "Minor mode variable.")
988 (make-variable-buffer-local 'tinypgp-key-mode)
989
990 (defconst tinypgp-:key-mode-name nil
991   "Minor mode name.
992 This is not a user variable because the string is modified dynamically.")
993 (make-variable-buffer-local 'tinypgp-:key-mode-name)
994
995 (defvar tinypgp-:key-mode-map nil
996   "Minor mode map.")
997
998 (defvar tinypgp-:key-mode-menu nil
999   "Menu for mode.")
1000
1001 (defcustom tinypgp-:key-mode-menu-name "TPk"
1002   "*Menu name for pgp key mode."
1003   :type  'string
1004   :group 'tinypgp-mode-definitions)
1005
1006 (defcustom tinypgp-:key-mode-prefix-key "\C-c'"
1007   "*Key map prefix."
1008   :type  'string
1009   :group 'tinypgp-mode-definitions)
1010
1011 ;;; .................................................. &v-summary-mode ...
1012
1013 (defvar tinypgp-summary-mode nil
1014   "Minor mode variable.")
1015 (make-variable-buffer-local 'tinypgp-summary-mode)
1016
1017 (defconst tinypgp-:summary-mode-name nil
1018   "Minor mode name. Changed dynamically.")
1019 (make-variable-buffer-local 'tinypgp-:summary-mode-name)
1020
1021 (defvar tinypgp-:summary-mode-map nil
1022   "Minor mode map. \\[tinypgp-:summary-mode-map].")
1023
1024 (defvar tinypgp-:summary-mode-menu nil
1025   "Menu for mode.")
1026
1027 (defcustom tinypgp-:summary-mode-menu-name "TPsum"
1028   "*Menu name for mode."
1029   :type  'string
1030   :group 'tinypgp-mode-definitions)
1031
1032 (defcustom tinypgp-:summary-mode-prefix-key tinypgp-:mode-prefix-key
1033   "*Key map prefix."
1034   :type  'string
1035   :group 'tinypgp-mode-definitions)
1036
1037 ;;; ................................................... &v-newnym-mode ...
1038
1039 (defvar tinypgp-newnym-mode nil
1040   "Minor mode variable.")
1041 (make-variable-buffer-local 'tinypgp-newnym-mode)
1042
1043 (defvar tinypgp-:newnym-mode-name " Nym"
1044   "Minor mode name.")
1045 (make-variable-buffer-local 'tinypgp-:newnym-mode-name)
1046
1047 (defvar tinypgp-:newnym-mode-map nil
1048   "Minor mode map. \\[tinypgp-:newnym-mode-map].")
1049
1050 (defvar tinypgp-:newnym-mode-menu nil
1051   "Menu for mode.")
1052
1053 (defcustom tinypgp-:newnym-mode-menu-name "TPnym"
1054   "*Menu name for mode."
1055   :type  'string
1056   :group 'tinypgp-mode-definitions)
1057
1058 ;;  escreen.el uses same prefix; so change this if you use that package.
1059 ;;  Also the (enable-flow-control) takes over C-\ key.
1060 ;;
1061 (defcustom tinypgp-:newnym-mode-prefix-key "\C-\\"
1062   "*Key map prefix."
1063   :type  'string
1064   :group 'tinypgp-mode-definitions)
1065
1066 ;;; ................................................. &v-mode-remailer ...
1067
1068 ;;  In HP the keys "/." are next to each other on the lower right
1069 ;;  near RET key
1070 ;;
1071 (defcustom tinypgp-:mode-prefix-key-remailer "\C-c/.r"
1072   "*Key map prefix for remailer commands."
1073   :type  'string
1074   :group 'tinypgp-mode-definitions)
1075
1076 (defcustom tinypgp-:mode-prefix-key-newnym "\C-c/.n"
1077   "*Keymap prefix for newnym type anon server commands.
1078 The default prefix key is C - c / . n; where p refers to (n)ewnym
1079 account; similar to famous nym.alias.net"
1080   :type  'string
1081   :group 'tinypgp-mode-definitions)
1082
1083 (defcustom tinypgp-:mode-prefix-key-nymserver "\C-c/.y"
1084   "*Keymap prefix for nymserver type anon server commands.
1085 The default prefix key is C - c / . y; where p refers to n(y)mserver
1086 account; similar to ex-anon.penet.fi.
1087
1088 As of writing this,  the only active remailer that resembles 'penet' is
1089 anon.nymserver.com"
1090   :type  'string
1091   :group 'tinypgp-mode-definitions)
1092
1093 ;;}}}
1094 ;;{{{ setup: user config
1095
1096 ;;; ........................................................ &v-config ...
1097 ;;; PGP executable settings
1098
1099 (defvar tinypgp-:pgp-binary-interactive-option
1100   (if (ti::win32-p)
1101       nil
1102     '(format "+comment=\"Processed by Emacs TinyPgp %s\""
1103              (tinypgp-version-number)))
1104   "*Extra encrypt option passed to PGP; use only \"+comment=\\\"\\\"\".
1105 This variable is EVALUATED; so it can contain lisp FORM.
1106 Must be nil in PCP platform.")
1107
1108 ;;   See tinypgp-binary-header-field-fix
1109
1110 (put 'tinypgp-:pgp-binary-interactive-option
1111      'comment
1112      (format "Processed by %sEmacs TinyPgp %s"
1113              (if (ti::win32-p) "WinNT " "")
1114              (tinypgp-version-number)))
1115
1116 (put 'tinypgp-:pgp-binary-interactive-option 'original
1117      tinypgp-:pgp-binary-interactive-option)
1118
1119 ;;; ....................................................... &v-pgp-exe ...
1120
1121 ;;  This variable also has property
1122 ;;  'crypt          The absolute path for 'crypt'.
1123 ;;
1124 ;;  In variable tinypgp-:hash you find following properties
1125 ;;  Note: this is not in the hash table itself, but in symbol's plist,
1126 ;;  because hash table is resetted in regular intervals.
1127 ;;
1128 ;;  'secring-passwd
1129 ;;  'secring        The whole secring.pgp
1130 ;;
1131 (defvar tinypgp-:pgp-binary nil
1132   "Property list of PGP executables.
1133 The value of variable is always nil (not used). Property list values are:
1134
1135   'version      string, PGP version number
1136
1137   'ppg2         symbol 'ok if found
1138   'ppg2-type    symbol 'unix or 'win32
1139
1140   'pgp5         symbol 'ok if found
1141   'ppg5-type    symbol 'unix or 'win32
1142
1143   'gpg
1144   'gpg-type     symbol 'unix or 'win32
1145
1146   'pgp          string, pgp 2.6.x executable path
1147
1148   'pgp{koves}   string, pgp 5 executable paths
1149
1150   'pgp-now      symbol 'pgp2, 'pgp5, `gpg;
1151                 What pgp version is used currently
1152   'pgp-now-type 'unix 'win32
1153                 What kind of pgp version is in use: Unix/Cygwin or Win32")
1154
1155 (defconst tinypgp-:pgp-binary-support-table
1156   '( ;; will generate a file with the specified filename, containing <nnn>
1157     ;; random bytes, to allow other programs to benefit from PGP's
1158     ;; strong random-number generator.
1159
1160     (random  "+makerandom=")
1161
1162     ;;  This prints trust parameters
1163
1164     (trust   "-km"))
1165   "Support table of undocumented commands for your PGP binary.
1166 These commands are usually available in 2.6.3, but they just aren't
1167 include in PGP documentation.")
1168
1169 (defcustom tinypgp-:pgp-binary-charset "noconv"
1170   "*See PGP documentation.
1171 If you change this value, you have to reload tinypgp.el.
1172
1173 Possible choices according to Pgp 2.6.3ia manual:
1174
1175   noconv        No conversion  [prefer this]
1176   latin1        ISO 8859-1
1177   koi8          Eastern countries e.g. Russia
1178   cp850         ms-dos users in Europe"
1179
1180   :type '(choice
1181           (const "noconv")
1182           (const "latin1")
1183           (const "koi8")
1184           (const "cp850"))
1185   :group 'tinypgp-pgp)
1186
1187 (defvar tinypgp-:pgp-sh-exe
1188   (let (path-win32
1189         path-unix)
1190     (when (ti::win32-p)
1191       (or (setq path-win32 (executable-find "cmdproxy.exe"))
1192           (error "\
1193 TinyPgp: `tinypgp-:pgp-sh-exe' - cmdproxy.exe not in exec-path?")))
1194
1195     (when (and (null (setq path-unix (executable-find "sh")))
1196                (not (ti::win32-p)))
1197       (error "\
1198 TinyPgp: `tinypgp-:pgp-sh-exe' - /bin/sh not in exec-path?"))
1199     (list
1200      (list 'unix  (or path-unix "/bin/sh")
1201            (list 'win32 (or path-win32 "cmdproxy.exe")))))
1202
1203   "*Shell executables. Use absolute path names for greater speed.
1204
1205 '((win32  \"cmdproxy.exe\")
1206   (unix   \"/bin/sh\"))")
1207
1208 ;;; ......................................................... &v-files ...
1209
1210 ;;; Please do not add exension to these files!
1211 ;;; --> PGP itself adds extension if it needs to create any additional files.
1212 ;;;
1213 (defcustom tinypgp-:file-source
1214   (if (ti::win32-p)
1215       "c:/pgp-src"
1216     (tinypgp-path "pgp-src"))
1217   "*Source file fed to PGP. Region is written to this file.
1218 Must reside in C:/ root directory in PC platform due to total command
1219 length restrictions."
1220   :type  'file
1221   :group 'tinypgp-file)
1222
1223 (defcustom tinypgp-:file-output
1224   (if (ti::win32-p)
1225       "c:/pgp-out"
1226     (tinypgp-path "pgp-out"))
1227   "*Output file produced by PGP when it gets `tinypgp-:file-source'.
1228 Must reside in C:/ root directory in PC platform."
1229   :type  'file
1230   :group 'tinypgp-file)
1231
1232 (defcustom tinypgp-:file-password
1233   (if (ti::win32-p)
1234       "c:/pgp-pwd"
1235     (tinypgp-path "pgp-pwd"))
1236   "*File where to save the password only during calling PGP.
1237 The file is immediately deleted after PGP has finished.
1238 Must reside in C:/ root directory in PC platform due to total command
1239 length restrictions."
1240   :type  'file
1241   :group 'tinypgp-file)
1242
1243 (defcustom tinypgp-:file-user-list
1244   (if (ti::win32-p)
1245       "c:/pgp-lst"
1246     (tinypgp-path "pgp-lst"))
1247   "*File where to store user list. (e.g. when encrypting).
1248 Must reside in C:/ root directory in PC platform due to total command
1249 length restrictions."
1250   :type  'file
1251   :group 'tinypgp-file)
1252
1253 (defcustom tinypgp-:file-key-cache (tinypgp-path "tinypgp-cache")
1254   "*File where to store key cache."
1255   :type  'file
1256   :group 'tinypgp-file)
1257
1258 (defcustom tinypgp-:file-secring
1259   (list
1260    (cons 'pgp2 (tinypgp-path "secring.pgp"))
1261    (cons 'pgp5 (tinypgp-path "secring.skr"))
1262    (cons 'gpg  (tinypgp-path "secring.gpg"
1263                              (list
1264                               (getenv "GNUPGHOME")
1265                               "~/.gnupg"))))
1266   "*Secring path. If you change this you must reload TinyPgp.
1267 Format:
1268   '((pgp2 . \"/absolute/path/secring.pgp\")
1269     (pgp5 . \"/absolute/path/secring.skr\"))"
1270   :type  'file
1271   :group 'tinypgp-file)
1272
1273 (defcustom tinypgp-:file-secring-encrypted (tinypgp-path "secring.enc")
1274   "*Where to store the encrypted secring."
1275   :type  'file
1276   :group 'tinypgp-file)
1277
1278 ;;; .......................................................... &v-user ...
1279
1280 (defcustom tinypgp-:user-primary
1281   (or (car-safe (ti::mail-email-from-string user-mail-address))
1282       (error
1283        "\
1284 TinyPgp: tinypgp-:user-primary, Set user-mail-address to foo@site.com: '%s'"
1285        user-mail-address))
1286   "*Variable is used when you decrypt mail in buffer.
1287
1288 o  whatever your logical user id may
1289    be currently, it is changed to this
1290
1291 After decrypt has finished, the previous user identity is restored.
1292 This should provide smooth processing of incoming encrypted messages,
1293 while you may be doing something else."
1294   :type  'string
1295   :group 'tinypgp-mode)
1296
1297 (defcustom tinypgp-:user-identity-table nil
1298   "*When decrypting, this table is consulted for right active pgp user.
1299
1300 Format:
1301
1302   '((\"key-hex-id\"  \"key-id\")
1303     ...)
1304
1305 The encrypted PGP ascii armor is examined and if the found
1306 hex key-id match, then switch to key-i (usually mode descriptive
1307 email string) as a current PGP user.
1308
1309 Example:
1310
1311  (setq tinypgp-:user-identity-table
1312    '(
1313      ;;  My known public keyid firtsname.surname@site.com
1314      (\"12345670\"  \"firsname.surname\")
1315
1316      ;;  If I receive pgp message from nymserver, then use my
1317      ;;  nymserver user id
1318
1319      (\"12345678\"  \"an12345@anon.nymserver\")))"
1320   :type '(repeat
1321           (list
1322            (string :tag "Key-id (8 hex)"
1323                    (string :tag "Clear text User id"))))
1324   :group 'tinypgp-mode)
1325
1326 ;;; .......................................................... &v-misc ...
1327
1328 (defcustom tinypgp-:register ?/
1329   "*Register used to store the contents of PGP output."
1330   :type  'character
1331   :group 'tinypgp-mode)
1332
1333 (defcustom tinypgp-:password-protection
1334   (if (ti::win32-p)
1335       nil
1336     t)
1337   "*If this variable is non-nil, use extra caution to protect the password.
1338 Set this to t only if you're in UNIX system where
1339 the processes commands can be seen by running 'ps'. This variable
1340 prohibits using PGP's -z flag and forces using file descriptors
1341 which cannot be snooped so easily.
1342
1343 Set the variable to t only if your PGP understands env variable PGPPASSFD
1344 and that it can use many file descriptors.
1345
1346 In default WinNT this variable must be nil."
1347   :type  'boolean
1348   :group 'tinypgp-pgp)
1349
1350 (defcustom tinypgp-:password-keep-time (* 15 60) ;; 15 minutes default
1351   "*How many seconds to keep password in memory before forgetting it.
1352 Set to nil, if you want to be asked password every time when you sign
1353 a message."
1354   :type  'integer
1355   :group 'tinypgp-mode)
1356
1357 (defcustom tinypgp-:decrypt-arg-interpretation nil
1358   "*How to interpret prefix argument to `tinypgp-decrypt-mail' (interacive only).
1359 This variable is used _only_ if function is called interactively.
1360
1361 If non-nil
1362   then meaning of the prefix arg passed to function
1363   `tinypgp-decrypt-mail' is reversed.
1364
1365 If 'preview
1366   As in non-nil but also the the content of the decrypted message is
1367   displayed in a separate buffer"
1368   :type  'boolean
1369   :group 'tinypgp-mode)
1370
1371 (defcustom tinypgp-:finger-discard-by-regexp (user-login-name)
1372   "*When fingering email addresses, discard those that match regexp.
1373 Please look at variable `tinypgp-:finger-discard-email-hook' for more."
1374   :type  'regexp
1375   :group 'tinypgp-mode)
1376
1377 ;;; ........................................................ &v-labels ...
1378
1379 (defcustom tinypgp-:label-table
1380   '((v      ("v+" "v-"))
1381     (s      "s")
1382     (d      "d")
1383     (e      "e")
1384     (pgp    "pgp"))
1385   "*Labels to attach to messages.
1386 There are two ways to use labels in your mail agent. Here is one style,
1387 where a general label is attached first and then the short flags. The advantage
1388 of this is that you can summarise a) all 'pgp' labels b) summarise
1389 'pgp' labels _and_ decrypted messages 'd'. See TinyRmail.el That adds
1390 new command to RMAIL to do this kind of label _and_ operation.
1391
1392    pgp,v+       PGP message, verified
1393    pgp,v+,d     PGP message, verified and decrypted
1394    pgp,v-,d     PGP message, verify failed and decrypted
1395
1396 Or you could leave out the general label out and mark each pgp actions with
1397
1398   pgp+v
1399   pgp+v, pgp-d
1400   pgp-v, pgp-d
1401
1402 Choose your style, but remember that shortest labels are the best.
1403
1404 Format:
1405  '((v   (OK-VERIFY-LABEL NOK-VERIFY-LABEL)
1406    (s   SIGN-LABEL)
1407    (d   DECRYPT-LABEL
1408    (e   ENCRYPT-LABEL)
1409    (pgp PGP-GENERAL-LABEL)   << can be empty string or nil
1410    ))"
1411   :type '(list
1412           (list (const v :tag "verify") (list string string))
1413           (list (const s :tag "sign")    string)
1414           (list (const d :tag "decrypt") string)
1415           (list (const e :tag "encrypt") string)
1416           (list (const pgp :tag "pgp")   string))
1417   :group 'TinyPgp)
1418
1419 ;;; ................................................... &v-tables-misc ...
1420
1421 (defcustom tinypgp-:pubring-table
1422   (let* ((file2  (tinypgp-path "pubring.pgp"))
1423          (file5  (tinypgp-path "pubring.pkr"))
1424          (gpg    (tinypgp-path "pubring.gpg"
1425                                (list
1426                                 (getenv "GNUPGHOME")
1427                                 "~/.gnupg"))))
1428     (if (and (not (file-exists-p file2))
1429              (not (file-exists-p file5))
1430              (not (file-exists-p gpg)))
1431         (error "\
1432 TinyPgp: tinypgp-:pubring-table, Please configure, cannot auto-install.
1433 File pubring.pgp or pubring.pkr couldn't be found. Check PGPPATH."))
1434
1435     (list
1436      (list 'pgp2 (if file2
1437                      (list (list "default" file2 "-"))))
1438      (list 'pgp5 (if file5
1439                      (list (list "default" file5 "-"))))
1440      (list 'gpg (if gpg
1441                     (list (list "default" gpg "-"))))))
1442   "*Pubrings, alias names and mode line indicators.
1443
1444 Description:
1445
1446   Possible pubrings user can select. Make sure your primary
1447   pubring is first in the list and that the others come
1448   in order of importance. The last one is least unimportant
1449   keyring. When searching for key, this is the search order.
1450
1451 To remember:
1452
1453   Your primary pubring must be first.
1454
1455   Your merged keyring must be last. When you're encrypting to
1456   multiple people, pgp needs one big pubring which contains
1457   all keys for those people that your encrypting the message. When
1458   program sees that you have multiple CC, BCC or To recipients,
1459   it automatically sets the active pubring to the last one in this
1460   list.
1461
1462 Tip:
1463
1464   Please use some common convention when creating new pubring, e.g.
1465   use name \"pr-\" to denote pubring and add the descriptor after it.
1466   pr-elisp.pgp            ;; my pgp keys for my elisp mates
1467   pr-news.pgp             ;; occasional users from newsgroups
1468   pr-pgpnews.pgp          ;; the pgp newsgroup people pubring
1469   ...
1470   pr-temp.pgp             ;; temporary storage that I may discard any time
1471   pr-all.pgp              ;; Merged, pubring for all. maybe keyserver ring.
1472
1473 Format:
1474
1475   '((BACKEND
1476      (COMPLETION-STRING PUBRING-FILE MODE-STRING) (COMP PUB-F MODE-S)
1477       ..)
1478     (BACKEND
1479      (COMPLETION-STRING PUBRING-FILE MODE-STRING) (COMP PUB-F MODE-S)
1480       ..))
1481
1482   BACKEND is either 'pgp2 or 'pgp5
1483
1484   COMPLETION-STRING is 'nice name' for the pubring.
1485
1486   PUBRING-FILE is the absolute filename where pubring resides.
1487
1488   MODE-STRING is displayed in the mode line to show which pubring
1489   you have active. Please choose some non-word character to give
1490   you enough visible hint which pubring you use currently. Eg.
1491
1492     -      default
1493     =      secondary
1494     *      special, whole keyserver pubring."
1495
1496   :type '(repeat
1497           (list
1498            (string :tag "Pubring completion name")
1499            (file   :tag "Pubring filename")
1500            (string :tag "String, One character modeline indicator")))
1501   :group 'tinypgp-mode)
1502
1503 (defcustom tinypgp-:header-sign-table
1504   ;;  Always use these fields
1505   '(("@" ("subject" "reply-to" )))
1506   "*List of headers that should be signed along with the message.
1507
1508 Format:
1509
1510  '((REGEXP '(HEADER-NAME-STRING HEADER-NAME-STRING ..) [NO-XPGP-MODE])
1511    ...)
1512
1513 Example:
1514
1515 Definition of fields:
1516
1517 REGEXP        If matches To-field or Newsgroup-field, the HEADER-LIST is used.
1518               You should not sign reply-to field if the destination
1519               address changes the field contents. Many times mailing
1520               list do this.
1521 HEADER-LIST   If it is empty, no headers are included in signing.
1522 NO-XPGP-MODE  This field is optional. If it is non-nil, then when you
1523               do signing, this flag is consulted. If the to-field matches
1524               the no X-Pgp signing is done, no matter what the
1525               `tinypgp-:xpgp-signing-mode' says currently. In some cases
1526               you can't send X-pgp signed messages to the destination
1527               address.
1528
1529 References:
1530
1531   `tinypgp-:xpgp-signing-mode'"
1532   :type '(repeat
1533           (list
1534            (regexp :tag "Regexp matching To/Newsgroups")
1535            (repeat (string :tag "Header field to be signed"))))
1536   :group 'tinypgp-header)
1537
1538 (defcustom tinypgp-:keyserver-mail-table
1539   '(
1540     ;; official
1541     ("pgp"                  "pgp-public-keys@keys.pgp.net")
1542
1543     ;; 1998-03 http://www.prairienet.org/~jalicqui/pgpfaq.txt
1544     ("uk"  "pgp-public-keys@keys.uk.pgp.net")
1545     ("de"  "pgp-public-keys@keys.de.pgp.net")
1546     ("no"  "pgp-public-keys@keys.no.pgp.net")
1547     ("us"  "pgp-public-keys@keys.us.pgp.net")
1548     ("nl"  "pgp-public-keys@keys.nl.pgp.net")
1549     ("fi"  "pgp-public-keys@keys.fi.pgp.net")
1550     ("es"  "pgp-public-keys@keys.es.pgp.net")
1551     ("hr"  "pgp-public-keys@keys.hr.pgp.net")
1552     ("tw"  "pgp-public-keys@keys.tw.pgp.net")
1553     ("pl"  "pgp-public-keys@keys.pl.pgp.net")
1554     ("au"  "pgp-public-keys@keys.au.pgp.net"))
1555   "*List of available Email keyservers.
1556 See PGP faq \"8.2. What public key servers...\" for updated list.
1557 http://www.pgp.net/mail-help/email-help-en.html
1558
1559 Format:
1560  '((COMPLETION-NAME EMAIL-ADDRESS))
1561    (COMP-N EMAIL-A)
1562    ..)"
1563   :link '(url-link :tag "PGP keyservers"
1564                    "http://www.pgp.net/mail-help/email-help-en.html")
1565   :type '(repeat (list string string))
1566   :group 'tinypgp-interface)
1567
1568 ;;  http://geronimo.uit.no/pgp/servruit.eng.html
1569 ;;  http://www-swiss.ai.mit.edu/~bal/bal-home.html
1570 ;;
1571 (defcustom tinypgp-:keyserver-http-table
1572   '(
1573
1574     ;; Maintainer: <grobi@uni-paderborn.de>
1575     ;; http://math-www.uni-paderborn.de/pgp/
1576
1577     ("wwwkeys.pgp.net:11371"
1578      "/pks/lookup?op=get&search=%s")
1579
1580     ;;  Hm, this is nowadays PGP 5 keyserver
1581
1582     ("pgp.ai.mit.edu"
1583      "/htbin/pks-extract-key.pl?op=get&search=%s")
1584
1585     ("goliat.upc.es:1137" ;; <marc@mit.edu>
1586      "/pks/lookup?op=index&search=%s"))
1587   "*List of available http keyservers.
1588 Be sure that you put your nearest/fastest keyserver first in the list.
1589 It is offered as default connection.
1590
1591 Format:
1592
1593   '((KEYSERVER COMMAND)
1594     (KEYSERVER COMMAND)
1595     ...)"
1596   :type  '(repeat (list string string))
1597   :group 'tinypgp-interface)
1598
1599 ;;; ................................................... &v-auto-action ...
1600
1601 (defcustom tinypgp-:sign-mail-p-function nil
1602   "*Function to decide if message should be signed.
1603 Auto signing mode is active when function is called.
1604 See `tinypgp-sign-mail-auto-mode'.
1605
1606 Function return values:
1607
1608   t     Yes, sign this mail
1609   nil   Ignore signing for this message
1610
1611 Example:
1612
1613   ;;  Do not sign messages that are sent to my fellow
1614   ;;  workers at domain 'foo'. Ie. sign messages to the outside
1615   ;;  world.
1616
1617   (setq tinypgp-:sign-mail-p-function
1618     '(lambda ()
1619        (not (string-match \"foo\" (or (mail-fetch-field \"to\") \"\")))))"
1620   :type  'sexp
1621   :group 'tinypgp-mode)
1622
1623 (defcustom tinypgp-:auto-action-encrypt-regexp nil
1624   "*Bulk encryption regexp to match all members in To, CC, BCC.
1625 This is special auto action variable and it is used only if
1626 there is more than _one_ address where you're sending a message.
1627 Typical situation: You want to send encrypted mail to Cc'd
1628 members who also have pgp.
1629
1630 The regexp s matched individually against each member in To, Cc and Bcc
1631 fields. If regexp didn't match for each member, then the auto encryption
1632 is not engaged.
1633
1634 You must know for sure who have pgp and those people's keys must
1635 be stored in big pubring 'all'. (see `tinypgp-:pubring-table')"
1636   :type  'regexp
1637   :group 'tinypgp-mode)
1638
1639 (defcustom tinypgp-:auto-action-table nil
1640   "*Automatic encrypt and sign control table.
1641 When there is only _one_ email destination (no CC, BCC and one entry in To)
1642
1643 Alternative way, see also:
1644   `tinypgp-:bbdb-field'
1645   Note: `tinypgp-:auto-action-table' overrides BBDB
1646
1647 Format:
1648
1649  '((EVAL-OR-REGEXP  [SIGN-KEY-ID] [ENCRYPT] [MIME] [XPGP] [KEYRING])
1650    ..)
1651
1652 Example:
1653
1654  ;;  To automatically send PGP/MIME encrypted messages to
1655  ;;  foo and bar, signed by you:
1656
1657  '((\"foo@bar.com\" 'my-pgp-key-id@site.com 'encrypt 'mime)
1658    (\"bar@bar.com\" 'my-pgp-key-id@site.com 'encrypt 'mime))
1659
1660 Definition of fields:
1661
1662   EVAL-OR-REGEXP: string or lisp list
1663   Regexp means matching on To field contents.
1664   *Note* To field must have address including @ character otherwise no
1665   comparison is done.
1666
1667   If you use EVAL, then you can refer to variable 'to-field' in the
1668   form that builds up eval. You can also search the buffer for specific
1669   strings before determining if the actions defined should be
1670   engaged.
1671
1672   SIGN-KEY-ID: string or symbol
1673   If this contains string key-id, that is used to sign the message. If
1674   value is SYMBOL instead of string _and_ the ENCRYPT is non-nil, then the
1675   result is 'one pass' encrypt and sign and not a separate encrypt + sign.
1676
1677   ENCRYPT: boolean
1678   If non-nil, the message is encrypted according to TO field content.
1679   See also `tinypgp-:email-substitution-table' if you want to encrypt
1680   using some other key.
1681
1682   MIME: symbol
1683   nil    use Regular pgp
1684   'mime  use PGP/MIME interface with TM or SEMI if mime interface is present.
1685
1686   XPGP: boolean
1687   If non-nil means signing by using X-Pgp headers;
1688   if this is nil, then use regular signing. This overrides any existing mode.
1689
1690   KEYRING: string; absolute filename
1691   tells which file to use as pubring when doing the encryption/signing.
1692   It defaults to current keyring in use.
1693
1694   The following example demonstrates EVAL-use of this variable, there are
1695   three entries in this list.
1696
1697   o   If newsgroup field is found from the message and
1698       it matches to pgp groups, then sign every mail.
1699   o   if to-field matches person foo@site.com, then the mail
1700       is encrypted and signed. (in this order)
1701   o   If message is sent somewhere else than my current domain,
1702       sign it.
1703
1704   (setq tinypgp-:auto-action-table
1705     '(
1706       ;;  elt 1
1707       ((let ((grp  (mail-fetch-field \"Newsgroups\")))
1708                     ((string-match \"pgp\" (or grp \"\"))))
1709         \"me@foo\")
1710
1711       ;; elt 2
1712       (\"foo@site.com\" \"me@foo\" 'enc)
1713
1714       ;; elt 3
1715       ((not (string-match \"@mysite.com\" to-field))
1716        \"me@foo\")))
1717
1718 Note 1:
1719
1720   If message _already_ contains some Pgp data (signed; encrypted)
1721   this variable is not used, because it's supposed that the user is
1722   controlling the layout of PGP message.
1723
1724 Note 2:
1725
1726   This variable is used only if you send message to _one_
1727   destination. If any CC or BCC is found from the message or if To:
1728   field contains comma, then this variable is not used.
1729
1730 Note 3:
1731
1732   All mode settings are overridden. Toggling modes on/off do not
1733   affect auto-action command.
1734
1735 Note 4:
1736
1737   The order of regexp elements is important: first one matched is used
1738   and the rest of the list is forgotten."
1739
1740   :type  '(repeat
1741            (list
1742             (sexp       :tag "To field regexp")
1743             (boolean    :tag "Sign flag")
1744             (boolean    :tag "X-pgp flag")
1745             (file       :tag "Keyring file used:")))
1746   :group 'tinypgp-mode)
1747
1748 ;;}}}
1749 ;;{{{ setup: header
1750
1751 ;;; ........................................................ &v-header ...
1752
1753 (defcustom tinypgp-:xpgp-signing-mode nil
1754   "*Non-nil if X-Pgp signing is used.
1755
1756 References:
1757   `tinypgp-:header-sign-table'   ,this overrides `tinypgp-:xpgp-signing-mode'
1758
1759 See \\[tinypgp-xpgp-header-mode-toggle]"
1760   :type  'boolean
1761   :group 'tinypgp-header)
1762
1763 (defcustom tinypgp-:xpgp-user-info
1764   '(format "Comment= \"Processed by Emacs TinyPgp.el %s\""
1765            (tinypgp-version-number))
1766   "*Additional information added to X-Pgp header.
1767 Set this variable to STRING-OR-EVAL-FORM that you wish to include
1768 in X-Pgp. The correct keywords are defined in X-Pgp standard.
1769 ftp://cs.uta.fi/pub/ssjaaa/pgp-xhd.html#additional_keywords:_telling_how_to
1770
1771 Notes:
1772
1773   DO NOT put newline code at the end of string.
1774   Put 2 spaces before each statement line (except first line).
1775   Every keyword must end to semicolon!
1776   Enclose strings in double quotes.
1777
1778 Full Example:
1779
1780   (setq tinypgp-:xpgp-user-info
1781    '(concat
1782      \"  Fingerprint=\\\"12 92 9C E4 60 DF 62 CD FC AD 18 47 9A 74 E7 D1\\\";\\n\"
1783      \"  Length=1024; Id=0x17D57681;\"
1784      \"  Access-type=Finger; Address=foo@site.com;\\n\"
1785      (format \"  Comment=\\\"Processed by Emacs TinyPgp.el %s\\\";\"
1786             (tinypgp-version-number))))
1787
1788 Recommended Example (only essential keywords):
1789
1790   (setq tinypgp-:xpgp-user-info
1791    '(concat
1792      \" Id=0x17D57681; Access-type=Finger; Address=foo@site.com;\\n\"
1793      (format \"  Comment=\\\"Processed by Emacs TinyPgp.el %s\\\";\"
1794             (tinypgp-version-number))))"
1795   :type  '(sexp :tag "String of Form")
1796   :group 'tinypgp-header)
1797
1798 ;;}}}
1799 ;;{{{ setup: remail private
1800
1801 ;;; ....................................................... &vp-remail ...
1802 ;;; Private
1803
1804 (defvar tinypgp-:r-levien-table nil
1805   "Updated by program. List of remailers and their properties.")
1806
1807 (defvar tinypgp-:r-host-table nil
1808   "Updated by program. List of accepted remailers and their properties.")
1809
1810 (defvar tinypgp-:r-history nil
1811   "History.")
1812
1813 ;; Raph's list is not always right. This variable is for experts only
1814 ;; and you should not touch it if you don't what you're doing.
1815 ;;
1816 (defconst tinypgp-:r-control-list nil
1817 ;;;  '(("replay"   ("ek"))                      ;does no support this
1818 ;;;    ("dustbin"  nil ("post"))                ;supports this
1819 ;;;    ("haystack" nil ("post"))                ;supports this
1820 ;;;    )
1821   "List of remailers and additional property control.
1822
1823 Format:
1824
1825   '((REMAILER (REMOVE-PLIST) (ADD-PLIST))
1826     (REMAILER ..))
1827
1828   For each remailer a property is either removed or added.
1829
1830 Example:
1831
1832   (setq tinypgp-:r-control-list
1833          ;; dustbin supported one day the property post.
1834         '((\"dustbin\" nil (\"post\"))))")
1835
1836 (defvar tinypgp-:r-mode-indication-flag nil
1837   "Non-nil means that current message should be treated with caution.
1838 Eg. if you encrypt the message, there will be no extra
1839 PGP 'Comment' keywords included that may reveal your identity.")
1840
1841 (make-variable-buffer-local 'tinypgp-:r-mode-indication-flag)
1842 (put 'tinypgp-:r-mode-indication-flag 'permanent-local t)
1843
1844 ;;}}}
1845 ;;{{{ setup: remail user config
1846
1847 ;;; ................................................... &v-remail-hook ...
1848
1849 (defcustom tinypgp-:r-post-before-hook '(tinypgp-r-post-before-default)
1850   "*Things to do before converting message to anonymous format.
1851 Turn off/exit all minor modes that may interfere the process."
1852   :type  'hook
1853   :group 'tinypgp-remail)
1854
1855 (defcustom tinypgp-:r-reply-block-basic-hook nil
1856   "*Hook that is run after reply block is added."
1857   :type  'hook
1858   :group 'tinypgp-remail-hook)
1859
1860 ;;; ........................................................ &v-remail ...
1861 ;;; User config
1862
1863 (defcustom tinypgp-:r-list-file
1864   (let ((file "~/.remailer.lst"))
1865
1866     ;;  Suppose we have low quota account; use .gz file if it exists.
1867     ;;  the regular file is not checked here: it is checked when
1868     ;;  user uses the remail functions.
1869
1870     (if (file-exists-p (concat file ".gz"))
1871         (concat file ".gz")
1872       file))
1873
1874   "*Remailer list file. See `tinypgp-r-update-remailer-list'."
1875   :type  'file
1876   :group 'tinypgp-remail)
1877
1878 (defcustom tinypgp-:r-user-mail-address user-mail-address
1879   "*Email address of your reply block.
1880 This account may be different from your regular email address."
1881   :type  'string
1882   :group 'tinypgp-remail)
1883
1884 ;;  1998-01  #finger also rlist@anon.lcs.mit.edu
1885 (defcustom tinypgp-:r-list-finger "remailer-list@kiwi.cs.berkeley.edu"
1886   "*Finger address where to get updated remailer list."
1887   :type  'string
1888   :group 'tinypgp-remail)
1889
1890 (defcustom tinypgp-:r-mail2news-remailer "replay"
1891   "*Remailer alias through which you want to send you Usenet posts.
1892 Variable is not a email address, but the remailer alias name according
1893 to Levien remailer list. This variable can contain lisp FORM.
1894
1895 Must support properties: POST PGP HASH CUTMARKS."
1896   :type  'string
1897   :group 'tinypgp-remail)
1898
1899 (defcustom tinypgp-:r-chain nil
1900   "*Remailer chain table. List of remailer.
1901 Only remailers that at least have properties PGP HASH EK are allowed.
1902
1903 Format:
1904
1905  '((COMPLETION-NAME
1906     [vector                 or (lisp-form-to-evaluate; must return vector)
1907      (REMAILER
1908       latent-time           this is optional
1909       encrypt-key)          this is optional
1910      (REMAILER
1911       ...)
1912      ])
1913     ...)
1914
1915 Examples:
1916
1917   (defconst tinypgp-:r-chain
1918     '((\"1-way\"     [(\"replay\" \"+0:05r\" \"ZepHyR1x\")])
1919       ;;  Select random path
1920       (\"hide\"      (progn (shuffle-vector [(\"replay\") (\"dustbin\")])))
1921       ;;  Use some reliable remailer, but hide identity better
1922       (\"milkyway\"  [\"replay\" \"replay\" \"replay\"])))"
1923   :type  'sexp
1924   :group 'tinypgp-remail)
1925
1926 (defcustom tinypgp-:r-subject-table
1927   '(" dummy"
1928     " This is a test"
1929     " ignore this message"
1930     " Regarding your previous message"
1931     " As for the www and html..."
1932     " Re: about the last subject..."
1933     " Re: Programming langueges.. ")
1934   "*List of dummy Subject sentences that are used in your Remailer message.
1935 The subject should be such that it doesn't draw your sysadm's attention."
1936   :type '(repeat (list string))
1937   :group 'tinypgp-remail)
1938
1939 (defcustom tinypgp-:r-reply-block-table nil
1940   "*Correct reply block for each remailer.
1941 Suggested filename could be ~/.r-dustbin for dustbin remailer.
1942 You can place anything after the last -----END PGP MESSAGE-----
1943 because the reply block is only read from `point-min' to this
1944 tag line and rest of the file is ignored.
1945
1946 File format:
1947
1948     ::
1949     Request-Remailing-To: remailer@replay.com
1950     Latent-Time: +0:00
1951
1952     ::
1953     Encrypted: PGP
1954
1955     -----BEGIN PGP MESSAGE-----
1956     Version: 2.6.3ia
1957
1958     hIkDPRWysueuweUBA+jLifdDpkCxcUYA
1959     ...
1960     -----END PGP MESSAGE-----
1961
1962     #
1963     # this is comment
1964     # this is another comment
1965     # end of file
1966
1967 Variable format:
1968
1969 '((REMAILER-ALIAS FILE)
1970   (R F)
1971   ..
1972   )"
1973   :type '(repeat
1974           (list
1975            (string :tag "Remailer alias")
1976            (file   :tag "Reply block File")))
1977   :group 'tinypgp-remail)
1978
1979 (defcustom tinypgp-:r-header-keep-list '("Gcc" "Fcc")
1980   "*In addition to strict RFC headers; keep these headers too.
1981 When you compose anon post, all the unnecessary headers will be
1982 killed so that your identity is not revealed by accident.
1983 This is list f headers that are preserved in addition to RFC headers.
1984 Please do not include colon or spaces.
1985
1986 Format:
1987   '(\"hdr1\" \"hdr2\" ..)"
1988   :type '(repeat string)
1989   :group 'tinypgp-remail)
1990
1991 ;;; ........................................................ &v-newnym ...
1992
1993 (defcustom tinypgp-:r-newnym-stamp-file-prefix
1994   (tinypgp-path "~/.emacs.tinypgp-stamp.")
1995   "*Newnym type accounts expire in 120 days.
1996 This file is touched every time user sends a newnym account
1997 request or remail. It is compared to current sate and a warning
1998 is issued after 100 days if user hasn't used the account.
1999
2000 The filenames are manfgled to protect reading the Newnym server and
2001 account information from them.
2002
2003 User must send `request' message to the account to keep it alive."
2004   :type  'file
2005   :group 'tinypgp-newnym)
2006
2007 (defcustom tinypgp-:r-newnym-default-account-table nil
2008   "*List of newnym servers and accounts you have.
2009 The active default server and login information are stored
2010 into properties 'default-server and 'default-account. If these properties
2011 are nil, then no default values are set.
2012
2013 Format:
2014   '((COMPLETION-NAME  NYM-SERVER NYM-ACCOUNT MODELINE-CHAR)
2015     (.. .. ..))
2016    Important: NYM-ACCOUNT must not have @site.suffix.com; only the account name
2017
2018 Example:
2019   '((\"weasel\" \"weasel\"  \"my-weasel-login-name\" \"W\")
2020     (\"nym\"    \"nym\"     \"my-nym-login-name\"    \"N\")
2021     (\"nym2\"   \"nym\"     \"my-nym-login-name2\"   \"N2\")
2022     (\"efga\"   \"efga\"    \"my-efga-login-name\"   \"E\"))"
2023   :type  '(repeat (list string string string))
2024   :group 'tinypgp-newnym)
2025
2026 (defcustom tinypgp-:r-newnym-mail2news-address
2027   "mail2news_nospam@anon.lcs.mit.edu"
2028   "*Email address through which the newsgroup posts are sent.
2029 This variable is evaled to get the email address.
2030
2031 Aug 13 1997 there was a list of gateways available at
2032 http://students.cs.byu.edu/~don/mail2news.html and the list below
2033 is copied from there.
2034
2035 Note:
2036
2037   The default value is mail2news_nospam@anon.lcs.mit.edu which creates
2038   headers like this:
2039
2040        From: Bogus Name <Use-Author-Address-Header@[127.1]>
2041        Author-Address: Name <AT> nym <DOT> alias <DOT> net
2042
2043   If you would use regular mail2news_nospam@anon.lcs.mit.edu; then your
2044   headers were as they would. But expect to get UCE mail through your newnym
2045   account as soon as you post to usenet.
2046
2047        From: Sam Bogus <name@nym.alias.net>  ????
2048
2049 Sites that scan headers:
2050
2051   mail2news@anon.lcs.mit.edu CONFIRMED Jun97
2052   mail2news@news.wsnet.com NOT FUNCTIONAL
2053
2054 Sites that parse the email address:
2055
2056   group.name.usenet@alpha.jpunix.com DO NOT USE
2057   m2n-YYYYMMDD-group.name+group.name@alpha.jpunix.com CONFIRMED Aug97
2058   post-group.name@newspost.zippo.com CONFIRMED Mar97
2059   group.name@news.cs.dal.ca PROBABLY NOT FUNCTIONAL
2060   no.group.name@news.uninett.no
2061     (uninett only reported to carry norwegian news) CONFIRMED Jul96
2062   group.name@news.uni-stuttgart.de CONFIRMED Mar97
2063   mail2news-YYYYMMDD-group.name+group.name@anon.lcs.mit.edu CONFIRMED Jul97
2064   group.name@myriad.alias.net CONFIRMED Jun97"
2065   :type  'string
2066   :group 'tinypgp-newnym)
2067
2068 (defcustom tinypgp-:r-newnym-help-file nil
2069   "*Remailer 'newnym' help file."
2070   :type  'file
2071   :group 'tinypgp-newnym)
2072
2073 (defconst tinypgp-:newnym-cmd-table
2074   '(("acksend"
2075      "per-message: automatic acknowledgment of successfully remailed message."
2076      "Default: -acksend")
2077     ("signsend"
2078      "per-message: automatic PGP signing of any outgoing mail."
2079      "Default: -signsend")
2080     ("cryptrecv"
2081      "automatic encryption with your nym's public key."
2082      "Default: +cryptrecv")
2083     ("fixedsize"
2084      "all messages padded to exactly the same size (roughly 10K)"
2085      "Default: -fixedsize")
2086     ("disable"
2087      "4 Megabytes per day disables account, notified if this happens."
2088      "Default: -disable. Re-enable account with -disable.")
2089     ("fingerkey"
2090      "Allow people to finger <yournym@weasel.owl.de> for you PGP key."
2091      "Default: -fingerkey")
2092     ("name"
2093      "\
2094 Describe text of nym >> From: YOUR-NAME-DESC-HERE <yournym@weasel.owl.de>"
2095      "Default: name=\"\". Example: name=\"Your Alias Name\"")
2096     ("create"
2097      "\
2098 Create fails if a nym exists. Use Create? for updating nym. (sign message)."
2099      "Example: create/create?")
2100     ("delete"
2101      "Deletes your alias and wipes your reply block. Acknowledged."
2102      "<no other options>")
2103     ("nobcc"
2104      "\
2105 Counce bcc, only  To, Cc, Resent-To, or Resent-Cc accepted. (SPAM protect)"
2106      "Default: -nobcc"))
2107   "Newnym command table.
2108 Format:
2109  '((COMMAND DESC cmd-example-or-default-value)
2110    (COMMAND DESC cmd-example-or-default-value)
2111    ..)")
2112
2113 ;;; ....................................................... &vp-remail ...
2114 ;;; Private variables.
2115
2116 (defvar tinypgp-:r-reply-block-cache nil
2117   "Reply block cache.
2118
2119 Format:
2120  '((BUFFER PGP-BEG PGP-END)
2121    (B P-B P-E)
2122    )")
2123
2124 ;;}}}
2125 ;;{{{ setup: Nymserver
2126
2127 ;;; ....................................................... &nymserver ...
2128
2129 (defcustom tinypgp-:nymserver-request-encrypt nil
2130   "*To send every command to 'nymserver' account in encrypted format.
2131 NOTE: You must have inserted the Server's PGP key into the keyring."
2132   :type  'boolean
2133   :group 'tinypgp-nymserver)
2134
2135 ;;;  Currently this is not user variable
2136 ;;;  There is only one nymserver type remailer currently active.
2137 ;;;
2138 (defconst tinypgp-:nymserver-table
2139   '(("nymserver"
2140      tinypgp-nymserver-create-1 "request@anon.nymserver.com"
2141      "anon@anon.nymserver.com"
2142      3))
2143   "Table of 'nymserver' type services.
2144 Format:
2145
2146   '((SERVER-ALIAS-STRING
2147      ACCOUNT-CREATE-FUNCTION
2148      ACCOUNT-CREATE-EMAIL-ADDRESS
2149      SERVER-EMAIL-POST-TO
2150      NEWSGROUP-POST-COUNT-LIMIT)
2151          (S A A S N )
2152     ..)")
2153
2154 ;;;  When you receive account creation confirmation; update
2155 ;;;  this variable immediately.
2156 ;;;
2157 (defcustom tinypgp-:nymserver-account-table nil
2158   "*Your nymserver account information table.
2159
2160 '((SERVER-ALIAS-STRING
2161    ACCOUNT-EMAIL
2162    ACCOUNT-PASSWORD
2163    [ACCOUNT-NICKNAME-STRING | nil ]
2164    [FROM-ADDRESS            | nil ]
2165    [HELP-FILE               | nil ]))
2166
2167 You get the slots ACCOUNT-EMAIL, ACCOUNT-PASSWORD when you order an
2168 account from the server. The ACCOUNT-NICKNAME-STRING can be nil,
2169 because nymserver also controls your Nickname. This overrides
2170 the server's value.
2171
2172 FROM-ADDRESS
2173
2174     is important. When you ordered account from nymserver, it
2175     allocates only your current address and handles only messages sent from
2176     that address.
2177
2178        aa@a.com  --> you ordered anon account here.
2179        bb@b.com  you have another normal account here
2180        cc@c.com  you have yet another normal account here
2181
2182     Suppose you want to post from account bb@b.com as anon. Can't
2183     do that because nymserver expects you to be only in aa@a.com, in the
2184     site where you initially ordered the anon account.
2185
2186     Now, if you set FROM-ADDRESS to aa@a.com, then the From-field is inserted
2187     into the message pretending that the mail is coming from aa@a.com and
2188     now you can use your Anon account from different sites.
2189
2190 HELP-FILE
2191
2192     If the E-mail message that contained the server manual which explains
2193     all its features. Store the mail to this file;
2194
2195 Example:
2196
2197  (defconst tinypgp-:nymserver-account-table
2198   '((\"nymserver\"
2199      \"an1111@anon.nymserver.com\"
2200      \"qF8asdd\"
2201      \"\"
2202      \"my.name@address.com\"
2203      \"~/txt/nymserver.hlp\"
2204      )))"
2205   :type '(list
2206           (const "nymserver" :tag "Server")
2207           (string :tag "Account email")
2208           (string :tag "Account ppassword")
2209
2210           ;; optional
2211           ;;
2212           (string :tag "nickname")
2213           (string :tag "From address")
2214           (file   :tag "Help file"))
2215   :group 'tinypgp-nymserver)
2216
2217 ;;}}}
2218
2219 ;;{{{ setup: private
2220
2221 ;;; ...................................................... &vp-private ...
2222
2223 (defvar tinypgp-:timer-elt nil
2224   "Timer process that e.g. expires passwords.")
2225
2226 (defvar tinypgp-:key-cache nil
2227   "Cache: '((key-id, pubring, public-key) (...)).")
2228
2229 (defvar tinypgp-:key-cache-last nil
2230   "Last accessed 'get element in cache. See function `tinypgp-key-cache'.
2231   (ORIGINAL-EMAIL (CACHE-KEY PUBRING ..))")
2232
2233 (defvar tinypgp-:return-value nil
2234   "Common return value between functions.
2235 This variable is used as a signal to TinyPgp when it has called
2236 some user function or hook. The usage is explained in
2237 the functions that use it. It will contain properties too.")
2238
2239 (defvar tinypgp-:buffer-tmp-shell "*tinypgp-shell-tmp*"
2240   "Temporary buffer.")
2241
2242 (defvar tinypgp-:buffer-tmp-finger " *tinypgp-finger-tmp*"
2243   "Temporary buffer.")
2244
2245 (defvar tinypgp-:buffer-tmp-copy " *tinypgp-copy-tmp*"
2246   "Temporary buffer.")
2247
2248 (defvar tinypgp-:buffer-tmp-article " *tinypgp-article*"
2249   "Temporary buffer.
2250 If user doesn't want to replace the contents of the
2251 buffer in mail-like modes, then the content is copied to
2252 this buffers first, so that any text properties or overlays can beremoved
2253 without invoking edit mode.")
2254
2255 (defvar tinypgp-:buffer-tmp-http " *tinypgp-http-tmp*"
2256   "Temporary buffer.")
2257
2258 (defvar tinypgp-:buffer-tmp-kring " *tinypgp-kring-tmp*"
2259   "Temporary buffer.")
2260
2261 (defvar tinypgp-:buffer-tmp-show " *tinypgp-show-tmp*"
2262   "Temporary buffer.")
2263
2264 (defvar tinypgp-:buffer-tmp-mail " *tinypgp-mail-tmp*"
2265   "Temporary mail buffer.")
2266
2267 (defvar tinypgp-:buffer-tmp " *tinypgp-tmp*"
2268   "Temporary buffer.")
2269
2270 (defvar tinypgp-:buffer-newnym "*mail-newnym*"
2271   "Newnym remailer mail buffer.")
2272
2273 (defvar tinypgp-:buffer-comint "tinypgp-comint"
2274   "Interactive comint buffer to talk with PGP.
2275 This buffer name will automatically have stars over the name.")
2276
2277 (defvar tinypgp-:buffer-view "*tinypgp-view*"
2278   "Interactive comint buffer to talk with PGP.
2279 This buffer name will automatically have stars over the name.")
2280
2281 (defvar tinypgp-:original-buffer nil
2282   "Original buffer storage. Set in macro `tinypgp-run-in-tmp-buffer'.")
2283
2284 (defvar tinypgp-:pgp-email-list nil
2285   "List of email addresses in ~/.emailrc.")
2286
2287 (defvar tinypgp-:pgp-email-abbrev-list nil
2288   "List of abbrevs and their expansions: '((\"abb\" . \"expa\") ..).")
2289
2290 (defvar tinypgp-:pgp-email-list-completions nil
2291   "Email assoc menu for completion. '((\"a@b.com\" . 1) ..)
2292 This variable is initialised to the contents of your
2293 ~/.mailrc file.")
2294
2295 (defvar tinypgp-:sign-data nil
2296   "Stored sign information for current message.
2297 Used for checking message tampering afterwards.
2298
2299 Format:
2300   number   ,message body length in characters.")
2301 (make-variable-buffer-local 'tinypgp-:sign-data)
2302 (put                        'tinypgp-:sign-data 'permanent-local t)
2303
2304 ;;; ....................................................... &vp-colors ...
2305
2306 (defvar tinypgp-:face-mark 'highlight
2307   "The face for text marking.")
2308
2309 (defvar tinypgp-:face-error 'bold
2310   "The face for pointing out errors.")
2311
2312 ;;; ...................................................... &vp-history ...
2313
2314 (defvar tinypgp-:history-key-info nil
2315   "History of used key info strings.")
2316
2317 (defvar tinypgp-:history-email nil
2318   "User email history.")
2319
2320 (defvar tinypgp-:history-newnym-account nil
2321   "Nym account name history.")
2322
2323 (defvar tinypgp-:history-r-chain nil
2324   "Remailer chain selection history.")
2325
2326 (defvar tinypgp-:history-r-chain nil
2327   "Remailer chain selection history.")
2328
2329 (defvar tinypgp-:history-http-keyserver nil
2330   "History of used key servers.")
2331
2332 (defvar tinypgp-:history-http-keyserver-string nil
2333   "History of used key server search strings.")
2334
2335 ;;; ..................................................... &vp-commands ...
2336
2337 (defconst tinypgp-:pgp-command-options
2338   (let* ((charset (ti::string-remove-whitespace
2339                    (if (ti::nil-p tinypgp-:pgp-binary-charset)
2340                        "noconv"
2341                      tinypgp-:pgp-binary-charset)))
2342          (secring (cdr (assq 'pgp2 tinypgp-:file-secring))))
2343     (concat
2344
2345      ;;  These options are best to left out from the commands in WinNT.
2346      ;;  The maximum command line parameter length is 255 or was it 180 ?
2347      ;;
2348      ;;  The PGP compress ratio is like 1,6M text --> 600k
2349
2350      (if (ti::win32-p)
2351          ""
2352        (concat
2353         (if secring
2354             (concat " +secring=" secring)
2355           "")
2356         " "
2357         " +nomanual"
2358         " +showpass=off"                ;There is no cmd line arg
2359         " +encrypttoself=off"
2360
2361         " +verbose=1"
2362         " +language=en"                 ;don't use language modules
2363         " +armorlines=0"                ;No separate UU chunks
2364         " +charset=" charset
2365         " "))
2366      ""))
2367   "Default 2.6.x options for every pgp command.
2368 Notice that in PC platform there may be restrictions.")
2369
2370 ;; #todo: tinypgp-:pgp-command-options5 for Unix?
2371
2372 (defconst tinypgp-:pgp-command-options5
2373   (let* ((charset (ti::string-remove-whitespace
2374                    (if (ti::nil-p tinypgp-:pgp-binary-charset)
2375                        "noconv"
2376                      tinypgp-:pgp-binary-charset))))
2377 ;;;      (secring (cdr (assq 'pgp5 tinypgp-:file-secring)))
2378
2379     (if (ti::win32-p)
2380         ""
2381       (concat
2382        " +headers"
2383        " +encrypttoself=off "
2384        " +compress=on "
2385        " +language=en "                 ;don't use language modules
2386        " +armorlines=0 "                ;No separate UU chunks
2387
2388        ;; " WarnOnMixRSADiffieHellman=on "
2389        ;; " WarnOnRSARecipAndNonRSASigner=on "
2390
2391        ;; batchmode; You must not add this to the switches, because
2392        ;; then PGP 5.x won't ask for pass phrase, but expects to get
2393        ;; it from PGPPASSFD. We don't use PGPASSFD in Unix, but the expect.el
2394        ;; will feed the pass phrase to the prompt.
2395        ;;
2396        ;; " +batchmode=1"
2397        ;;
2398        ;; " -v "   ;; Verbose mode
2399
2400        " +charset=" charset
2401        " ")))
2402   "Default 5.x options for every pgp command.
2403 Notice that in PC platform there may be restrictions.")
2404
2405 (defconst tinypgp-:gpg-command-table
2406   (let* ((common2 tinypgp-:pgp-command-options) ;Without batch mode
2407          (common
2408           (concat
2409            common2
2410            " --batch "
2411            " "))
2412          (passwd-scheme
2413           (concat
2414            " echo #password #bin "
2415            common
2416            " --passphrase-fd 0 ")))
2417
2418     (list
2419      ;; Encrypt and output ascii #todo
2420      (list
2421       'encrypt-info
2422       (concat common " -f -u xx_test -z xx_test #SOURCE-FILE"))
2423
2424      (list
2425       'encrypt
2426       ;; Multiple users
2427       (concat passwd-scheme
2428               " #OUT-FILE -e -a #MUSER #SOURCE-FILE  "))
2429
2430      (list
2431       'encrypt-sign
2432       (concat common
2433               " --textmode --sign -e -a #MUSER #PGP-USER #password"))
2434
2435      (list
2436       'decrypt
2437       (concat passwd-scheme " #OUT-FILE --decrypt #USER #SOURCE-FILE "))
2438
2439      (list
2440       'decrypt-base64
2441       (concat (concat common " -f  ")))
2442
2443      (list
2444       'crypt
2445       (concat common2 " -a -c "))
2446
2447      (list
2448       'sign
2449       (concat
2450        passwd-scheme
2451        " #OUT-FILE --textmode --clearsign  -a #USER #SOURCE-FILE "))
2452
2453      (list
2454       'sign-detach
2455       (concat common " -bsatf #USER #password "))
2456
2457      (list
2458       'verify
2459       (concat common " --verify "))
2460
2461      (list
2462       'key-get
2463       (concat common " -kaf "))
2464
2465      (list
2466       'key-info
2467       (concat common "  -kvc "))
2468
2469      (list
2470       'key-add
2471       (concat common "  -fka "))
2472
2473      (list
2474       'key-extract
2475       (concat common "  -fkxa "))
2476
2477      (list
2478       'key-generate
2479       (concat common2 "  -kg "))
2480
2481      (list
2482       'key-delete
2483       (concat common " +force  -kr "))
2484
2485      (list
2486       'key-remove
2487       (concat common " +force  -kr "))
2488
2489      (list
2490       'key-sign-a
2491       (concat common " +force  #USER -ks "))
2492
2493      (list
2494       'key-sign-b
2495       (concat common " +force  #USER -krs "))))
2496   "GPG 1.0.4 command table.")
2497
2498 (defconst tinypgp-:pgp-command-table
2499   (let* ((common2 tinypgp-:pgp-command-options) ;Without batch mode
2500          (common
2501           (concat
2502            common2
2503            " +batchmode "
2504            " ")))
2505
2506     ;;  To use a Unix-style filter  mode,  reading  from  standard
2507     ;;  input and writing to standard output, use -f option
2508
2509     ;;  converted to recipient's local text
2510     ;;  line conventions,  add  the  -t  (text)
2511
2512     (list
2513      ;; Encrypt and output ascii ascii
2514      (list
2515       'encrypt-info
2516       (concat common " #PUBRING -f -u xx_test -z xx_test #SOURCE-FILE"))
2517
2518      (list
2519       'encrypt
2520       ;; Multiple users
2521       (concat common " #PUBRING -eatf #SOURCE-FILE #MUSER "))
2522
2523      (list
2524       'encrypt-sign
2525       (concat common " #PUBRING -eatfs #MUSER #PGP-USER #password"))
2526
2527      (list
2528       'decrypt
2529       (concat common " #PUBRING -f #password "))
2530
2531      (list
2532       'decrypt-base64
2533       (concat common " -f  "))
2534
2535      (list
2536       'crypt
2537       (concat common2 " -a -c "))
2538
2539      (list
2540       'sign
2541       (concat common " #PUBRING -satf #USER #password "))
2542
2543      (list
2544       'sign-detach
2545       (concat common " #PUBRING -bsatf #USER #password "))
2546
2547      (list
2548       'verify
2549       (concat common " #PUBRING -f "))
2550
2551      (list
2552       'key-get
2553       (concat common " #PUBRING -kaf "))
2554
2555      (list
2556       'key-info
2557       (concat common " #PUBRING -kvc "))
2558
2559      (list
2560       'key-add
2561       (concat common " #PUBRING -fka "))
2562
2563      (list
2564       'key-extract
2565       (concat common " #PUBRING -fkxa "))
2566
2567      (list
2568       'key-generate
2569       (concat common2 " #PUBRING -kg "))
2570
2571      (list
2572       'key-delete
2573       (concat common " +force #PUBRING -kr "))
2574
2575      (list
2576       'key-remove
2577       (concat common " +force #PUBRING -kr "))
2578
2579      (list
2580       'key-sign-a
2581       (concat common " +force #PUBRING #USER -ks "))
2582
2583      (list
2584       'key-sign-b
2585       (concat common " +force #PUBRING #USER -krs "))))
2586   "PGP 2.6.x command table.")
2587
2588 ;; #todo: #PUBRING is not in the switches.
2589 ;; #todo: I have no idea if these work in Unix
2590
2591 (defconst tinypgp-:pgp-command-table5
2592   (let* ((common tinypgp-:pgp-command-options5))
2593     (list
2594      ;; Encrypt and output ascii ascii
2595      (list
2596       'encrypt-info
2597       (concat common " -f -u xx_test -z xx_test #SOURCE-FILE"))
2598
2599      (list
2600       'encrypt
2601       (concat common " -atf #OUT-FILE  #MUSER #SOURCE-FILE"))
2602
2603      (list
2604       'encrypt-sign
2605       (concat
2606        common
2607        " -atf -s #OUT-FILE #USER #MUSER #password #SOURCE-FILE "))
2608
2609      (list
2610       'decrypt
2611       (concat common " -f  #OUT-FILE  #password #SOURCE-FILE"))
2612
2613      (list
2614       'decrypt-base64
2615       (concat common " -f #OUT-FILE #SOURCE-FILE"))
2616
2617      (list
2618       'crypt
2619       (concat common " -a -c  #SOURCE-FILE"))
2620
2621      (list
2622       'sign
2623       (concat
2624        common
2625        " -atv #USER #password #OUT-FILE #SOURCE-FILE "))
2626
2627      (list
2628       'sign-detach
2629       (concat
2630        common
2631        " -b -atv #USER #password #OUT-FILE #SOURCE-FILE "))
2632
2633      (list
2634       'verify
2635       ;;  option -z requires pass phrase argument.
2636       ;;
2637       (concat common "  #OUT-FILE #SOURCE-FILE "))
2638
2639      (list
2640       'key-get
2641       (concat common " -kaf "))
2642
2643      (list
2644       'key-info
2645       (concat common " -ll "))
2646
2647      (list
2648       'key-add
2649       (concat common " -a "))
2650
2651      (list
2652       'key-extract
2653       (concat common " -xa "))
2654
2655      (list
2656       'key-generate
2657       (concat common " -g "))
2658
2659      (list
2660       'key-delete
2661       (concat common " -r "))
2662
2663      (list
2664       'key-remove
2665       (concat common " -kr "))
2666
2667      (list
2668       'key-sign-a
2669       (concat common " #USER -ks "))
2670
2671      (list
2672       'key-sign-b
2673       (concat common "#USER -krs "))))
2674   "PGP 5.0.x command table.")
2675
2676 (defconst tinypgp-:pgp-binary-exit-code-table
2677   '((pgp2 .
2678           (
2679            ;; Possible error exit codes - not all of these are used.  Note that
2680            ;; we don't use the ANSI EXIT_SUCCESS and EXIT_FAILURE.  To make
2681            ;; things easier for compilers which don't support enum we use
2682            ;; #defines
2683
2684            (0  'EXIT_OK "JumBoJumboMamboBaile")
2685            (1  'INVALID_FILE_ERROR)
2686            (2  'FILE_NOT_FOUND_ERROR)
2687            (3  'UNKNOWN_FILE_ERROR)
2688            (4  'NO_BATCH)
2689            (5  'BAD_ARG_ERROR)
2690            (6  'INTERRUPT)
2691            (7  'OUT_OF_MEM)
2692            ;; /* Keyring errors: Base value = 10 */
2693            (10 'KEYGEN_ERROR )
2694            (11 'NONEXIST_KEY_ERROR)
2695            (12 'KEYRING_ADD_ERROR)
2696            (13 'KEYRING_EXTRACT_ERROR)
2697            (14 'KEYRING_EDIT_ERROR)
2698            (15 'KEYRING_VIEW_ERROR)
2699            (16 'KEYRING_REMOVE_ERROR)
2700            (17 'KEYRING_CHECK_ERROR)
2701            (18 'KEY_SIGNATURE_ERROR)
2702            (19 'KEYSIG_REMOVE_ERROR)
2703            ;; /* Encode errors: Base value = 20 */
2704            (20 'SIGNATURE_ERROR)
2705            (21 'RSA_ENCR_ERROR)
2706            (22 'ENCR_ERROR)
2707            (23 'COMPRESS_ERROR)
2708            ;; /* Decode errors: Base value = 30
2709            (30 'SIGNATURE_CHECK_ERROR)
2710            (31 'RSA_DECR_ERROR)
2711            (32 'DECR_ERROR)
2712            (33 'DECOMPRESS_ERROR))))
2713   "Error codes of PGP versions.
2714 Format:
2715  '((PGP-VERSION-REGEXP .((EXIT-CODE ERROR-SYMBOL [ERROR-REGEXP] ..)))
2716    (P-V-R . ((EX ES ER) (EX ES ER) ..))))
2717
2718 If ERROR-REGEXP is not specified, then ERROR-SYMBO should be used to
2719 show the error to user.")
2720
2721 (defconst tinypgp-:pgp-binary-error-regexp
2722   (concat
2723    "Bad pass phrase"
2724    "\\|user ID is required"
2725    "\\|Unable to get terminal"
2726    "\\|Transport armor stripping failed"
2727    "\\|Encryption error"
2728    "\\|No such file or directory"
2729    "\\|Cannot find the public key"
2730    "\\|Output file.*already exists"
2731    "\\|You do not have the secret key needed to decrypt this file\\."
2732    "\\|We need to generate.*bits" ;; Can I handle this in the prg?
2733
2734    ;;  If you encrypt with multiple keys, then missing key is flagged
2735
2736    "\\|This user will not be able to decrypt this message"
2737
2738    "\\|Key matching userid.*not found in file"
2739    "\\|Key matching.*not found in file"
2740
2741 ;;; Signature validation....
2742 ;;;   "\\|Key matching expected Key ID.*not found in file"
2743
2744    "\\|Keyring extract error\\."
2745
2746    ;;  When removing keys...
2747
2748    "\\|Do you also want to remove it from.*[?]"
2749
2750    ;; When you try to verify detached sig file and say that some file
2751    ;; XXX holds sig (when it doesn't)
2752
2753    "\\|Error:.*is not a ciphertext, signature, or key file."
2754
2755    ;; Eg. From conventional crypt error
2756
2757    "\\|You need a pass phrase to decrypt this file"
2758
2759    ;;  PGP 5.x Error!  Unable to load string PRIVATE_KEY_MISSING.
2760
2761    "\\|Error!.*Unable to load string.")
2762   "All error messages from PGP executable.
2763 These are case sensitive sentences.")
2764
2765 (defconst tinypgp-:pgp-binary-error-regexp-quiet
2766   (concat
2767    "Bad pass phrase"
2768    "\\|Cannot find the public key"
2769    "\\|Key matching userid.*not found in file"
2770    "\\|Key matching.*not found in file")
2771   "List of errors that does not bring up the Shell Error buffer.
2772 The buffer contain the last PGP executable call.
2773 Consider these errors so familiar that you don't have to
2774 examine the shell error message better.")
2775
2776 (defvar tinypgp-:error nil
2777   "Last error message.")
2778
2779 (defvar tinypgp-:last-pgp-exe-command nil
2780   "Last command sent to PGP exe.")
2781
2782 ;;; .................................................... &vp-pass-hash ...
2783
2784 (defvar tinypgp-:hash-password (make-vector 127 0)
2785   "Stored passwords, expired periodically.")
2786
2787 ;;  Some variables must be stored locally, but some variables must
2788 ;;  be globally visible; becfause on error conditions the
2789 ;;  current buffer may have changed and in order to restore
2790 ;;  situation, we must do lookup from GLOBAL array, because we don't
2791 ;;  know any more what was the starting buffer.
2792 ;;
2793 (defvar tinypgp-:hash nil
2794   "General _local_  hash storage.")
2795 (make-variable-buffer-local 'tinypgp-:hash)
2796
2797 (defvar tinypgp-:hash-global nil
2798   "General _global_ hash storage.")
2799
2800 (defvar tinypgp-:secring-crypt-mode nil
2801   "If Non-nil, use encrypted secring.
2802 This is NOT A USER VARIABLE. Use \\[tinypgp-secring-crypt-mode-toggle]
2803 Variable's value should not be trusted at all; but instead set it
2804 by calling function `tinypgp-secring-crypt-mode-detect' and only
2805 then trusting the value.")
2806
2807 ;;; ......................................................... &vp-misc ...
2808
2809 (defvar tinypgp-:header-sign-smf-info nil
2810   "The header SMF data that was constructed is stored here.")
2811
2812 (defvar tinypgp-:pubring-now nil
2813   "Current pubring in use.
2814 This will be initialised in `tinypgp-backend-select'")
2815
2816 (defvar tinypgp-:user-now
2817   (let* ((em user-mail-address))
2818     (cond
2819      ((not (stringp em))
2820       (error "\
2821 TinyPgp: tinypgp-:user-now, user-mail-address is not str like foo@site.com"))
2822
2823      ;;  If you have <> in user-mail-address that messes up From
2824      ;;  field.
2825
2826      ((string-match "<.*@.*>" em)
2827       (error "\
2828 TinyPgp: tinypgp-:user-now, please remove <> from user-mail-address")))
2829     (car (ti::mail-email-from-string em)))
2830   "Current user.")
2831
2832 (defvar tinypgp-:last-network-error nil
2833   "Last finger call error text.")
2834
2835 ;;}}}
2836
2837 ;;; ########################################################### &Funcs ###
2838
2839 ;;{{{ Bug report
2840
2841 ;;; ........................................................... &debug ...
2842
2843 (defvar tinypgp-:debug-buffer-size 100000
2844   "The buffer size after which the debug buffer is emptied.
2845 If you don't see all the information, increase size.")
2846
2847 (defvar tinypgp-:debug t
2848   "*Debug flag.")
2849
2850 (defvar tinypgp-:debug-buffer "*tinypgp-debug*"
2851   "*Debug buffer.")
2852
2853 ;;; ----------------------------------------------------------------------
2854 ;;;
2855 (defmacro tinypgpd (&rest args)
2856   "Generate debug if debug is on and output ARGS."
2857   (`
2858    (when tinypgp-:debug
2859      (let* ( ;; write to package's private buffer.
2860             (ti:m-debug-buffer tinypgp-:debug-buffer))
2861        (save-match-data
2862          (ti::d!! (,@ args) "\n")
2863          ;;  don't let it grow without limit....
2864          (with-current-buffer ti:m-debug-buffer
2865            (if (and (integerp tinypgp-:debug-buffer-size)
2866                     (> (buffer-size) tinypgp-:debug-buffer-size))
2867                (erase-buffer))))))))
2868
2869 ;;; ----------------------------------------------------------------------
2870 ;;;
2871 (defun tinypgp-debug-buffer-clear ()
2872   "Clear the debug buffer."
2873   (interactive)
2874   (ti::temp-buffer tinypgp-:debug-buffer 'clear)
2875   (if (interactive-p)
2876       (message "TinyPgp: Debug buffer cleared.")))
2877
2878 ;;; ----------------------------------------------------------------------
2879 ;;;
2880 (defun tinypgp-password-wipe-buffer (&optional force)
2881   "Wipe password strings from buffer. This may not succeed if cache is empty.
2882 if passwords are not in cache any more this function is no-op.
2883
2884 If FORCE is non-nil ask interactively.
2885 If force is nil, then get the passwords from cache and
2886
2887 Normally getting passwords from cache is performed in `mail-send-hook'"
2888   (interactive (list (interactive-p)))
2889   (let ((fid  "tinypgp-password-wipe-buffer:")
2890         passwd
2891         serv-passwd)
2892
2893     (cond
2894      (force
2895       (setq passwd (tinypgp-password-set "\
2896 I need pass phrase to wipe out all references to it: "))
2897
2898       (setq
2899        serv-passwd (tinypgp-nymserver-password
2900                     (tinypgp-nymserver-ask
2901                      "Nymserver server you have used: "))))
2902      (t
2903       ;; is it there?
2904       (if (ti::vector-table-get tinypgp-:hash-password tinypgp-:user-now)
2905           (setq passwd (ti::vector-table-property
2906                         tinypgp-:hash-password tinypgp-:user-now 'password)))
2907       ;;
2908       ;;  Actually there may be multiple passwords if user has several PGP
2909       ;;  keys (common, if you use remailers)
2910       ;;
2911       ;; #todo: We don't know nymserver password, because it is not in hash
2912
2913       (mapatoms
2914        (function
2915         (lambda (x)
2916           (when x)))
2917        ;;  (ti::d! x)
2918        tinypgp-:hash-password)))
2919
2920     ;; finally, scramble any pass pharases, so that they are not sent
2921     ;; to Maintainer!
2922
2923     (ti::save-line-column-macro nil nil
2924       (when (stringp passwd)
2925         (ti::mail-hmax 'move)
2926         (replace-string passwd "#PASSWD-WAS-HERE"))
2927
2928       (when (stringp serv-passwd)
2929         (ti::mail-hmax 'move)
2930         (replace-string serv-passwd "#PASSWD-WAS-HERE-ANON")))
2931     (tinypgpd fid "out:" (current-buffer))
2932     ;;  Clean return value
2933     nil))
2934
2935 ;;; ----------------------------------------------------------------------
2936 ;;;
2937 (defun tinypgp-submit-bug-report ()
2938   "Submit bug report or feedback.
2939 When you call this function it automatically includes all needed
2940 buffers. Please leave the *Backtrace* buffer before you call this function
2941 and it will be copied too.
2942
2943 If this is feedback call, then do not include any extra buffers.
2944 \[Answer 'n' when to insert questions]"
2945   (interactive)
2946   (ti::package-submit-bug-report
2947    "tinypgp.el"
2948    tinypgp-:version-id
2949    '(tinypgp-:version-id
2950
2951      message-send-hook
2952      mail-send-hook
2953      message-send-hook
2954
2955      mail-mode-hook
2956      rmail-mode-hook
2957      vm-mode-hook
2958      vm-version
2959      message-mode-hook
2960      gnus-article-mode-hook
2961      gnus-version
2962      news-reply-mode-hook
2963      mh-show-mode-hook
2964      mh-letter-mode-hook
2965      mh-before-send-letter-hook
2966      mh-show-hook
2967      mh-e-version
2968
2969      tinypgp-:load-hook
2970      tinypgp-:mode-hook
2971      tinypgp-:turn-on-hook-list
2972      tinypgp-:sig-from-header-hook
2973      tinypgp-:sig-to-header-hook
2974      tinypgp-:sign-loose-info-hook
2975      tinypgp-:key-mode-define-keys-hook
2976      tinypgp-:do-command-region-before-hook
2977      tinypgp-:do-command-region-after-hook
2978      tinypgp-:cmd-macro-before-hook
2979      tinypgp-:cmd-macro-after-hook
2980      tinypgp-:verify-before-hook
2981      tinypgp-:verify-after-hook
2982      tinypgp-:read-email-after-hook
2983      tinypgp-:find-by-guess-hook
2984      tinypgp-:finger-discard-email-hook
2985      tinypgp-:r-post-before-hook
2986      tinypgp-:r-post-after-hook
2987      tinypgp-:nymserver-post-hook
2988      tinypgp-:r-post-before-hook
2989      tinypgp-:r-reply-block-basic-hook
2990      tinypgp-:define-keys-hook
2991
2992      tinypgp-:pgp-encrypted-p-function
2993      tinypgp-:decrypt-arg-interpretation
2994      tinypgp-:pgp-decrypt-arg-function
2995      tinypgp-:pgp-command-compose-function
2996      tinypgp-mode
2997      tinypgp-:mode-name
2998 ;;;       tinypgp-:mode-menu-name
2999 ;;;       tinypgp-:mode-map
3000      tinypgp-:mode-prefix-key
3001      tinypgp-:mode-prefix-key-remailer
3002      tinypgp-:mode-prefix-key-nymserver
3003      tinypgp-key-mode
3004 ;;;       tinypgp-:key-mode-map
3005 ;;;       tinypgp-:key-mode-menu
3006      tinypgp-:key-mode-menu-name
3007      tinypgp-:key-mode-prefix-key
3008      tinypgp-:xpgp-user-info
3009      tinypgp-:pgp-binary-charset
3010      tinypgp-:pgp-sh-exe
3011      tinypgp-:pgp-binary
3012      tinypgp-:file-source
3013      tinypgp-:file-output
3014      tinypgp-:file-password
3015      tinypgp-:file-user-list
3016      tinypgp-:file-key-cache
3017      tinypgp-:file-secring-encrypted
3018      tinypgp-:face-mark
3019      tinypgp-:face-error
3020      tinypgp-:register
3021      tinypgp-:finger-discard-by-regexp
3022      tinypgp-:password-protection
3023      tinypgp-:password-keep-time
3024      tinypgp-:user-primary
3025      tinypgp-:filter-email-function
3026      tinypgp-:sign-mail-p-function
3027
3028 ;;; Do not send this to maintainer!
3029 ;;;       tinypgp-:user-identity-table
3030      tinypgp-:header-sign-table
3031 ;;;       tinypgp-:keyserver-mail-table
3032      tinypgp-:auto-action-table
3033      tinypgp-:pubring-table
3034      tinypgp-:r-levien-table
3035      tinypgp-:r-host-table
3036      tinypgp-:r-history
3037      tinypgp-:r-mode-indication-flag
3038      tinypgp-:r-list-file
3039      tinypgp-:r-user-mail-address
3040      tinypgp-:r-list-finger
3041      tinypgp-:r-newnym-help-file
3042      tinypgp-:r-mail2news-remailer
3043      tinypgp-:r-chain
3044      tinypgp-:r-reply-block-table
3045      tinypgp-:r-reply-block-cache
3046      tinypgp-:nymserver-request-encrypt
3047      tinypgp-:nymserver-account-table
3048      tinypgp-:debug
3049      tinypgp-:debug-buffer-size
3050 ;;;     tinypgp-:key-cache
3051      tinypgp-:key-cache-last
3052      tinypgp-:return-value
3053      tinypgp-:buffer-tmp-shell
3054      tinypgp-:buffer-tmp-finger
3055      tinypgp-:buffer-tmp-copy
3056      tinypgp-:buffer-tmp-http
3057      tinypgp-:buffer-tmp-kring
3058      tinypgp-:buffer-tmp-show
3059      tinypgp-:buffer-tmp-mail
3060      tinypgp-:buffer-tmp
3061      tinypgp-:buffer-comint
3062      tinypgp-:buffer-view
3063      tinypgp-:original-buffer
3064      tinypgp-:xpgp-signing-mode
3065      tinypgp-:history-email
3066 ;;;       tinypgp-:pgp-email-list
3067 ;;;       tinypgp-:pgp-email-abbrev-list
3068 ;;;       tinypgp-:pgp-email-list-completions
3069      tinypgp-:sign-data
3070      tinypgp-:history-key-info
3071      tinypgp-:error
3072      tinypgp-:last-pgp-exe-command
3073 ;;;       tinypgp-:hash-password
3074 ;;;       tinypgp-:hash
3075      tinypgp-:header-sign-smf-info
3076      tinypgp-:pubring-now
3077      tinypgp-:user-now
3078      tinypgp-:last-network-error
3079      tinypgp-:nymserver-echo-menu-use-p
3080
3081      tinypgp-:key-mode-name
3082      tinypgp-:pgp-binary-interactive-option
3083      tinypgp-:pgp-binary-support-table
3084 ;;;       tinypgp-:keyserver-http-table
3085      tinypgp-:r-control-list
3086 ;;;       tinypgp-:r-subject-table
3087      tinypgp-:nymserver-table))
3088 ;;;       tinypgp-:pgp-command-table
3089 ;;;       tinypgp-:pgp-binary-error-regexp
3090 ;;;       tinypgp-:nymserver-echo-menu
3091
3092   (save-excursion
3093
3094     (ti::pmax)
3095
3096     (when (get-buffer "*Backtrace*")
3097       (insert "\n\n#BACKTRACE BEGIN-------------\n")
3098       (insert-buffer (get-buffer "*Backtrace*")) (ti::pmax)
3099       (insert "\n\n#BACKTRACE END-------------\n"))
3100
3101     (when (and (get-buffer tinypgp-:buffer-tmp-shell)
3102                (y-or-n-p "Insert PGP shell buffer contents? "))
3103       (insert "\n\n#SHELL BEGIN-------------\n")
3104       (insert-buffer (get-buffer tinypgp-:buffer-tmp-shell)) (ti::pmax)
3105       (insert "\n\#SHELL END-------------\n"))
3106
3107     (cond
3108      ((or
3109        (and
3110         (null (get-buffer tinypgp-:debug-buffer))
3111         (y-or-n-p
3112          "No debug buffer: Are you sure maintainer doesn't need it? "))
3113        (y-or-n-p "Insert the debug buffer contents too? "))
3114       (insert "\n\n#DEBUG BEGIN-------------\n")
3115       (insert-buffer tinypgp-:debug-buffer) (ti::pmax)
3116       (insert "\n\#DEBUG END-------------\n")))
3117
3118     (tinypgp-password-wipe-buffer 'force))
3119   (ti::read-char-safe-until
3120    "[press]Please check that your pass phrase wasn't included..."))
3121
3122 ;;}}}
3123 ;;{{{ macros: test-p
3124
3125 ;;; ----------------------------------------------------------------------
3126 ;;;
3127 (defsubst tinypgp-backend-now ()
3128   "Return 'gpg 'pgp2 or 'pgp5"
3129   (get 'tinypgp-:pgp-binary 'pgp-now))
3130
3131 ;;; ----------------------------------------------------------------------
3132 ;;;
3133 (defsubst tinypgp-backend-type (&optional backend)
3134   "Return BACKEND type: 'unix or 'win32."
3135   (let* ((prop (intern (concat (symbol-name
3136                                 (or backend
3137                                     (tinypgp-backend-now)))
3138                                "-type"))))
3139     (get 'tinypgp-:pgp-binary prop)))
3140
3141 ;;; ----------------------------------------------------------------------
3142 ;;;
3143 (defun tinypgp-backend-file (file)
3144   (concat file  "."  (symbol-name (tinypgp-backend-now))))
3145
3146 ;;; ----------------------------------------------------------------------
3147 ;;;
3148 (defsubst tinypgp-backend-pgp2-p  ()
3149   "Return non-nil is if pgp 2.6.x is in use."
3150   (eq (tinypgp-backend-now) 'pgp2))
3151
3152 ;;; ----------------------------------------------------------------------
3153 ;;;
3154 (defsubst tinypgp-backend-gpg-p  ()
3155   "Return non-nil is if gpg is in use."
3156   (eq (tinypgp-backend-now) 'gpg))
3157
3158 ;;; ----------------------------------------------------------------------
3159 ;;;
3160 (defsubst tinypgp-backend-list ()
3161   "Return available backends: 'pgp2 'pgp5"
3162   (get 'tinypgp-:pgp-binary 'pgp-backends))
3163
3164 ;;; ----------------------------------------------------------------------
3165 ;;;
3166 (defsubst tinypgp-backend-exist-pgp2 ()
3167   "Return non-nil if pgp2 is available"
3168   (memq 'pgp2 (tinypgp-backend-list)))
3169
3170 ;;; ----------------------------------------------------------------------
3171 ;;;
3172 (defsubst tinypgp-backend-exist-pgp5 ()
3173   "Return non-nil if pgp5 is aailable"
3174   (memq 'pgp5 (tinypgp-backend-list)))
3175
3176 ;;; ----------------------------------------------------------------------
3177 ;;;
3178 (defsubst tinypgp-sign-data-same-p ()
3179   "Compare previous signing info against current buffer content.
3180 If this function returns non-nil, the buffer has been changed and
3181 it should be resigned."
3182   (eq (ti::mail-message-length) tinypgp-:sign-data))
3183
3184 ;;; ----------------------------------------------------------------------
3185 ;;;
3186 (defsubst tinypgp-sign-data-set ()
3187   "Store sign information."
3188   (if (ti::mail-mail-p)
3189       (setq tinypgp-:sign-data (ti::mail-message-length))))
3190
3191 ;;; ----------------------------------------------------------------------
3192 ;;;
3193 (defsubst tinypgp-sign-mail-auto-mode-on-p ()
3194   "Check if auto sign is active."
3195   (memq 'tinypgp-sign-mail-func  mail-send-hook))
3196
3197 ;;; ----------------------------------------------------------------------
3198 ;;;
3199 (defsubst tinypgp-mail-buffer-p (&optional msg-flag)
3200   "Check if buffer look like mail message.
3201 Non-nil MSG-FLAG displays message if test is nil."
3202   ;;  Gnus uses message-mode
3203   ;;
3204   (if (ti::mail-mail-p)
3205       t
3206     (tinypgpd "tinypgp-mail-buffer-p")
3207     (when msg-flag
3208       (message "This PGP action is available only in mail, news")
3209       (sit-for 1))
3210     nil))
3211
3212 ;;; ----------------------------------------------------------------------
3213 ;;;
3214 (defsubst tinypgp-hidden-p ()
3215   "Check if the PGP BLOCK is hidden.
3216 Return:
3217   nil
3218   (point . invisible-property-value)"
3219   (let* ((point (point-min))              ;Before widen
3220          (pmax  (+ (point-max) (* 80 6))) ;lookahead about 6 full lines
3221          pos
3222          prop)
3223     ;;  first find our property. Then see if it's invisible
3224     ;;
3225     (when (and
3226            ;;  In RMAIL buffer this widens a lot!
3227            (ti::widen-safe
3228              (setq pos (text-property-any
3229                         point
3230                         ;; Select lookahead or point-max.
3231                         ;; In RMAIL the pmax is selected.
3232                         ;;
3233                         (min pmax (point-max))
3234                         'owner 'tinypgp)))
3235            (setq prop (get-text-property pos 'invisible)))
3236       (cons pos prop))))
3237
3238 ;;; ----------------------------------------------------------------------
3239 ;;;
3240 (defsubst tinypgp-user-list  (&optional list)
3241   "Add to LIST users from `tinypgp-:encrypt-with-function'."
3242   (let* ((add (if tinypgp-:encrypt-with-function
3243                   (funcall tinypgp-:encrypt-with-function))))
3244     (if add
3245         (ti::list-merge-elements list add)
3246       list)))
3247
3248 ;;; ----------------------------------------------------------------------
3249 ;;;
3250 (defun tinypgp-user-find-current ()
3251   "Find current user.
3252
3253 If buffer is read-only (supposing RMAIL, VM):
3254
3255   look at the PGP stream in buffer and consult `tinypgp-:user-identity-table'.
3256
3257 If buffer is writable:
3258
3259   Do nothing special."
3260   (let ((fid    "tinypgp-user-find-current:")
3261         (type   (tinypgp-hash 'action 'get 'now nil 'global))
3262         key-id
3263         elt)
3264
3265     (tinypgpd fid "TYPE" type "READ-ONLY" buffer-read-only (buffer-name)
3266               "remail" tinypgp-:r-mode-indication-flag)
3267
3268     (cond
3269      ((or (and (not (member (buffer-name) '("RMAIL" "INBOX")))
3270                (not buffer-read-only))
3271           tinypgp-:r-mode-indication-flag)
3272       nil)
3273      (t
3274       (setq type (save-excursion
3275                    (ti::pmin)
3276                    (ti::mail-pgp-stream-forward-and-study)))
3277       (tinypgpd fid type)
3278       (when (and (eq (car type) 'enc)
3279                  (setq key-id (nth 3 type))
3280                  (inline
3281                    (setq elt
3282                          (ti::list-find
3283                           tinypgp-:user-identity-table key-id))))
3284         (nth 1 elt))))))
3285
3286 ;;; ----------------------------------------------------------------------
3287 ;;;
3288 (put 'tinypgp-interactive-enable 'lisp-indent-function 2)
3289 (defmacro tinypgp-interactive-enable (type)
3290   "Check TYPE condition and display MSG if function usage is prohibited."
3291   (`
3292    (cond
3293     ((eq (, type) 'remail)
3294      (unless (tinypgp-install-menu-bar-remail)
3295        (message "You haven't configured TinyPgp to use remailers yet.")
3296        (sit-for 1)
3297        (error "See TinyPgp Manual and 'tinypgp-:r-levien-table'")))
3298
3299     ((eq (, type) 'newnym)
3300      (unless (tinypgp-install-menu-bar-newnym)
3301        (message "\
3302 You haven't ordered newnym account or configured TinyPgp to use it.")
3303        (sit-for 1)
3304        (error "See TinyPgp Manual and 'tinypgp-:r-levien-table'")))
3305
3306     ((eq (, type) 'nymserver)
3307      (unless (tinypgp-install-menu-bar-nymserver)
3308        (message "\
3309 You haven't ordered nymserver account or configured TinyPgp to use it.")
3310        (sit-for 1)
3311        (error "See TinyPgp Manual and `tinypgp-:nymserver-account-table'")))
3312     (t
3313      (error "Not know type. %s" (, type))))))
3314
3315 (defsubst tinypgp-r-i-enable ()
3316   "Interactive check."
3317   (tinypgp-interactive-enable 'remail))
3318
3319 (defsubst tinypgp-newnym-i-enable ()
3320   "Interactive check."
3321   (tinypgp-interactive-enable 'newnym))
3322
3323 (defsubst tinypgp-nymserver-i-enable ()
3324   "Interactive check."
3325   (tinypgp-interactive-enable 'nymserver))
3326
3327 ;;}}}
3328 ;;{{{ macros: misc and inline defsubst
3329
3330 ;;; .......................................................... &macros ...
3331 ;;; Macros must be defined before used --> keep them at the top of file
3332
3333 ;;; ----------------------------------------------------------------------
3334 ;;;
3335 (defsubst tinypgp-email-or-string (string)
3336   "Return email address from STRING or STRING itself."
3337   (or (ti::string-match "[^< \t]+@[^ >\t]+" 0 string)
3338       string))
3339
3340 ;;; ----------------------------------------------------------------------
3341 ;;;
3342 (defsubst tinypgp-comint-buffer ()
3343   "Return comint buffer name."
3344   (concat "*" tinypgp-:buffer-comint "*"))
3345
3346 ;;; ----------------------------------------------------------------------
3347 ;;; - This "stringifies" a regexp :-)
3348 ;;;
3349 (defsubst tinypgp-cnv (string)
3350   "Remove possible anchor tag or other RE tags from STRING."
3351   (replace-regexp-in-string "[\n\r?$^]+" "" string))
3352
3353 ;;; ----------------------------------------------------------------------
3354 ;;;
3355 (defsubst tinypgp-pubring-table ()
3356   "Return backend's pubring table."
3357   (or (nth 1 (assq (tinypgp-backend-now) tinypgp-:pubring-table))
3358       (error "tinypgp-:pubring-table is corrupt. No backend %s: %s"
3359              (tinypgp-backend-now)
3360              tinypgp-:pubring-table)))
3361
3362 ;;; ----------------------------------------------------------------------
3363 ;;;
3364 (defsubst tinypgp-pubring-set-big ()
3365   "Set `tinypgp-:pubring-now' to point to big pubring."
3366   (setq tinypgp-:pubring-now
3367         (nth 1 (car (reverse (tinypgp-pubring-table))))))
3368
3369 ;;; ----------------------------------------------------------------------
3370 ;;;
3371 (defmacro tinypgp-do-shell-env (&rest body)
3372   "Execute BODY in specific shell environment."
3373   (`
3374    (let* ((pgp-type (tinypgp-backend-type))
3375           (shell    (nth 1 (assq pgp-type tinypgp-:pgp-sh-exe)))
3376           (explicit-shell-file-name  (or shell
3377                                          explicit-shell-file-name
3378                                          shell-file-name))
3379           (shell-file-name           (or shell shell-file-name)))
3380      (if (null explicit-shell-file-name) ;; nop-op Quiet XE ByteCompiler
3381          (setq explicit-shell-file-name nil))
3382      (,@ body))))
3383
3384 ;;; ----------------------------------------------------------------------
3385 ;;;
3386 (put 'tinypgp-save-state-macro 'lisp-indent-function 0)
3387 (defmacro tinypgp-save-state-macro (&rest body)
3388   "Save key values of program and execute BODY."
3389   (`
3390    (let ((TINYPGP-user  tinypgp-:user-now) ;Mixed case: Prevent variable suicide
3391          (TINYPGP-userp tinypgp-:user-primary)
3392          (TINYPGP-pring tinypgp-:pubring-now)
3393          (TINYPGP-h-s-t tinypgp-:header-sign-table)
3394          (TINYPGP-x-s-m tinypgp-:xpgp-signing-mode))
3395      (prog1 (progn (,@ body))
3396        (setq tinypgp-:user-now           TINYPGP-user
3397              tinypgp-:user-primary               TINYPGP-userp
3398              tinypgp-:pubring-now                TINYPGP-pring
3399              tinypgp-:header-sign-table  TINYPGP-h-s-t
3400              tinypgp-:xpgp-signing-mode  TINYPGP-x-s-m)))))
3401
3402 ;;; ----------------------------------------------------------------------
3403 ;;;
3404 (defsubst tinypgp-clone-buffer ()
3405   "Copy content of current buffer to `tinypgp-:buffer-tmp-article'."
3406   (tinypgp-copy-to-buffer (tinypgp-ti::temp-buffer 'article)))
3407
3408 ;;; ----------------------------------------------------------------------
3409 ;;;
3410 (defun tinypgp-copy-to-buffer (buffer)
3411   "Copy content of current buffer to BUFFER and remove all properties."
3412   (let ((data-buffer (current-buffer)))
3413     (tinypgpd "tinypgp-copy-to-buffer" buffer)
3414     (with-current-buffer (get-buffer-create buffer)
3415       (erase-buffer)
3416       (insert-buffer data-buffer)
3417
3418       ;; SIG may be hidden; Gnus hides headers with properties
3419
3420       (ti::buffer-text-properties-wipe (point-min) (point-max))
3421       (ti::overlay-remove-region (point-min) (point-max))
3422       buffer)))
3423
3424 ;;; ----------------------------------------------------------------------
3425 ;;;
3426 (put 'tinypgp-run-in-tmp-buffer  'lisp-indent-function 1)
3427 (defmacro tinypgp-run-in-tmp-buffer (buffer &rest body)
3428   "Use BUFFER, which is copy of current buffer, and do BODY.
3429 All text properties in the copy are removed. If BUFFER is nil,
3430 then use internal temporary buffer.
3431
3432 Note:
3433   The `set-buffer' command leaves pointer to copy buffer.
3434
3435 References:
3436   `tinypgp-:original-buffer' is set to buffer from where the text was copied."
3437   (`
3438    (let ((Data-buffeR           (current-buffer))
3439          BuffeR)
3440      (setq BuffeR (or (, buffer) (tinypgp-ti::temp-buffer 'copy)))
3441      (tinypgpd "tinypgp-run-in-tmp-buffer" BuffeR)
3442
3443      (setq tinypgp-:original-buffer Data-buffeR) ;save position
3444      (tinypgp-copy-to-buffer BuffeR)
3445
3446      (with-current-buffer BuffeR
3447        (,@ body)))))
3448
3449 ;;; ----------------------------------------------------------------------
3450 ;;;
3451 (put 'tinypgp-set-pgp-env-macro 'lisp-indent-function 2)
3452 (defmacro tinypgp-set-pgp-env-macro (user-list &optional verb &rest body)
3453   "Set environment. Find correct keyring and switch to it temporarily.
3454 But only if USER-LIST length is 1; if list is longer, use big pubring
3455 that holds all keys. The VERB parameter must also be set. Do BODY.
3456
3457 Error is signalled if we can't find keyring."
3458   (`
3459    (tinypgp-save-state-macro
3460     ;;  Let's be a little user friendly and try finding the key
3461     ;;
3462     (let ((user   (cond
3463                    ((stringp (, user-list))
3464                     (, user-list))
3465
3466                    ((and (ti::listp (, user-list))
3467                          (eq 1 (length (, user-list))))
3468                     (car (, user-list)))))
3469           kring)
3470
3471       (when (, verb)
3472
3473         (cond
3474          (user
3475           (if (not (setq kring (tinypgp-key-find-by-guess user)))
3476               (error "Sorry, can't set keyring '%s'. Fetch key first." user)
3477             (tinypgpd "tinypgp-set-pgp-env-macro" (, user-list) kring )
3478             (setq tinypgp-:pubring-now kring)))
3479
3480          ((ti::listp (, user-list))
3481           ;;  Multiple users, set pubring to point to BIG RING
3482           ;;
3483           (tinypgpd "tinypgp-set-pgp-env-macro: LAST KRING")
3484           (tinypgp-pubring-set-big))))
3485       (tinypgpd "tinypgp-set-pgp-env-macro: BODY " verb (, user-list)
3486                 tinypgp-:pubring-now)
3487
3488       (,@ body)))))
3489
3490 ;;; ----------------------------------------------------------------------
3491 ;;;
3492 (put 'tinypgp-user-change-macro  'lisp-indent-function 0)
3493 (defmacro tinypgp-user-change-macro (&rest body)
3494   "Change pgp user if From field address match `tinypgp-:user-identity-table'.
3495 If there is no From field or match this macro does nothing to BODY."
3496   (`
3497    (let (UseR)
3498      (if (setq UseR (tinypgp-user-find-current))
3499          (setq tinypgp-:user-now UseR))
3500      (tinypgpd "tinypgp-user-change-macro: " tinypgp-:user-now)
3501      (,@ body))))
3502
3503 ;;; ----------------------------------------------------------------------
3504 ;;;
3505 (defsubst tinypgp-name2alias (str table)
3506   "Return Nth 0 when NTH 1 STR is given from TABLE."
3507   (let* (ret)
3508     (dolist (elt table)
3509       (when (string= str (nth 1 elt))
3510         (setq ret elt)
3511         (return)))
3512     ret))
3513
3514 ;;; ----------------------------------------------------------------------
3515 ;;;
3516 (defsubst tinypgp-alias2name (str table)
3517   "Return Nth 1 when NTH 0 STR is given from TABLE."
3518   (nth 1 (assoc str table)))
3519
3520 ;;; ----------------------------------------------------------------------
3521 ;;;
3522 (defsubst tinypgp-x-headers-deinstall ()
3523   "Move X-pgp signature to normal format (if X-pgp exist)."
3524   (tinypgpd "tinypgp-x-headers-deinstall")
3525   (if (ti::mail-pgp-headers-p)
3526       ;;   Move X-pgp headers to their normal places
3527       ;;
3528       (tinypgp-signature-from-header)))
3529
3530 ;;; ----------------------------------------------------------------------
3531 ;;;
3532 (defsubst tinypgp-pubring-complete (&optional prompt init)
3533   "Read the pubring name with PROMPT and INIT. Return nil or selected string."
3534   (let ((ans
3535          (completing-read
3536           (or prompt "Select pubring: ")
3537           (ti::list-to-assoc-menu (mapcar 'car (tinypgp-pubring-table)))
3538           nil
3539           'require-match
3540           init)))
3541     (if (ti::nil-p ans)
3542         nil
3543       ans)))
3544
3545 ;;; ----------------------------------------------------------------------
3546 ;;;
3547 (defsubst tinypgp-pubring-alias2file (name)
3548   "Find real pubring behind completion NAME."
3549   (if name
3550       (tinypgp-expand-file-name
3551        (nth 1 (assoc name (tinypgp-pubring-table))))))
3552
3553 ;;; ----------------------------------------------------------------------
3554 ;;;
3555 (defun tinypgp-pubring-file2alias (name)
3556   "Find alias for real pubring NAME. Return nil if no match."
3557   (let* (ret)
3558     (setq name (tinypgp-expand-file-name name))
3559     (dolist (elt (tinypgp-pubring-table))
3560       (when (string= name (tinypgp-expand-file-name (nth 1 elt)))
3561         (setq ret (car elt))
3562         (return)))
3563     (or ret
3564         (error "Can't find alias for: %s"))))
3565
3566 ;;; ----------------------------------------------------------------------
3567 ;;;
3568 (defsubst tinypgp-pubring-list ()
3569   "Return all pubrings known to program."
3570   (let (list)
3571     (dolist (elt (tinypgp-pubring-table))
3572       (push (tinypgp-expand-file-name (nth 1 elt)) list))
3573     list))
3574
3575 ;;; ----------------------------------------------------------------------
3576 ;;;
3577 (defsubst tinypgp-pubring-many-p ()
3578   "Return non nil if there are many pubrings."
3579   (> (length (tinypgp-pubring-table)) 1))
3580
3581 ;;; ----------------------------------------------------------------------
3582 ;;;
3583 (defsubst tinypgp-pubring-default ()
3584   "Return first pubring< which is supposed to be default."
3585   (nth 1 (car (tinypgp-pubring-table))))
3586
3587 ;;; ----------------------------------------------------------------------
3588 ;;;
3589 (defsubst tinypgp-pubring-change-to-current ()
3590   "Change to pubring relative to current user.
3591 Calling function should possibly save the `tinypgp-:pubring-now'."
3592   (setq tinypgp-:pubring-now
3593         (or (tinypgp-key-find-by-cache tinypgp-:user-now)
3594             tinypgp-:pubring-now)))
3595
3596 ;;; ----------------------------------------------------------------------
3597 ;;;
3598 (defsubst tinypgp-user-change-to-primary ()
3599   "Change current variable settings to reflect primary user.
3600 The calling function should copy the key values of TinyPgp
3601 before calling this function.
3602
3603 This also changes the pubring.
3604
3605 Reference:
3606   `tinypgp-save-state-macro'"
3607   (tinypgpd "tinypgp-user-change-to-primary" tinypgp-:user-primary )
3608   (setq tinypgp-:user-now    tinypgp-:user-primary)
3609   (setq tinypgp-:pubring-now
3610         (tinypgp-expand-file-name
3611          (if (tinypgp-key-find-by-cache
3612               tinypgp-:user-now)
3613              (nth 1 (car (tinypgp-pubring-table)))))))
3614
3615 ;;; ----------------------------------------------------------------------
3616 ;;;
3617 (defsubst tinypgp-randseed-file ()
3618   "Return randseed filename."
3619   (or (getenv "RANDSEED")
3620       (format "%s/%s"
3621               (tinypgp-expand-file-name (or (getenv "PGPPATH") "~/.pgp"))
3622               "randseed.bin")))
3623
3624 ;;; ----------------------------------------------------------------------
3625 ;;;
3626 (defsubst tinypgp-finger-email-filter (list)
3627   "Filter out unwanted entries from email LIST."
3628   (when list
3629     (setq  list (tinypgp-email-discard-default list))
3630     (when tinypgp-:finger-discard-email-hook
3631       (setq list (run-hook-with-args-until-success
3632                   'tinypgp-:finger-discard-email-hook list)))
3633     list))
3634
3635 ;;; ----------------------------------------------------------------------
3636 ;;;
3637 (defun tinypgp-email-find-region (beg end)
3638   "Read all email addressed from BEG END and filter out unwanted ones.
3639 See. `tinypgp-:finger-discard-email-hook'."
3640   (tinypgp-finger-email-filter
3641    (ti::mail-email-find-region beg end 'no-dupes)))
3642
3643 ;;}}}
3644
3645 ;;{{{ misc: messages, error; hash; whatever...
3646
3647 ;;; ----------------------------------------------------------------------
3648 ;;;
3649 (defun tinypgp-error (message)
3650   "Generate error using MESSAGE and show buffer `tinypgp-:buffer-tmp-shell'.
3651 If the error is in list `tinypgp-:pgp-binary-error-regexp-quiet' then the
3652 shell buffer is not shown."
3653
3654   (tinypgpd "tinypgp-error" message tinypgp-:cmd-macro-after-hook)
3655
3656   (if (not (string-match tinypgp-:pgp-binary-error-regexp-quiet message))
3657       (ti::pop-to-buffer-or-window  tinypgp-:buffer-tmp-shell))
3658
3659   ;;  We must close the EDIT-RMAIL etc. before calling error.
3660
3661   (run-hook-with-args-until-success 'tinypgp-:cmd-macro-after-hook 'cancel)
3662   (tinypgp-password-expire-now 'keep-tmp-files)
3663
3664   (when (eq '1pass (tinypgp-hash 'action 'get 'detail 'global))
3665     (setq
3666      message
3667      (concat
3668       message
3669       "[possible cause: you don't have all the keys in this keyring.]")))
3670   (error "[PGP executable signalled error] %s" message))
3671
3672 ;;; ----------------------------------------------------------------------
3673 ;;;
3674 (defun tinypgp-unfinished-function ()
3675   "Signal error."
3676   (if  (not (string= (getenv "USER") "jaalto"))
3677       (error "\
3678 Function you tried to call is not yet ready; it's on todo list.")))
3679
3680 ;;; ----------------------------------------------------------------------
3681 ;;;
3682 (defun tinypgp-initial-message ()
3683   "
3684 Release note
3685
3686   1999-12-10 Development of this package has been stalled and there is no
3687   guarrantees that it will continue to work in new Emacs versions. The last
3688   update was more than year ago and since then I've been busy elswhere.
3689   I do appreciate bug reports, even if I can't adress any of the defects
3690   raised by the reports --The Maintainer.
3691
3692   Emacs debug and TinyPgp debug is now ON."
3693   (interactive)
3694   (let* ((win  (selected-window)))
3695     (tinypgp-version)
3696     (ti::pmin)
3697     (insert (documentation 'tinypgp-initial-message) "\n\n")
3698     (ti::pmin)
3699     (select-window win)))
3700
3701 ;;; ----------------------------------------------------------------------
3702 ;;;
3703 (defun tinypgp-hash (var-sym mode &optional property value global)
3704   "Set or get data from obarray.
3705 This function is used for internal data handling for current buffer.
3706
3707 Input:
3708
3709   VAR-SYM       variable name as symbol
3710   MODE          'put or 'get and 'def checks if defined
3711   PROPERTY      property name
3712   VALUE         value for property
3713   GLOBAL        Instead of using buffer local hash, use global hash table
3714
3715 References:
3716   `tinypgp-:hash'
3717   `tinypgp-:hash-global'"
3718
3719   ;; Make sure these two are initialized.
3720   (unless (vectorp tinypgp-:hash)
3721     (ti::vector-table-init  tinypgp-:hash))
3722 ;;;    (tinypgpd "HASH INIT" tinypgp-:hash)
3723
3724 ;;;  (tinypgpd "HASH" var-sym mode property tinypgp-:hash)
3725
3726   (or (vectorp tinypgp-:hash-global)
3727       (ti::vector-table-init  tinypgp-:hash-global))
3728
3729   (let* ((hash (if global
3730                    tinypgp-:hash-global
3731                  tinypgp-:hash)))
3732
3733     (if (symbolp var-sym)
3734         (setq var-sym (symbol-name var-sym))
3735       (error "TinyPgp: Must give a symbol '%s' " var-sym))
3736
3737     (cond
3738      ((eq mode 'def)
3739       (let* ((sym (ti::vector-table-get hash var-sym)))
3740         (if (null property)             ;Check only if variable exist.
3741             (ti::vector-table-get hash var-sym)
3742           (when sym                     ;Check property list
3743             (memq property (symbol-plist sym))))))
3744
3745      ((eq mode 'get)
3746       (if (ti::vector-table-get  hash var-sym) ;Exist ?
3747           (ti::vector-table-property hash var-sym property)))
3748
3749      ((eq mode 'put)
3750       (ti::vector-table-get  hash var-sym 'allocate)
3751       (ti::vector-table-property hash var-sym property value 'set))
3752      (t
3753       (error "TinyPgp: No such mode '%s' ." mode)))))
3754
3755 ;;; ----------------------------------------------------------------------
3756 ;;;
3757 (defun tinypgp-update-modeline ()
3758   "Set correct mode name."
3759   (let* ((fid   "tinypgp-update-modeline:")
3760          (str   (cond
3761                  ((tinypgp-backend-pgp2-p)
3762                   " pgp")
3763                  ((tinypgp-backend-gpg-p)
3764                   " gpg")
3765                  (t
3766                   " pgp5")))
3767          elt
3768          D)                             ;_Extra_ debug
3769
3770     (if elt
3771         (setq elt nil))                 ;No-op, byteComp silencer
3772
3773     ;;  This makes sense only if mode is on.
3774
3775     (when tinypgp-mode
3776       (tinypgpd fid  "BEGIN" (point))
3777
3778       ;; ................................................ update hooks ...
3779       ;;  Keep the hooks in proper order, Call function only
3780       ;;  periodically every 20th time. (it's too heavy operation to
3781       ;;  run all the time)
3782
3783       (inline (tinypgp-install-menu-bar))
3784
3785       (unless (setq elt (tinypgp-hash 'vital-hook 'get 'counter nil 'global))
3786         (setq elt 1)
3787         (tinypgp-hash 'vital-hook 'put 'counter 0 'global))
3788
3789       (when (zerop (% (incf  elt) 20))
3790         (tinypgp-install-hooks-vital)
3791         (setq elt 1))
3792
3793       (tinypgp-hash 'vital-hook 'put 'counter elt 'global)
3794
3795       (if D (tinypgpd fid  "1" (point)))
3796
3797       ;; ............................................... install check ...
3798       ;; Confirm proper installation. If we see any new packages since last
3799       ;; modeline update, these trigger auto installation.
3800
3801       (if (and (featurep 'gnus) (null (get 'tinypgp-:hash 'gnus-check)))
3802           (tinypgp-install-gnus))
3803
3804       (inline (tinypgp-install-mime-pgp))
3805
3806       (if (and (featurep 'vm) (null (get 'tinypgp-:hash 'vm-check)))
3807           (tinypgp-install-vm))
3808
3809       ;; .............................................. update pubring ...
3810       (setq elt (tinypgp-pubring-elt))
3811
3812       (setq str (concat                 ;Set pubring indicator
3813                  str
3814                  (or (nth 2 elt)
3815                      (error "\
3816 Internal error tinypgp-:pubring-table tinypgp-:pubring-now conflict"))))
3817
3818       (if D (tinypgpd fid  "2" (point)))
3819
3820       ;; ..................................................... secring ...
3821
3822       (inline (tinypgp-secring-crypt-mode-detect))
3823
3824       (when tinypgp-:secring-crypt-mode
3825         (setq str (concat str "c")))
3826
3827       ;; ...................................................... remail ...
3828
3829       (if tinypgp-:r-mode-indication-flag
3830           (setq str (concat str "r")))
3831
3832       (when tinypgp-:read-email-after-hook
3833         (if (tinypgp-key-id-conversion-check)
3834             (setq str (concat str "E"))
3835           (setq str (concat str "e"))))
3836
3837       ;;  Hmm, Should I call (tinypgp-header-sign-active-list)
3838       ;;  Which tells if this message will have headers?
3839       ;;
3840       ;;  Right now I just show the mode.
3841
3842       (if tinypgp-:header-sign-table
3843           (setq str (concat str "h")))
3844
3845       (if tinypgp-:xpgp-signing-mode
3846           (setq str (concat str "x")))
3847
3848       (when (tinypgp-sign-mail-auto-mode-on-p)
3849         (if (inline (tinypgp-sign-mail-auto-p))
3850             (setq str (concat str "A"))
3851           (setq str (concat str "a"))))
3852
3853       (if D (tinypgpd fid  "3" (point)))
3854
3855 ;;;      (if (tinypgp-nymserver-mail-p)
3856 ;;;       (setq str (concat str "n")))
3857
3858       (when (setq elt (get 'tinypgp-:r-newnym-default-account-table
3859                            'default-completion))
3860         (setq str
3861               (concat
3862                str
3863                (or (nth 3 (assoc elt tinypgp-:r-newnym-default-account-table))
3864                    "N")))
3865
3866       (if D (tinypgpd fid  "3.5" (point)))
3867
3868       (cond
3869        ((progn
3870           (if D (tinypgpd fid  "3.510" (point)))
3871           (tinypgp-auto-action-multiple-addresses-p))
3872         (if D (tinypgpd fid  "3.511" (point)))
3873         (setq str (concat str "$"))
3874         (unless (tinypgp-hash 'auto-action 'get 'user-mode)
3875           (setq str (concat str "-"))))
3876
3877        ((progn
3878           (if D (tinypgpd fid  "3.520" (point)))
3879           (tinypgp-auto-action-on-p))
3880         (if D (tinypgpd fid  "3.521" (point)))
3881         (setq str (concat str "!"))
3882         (unless (tinypgp-hash 'auto-action 'get 'user-mode)
3883           (setq str (concat str "-")))))
3884
3885       (if D (tinypgpd fid  "4" (point)))
3886
3887 )      ;;  check if we know this person: is the
3888       ;;  public key pubring info in cache?
3889
3890       (when (and (null buffer-read-only) ;skip RMAIL
3891                  (inline (ti::mail-mail-p))
3892                  (setq elt (car-safe (ti::mail-email-from-string
3893                                       (mail-fetch-field  "to"))))
3894
3895                  ;;  Call the conversion if it is activated,
3896                  ;;  save possibly one function call
3897
3898                  (or (and tinypgp-:read-email-after-hook
3899                           (setq elt (car-safe (tinypgp-key-id-conversion elt))))
3900                      t)
3901                  (inline (tinypgp-key-find-by-cache elt "modeline")))
3902         ;;  Yes, key is known
3903         (setq str (concat str "k")))
3904       (setq tinypgp-:mode-name str)
3905       (tinypgpd fid  "END" (point))
3906       (ti::compat-modeline-update))
3907
3908     ;;  These modes may have dynamic mode name later
3909     ;; .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. ..  key mode . .
3910
3911     (when  tinypgp-key-mode
3912       (setq tinypgp-:key-mode-name " pgpK")
3913       (ti::compat-modeline-update))
3914
3915     ;; .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. summary mode . .
3916
3917     (when  tinypgp-summary-mode
3918       (setq tinypgp-:summary-mode-name " pgp-sum")
3919       (ti::compat-modeline-update))))
3920
3921 ;;; ----------------------------------------------------------------------
3922 ;;;
3923 (defun tinypgp-highlight
3924   (regexp &optional level point face ov-type arg1 arg2 arg3)
3925   "Mark text forward.
3926 If Emacs does not support highlight, this function does nothing.
3927
3928 Input:
3929
3930   REGEXP        string to search
3931                  This can also be symbol with special meaning.
3932                  Additional arguments are passed in other variables.
3933                  'delet-all      remove all _tinypgp_ overlays
3934                  'wipe-all       delete ALL overlays and faces
3935                  'match          mark matched text
3936
3937   LEVEL         which level in string to match, defaults to 0
3938   POINT         from which point forward, defaults to `point-min'
3939   FACE          defaults to `tinypgp-:face-mark'
3940   OV-TYPE       overlay type information. Defaults to 'mark
3941   ARG1          additional arguments to 'match
3942   ARG2
3943   ARG3"
3944   (when (ti::colors-supported-p)
3945
3946     (let* ((fid "tinypgp-highlight: ")
3947            plist)
3948
3949       (setq face    (or face  tinypgp-:face-mark)
3950             level   (or level 0)
3951             ov-type (or ov-type 'mark)) ;used to be overlay type
3952
3953       (setq plist                       ;property list
3954             (list 'owner    'tinypgp
3955                   'type     ov-type
3956                   'face     face))
3957
3958       (tinypgpd fid "r" regexp "l" level "point" point face ov-type
3959                 (current-buffer))
3960
3961       (save-excursion
3962         (cond
3963          ((stringp regexp)
3964           (goto-char (or point (point-min)))
3965           (ti::text-re-search regexp nil level nil plist))
3966
3967          ((eq regexp 'match)
3968           (tinypgpd fid "level" level arg1 arg2)
3969           (ti::text-match-level level plist arg1 arg2))
3970
3971          ((eq regexp 'delete-all)
3972           (ti::text-clear-region-properties
3973            (point) (point-max) '(owner tinypgp) ))
3974
3975          ((eq regexp 'wipe-all)
3976           (set-text-properties (point) (point-max) nil))
3977
3978          (t
3979           (error "TinyPgp: No such action as '%s'" regexp)))))))
3980
3981 ;;; ----------------------------------------------------------------------
3982 ;;;
3983 (defun tinypgp-set-session-parameters (action)
3984   "Set program flags according to ACTION.
3985 In some cases the program's parameters must be in certain state
3986 before ACTION 'sign 'encrypt 'decrypt 'verify is carried out.
3987
3988 Here is one reason to do so:
3989
3990   When you sign create command to 'newnym' account: the X-Pgp
3991   signing must not be used, No headers must be signed.
3992
3993 This function should be inside wrapper macro that saves the previous
3994 state of session. Use `tinypgp-save-state-macro'.
3995
3996 Return:
3997  t          if state changed
3998  nil        nothing done"
3999   (when (ti::mail-mail-p)
4000     (let* ((to    (or (mail-fetch-field  "to") ""))
4001            ret)
4002       (cond
4003        ((string-match
4004          "@weasel\\|@squirrel\\|efga\\|nym.alias" to) ;Newnym remailers
4005         (setq tinypgp-:header-sign-table nil
4006               tinypgp-:xpgp-signing-mode nil
4007               ret t)))
4008       ret)))
4009
4010 ;;; ----------------------------------------------------------------------
4011 ;;;
4012 (defun tinypgp-add-signature-if-signing ()
4013   "Insert `mail-signature-file' in mail. Do nothing in `message-mode'."
4014   (when (and (boundp 'mail-signature-file)
4015              (memq major-mode
4016                    '(mail-mode
4017                      news-reply-mode)))
4018     ;; message-mode , Gnus
4019
4020     (let* ((file  (symbol-value 'mail-signature-file))
4021            (sig   (and file
4022
4023                        ;; Gnus composes messages in message-mode,
4024                        ;; we don't touch
4025                        ;; that buffer because Gnus 5 can add signature when
4026                        ;; you compose the mail.
4027
4028                        (file-exists-p file)
4029                        (null (ti::mail-signature-p))
4030
4031                        ;;  If we're signing whole mail  buffer, then ask if
4032                        ;; signature should be added before signing.
4033
4034                        (y-or-n-p
4035                         "Tinypgp: Add .signature before sign? "))))
4036       (when sig
4037         (save-excursion
4038           (ti::pmax)
4039           (insert-file-contents file)
4040           ;;  According to RFC there must be "-- \n" before signature.
4041           (ti::mail-signature-insert-break))
4042         nil))))
4043
4044 ;;; ----------------------------------------------------------------------
4045 ;;;
4046 (defun tinypgp-after-pgp-command (&optional cmd &rest args)
4047   "Example function: run after you have executed and some PGP command.
4048 If buffer contains diff (after decrypting) and you have tinydiff.el
4049 loaded, call function `tinydiff-patch' to apply that diff.
4050
4051 Input:
4052   CMD       ,'encrypt 'sign 'verify ...
4053   ARGS      ,ignored"
4054   (if (and (fboundp 'tinydiff-patch)
4055            ;;  We suppose that we're in incoming RMAIL or VM buffer
4056
4057            (memq major-mode '(rmail-mode vm-mode))
4058            (memq cmd '(verify decrypt))
4059            (ti::buffer-diff-type-p))    ;Is there diff
4060       (call-interactively 'tinydiff-patch))
4061   nil)
4062
4063 ;;}}}
4064 ;;{{{ misc: file control; abbrevs
4065
4066 ;;; ........................................................ &pgp-misc ...
4067
4068 ;;; ----------------------------------------------------------------------
4069 ;;;
4070 (defun tinypgp-show-last-finger-error ()
4071   "Show last finger error message in echo area."
4072   (interactive)
4073   (if (stringp tinypgp-:last-network-error)
4074       (message tinypgp-:last-network-error)
4075     (message "No Finger error information.")))
4076
4077 ;;; ----------------------------------------------------------------------
4078 ;;;
4079 (defun tinypgp-view-register (&optional noerr)
4080   "View content of register.
4081 Do not signal error if the register `tinypgp-:register' is empty and
4082 NOERR is non nil. NOERR is automatically t if function is called
4083 interactively."
4084   (interactive)
4085   (let* ((reg   tinypgp-:register)
4086          (msg   (format "TinyPgp: register '%c' doesn't contain data yet."
4087                         tinypgp-:register))
4088          win)
4089     (if (not (stringp (get-register reg)))
4090         (unless noerr
4091           (if (interactive-p)
4092               (message msg)
4093             (error msg)))
4094       (setq win (get-buffer-window tinypgp-:buffer-view t))
4095
4096       (if (null win)
4097           (pop-to-buffer (ti::temp-buffer tinypgp-:buffer-view 'clear))
4098         (raise-frame (window-frame win))
4099         (select-window win)
4100         (erase-buffer))
4101
4102       (insert-register tinypgp-:register)
4103       (ti::pmin)
4104       (when (interactive-p)
4105         (message "Content of register '%c'" tinypgp-:register)
4106         (sleep-for 1)))))
4107
4108 ;;; ----------------------------------------------------------------------
4109 ;;;
4110 (defun tinypgp-file-control (mode &optional arg)
4111   "Do file operation according to MODE and ARG.
4112
4113 Input:
4114   MODE  'all-kill
4115         'password-write
4116         'password-kill
4117         'password-kill
4118         'source-kill
4119         'source-write
4120         'users-write
4121   ARG"
4122   (let* (buffer)
4123     (tinypgpd "file-control in:" mode arg)
4124
4125     (cond
4126      ((eq 'all-kill mode)
4127       (dolist (file
4128                (list
4129                 tinypgp-:file-source
4130                 tinypgp-:file-output
4131                 tinypgp-:file-password
4132                 tinypgp-:file-user-list))
4133         (if (file-exists-p file)
4134             (delete-file file))))
4135
4136      ((eq 'password-write mode)
4137       (ti::file-delete-safe tinypgp-:file-password)
4138
4139       (with-current-buffer (tinypgp-ti::temp-buffer)
4140         (buffer-disable-undo (current-buffer))
4141
4142         (insert
4143          (or arg
4144              (ti::vector-table-property
4145               tinypgp-:hash-password tinypgp-:user-now 'password)))
4146
4147         (set-buffer-modified-p nil)
4148         (write-region (point-min) (point-max) tinypgp-:file-password)
4149
4150         ;;  Don't leave password traces in the buffer
4151
4152         (if (fboundp 'passwd-erase-buffer)
4153             (ti::funcall 'passwd-erase-buffer) ;passwd.el
4154           (let ((s (* (buffer-size) 3))) ;Code copied from passwd.el
4155             (erase-buffer)
4156             (while (> s 0)
4157               (insert ?\000)
4158               (setq s (1- s)))
4159             (erase-buffer)))
4160
4161         (ti::file-mode-protect tinypgp-:file-password)))
4162
4163      ((eq 'password-kill mode)
4164       (if (file-exists-p tinypgp-:file-password)
4165           (delete-file tinypgp-:file-password)))
4166
4167      ((eq 'source-kill mode)
4168       (if (file-exists-p tinypgp-:file-source)
4169           (delete-file tinypgp-:file-source)))
4170
4171      ((eq 'source-write mode)
4172       ;;  When wring the file out, it must be exactly
4173       ;;  as it appears in buffer
4174
4175       (let* ((require-final-newline nil))
4176         (ti::file-delete-safe
4177          (list tinypgp-:file-source
4178                (concat tinypgp-:file-source ".asc")))
4179
4180         ;;  I don't think this is good for Multibyte Chars
4181
4182 ;;;     (if (fboundp 'as-binary-process)
4183 ;;;         (as-binary-process
4184 ;;;          (write-region (point) (point-max) tinypgp-:file-source))
4185
4186         (write-region (point) (point-max) tinypgp-:file-source)
4187
4188         (ti::file-mode-protect tinypgp-:file-source)))
4189
4190      ((eq 'users-write mode)
4191       (ti::file-delete-safe tinypgp-:file-user-list)
4192       (setq buffer (tinypgp-ti::temp-buffer))
4193       (unless arg
4194         (error "No USER LIST"))
4195
4196       (with-current-buffer buffer
4197
4198         (dolist (elt (ti::list-make arg))
4199           (unless (stringp elt)
4200             (error "Users corrupt. Check tinypgp-:encrypt-with-function"))
4201           (insert (ti::string-remove-whitespace elt) "\n"))
4202
4203         (ti::file-delete-safe tinypgp-:file-user-list)
4204         (write-region (point-min) (point-max) tinypgp-:file-user-list)
4205         (ti::file-mode-protect tinypgp-:file-user-list)))
4206
4207      (t
4208       (error "Unknown mode")))))
4209
4210 ;;; ----------------------------------------------------------------------
4211 ;;;
4212 (defun tinypgp-mail-abbrevs-filter (email-list)
4213   "Filter invalid entries out form EMAIL-LIST.
4214 Every entry must have .xx or .xxx extension, which refers to country
4215 name or organisation form."
4216   (let* (ret)
4217     (dolist (elt email-list)
4218       (if (string-match "\\....?$" (car (ti::mail-email-from-string elt)))
4219           (push elt ret)))
4220     ret))
4221
4222 ;;; ----------------------------------------------------------------------
4223 ;;;
4224 (defun tinypgp-update-mail-abbrevs ()
4225   "Update mail abbrevs.
4226 You need to do this is you have modified ~/.mailrc.
4227 Call mail abbrev.el first to read the file."
4228   (interactive)
4229   (let* ((sym 'timi-:mail-aliases-alist)
4230          list)
4231     (tinypgpd "update-mail-abbrevs 1:")
4232
4233     ;;   since the tinymail.el and tinypgp.el use the same
4234     ;;   abbrevs list, it isn't worth to build 2 separate lists,
4235     ;;   because creating alist is slow!
4236     ;;
4237     ;;   Now we share the same list and the abbrevs are built by
4238     ;;   tinymail, which we copy here.
4239
4240     (if (and (featurep 'tinymail)
4241              (boundp 'timi-:mail-aliases-alist))
4242         (setq  tinypgp-:pgp-email-abbrev-list (symbol-value sym))
4243       (setq  tinypgp-:pgp-email-abbrev-list (ti::mail-abbrev-get-alist)))
4244
4245     (tinypgpd "update-mail-abbrevs 2:")
4246     (setq  tinypgp-:pgp-email-list
4247            (ti::mail-mail-abbrevs-email-list tinypgp-:pgp-email-abbrev-list))
4248
4249     (tinypgpd "update-mail-abbrevs 3:")
4250
4251     ;;  maybe not all are valid in the obarray...
4252
4253     (setq list (funcall tinypgp-:filter-email-function
4254                         tinypgp-:pgp-email-list))
4255
4256     (tinypgpd "update-mail-abbrevs 4:")
4257     (setq tinypgp-:pgp-email-list-completions
4258           (ti::list-to-assoc-menu list))
4259
4260     nil))
4261
4262 ;;; ----------------------------------------------------------------------
4263 ;;;
4264 (defun tinypgp-update-mail-abbrevs-hook ()
4265   "Reparse the ~/.mailrc file when it is saved.
4266 This function is installed into `write-file-hooks'."
4267   (when (string-match "\\.mailrc" (or buffer-file-name "#noName"))
4268     (message "Updating mail abbrevs for TinyPgp...")
4269     (tinypgpd "update-mail-abbrevs-hook in:")
4270     (tinypgp-update-mail-abbrevs)
4271     (message "Updating mail abbrevs for TinyPgp...done")
4272     nil))                               ;Hook return value
4273
4274 ;;; ----------------------------------------------------------------------
4275 ;;;
4276 (defun tinypgp-invisible-region (beg end &optional show)
4277   "Make BEG END invisible. Optionally SHOW it."
4278   ;;  We also say that these properties belong to "tinypgp"
4279   (let* (buffer-read-only)              ;allow writing
4280     (with-buffer-modified
4281       (if (null show)
4282           (set-text-properties beg end '(invisible t owner tinypgp))
4283         (set-text-properties beg end '(invisible nil owner tinypgp))))))
4284
4285 ;;}}}
4286 ;;{{{ misc: test-p, or or primitives
4287
4288 ;;; ........................................................... &tests ...
4289
4290 ;;; ----------------------------------------------------------------------
4291 ;;;
4292 (defun tinypgp-pgp-encrypted-p-default ()
4293   (let (stat)
4294     ;; this function returns symbol, convert it to string
4295     (save-excursion
4296       (ti::pmin)
4297       (if (setq stat (ti::mail-pgp-data-type))
4298           (symbol-name stat)))))
4299
4300 ;;; ----------------------------------------------------------------------
4301 ;;;
4302 (defun tinypgp-password-time-valid-p ()
4303   "Return non-nil, if it's not yet time to forget password.
4304 The returned value is number of seconds left."
4305   (let* (secs-was
4306          secs-now
4307          diff
4308          val)
4309     (cond
4310      ((not (integerp tinypgp-:password-keep-time))
4311       nil)
4312      (t
4313       (if (null (tinypgp-hash 'password-time 'get 'tick nil 'global))
4314           (tinypgp-hash 'password-time 'put 'tick (current-time) 'global))
4315
4316       (setq val         (tinypgp-hash 'password-time 'get 'tick nil 'global)
4317             secs-was    (nth 1  val)
4318             secs-now    (nth 1  (current-time))
4319             diff        (- secs-now secs-was)
4320             diff        (- tinypgp-:password-keep-time diff))
4321
4322 ;;;      (ti::d! diff)
4323
4324       (if (> diff 0)
4325           ;; How much is left, counts down...
4326           diff)))))
4327
4328 ;;}}}
4329 ;;{{{ misc: email and substitutions
4330
4331 ;;; ........................................................... &email ...
4332
4333 (defvar tinypgp-:email-substitution-table nil
4334   "Where this variable is used:
4335
4336     Change email addresses if needed to get right public key.
4337
4338     Say, the PGP key-id shows <foo@site.com> as email, but the person also
4339     has mailing address <foo@x-site.com>. If we receive mail from
4340     foo@x-site.com, PGP wouldn't find it from the database if we used
4341     that. Instead we must immediately tell 'hey, this person is known as
4342     <foo@site.com>' which is listed in his key-id field.
4343
4344 How this variable is used:
4345
4346     List of email substitution. When REGEXP is matches then SUBST is used.
4347     SUBST is should match unique key entry in your keyrings. Best if
4348     SUBST is 0xFFFF key id, but many times it more descriptive to use
4349     alternative email address.
4350
4351 Where this variable is used
4352
4353     In function `tinypgp-email-substitution-default' which is installed
4354     to `tinypgp-:read-email-after-hook'
4355
4356 Example:
4357
4358     WE CHANGE THIS VARIABLE WITH FUNCTION `tinypgp-email-substitution-add'
4359
4360     ;;  List of email addresses that are not in the person's pgp-key id
4361     ;;  Use the right Hand key when left hand matches.
4362
4363     (defconst my-:tinypgp-email-substitution-table
4364       (list
4365        (cons \"xxx@.*lycaeum\"   \"yyy@lycaeum.org\")
4366        (cons \"xxx.*jena.de\"    \"zzz.foo@Jena.Thur.De\")
4367
4368        ;; This one has multiple keys and we want to use one particular.
4369        ;; The 0xFFFF is unique way to tell which key to use
4370
4371        (cons \"valkyr\"     \"0xA73B5E6D\"))
4372       \"*My email substitutions that will be added to
4373     `tinypgp-:email-substitution-table'\")
4374
4375     ;;  Now add my substitutions
4376
4377     (tinypgp-email-substitution-add my-:tinypgp-email-substitution-table)
4378
4379 Format:
4380   '((REGEXP  SUBST) (R S) ..)")
4381
4382 ;;; ----------------------------------------------------------------------
4383 ;;;
4384 (defun tinypgp-email-make-choices (email)
4385   "Make new choices from EMAIL.
4386 If you try to encrypt with EMAIL and it fails; it may be
4387 the case that the email address is not added to user's PGP key-id field.
4388
4389 This function examines EMAIL and constructs some suitable
4390 choices that may match better when doing new lookup.
4391
4392 Return:
4393   nil
4394   (\"string\"
4395    ..)"
4396   (let* (list
4397          str
4398          s1
4399          s2)
4400
4401     ;;  firstname.surname@site.com --> "Firstname Surname"
4402
4403     (when (string-match "^\\(.*\\)\\.\\(.*\\)@" email)
4404       (setq s1 (capitalize (match-string 1 email))
4405             s2 (capitalize (match-string 2 email)))
4406
4407       ;;  Because the firsh name may be shortened
4408       ;;  "Rich" is actually "Richard", we want to add the surname
4409       ;;  by it self to the list too
4410
4411       (push  (concat s1 " " s2) list)
4412       (push s2 list))
4413
4414     ;;   many times the 'server' is local and is not
4415     ;;   included in the key id
4416     ;;
4417     ;;   @server.domain.here.com -->  "domain.here.com"
4418
4419     (if (setq str (ti::string-match "@[^.]+\\.\\(.*\\..*\\)" 1 email))
4420         (push str list))
4421
4422     list))
4423
4424 ;;; ----------------------------------------------------------------------
4425 ;;;
4426 (defun tinypgp-email-discard-default (list)
4427   "Toss away addresses from LIST that are not finger sites.
4428
4429 In-Reply-To: <199611101605.LAA18736@site.com> from Foo Bar at..
4430 X-Face: >>@YIrj6h"
4431   (let (ret)
4432     (tinypgpd "tinypgp-email-discard-default in: " list )
4433
4434     (when list
4435       (dolist (elt (ti::list-make list))
4436         (when (and (not (string-match
4437                          (concat
4438                           "\\(19[89][0-9]\\|200[0-9]\\)[0-9][0-9]"
4439                           "\\|^foo\\|^ba[zr]@\\|@site.com"
4440                           "\\|[^-_0-9a-zA-Z+]@")
4441                          elt))
4442                    ;;  leave only real email addresses
4443                    (string-match "@" elt))
4444           (push elt ret))))
4445     (tinypgpd "tinypgp-email-discard-default out: " ret )
4446     (if ret
4447         (nreverse ret))))
4448
4449 ;;; ----------------------------------------------------------------------
4450 ;;;
4451 (defun tinypgp-email-substitution-add-1 (cons-cell &optional remove)
4452   "Add new CONS-CELL (RE . SUBST) to `tinypgp-:email-substitution-table'.
4453 IF REMOVE is non-nil, search for SUBST and delete the entry
4454 from the table.
4455
4456 Return:
4457   killed entry
4458   added entry
4459   nil           ;already exist(add) or not exist(remove)"
4460   (let* (elt
4461          ret)
4462     (setq elt (rassoc (cdr cons-cell) tinypgp-:email-substitution-table))
4463     (cond
4464      (remove
4465       (when elt
4466         (setq tinypgp-:email-substitution-table
4467               (delete elt  tinypgp-:email-substitution-table))
4468         (setq ret elt)))
4469
4470      ((null elt)                        ;Add new element if not there.
4471       (setq ret cons-cell)
4472       (push cons-cell tinypgp-:email-substitution-table)))
4473     ret))
4474
4475 ;;; ----------------------------------------------------------------------
4476 ;;;
4477 (defun tinypgp-email-substitution-add (cons-list &optional remove)
4478   "Add CONS-LIST or REMOVE it from list of email substitutions.
4479 The CONS-LIST must be in format:
4480
4481 '((RE . SUBST) (R . S) ..)"
4482
4483   (mapcar
4484    (function
4485     (lambda (x)
4486       (tinypgp-email-substitution-add-1 x remove)))
4487    cons-list))
4488
4489 ;;; ----------------------------------------------------------------------
4490 ;;;
4491 (defun tinypgp-email-substitution-default (list)
4492   "Check LIST of email addresses and subtitute them with suitable pgp-ids.
4493 `tinypgp-:email-substitution-table' takes precedence over BBDB record `pgp-id'.
4494
4495 References:
4496   `tinypgp-:email-substitution-table'
4497   `tinypgp-:read-email-after-hook'."
4498   (let* (re
4499          subst
4500          bbdb-pgp-id
4501          ret)
4502     (dolist (email (ti::list-make list))
4503
4504       (dolist (elt tinypgp-:email-substitution-table)
4505         (setq re (car elt)    subst (cdr elt))
4506         (cond
4507          ((string-match re email)
4508           (setq email subst) ;;  substitute and stop loop
4509           (return))
4510          ((setq bbdb-pgp-id (tinypgp-bbdb-id email))
4511           (setq email bbdb-pgp-id)
4512           (return))))
4513
4514       (push email ret))
4515     ret))
4516
4517 ;;; ----------------------------------------------------------------------
4518 ;;;
4519 (defun tinypgp-email-substitution-toggle (&optional mode)
4520   "Toggle email substitution.
4521 It is possible that you have coded an email substitution function
4522 and installed it into `tinypgp-:read-email-after-hook'.
4523
4524 If there is such a function; it probably converts some email addresses
4525 to some relevant PGP key ids. However sometimes you may want to turn
4526 off this feature completely to be sure that when reading the
4527 email address eg from TO: field, it will also be used when calling
4528 for encryption.
4529
4530 This functions toggles email substitution functions on/off by
4531 clearing/restoring the `tinypgp-:read-email-after-hook'
4532
4533 MODE can be
4534  nil        toggle
4535  0 -1       off
4536  other      on"
4537   (interactive)
4538   (let* ((sym 'tinypgp-:read-email-after-hook))
4539
4540     ;; Not recorded; record original value
4541
4542     (if (null (get sym 'original))
4543         (put sym 'original (symbol-value sym)))
4544
4545     (cond
4546      ((or (memq mode '(0 -1))
4547           (symbol-value sym))
4548       (set sym nil)
4549       (message "Email substitution off."))
4550      (t
4551       (set sym (get sym 'original))
4552       (message "Email substitution restored to original.")))
4553
4554     (tinypgp-update-modeline)))
4555
4556 ;;; ----------------------------------------------------------------------
4557 ;;;
4558 (defun tinypgp-key-id-conversion (single-or-list)
4559   "Modify SINGLE-OR-LIST and return possibly modified list.
4560 Function is used to convert any email address in the list to a suitable pgp
4561 key-id that can be used in place of the 'email' string.
4562
4563 This function stores the list to hash table and reads the
4564 conversion from there if it exist in symbol 'key-id property
4565 'conversion.
4566
4567 References:
4568
4569   `tinypgp-:read-email-after-hook'"
4570   (let* ((fid     "tinypgp-key-id-conversion: ")
4571          ;;  Make hash access key property
4572          (prop    (when single-or-list
4573                     (make-symbol
4574                      (mapconcat
4575                       'concat
4576                       (ti::list-make single-or-list)
4577                       ""))))
4578          val)
4579
4580     ;;  Because you use the key-id conversion in the program all the
4581     ;;  time (called multiple times) and the conversion will
4582     ;;  always be same, we save the converted list into hash table
4583     ;;  for later use.
4584     ;;
4585     ;;  1. the hash-key is all list strings concatenated
4586     ;;     together "me@foo.siteyou@bar.site"
4587     ;;
4588     ;;  2. If that hash entry is not found, then we call conversion
4589     ;;     function and store the result to hash
4590     ;;
4591     ;;  3. Next time the conversion is already available for us
4592     ;;     from quick cache.
4593     ;;
4594     ;;  This should result faster response, becuse calling hook
4595     ;;  functions is real slow.
4596
4597     (tinypgpd fid 'KEY prop 'LIST single-or-list)
4598
4599     (when single-or-list
4600       (cond
4601        ((tinypgp-hash 'key-id-conversion 'def prop)
4602         (when (setq val (tinypgp-hash 'key-id-conversion 'get prop))
4603           (setq single-or-list val))
4604         (tinypgpd fid 'HASH single-or-list))
4605        (t
4606         (tinypgpd fid 'HOOK tinypgp-:read-email-after-hook)
4607         (dolist (func (ti::list-make tinypgp-:read-email-after-hook))
4608           (setq single-or-list  (funcall func single-or-list)))
4609
4610         (tinypgp-hash 'key-id-conversion 'put prop single-or-list)
4611         (tinypgpd fid 'OUT single-or-list))))
4612
4613     (when single-or-list
4614       (ti::list-make single-or-list))))
4615
4616 ;;; ----------------------------------------------------------------------
4617 ;;;
4618 (defun tinypgp-key-id-conversion-check ()
4619   "Return non-nil if the the conversion happens on TO field.
4620 To field must contain only one address."
4621   (let* (elt)
4622     (when (ti::mail-mail-p)
4623       ;;   Will conversion happen?
4624       ;;   - To field must have something
4625       ;;   - there must be only one email
4626       ;;   - the conversion has changed email.
4627       (cond
4628        ((and (not (ti::nil-p (setq elt (mail-fetch-field "To"))))
4629              (not (string-match "," elt))
4630              (not (string= elt (or (car-safe (tinypgp-key-id-conversion elt))
4631                                    ""))))
4632         (or (car-safe (tinypgp-key-id-conversion elt))
4633             ""))
4634        (t
4635         nil)))))
4636
4637 ;;; ----------------------------------------------------------------------
4638 ;;;
4639 (defun tinypgp-key-id-conversion-check-verbose ()
4640   "Check if email address conversion is about to happen in To field."
4641   (interactive)
4642   (let* (stat)
4643     (cond
4644      ((null (ti::mail-mail-p))
4645       (message "Email conversion: not a mail buffer, can't read To field."))
4646      (t
4647       (setq stat (tinypgp-key-id-conversion-check))
4648       (cond
4649        ((null tinypgp-:read-email-after-hook)
4650         (message "You have turned off Email conversion mode. %s"
4651                  (if stat (format "[cnv: %s" stat))))
4652        (t
4653         (if stat
4654             (message "Conversion to: %s" stat)
4655           (message "No Email conversion trigges"))))))))
4656
4657 ;;; ----------------------------------------------------------------------
4658 ;;;
4659 (defun tinypgp-key-id-find ()
4660   "Try to find 'Id' 0x12345678 from current buffer. X-Pgp is searched first."
4661   (let* ((list (tinypgp-xpgp-get-info))
4662          elt
4663          ret)
4664     (cond
4665      ((and list                         ; Id=0xF72ED579;
4666            (setq elt (assoc "id" list)))
4667       (setq ret (nth 1 elt)))
4668      (t                                 ;No other methods yet.
4669       nil))
4670     ret))
4671
4672 ;;}}}
4673
4674 ;;{{{ buffer: generate, show
4675
4676 ;;; ----------------------------------------------------------------------
4677 ;;;
4678 (defun tinypgp-ti::temp-buffer (&optional choice arg1 arg2 arg3)
4679   "Create tmp buffer for TinyPgp.el. CHOICE ARG1 ARG2 ARG3 are internal."
4680   (let ((fid "tinypgp-ti::temp-buffer:")
4681         mail-setup-hook                 ;No hooks now (slow) !
4682         mail-mode-hook
4683         message-mode-hook
4684         buffer)
4685     (tinypgpd fid choice arg1 arg2 arg3)
4686
4687     ;;  ByteComp silencer, this is no-op
4688     (if mail-setup-hook (setq mail-setup-hook nil))
4689     (if mail-mode-hook  (setq mail-setup-hook nil))
4690
4691     (setq
4692      buffer
4693      (cond
4694       ((eq choice 'shell)
4695        (ti::temp-buffer tinypgp-:buffer-tmp-shell 'clear))
4696
4697       ((eq choice 'copy)
4698        (ti::temp-buffer tinypgp-:buffer-tmp-copy  'clear))
4699
4700       ((eq choice 'article)
4701        (ti::temp-buffer tinypgp-:buffer-tmp-article  'clear))
4702
4703       ((eq choice 'finger)
4704        (ti::temp-buffer tinypgp-:buffer-tmp-finger 'clear))
4705
4706       ((eq choice 'http)
4707        (ti::temp-buffer tinypgp-:buffer-tmp-http 'clear))
4708
4709       ((eq choice 'kring)
4710        (ti::temp-buffer tinypgp-:buffer-tmp-kring 'clear))
4711
4712       ((eq choice 'show)
4713        (ti::temp-buffer tinypgp-:buffer-tmp-show 'clear))
4714
4715       ((eq choice 'mail)
4716        (ti::kill-buffer-safe tinypgp-:buffer-tmp-mail)
4717        (setq buffer (ti::temp-buffer tinypgp-:buffer-tmp-mail 'clear))
4718        (with-current-buffer buffer
4719          (setq tinypgp-:hash nil)       ;Clear hash array
4720          (mail-mode)
4721          ;;   to subject in-reply-to cc replybuffer actions
4722          ;;
4723          (mail-setup arg1 arg2 nil arg3 nil nil))
4724        (tinypgpd fid "MAIL OUT")
4725        buffer)
4726
4727       ((null choice)
4728        (ti::temp-buffer tinypgp-:buffer-tmp 'clear))
4729       (t
4730        (error "TinyPgp: No such mode '%s'" choice))))
4731
4732     (with-current-buffer buffer
4733       (defconst font-lock-mode nil)
4734       (defconst lazy-lock-mode nil)
4735       ;;  one time scratch buffer
4736       (buffer-disable-undo (current-buffer)))
4737
4738     buffer))
4739
4740 ;;; ----------------------------------------------------------------------
4741 ;;;
4742 (defun tinypgp-show-buffer-general (type)
4743   "Pop to buffer TYPE."
4744   (let ((buffer
4745          (cond
4746           ((eq type 'comint)  (tinypgp-comint-buffer))
4747           ((eq type 'debug)   tinypgp-:debug-buffer)
4748           ((eq type 'finger)  tinypgp-:buffer-tmp-finger)
4749           ((eq type 'http)    tinypgp-:buffer-tmp-http)
4750           ((eq type 'shell)   tinypgp-:buffer-tmp-shell)
4751           ((eq type 'tmp)     tinypgp-:buffer-tmp))))
4752     (cond
4753      ((null buffer)
4754       (error "TinyPgp: Wrong type '%s' " type))
4755      ((get-buffer buffer)
4756       (pop-to-buffer buffer))
4757      (t
4758       (message "Buffer does not exist: '%s'" buffer)))))
4759
4760 (defun tinypgp-show-buffer-comint ()
4761   "Show buffer."
4762   (interactive) (tinypgp-show-buffer-general 'comint))
4763
4764 (defun tinypgp-show-buffer-debug ()
4765   "Show buffer."
4766   (interactive) (tinypgp-show-buffer-general 'debug))
4767
4768 (defun tinypgp-show-buffer-finger ()
4769   "Show buffer."
4770   (interactive) (tinypgp-show-buffer-general 'finger))
4771
4772 (defun tinypgp-show-buffer-http ()
4773   "Show buffer."
4774   (interactive) (tinypgp-show-buffer-general 'http))
4775
4776 (defun tinypgp-show-buffer-shell ()
4777   "Show buffer."
4778   (interactive) (tinypgp-show-buffer-general 'shell))
4779
4780 (defun tinypgp-show-buffer-tmp ()
4781   "Show buffer."
4782   (interactive) (tinypgp-show-buffer-general 'tmp))
4783
4784 ;;}}}
4785 ;;{{{ pubring: misc
4786
4787 ;;; ----------------------------------------------------------------------
4788 ;;;
4789 (defun tinypgp-pubring-elt ()
4790   "Return active pubring ELT."
4791   (let* ((ring  (tinypgp-expand-file-name tinypgp-:pubring-now))
4792          kring
4793          ret)
4794     (dolist (elt (tinypgp-pubring-table))
4795       (setq kring (nth 1 elt))
4796       (cond
4797        ((stringp kring)
4798         ;; Second element must be filename string
4799         (when (string= ring (tinypgp-expand-file-name kring))
4800           (setq ret elt)
4801           (return)))
4802        (t
4803         (error "Invalid format: tinypgp-:pubring-table, please check."))))
4804
4805     (unless ret
4806       (error "tinypgp-:pubring-table, can't find tinypgp-:pubring-now?"))
4807
4808     ret))
4809
4810 ;;; ----------------------------------------------------------------------
4811 ;;;
4812 (defun tinypgp-pubring-ask (&optional msg)
4813   "Ask pubring with MSG and offer 'alias' completion.
4814
4815 Return:
4816   nil
4817   pubring file"
4818   (let (ret)
4819     (setq ret
4820           (tinypgp-pubring-complete
4821            (if msg
4822                msg
4823              (format
4824               "Ok to use pubring '%s' [ret=yes]? "
4825               (or (tinypgp-pubring-file2alias tinypgp-:pubring-now)
4826                   "<unknown>")))))
4827
4828     (if (not (ti::nil-p ret))
4829         (setq ret (tinypgp-pubring-alias2file ret))
4830       (setq ret nil))
4831
4832     (tinypgpd "tinypgp-pubring-ask out: " ret )
4833     ret))
4834
4835 ;;; ----------------------------------------------------------------------
4836 ;;;
4837 (defun tinypgp-pubring-in-use-confirm ()
4838   "Change pubring if it is not the first entry in `tinypgp-pubring-table'.
4839 Ask confirmation for the change. The calling
4840 function should bound variable `tinypgp-pubring-table' locally,
4841 because it may be changed here.
4842
4843 References:
4844   `tinypgp-save-state-macro'"
4845   (let ((first  (tinypgp-expand-file-name
4846                  (nth 1 (car (tinypgp-pubring-table)))))
4847         (now    (tinypgp-expand-file-name tinypgp-:pubring-now)))
4848     (when (not (string= first now))
4849       (setq now (tinypgp-pubring-ask))
4850       (when now
4851         (setq tinypgp-:pubring-now now)
4852         (tinypgpd "tinypgp-pubring-in-use-confirm out: "
4853                   tinypgp-:pubring-now)))))
4854
4855 ;;}}}
4856 ;;{{{ pubring: interactive
4857
4858 ;;; ----------------------------------------------------------------------
4859 ;;;
4860 (defun tinypgp-pubring-display ()
4861   "Show current pubring in use."
4862   (interactive)
4863   (message "Current pubring: %s" tinypgp-:pubring-now)
4864   (sit-for 1)) ;; If drawn from menu, the mouse move wipes it away..
4865
4866 ;;; ----------------------------------------------------------------------
4867 ;;;
4868 (defun tinypgp-pubring-set-current (alias)
4869   "Set active pubring using ALIAS and update mode line."
4870   (interactive (list (tinypgp-pubring-complete "Set active pubring to: ")))
4871   (when alias
4872     (setq tinypgp-:pubring-now
4873           (tinypgp-expand-file-name (nth 1 (assoc alias
4874                                                   (tinypgp-pubring-table)))))
4875
4876     (if (not (file-exists-p tinypgp-:pubring-now))
4877         (error "No pubring file %s" tinypgp-:pubring-now))
4878
4879     (tinypgpd "tinypgp-pubring-set-current out: " alias tinypgp-:pubring-now)
4880
4881     (tinypgp-update-modeline)
4882     (if (interactive-p)
4883         (tinypgp-pubring-display))))
4884
4885 ;;}}}
4886 ;;{{{ user: general, interactive
4887
4888 ;;; ----------------------------------------------------------------------
4889 ;;;
4890 (defun tinypgp-user-in-use-confirm (&optional msg)
4891   "Change user if Primary user is not active ask confirmation with MSG."
4892   (let (ans)
4893     (setq msg
4894           (or
4895            msg
4896            "Not primary, change user id to [empty = no change]: "))
4897     (if (and (not (string-match
4898                    (regexp-quote tinypgp-:user-primary) tinypgp-:user-now))
4899              (not
4900               (ti::nil-p
4901                (setq ans (read-from-minibuffer msg tinypgp-:user-now)))))
4902         (setq tinypgp-:user-now ans))))
4903
4904 ;;; ----------------------------------------------------------------------
4905 ;;;
4906 (defun tinypgp-user-display ()
4907   "Show active user."
4908   (interactive)
4909   (ti::read-char-safe-until (concat "Current user: " tinypgp-:user-now)))
4910
4911 ;;; ----------------------------------------------------------------------
4912 ;;;
4913 (defun tinypgp-user-set-current (user)
4914   "Set active USER."
4915   (interactive
4916    (list
4917     (completing-read
4918      (format "[%s] Set pgp user to: " tinypgp-:user-now)
4919      tinypgp-:pgp-email-list-completions
4920      nil nil nil
4921      'tinypgp-:history-email)))
4922
4923   (if (ti::nil-p user)
4924       (error "Invalid input."))
4925
4926   (setq tinypgp-:user-now user)
4927   (if (interactive-p)
4928       (tinypgp-user-display)))
4929
4930 ;;}}}
4931 ;;{{{ key: handling
4932
4933 ;;; ----------------------------------------------------------------------
4934 ;;;
4935 (defun tinypgp-key-cache (mode &optional data1 data2 data3)
4936   "Function to control caching of key-id and.
4937 The cache hook tells if the entry should be cached when MODE is 'put
4938
4939 When inserting new keys into cache, every 3rd key triggers saving
4940 the cache to disk.
4941
4942 References:
4943
4944   `tinypgp-:key-cache'
4945   `tinypgp-:key-cache-last'
4946
4947 Input MODE:
4948
4949   'get  look for data1 from cache and return cache entry or nil
4950   'put  cache entries data1, data2, data3
4951   'del  remove named entry from cache. Do nothing if no such entry.
4952
4953 Data arguments:
4954
4955   DATA1 DATA2 DATA3
4956
4957 Return:
4958
4959   nil
4960   cache entry"
4961   (let ((last           tinypgp-:key-cache-last)
4962         (data1-orig     data1)          ;Email may be changed
4963         (debug          nil)            ;developer's manual debug flag
4964         (fid            "tinypgp-key-cache: ")
4965         ret)
4966
4967     ;;  The cache is used only if user has multiple pubrings
4968     (when (tinypgp-pubring-many-p)
4969
4970       ;; .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. fast case . .
4971       ;;  Remember that modeline calls us many times
4972
4973       (cond                             ;Is the entry in QUICK cache?
4974        ((and last                     ;bypass everything if we find it
4975              (eq mode 'get)       ;many time we call 'get successively
4976              (string= (car last) data1))
4977         (setq ret (nth 1 (nth 1 last)))
4978
4979         (if debug
4980             (tinypgpd fid "fast get" data1 ret )))
4981
4982        (t
4983         ;; .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. . normal case  ..
4984
4985 ;;;    (ti::d! "C in: " mode data1 data2)
4986
4987         (setq data1 (ti::remove-properties data1))
4988
4989         (if data2
4990             (setq data2 (ti::remove-properties data2)))
4991
4992         (if debug
4993             (tinypgpd fid "in:" 'MODE  mode 'DATA1 data1 'DATA2 data2))
4994
4995 ;;;    (ti::d! "Cache name>>" data1 data2)
4996
4997         ;;  Note: I used elp.el to check if the obarray method
4998         ;;  would be faster, but it seems that at least for single entry
4999         ;;  the list implementation is faster? I was suprised..
5000
5001         (if (not (listp tinypgp-:key-cache)) ;make sure this is a list
5002             (setq tinypgp-:key-cache nil))
5003
5004         (cond
5005
5006          ((eq mode 'get)
5007           (when (setq ret (assoc data1 tinypgp-:key-cache))
5008             (setq tinypgp-:key-cache-last  (list data1-orig ret))
5009             (setq ret (nth 1 ret))))
5010
5011          ((eq mode 'del)
5012           (if (setq ret (assoc data1 tinypgp-:key-cache))
5013               (adelete 'tinypgp-:key-cache (car ret))))
5014
5015          (t
5016           (if (and (null (assoc data1 tinypgp-:key-cache)) ;;  Already there ?
5017                    (< (length  tinypgp-:key-cache) 300))   ;Hard limit
5018               (push (list data1 data2 data3) tinypgp-:key-cache ))
5019
5020           ;;  Save every 3rd new entry.
5021
5022           (if (eq (% (length tinypgp-:key-cache) 3) 0)
5023               (tinypgp-key-cache-save)))))))
5024
5025     (if debug
5026         (tinypgpd fid "out: RET" ret))
5027
5028     ret))
5029
5030 ;;; ----------------------------------------------------------------------
5031 ;;;
5032 (defun tinypgp-key-cache-save (&optional load)
5033   "Save or LOAD the key cache file.
5034 If the underlying cache file has recent copy; the SAVE is not
5035 performed, but the newer copy reloaded and evaluated.
5036
5037 Signal no erro if LOAD cannot find cache file."
5038   (let* ((fid   "tinypgp-key-cache-save:")
5039          (file  (or (tinypgp-backend-file tinypgp-:file-key-cache)
5040                     (error "TinyPgp: Internal cache error")))
5041          (list  tinypgp-:key-cache)
5042          (len   (length list))
5043          (olen  (tinypgp-hash 'cache 'get 'len nil 'global))
5044          buffer
5045          done)
5046     (tinypgpd fid "in: FILE" file 'LEN len 'OLEN olen 'LOAD-FLAG load)
5047
5048     (cond
5049      (load
5050       (when (file-exists-p file)
5051         (with-current-buffer (find-file-noselect file)
5052           (if (fboundp 'eval-buffer)    ;XE 19.14
5053               (ti::funcall 'eval-buffer)
5054             (ti::funcall 'eval-current-buffer))
5055           (setq done t))))
5056
5057      ;; ......................................................... save ...
5058      (t
5059       ;;   There may be several emacsen running, and they may have saved the
5060       ;;   cache too. Reload the file if it is newer that the buffer
5061       ;;   in this emacs (it has been saved by some other emacs)
5062
5063       (when (and (buffer-live-p (setq buffer (find-buffer-visiting file)))
5064                  (with-current-buffer buffer (ti::file-changed-on-disk-p)))
5065         (with-current-buffer buffer
5066           (revert-buffer t t)           ;No confirmations
5067           (if (fboundp 'eval-buffer)    ;XE 19.14
5068               (ti::funcall 'eval-buffer)
5069             (ti::funcall 'eval-current-buffer)
5070             (setq done t))))
5071
5072       (when (and (null done)
5073                  ;; Something to save? Has Length changed
5074                  (or (not (eq len olen))
5075                      ;;  Not yet saved?
5076                      (not (file-exists-p file))))
5077         (tinypgp-hash 'cache 'put 'len len 'global)
5078         (with-current-buffer (find-file-noselect file)
5079           (erase-buffer)
5080           (insert ";;\n;;\tEmacs TinyPgp.el: key cache file\n;;\n\n")
5081           (insert "(defconst tinypgp-:key-cache\n  '(\n")
5082           (dolist (elt list) (insert "    " (prin1-to-string elt) "\n"))
5083           (insert "    ))\n\n;; End of file\n")
5084           (save-buffer)))))
5085     done))
5086
5087 ;;; ----------------------------------------------------------------------
5088 ;;;
5089 (defun tinypgp-key-cache-display (&optional verb)
5090   "Print contents of cache. VERB."
5091   (interactive)
5092   (tinypgp-key-cache-save) ;;  Save latest first
5093   (let* ((fid    "tinypgp-key-cache-display:")
5094          (file   (tinypgp-backend-file tinypgp-:file-key-cache))
5095          (buffer (or (find-buffer-visiting file)
5096                      (and (file-exists-p file)
5097                           (find-file-noselect file)))))
5098     (tinypgpd fid file buffer)
5099     (if (null buffer)
5100         (error "Can't display %s" file)
5101       (display-buffer buffer))))
5102
5103 ;;; ----------------------------------------------------------------------
5104 ;;;
5105 (defun tinypgp-key-cache-remove-entry-last ()
5106   "Clear last fast cache entry."
5107   (interactive)
5108   (setq tinypgp-:key-cache-last nil)
5109   (if (interactive-p)
5110       (message "Cleared last cache entry.")))
5111
5112 ;;; ----------------------------------------------------------------------
5113 ;;;
5114 (defun tinypgp-key-cache-remove-entry (string &optional raw-entry)
5115   "Read email addresses from string and remove it from cache.
5116
5117 Input:
5118   STRING     String ==> email address is picked from it
5119   RAW-ENTRY  if nono-nil, then bypass call to
5120              `tinypgp-:read-email-after-hook' which may change the string"
5121   (let* ((fid "tinypgp-key-cache-remove-entry: ")
5122          list)
5123     (tinypgpd fid "in:" raw-entry string )
5124
5125     (when (tinypgp-pubring-many-p)
5126
5127       (cond
5128        (raw-entry
5129         (tinypgp-key-cache 'del string))
5130
5131        (t
5132         (or (setq list (ti::mail-email-from-string string))
5133             (setq list (list string)))
5134         (dolist (elt list)
5135           (when elt ;; Should we change the keyId that is read from field?
5136             (setq elt (car (tinypgp-key-id-conversion elt))))
5137           (tinypgp-key-cache 'del elt))))
5138       ;; Clear fast cache
5139       (tinypgp-key-cache-remove-entry-last))))
5140
5141 ;;; ----------------------------------------------------------------------
5142 ;;;
5143 (defun tinypgp-key-generate
5144   (key-bit-choice user-id pass-phrase &optional verb)
5145   "Generate new key. Only default key sizes are supported.
5146
5147 Input:
5148   KEY-BIT-CHOICE        1,2 or 3
5149   USER-ID
5150   PASS-PHRASE
5151   VERB"
5152   (interactive
5153    (let* ((key-list
5154            '(("512"   1)
5155              ("768"   2)
5156              ("1024"  3)))
5157           key
5158           user
5159           pass
5160           ans)
5161
5162      (setq key (completing-read "Key size: " key-list nil 'match-it "768"))
5163      (if (null (setq key (tinypgp-alias2name key key-list)))
5164          (error "No key choice found."))
5165
5166      (setq user (read-from-minibuffer "User id for your public key: "))
5167      (if (ti::nil-p user)
5168          (error "Empty user id."))
5169
5170      (setq pass (ti::compat-read-password "Pass phrase: "))
5171      (if (ti::nil-p pass)
5172          (error "Empty pass phrase"))
5173
5174      (list key user pass)))
5175
5176   ;; ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...  body . .
5177
5178   (if (not (and (memq key-bit-choice '(1 2 3))
5179                 (stringp user-id)
5180                 (stringp pass-phrase)))
5181       (error "Arg error."))
5182
5183   (let* ( ;; (BCMD  (tinypgp-binary-get-cmd 'key-generate))
5184          ;; (cmd   (tinypgp-cmd-compose BCMD user-id pass-phrase))
5185          ret)
5186     (ti::verb)
5187     (tinypgp-unfinished-function)
5188
5189     (tinypgp-save-state-macro
5190      (if verb  (tinypgp-pubring-in-use-confirm)))
5191
5192     (if verb
5193         (message "Generating new user-id...done."))
5194
5195     ret))
5196
5197 ;;}}}
5198
5199 ;;{{{ misc: auto-action
5200
5201 ;;; ..................................................... &auto-action ...
5202
5203 ;;; ----------------------------------------------------------------------
5204 ;;;
5205 (defun tinypgp-auto-action-on-modeline-p ()
5206   "Check if mode line string say that auto action in 'on'."
5207   (and (stringp tinypgp-:mode-name)
5208        (string-match "!$\\|!k" tinypgp-:mode-name)))
5209
5210 ;;; ----------------------------------------------------------------------
5211 ;;;
5212 (defun tinypgp-auto-action-on-p ()
5213   "Check is user has allowed action and if action exists."
5214   ;;  There is no auto action for read only buffer like RMAIL
5215   (tinypgpd "tinypgp-auto-action-on-p: "
5216             tinypgp-mode
5217             (tinypgp-hash 'auto-action 'def 'user-mode)
5218             (tinypgp-hash 'auto-action 'get 'user-mode))
5219
5220   (when (and (null buffer-read-only)
5221              tinypgp-mode)
5222     (unless (tinypgp-hash 'auto-action 'def 'user-mode)
5223       ;;  Not defined, initialize
5224       (tinypgpd "tinypgp-auto-action-on-p: SET DEFAULT")
5225       (tinypgp-hash 'auto-action 'put 'user-mode t))
5226     (tinypgp-auto-action-p 'read-hash)))
5227
5228 ;;; ----------------------------------------------------------------------
5229 ;;;
5230 (defun tinypgp-auto-action-defeat-p ()
5231   "Check if auto action should be cancelled."
5232   ;;  Forget mime multiparts/PGP signed.
5233   (ti::mail-mime-maybe-p))
5234
5235 ;;; ----------------------------------------------------------------------
5236 ;;;
5237 (defun tinypgp-auto-action-verbose ()
5238   "Show auto-action entry to user.
5239 If auto action is found it is also available from `tinypgp-:register'."
5240   (interactive)
5241   (let* (elt)
5242     (tinypgpd "tinypgp-auto-action-verbose in:")
5243
5244     (cond
5245      ((ti::mail-mime-maybe-p)
5246       (message "TinyPgp;  Looks like MIME message, no auto action allowed"))
5247
5248      ((tinypgp-auto-action-multiple-addresses-p 'force)
5249       (message "TinyPgp; encryption to multiple recipients pending."))
5250
5251      ((setq elt (tinypgp-auto-action-p))
5252       (message "TinyPgp; Auto-action triggers: %s" (prin1-to-string elt))
5253       (set-register tinypgp-:register (prin1-to-string elt)))
5254
5255      (t
5256       (message "TinyPgp; There is no auto action that would activate.")))
5257     (tinypgp-update-modeline)))
5258
5259 ;;; ----------------------------------------------------------------------
5260 ;;;
5261 (defun tinypgp-auto-action-update-modeline ()
5262   "Do auto action check and update mode line."
5263   (tinypgp-auto-action-p)
5264   (tinypgp-update-modeline))
5265
5266 ;;; ----------------------------------------------------------------------
5267 ;;;
5268 (defun tinypgp-auto-action-p (&optional read-hash)
5269   "Check if auto-action entry is defined for current (email) buffer.
5270 If buffer is read only, this does nothing.
5271 Any MIME message in buffer suppresses auto-action.
5272
5273 Note:
5274
5275   Multiple recipients are not checked, Only To address.
5276   See `tinypgp-auto-action-multiple-addresses-p' for that.
5277
5278 References:
5279
5280   `tinypgp-:auto-action-table'
5281
5282 Input:
5283
5284   READ-HASH     non-nil instructs to read the value
5285                 from storage, if the TO: address hasn't changed.
5286                 This is faster than evaluating the list every time.
5287
5288 Return:
5289
5290   elt           entry from action table"
5291   (let ( ;; (EVAL-OR-STRING  SIGN-FLAG [ENCRYPT-FLAG] [KEYRING])
5292         (fid    "tinypgp-auto-action-p: ")
5293         (tbl    tinypgp-:auto-action-table)
5294
5295         ;;   We don't enable this because timer calls us
5296         ;;   Only when we debug the function
5297
5298         (debug  t)
5299
5300         ;;  These tags must be broken in this file so that TM won't get upset
5301         ;;  seeing them
5302         ;;
5303         ;; -- } - <<signed>>
5304         ;; -- } - <<encrypted>>
5305
5306         (mime-p  (ti::re-search-check "--[}]-<<"))
5307
5308         user-mode
5309         to-field
5310         val
5311         ret)
5312
5313     ;;  This function is called from a timer process to update the
5314     ;;  modeline, that's why we can't afford to rescan the auto-action
5315     ;;  list all the time: it takes too much time.
5316     ;;
5317     ;;  Instead, we store the found ACTION to hash table and read the
5318     ;;  hash entry. The drawback is that if user goes and changes
5319     ;;  the auto action table, we can't tell about it in the modeline.
5320     ;;
5321     ;;  Used local hash properties on variable 'auto-action
5322     ;;  'user-mode      bool    t = ok, nil = defeated by user
5323     ;;  'to-field       string  to field contents
5324     ;;  'elt            lisp    stored auto action.
5325
5326     ;;  If not yet defined, set the auto action to 't'
5327     ;;  User may defeat the action manually.
5328
5329     (if (tinypgp-hash 'auto-action 'def 'user-mode)
5330         (setq user-mode (tinypgp-hash 'auto-action 'get 'user-mode))
5331       (tinypgp-hash 'auto-action 'put 'user-mode t)
5332       (setq user-mode t))
5333
5334     ;;  Should always be a string otherwise lot of code breaks.
5335
5336     (unless (stringp tinypgp-:user-now)
5337       (message "\
5338 Tinypgp: Warning, tinypgp-:user-now is not a string. Fixing...")
5339       (sit-for 1)
5340       (setq tinypgp-:user-now (user-login-name)))
5341
5342     ;;  TO FIELD: see what we have in the hash table
5343
5344     (setq val (tinypgp-hash 'auto-action 'get 'to-field))
5345
5346     (when debug
5347       (tinypgpd fid
5348                 "read-only"       buffer-read-only
5349                 "USER-MODE"       user-mode
5350                 "mail"            (ti::mail-mail-p)
5351                 "pgp"             (ti::mail-pgp-p)
5352                 "MIME"            (ti::mail-mime-maybe-p) mime-p
5353                 "remail"          tinypgp-:r-mode-indication-flag
5354                 "READ HASH"       read-hash
5355                 "to-field hash"   val
5356                 "to-field"        (mail-fetch-field "to")))
5357
5358     (when (and (ti::mail-mail-p)
5359                (null buffer-read-only)
5360                (cond
5361                 ((or (ti::mail-mime-maybe-p) mime-p)
5362                  ;;  MIME found, defeat auto action immediately.
5363                  ;;
5364                  (tinypgp-hash 'auto-action 'put 'elt nil)
5365                  nil)
5366                 (t t))
5367                ;;
5368                ;;  only if there is no previous PGP,
5369                ;;  If there is PGP, let go through is there is
5370                ;;  remailer message Eg. newnym account create where
5371                ;;  you send you PGP key in buffer.
5372                ;;
5373                (if (ti::mail-pgp-p)
5374                    (if tinypgp-:r-mode-indication-flag
5375                        t nil)
5376                  t)
5377
5378                (not (ti::nil-p (setq to-field (mail-fetch-field  "to"))))
5379                (not (string-match "," to-field)) ;skip multiple addresses
5380                (ti::nil-p (mail-fetch-field "cc")))
5381
5382       ;; .................................................. hash check ...
5383
5384       (cond
5385        ((and read-hash
5386              val                        ;previous TO field in HASH ?
5387              (string= to-field val)) ;compare previous with current TO
5388         (setq val   (tinypgp-hash 'auto-action 'get 'elt))
5389         (when debug (tinypgpd fid "hash ret"))
5390         (setq ret val))
5391
5392        ;; .................................................. raw check ...
5393
5394        (t
5395
5396         ;; Empty field with spaces does not come here
5397         ;; To field has changed, we must calculate new entry
5398         ;; OR the hash-get wasn't set.
5399
5400         (tinypgp-hash 'auto-action 'put 'to-field to-field)
5401         (tinypgp-hash 'auto-action 'put 'elt nil)
5402         (when debug (tinypgpd fid "evaluate"))
5403
5404         ;; First check BBDB entry
5405
5406         (setq ret (tinypgp-bbdb-entry))
5407         (when debug (tinypgpd fid to-field "BBDB" ret))
5408
5409         ;; And this table overrrides bbdb
5410
5411         (dolist (elt tbl)
5412           (setq val  (nth 0  elt))
5413           (when debug (tinypgpd fid "action tbl" val))
5414           (when (or                     ;Try to match
5415                  (and (stringp val)
5416                       (string-match val to-field))
5417                  (and (symbolp val) (not (ti::bool-p val))
5418                       (eval val)))
5419             (setq ret elt)
5420             (return)))
5421
5422         (if ret
5423             (tinypgp-hash 'auto-action 'put 'elt ret))))) ;Save it!
5424
5425     (if debug
5426         (tinypgpd fid "RET" ret))
5427     ret))
5428
5429 ;;; ----------------------------------------------------------------------
5430 ;;;
5431 (defun tinypgp-auto-action ()
5432   "Determine right auto action for mail message.
5433 If auto-action has been disabled or if `tinypgp-mode' is off,  do nothing.
5434
5435 References:
5436
5437   `tinypgp-:header-sign-table'
5438   `tinypgp-:auto-action-table'
5439   `tinypgp-:auto-action-defeat-hook'"
5440   (tinypgpd "tinypgp-auto-action: function entry")
5441   (let ((fid            "tinypgp-auto-action: ")
5442         (umode          (tinypgp-hash 'auto-action 'get 'user-mode))
5443         (multi-flag     (tinypgp-auto-action-multiple-addresses-p 'force))
5444         (pgp-p          (ti::mail-pgp-p))
5445         to-field
5446         sign enc mime-mua xpgp keyr
5447         email
5448         len
5449         elt)
5450
5451     (tinypgpd fid 'user-mode umode 'multi-flag multi-flag 'pgp-p pgp-p)
5452
5453     (when tinypgp-mode
5454       (run-hooks 'tinypgp-:auto-action-before-hook)
5455
5456       (cond
5457        ;; ............................................ user defeat ...
5458
5459        ((or pgp-p
5460             (run-hook-with-args-until-success
5461              'tinypgp-:auto-action-defeat-hook))
5462         (tinypgpd fid "defeated")
5463         nil)
5464
5465        ;; ........................................... nymserver-cc ...
5466
5467        ((and (tinypgp-nymserver-mail-p)
5468              (tinypgp-nymserver-send))  ;Maybe no multi-CC ?
5469         (tinypgpd fid "Nymserver"))
5470
5471        ;; ............................................... defeated ...
5472
5473        ((not umode)                     ;User has defeated the action
5474         (tinypgpd fid "Umode")
5475         nil)
5476
5477        ;; ............................................ encrypt-to-many ...
5478
5479        (multi-flag
5480         (tinypgpd fid "Multi")
5481         (tinypgp-auto-action-multiple-addresses))
5482
5483        ;; ............................................ auto-action ...
5484
5485        ((and (not (ti::nil-p (setq to-field  (mail-fetch-field   "to"))))
5486
5487              ;;  The Addresses must be expanded so that they have @
5488
5489              (string-match "@" to-field)
5490
5491              ;; Force reading real action. If user has made changes
5492              ;; in his rc file; this guarrantees that we see them.
5493
5494              (setq elt (tinypgp-auto-action-p))
5495
5496              ;;  returns a list of email strings
5497
5498              (setq email (ti::mail-email-from-string to-field)))
5499
5500         (tinypgpd fid "--Action--" 'TO to-field 'EMAIL email 'ELT elt)
5501
5502         (setq len  (length elt)
5503               sign (nth 1  elt)
5504               keyr tinypgp-:pubring-now)
5505
5506         ;;  Should we change the key-id that is read from field?
5507
5508         (setq email (car-safe (tinypgp-key-id-conversion email)))
5509
5510         ;;  optional fields
5511
5512         (setq enc        (if (> len 2) (nth 2 elt))
5513               mime-mua   (if (> len 3) (nth 3 elt))
5514               xpgp       (if (> len 4) (nth 4 elt))
5515               keyr       (tinypgp-expand-file-name
5516                           (cond
5517                            ((> len 5)
5518                             (nth 5 elt))
5519                            ((tinypgp-key-find-by-keyrings email))
5520                            (t
5521                             tinypgp-:pubring-now))))
5522
5523         ;;  XE byteCompiler 19.14 has bug here, it reports that
5524         ;;  variable 'xpgp bound but not referenced, allthoug
5525         ;;  it is used in 'let' stement underneath! The following
5526         ;;  silences byteCompiler.
5527
5528         (if (null xpgp) (setq xpgp nil))
5529
5530         (tinypgpd fid "addr" email "ENC" enc "SIGN" sign "XP" xpgp
5531                   "KEY" keyr "MUA" mime-mua elt)
5532
5533         (when (and mime-mua
5534                    (null (ti::mail-mime-tm-featurep-p))
5535                    (null (ti::mail-mime-semi-featurep-p)))
5536           (setq mime-mua nil)
5537           (message "\
5538 Auto-action: PGP/MIME requested but no TM/SEMI mime support present.")
5539           (sit-for 2))
5540
5541         (cond
5542          (mime-mua
5543
5544           ;;  These only add the TAGS into the buffer. SEMI/TM
5545           ;;  hook handles the actual work of turning then to PGP/MIME
5546           ;;  --> It calls TinyPgp to do it.
5547
5548           (if sign (ti::mail-mime-sign-region))
5549           (if enc  (ti::mail-mime-encrypt-region)))
5550          (t
5551           (tinypgp-save-state-macro
5552            (if sign   (setq tinypgp-:user-now
5553                             (if (and (not (ti::bool-p sign))
5554                                      (symbolp sign)) ;One pass encrypt/sign
5555                                 (symbol-name sign)
5556                               sign)))
5557            (if keyr   (setq tinypgp-:pubring-now keyr))
5558            (setq tinypgp-:xpgp-signing-mode xpgp)
5559
5560            (tinypgpd fid "SIGN" sign "KEY" keyr tinypgp-:user-now "KRING" keyr)
5561
5562            ;; ............................................ do encrypt ...
5563
5564            (when enc
5565              (when (and (not (ti::bool-p sign)) (symbolp sign))
5566                (tinypgp-password-set
5567                 (format "[%s] Auto-action sign password: "
5568                         tinypgp-:user-now)))
5569              (tinypgp-encrypt-mail
5570               email
5571               (not 'register-insert)
5572               (if (and (not (ti::bool-p sign)) (symbolp sign))
5573                   '1pass)
5574               nil
5575               'verb))
5576
5577            ;; ......................................... possibly sign ...
5578
5579            (when (and sign (stringp sign))
5580              (tinypgp-password-set
5581               (format "Auto-action, Sign pass phrase %s: " tinypgp-:user-now))
5582
5583              ;; The previous function call may have changed the user,
5584              ;; keep the pubring also in sync
5585
5586              (tinypgp-pubring-change-to-current)
5587              (call-interactively 'tinypgp-sign-mail))))))
5588
5589        ;; ........................................... auto-encrypt ...
5590        ;; If there is no auto action, we check if we have previously
5591        ;; encrypted to that person.
5592
5593        ((and (null (ti::mail-pgp-p))    ;No previsou pgp
5594              (not (ti::nil-p (setq to-field  (mail-fetch-field   "to"))))
5595              (setq elt
5596                    (tinypgp-key-find-by-cache
5597                     (car-safe (ti::mail-email-from-string to-field)))))
5598         (tinypgpd fid "encrypt guess" to-field elt)))
5599
5600       ;;  We actually do nothing here...but the code is ready
5601       ;;  (tinypgp-encrypt-mail email)
5602
5603       (tinypgpd fid "out:" (current-buffer))
5604
5605       ;; ..................................................... restore ...
5606
5607       ;; If this was nym create request, restore pgp user
5608       ;; - If there are these buffer local variables and PGP msg found
5609       ;; - If saver "now" is "now"; ie. user hasn't changed active user
5610       ;;   after the create request was started.
5611       ;; - THEN restore the original pgp user
5612
5613       (when (and (boundp 'tinypgp-pgp-user-original)
5614                  (boundp 'tinypgp-pgp-user-now)
5615                  (ti::mail-pgp-p))
5616         (let* ((orig  (symbol-value 'tinypgp-pgp-user-original))
5617                (now   (symbol-value 'tinypgp-pgp-user-now)))
5618           (if (string= now tinypgp-:user-now)
5619               (setq tinypgp-:user-now orig))))
5620
5621 ;;;    (ti::d! "AUTO-ACT done" email)
5622       elt)))
5623
5624 ;;; ----------------------------------------------------------------------
5625 ;;;
5626 (defun tinypgp-auto-action-multiple-addresses-p (&optional force)
5627   "Check multiple address auto-action. Optionally FORCE raw check."
5628   (and (null (tinypgp-nymserver-mail-p))
5629        (tinypgp-auto-action-multiple-addresses 'check force)))
5630
5631 ;;; ----------------------------------------------------------------------
5632 ;;;
5633 (defun tinypgp-auto-action-multiple-addresses (&optional mode force)
5634   "Determine if multiple address encryption will be done.
5635 Function does nothing if buffer is read only
5636
5637 Input:
5638
5639   MODE      If 'check, then return nil or t if auto-action
5640             is in progress. Any other value starts auto-encryption
5641             if the conditions are met.
5642
5643   FORCE     Force re-evaluating the buffer check (normally read result
5644             from stored value in hash table)
5645
5646 Return:
5647
5648   non-nil       auto action in progress. All recipientsents have PGP
5649   LIST          '(email email ..) There were many recipients
5650                 but not all members members have PGP. This is list of email
5651                 addresses that had PGP.
5652   nil
5653
5654 References:
5655
5656   `tinypgp-:auto-action-encrypt-regexp'
5657   `tinypgp-:auto-action-encrypt-ok-hook'"
5658   (let* ((re    tinypgp-:auto-action-encrypt-regexp)
5659          (fid   "tinypgp-auto-action-multiple-addresses: ")
5660          (debug nil)                    ;func is Called by timer...
5661          hsize-prev
5662          hsize
5663          list
5664          len
5665          ret
5666          pgp-ok-list
5667          pgp-nok-list)
5668
5669     ;;  Because this function is called from timer process, the
5670     ;;  'check must be very quick in order not to decrease
5671     ;;  emacs performance
5672     ;;
5673     ;;  'many-addr-hsize
5674     ;;    We count the length of the header area and put that value
5675     ;;    into property. If the size has changed, we reread
5676     ;;    the To,CC,BCC headers again and do the checking
5677     ;;
5678     ;;    If the headers have not changed, then we don't do time
5679     ;;    consuming parse, but assume thet 'many-addr-hsize value
5680     ;;    is valid (No changes compared to last parse)
5681     ;;
5682     ;;  'many-addr-stat
5683     ;;    Holds value t or nil if auto action should be engaged.
5684
5685     (if debug  (tinypgpd fid
5686                          "in: mode" mode
5687                          'force force
5688                          'mail  (ti::mail-mail-p)
5689                          'point (point) ))
5690
5691     (when (and (ti::mail-mail-p)        ;Only do in mail buffers
5692                (null buffer-read-only))
5693       (setq hsize       (ti::mail-header-area-size)
5694             hsize-prev  (tinypgp-hash 'auto-action 'get 'many-addr-hsize))
5695
5696       (when debug
5697         (tinypgpd fid
5698                   'hsize hsize
5699                   'prev hsize-prev
5700                   (ti::mail-get-all-email-addresses
5701                    nil tinypgp-:pgp-email-abbrev-list)
5702                   "point"
5703                   (point)))
5704
5705       (if force (setq hsize nil hsize-prev 1)) ;Re-evaluate.
5706
5707       (cond
5708        ;; .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .
5709        ((and (eq hsize hsize-prev)
5710              mode)
5711         ;; return the precalculated status
5712         ;;
5713         (setq ret (tinypgp-hash 'auto-action 'get 'many-addr-stat))
5714         (if debug (tinypgpd fid 'cond1-hash ret (point))))
5715
5716        ;; .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .
5717
5718        ((eq hsize hsize-prev)           ;Not check mode, do action
5719         (if debug (tinypgpd fid 'cond2-enc ret (point)))
5720         (if (and (tinypgp-hash 'auto-action 'get 'many-addr-stat)
5721                  (not (ti::mail-pgp-p))) ;No previous pgp
5722             (tinypgp-encrypt-mail-verbose)))
5723
5724        ;; .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. ..  recalculate . .
5725        ;; *) The size has changed, so update it immediately.
5726        ;; *) put initial value into the property, because we may not enter
5727        ;;    the case at all if list is empty
5728        ;;
5729        ;; The rest of the 'and' are real tests
5730
5731        ((and (prog1 t
5732                (tinypgp-hash 'auto-action 'put 'many-addr-hsize hsize)
5733                (tinypgp-hash 'auto-action 'put 'many-addr-stat nil))
5734              (setq list (ti::mail-get-all-email-addresses
5735                          nil tinypgp-:pgp-email-abbrev-list))
5736              (> (setq len  (length list)) 1))
5737         (if debug  (tinypgpd fid 'cond3 len list (point)))
5738 ;;;     (ti::d! "HZ" hsize (tinypgp-hash 'auto-action 'get 'many-addr-hsize))
5739
5740         ;; .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. do checking ..
5741         ;;  Is there regexp defined in the table ?
5742
5743         (when (stringp re)
5744           ;;  See if there is hit for all recipinets,
5745           ;;  then we want t'1o encrypt this mail.
5746           ;;
5747           ;;  Other times; this may be just regular CC mail
5748
5749           (dolist (elt list)
5750
5751             (when debug
5752               (tinypgpd fid 'dolist-match
5753                         (string-match re elt)
5754                         (if (string-match re elt)
5755                             (match-string 0 elt))
5756                         elt))
5757
5758             (if (string-match re elt)
5759                 (push elt pgp-ok-list)
5760               (push elt pgp-nok-list)))
5761
5762           (if debug  (tinypgpd fid (ti::mail-pgp-p)))
5763
5764           (tinypgp-hash 'auto-action 'put 'many-addr-ok-list  pgp-ok-list)
5765           (tinypgp-hash 'auto-action 'put 'many-addr-nok-list pgp-nok-list)
5766
5767           ;;  There must not be no PGP already in the buffer!
5768
5769           (if (ti::mail-pgp-p)
5770               (tinypgp-hash 'auto-action 'put 'many-addr-stat nil)
5771             (tinypgp-hash 'auto-action 'put 'many-addr-stat pgp-ok-list)))
5772
5773         (setq ret (tinypgp-hash 'auto-action 'get 'many-addr-stat))
5774
5775         ;; .. .. .. .. .. .. .. .. .. .. .. .. .. .. ..  return action ..
5776         (when (and ret (null mode))
5777           (setq pgp-ok-list  (tinypgp-hash 'auto-action 'get 'many-addr-ok-list)
5778                 pgp-nok-list (tinypgp-hash 'auto-action 'get 'many-addr-nok-list))
5779           (if (null pgp-nok-list)
5780               (tinypgp-encrypt-mail-verbose)
5781
5782             ;; #todo: send each message separately: those who have PGP
5783             ;; #todo: and those that don't? Hmm.. this function
5784             ;; is run from `mail-send-hook' so we have to send non-pgp first.
5785
5786             (message "TinyPgp: auto-action info, not all recipients have pgp")
5787             (sleep-for 2)
5788
5789             (if (y-or-n-p "\
5790 Would you like to send separate PGP and plain mail messages?")
5791                 (let* ((orig   (current-buffer))
5792                        (buffer (tinypgp-ti::temp-buffer 'mail "" "")))
5793                   (with-current-buffer buffer
5794                     (erase-buffer)
5795                     (insert-buffer orig)
5796                     (ti::mail-set-recipients pgp-nok-list pgp-ok-list 'cc-all)
5797 ;;;               (pop-to-buffer buffer)
5798                     (mail-send-and-exit nil))
5799                   ;; Now it's time to encrypt this message for recipients that
5800                   ;; do have pgp.
5801
5802                   (ti::mail-set-recipients pgp-ok-list pgp-nok-list)
5803                   (tinypgp-encrypt-mail (tinypgp-key-id-conversion pgp-ok-list)))))))
5804        )) ;; if-let
5805
5806     (if debug  (tinypgpd fid 'RET ret 'pgp-p (ti::mail-pgp-p) 'point (point) "\n"))
5807
5808     ;;  If we decided it was okay to send multiple encrypted message,
5809     ;;  let user say final word
5810
5811     (if (and ret tinypgp-:auto-action-encrypt-ok-hook)
5812         (setq ret (run-hook-with-args
5813                    tinypgp-:auto-action-encrypt-ok-hook
5814                    list)))
5815
5816     (if debug (tinypgpd fid 'after-user-hook ret))
5817
5818     ret))
5819
5820 ;;; ----------------------------------------------------------------------
5821 ;;;
5822 (defun tinypgp-auto-action-toggle (&optional mode verb)
5823   "If the auto action is detected for this buffer, toggle MODE on/off.
5824 Otherwise if no auto action is present, do nothing. VERB."
5825   (interactive)
5826   (let* ((act   (tinypgp-auto-action-p))
5827          val)
5828     (ti::verb)
5829     (if (null act)
5830         (if verb (message "TinyPgp: no action entry found for this buffer."))
5831       (setq val (tinypgp-hash 'auto-action 'get 'user-mode))
5832
5833       (ti::bool-toggle val mode)
5834       (tinypgp-hash 'auto-action 'put 'user-mode val)
5835       (tinypgp-update-modeline)
5836
5837       (if verb
5838           (message (format "TinyPgp auto action: %s"
5839                            (if (not val) "pending" "defeated")))))))
5840
5841 ;;}}}
5842 ;;{{{ misc: functions
5843
5844 ;;; ----------------------------------------------------------------------
5845 ;;;
5846 (defsubst tinypgp-require-final-newline ()
5847   "Make sure there is empty line at the end."
5848   (save-excursion
5849     (ti::pmax)
5850     (if (not (looking-at "^[ \t]*$"))
5851         (insert "\n"))))
5852
5853 ;;; ----------------------------------------------------------------------
5854 ;;;
5855 (defun tinypgp-xpgp-get-info ()
5856   "Return X-pgp info '((MIME-KEY  DATA) (MIME-K  DATA) ..) or nil.
5857 This function caches the read X-Pgp information so that the parsing
5858 doesn't take effect in every call. The cache will be expired if the buffer
5859 size has changed and the new data parsing will be done."
5860   (let* ((fid   "tinypgp-xpgp-get-info:")
5861          (size  (- (point-max) (point-min)))
5862          field
5863          list)
5864     (cond
5865      ((and (eq  size  (tinypgp-hash 'xpgp-info 'get 'size))
5866            (setq list (tinypgp-hash 'xpgp-info 'get 'data)))
5867       (tinypgpd fid "cache"))
5868      ((setq field  (mail-fetch-field "X-Pgp-signed"))
5869       (setq list   (ti::mail-mime-parse-header field 'downcase))
5870       (tinypgp-hash 'xpgp-info 'put 'size size)
5871       (tinypgp-hash 'xpgp-info 'put 'data list)))
5872     (tinypgpd fid (current-buffer) list)
5873     list))
5874
5875 ;;; ----------------------------------------------------------------------
5876 ;;;
5877 (defun tinypgp-xpgp-key-address (type &optional message)
5878   "Return TYPE (Finger or http) URL if can be found from X-Pgp header.
5879 Print optional MESSAGE if there is no such information.
5880
5881 TYPE can be
5882  'finger
5883  'http
5884
5885 Return:
5886  string
5887  nil"
5888   (let* ((elt (tinypgp-xpgp-get-info))
5889          ret)
5890     (when elt
5891       (cond
5892        ((and (eq type 'finger)
5893              (setq elt (assoc "address" elt)))
5894         (setq ret (nth 1 elt)))
5895        ((and (eq type 'http)
5896              (setq elt (assoc "url" elt)))
5897         (setq ret (nth 1 elt)))))
5898     (if message
5899         (message message))
5900
5901     ret))
5902
5903 ;;; ----------------------------------------------------------------------
5904 ;;;
5905 (defun tinypgp-header-sign-mode-toggle (&optional mode)
5906   "Toggle signing of selected headers `tinypgp-:header-sign-table' with MODE.
5907 When the mode if OFF, the `tinypgp-:header-sign-table' is ignored."
5908   (interactive)
5909   (let* ((sym 'tinypgp-:header-sign-table))
5910     ;; Not recorded; record original value
5911     ;;
5912     (if (null (get sym 'original))
5913         (put sym 'original (symbol-value sym)))
5914
5915     (cond
5916      ((or (memq mode '(0 -1))
5917           (symbol-value sym))
5918       (set sym nil)
5919       (message "Headers are not signed: tinypgp-:header-sign-table is ignored."))
5920      (t
5921       (set sym (get sym 'original))
5922       (message "Header list tinypgp-:header-sign-table is used.")))
5923     (tinypgp-update-modeline)))
5924
5925 ;;; ----------------------------------------------------------------------
5926 ;;;
5927 (defun tinypgp-header-list-show ()
5928   "See what headers will be signed for this message."
5929   (interactive)
5930   (tinypgp-header-sign-active-list 'display))
5931
5932 ;;; ----------------------------------------------------------------------
5933 ;;;
5934 (defun tinypgp-header-sign-active-list (&optional display)
5935   "See what headers we should sign. Optionally DISPLAY to user.
5936 Subject is the only safe field to sign when you for example
5937 send a message to some mailing list that may alter all other fields.
5938
5939 References:
5940   `tinypgp-:header-sign-table'"
5941   (let* ((list   tinypgp-:header-sign-table)
5942          to
5943          elt)
5944     (and list
5945          (setq to (or (mail-fetch-field  "To")
5946                       (mail-fetch-field  "Newsgroups")))
5947          (not (ti::nil-p to))
5948          (setq elt (ti::list-find list to)))
5949     (when display
5950       (cond
5951        ((ti::nil-p to)
5952         (message "Header sign info: Can't find field To or Newsgroups."))
5953        ((null elt)
5954         (message "Header sign info: To or Newsgroup header does not trigger."))
5955        (t
5956         (message "Header sign info: %s" (ti::list-to-string (nth 1 elt))))))
5957
5958     elt))
5959
5960 ;;; ----------------------------------------------------------------------
5961 ;;;
5962 (defun tinypgp-header-move-to-body (&optional opt1 opt2)
5963   "Move headers into body and anonymize them. See source for OPT1 and OPT2"
5964   (interactive)
5965   (ti::mail-pgpr-anonymize-headers
5966    (or opt1 'move-to-body-maybe) opt2 "message" "dummy"))
5967
5968 ;;; ----------------------------------------------------------------------
5969 ;;;
5970 (defun tinypgp-header-kill (&optional add-list)
5971   "Kill all but the most crucial headers.
5972 ADD-LIST is additional headers to keep."
5973   (let* ((hlist (ti::list-merge-elements
5974                  (mapcar
5975                   (function
5976                    (lambda (x)
5977                      (make-symbol
5978                       (downcase x))))
5979                   tinypgp-:r-header-keep-list)
5980                  (ti::mail-required-headers))))
5981     (ti::mail-kill-non-rfc-fields hlist)))
5982
5983 ;;; ----------------------------------------------------------------------
5984 ;;;
5985 (defun tinypgp-header-sign-make-smf (&optional read-xpgp &optional header-list)
5986   "Construct header SMF (a stripped message format).
5987 Read header field names and their contents from the message. If some
5988 header does not exist or is empty in message, then that header is ignored.
5989
5990 References:
5991
5992   `tinypgp-:header-sign-table'      Read from
5993   `tinypgp-:header-sign-smf-info'           Written to
5994
5995 Input:
5996
5997   READ-XPGP    ,The headers that were signed are told in X-Pgp.
5998                 If cannot read all headers, signal error.
5999   HEADER-LIST  ,list of headers names
6000
6001 Return:
6002   (string (hdr hdr ..))        ,SMF'd header-string and headers included
6003   nil"
6004   (interactive)
6005   (let* ((fid   "tinypgp-header-sign-make-smf:")
6006          elt
6007          (list (or header-list
6008                    (if (setq elt (tinypgp-header-sign-active-list))
6009                        (nth 1 elt))))
6010          hdr-name
6011          flag
6012          fld
6013          hlist
6014          str
6015          buffer
6016          ret)
6017
6018     (tinypgpd fid "in" read-xpgp header-list "list" elt)
6019     ;;  Clear this global
6020     ;;
6021     (setq tinypgp-:header-sign-smf-info nil)
6022
6023     (when read-xpgp
6024       (setq fld (mail-fetch-field        "X-Pgp-signed"))
6025       (when (setq fld (ti::string-match "SignedHeaders=\\([^;]+\\);" 1 fld))
6026         ;;  Remove newlines, because the field may continue
6027         ;;
6028         (setq fld  (subst-char-with-string fld ?\n " "))
6029         (setq list (split-string fld "[ ,]+"))))
6030
6031     (when (ti::listp list)
6032       (setq buffer (tinypgp-ti::temp-buffer))
6033       ;;  Get the fields
6034       ;;
6035       (save-restriction
6036         (dolist (elt list)
6037
6038           (when (setq str (ti::mail-get-field elt nil 'pure))
6039
6040             ;;  this code is inside loop, because outside loop
6041             ;;  we don't know if we got any headers
6042             ;;
6043             (unless  flag               ;Do only once
6044               (setq flag t)             ;Remailer type header hash ##
6045               (ti::append-to-buffer buffer "##\n"))
6046
6047             ;;  We want to store the real header name, not the "list"
6048             ;;  names that can be "reply-to", where real header name is like
6049             ;;
6050             ;;  REPLY-to:  .....
6051             ;;
6052             (setq hdr-name (ti::string-match "^\\([^:]+\\):" 1 str))
6053             (tinypgpd fid "READ" elt "NAME" hdr-name str)
6054             (ti::nconc hlist hdr-name)
6055
6056             (ti::append-to-buffer
6057              buffer
6058              (format "%s\n" (ti::string-remove-whitespace str) )))))
6059
6060       (when hlist
6061         ;;   Add final newline after the headers.
6062         ;;
6063         (ti::append-to-buffer buffer "\n")
6064         (with-current-buffer buffer
6065           (setq ret (buffer-substring (point-min) (point-max))))))
6066
6067     (tinypgpd fid "ret" ret hlist)
6068
6069     (when ret
6070       (setq tinypgp-:header-sign-smf-info (list ret hlist)))))
6071
6072 ;;}}}
6073 ;;{{{ timer control
6074
6075 ;;; .......................................................... &timers ...
6076
6077 ;;; ----------------------------------------------------------------------
6078 ;;;
6079 (defun tinypgp-timer-process ()
6080   "PGP timer process. Expires stored password and update mode line."
6081   ;;  Run only if some visible windows has tinypgp-mode on.
6082   ;;
6083   (let (do-it)
6084     (dolist (win (ti::window-list))
6085       (with-current-buffer (window-buffer win)
6086         (when tinypgp-mode (setq do-it t   wlist nil))))
6087
6088     (if do-it (tinypgp-update-modeline))
6089     (if (not (tinypgp-password-time-valid-p))
6090         (tinypgp-password-expire-now))
6091     do-it))
6092
6093 ;;; ----------------------------------------------------------------------
6094 ;;;
6095 (defun tinypgp-timer-control (&optional remove verb)
6096   "Keep the password expiration timer alive. Optionally REMOVE it. VERB."
6097   (interactive "P")
6098   (let* ((fid   "tinypgp-timer-control: ")
6099          (timer tinypgp-:timer-elt))
6100     (ti::verb)
6101
6102     (tinypgpd fid "in:" timer)
6103
6104     (ti::compat-timer-cancel-function 'tinypgp-timer-process)
6105
6106     (unless remove
6107       (setq tinypgp-:timer-elt (run-at-time "10 sec" 10 'tinypgp-timer-process)))
6108
6109     (when verb
6110       (if remove
6111           (message "TinyPgp timer process installed")
6112         (message "TinyPgp timer process removed.")))))
6113
6114 ;;}}}
6115 ;;{{{ password control
6116
6117 ;;; ........................................................ &password ...
6118
6119 ;;; ----------------------------------------------------------------------
6120 ;;;
6121 (defun tinypgp-password-expire-now (&optional no-file-kill verb)
6122   "Expire all PGP passwords including used files.
6123 Input:
6124
6125   NO-FILE-KILL  if non-nil, then temporary files are not removed.
6126   VERB          Display verbose message."
6127   (interactive "P")
6128   (ti::verb)
6129   (tinypgpd "tinypgp-password-expire-now" no-file-kill verb)
6130
6131   ;;  Do not leave traces to memory (gc)
6132   ;;
6133   (let* ((gc-cons-threshold (* 1024 1024)))
6134     (ti::vector-table-clear tinypgp-:hash-password))
6135
6136   ;;  Create new
6137   ;;
6138   (ti::vector-table-init tinypgp-:hash-password)
6139
6140   ;;  This command also may contains the password, wipe it
6141   ;;
6142   (setq tinypgp-:last-pgp-exe-command nil)
6143   (tinypgp-hash 'password-time 'put 'tick nil 'global)
6144
6145   (if (null no-file-kill)
6146       (tinypgp-file-control 'all-kill))
6147
6148   (when (or verb (interactive-p))
6149     ;;  If user called us; expire also secring password
6150     ;;
6151     (tinypgp-secring-crypt-expire-password)
6152     (message "TinyPgp: all pass phrases and files expired.")))
6153
6154 ;;; ----------------------------------------------------------------------
6155 ;;;
6156 (defun tinypgp-password-get  ()
6157   "Get password."
6158   (let* ((sym tinypgp-:user-now)
6159          (type (tinypgp-hash 'action 'get 'now nil 'global))
6160          ret)
6161     (tinypgpd "tinypgp-password-get:" sym type)
6162
6163     ;;  This may be "pgp" decrypt or "conventional". pick right
6164     ;;  password from hash.
6165
6166     (when (string= "conventional" type)
6167       (setq sym "conventional"))
6168
6169     (tinypgp-password-set
6170      "Password: "
6171      (if (string= "conventional" type)
6172          'conventional))
6173
6174     (unless (setq ret
6175                   (ti::vector-table-property
6176                    tinypgp-:hash-password sym 'password))
6177       (error "Internal error. Password hash corrupt."))
6178
6179     ret))
6180
6181 ;;; ----------------------------------------------------------------------
6182 ;;;
6183 (defun tinypgp-password-set (&optional prompt type)
6184   "Set pass phrase for `tinypgp-:user-now' or ask again with PROMPT (expired).
6185 Eg. if last PGP command terminated to error, that had expired all
6186 pass phrases.
6187
6188 Input:
6189
6190   prompt    string, Prompt to user
6191   TYPE      symbol, if 'conventional, set conventional password.
6192             If 'e-s, set one pass encrypt&sign password
6193
6194 Return:
6195  t     if password available"
6196   (let* ((fid "tinypgp-password-set:")
6197          (sym (if (and (not (ti::bool-p type))
6198                        (symbolp type))
6199                   (symbol-name type)
6200                 tinypgp-:user-now))
6201          ret
6202          pass)
6203     (or prompt
6204         (setq
6205          prompt
6206          (cond
6207           ((equal type 'conventional)
6208            "Conventional decrypt password: ")
6209           ((equal type 'e-s)
6210            (format "[%s] One pass encrypt&Sign password: " tinypgp-:user-now))
6211           (t            (format "[%s] Pass phrase:  " tinypgp-:user-now)))))
6212
6213     (tinypgpd fid "in:" tinypgp-:user-now prompt type sym)
6214
6215     (if (and (ti::vector-table-get tinypgp-:hash-password sym)
6216              (ti::vector-table-property tinypgp-:hash-password sym 'password)
6217              (tinypgp-password-time-valid-p)
6218              (null tinypgp-:error))
6219         (setq ret t)                    ;Ok, was in hash
6220
6221       ;;  unwind: Makes sure 'pass' is wiped away
6222
6223       (unwind-protect
6224           (progn
6225             (setq pass (ti::compat-read-password prompt))
6226             (when tinypgp-:password-keep-time
6227
6228               ;;  Create new user to hash table
6229
6230               (intern sym  tinypgp-:hash-password)
6231
6232               ;;  Set user's password in the hash
6233
6234               (ti::vector-table-property tinypgp-:hash-password sym 'password pass 'force)
6235               (tinypgp-hash 'password-time 'put 'tick nil 'global)
6236               (setq tinypgp-:error nil)
6237               (setq ret t)))))
6238 ;;; Hmm; this also wipes the password from hash; why?
6239 ;;;     (if pass (fillarray pass 0))
6240
6241     (tinypgpd fid "out:" tinypgp-:user-now prompt type ret)
6242
6243     ret))
6244
6245 ;;}}}
6246
6247 ;;{{{ installation funcs
6248
6249 ;;; ----------------------------------------------------------------------
6250 ;;; We can't initialize the substitution table in defvar, because
6251 ;;; it may be possible that some user sats (setq ...) and then these
6252 ;;; definitions aren't there any more.
6253 ;;;
6254 (defun tinypgp-install-default-substitutions (&optional remove)
6255   "Add default email substitutions or REMOVE."
6256   (let* ((nymserver-re
6257           (concat
6258            "\\("
6259            (mapconcat
6260             'concat
6261             '("anon" "finger" "ping" "remove" "help"
6262               "nick"
6263               "newpassword" "newalias" "newpgp" "newaddress"
6264               "vacation" "noarchive" "setnon" "paranoid"
6265               "pgpencrypt" "pgpsign" "sendmix"
6266               "abuse")
6267             "\\|")
6268            "\\)@anon.nymserver.com"))
6269
6270          (weasel-re "@weasel.owl.de\\|@squirrel.owl.de"))
6271
6272     (tinypgp-email-substitution-add
6273      (list
6274       ;; the 2nd entry is found from PGP key id.
6275       (cons nymserver-re "Nymserver at anon.nymserver.com")
6276
6277       ;;  You can get the Weasel 'newnym' PGP key from
6278       ;;     <info@weasel.owl.de>
6279       ;;     Johannes Kroeger <jkroeger@squirrel.owl.de>
6280       ;;
6281       ;;  Squirrel.owl.de and weasel.owl.de offer the following mail services:
6282       ;;  1.  The Squirrel Remailer, a Mixmaster/Ghio remailer combination:
6283       ;;
6284       ;;  The capabilities of the Ghio remailer are: $remailer{"squirrel"} =
6285       ;;  "<mix@squirrel.owl.de> cpunk mix pgp pgponly hash latent cut ek" The
6286       ;;  abbrevs are explained in http://www.publius.net/rlist.html
6287       ;;
6288       ;;  It accepts only PGP messages encrypted
6289
6290       (cons weasel-re "config@weasel.owl.de"))
6291      remove)))
6292
6293 ;;; ----------------------------------------------------------------------
6294 ;;;
6295 (defun tinypgp-install-send-mail-hook (&optional remove)
6296   "Install right hook order to `' or REMOVE hooks."
6297   (let* (hook
6298          func)
6299
6300     ;;   Hook chain is this:
6301     ;;
6302     ;;     tinypgp-password-wipe-buffer
6303     ;;     tinypgp-sign-modify-check
6304     ;;     tinypgp-auto-action
6305     ;;     --> rest of the user hooks.
6306     ;;
6307     ;;   The REST user hooks that do something TO BUFFER before sending
6308     ;;   message, should be in tinypgp-cmd-
6309     ;;   or to `tinypgp-:auto-action-before-hook'.
6310     ;;
6311
6312     (setq hook tinypgp-:mail-send-hook-list
6313           func '(tinypgp-auto-action
6314                  tinypgp-sign-modify-check
6315                  tinypgp-password-wipe-buffer))
6316
6317     ;;  First remove then add --> puts hooks to the beginning.
6318     ;;  IMPORTANT:
6319     ;;
6320     ;;      tinypgp-auto-action         --> add SEMI tags
6321     ;;      mime-edit-maybe-translate   --> translate tags and make PGP/MIME
6322     ;;
6323     ;;  So, TM/SEMI hook must be after TinyPgp hooks.
6324
6325     (ti::add-hooks hook func 'remove)
6326
6327     ;; Add the hooks in right order
6328
6329     (unless remove
6330       (ti::add-hooks hook func))))
6331
6332 ;;; ----------------------------------------------------------------------
6333 ;;;
6334 (defun tinypgp-install-hooks-vital (&optional remove)
6335   "Install and keep vital functions in right order. Optionally REMOVE."
6336   (interactive "P")
6337   (let* (func
6338          list)
6339
6340     ;; .............................................. kring find hooks ...
6341
6342     (setq list
6343           '(tinypgp-key-find-by-cache
6344             tinypgp-key-find-by-keyrings-verbose
6345             tinypgp-key-find-by-finger-verbose
6346             tinypgp-key-find-by-http-url-verbose
6347             tinypgp-key-find-by-http-keyserver-verbose))
6348
6349     (ti::add-hooks 'tinypgp-:find-by-guess-hook list 'remove)
6350     (unless remove (ti::add-hooks 'tinypgp-:find-by-guess-hook (nreverse list)))
6351
6352     ;; ................................................. control hooks ...
6353
6354     (remove-hook 'tinypgp-:cmd-macro-after-hook
6355                  'tinypgp-mode-specific-control-after)
6356     (unless remove
6357       (add-hook 'tinypgp-:cmd-macro-after-hook
6358                 'tinypgp-mode-specific-control-after 'append))
6359
6360     ;; .......................................................... mail ...
6361
6362     (tinypgp-install-send-mail-hook remove)
6363
6364     ;; ...................................................... external ...
6365     ;; It is essential that mime translate hooks is after TinyPgp
6366     ;; or otherwise eg when you send patch:
6367     ;;
6368     ;;  o   content is made quoted printble (=3D ...)
6369     ;;  o   auto action triggers encrypting
6370     ;;  --> receiving end doesn't get clean patch
6371
6372     (setq func 'mime-editor/maybe-translate ;TM.el
6373           list '(mail-send-hook
6374                  message-send-hook))
6375
6376     (dolist (hook list)
6377       (when (and (boundp hook)
6378                  (memq func (symbol-value hook)))
6379         (remove-hook hook func)
6380         ;; Make sure it is last
6381         (add-hook hook func 'append)))))
6382
6383 ;;; ----------------------------------------------------------------------
6384 ;;;
6385 (defun tinypgp-install-hooks (&optional remove)
6386   "Install package hooks. Optionally REMOVE installation.
6387 Can't restore changes to key maps."
6388   (interactive "P")
6389
6390   (ti::add-hooks 'find-file-hooks 'turn-on-tinypgp-mode-maybe remove)
6391
6392   (ti::add-hooks tinypgp-:turn-on-hook-list 'turn-on-tinypgp-mode remove)
6393
6394   (ti::add-hooks 'tinypgp-:define-keys-hook ;; just to make sure they are there.
6395                  '(tinypgp-mode-define-menu
6396                    tinypgp-mode-define-keys))
6397
6398   (ti::add-hooks 'tinypgp-:key-mode-define-keys-hook
6399                  '(tinypgp-key-mode-define-menu
6400                    tinypgp-key-mode-define-keys))
6401
6402   (ti::add-hooks 'tinypgp-:summary-mode-define-keys-hook
6403                  '(tinypgp-summary-mode-define-menu
6404                    tinypgp-summary-mode-define-keys))
6405
6406   (ti::add-hooks 'tinypgp-:newnym-mode-define-keys-hook
6407                  '(tinypgp-newnym-mode-define-menu
6408                    tinypgp-newnym-mode-define-keys))
6409
6410   (ti::add-hooks '(rmail-show-message-hook
6411                    vm-display-buffer-hook
6412                    mh-show-hook)
6413                  'tinypgp-hide
6414                  remove)
6415
6416   (ti::add-hooks '( ;; RMAIL summary is handled elswhere
6417                    vm-summary-mode-hook
6418                    gnus-summary-mode-hook
6419                    mh-show-mode-hook)
6420                  'turn-on-tinypgp-summary-mode
6421                  remove)
6422
6423   (ti::add-hooks 'gnus-select-article-hook 'tinypgp-hide-gnus remove) ;Gnus 4
6424
6425   (tinypgp-install-hooks-vital remove)
6426
6427   ;;  This must be after the mode specific hook has finished.
6428
6429   (unless remove
6430     (add-hook 'tinypgp-:cmd-macro-after-hook
6431               'tinypgp-after-pgp-command 'append))
6432
6433   (ti::add-hooks 'tinypgp-:verify-before-hook
6434                  'tinypgp-mode-specific-control-before
6435                  remove)
6436
6437   (ti::add-hooks 'tinypgp-:verify-after-hook
6438                  'tinypgp-mode-specific-control-after
6439                  remove)
6440
6441   (ti::add-hooks 'write-file-hooks      ; ~/.mailrc parsing
6442                  'tinypgp-update-mail-abbrevs-hook
6443                  remove)
6444
6445   (ti::add-hooks 'tinypgp-:r-reply-block-basic-hook
6446                  'tinypgp-r-mail-mode-init
6447                  remove))
6448
6449 ;;; ----------------------------------------------------------------------
6450 ;;;
6451 (defun tinypgp-install-menu-bar-remail ()
6452   "Disable or enable items from menubar."
6453   (if (tinypgp-hash 'remail 'get 'init nil 'global) ;If initialised
6454       (put 'tinypgp-:mode-menu 'remail t)
6455     (put 'tinypgp-:mode-menu 'remail nil)))
6456
6457 ;;; ----------------------------------------------------------------------
6458 ;;;
6459 (defun tinypgp-install-menu-bar-newnym ()
6460   "Disable or enable items from menubar."
6461   ;;  Hmm. Let me think of some test here later; Now it is enabled always.
6462   ;;
6463   (if (tinypgp-hash 'remail 'get 'init nil 'global)
6464       (put 'tinypgp-:mode-menu 'newnym t)
6465     (put 'tinypgp-:mode-menu 'newnym nil)))
6466
6467 ;;; ----------------------------------------------------------------------
6468 ;;;
6469 (defun tinypgp-install-menu-bar-nymserver ()
6470   "Disable or enable items from menubar."
6471   ;;  Enable only if user has ordered Nymserver account
6472   (if (ti::listp tinypgp-:nymserver-account-table)
6473       (put 'tinypgp-:mode-menu 'nymserver t)
6474     (put 'tinypgp-:mode-menu 'nymserver nil)))
6475
6476 ;;; ----------------------------------------------------------------------
6477 ;;;
6478 (defun tinypgp-install-menu-bar ()
6479   "Disable or enable items from menubar."
6480   (tinypgp-install-menu-bar-remail)
6481   (tinypgp-install-menu-bar-newnym)
6482   (tinypgp-install-menu-bar-nymserver))
6483
6484 ;;; ----------------------------------------------------------------------
6485 ;;;
6486 (defun tinypgp-install-check-environment  ()
6487   "Check basic environment variabler or die on error.
6488 PGP uses TMP for temporary files, make sure directory is accessible."
6489   (let* ((dir  (getenv "TMP"))
6490          file)
6491
6492     ;; PGP 2.6.x uses TMP env variable. See pgp.doc
6493
6494     (unless dir
6495       (message "TinyPgp: WARNING, environment variable TMP is not set.")
6496       (sleep-for 2)
6497       (dolist (directory '("/tmp" "/temp"))
6498         (when (file-directory-p directory)
6499           (setenv "TMP" directory)
6500           (setq dir directory)
6501           (message "TinyPgp: Setenv TMP ==> %s" directory)
6502           (return))))
6503
6504     (when (file-directory-p dir)
6505       (setq file (ti::file-make-path dir "tinypgp.tmp")))
6506
6507     (cond
6508      ((null dir)
6509       (error "TinyPgp: environment variable TMP is not set."))
6510
6511      ((not (file-directory-p dir))
6512       (error "TinyPgp: environment variable TMP is not pointing to directory"))
6513
6514      ((not (file-writable-p file))
6515       (error "TinyPgp: Can't write to TMP dir: %s" dir))
6516
6517      ;; Actually try to write, one day I got weir error from my TMP
6518      ;; file system. This neede fcsk run because disk had inode broken.
6519      ;;
6520      ;;   echo test > test.txt
6521      ;;   test.txt: No such device or address.
6522
6523      ((with-temp-buffer
6524         (insert "test\n")
6525         (write-region (point-min) (point-max) file) ;Breaks if not ok
6526         ;;  Breaks if not ok
6527         (delete-file file))))))
6528
6529 ;;; ----------------------------------------------------------------------
6530 ;;;
6531 (defun tinypgp-install (&optional remove)
6532   "Install whole package or REMOVE installation.
6533 This is main installation controller."
6534   (interactive)
6535   (tinypgpd "tinypgp-install in:" remove)
6536   (tinypgp-install-check-environment)
6537
6538   (tinypgp-binary-path-set)
6539
6540   ;;   Set the backenmd if thsi is firt time when program loads
6541
6542   (unless (get 'tinypgp-:pgp-binary 'pgp-now)
6543     (tinypgp-backend-select-auto))
6544
6545   (tinypgp-secring-crypt-mode-detect)
6546   (tinypgp-install-default-substitutions)
6547
6548   (tinypgp-install-hooks            remove)
6549   (tinypgp-timer-control            remove)
6550
6551 ;;; this is run from 'update modeline' Do not call here; because
6552 ;;; we're in wrong buffer and TP mode is not on.
6553 ;;;
6554 ;;;   (tinypgp-install-menu-bar)
6555
6556   (unless remove
6557     (tinypgp-key-cache-save 'load))
6558   (tinypgpd "tinypgp-install out:"))
6559
6560 ;;; ----------------------------------------------------------------------
6561 ;;;
6562 (defun tinypgp-install-to-current-emacs ()
6563   "Examine every emacs buffer and turn on PGP minor mode when needed."
6564   (interactive)
6565
6566   ;;  Forced install. Clear these
6567
6568   (put 'tinypgp-:hash 'vm-check nil)   (tinypgp-install-vm)
6569   (put 'tinypgp-:hash 'gnus-check nil) (tinypgp-install-gnus)
6570
6571   (put 'tinypgp-:hash 'mime-backend-in-use nil)
6572   (put 'tinypgp-:hash 'mime-backend-in-use nil)
6573   (tinypgp-install-mime-pgp)
6574
6575   ;; If user loads TinyPgp, it should immediately install itself to
6576   ;; appropriate buffers. Otherwise user has to call manually
6577   ;; `tinypgp-mode' for every mail buffer and that is not very nice.
6578
6579   (save-excursion
6580     (dolist (elt (buffer-list))
6581       (set-buffer elt)
6582       (cond
6583        ((memq major-mode '(vm-mode
6584                            rmail-mode
6585                            rmail-edit-mode
6586                            mail-mode
6587                            message-mode
6588                            gnus-article-mode
6589                            gnus-article-edit-mode
6590                            mime/viewer-mode)) ;TM
6591         (unless tinypgp-mode (tinypgp-mode 1)))
6592
6593        ((memq major-mode '(vm-summary-mode
6594                            rmail-summary-mode
6595                            gnus-summary-mode))
6596         (unless tinypgp-summary-mode
6597           (tinypgp-summary-mode 1)))))))
6598
6599 ;;; ----------------------------------------------------------------------
6600 ;;;
6601 (defun tinypgp-install-gnus-do ()
6602   "Add Headers to GNUS."
6603   (let* ((h    "X-pgp-signed")
6604          (hdr  "\\|X-pgp-signed:")
6605          (h2   "^X-pgp-signed:")
6606          sym
6607          val)
6608
6609     ;;  Bytecomp silencer with symbols
6610
6611     (dolist (sym '(gnus-saved-headers gnus-visible-headers))
6612       (setq val  (symbol-value sym))
6613       (if (not (stringp val))
6614           (error "Install problem1: See manual for GNUS installation.")
6615         (unless (string-match h val)
6616           (set sym (concat val hdr)))))
6617
6618     (setq sym 'gnus-sorted-header-list   val (symbol-value sym))
6619
6620     (if (not (ti::listp val))
6621         (error "Install problem2: See manual for GNUS installation.")
6622       (unless (member h2 val)
6623         ;;  Add to the end
6624         (set sym (append val (list h2)) )))))
6625
6626 ;;; ----------------------------------------------------------------------
6627 ;;;
6628 (defun tinypgp-install-gnus (&optional force)
6629   "Check that GNUS is configured right. Optionally FORCE."
6630   (when (and (featurep 'gnus)
6631              (or (boundp 'gnus-saved-headers) ;Gnus check
6632                  ;; Not bound, this is old gnus. Do not install
6633                  ;;
6634                  (prog1 nil (put 'tinypgp-:hash 'gnus-check t)))
6635              (null   (get 'tinypgp-:hash 'gnus-check)))
6636     (tinypgp-install-gnus-do)
6637     ;;  Done, do not repeat
6638     (put 'tinypgp-:hash 'gnus-check t)))
6639
6640 ;;; ----------------------------------------------------------------------
6641 ;;;
6642 (defun tinypgp-install-mime-tm-do ()
6643   "Install package to TM."
6644   (unless (featurep 'tm-tinypgp-setup)
6645     (or (load "tm-tinypgp-setup" 'noerr)
6646         (progn
6647           (message
6648            "tm-tinypgp-setup.el not found. Couldn't auto-install to TM")
6649           (sleep-for 5)))))
6650
6651 ;;; ----------------------------------------------------------------------
6652 ;;;
6653 (defun tinypgp-install-mime-semi-do ()
6654   "Install package to SEMI."
6655   (unless (featurep 'mime-tinypgp-setup)
6656     (or (load "mime-tinypgp-setup" 'noerr)
6657         (progn
6658           (message
6659            "mime-tinypgp-setup.el not found. Couldn't auto-install to SEMI")
6660           (sleep-for 5)))))
6661
6662 ;;; ----------------------------------------------------------------------
6663 ;;;
6664 (defun tinypgp-install-mime-tm (&optional force)
6665   "Check that GNUS is configured right. Optionally FORCE."
6666   (when (and (null (get 'tinypgp-:hash 'mime-backend-in-use))
6667              (ti::mail-mime-tm-featurep-p))
6668     (when (ti::mail-mime-semi-featurep-p)
6669       (error "\
6670 TinyPgp: Conflict; Trying to use TM while SEMI is present. Restart Emacs."))
6671     (tinypgp-install-mime-tm-do)
6672     ;;  Done, do not repeat
6673     (put 'tinypgp-:hash 'mime-backend-in-use 'tm)))
6674
6675 ;;; ----------------------------------------------------------------------
6676 ;;;
6677 (defun tinypgp-install-mime-semi (&optional force)
6678   "Check that GNUS is configured right. Optionally FORCE."
6679   (when (and (null (get 'tinypgp-:hash 'mime-backend-in-use))
6680              (ti::mail-mime-semi-featurep-p))
6681     (when (ti::mail-mime-tm-featurep-p)
6682       (error "\
6683 TinyPgp: Conflict; Trying to use SEMI while TM is present. Restart Emacs."))
6684     (tinypgp-install-mime-semi-do)
6685     (put 'tinypgp-:hash 'mime-backend-in-use 'semi)))
6686
6687 ;;; ----------------------------------------------------------------------
6688 ;;;
6689 (defun tinypgp-install-mime-pgp (&optional force)
6690   "Install PGP/MIME support or possible FORCE install. Need TM or SEMI."
6691   (interactive "P")
6692   (when (or force
6693             (null (get 'tinypgp-:hash 'mime-backend-in-use)))
6694     (cond
6695      ((ti::mail-mime-tm-featurep-p)
6696       (tinypgp-install-mime-tm)
6697       (tinypgp-install-hooks-vital))    ;Arrange TM look last
6698
6699      ((ti::mail-mime-semi-featurep-p)
6700       (tinypgp-install-mime-semi)
6701       ;;  Arrange SEMI hook last
6702       (tinypgp-install-hooks-vital)))))
6703
6704 ;;; ----------------------------------------------------------------------
6705 ;;;
6706 (defun tinypgp-install-vm ()
6707   "Install minor mode indication to VM summary buffer."
6708   ;;  1. User loads TinyPgp and VM is not loaded yet
6709   ;;     --> this function does nothing
6710   ;;  2. When user uses commands afterwards in VM, this function
6711   ;;     is called to chek the situation.
6712   ;;
6713   (when (and (featurep 'vm)
6714              (null (get 'tinypgp-:hash 'vm-check)))
6715     (let* ((sym     'vm-mode-line-format)
6716            (val     (symbol-value sym))
6717            (hdr     "X-Pgp-Signed:"))
6718
6719       ;;  The modeline format is defined in vm-vars.el::vm-mode-line-format,
6720       ;;  but it does not have variable minor-mode-alist. That's why TPsum
6721       ;;  mode is not shown in summary buffer.
6722       ;;
6723       (save-excursion
6724         (dolist (buffer (buffer-list))
6725           (set-buffer buffer)
6726           (when (and (eq major-mode 'vm-summary-mode)
6727                      (not (memq 'minor-mode-alist val)))
6728             ;;  Add this and update modeline
6729             (ti::nconc val 'minor-mode-alist)
6730             (ti::compat-set-mode-line-format val)
6731             (vm-update-summary-and-mode-line))))
6732
6733       (setq sym 'vm-visible-headers  val (symbol-value sym))
6734       (tinypgpd "tinypgp-install-vm:" sym val)
6735
6736       (if (not (ti::listp val))
6737           (error "Install problem: See manual for VM installation.")
6738         (unless (member hdr val)
6739           ;;  Add to the end
6740           (set sym (append val (list hdr))) ))
6741
6742       (put 'tinypgp-:hash 'vm-check t))))
6743
6744 ;;}}}
6745 ;;{{{ install: modes, keys
6746
6747 ;;; ----------------------------------------------------------------------
6748 ;;;
6749 (defun tinypgp-install-modes (&optional remove)
6750   "Install or REMOVE minor modes.
6751 Calling this always removes old mode and does reinstall."
6752   (interactive "P")
6753   (cond
6754    (remove
6755     (ti::keymap-add-minor-mode 'tinypgp-mode     nil nil 'remove)
6756     (ti::keymap-add-minor-mode 'tinypgp-key-mode nil nil 'remove)
6757     (ti::keymap-add-minor-mode 'tinypgp-summary-mode nil nil 'remove))
6758
6759    (t
6760     (setq tinypgp-:mode-map  (make-sparse-keymap)) ;; always refresh
6761     (run-hooks 'tinypgp-:define-keys-hook)
6762     (ti::keymap-add-minor-mode 'tinypgp-mode nil nil 'remove)
6763     (ti::keymap-add-minor-mode 'tinypgp-mode
6764                                'tinypgp-:mode-name
6765                                tinypgp-:mode-map)
6766
6767     (setq tinypgp-:key-mode-map  (make-sparse-keymap)) ;; always refresh
6768     (run-hooks 'tinypgp-:key-mode-define-keys-hook)
6769     (ti::keymap-add-minor-mode 'tinypgp-key-mode nil nil 'remove)
6770     (ti::keymap-add-minor-mode 'tinypgp-key-mode
6771                                'tinypgp-:key-mode-name
6772                                tinypgp-:key-mode-map)
6773
6774     (setq tinypgp-:summary-mode-map  (make-sparse-keymap)) ;; always refresh
6775     (run-hooks 'tinypgp-:summary-mode-define-keys-hook)
6776     (ti::keymap-add-minor-mode 'tinypgp-summary-mode nil nil 'remove)
6777     (ti::keymap-add-minor-mode 'tinypgp-summary-mode
6778                                'tinypgp-:summary-mode-name
6779                                tinypgp-:summary-mode-map)
6780
6781     (setq tinypgp-:newnym-mode-map  (make-sparse-keymap)) ;; always refresh
6782     (run-hooks 'tinypgp-:newnym-mode-define-keys-hook)
6783     (ti::keymap-add-minor-mode 'tinypgp-newnym-mode nil nil 'remove)
6784     (ti::keymap-add-minor-mode 'tinypgp-newnym-mode
6785                                'tinypgp-:newnym-mode-name
6786                                tinypgp-:newnym-mode-map))))
6787
6788 ;;}}}
6789
6790 ;;{{{ menu: main
6791
6792 (put 'tinypgp-:mode-menu 'nymserver nil)
6793
6794 ;;; ------------------------------------------------------------ &menu ---
6795 ;;;
6796 (defun tinypgp-mode-define-menu ()
6797   "Define menus."
6798   (easy-menu-define
6799     tinypgp-:mode-menu
6800     (if (ti::xemacs-p) nil (list tinypgp-:mode-map))
6801     "TinyPgp menu"
6802     (list
6803      tinypgp-:mode-menu-name
6804      ["Next action"                     tinypgp-next-action-mail                    t]
6805      ["Sign"                            tinypgp-sign-mail                           t]
6806      ["Sign, base64"                    tinypgp-sign-mail-base64                    t]
6807      ["Sign, detached"                  tinypgp-sign-mail-detached          t]
6808      ["Sign, PGP/MIME"                  tinypgp-sign-mail-mime              t]
6809
6810      ["Encrypt"                         tinypgp-encrypt-mail                t]
6811      ["Encrypt and sign (one pass)"     tinypgp-encrypt-mail-sign                   t]
6812      ["Encrypt PGP/MIME"                tinypgp-encrypt-mail-mime                   t]
6813
6814      ["Decrypt"                         tinypgp-decrypt-mail                t]
6815      ["Verify"                          tinypgp-verify-mail                 t]
6816      ["Verify detached signature on file"   tinypgp-verify-detached-signature t]
6817      ["Conventional crypt"              tinypgp-crypt-mail                  t]
6818      ["Insert file, base64 signed"      tinypgp-sign-base64-insert-file     t]
6819
6820      "----"
6821
6822      (list
6823       "Region PGP"
6824       ["Sign"                           tinypgp-sign-region                 t]
6825       ["Sign, base64"                   tinypgp-sign-region-base64          t]
6826       ["Sign, detached"                 tinypgp-sign-region-detached        t]
6827       ["Encrypt"                        tinypgp-encrypt-region              t]
6828       ["Encrypt and sign (one pass)"    tinypgp-encrypt-region-sign         t]
6829       ["Decrypt"                        tinypgp-decrypt-region              t]
6830       ["Verify"                         tinypgp-verify-region               t])
6831
6832      (list
6833       "Key handling"
6834       ["Fetch by finger"                tinypgp-key-find-by-finger          t]
6835       ["Fetch by http [keyserver]"      tinypgp-key-find-by-http-guess      t]
6836       ["Fetch by email keysrv request"  tinypgp-key-find-by-email           t]
6837       ["Fetch by guess"                 tinypgp-key-find-by-guess           t]
6838       "----"
6839       ["Insert with batch to pubring"   tinypgp-key-add-region-batch        t]
6840       ["Insert with ask to pubring"     tinypgp-key-add-region-interactive  t]
6841       ["Extract to point"               tinypgp-key-extract-to-point        t]
6842
6843 ;;;#todo menu
6844 ;;;      ["Generate new key"            tinypgp-key-generate                t]
6845       ["Remove from keyring"            tinypgp-key-delete-region           t]
6846       "----"
6847       ["Info insert matches"            tinypgp-key-info-insert             t]
6848       ["Info show matches"              tinypgp-key-info-at-point-show      t])
6849
6850      (list
6851       "Pubring and user control"
6852       ["Pubring show"                   tinypgp-pubring-display      t]
6853       ["Pubring change"                 tinypgp-pubring-set-current  t]
6854       "----"
6855       ["User show"                      tinypgp-user-display         t]
6856       ["User change"                    tinypgp-user-set-current     t])
6857
6858      (list
6859       "Modes and toggles"
6860       ["Flip x-pgp header/regular pgp"  tinypgp-xpgp-header-toggle    t]
6861       ["Flip Signature hide/show"       tinypgp-hide-show-toggle      t]
6862       "----"
6863       ["Mode Auto action on/off"        tinypgp-auto-action-toggle          t]
6864       ["Mode Auto signing on/off"       tinypgp-sign-mail-auto-mode         t]
6865       ["Mode Header sign on/off"        tinypgp-header-sign-mode-toggle     t]
6866       ["Mode x-pgp on/off"              tinypgp-xpgp-header-mode-toggle     t]
6867       "----"
6868       ["Mode Secring crypt on/off"      tinypgp-secring-crypt-mode-toggle   t]
6869       ["Mode Email substitution on/off" tinypgp-email-substitution-toggle   t])
6870
6871 ;;;     "----"
6872
6873      (list
6874       "Extra commands"
6875       ["Info Show Encrypt keys used"        tinypgp-encrypt-info          t]
6876       ["Info Show auto action entry"        tinypgp-auto-action-verbose   t]
6877       ["Info Show email conversion"  tinypgp-key-id-conversion-check-verbose t]
6878       ["Info Show header signing fields"    tinypgp-header-list-show      t]
6879       ["Info Show last finger error"     tinypgp-show-last-finger-error   t]
6880       "----"
6881       ["Info Describe mode"                 tinypgp-mode-describe         t]
6882       ["Info View pgp register"             tinypgp-view-register         t]
6883       ["Info Sudy PGP stream forward." tinypgp-pgp-stream-forward-study   t]
6884       "----"
6885       ["Wash Anonymize headers"             tinypgp-header-move-to-body   t]
6886       ["Wash expire pass phrases/files"     tinypgp-password-expire-now   t]
6887       ["Wash expire secring password"
6888        tinypgp-secring-crypt-expire-password                             t]
6889       ["Wash loose signing information"     tinypgp-sign-loose-info       t]
6890       ["Wash wipe passwords from buffer"    tinypgp-password-wipe-buffer  t]
6891       ["Wash delete running PGP processes"  tinypgp-delete-processes      t]
6892       "----"
6893       ["Send email: .plan has no PGP key"   tinypgp-sendmail-key-not-in-plan t]
6894       ["Send email: keyserver cmd"          tinypgp-keysrv-send-email-command t])
6895      "----"
6896
6897      (list
6898       "Remailer service"
6899       ["Post as Anon "                  tinypgp-r-post
6900        (get 'tinypgp-:mode-menu 'remail)]
6901       ["Encrypt-Remail message once"    tinypgp-r-chain-1
6902        (get 'tinypgp-:mode-menu 'remail)]
6903       ["Encrypt-Remail message using chain"  tinypgp-r-chain
6904        (get 'tinypgp-:mode-menu 'remail)]
6905       "----"
6906       ["Initialize remailer support"    tinypgp-r-init              t]
6907       ["Update remailer list"           tinypgp-r-update-remailer-list t]
6908       (list
6909        "Reply block"
6910        ["Make basic reply block"         tinypgp-r-reply-block-basic
6911         (get 'tinypgp-:mode-menu 'remail)]
6912        ["Construct remailer reply block" tinypgp-r-reply-block-insert
6913         (get 'tinypgp-:mode-menu 'remail)]
6914        ["Test defined reply blocks"      tinypgp-r-reply-block-test
6915         (get 'tinypgp-:mode-menu 'remail)])
6916
6917      (list
6918       "Newnym service"
6919       ["Show or get account help"       tinypgp-newnym-help
6920        (get 'tinypgp-:mode-menu 'newnym)]
6921       ["Default account in use/not in use" tinypgp-newnym-default-toggle
6922        tinypgp-:r-newnym-default-account-table]
6923       ["Default account select"         tinypgp-newnym-default-set
6924        tinypgp-:r-newnym-default-account-table]
6925       ["Post as Anon "                  tinypgp-newnym-post
6926        (get 'tinypgp-:mode-menu 'newnym)]
6927       "----"
6928       (list
6929        "Requests"
6930        ["acksend"               tinypgp-newnym-req-acksend
6931         (get 'tinypgp-:mode-menu 'newnym)]
6932        ["cryptrecv"             tinypgp-newnym-req-cryptrecv
6933         (get 'tinypgp-:mode-menu 'newnym)]
6934        ["disable"               tinypgp-newnym-req-disable
6935         (get 'tinypgp-:mode-menu 'newnym)]
6936        ["fingerkey"             tinypgp-newnym-req-fingerkey
6937         (get 'tinypgp-:mode-menu 'newnym)]
6938        ["fixedsize"             tinypgp-newnym-req-fixedsize
6939         (get 'tinypgp-:mode-menu 'newnym)]
6940        ["sigsend"               tinypgp-newnym-req-sigsend
6941         (get 'tinypgp-:mode-menu 'newnym)])
6942       (list
6943        "Configuration and misc"
6944        ["Account expiry status"  tinypgp-newnym-account-expiry-warnings t]
6945        ["Configuration template" tinypgp-newnym-config-sendmail-template
6946         (get 'tinypgp-:mode-menu 'newnym)]
6947        ["Create new account"            tinypgp-newnym-create
6948         (get 'tinypgp-:mode-menu 'newnym)]
6949        ["Delete account"                tinypgp-newnym-delete
6950         (get 'tinypgp-:mode-menu 'newnym)]
6951        "----"
6952        ["Get used account list"         tinypgp-newnym-get-used-list
6953         (get 'tinypgp-:mode-menu 'newnym)]
6954        ["Get server's PGP key"          tinypgp-newnym-get-pgp-key
6955         (get 'tinypgp-:mode-menu 'newnym)])
6956
6957      (list
6958       "Nymserver service"
6959       ["Post as anon"                   tinypgp-nymserver-post
6960        (get 'tinypgp-:mode-menu 'nymserver)]
6961       ["Finger, account status"         tinypgp-nymserver-finger
6962 ));;; Yes; you can finger an anon address ok: anNNN@anon-nymserver.com
6963 ;;;     (get 'tinypgp-:mode-menu 'nymserver)
6964        t]
6965       ["Ping, your account status"      tinypgp-nymserver-ping
6966        (get 'tinypgp-:mode-menu 'nymserver)]
6967       ["Help, read file"                tinypgp-nymserver-help
6968        (get 'tinypgp-:mode-menu 'nymserver)]
6969       "----"
6970       (list
6971        "Change account properties"
6972        ["Change account alias"          tinypgp-nymserver-newalias
6973         (get 'tinypgp-:mode-menu 'nymserver)]
6974        ["Change nickname"               tinypgp-nymserver-nickname
6975         (get 'tinypgp-:mode-menu 'nymserver)]
6976        ["Change .plan"                  tinypgp-nymserver-newplan
6977         (get 'tinypgp-:mode-menu 'nymserver)]
6978        ["Change .signature"             tinypgp-nymserver-newsig
6979         (get 'tinypgp-:mode-menu 'nymserver)]
6980        ["Change to new address"         tinypgp-nymserver-newaddress
6981         (get 'tinypgp-:mode-menu 'nymserver)])
6982
6983       (list
6984        "Flags and pgp key"
6985        ["flag, paranoid"                tinypgp-nymserver-paranoid
6986         (get 'tinypgp-:mode-menu 'nymserver)]
6987        ["flag, vacation"                tinypgp-nymserver-vacation
6988         (get 'tinypgp-:mode-menu 'nymserver)]
6989        ["flag, no archive"              tinypgp-nymserver-noarchive
6990         (get 'tinypgp-:mode-menu 'nymserver)]
6991        ["flag, anNNN/naNNN"             tinypgp-nymserver-setnon
6992         (get 'tinypgp-:mode-menu 'nymserver)]
6993        "----"
6994        ["PGP key upload "               tinypgp-nymserver-pgp-upload
6995         (get 'tinypgp-:mode-menu 'nymserver)]
6996        ["PGP flag, encrypt"             tinypgp-nymserver-pgp-encrypt
6997         (get 'tinypgp-:mode-menu 'nymserver)]
6998        ["PGP flag, sign"                tinypgp-nymserver-pgp-sign
6999         (get 'tinypgp-:mode-menu 'nymserver)]
7000        ["PGP flag, mixmaster"           tinypgp-nymserver-pgp-sendmix
7001         (get 'tinypgp-:mode-menu 'nymserver)])
7002
7003       (list
7004        "Create"
7005        ["Account create"                tinypgp-nymserver-create            t]
7006        ["Account remove"                tinypgp-nymserver-remove
7007         (get 'tinypgp-:mode-menu 'nymserver)]))
7008      "----"
7009
7010      (list
7011       "Cache service"
7012       ["Remove last entry"              tinypgp-key-cache-remove-entry-last  t]
7013       ["Display"                        tinypgp-key-cache-display           t])
7014
7015      (list
7016       "Report and backend service"
7017       ["Select PGP backend"             tinypgp-backend-select    t]
7018       ["Select PGP backend 2.6.x"       tinypgp-backend-select-pgp2   t]
7019       ["Select PGP backend 5.x"         tinypgp-backend-select-pgp5   t]
7020       ["Show TinyPgp version"           tinypgp-version-message     t]
7021       ["Show TinyPgp initial message"   tinypgp-initial-message     t]
7022       ["Submit bug report"              tinypgp-submit-bug-report     t]
7023       "----"
7024       ["Debug on/off"                   tinypgp-debug-toggle          t]
7025       ["Debug buffer clear"             tinypgp-debug-buffer-clear    t]
7026       "----"
7027       ["Display comint"                 tinypgp-show-buffer-comint    t]
7028       ["Display debug"                  tinypgp-show-buffer-debug           t]
7029       ["Display finger"                 tinypgp-show-buffer-finger    t]
7030       ["Display http"                   tinypgp-show-buffer-http            t]
7031       ["Display shell"                  tinypgp-show-buffer-shell           t]
7032       ["Display tmp"                    tinypgp-show-buffer-tmp     t]))))
7033
7034 ;;; I don't know if average user realizes what this command does...
7035 ;;;     ["Generate randseed.bin"  t]
7036
7037 ;;}}}
7038 ;;{{{ menu: echo, newnym
7039
7040 ;;; ----------------------------------------------------------------------
7041 ;;;
7042 (defun tinypgp-mode-define-keys-newnym (map n)
7043   ;;  Seldom used command in big letter to prevent accidents.
7044   ;;
7045   (define-key map (concat n "?") 'tinypgp-newnym-help)
7046   (define-key map (concat n "a") 'tinypgp-newnym-req-acksend)
7047   (define-key map (concat n "b") 'tinypgp-newnym-req-nobcc)
7048   (define-key map (concat n "C") 'tinypgp-newnym-create)
7049
7050   (define-key map (concat n "c")
7051     'tinypgp-newnym-config-sendmail-template)
7052
7053   (define-key map (concat n "D") 'tinypgp-newnym-delete)
7054   (define-key map (concat n "e") 'tinypgp-newnym-req-disable)
7055   (define-key map (concat n "f") 'tinypgp-newnym-req-fingerkey)
7056   (define-key map (concat n "K") 'tinypgp-newnym-get-pgp-key)
7057   (define-key map (concat n "u") 'tinypgp-newnym-get-used-list)
7058   (define-key map (concat n "p") 'tinypgp-newnym-post)
7059   (define-key map (concat n "r") 'tinypgp-newnym-req-cryptrecv)
7060   (define-key map (concat n "s") 'tinypgp-newnym-req-sigsend)
7061   (define-key map (concat n "\t") 'tinypgp-newnym-default-set)
7062   (define-key map (concat n "t") 'tinypgp-newnym-default-toggle)
7063   (define-key map (concat n "x") 'tinypgp-newnym-account-expiry-warnings)
7064   (define-key map (concat n "z") 'tinypgp-newnym-req-fixedsize))
7065
7066 ;;; ----------------------------------------------------------------------
7067 ;;;
7068 (defcustom tinypgp-:newnym-echo-menu-use-p t
7069   "*Should the 'newnym' commands be accessible from echo-area menu?.
7070 You can set this only once; otherwise you have to reload package."
7071   :type  'boolean
7072   :group 'tinypgp-nymserver)
7073
7074 ;; Change this mane in the load-hook is need to.
7075 ;;
7076 (defconst tinypgp-:newnym-echo-menu
7077   '(
7078     (let* ((srv (get 'tinypgp-:r-newnym-default-account-table 'default-server))
7079            (pfx (if current-prefix-arg "+" ""))
7080            (def (format "%s[%s]" pfx (or srv "Newnym") )))
7081       (tinypgp-backend-set-for-action 'newnym)
7082       (format
7083        "\
7084 %s p)ost c)fg t/ab)oggle h)lp req:a)ck b)cc e)nab f)ing s)ig si(z)e [utx CDK]"
7085        def))
7086     ((?a  . ( (call-interactively 'tinypgp-newnym-req-acksend)))
7087      (?C  . ( (call-interactively 'tinypgp-newnym-create)))
7088      (?b  . ( (call-interactively 'tinypgp-newnym-req-nobcc)))
7089      (?c  . ( (call-interactively 'tinypgp-newnym-config-sendmail-template)))
7090      (?D  . ( (call-interactively 'tinypgp-newnym-delete)))
7091      (?e  . ( (call-interactively 'tinypgp-newnym-req-disable)))
7092      (?f  . ( (call-interactively 'tinypgp-newnym-req-fingerkey)))
7093      (?h  . ( (tinypgp-newnym-help-verbose current-prefix-arg)))
7094      (?K  . ( (call-interactively 'tinypgp-newnym-get-pgp-key)))
7095      (?u  . ( (call-interactively 'tinypgp-newnym-get-used-list)))
7096      (?p  . ( (call-interactively 'tinypgp-newnym-post)))
7097      (?r  . ( (call-interactively 'tinypgp-newnym-req-cryptrecv)))
7098      (?s  . ( (call-interactively 'tinypgp-newnym-req-sigsend)))
7099      (?t  . (t (call-interactively 'tinypgp-newnym-default-toggle)))
7100      (?\t . ( (call-interactively 'tinypgp-newnym-default-set)))
7101      (?x  . ( (tinypgp-newnym-account-expiry-warnings)))
7102      (?z  . ( (call-interactively 'tinypgp-newnym-req-fixedsize)))))
7103   "Nym account menu.
7104 Esc or q to exit menu without choosing. Less used commands are in uppercase.
7105
7106 Basic Nym commands
7107
7108   h   = Show help file (prefix arg orders help file by mail)
7109   p   = convert current message to anon (p)ost
7110
7111 Nym account requests
7112
7113   All these commands send the minus(-) request and request action is
7114   explained to the right. Supply prefix argument if you want to send plus(+)
7115   request.
7116
7117   a   = (a)cksend    disable automatic acknowledgement
7118   b   = no(b)cc      receive bcc carbon copies. Needed if you
7119                      subscribe to mailing lists.
7120   r   = c(r)yptrecv  disable encryption to you.
7121   e   = disable      re-(e)nable account
7122   f   = (f)ingerkey  disallow people to get your PGP key.
7123   z   = fixedsi(z)e  do not padd messages to 10K
7124   s   = (s)igsend    disable automatic pgp signing
7125
7126 Nym account management
7127
7128   t   = (t)oggle using default account.
7129   tab = set default server and account
7130   c   = prepare (c)onfigure template and enter 'Nym' mode.
7131         You can manage you account in details. See tab key in this mode.
7132   C   = (C)reate account
7133   D   = (D)elete account
7134
7135 Other
7136
7137   x   = Display count of days to account e(x)piration.
7138   u   = Get account list ie. (u)sed nym names
7139   K   = Get server's PGP (k)ey.")
7140
7141 ;;}}}
7142 ;;{{{ menu: echo, nymserver
7143
7144 ;;; ----------------------------------------------------------------------
7145 ;;;
7146 (defun tinypgp-mode-define-keys-nymserver (map y)
7147   ;; Normal keybindings then. No menu in echo area used.
7148
7149   (define-key map (concat y "p") 'tinypgp-nymserver-post)
7150   (define-key map (concat y "f") 'tinypgp-nymserver-finger)
7151   (define-key map (concat y "i") 'tinypgp-nymserver-ping)
7152
7153   (define-key map (concat y "a") 'tinypgp-nymserver-newalias)
7154   (define-key map (concat y "n") 'tinypgp-nymserver-nickname)
7155   (define-key map (concat y "w") 'tinypgp-nymserver-newpassword)
7156
7157   (define-key map (concat y "o") 'tinypgp-nymserver-paranoid)
7158   (define-key map (concat y "v") 'tinypgp-nymserver-vacation)
7159   (define-key map (concat y "d") 'tinypgp-nymserver-newaddress)
7160   (define-key map (concat y "r") 'tinypgp-nymserver-noarchive)
7161   (define-key map (concat y "l") 'tinypgp-nymserver-newplan)
7162   (define-key map (concat y "g") 'tinypgp-nymserver-newsig)
7163   (define-key map (concat y "t") 'tinypgp-nymserver-setnon)
7164
7165   (define-key map (concat y "k") 'tinypgp-nymserver-pgp-upload)
7166   (define-key map (concat y "e") 'tinypgp-nymserver-pgp-encrypt)
7167   (define-key map (concat y "s") 'tinypgp-nymserver-pgp-sign)
7168   (define-key map (concat y "x") 'tinypgp-nymserver-pgp-sendmix)
7169
7170   (define-key map (concat y "C") 'tinypgp-nymserver-create)
7171   (define-key map (concat y "D") 'tinypgp-nymserver-remove)
7172   (define-key map (concat y "A") 'tinypgp-nymserver-abuse)
7173
7174   (define-key map (concat y "h") 'tinypgp-nymserver-help))
7175
7176 (defcustom tinypgp-:nymserver-echo-menu-use-p t
7177   "*Should the 'nymserver' commands be accessible from echo-area menu?.
7178 You can set this only once; otherwise you have to reload package."
7179   :type  'boolean
7180   :group 'tinypgp-nymserver)
7181
7182 ;; Change this mane in the load-hook is need to.
7183 ;;
7184 (defconst tinypgp-:nymserver-echo-menu
7185   '(
7186     (progn
7187       (tinypgp-backend-set-for-action 'nymserv)
7188       "Nymserv p)ost f)ing p(i)ng n)ick si(g) p(l)an PGP.kesx req.drtovwa [hACR]")
7189     ((?p  . ( (call-interactively 'tinypgp-nymserver-post)))
7190      (?f  . ( (call-interactively 'tinypgp-nymserver-finger)))
7191      (?i  . ( (call-interactively 'tinypgp-nymserver-ping)))
7192
7193      (?n  . ( (call-interactively 'tinypgp-nymserver-nickname)))
7194      (?v  . ( (call-interactively 'tinypgp-nymserver-vacation)))
7195      (?a  . ( (call-interactively 'tinypgp-nymserver-newalias)))
7196
7197      (?l  . ( (call-interactively 'tinypgp-nymserver-newplan)))
7198      (?g  . ( (call-interactively 'tinypgp-nymserver-newsig)))
7199      (?r  . ( (call-interactively 'tinypgp-nymserver-noarchive)))
7200
7201      (?y  . ( (call-interactively 'tinypgp-nymserver-setnon)))
7202      (?o  . ( (call-interactively 'tinypgp-nymserver-paranoid)))
7203      (?d  . ( (call-interactively 'tinypgp-nymserver-newaddress)))
7204      (?w  . ( (call-interactively 'tinypgp-nymserver-newpassword)))
7205
7206      (?k  . ( (call-interactively 'tinypgp-nymserver-pgp-upload)))
7207      (?e  . ( (call-interactively 'tinypgp-nymserver-pgp-encrypt)))
7208      (?s  . ( (call-interactively 'tinypgp-nymserver-pgp-sign)))
7209      (?x  . ( (call-interactively 'tinypgp-nymserver-pgp-sendmix)))
7210
7211      (?A  . ( (call-interactively 'tinypgp-nymserver-abuse)))
7212      (?C  . ( (call-interactively 'tinypgp-nymserver-create)))
7213      (?D  . ( (call-interactively 'tinypgp-nymserver-remove)))
7214      (?h  . ( (tinypgp-nymserver-help-verbose current-prefix-arg)))))
7215   "anon.nymserver.com menu.
7216 Esc or q to exit menu without choosing.
7217
7218 Basic commands
7219
7220   p   = convert current message to anon (p)ost
7221   f   = (f)inger account for configuration information.
7222
7223 Common commands
7224
7225   n   = (n)ickname change request
7226   g   = upload new .(s)ignature file
7227   l   = upload new .p(l)an file
7228
7229 PGP related requests
7230
7231   k   = upload PGP (k)ey to your account
7232   e   = (e)ncrypt request
7233   s   = (s)igning request
7234   x   = mi(x)master request
7235
7236 Requests
7237
7238   d   = newa(dd)ress request
7239   r   = noa(r)chive request
7240   t   = se(t)non request
7241   o   = paran(o)id request
7242   v   = (v)acation request
7243   w   = ne(w)password request
7244   a   = new(a)lias request. This changes your anNNN to vanity alias.
7245
7246 Other
7247
7248   h   = show (h)elp file, With Prefix arg send help request email.
7249   A   = Send (a)buse mail
7250   C   = (C)reate new account. This command can be sent only once.
7251   D   = (D)elete account. This is opposite of create.")
7252
7253 ;;}}}
7254 ;;{{{ menu: echo, remail
7255
7256 ;;; ----------------------------------------------------------------------
7257 ;;;
7258 (defun tinypgp-mode-define-keys-remail (map p)
7259   (define-key map (concat p "b")  'tinypgp-r-reply-block-basic)
7260   (define-key map (concat p "r")  'tinypgp-r-reply-block-insert)
7261   (define-key map (concat p "i")  'tinypgp-r-init)
7262   (define-key map (concat p "u")  'tinypgp-r-update-remailer-list)
7263   (define-key map (concat p "p")  'tinypgp-r-post)
7264   (define-key map (concat p "t")  'tinypgp-r-reply-block-test)
7265   (define-key map (concat p "C")  'tinypgp-r-chain-1)
7266   (define-key map (concat p "c")  'tinypgp-r-chain))
7267
7268 (defcustom tinypgp-:remail-echo-menu-use-p t
7269   "*Should the 'remail' commands be accessible from echo-area menu?.
7270 You can set this only once; otherwise you have to reload package."
7271   :type  'boolean
7272   :group 'tinypgp)
7273
7274 (defconst tinypgp-:remail-echo-menu
7275   '(
7276     (progn
7277       (tinypgp-backend-set-for-action 'remail)
7278       "remail: p)ost cC)hain b)asic-rb t)est-rb r)b-insert   u)pdate i)nit")
7279     ((?b . ( (call-interactively 'tinypgp-r-reply-block-basic)))
7280      (?r . ( (call-interactively 'tinypgp-r-reply-block-insert)))
7281      (?i . ( (call-interactively 'tinypgp-r-init)))
7282      (?u . ( (call-interactively 'tinypgp-r-update-remailer-list)))
7283      (?p . ( (call-interactively 'tinypgp-r-post)))
7284      (?t . ( (call-interactively 'tinypgp-r-reply-block-test)))
7285      (?C . ( (call-interactively 'tinypgp-r-chain-1)))
7286      (?c . ( (call-interactively 'tinypgp-r-chain)))))
7287   "Remail management menu
7288
7289 p  convert message to remailer post
7290 c  Chain message using predefined paths. Use (p) first
7291 C  Chain once manually. Use (p) first
7292
7293 b  construct basic reply block
7294 r  Insert reply block
7295
7296 i  Initialise remailer support
7297 u  update remailer list
7298 t  test reply blocks")
7299
7300 ;;}}}
7301
7302 ;;{{{ menu: echo, buffer
7303
7304 ;;; ----------------------------------------------------------------------
7305 ;;;
7306 (defun tinypgp-mode-define-keys-buffer (map p)
7307   "Define buffer handling keys. Use P prefix key and assign to MAP."
7308   ;;  Buffer management in prefix "b"
7309   ;;
7310   (define-key map (concat p "c")  'tinypgp-show-buffer-comint)
7311   (define-key map (concat p "d")  'tinypgp-show-buffer-debug)
7312   (define-key map (concat p "f")  'tinypgp-show-buffer-finger)
7313   (define-key map (concat p "h")  'tinypgp-show-buffer-http)
7314   (define-key map (concat p "s")  'tinypgp-show-buffer-shell)
7315   (define-key map (concat p "t")  'tinypgp-show-buffer-tmp)
7316
7317   (define-key map (concat p "\b")   'tinypgp-debug-buffer-clear)
7318   (define-key map (concat p "\177") 'tinypgp-debug-buffer-clear)
7319   (define-key map (concat p "\C-m") 'tinypgp-show-buffer-debug))
7320
7321 ;;; ----------------------------------------------------------------------
7322 ;;;
7323 (defcustom tinypgp-:show-buffer-echo-menu-use-p t
7324   "*Should the 'show-buffer' commands be accessible from echo-area menu?.
7325 You can set this only once; otherwise you have to reload package."
7326   :type  'boolean
7327   :group 'tinypgp)
7328
7329 (defconst tinypgp-:show-buffer-echo-menu
7330   '(
7331     "buffer: c)ache d)ebug,RET f)ing h)ttp s)hell t)emp DEL)debug clear "
7332     ((?c     . ( (tinypgp-key-cache-display)))
7333      (?d     . ( (tinypgp-show-buffer-debug)))
7334      (?f     . ( (tinypgp-show-buffer-finger)))
7335      (?h     . ( (tinypgp-show-buffer-http)))
7336      (?s     . ( (tinypgp-show-buffer-shell)))
7337      (?t     . ( (tinypgp-show-buffer-tmp)))
7338      (?\b    . ( (tinypgp-debug-buffer-clear)))
7339      (?\177  . ( (tinypgp-debug-buffer-clear)))
7340      (?\C-m  . ( (tinypgp-show-buffer-debug)))))
7341   "buffer show menu
7342
7343 c   Show key cache buffer
7344 d   Show debug buffer
7345 f   Show finger buffer
7346 h   Show http buffer
7347 s   Show shell buffer
7348 t   Show temp buffer
7349
7350 RET Show debug buffer
7351 DEL Clear debug buffer")
7352
7353 ;;; ----------------------------------------------------------------------
7354 ;;;
7355 (defun tinypgp-mode-define-keys-user (map p)
7356   "Define user keys. Use P prefix key and assign to MAP."
7357   (define-key map (concat p "s")  'tinypgp-user-display)
7358   (define-key map (concat p "\t") 'tinypgp-user-set-current))
7359
7360 (defcustom tinypgp-:user-echo-menu-use-p t
7361   "*Should the 'user' commands be accessible from echo-area menu?.
7362 You can set this only once; otherwise you have to reload package."
7363   :type  'boolean
7364   :group 'tinypgp)
7365
7366 (defconst tinypgp-:user-echo-menu
7367   '(
7368     "user: s)how tab)change"
7369     ((?s  . ( (call-interactively 'tinypgp-user-display)))
7370      (?\t . ( (call-interactively 'tinypgp-user-set-current)))))
7371   "User handling menu
7372
7373 s   Show current pgp user
7374 tab Change current pgp user")
7375
7376 ;;}}}
7377 ;;{{{ menu: echo, key
7378
7379 ;;; ----------------------------------------------------------------------
7380 ;;;
7381 (defun tinypgp-mode-define-keys-pubring (map p)
7382   (define-key map (concat p "s")  'tinypgp-pubring-display)
7383   ;;  This is little faster key
7384   (define-key map (concat p "\t") 'tinypgp-pubring-set-current))
7385
7386 (defcustom tinypgp-:pubring-echo-menu-use-p t
7387   "*Should the 'pubring' commands be accessible from echo-area menu?.
7388 You can set this only once; otherwise you have to reload package."
7389   :type  'boolean
7390   :group 'tinypgp)
7391
7392 (defconst tinypgp-:pubring-echo-menu
7393   '(
7394     "pubring: s)how tab)change"
7395     ((?s  . ( (call-interactively 'tinypgp-pubring-display)))
7396      (?\t . ( (call-interactively 'tinypgp-pubring-set-current)))))
7397   "User handling menu
7398
7399 s   Show current pubring in use
7400 tab Change current pubring")
7401
7402 ;;}}}
7403 ;;{{{ menu: echo, key
7404
7405 ;;; ----------------------------------------------------------------------
7406 ;;;
7407 (defun tinypgp-mode-define-keys-cache (map p)
7408   (define-key map (concat p "r")
7409     'tinypgp-key-cache-remove-entry-last)
7410   (define-key map (concat p "s") 'tinypgp-key-cache-display))
7411
7412 (defcustom tinypgp-:cache-echo-menu-use-p t
7413   "*Should the 'pubring' commands be accessible from echo-area menu?.
7414 You can set this only once; otherwise you have to reload package."
7415   :type  'boolean
7416   :group 'tinypgp)
7417
7418 (defconst tinypgp-:cache-echo-menu
7419   '(
7420     "pubring: s)how tab)change"
7421     ((?r . ( (call-interactively 'tinypgp-key-cache-remove-entry-last)))
7422      (?s . ( (call-interactively 'tinypgp-key-cache-display)))))
7423   "Cache menu
7424
7425 r   remove entry from cache.
7426 s   Show cache")
7427
7428 ;;}}}
7429
7430 ;;{{{ menu: echo, debug
7431
7432 ;;; ----------------------------------------------------------------------
7433 ;;;
7434 (defun tinypgp-mode-define-keys-debug (map p)
7435   (define-key map (concat p "d")  'tinypgp-debug-toggle)
7436   (define-key map (concat p "c")  'tinypgp-debug-buffer-clear)
7437   (define-key map (concat p "s")  'tinypgp-submit-bug-report)
7438   (define-key map (concat p "v")  'tinypgp-version-message)
7439   (define-key map (concat p "i")  'tinypgp-initial-message)
7440   (define-key map (concat p "\e")  'tinypgp-submit-bug-report))
7441
7442 (defcustom tinypgp-:debug-echo-menu-use-p t
7443   "*Should the 'debug' commands be accessible from echo-area menu?.
7444 You can set this only once; otherwise you have to reload package."
7445   :type  'boolean
7446   :group 'tinypgp)
7447
7448 (defconst tinypgp-:debug-echo-menu
7449   '(
7450     "debug: d)toggle c)lear s)submit report   v)ersion msg i)nit msg"
7451     ((?d . ( (call-interactively 'tinypgp-debug-toggle)))
7452      (?c . ( (call-interactively 'tinypgp-debug-buffer-clear)))
7453      (?s . ( (call-interactively 'tinypgp-submit-bug-report)))
7454      (?v . ( (call-interactively 'tinypgp-version-message)))
7455      (?i . ( (call-interactively 'tinypgp-initial-message)))))
7456   "Debug menu
7457 d  Toggle debug
7458 c  Clear debug buffer
7459 s  Submit bug report
7460
7461 v  Show version message
7462 i  Show initial startup message")
7463
7464 ;;}}}
7465 ;;{{{ menu: echo, region
7466
7467 ;;; ----------------------------------------------------------------------
7468 ;;;
7469 (defun tinypgp-mode-define-keys-region (map p)
7470   (define-key map (concat p "s") 'tinypgp-sign-region)
7471   (define-key map (concat p "S") 'tinypgp-sign-region-base64)
7472   (define-key map (concat p "D") 'tinypgp-sign-region-detached)
7473   (define-key map (concat p "e") 'tinypgp-encrypt-region)
7474   (define-key map (concat p "t") 'tinypgp-encrypt-region-sign)
7475   (define-key map (concat p "d") 'tinypgp-decrypt-region)
7476   (define-key map (concat p "v") 'tinypgp-verify-region)
7477   (define-key map (concat p "c") 'tinypgp-crypt-region))
7478
7479 (defcustom tinypgp-:region-echo-menu-use-p t
7480   "*Should the 'region' commands be accessible from echo-area menu?.
7481 You can set this only once; otherwise you have to reload package."
7482   :type  'boolean
7483   :group 'tinypgp)
7484
7485 (defconst tinypgp-:region-echo-menu
7486   '(
7487     "region: sSD)sign,base64,detach e)ncrypt t)1pass d)ecrypt v)erify c)rypt "
7488     ((?s  . ( (call-interactively 'tinypgp-sign-region)))
7489      (?S  . ( (call-interactively 'tinypgp-sign-region-base64)))
7490      (?D  . ( (call-interactively 'tinypgp-sign-region-detached)))
7491      (?e  . ( (call-interactively 'tinypgp-encrypt-region)))
7492      (?t  . ( (call-interactively 'tinypgp-encrypt-region-sign)))
7493      (?d  . ( (call-interactively 'tinypgp-decrypt-region)))
7494      (?v  . ( (call-interactively 'tinypgp-verify-region)))
7495      (?c  . ( (call-interactively 'tinypgp-crypt-region)))))
7496   "Region menu
7497
7498 s   Sign
7499 S   Sign with base64 armor
7500 D   Detach sign
7501 e   encrypt
7502 t   encrypt and sign on 1pass
7503 d   decrypt
7504 v   verify
7505 c   crypt
7506 ")
7507
7508 ;;}}}
7509 ;;{{{ menu: echo, keyring
7510
7511 ;;; ----------------------------------------------------------------------
7512 ;;;
7513 (defun tinypgp-mode-define-keys-key (map p)
7514   ;; #todo key generate
7515   ;; A  (define-key map (concat p "g") 'tinypgp-key-generate)
7516   ;;  - "ki" is closer to keyboard than default pgp "kv".
7517
7518   (define-key map (concat p "i") 'tinypgp-key-info-at-point-show)
7519   (define-key map (concat p "I") 'tinypgp-key-info-insert)
7520   (define-key map (concat p "v") 'tinypgp-key-info-insert)
7521
7522   (define-key map (concat p "a") 'tinypgp-key-add-region-batch)
7523   (define-key map (concat p "A")
7524     'tinypgp-key-add-region-interactive)
7525   (define-key map (concat p "x") 'tinypgp-key-extract-to-point)
7526   (define-key map (concat p "r") 'tinypgp-key-delete-region))
7527
7528 (defcustom tinypgp-:key-echo-menu-use-p t
7529   "*Should the 'key' commands be accessible from echo-area menu?.
7530 You can set this only once; otherwise you have to reload package."
7531   :type  'boolean
7532   :group 'tinypgp)
7533
7534 (defconst tinypgp-:key-echo-menu
7535   '(
7536     "key: i)nfo show vI)nsert a)dd batch A)add interactive x)tract r)emove"
7537     ((?i  . ( (call-interactively 'tinypgp-key-info-at-point-show)))
7538      (?I  . ( (call-interactively 'tinypgp-key-info-insert)))
7539      (?v  . ( (call-interactively 'tinypgp-key-info-insert)))
7540      (?a  . ( (call-interactively 'tinypgp-key-add-region-batch)))
7541      (?A  . ( (call-interactively 'tinypgp-key-add-region-interactive)))
7542      (?x  . ( (call-interactively 'tinypgp-key-extract-to-point)))
7543      (?r  . ( (call-interactively 'tinypgp-key-delete-region)))))
7544   "Key management menu
7545
7546 i  Show keys matching string at point
7547 I  Insert key info mathing string to point
7548 v  ...same... (synonym)
7549 a  add keys in region to pubring
7550 A  add keys in region to pubring (interactive)
7551 x  Extract key from keyring to point
7552 r  removed selected keys in region from keyring
7553 ")
7554
7555 ;;}}}
7556 ;;{{{ menu: echo, modes
7557
7558 ;;; ----------------------------------------------------------------------
7559 ;;;
7560 (defun tinypgp-mode-define-keys-mode (map p)
7561   (define-key map (concat p "!") 'tinypgp-auto-action-toggle)
7562   (define-key map (concat p "c") 'tinypgp-secring-crypt-mode-toggle)
7563
7564   (define-key map (concat p "e")
7565     'tinypgp-email-substitution-toggle)
7566
7567   (define-key map (concat p "h") 'tinypgp-xpgp-header-mode-toggle)
7568   (define-key map (concat p "H")
7569     'tinypgp-header-sign-mode-toggle)
7570
7571   (define-key map (concat p "s") 'tinypgp-sign-mail-auto-mode))
7572
7573 (defcustom tinypgp-:mode-echo-menu-use-p t
7574   "*Should the 'mode' commands be accessible from echo-area menu?.
7575 You can set this only once; otherwise you have to reload package."
7576   :type  'boolean
7577   :group 'tinypgp)
7578
7579 (defconst tinypgp-:mode-echo-menu
7580   '(
7581     "mode: !)action c)rypt secring e)mail h)x-pgp H)eader sign s)ign"
7582     ((?! . ( (call-interactively 'tinypgp-auto-action-toggle)))
7583      (?c . ( (call-interactively 'tinypgp-secring-crypt-mode-toggle)))
7584      (?e . ( (call-interactively 'tinypgp-email-substitution-toggle)))
7585      (?h . ( (call-interactively 'tinypgp-xpgp-header-mode-toggle)))
7586      (?H . ( (call-interactively 'tinypgp-header-sign-mode-toggle)))
7587      (?s . ( (call-interactively 'tinypgp-sign-mail-auto-mode)))))
7588   "Mode handling menu
7589
7590 !  Toggle auto action: enable, disable
7591 c  Toggle secring crypt mode
7592 e  Toggle email subtitution mode
7593 f  Toggle fcc encrypt mode
7594 h  Toggle header based x-pgp signing mode
7595 H  Toggle including part of the headers for signing
7596 s  Toggle auto signing mode of outgoing mail")
7597
7598 ;;}}}
7599 ;;{{{ menu: echo, key
7600
7601 ;;; ----------------------------------------------------------------------
7602 ;;;
7603 (defun tinypgp-mode-define-keys-extra (map p)
7604
7605   (define-key map (concat p "a") 'tinypgp-auto-action-verbose)
7606
7607   (define-key map (concat p "b") 'tinypgp-backend-select)
7608   (define-key map (concat p "B") 'tinypgp-secring-backup)
7609
7610   (define-key map (concat p "D") 'tinypgp-delete-processes)
7611
7612   (define-key map (concat p "E")
7613     'tinypgp-key-id-conversion-check-verbose)
7614
7615   (define-key map (concat p "e") 'tinypgp-encrypt-info)
7616
7617   (define-key map (concat p "h") 'tinypgp-header-list-show)
7618   (define-key map (concat p "i")
7619     'tinypgp-pgp-stream-forward-study)
7620
7621   (define-key map (concat p "f") 'tinypgp-show-last-finger-error)
7622
7623   (define-key map (concat p "k")
7624     'tinypgp-keysrv-send-email-command)
7625
7626   (define-key map (concat p "l") 'tinypgp-sign-loose-info)
7627
7628   (define-key map (concat p "p")
7629     'tinypgp-sendmail-key-not-in-plan)
7630
7631   (define-key map (concat p "w") 'tinypgp-password-wipe-buffer)
7632
7633   (define-key map (concat p "x") 'tinypgp-password-expire-now)
7634   (define-key map (concat p "X") 'tinypgp-secring-crypt-expire-password))
7635
7636 (defcustom tinypgp-:extra-echo-menu-use-p t
7637   "*Should the 'extra' commands be accessible from echo-area menu?.
7638 You can set this only once; otherwise you have to reload package."
7639   :type  'boolean
7640   :group 'tinypgp)
7641
7642 (defconst tinypgp-:extra-echo-menu
7643   (list
7644    "\
7645 extra: aeh)info f)ing iE)pgp kp)email l)oose b)backend B)up wDxX)pire >dC "
7646    (list
7647     '(?a . ( (call-interactively 'tinypgp-auto-action-verbose)))
7648     '(?b . ( (call-interactively 'tinypgp-backend-select)))
7649     '(?B . ( (call-interactively 'tinypgp-secring-backup)))
7650     '(?D . ( (call-interactively 'tinypgp-delete-processes)))
7651     '(?e . ( (call-interactively 'tinypgp-key-id-conversion-check-verbose)))
7652     '(?E . ( (call-interactively 'tinypgp-encrypt-info)))
7653     '(?h . ( (call-interactively 'tinypgp-header-list-show)))
7654     '(?i . ( (call-interactively 'tinypgp-pgp-stream-forward-study)))
7655     '(?f . ( (call-interactively 'tinypgp-show-last-finger-error)))
7656     '(?k . ( (call-interactively 'tinypgp-keysrv-send-email-command)))
7657     '(?l . ( (call-interactively 'tinypgp-sign-loose-info)))
7658     '(?p . ( (call-interactively 'tinypgp-sendmail-key-not-in-plan)))
7659     '(?w . ( (call-interactively 'tinypgp-password-wipe-buffer)))
7660     '(?x . ( (call-interactively 'tinypgp-password-expire-now)))
7661     '(?X . ( (call-interactively 'tinypgp-secring-crypt-expire-password)))
7662
7663     (cons ?d 'tinypgp-:debug-echo-menu)
7664     (cons ?C 'tinypgp-:cache-echo-menu)))
7665   "Extra menu
7666
7667 Information
7668
7669     a  Show auto action that would trigger this mail
7670     e  Show what email conversion would apply to To address
7671     h  Show what headers would be signed
7672     f  Show last finger error in echo area
7673
7674   Pgp block
7675
7676     E  Study encrypted message and show whom it's encrypted to
7677     i  Study pgp stream forward and show info (type pgp version etc.)
7678
7679 Email
7680
7681     k  Send command to keyserver
7682     p  Send notice that user's key was not in .plan when fingered.
7683
7684 Miscellaneous
7685
7686     l  Loose signing information
7687     b  Select backend> pgp 2.6.x or pgp 5.x
7688     B  Backup secring in encrypted format
7689
7690 Wipe
7691
7692     d  Delete all running PGP processes. Eg. Pgp 5.x may be hung in your
7693        emacs. Use this command to get rip of those zombies. See process
7694        list with command \\[list-processes]
7695     w  wipe passwords from buffer
7696     x  Expire pass phrases
7697     X  Expire encrypted secring password.")
7698
7699 ;;}}}
7700
7701 ;;{{{ menu: define keys
7702
7703 ;;; ----------------------------------------------------------------------
7704 ;;;
7705 (defun tinypgp-mode-define-keys ()
7706   "Define keys."
7707   (let* ((map  tinypgp-:mode-map)
7708          (p    tinypgp-:mode-prefix-key)
7709          (r    tinypgp-:mode-prefix-key-remailer)
7710          (y    tinypgp-:mode-prefix-key-nymserver)
7711          (n    tinypgp-:mode-prefix-key-newnym))
7712
7713     (if tinypgp-:region-echo-menu-use-p
7714         (define-key map (concat p "r")
7715           (ti::definteractive (ti::menu-menu 'tinypgp-:region-echo-menu arg)))
7716       (tinypgp-mode-define-keys-region map (concat p "r")))
7717
7718     ;; ................................................. user, pubring ...
7719
7720     (if tinypgp-:user-echo-menu-use-p
7721         (define-key map (concat p "u")
7722           (ti::definteractive (ti::menu-menu 'tinypgp-:user-echo-menu arg)))
7723       (tinypgp-mode-define-keys-user map (concat p "u")))
7724
7725     (if tinypgp-:pubring-echo-menu-use-p
7726         (define-key map (concat p "p")
7727           (ti::definteractive (ti::menu-menu 'tinypgp-:pubring-echo-menu arg)))
7728       (tinypgp-mode-define-keys-pubring map (concat p "p")))
7729
7730     ;; ....................................................... keyring ...
7731
7732     (if tinypgp-:key-echo-menu-use-p
7733         (define-key map (concat p "k")
7734           (ti::definteractive (ti::menu-menu 'tinypgp-:key-echo-menu arg)))
7735       (tinypgp-mode-define-keys-key map (concat p "k")))
7736
7737     ;; ........................................................ buffer ...
7738
7739     (if tinypgp-:show-buffer-echo-menu-use-p
7740         (define-key map (concat p "b")
7741           (ti::definteractive (ti::menu-menu 'tinypgp-:show-buffer-echo-menu arg)))
7742       (tinypgp-mode-define-keys-buffer map (concat p "b")))
7743
7744     ;; ......................................................... extra ...
7745
7746     (if tinypgp-:extra-echo-menu-use-p
7747         (define-key map (concat p "x")
7748           (ti::definteractive (ti::menu-menu 'tinypgp-:extra-echo-menu arg)))
7749       (tinypgp-mode-define-keys-extra map (concat p "x")))
7750
7751     (unless tinypgp-:debug-echo-menu-use-p
7752       (tinypgp-mode-define-keys-debug map (concat p "xd")))
7753
7754     (unless tinypgp-:debug-echo-menu-use-p
7755       (tinypgp-mode-define-keys-cache map (concat p "xC")))
7756
7757     ;; .......................................................... mode ...
7758
7759     (if tinypgp-:mode-echo-menu-use-p
7760         (define-key map (concat p "m")
7761           (ti::definteractive (ti::menu-menu 'tinypgp-:mode-echo-menu arg)))
7762       (tinypgp-mode-define-keys-mode map (concat p "m")))
7763
7764     ;; ...................................................... remailer ...
7765
7766     (if tinypgp-:remail-echo-menu-use-p
7767         (define-key map r
7768           (ti::definteractive (ti::menu-menu 'tinypgp-:remail-echo-menu arg)))
7769       (tinypgp-mode-define-keys-remail map r))
7770
7771     ;; ..................................................... nymserver ...
7772
7773     (if tinypgp-:nymserver-echo-menu-use-p
7774         (define-key map y
7775           (ti::definteractive
7776            (ti::menu-menu 'tinypgp-:nymserver-echo-menu arg)))
7777       (tinypgp-mode-define-keys-nymserver map y))
7778
7779     ;; ........................................................ newnym ...
7780
7781     (if tinypgp-:newnym-echo-menu-use-p
7782         (define-key map n
7783           (ti::definteractive (ti::menu-menu 'tinypgp-:newnym-echo-menu arg)))
7784       (tinypgp-mode-define-keys-nymserver map n))
7785
7786     ;; ....................................................... regular ...
7787
7788     (define-key map
7789       (concat p (ti::string-right p 1))    'tinypgp-next-action-mail)
7790
7791     (define-key map (concat p "?")  'tinypgp-mode-describe)
7792
7793     (define-key map (concat p "a")  'tinypgp-header-move-to-body)
7794     (define-key map (concat p "s")  'tinypgp-sign-mail)
7795     (define-key map (concat p "S")  'tinypgp-sign-mail-base64)
7796     (define-key map (concat p "D")  'tinypgp-sign-mail-detached)
7797
7798     (define-key map (concat p "e")  'tinypgp-encrypt-mail)
7799     (define-key map (concat p "t")  'tinypgp-encrypt-mail-sign)
7800
7801     ;;  There no particular reason why "q" for mime.
7802     ;;  I chose it because, Q char is obscure enough to
7803     ;;  remind that in 1998-03 the PGP/MIME is still new.
7804
7805     (define-key map (concat p "q")  'tinypgp-sign-mail-mime)
7806     (define-key map (concat p "Q")  'tinypgp-encrypt-mail-mime)
7807
7808     (define-key map (concat p "d")  'tinypgp-decrypt-mail)
7809     (define-key map (concat p "v")  'tinypgp-verify-mail)
7810     (define-key map (concat p "V")
7811       'tinypgp-verify-detached-signature)
7812
7813     (define-key map (concat p "c")  'tinypgp-crypt-mail)
7814     (define-key map (concat p "i")  'tinypgp-sign-base64-insert-file)
7815
7816     (define-key map (concat p "h")  'tinypgp-xpgp-header-toggle)
7817     (define-key map (concat p "g")  'tinypgp-hide-show-toggle)
7818
7819     (define-key map (concat p "R")  'tinypgp-view-register)
7820     (define-key map (concat p "F")  'tinypgp-key-find-by-finger)
7821
7822     (define-key map (concat p "G")
7823       'tinypgp-key-find-by-guess)
7824
7825     (define-key map (concat p "E")  'tinypgp-key-find-by-email)
7826
7827     (define-key map (concat p "K")
7828       'tinypgp-key-find-by-http-guess)
7829
7830     (define-key map (concat p "2")  'tinypgp-backend-select-pgp2)
7831     (define-key map (concat p "5")  'tinypgp-backend-select-pgp5)
7832
7833     (define-key map (concat p "\C-m") 'tinypgp-key-find-by-guess)))
7834
7835 ;;}}}
7836 ;;{{{ mode: key mode
7837
7838 ;;; ----------------------------------------------------------------------
7839 ;;;
7840 (defun tinypgp-key-mode-define-menu ()
7841   "Define menus."
7842   (easy-menu-define
7843     tinypgp-:key-mode-menu (if (ti::xemacs-p) nil tinypgp-:key-mode-map)
7844     "TinyPgp Key management menu"
7845     (list
7846      tinypgp-:key-mode-menu-name)))
7847 ;;;    ["Mail Sign"                     tinypgp-sign-mail                   t]
7848
7849 ;;; ----------------------------------------------------------------------
7850 ;;;
7851 (defun tinypgp-key-mode-define-keys ()
7852   "Define keys."
7853   (let* ((p    tinypgp-:key-mode-prefix-key)
7854          (map  tinypgp-:key-mode-map))
7855     (define-key map (concat p "a") 'tinypgp-key-add-region-batch)))
7856
7857 ;;}}}
7858 ;;{{{ mode: summary mode
7859
7860 ;;; --------------------------------------------------------- &summary ---
7861 ;;;
7862 (defun tinypgp-summary-mode-define-menu ()
7863   "Define menus."
7864   (easy-menu-define
7865     tinypgp-:summary-mode-menu (if (ti::xemacs-p) nil tinypgp-:summary-mode-map)
7866     "TinyPgp Mail Summary management menu"
7867     (list
7868      tinypgp-:summary-mode-menu-name
7869      ["Verify"                   tinypgp-summary-mode-verify       t]
7870      ["Decrypt"                  tinypgp-summary-mode-decrypt      t]
7871      ["Next action"              tinypgp-summary-mode-next-action  t]
7872      ["Describe mode"            tinypgp-summary-mode-describe     t]
7873
7874      "----"
7875      (list
7876       "Extra commands"
7877       ["Wash expire pass phrases/files"  tinypgp-password-expire-now         t]
7878       ["Wash expire secring password"
7879        tinypgp-secring-crypt-expire-password        t]
7880       "----"
7881       ["Info Display last finger error"  tinypgp-show-last-finger-error    t]
7882       ["Info View pgp register"          tinypgp-view-register               t]
7883       "----"
7884       ["Send email: .plan has no PGP key" tinypgp-sendmail-key-not-in-plan  t]
7885       ["Send email: keyserver cmd"        tinypgp-keysrv-send-email-command t])
7886
7887      (list
7888       "Cache service"
7889       ["Remove last entry" tinypgp-key-cache-remove-entry-last   t]
7890       ["Display"           tinypgp-key-cache-display                 t])
7891
7892      (list
7893       "Report service"
7894       ["Submit bug report"               tinypgp-submit-bug-report     t]
7895       ["Debug on/off"                    tinypgp-debug-toggle          t]
7896       ["Debug buffer clear"              tinypgp-debug-buffer-clear    t]
7897       "----"
7898       ["Display comint"                  tinypgp-show-buffer-comint    t]
7899       ["Display debug"                   tinypgp-show-buffer-debug           t]
7900       ["Display finger"                  tinypgp-show-buffer-finger    t]
7901       ["Display http"                    tinypgp-show-buffer-http            t]
7902       ["Display shell"                   tinypgp-show-buffer-shell           t]
7903       ["Display tmp"                     tinypgp-show-buffer-tmp     t]))))
7904
7905 ;;; ----------------------------------------------------------------------
7906 ;;;
7907 (defun tinypgp-summary-mode-define-keys ()
7908   "Define keys."
7909   (let* ((p    tinypgp-:summary-mode-prefix-key)
7910          (map  tinypgp-:summary-mode-map))
7911
7912     (tinypgp-mode-define-keys-buffer map p)
7913     (tinypgp-mode-define-keys-user   map p)
7914
7915     (define-key map
7916       (concat p (ti::string-right p 1)) 'tinypgp-summary-mode-next-action)
7917
7918     (define-key map (concat p "?")      'tinypgp-summary-mode-describe)
7919     (define-key map (concat p "d")      'tinypgp-summary-mode-decrypt)
7920     (define-key map (concat p "v")      'tinypgp-summary-mode-verify)))
7921
7922 ;;}}}
7923 ;;{{{ code: Mode functions
7924
7925 (eval (ti::macrof-minor-mode-viper-attach "tinypgp-mode-" 'tinypgp-mode))
7926
7927 ;;; ----------------------------------------------------------------------
7928 ;;;
7929 ;;;
7930 (ti::macrof-minor-mode
7931  tinypgp-mode                           ;1
7932  "PGP minor mode.
7933 Mode description:
7934 \\{tinypgp-:mode-map}
7935 "
7936  tinypgp-install-modes                  ;3
7937  tinypgp-mode                           ;4
7938  tinypgp-:mode-name
7939
7940  tinypgp-:mode-prefix-key               ;5
7941  tinypgp-:mode-menu                     ;6
7942
7943  nil                                    ;7
7944  "TinyPgp"                              ;8
7945  tinypgp-:mode-hook
7946
7947  (progn
7948    (if (null tinypgp-:pubring-now)
7949        (setq tinypgp-:pubring-now
7950              (tinypgp-expand-file-name
7951               (nth 1 (car (tinypgp-pubring-table))))))
7952
7953    (if (not (file-exists-p tinypgp-:pubring-now))
7954        (error "TinyPgp: Can't init mode, pubring not found '%s'"
7955               tinypgp-:pubring-now))
7956
7957    (if (not (stringp tinypgp-:user-now))
7958        (error "TinyPgp: Can't init mode, user is not defined '%s'"
7959               tinypgp-:user-now))
7960    (tinypgpd "tinypgp-mode" arg)
7961    (tinypgp-update-modeline)))
7962
7963 (defun turn-on-tinypgp-mode  ()
7964   "Pgp mode on."
7965   (tinypgp-mode 1))
7966
7967 (defun turn-off-tinypgp-mode ()
7968   "Pgp mode off."
7969   (tinypgp-mode 0))
7970
7971 ;;; ----------------------------------------------------------------------
7972 ;;;
7973 (defun turn-on-tinypgp-mode-maybe ()
7974   "Turn on `tinypgp-mode' only if PGP tags are found from buffer.
7975 This function is by default installed into `find-file-hooks'."
7976   (when (and (null tinypgp-mode)
7977              (ti::mail-pgp-p))
7978     (turn-on-tinypgp-mode)))
7979
7980 ;;; ----------------------------------------------------------------------
7981 ;;;
7982 (defun tinypgp-mode-describe ()
7983   "Describe mode."
7984   (interactive)
7985   (describe-function 'tinypgp-mode))
7986
7987 ;;; .................................................... &pgp-key-mode ...
7988
7989 ;;; ----------------------------------------------------------------------
7990 ;;;
7991 (ti::macrof-minor-mode
7992  tinypgp-key-mode
7993  "PGP key handling minor mode. You should extract the the key information
7994 to some buffer first before turning on this mode.
7995 Eg. with \\[tinypgp-key-info-at-point-show]
7996
7997 Mode description:
7998 \\{tinypgp-:key-mode-map}
7999 "
8000  tinypgp-install-modes
8001  tinypgp-key-mode
8002  tinypgp-:key-mode-name                 ;5
8003
8004  tinypgp-:key-mode-prefix-key
8005  tinypgp-:key-mode-menu                 ;7
8006
8007  nil
8008  "TinyPgp Key handling"
8009  tinypgp-:key-mode-hook                 ;10
8010
8011  (progn
8012    (if tinypgp-key-mode
8013        (tinypgp-update-modeline))))
8014
8015 ;;; ----------------------------------------------------------------------
8016 ;;;
8017 (defun tinypgp-key-mode-describe ()
8018   "Describe mode."
8019   (interactive)
8020   (describe-function 'tinypgp-key-mode))
8021
8022 ;;; .................................................... &pgp-sum-mode ...
8023
8024 ;;; ----------------------------------------------------------------------
8025 ;;;
8026 (ti::macrof-minor-mode
8027  tinypgp-summary-mode
8028  "PGP summary minor mode. This function can only be turned on in VM
8029 RMAIL and GNUS summary buffer.  Any PGP action called there is reflected
8030 on the current message selected.
8031
8032 Mode description:
8033 \\{tinypgp-:summary-mode-map}
8034 "
8035  tinypgp-install-modes
8036  tinypgp-summary-mode
8037  tinypgp-:summary-mode-name
8038
8039  tinypgp-:summary-mode-prefix-key
8040  tinypgp-:summary-mode-menu
8041
8042  nil
8043  "TinyPgp Mail Summary"
8044  tinypgp-:summary-mode-hook
8045
8046  (progn
8047    (when tinypgp-summary-mode
8048      (unless (memq major-mode
8049                    '(rmail-summary-mode
8050                      vm-summary-mode
8051                      gnus-summary-mode
8052                      mh-show-mode))
8053        (setq tinypgp-summary-mode nil)
8054        (error "You can use this mode only in Mail summary buffers."))
8055
8056      ;; This modeline update is a problem only in RMAIL-summary buffer.
8057      ;; We cannot use rmail-summary-mode-hook, because turning mode on
8058      ;; there does no good (summary buffer is not shown yet)
8059      ;;
8060      ;; See advised function rmail-new-summary which calls us.
8061      ;;
8062      (tinypgp-update-modeline))))
8063
8064 (defun turn-on-tinypgp-summary-mode ()
8065   "Summary mode." (tinypgp-summary-mode 1))
8066
8067 (defun turn-off-tinypgp-summary-mode ()
8068   "Summary mode." (tinypgp-summary-mode 0))
8069
8070 ;;; ----------------------------------------------------------------------
8071 ;;;
8072 (defun tinypgp-summary-mode-describe ()
8073   "Describe mode."
8074   (interactive)
8075   (describe-function 'tinypgp-summary-mode))
8076
8077 ;;; ----------------------------------------------------------------------
8078 ;;;
8079 (defun tinypgp-summary-mode-verify (&optional arg)
8080   "Verify current article with ARG.
8081
8082 Note:
8083
8084   In GNUS Summary buffer, where the *Article* is guessed to be a newsgroup
8085   post, the prefix arg meaning has been reversed. When you verify
8086   newsgroup article, the content of the article is not replaced, as it
8087   would anywhere else."
8088   (interactive "P") (tinypgp-summary-action 'verify arg 'verb))
8089
8090 (defun tinypgp-summary-mode-decrypt (&optional arg)
8091   "Decrypt current article with ARG."
8092   (interactive "P") (tinypgp-summary-action 'decrypt arg 'verb))
8093
8094 (defun tinypgp-summary-mode-next-action (&optional arg)
8095   "Guess next action and pass ARG."
8096   (interactive "P") (tinypgp-summary-action 'next-action arg 'verb))
8097
8098 ;;; ----------------------------------------------------------------------
8099 ;;;
8100 (defun tinypgp-summary-action-1 (action func arg verb)
8101   "See source code for `tinypgp-summary-action' for ACTION FUNC ARG VERB."
8102   (save-excursion
8103     (pop-to-buffer (current-buffer))
8104     (cond
8105      ((eq action 'verify)       (funcall func arg 'verb))
8106      ((eq action 'next-action)  (call-interactively func))
8107      ((eq action 'decrypt)      (tinypgp-decrypt-mail-verbose (quote arg))))))
8108
8109 ;;; ----------------------------------------------------------------------
8110 ;;;
8111 (defun tinypgp-summary-action (action-sym &optional arg verb)
8112   "Do ACTION-SYM in summary buffer. ARG is passed to called function. VERB."
8113   (let* ((fid   "tinypgp-summary-action: ")
8114          (win   (get-buffer-window (current-buffer)))
8115          (list  '(verify decrypt next-action))
8116          str
8117          func)
8118     (if (not (memq action-sym list))
8119         (error "TinyPgp: Unregognized/Not supported summary action."))
8120
8121     (setq str (format "tinypgp-%s-mail" (symbol-name action-sym)))
8122
8123     (if (null (setq func (intern-soft str)))
8124         (error "TinyPgp: Function not found %s" str))
8125
8126     (tinypgpd fid major-mode action-sym func)
8127
8128     (cond
8129      ((eq major-mode 'rmail-summary-mode)
8130       (ti::mail-rmail-macro
8131        (tinypgp-summary-action-1 action-sym func arg verb)))
8132
8133      ((eq major-mode 'vm-summary-mode)
8134       (ti::mail-vm-macro
8135        (tinypgp-summary-action-1 action-sym func arg verb)))
8136
8137      ((eq major-mode 'gnus-summary-mode)
8138       (ti::mail-gnus-macro
8139        ;;  In newsgroup post the user doesn't want to "open"
8140        ;;  the message when he verifies it. Reverse the ARG meaning
8141        (when (and (eq action-sym 'verify) (ti::mail-news-buffer-p))
8142          (ti::bool-toggle arg))
8143        (tinypgpd fid action-sym "ARG" arg "NEWS" (ti::mail-news-buffer-p))
8144        (tinypgp-summary-action-1 action-sym func arg verb)))
8145
8146      ((eq major-mode 'mh-show-mode)
8147       (ti::mail-mh-macro
8148        (tinypgp-summary-action-1 action-sym func arg verb)))
8149
8150      (t
8151       (error "TinyPgp: I Can't do anything in this major mode.")))
8152     (if (window-live-p win)             ;Back to summary
8153         (select-window win))))
8154
8155 ;;}}}
8156
8157 ;;{{{ code: defadvice
8158
8159 ;;; ....................................................... &defadvice ...
8160
8161 (defadvice rmail-new-summary (after tinypgp act)
8162   "Update mode line.
8163 For some reason this couldn't be done from 19.28's`rmail-summary-mode-hook'."
8164   (tinypgp-summary-mode))
8165
8166 ;;; (ad-unadvise 'vm-edit-message)
8167 ;;;
8168 (defadvice vm-edit-message (after tinypgp dis)
8169   "If Edit is called interactively, call `turn-on-tinypgp-mode'.
8170 We can't do this in `vm-edit-message-hoo' because the hook function
8171 doesn't know if the function were called interactively or not."
8172   (if (and (interactive-p)
8173            (null tinypgp-mode))
8174       (turn-on-tinypgp-mode)))
8175
8176 ;;}}}
8177
8178 ;;{{{ Special: sending email
8179
8180 ;;; ........................................................ &sendmail ...
8181
8182 ;;; ----------------------------------------------------------------------
8183 ;;;
8184 (defun tinypgp-sendmail-key-not-in-plan (email)
8185   "Send small mail to EMAIL and ask him to add his PGP key to ~/.plan.
8186
8187 When you finger someone for his pgp key, consider this before you send
8188 notice to person. (check the content of finger buffer)
8189
8190 o  Finger finds the .plan file and the contents seems valid, there is login
8191    name and directory information and soon. This would indicate that
8192    it is ok to send notice to person.
8193 o  Finger result"
8194   (interactive
8195    (let* (ret)
8196      (and (y-or-n-p
8197            ;;  someone may think this harrashement
8198            ;;
8199            "Are you sure you want to send .plan notice? Think twice..." )
8200           (y-or-n-p
8201            "You did check the content of the finger results: was it ok otw? ")
8202           (setq ret
8203                 (read-from-minibuffer
8204                  "Mail to: "
8205                  (ignore-errors (ti::mail-get-field "to" nil 'nil-mode)))))
8206      (if (not (string-match "@"))
8207          (error "Abort."))
8208      (list ret)))
8209   (tinypgp-sendmail email 'pk-finger-none)
8210   (if (interactive-p)
8211       (message "Email sent to: %s" email)))
8212
8213 ;;; ----------------------------------------------------------------------
8214 ;;;
8215 (defun tinypgp-sendmail (email mode &optional arg1 arg2 arg3)
8216   "Send email notice to EMAIL address according to MODE and ARG1 ARG2 ARG3."
8217   (let* ((id
8218           (format
8219            "\nThis is message from TinyPgp.el %s\n\n"
8220            (tinypgp-version-number)))
8221
8222          (subject       (format
8223                          " %s, Notification concerning your PGP."
8224                          email))
8225          msg)
8226     (cond
8227      ((eq mode 'pk-no-full-format)
8228       (setq msg
8229             (format
8230              (concat
8231               "\tWe fingered address %s to get your public key\n\t"
8232               "but it was not presented in full format of pgp -fakx.\n\t"
8233               "Would you please insert all test starting from\n\t"
8234               "'Key for user ID:' line from the -fakx output. \n\t"
8235               "That would offer access to your other information\n\t"
8236               "that may be needed. \nt"
8237               "\n"
8238               "Please note that the -kv format is not the same as -fakx\n"
8239               "\n"
8240               "\tThank you.\n")
8241              email)))
8242      ((eq mode 'pk-finger-none)
8243       (setq msg
8244             (format
8245              (concat
8246               "\tHi!\n\t"
8247               "We could finger address %s but there was no PGP \n\t"
8248               "Public key available. Would you kindly run \n\t"
8249               "'pgp -fakx' on you keyId and put all\n\t"
8250               "lines after 'Key for user ID:' to you $HOME/.plan file.\n\n\t"
8251               "Thank you.  Please excuse this message if you don't have\n"
8252               "or use PGP\n")
8253              email)))
8254      (t
8255       (error "TinyPgp: Unknown mode")))
8256
8257     (ti::mail-sendmail-macro email subject 'send
8258                              (insert id msg))))
8259
8260 ;;}}}
8261 ;;{{{ BBDB
8262
8263 ;;; ............................................................ &bbdb ...
8264
8265 (defcustom tinypgp-:bbdb-field 'pgp-mail
8266   "*Field to use in BBDB to store PGP preferences.
8267 Entry in table `tinypgp-:auto-action-table' overrides BBDB definition.
8268
8269 Field can have values:
8270
8271   'sign'        Sign message
8272   'sign-Keyid'  Sign with KeyId
8273   'xpgp'        Use X-pgp when signing.
8274   'enccrypt'    Encrypt message by looking at To field. If you want to encrypt
8275                 using some other value, like 0xFFFFFF hex key id, see
8276                 variable `tinypgp-:email-substitution-table'
8277   'mime-tm'     use PGP/MIME with package TM
8278   '1pass'       Use 1 pass encrypt and sign. The message is signed with
8279                 active pgp user's key
8280   '1pass-keyId' ..same but sign by using KeyId
8281
8282 You can't use `sign' and `encrypt' with `1pass', which has highest
8283 precedence.
8284
8285 Examples:
8286
8287   pgp-mail: sign                ;; Sign by pgp user
8288   pgp-mail: sign mime-tm        ;; PGP/MIME sign with TM package
8289   pgp-mail: encrypt
8290   pgp-mail: 1pass               ;; encryt and sign"
8291   :type   'symbol
8292   :group 'TinyPgp)
8293
8294 ;;; ----------------------------------------------------------------------
8295 ;;;
8296 (defun tinypgp-bbdb-1 (name address field)
8297   "Look up user NAME and ADDRESS in BBDB and return FIELD"
8298   (let* ((record (bbdb-search-simple name address)))
8299     (when record
8300       (bbdb-record-getprop record field))))
8301
8302 ;;; ----------------------------------------------------------------------
8303 ;;;
8304 (defun tinypgp-bbdb-id (&optional email)
8305   "Return BBDB `pgp-id' field matching EMAIL or To-field address."
8306   (interactive)
8307   (when (featurep 'bbdb)
8308     (let* ((fid      "tinypgp-bbdb-id:")
8309            (key      'pgp-id)
8310            ret
8311            address)
8312       (setq ret
8313             (if email
8314                 (tinypgp-bbdb-1 "" email key)
8315               (setq address  (mail-extract-address-components
8316                               (or (mail-fetch-field "To" nil t) "")))
8317               (when (nth 1 address)
8318                 (tinypgp-bbdb-1 (or (nth 0 address) "") (nth 1 address) key))))
8319       (tinypgpd fid 'ARG email 'address address 'RET ret)
8320       ret)))
8321
8322 ;;; ----------------------------------------------------------------------
8323 ;;;
8324 (defun tinypgp-bbdb-entry ()
8325   "Return bbdb auto action entry in format `tinypgp-:auto-action-table'."
8326   (when (featurep 'bbdb)
8327     (let* ((fid      "tinypgp-bbdb-entry:")
8328            (to-field (mail-fetch-field "To" nil t))
8329            (address  (mail-extract-address-components (or to-field "")))
8330            elt sign enc mime-mua xpgp)
8331       (tinypgpd fid to-field address)
8332
8333       (when (and (nth 1 address)
8334                  (setq elt (tinypgp-bbdb-1 (car address) (nth 1 address)
8335                                            tinypgp-:bbdb-field)))
8336
8337         (if (string-match "mime" elt)
8338             (setq mime-mua 'mime))
8339
8340         (cond
8341          ((string-match "sign-\\([^ \t]+\\)" elt)
8342           (setq sign (match-string 1 elt)))
8343          ((string-match "sign" elt)
8344           (setq sign tinypgp-:user-now)))
8345
8346         (if (string-match "xpgp" elt)
8347             (setq xpgp t))
8348
8349         (setq enc (string-match "encrypt" elt))
8350
8351         (when (string-match "1pass" elt)
8352           (setq sign (make-symbol tinypgp-:user-now))
8353           (setq enc  t))
8354
8355         (if (and mime-mua sign)
8356             (setq sign (make-symbol sign)))
8357
8358         ;; '(EVAL-OR-REGEXP  [SIGN-KEY-ID] [ENCRYPT]
8359         ;;   [MIME-MUA] [XPGP] [KEYRING])
8360
8361         (list
8362          (nth 1 address)
8363          sign enc mime-mua xpgp)))))
8364 ;;}}}
8365
8366 ;;{{{ special: Mode specific actions
8367
8368 ;;; ................................................... &mode-specific ...
8369
8370 ;;; ----------------------------------------------------------------------
8371 ;;; #todo: tinypgp-mail-do-fcc breaks in VM
8372 ;;;
8373 (defun tinypgp-mail-do-fcc (&optional cmd user msg string)
8374   "Do FCC before the message is encrypted and remove FCC field.
8375 You don't want sendmail.el to FCC message which was encrypted
8376 with the other user's public key.
8377
8378 This function Supports MUAs:
8379
8380   Sendmail Fcc      -- mail-mode
8381   Gnus Gcc          -- message-mode
8382
8383 Input:
8384   CMD
8385   USER
8386   MSG
8387   STRING"
8388   (let ((fid "tinypgp-mail-do-fcc: ")
8389         field-fcc field-gcc
8390         hmax)
8391
8392     ;;#todo VM FCC must be handled differently ?
8393     ;;#todo Gnus 5 mail fcc ?
8394
8395     (tinypgpd fid "in: " cmd user msg string major-mode)
8396
8397     (setq field-fcc (mail-fetch-field "fcc")
8398           field-gcc (mail-fetch-field "gcc"))
8399
8400     (when (and (memq major-mode '(mail-mode message-mode))
8401                (memq cmd        '(encrypt encrypt-sign)))
8402
8403       (setq hmax (ti::mail-hmax))
8404
8405       (tinypgpd fid 'fcc field-fcc 'gcc field-gcc
8406                 'buffer (current-buffer)
8407                 'header-max  hmax
8408                 'point-max   (point-max))
8409
8410       (when (and field-gcc (featurep 'gnus))
8411         (gnus-inews-do-gcc))
8412
8413       (cond
8414        ((ti::xemacs-p)                  ;needs MARKER
8415         (save-excursion
8416           (goto-char hmax)
8417           (setq hmax (point-marker)))
8418         (mail-do-fcc hmax)              ;Header end
8419         (setq hmax nil))                ;kill marker
8420
8421        (t                               ;XE19.14 and Emacs needs POINT
8422         (mail-do-fcc (ti::mail-hmax))))
8423
8424       (tinypgp-hash 'fcc 'put 'fcc field-fcc)
8425       (tinypgp-hash 'gcc 'put 'gcc field-gcc)
8426
8427       ;; Message saving happened in another buffer, remove these
8428       ;; fields from this original buffer.
8429
8430       (while (not (ti::nil-p (mail-fetch-field "fcc")))
8431         (ti::mail-kill-field "^FCC"))
8432
8433       (while (not (ti::nil-p (mail-fetch-field "gcc")))
8434         (ti::mail-kill-field "^GCC")))))
8435
8436 ;;; ----------------------------------------------------------------------
8437 ;;;
8438 (defun tinypgp-mode-specific-control-before
8439   (cmd &optional user msg string)
8440   "Turn on possible edit mode while we do some PGP action.
8441 This function is called prior the PGP action takes effect in current
8442 region or buffer. Eg. in RMAIL we have to turn on the edit mode in
8443 order to modify the message content.
8444
8445 Input:
8446
8447   The content of these function call parameter depends on the
8448   calling CMD which can be 'sign 'encrypt 'decrypt 'verify.
8449   You have to look at the source code to see what is passed in each case.
8450   CMD OPTIONAL USER MSG STRING
8451
8452 Used hash entries:
8453
8454   The buffer pointer is recorded to hash table under property
8455   'mode-specific and value 'buffer. This is name of the current buffer
8456   where the original message is.
8457
8458   When edit mode is turned on, the buffer may now be different and
8459   the buffer pointer is recorded under property 'mode-specific and value
8460   'buffer-edit.
8461
8462 References:
8463
8464   `tinypgp-:verify-before-hook'         ;; contain this function
8465   `tinypgp-cmd-macro'                   ;; calls this function
8466   `tinypgp-mode-specific-control-after'   ;; 'the other side of the coin'"
8467   (let ((fid "tinypgp-mode-specific-control-before: "))
8468
8469     (tinypgpd fid "CMD" cmd user msg  "BUFFER" (current-buffer) major-mode)
8470
8471     (tinypgp-mail-do-fcc cmd user msg string)
8472
8473     ;; When "after" function runs it checks if this flag is non-nil
8474     ;; and strores the contents of the "clone" buffer there.
8475
8476     (tinypgp-hash 'mode-specific 'put 'register  nil    'global)
8477
8478     ;;  We have to record the initial buffer, so that the AFTER
8479     ;;  hook can restore the state in correct buffer. The package
8480     ;;  may die anywhere in the code and the buffer pointer certainly
8481     ;;  isn't pointing to the right place any moreon error.
8482
8483     (tinypgp-hash 'mode-specific 'put 'buffer      (buffer-name)  'global)
8484     (tinypgp-hash 'mode-specific 'put 'major-mode  major-mode     'global)
8485     (tinypgp-hash 'vm          'put 'control     nil            'global)
8486
8487     ;; - For some unknown reason the VM window configurations
8488     ;;   is mixed when we open edit mode and close it afterwards,
8489     ;;   we must save window configuration now.
8490     ;; - We save this every time, but we only use it in VM
8491
8492     (tinypgp-hash 'mode-specific 'put 'wcfg
8493                   (current-window-configuration)
8494                   'global)
8495
8496     (tinypgp-hash 'mode-specific 'put 'frame    (selected-frame)    'global)
8497     (tinypgp-hash 'mode-specific 'put 'window   (selected-window)   'global)
8498     (tinypgp-hash 'mode-specific 'put 'read-only buffer-read-only    'global)
8499
8500     (when (featurep 'vm)
8501       (tinypgp-hash 'vm 'put 'vm-frame-per-edit vm-frame-per-edit 'global))
8502
8503     (tinypgp-hash 'mode-specific 'put 'buffer      (buffer-name)  'global)
8504
8505     ;; ....................................................... secring ...
8506     (when (and tinypgp-:secring-crypt-mode
8507                (not (memq cmd '(verify))))
8508       (tinypgp-secring-use))
8509
8510     ;; ......................................................... modes ...
8511
8512     ;;  We have to quit TM so that underlying mode underneath is
8513     ;;  exposed.
8514     ;;
8515     ;;  But in Gnus, this wouldn't have any effect, because TM is permanently
8516     ;;  on. See ESC-t which runs `gnus-summary-toggle-mime'.
8517
8518     (when (eq major-mode 'mime/viewer-mode) ;TM preview buffer
8519       (cond
8520        ((and (featurep 'gnus)
8521              (string= (buffer-name)
8522                       (symbol-value 'gnus-article-buffer)))
8523         nil)                        ;Entering article edit quits mime.
8524        (t
8525 ;;;     (setq buffer-read-only nil)
8526         ;;  in RMAIL this works
8527         (mime-viewer/quit))))
8528
8529     (cond
8530      ((and (featurep 'gnus)
8531            (or (string= (buffer-name) (symbol-value 'gnus-article-buffer))
8532                (eq major-mode 'gnus-article-mode)))
8533       (when (and buffer-read-only
8534                  (not (eq 'ok (ignore-errors
8535                                 (gnus-summary-edit-article) 'ok))))
8536         ;;  Eg. NNTP backend doesn't allow editing buffers.
8537         (message (substitute-command-keys "\
8538 Gnus backend doesn't support edit. Use \\[tinypgp-view-register]"))
8539         (tinypgp-hash 'mode-specific 'put 'register t 'global)
8540         (set-buffer (tinypgp-clone-buffer)))
8541
8542       ;;  Old Gnus versions have a bug, they give *Article* buffer
8543       ;;  for editing, which is not good. The buffer may have been
8544       ;;  formatted so that there is gnus buttons in the middle of the PGP
8545       ;;
8546       ;;  noRr110XVahfo/3MaLL2PGlJ/h8rOdZkJCPCQ1OO8BKcXg3NQWTb+RpqSbSRnbEq
8547       ;;  [...]
8548       ;;  win0apLYccO+tqhhzK3CIiDbgBGfQLNU9ju+nMOOm1VUfF2A/phMoQg6ucYrXFxk
8549       ;;
8550       ;;  We must edit the `gnus-original-article-buffer', which contains
8551       ;;  the message "as is".
8552
8553       ;;  I submitted gnus bug report on this, but Lars didn't consider
8554       ;;  it as a bug: User is expect to do C-u g to view raw article.
8555
8556       (if (not (buffer-live-p
8557                 (get-buffer (symbol-value 'gnus-original-article-buffer))))
8558           ;;  If the original article weren't found, try anyway in
8559           ;;  this *Article* buffer. It may even succeed if there
8560           ;;  is no gnus buttons in the PGP block.
8561
8562           (message "TinyPgp: Wish me luck, I couldn't find original article")
8563
8564         ;;  Ok, found buffer, so play safe
8565
8566         (delete-region (point-min) (point-max))
8567         (insert-buffer (symbol-value 'gnus-original-article-buffer))))
8568
8569      ((memq major-mode '(rmail-mode))
8570       (rmail-edit-current-message))
8571
8572      ((memq major-mode '(vm-mode))
8573
8574       ;; - VM opens another frame immediately if you
8575       ;;   put message in edit mode (that happend when you decrypt mail)
8576       ;; - We don't want it to do that; Set this locally to nil
8577
8578       (setq vm-frame-per-edit nil)
8579       (vm-edit-message)
8580       (tinypgp-hash 'vm 'put 'control 'edit 'global)))
8581
8582     ;;  Expose any hidden text
8583
8584     (set-text-properties (point-min) (point-max) nil)
8585     (ti::overlay-remove-region (point-min) (point-max))
8586
8587     (tinypgp-hash 'mode-specific 'put 'buffer-edit (buffer-name) 'global)
8588     (tinypgpd fid major-mode "BUFFER-EDIT" (current-buffer))
8589     nil))
8590
8591 ;;; ----------------------------------------------------------------------
8592 ;;;
8593 (defun tinypgp-mode-specific-label (cmd &optional buffer)
8594   "Add mail-agent labels according to CMD. Work buffer is BUFFER."
8595   (let* ((fid "tinypgp-mode-specific-label")
8596
8597          (tbl   tinypgp-:label-table)
8598          (v+    (nth 0 (nth 1 (assq 'v tbl))))
8599          (v-    (nth 1 (nth 1 (assq 'v tbl))))
8600          (si    (nth 1 (assq 's tbl)))
8601          (en    (nth 1 (assq 'e tbl)))
8602          (de    (nth 1 (assq 'd tbl)))
8603          (pgp   (nth 1 (assq 'pgp tbl)))
8604          stat)
8605     (with-current-buffer (or buffer (current-buffer))
8606       (cond
8607
8608        ;; ...................................................... rmail ...
8609
8610        ((memq major-mode '(rmail-mode rmail-edit-mode))
8611
8612         (cond
8613          ((eq cmd 'sign)
8614           (rmail-kill-label v+)
8615           (rmail-kill-label v-)
8616           (when (not (ti::nil-p pgp)) (rmail-add-label pgp))
8617           (when (not (ti::nil-p si)) (rmail-add-label si)))
8618
8619          ((eq cmd 'decrypt)
8620           (rmail-kill-label en)
8621           (when (not (ti::nil-p pgp)) (rmail-add-label pgp))
8622           (rmail-add-label de)
8623
8624           ;;  The message may have beeen encrypted and signed (one pass),
8625           ;;  force checking verify too.
8626
8627           (setq cmd 'verify))
8628
8629          ((eq cmd 'encrypt)
8630           (rmail-kill-label de)
8631           (when (not (ti::nil-p pgp)) (rmail-add-label pgp))
8632           (rmail-add-label en))
8633
8634          ((eq cmd 'encrypt-sign)
8635           (rmail-kill-label de)
8636           (when (not (ti::nil-p pgp)) (rmail-add-label pgp))
8637           (rmail-add-label en)
8638           (rmail-add-label si)))
8639
8640         (when (eq cmd 'verify)
8641           ;;  This is special, the parameter call order is 'beg end RET'
8642           ;;
8643           (rmail-add-label "pgp")
8644           (setq stat (or (tinypgp-binary-get-result-verify-status) ""))
8645           (cond
8646            ((string-match "good.*signature" stat)
8647             (rmail-kill-label si)
8648             (rmail-kill-label v-)
8649             (rmail-add-label  v+))
8650            ((string-match "bad.*signature" stat)
8651             (rmail-kill-label si)
8652             (rmail-kill-label v+)
8653             (rmail-add-label  v-)))))
8654
8655        ;; ......................................................... vm ...
8656
8657        ((or (memq major-mode '(vm-mode vm-edit-mode))
8658             (string-match "edit.*note " (buffer-name)))
8659         (tinypgpd fid "LABELING" cmd (current-buffer))
8660
8661         (cond
8662          ((eq cmd 'sign)
8663           (vm-delete-message-labels v+ 1)
8664           (vm-delete-message-labels v- 1)
8665           (vm-add-message-labels    si 1)
8666           (when (not (ti::nil-p pgp)) (vm-add-message-labels    pgp 1)))
8667
8668          ((eq cmd 'decrypt)
8669           (vm-delete-message-labels en 1)
8670           (vm-add-message-labels    de 1)
8671           (when (not (ti::nil-p pgp)) (vm-add-message-labels    pgp 1))
8672           (setq cmd 'verify))
8673
8674          ((eq cmd 'encrypt)
8675           (vm-delete-message-labels de 1)
8676           (vm-add-message-labels    en 1)
8677           (when (not (ti::nil-p pgp)) (vm-add-message-labels    pgp 1)))
8678
8679          ((eq cmd 'encrypt-sign)
8680           (vm-delete-message-labels de 1)
8681           (vm-add-message-labels    si 1)
8682           (vm-add-message-labels    en 1)
8683           (when (not (ti::nil-p pgp)) (vm-add-message-labels    pgp 1))))
8684
8685         (when (eq cmd 'verify)
8686           (when (not (ti::nil-p pgp)) (vm-add-message-labels pgp 1))
8687           (setq stat (or (tinypgp-binary-get-result-verify-status) ""))
8688           (cond
8689            ((string-match "good.*signature" stat)
8690             (vm-delete-message-labels si 1)
8691             (vm-delete-message-labels v- 1)
8692             (vm-add-message-labels    v+ 1))
8693            ((string-match "bad.*signature" stat)
8694             (vm-delete-message-labels si 1)
8695             (vm-delete-message-labels v+ 1)
8696             (vm-add-message-labels    v- 1)
8697             (when (not (ti::nil-p pgp))
8698               (vm-add-message-labels    pgp 1))))))))))
8699
8700 ;;; ----------------------------------------------------------------------
8701 ;;;
8702 (defun tinypgp-mode-specific-control-after
8703   (cmd &optional user msg string)
8704   "See `tinypgp-mode-specific-control-before' for CMD USER  MSG STRING."
8705   (let* ((fid  "tinypgp-mode-specific-control-after: ")
8706
8707          ;;  We have to set this to nil; otherwise TM goes nuts
8708          ;;  when it calls tm-rmail/preview-message
8709          ;;  #todo: investigate
8710
8711          rmail-show-message-hook
8712
8713          (buffer
8714           (tinypgp-hash 'mode-specific 'get 'buffer nil 'global))
8715          (buffer-edit
8716           (tinypgp-hash 'mode-specific 'get 'buffer-edit nil 'global))
8717
8718          restore-cfg)
8719
8720     (when (tinypgp-hash 'mode-specific 'get 'register nil 'global)
8721       (with-current-buffer tinypgp-:buffer-tmp-article
8722         (ti::mail-hmax 'move)
8723         (set-register
8724          tinypgp-:register
8725          (buffer-substring (point) (point-max)))))
8726
8727     (if rmail-show-message-hook ;;  ByteComp silencer; no-op
8728         (setq rmail-show-message-hook nil))
8729
8730     (tinypgpd fid cmd user "BUFFER" buffer "B-edit" buffer-edit major-mode
8731               msg string (buffer-name))
8732
8733     ;; ....................................................... secring ...
8734
8735     (when tinypgp-:secring-crypt-mode
8736       (tinypgp-secring-kill-maybe))
8737
8738     ;; .......................................................... mode ...
8739     ;;  The "before" hook must have been called otherwise, there must be
8740     ;;  some error somewhere or exist some situation I haven't thought of.
8741
8742     (with-current-buffer (or buffer-edit
8743                              (prog1 nil
8744                                (tinypgpd fid "**CONFLICT; no buffer")
8745                                (ti::read-char-safe-until
8746                                 "\
8747 Internal error in AFTER HOOK; send bug report + debug immediately."))
8748                              (current-buffer))
8749       (cond
8750        ((memq major-mode '(rmail-mode rmail-edit-mode))
8751         ;; ..................................................... rmail ...
8752
8753         (if (eq major-mode 'rmail-edit-mode)
8754             (rmail-cease-edit))
8755         (tinypgp-mode-specific-label cmd))
8756
8757        ;; ....................................................... gnus ...
8758        ((eq major-mode 'gnus-article-edit-mode)
8759         (gnus-article-edit-done))
8760
8761        ((memq major-mode '(gnus-article-mode
8762                            mime/viewer-mode))
8763         (setq buffer-read-only          ;Restore this value
8764               (tinypgp-hash 'mode-specific 'get 'read-only nil 'global)))
8765
8766        ;; ......................................................... vm ...
8767        ((or (memq major-mode '(vm-mode vm-edit-mode))
8768             ;;  XEmacs 19.14 sources say...
8769             ;;
8770             ;;  In vm-edit.el :: vm-edit-message
8771             ;;  It says (funcall (or vm-edit-message-mode 'text-mode)),
8772             ;;  where vm-vars.el:1506:(defvar vm-edit-message-mode 'text-mode
8773             ;;
8774             ;;  --> VM does editing in text mode? Glup; that makes hard
8775             ;;      to detect its edit buffer.
8776             ;;
8777             (string-match "edit.*note " (buffer-name)))
8778
8779         (tinypgpd fid "VM ENTRY" major-mode (current-buffer) (buffer-name))
8780
8781         (setq restore-cfg 'vm)        ;Yes; we need to restore Win cfg
8782
8783         (setq
8784          vm-frame-per-edit
8785          (tinypgp-hash 'vm 'put 'vm-frame-per-edit vm-frame-per-edit 'global))
8786
8787         ;;  Only close edit mode if we opened it. If user was inside
8788         ;;  edit buffer, we don't close it here.
8789
8790         (when (and (tinypgp-hash 'vm 'get 'control  nil 'global)
8791                    (or (eq major-mode 'vm-edit-mode)
8792                        (string-match "edit.*note " (buffer-name))))
8793           (vm-edit-message-end))
8794         (tinypgp-mode-specific-label cmd))))
8795
8796     (when restore-cfg
8797       (let* ((wcfg
8798               (tinypgp-hash 'mode-specific 'get 'wcfg nil 'global))
8799              (frame
8800               (tinypgp-hash 'mode-specific 'get 'frame nil 'global))
8801              (window
8802               (tinypgp-hash 'mode-specific 'get 'window nil 'global)))
8803         (set-window-configuration wcfg)
8804         (select-frame frame)
8805         (select-window window)))
8806
8807     (tinypgp-hash 'mode-specific 'put 'buffer nil) ;Clear this
8808     ;; hook's return value
8809     nil))
8810
8811 ;;}}}
8812
8813 ;;{{{ remail: misc
8814
8815 ;;; .......................................................... &remail ...
8816 ;;; -r-  refers to remailing
8817 ;;; -r-h refers to remailer headers
8818
8819 ;;; ----------------------------------------------------------------------
8820 ;;;
8821 (defsubst tinypgp-r-subject-cookie ()
8822   "Return random subject cookie."
8823   (nth (1- (rand1 (length tinypgp-:r-subject-table)))
8824        tinypgp-:r-subject-table))
8825
8826 ;;; ----------------------------------------------------------------------
8827 ;;;
8828 (defsubst tinypgp-r-elt-email2elt (email)
8829   "Return remailer entry when EMAIL is known."
8830   (ti::list-find tinypgp-:r-levien-table email
8831                  (function
8832                   (lambda (arg elt)
8833                     (string= arg (nth 1 elt))))))
8834
8835 ;;; ----------------------------------------------------------------------
8836 ;;;
8837 (defsubst tinypgp-r-elt-remailer (remailer)
8838   "Return remailer elt when REMAILER is known."
8839   ;;  We have the alias name, find the real email address
8840   (or (assoc remailer tinypgp-:r-host-table)
8841       (error "No such remailer %s" remailer)))
8842
8843 ;;; ----------------------------------------------------------------------
8844 ;;;
8845 (defsubst tinypgp-r-type (alias &optional email)
8846   "Return post type for remailer. ALIAS and EMAIL are mutually exclusive."
8847   (if email
8848       (ti::mail-pgpr-reply-type (nth 2 (tinypgp-r-elt-email2elt email))))
8849   (ti::mail-pgpr-reply-type (nth 2 (assoc alias tinypgp-:r-levien-table))))
8850
8851 ;;; ----------------------------------------------------------------------
8852 ;;;
8853 (put 'tinypgp-r-server-macro 'lisp-indent-function 2)
8854 (defmacro tinypgp-r-server-macro (server account &rest body)
8855   "Find SERVER and do body or signal error.
8856
8857 Input:
8858
8859   SERVER    remailer server (alias name)
8860   ACCOUNT   remailer ACCOUNT@some.remailer.net
8861             Can also be nil, in that case the `email' is not constructed.
8862             (gains little speed)
8863   BODY      lisp form to do if server exists.
8864
8865 Defined variables inside BODY
8866
8867   `info'    Full Levien list entry for server
8868   `email'   Constructed according to ACCOUNT."
8869   (`
8870    (let* ((info  (or (assoc (, server) tinypgp-:r-levien-table)
8871                      (error "Server is unknown %s" (, server))))
8872           email)
8873      (if (, account)
8874          (setq email (tinypgp-r-format-email-address (, account) info)))
8875
8876      ;;  If these varibles are not used in the macro BODY,
8877      ;;  then byteCompiler nags. Make it quiet.
8878
8879      (if (null email) (setq email nil))
8880      (if (null info)  (setq info  nil))
8881
8882      (,@ body))))
8883
8884 ;;; ----------------------------------------------------------------------
8885 ;;;
8886 (defsubst tinypgp-r-post-p (elt)
8887   "Check if this remailer ELT can be used for posting."
8888   (or (string-match "cut.* hash.* pgp.* post" (nth 2 elt))
8889       (error "\
8890 TinyPgp: not enough properties %s '%s'" (nth 0 elt) (nth 2 elt))))
8891
8892 ;;; ----------------------------------------------------------------------
8893 ;;;
8894 (defsubst tinypgp-r-init-maybe ()
8895   "Call initialise function is needed."
8896   (tinypgp-backend-set-for-action 'remail)
8897   (or (tinypgp-hash 'remail 'get 'init nil 'global)
8898       (tinypgp-r-init)))
8899
8900 ;;; ----------------------------------------------------------------------
8901 ;;;
8902 (defun tinypgp-r-init (&optional force)
8903   "Initialise remailer support. Set up all necessary variables etc.
8904 If `tinypgp-:r-levien-table' is non-nil, then this function does nothing.
8905
8906 FORCE tells to discard old values and build all from scratch.
8907 You usually do this if you have updated your remailer list.
8908 FORCE is set to t if you call this function interactively.
8909
8910 References:
8911   `tinypgp-:r-init-hook'  is run after initialise sequences have been completed."
8912   (interactive (list 'force))      ;inteactive call always forces init
8913
8914   (let ((file  tinypgp-:r-list-file)
8915         (clist tinypgp-:r-control-list)
8916         val)
8917     (tinypgp-backend-set-for-action 'remail)
8918
8919     ;; ... ... ... ... ... ... ... ... ... ... ... ... ... ... . check ...
8920
8921     (if (not (stringp tinypgp-:r-mail2news-remailer)) ;has default
8922         (error "TinyPgp: Please set Usenet post remailer tinypgp-:r-mail2news-remailer."))
8923
8924     (if (not (stringp tinypgp-:r-user-mail-address)) ;has default
8925         (error "TinyPgp: Please set tinypgp-:r-user-mail-address"))
8926
8927     (when (not (and (stringp tinypgp-:r-list-file)
8928                     (file-exists-p tinypgp-:r-list-file)))
8929       (error "TinyPgp: Hm, no tinypgp-:r-list-file please see manual.")
8930
8931       ;; 1997-08-30
8932       ;; - not a good idea. Person may not have access to ftp or
8933       ;;   the ftp location does not exist any more.
8934
8935       (message "TinyPgp: Hm, no tinypgp-:r-list-file; fetching it by finger..")
8936       (sit-for 1)
8937       ;;  Notice the 'no-init parameter. It would otw loop back to us.
8938       (tinypgp-r-update-remailer-list 'verb 'no-init))
8939
8940     ;; It is important that you have new remailer file, print
8941     ;; warning regularly if the file is old
8942
8943     (when (and tinypgp-:r-list-file
8944                (progn
8945                  (setq val (tinypgp-hash 'remail 'get 'file-warning))
8946                  (if (not (integerp val))
8947                      (setq val 0))
8948                  (incf  val)
8949                  (tinypgp-hash 'remail 'put 'file-warning val)
8950                  (eq 0 (% val 5))))     ;every 5th call
8951       (tinypgp-hash 'remail 'put 'file-warning 0)
8952       (tinypgp-r-file-old-warning))
8953
8954     ;; ... ... ... ... ... ... ... ... ... ... ... ... ... ... do init ...
8955
8956     ;;  If this doesn't exist, init all
8957
8958     (when (or force (null tinypgp-:r-levien-table))
8959       (when (or (not (stringp file))
8960                 (not (file-exists-p file)))
8961         (error
8962          (substitute-command-keys
8963           (concat
8964            "TinyPgp: Please set variable tinypgp-:r-list-file and call"
8965            "\\[tinypgp-r-update-remailer-list]"))))
8966
8967       ;;  Full RAPH's list
8968
8969       (setq tinypgp-:r-levien-table (tinypgp-r-get-list "." nil file clist))
8970       (tinypgpd "tinypgp-r-init: " tinypgp-:r-levien-table)
8971
8972       (setq tinypgp-:r-host-table      ;only cpunk and some properties
8973             (tinypgp-r-get-list nil tinypgp-:r-levien-table))
8974
8975       (if (null tinypgp-:r-host-table)
8976           (error
8977            "TinyPgp: Can't find good remailers from '%s'. Consult maintainer."
8978            tinypgp-:r-list-file))
8979
8980       (setq tinypgp-:r-reply-block-cache nil) ;Build from scratch
8981
8982       (tinypgp-hash 'remail 'put 'init (or force 'done) 'global)
8983       (if tinypgp-:r-init-hook (run-hooks 'tinypgp-:r-init-hook))
8984
8985       (if (interactive-p)
8986           (message "TinyPgp: Remailer support initialised.")))))
8987
8988 ;;; ----------------------------------------------------------------------
8989 ;;;
8990 (defun tinypgp-r-file-old-warning (&optional file days-old fmt)
8991   "Print warning if file is too old.
8992 Input:
8993
8994   FILE      Defaults to `tinypgp-:r-list-file'
8995   DAYS-OLD  Defaults to 24 (3 weeks).
8996   FMT       Message  format. First arg is %s file and second %d how old file."
8997   (interactive)
8998   (let* (days)
8999     (or file
9000         (setq file tinypgp-:r-list-file)
9001         (error "No tinypgp-:r-list-file set."))
9002
9003     (or days-old
9004         (setq days-old (* 3 7)))
9005     (setq days (ti::file-days-old file))
9006
9007     ;;  over 3 weeks old remailer list...too old
9008     ;;
9009     (when (> days days-old)
9010       (save-excursion
9011         (message
9012          (format
9013           (or fmt "'%s' is approx %d days old, which is too much.")
9014           file days))
9015         (sit-for 1)))))
9016
9017 ;;; ----------------------------------------------------------------------
9018 ;;;
9019 (defun tinypgp-r-get-list (&optional re list file control-list)
9020   "Get remailer list matching RE.
9021
9022 Input:
9023   RE        what properties to grep. The properties are sorted
9024             and defaults to \"cpunk.* hash.* pgp\". These features are
9025             considered minimum features from remailer.
9026   LIST      prepared list
9027   FILE      file from where to read the Levien list. LIST must be nil.
9028   CONTROL-LIST  See `ti::mail-pgpr-parse-levien-list'.
9029
9030 References:
9031   `tinypgp-:r-get-list-hook'  is run after the Levien file is read into
9032                             temporary buffer."
9033   (let* ((fid  "tinypgp-r-get-list:")
9034          ret)
9035     (setq re (or re "cpunk.* hash.* pgp"))
9036
9037     (unless list
9038
9039       ;;  Read remailer list from file and parse it
9040
9041       (if (or (null file)
9042               (not (file-exists-p file)))
9043           (error "TinyPgp: Can't read remailer file file '%s'" file))
9044
9045       (with-current-buffer (tinypgp-ti::temp-buffer)
9046         (insert-file-contents file)
9047         (run-hooks 'tinypgp-:r-get-list-hook)
9048         (tinypgp-r-file-old-warning)
9049
9050         (ti::pmin)
9051         (unless (setq list (ti::mail-pgpr-parse-levien-list
9052                             nil control-list))
9053           (tinypgpd fid (buffer-string))
9054           (pop-to-buffer (current-buffer))
9055           (error "\
9056 TinyPgp: Cannot parse this buffer: not in levien format. %s " file))))
9057
9058     (dolist (elt list)
9059       (if (string-match re (nth 2 elt))
9060           (push elt ret)))
9061
9062     ret))
9063
9064 ;;; ----------------------------------------------------------------------
9065 ;;;
9066 (defun tinypgp-r-mail-mode-init ()
9067   "Turn off all interfering minor modes from remailer mail buffer."
9068   (let (s)
9069     (setq s 'post-command-hook)
9070     (make-local-hook s)                 ;19.30+
9071     (remove-hook s 'timi-post-command)  ;disable tinymail.el
9072
9073     ;;  What should we remove from this hook ?
9074
9075     (setq s 'post-command-idle-hook)
9076     (when (boundp s) (make-local-hook s))
9077
9078     (setq s 'mime/editor-mode-flag)     ;tm.el
9079     (when (boundp s)  (set s nil))))
9080
9081 ;;; ----------------------------------------------------------------------
9082 ;;;
9083 (defun tinypgp-r-post-before-default ()
9084   "Disable/exit known minor modes/features."
9085   (ti::mail-mime-turn-off-mode)
9086   (if (featurep 'tinymail)
9087       (timi-mail 'disable)))
9088
9089 ;;; ----------------------------------------------------------------------
9090 ;;;
9091 (defun tinypgp-r-latent-time-random (remailer str)
9092   "Add 'r' to the time if REMAILER supports it. If STR is nil, do nothing."
9093   (when (stringp str)
9094     ;;
9095     ;; The remailers are not checked yet.
9096     ;;
9097     (if (not (char= (aref str (1- (length str))) ?r))
9098         (setq str (concat str "r"))))
9099   str)
9100
9101 ;;}}}
9102 ;;{{{ remail: reply block
9103
9104 ;;; ................................................... &r-reply-block ...
9105
9106 ;;; ----------------------------------------------------------------------
9107 ;;;
9108 (defun tinypgp-r-reply-block-read (remailer)
9109   "Read reply block for the REMAILER.
9110 Don't use this function, use `tinypgp-r-reply-block-cache' instead.
9111
9112 Return:
9113   '(buffer-pointer
9114     pgp-beg          ,points
9115     pgp-end
9116     )"
9117   (let ((elt (assoc remailer tinypgp-:r-reply-block-table))
9118         file
9119         buffer
9120         reg
9121         beg
9122         end)
9123     (unless elt
9124       (error
9125        (format
9126         (concat
9127          "TinyPgp: No Reply block defined for remailer '%s' "
9128          "in tinypgp-:r-reply-block-table")
9129         remailer)))
9130
9131     (setq file   (nth 1 elt)
9132           buffer (or (find-buffer-visiting file)
9133                      (if (file-exists-p file)
9134                          ;;
9135                          ;;  pure find avoigs calling hooks/modes
9136                          ;;  when file is loaded.
9137                          ;;
9138                          (ti::find-file-literally file)
9139                        (error "TinyPgp: No reply block file %s" file))))
9140     (with-current-buffer buffer
9141       (ti::pmin)
9142
9143       ;;  Make sure it will not be modified.
9144
9145       (setq buffer-read-only t)
9146 ;;;     (rename-buffer (concat " " file))
9147
9148       (unless (setq reg (ti::mail-pgp-block-area 'any))
9149         (pop-to-buffer buffer)
9150         (error "TinyPgp: Can't find reply block region?"))
9151       (setq beg (point-min) end (cdr reg)))
9152     (if buffer
9153         (list buffer beg end))))
9154
9155 ;;; ----------------------------------------------------------------------
9156 ;;;
9157 (defun tinypgp-r-reply-block-cache (mode &optional arg1)
9158   "Reply block cache management according to MODE and ARG1.
9159
9160 MODE:
9161
9162   'get     ARG1 = remailer alias; return reply block.
9163   'put     ARG1 = `tinypgp-:r-reply-block-cache' element
9164   'del     ARG1 = remailer alias"
9165   (let ((table   tinypgp-:r-reply-block-table)
9166         buffer
9167         elt
9168         old)
9169     (cond
9170      ((eq mode 'get)
9171       (or (setq elt (assoc arg1 table))
9172           (error "TinyPgp: %s not defined in tinypgp-:r-reply-block-table '%s'"
9173                  arg1 mode))
9174
9175       ;;  Have we read it already?
9176       (setq buffer (find-buffer-visiting (nth 1 elt)))
9177       (or (setq elt  (assq buffer tinypgp-:r-reply-block-cache))
9178           ;;  No, load it from file then
9179           ;;
9180           (and (setq elt (tinypgp-r-reply-block-read arg1))
9181                (setq old (assq (car elt) tinypgp-:r-reply-block-cache))
9182                (setq tinypgp-:r-reply-block-cache
9183                      (delq old tinypgp-:r-reply-block-cache)))
9184           (push elt tinypgp-:r-reply-block-cache))
9185
9186       ;;  Remove non-existing buffers -- keep the list up to date
9187
9188       (dolist (elt tinypgp-:r-reply-block-cache)
9189         (if (buffer-live-p (get-buffer (car elt)))
9190             (setq tinypgp-:r-reply-block-cache
9191                   (delq elt tinypgp-:r-reply-block-cache))))
9192
9193       elt)
9194
9195      ((eq mode 'del)
9196       (and (setq elt    (assoc arg1 table))
9197            (setq buffer (get-buffer
9198                          (file-name-nondirectory
9199                           (nth 1 elt))))
9200            (setq elt    (assq buffer tinypgp-:r-reply-block-cache))
9201            (setq tinypgp-:r-reply-block-cache
9202                  (delq elt tinypgp-:r-reply-block-cache)))
9203       tinypgp-:r-reply-block-cache)
9204
9205      ((eq mode 'put)
9206       (push arg1 tinypgp-:r-reply-block-cache)
9207       arg1))))
9208
9209 ;;; ----------------------------------------------------------------------
9210 ;;;
9211 (defun tinypgp-r-reply-block-insert (remailer)
9212   "Insert REMAILER's reply block."
9213   (interactive (list (tinypgp-ask-reply-block-remailer)))
9214   (let* ((elt (tinypgp-r-reply-block-cache 'get remailer)))
9215     (if (null elt)
9216         (error "TinyPgp: Invalid return value.")
9217       (insert-buffer-substring (nth 0 elt) (nth 1 elt) (nth 2 elt)))))
9218
9219 ;;; ----------------------------------------------------------------------
9220 ;;;
9221 (defun tinypgp-r-reply-block-header (remailer latent key anon-to)
9222   "Return reply block headers of remailer.
9223
9224 Input:
9225
9226   REMAILER  string or symbol or list, The remailer used.
9227             If list, then the REMAILER is remailer-elt from
9228             `tinypgp-:r-levien-table'
9229   LATENT    latent time specification. This is not be used if
9230             remailer does not support it.
9231   KEY       The conventional crypt password
9232   ANON-TO   Where to send the reply block (return address)."
9233   (if (symbolp remailer) (setq remailer (symbol-name remailer)))
9234   (let* ((properties   (cond
9235                         ((ti::listp remailer)  remailer)
9236                         ((tinypgp-r-elt-remailer remailer))))
9237 ;;;      (email         (nth 1 properties))
9238          (rtype         (ti::mail-pgpr-reply-type        (nth 2 properties)))
9239          ;;  What kind of reply block: With/out latent ?
9240          ;;
9241          (btype         (nth 2 properties)))
9242     (when latent
9243       (if (null (string-match "latent" btype))
9244           (setq latent nil)             ;Not supported
9245         (setq latent (tinypgp-r-latent-time-random remailer latent))))
9246
9247     (when key
9248       (if (null (string-match "ek" btype))
9249           (setq key nil)))
9250     ;;  The Reply string type "cpunk, eric..."
9251     (ti::mail-pgpr-block nil rtype anon-to key latent)))
9252
9253 ;;}}}
9254 ;;{{{ remail: reply-block: interactive
9255
9256 ;;; ................................................... &reply-block-i ...
9257 ;;;
9258 (defun tinypgp-r-reply-block-test (&optional no-confirm)
9259   "Send every reply block listed in `tinypgp-:r-reply-block-table'.
9260 NO-CONFIRM bypasses asking.
9261 If you don't receive mail back, there are two possibilities:
9262 o  remailer is down
9263 o  your reply block was not constructed correctly."
9264   (interactive "P")
9265   (tinypgp-r-init-maybe)
9266   (let* ((fid      "tinypgp-r-reply-block-test: ")
9267          (i       0)
9268          remailer
9269          email)
9270     (dolist (elt tinypgp-:r-reply-block-table)
9271       (setq remailer (nth 0 elt))
9272       (setq email    (nth 1 (assoc remailer tinypgp-:r-levien-table)))
9273
9274       (tinypgpd fid remailer email)
9275
9276       (cond
9277        ((null email)
9278         (ti::read-char-safe-until
9279          (format
9280           "[%s] Does not exist any more, delete reply block. [press]"
9281           remailer)))
9282        (t
9283         (when (or no-confirm
9284                   (y-or-n-p (format "Send reply block to %s " remailer)))
9285           (incf  i)
9286           (ti::mail-sendmail-macro email remailer 'send
9287                                    (ti::mail-kill-field
9288                                     "^Subject"
9289                                     (format
9290                                      "r-test %s"
9291                                      (ti::date-standard-date)))
9292 ;;;         (pop-to-buffer (current-buffer))
9293                                    ;;          (insert (ti::mail-pgpr-block 'epgp "cpunk" ) "\n")
9294                                    (tinypgp-r-reply-block-insert remailer)))))
9295 ;;;         (ti::pmin) (ti::d! "testing-rblock")
9296
9297       (if (interactive-p)
9298           (message "Sent %d test reply block%s."
9299                    i (if (eq i 1) "" "s"))))))
9300
9301 ;;; ----------------------------------------------------------------------
9302 ;;;
9303 (defun tinypgp-r-reply-block-basic
9304   (remailer-elt &optional latent key anon-to final verb)
9305   "Contruct most basic reply block.
9306
9307 The created encrypted reply block will contain following
9308
9309   ::
9310   Request-Remailing-To: <`tinypgp-:r-user-mail-address'>
9311   Encrypt-Key: <key you gave>
9312   Latent-Time: <latent time you gave>
9313
9314 Important:
9315
9316   You must be in empty [mail] buffer. When this function finishes, you
9317   should _encrypt_ the mail body.
9318
9319 Input:
9320
9321   REMAILER-ELT      Remailer table entry
9322   LATENT            \"+1:00\"
9323   KEY               crypt key, no spaces
9324   ANON-TO           send-to@some.com
9325   FINAL             flag, if this is final block, include
9326                     \"**\" to the end. (See remailer faqs)
9327                     And kill any extra headers.
9328
9329   VERB              Verbose messages.
9330
9331 Interactive call note:
9332
9333   LATENT can be passed by prefix arg. Each \\[universal-argument] adds 30 minutes, so
9334   3 times \\[universal-argument] is same as +1:30.
9335   Numeric argument gives straigh hours, so M - x 2 means +2:00. Latent time
9336   is not always supported by selected remailer and it is ignored if remailer
9337   can't use it.
9338
9339   ANON-TO  is `tinypgp-:r-user-mail-address'.
9340
9341   FINAL is always set to t"
9342   (interactive
9343    (progn
9344
9345      (unless (ti::mail-body-empty-p)
9346        (if (y-or-n-p "Fresh buffer needed, empty this buffer? ")
9347            (progn
9348              (ti::mail-text-start 'move) (delete-region (point) (point-max)))
9349          (error "TinyPgp: Buffer must be emptied first")))
9350
9351      (ti::list-merge-elements
9352       (tinypgp-ask-remail-args)
9353       tinypgp-:r-user-mail-address
9354       t)))
9355   ;; ... ... ... ... ... ... ... ... ... ... ... ... . interactive end . .
9356
9357   (let* ()
9358     (tinypgp-r-init-maybe)
9359     (ti::verb)
9360     (unless (ti::mail-body-empty-p)
9361       (error "TinyPgp: Buffer must be emptied first"))
9362
9363     (tinypgp-r-chain-1 remailer-elt latent key anon-to final)
9364
9365     (if tinypgp-:r-reply-block-basic-hook
9366         (run-hooks 'tinypgp-:r-reply-block-basic-hook))
9367
9368 ;;;    (if verb
9369 ;;;     (message "If you encrypt this, you should leave '**' outside."))
9370
9371     nil))
9372
9373 ;;}}}
9374 ;;{{{ remail: interactive
9375
9376 ;;; ................................................... &r-interactive ...
9377
9378 ;;; ----------------------------------------------------------------------
9379 ;;;
9380 (defun tinypgp-r-chain-1 (remailer-elt &optional latent key anon-to final)
9381   "Encrypt mail to next remailer.
9382 Input:
9383
9384   REMAILER-ELT      remailer elt from `tinypgp-:r-levien-table'
9385   LATENT            latent time e.g. 0:00r  (not used if...)
9386   KEY               Encrypt key (not used if remailer does not support it)
9387   ANON-TO           send-to@somewhere.com
9388   FINAL             flag, prefix arg, if this is final block, include
9389                     \"**\" to the end. (See remailer faqs)
9390
9391 Return:
9392   email             remailer address"
9393   (interactive
9394    (ti::list-merge-elements
9395     (tinypgp-ask-remail-args)
9396     (read-from-minibuffer
9397      "Anon to: "
9398      (mail-fetch-field "To"))))
9399   (tinypgp-r-init-maybe)
9400   (let* (tinypgp-:xpgp-signing-mode     ;Do not use X-Pgp
9401          (properties    remailer-elt)
9402          (email         (nth 1 properties))
9403
9404          ;;  The Reply string type "cpunk, eric..."
9405
9406          (rtype         (ti::mail-pgpr-reply-type        (nth 2 properties)))
9407
9408          (mail          (ti::mail-mail-p))
9409          str)
9410 ;;;      str2
9411     (or tinypgp-:r-mode-indication-flag
9412         (setq tinypgp-:r-mode-indication-flag 'basic-1))
9413
9414     (if (and key (string-match "[ \t\n]" key))
9415         (error "TinyPgp: Key may not contains spaces '%s'" key))
9416
9417     ;; ........................................... destination address ...
9418
9419     (ti::mail-text-start 'move)
9420
9421     (setq str (tinypgp-r-reply-block-header remailer-elt latent key anon-to))
9422
9423     (insert str "\n")
9424     (tinypgp-encrypt-mail email)
9425
9426     ;; ................................................ remail address ...
9427
9428     (ti::mail-text-start 'move)
9429
9430     ;;  The outer block encrypt key is disabled for now because
9431     ;;  it causes double encryptinn. When you receive the mail,
9432     ;;  then you have to decrypt it twice...not convenient.
9433     ;;
9434     ;;  The Reply Blocks EK should be enough. User can add the
9435     ;;  extra Field if he wants it.
9436
9437     (setq str (ti::mail-pgpr-block nil rtype email nil latent))
9438     (insert str "\n")
9439
9440     ;; ... ... ... ... ... ... ... ... ... ... ... ... ... ... . final ...
9441
9442     (when final
9443       (ti::mail-pgpr-close)
9444
9445       (when mail
9446         (ti::mail-kill-field "^To" (concat "  " email) )
9447
9448         ;;  sysadm in your site probably isn't interested in subjects
9449         ;;  like this one. We don't want to draw his attention
9450
9451         (ti::mail-kill-field "^Subject" (tinypgp-r-subject-cookie))
9452         (ti::mail-kill-field "^Fcc")
9453         (ti::mail-kill-field "^Gcc")    ;GNUS 5
9454         (ti::mail-kill-field "^Reply-to")))
9455
9456     email))
9457
9458 ;;; ----------------------------------------------------------------------
9459 ;;;
9460 (defun tinypgp-r-chain (chain &optional verb)
9461   "Decrypt current message according to remailer CHAIN. VERB.
9462 Important, before you call this function:
9463 1. You have called \\[tinypgp-r-post] or \\[tinypgp-newnym-post] to convert
9464    the message into remail post format first.
9465 2. You must have encrypted the message.
9466
9467 Only after these, the additonal chain layers are feasible."
9468   (interactive
9469    (progn
9470      (or tinypgp-:r-chain
9471          (error "TinyPgp: tinypgp-:r-chain is empty"))
9472      (list
9473       (completing-read
9474        "Select remailer chain: "
9475        tinypgp-:r-chain nil 'match nil 'tinypgp-:history-r-chain))))
9476   (let* (to
9477          list
9478          remailer
9479          remailer-elt
9480          latent key anon-to
9481          final)
9482     (ti::verb)
9483     (or (setq chain (assoc chain tinypgp-:r-chain))
9484         (error "TinyPgp: No such choice in tinypgp-:r-chain"))
9485
9486     (setq chain (nth 1 chain)   list chain)
9487
9488     (unless (or (vectorp chain)
9489                 (vectorp (setq list (eval chain))))
9490       (error "TinyPgp: %s evaluated to %s, which is not vector." chain list))
9491
9492     (or (setq list (append list nil))   ;Convert to list :-)
9493         (error "TinyPgp: Vector list was empty?"))
9494
9495     ;;  I can't do automatic encryption, because I have no of
9496     ;;  knowing if user had called C-c / . p to convert the message
9497     ;;  to post format. It would be disaster to encrypt non-post message
9498
9499     (or (ti::mail-pgp-encrypted-p)
9500         (error "\
9501 TinyPgp: The message must have been encrypted to mail2news gateway."))
9502
9503     (dolist (elt list) ;; #todo: Can't use dolist beacause tests FINAL
9504       (setq remailer (nth 0 elt)
9505             latent   (nth 1 elt)
9506             key      (nth 2 elt)
9507             remailer-elt  (tinypgp-r-elt-remailer remailer)
9508             final    (null (cdr list))  ;No more remailers
9509             anon-to  (mail-fetch-field "to"))
9510       (or (ti::nil-p to)
9511           (error "TinyPgp: To address is empty, can't use Anon-to"))
9512       (tinypgp-r-chain-1 remailer-elt latent key anon-to final))
9513
9514     ;;  Let's do fast check and turn off auto-action
9515
9516     (when (and verb (tinypgp-auto-action-on-modeline-p))
9517       (tinypgp-hash 'auto-action 'put 'user-mode nil))))
9518
9519 ;;; ----------------------------------------------------------------------
9520 ;;;
9521 (defun tinypgp-r-update-remailer-list (&optional verb no-auto-init)
9522   "Finger remailer list maintainer and get updated list.
9523 VERB allows verbose messages. NO-AUTO-INIT suppresses call to
9524 `tinypgp-r-init' after file update."
9525   (interactive)
9526   (let ((file   tinypgp-:r-list-file)
9527         (email  tinypgp-:r-list-finger)
9528         (buffer (tinypgp-ti::temp-buffer))
9529         ret)
9530     (ti::verb)
9531
9532     (setq ret (ti::process-finger email nil nil buffer verb))
9533     (cond
9534      ((not (bufferp ret))
9535       (setq tinypgp-:last-network-error ret)
9536       (error "TinyPgp: finger Failed: %s" ret))
9537      (t
9538       (ti::file-delete-safe file)
9539       (with-current-buffer ret (write-region (point-min) (point-max) file))
9540       (if verb
9541           (message "TinyPgp: remailer list [%s] updated." file))
9542       (call-interactively 'tinypgp-r-init)))))
9543
9544 ;;; ----------------------------------------------------------------------
9545 ;;;
9546 (defun tinypgp-r-post (&optional type)
9547   "Anonymize message. See TYPE from `tinypgp-r-post-usenet'."
9548   (interactive)
9549   (let* ()
9550     (or type
9551         (setq type 'remail))
9552     (tinypgp-r-init-maybe)
9553     (run-hooks 'tinypgp-:r-post-before-hook)
9554     (if (ti::mail-news-buffer-p)
9555         (tinypgp-r-post-usenet type)
9556       (call-interactively 'tinypgp-r-post-regular))
9557     (run-hooks 'tinypgp-:r-post-after-hook)))
9558
9559 ;;; ----------------------------------------------------------------------
9560 ;;;
9561 (defun tinypgp-r-post-regular
9562   (remailer &optional insert-reply-block remailer-elt)
9563   "Normal mail to: send as anonymous post. Bulk mail is not permitted.
9564 This means that any BCC or FCC field generates error.
9565
9566 The Prefix arg inserts to the message a reply block, so that person
9567 can answer to the mail if he sends the message back to remailer.
9568
9569 Notes:
9570
9571   `post-command-hook' and possible `post-command-idle-hook' are
9572   bound locally to current buffer and set to nil,
9573   so that nothing special happens when you compose and send this mail.
9574
9575 Input:
9576
9577   REMAILER              remailer alias name
9578   INSERT-REPLY-BLOCK    prefix arg, if non-nil, insert remailer reply block
9579   REMAILER-ELT          the remailer entry from table `tinypgp-:r-host-table'"
9580   (interactive
9581    (let (remailer
9582          remailer-elt)
9583      (setq remailer (tinypgp-ask-remailer))
9584      (setq remailer-elt (tinypgp-r-elt-remailer remailer))
9585      (list remailer current-prefix-arg remailer-elt)))
9586   (let* (tinypgp-:xpgp-signing-mode     ;Do not use X-Pgp
9587          (var-list    '(post-command-hook
9588                         post-command-idle-hook))
9589          (hlist       (delete 'newsgroups (ti::mail-required-headers)))
9590          (hlist       (push  'to hlist))
9591          (to          (ti::mail-get-field "TO" nil 'nil-mode))
9592
9593          (reply-msg   "To reply to this message, send it to some remailer.")
9594          (properties   (or remailer-elt
9595                            (assoc remailer tinypgp-:r-levien-table)
9596                            (error "TinyPgp: No remailer [%s]" remailer)))
9597          (email         (nth 1 properties))
9598
9599          ;;  The Reply string type "cpunk, eric..."
9600          ;;
9601          (rtype         (ti::mail-pgpr-reply-type        (nth 2 properties)))
9602
9603          hash-headers
9604          header-block
9605          message
9606          point
9607          str)
9608
9609     (if (or (mail-fetch-field    "CC")
9610             (mail-fetch-field    "BCC"))
9611         (error "TinyPgp: sorry, bulk CC or BCC mail is not permitted."))
9612
9613     (if (null to)
9614         (error "TinyPgp: No TO field filled."))
9615
9616     (tinypgp-r-init-maybe)
9617     (setq str (ti::mail-pgpr-block nil rtype to))
9618
9619     ;; ... ... ... ... ... ... ... ... ... ... ... ... ... . headers . .
9620     ;;  Get rid of headers that may reveal your identity
9621
9622     (ti::mail-kill-non-rfc-fields hlist)
9623
9624     (if (setq hash-headers (tinypgp-header-move-to-body 'move-to-body 'no-ins))
9625         (setq header-block (mapconcat 'concat hash-headers ""))
9626       (setq header-block ""))
9627
9628     ;; ... ... ... ... ... ... ... ... ... ... ... ... . doing message ...
9629
9630     (ti::mail-kill-field "to" email)
9631     (setq point   (ti::mail-text-start))
9632     (setq message (buffer-substring point (point-max)))
9633     (delete-region point (point-max))
9634
9635     (ti::pmax)
9636     (insert
9637      str
9638      "Cutmarks: --\n\n"
9639      "##\n" header-block "\n")
9640
9641     (when insert-reply-block
9642       (tinypgp-r-reply-block-insert remailer))
9643
9644     (when (and insert-reply-block reply-msg)
9645       (insert reply-msg "\n" ))
9646     (insert message "\n--\n")
9647
9648     ;;  Make sure there is nothing that interferes sending.
9649     ;;  make them first local; then set them to nil
9650
9651     (dolist (sym var-list)
9652       (when (boundp sym)
9653         (make-local-hook sym)
9654         (set sym nil)))))
9655
9656 ;;; ----------------------------------------------------------------------
9657 ;;;
9658 ;;;
9659 (defun tinypgp-r-post-usenet-body-convert
9660   (groups email &optional rb rtype rblk)
9661   "Convert body text into Remail post.
9662 Supposes that you have already reformatted the buffer.
9663
9664 Input:
9665
9666   GROUPS    list of newsgroups where to post.
9667   EMAIL     the mail2news gateway email address
9668   RB        if string, insert reply block of remailer given.
9669   RTYPE     Remailer reply type, e.g. 'cpunk'
9670   RBLK      Header block"
9671   (interactive)
9672   (let* ((reply-msg   "To reply to this message, send it to some remailer.")
9673          point
9674          message
9675          block
9676          str)
9677
9678     ;; ... ... ... ... ... ... ... ... ... ... ... ...  doing blocks . .
9679
9680     (setq point   (ti::mail-text-start)
9681           message (buffer-substring point (point-max)))
9682     (delete-region point (point-max))
9683
9684     (dolist (grp groups)
9685       (setq str   (ti::mail-pgpr-block nil rtype grp)
9686             block (concat str "\n##\n" rblk  "\n"))
9687       (ti::pmax)
9688       (insert block)
9689       (when rb
9690         (tinypgp-r-reply-block-insert rb)
9691         (insert "**\n")
9692         (insert reply-msg "\n" ))
9693       (insert message "\n--\n"))))
9694
9695 ;;; ----------------------------------------------------------------------
9696 ;;;
9697 (defun tinypgp-r-post-usenet (type &optional rb)
9698   "Usenet message: Convert current message into anonymous remailer post.
9699 Call error if buffer is not a newsgroup post.
9700
9701 Input:
9702
9703   TYPE  type of conversion: 'newnym or 'remail
9704   RB    Insert reply block of remailer RB, so that user can aswer to you
9705         directly by using this replay block.
9706
9707 Return:
9708
9709  '(remailer-email-addr  (newsgroup newsgroup ..))
9710
9711 References:
9712
9713  `tinypgp-:r-mail2news-remailer'"
9714   (let* (post-command-hook
9715          mail-setup-hook
9716          mail-mode-hook
9717          message-mode-hook
9718
9719          hash-headers
9720          header-block
9721          group-fld
9722          group-list
9723          phost                          ;posting host
9724          phost-elt
9725          phost-prop
9726          phost-email
9727          rtype
9728          sym)
9729     (setq tinypgp-:r-mode-indication-flag 'post)
9730
9731     ;;  Why these if statemnts? Because the byteCompiler sees that
9732     ;;  I have introduced hooks in let*, but I never use them!
9733     ;;  This fools bytecompiler to believe they are used and it
9734     ;;  doesn't give any warnings any more
9735
9736     (if post-command-hook   (setq post-command-hook nil)) ;ByteComp silencer
9737     (if mail-setup-hook     (setq mail-setup-hook nil))
9738     (if mail-mode-hook      (setq mail-mode-hook nil))
9739
9740     ;;  This does exist between 19.30 - 19.33; but then it was made obsolete
9741     ;;  This trick gives clean byteCompilation and no warnings
9742
9743     (setq sym 'post-command-idle-hook)
9744
9745     (when (fboundp sym)
9746       (make-local-hook sym)
9747       (set sym  nil))
9748
9749     (setq group-fld   (mail-fetch-field  "Newsgroups"))
9750
9751     (when (and t                        ;Enabled now
9752                (ti::nil-p group-fld))
9753       (error "TinyPgp: No newsgroups? Buffer must contain a news message."))
9754
9755     (run-hooks 'tinypgp-:r-post-before-hook)
9756
9757     ;; ... ... ... ... ... ... ... ... ... ... ... ... ... variables . .
9758     ;;  Read needed variables
9759
9760     (if (or (null (setq phost     (eval tinypgp-:r-mail2news-remailer)))
9761             (null (setq phost-elt (assoc phost tinypgp-:r-levien-table))))
9762         (error "TinyPgp: tinypgp-:r-mail2news-remailer '%s' %s"
9763                tinypgp-:r-mail2news-remailer phost))
9764
9765     (tinypgp-r-post-p phost-elt)    ;Calls error is not capable enough
9766     (setq phost-email (nth 1 phost-elt)
9767           phost-prop  (nth 2 phost-elt)
9768           rtype       (ti::mail-pgpr-reply-type phost-prop))
9769
9770     ;; ... ... ... ... ... ... ... ... ... ... ... ... ... . headers . .
9771     ;;  Get rid of headers that may reveal your identity
9772     ;;  Don't kill in-reply to because it is used in newsgroup postings.
9773
9774     (tinypgp-header-kill)
9775
9776     ;;  Save all headers because they are inserted into body
9777
9778     (if (setq hash-headers (tinypgp-header-move-to-body 'move-to-body 'no-ins))
9779         (setq header-block (mapconcat 'concat hash-headers ""))
9780       (setq header-block ""))
9781
9782     ;;  The remaier doesn't need this field
9783
9784     (ti::mail-kill-field "in-reply-to")
9785     (ti::mail-kill-field "newsgroups")
9786
9787     (if (string-match "," group-fld)
9788         (setq group-list (split-string group-fld "[,\t\n ]+"))
9789       (setq group-list (list group-fld)))
9790
9791     ;; ... ... ... ... ... ... ... ... ... ... ... ...  doing blocks . .
9792
9793 ;;;      (setq point   (ti::mail-text-start)
9794 ;;;         message (buffer-substring point (point-max)))
9795 ;;;      (delete-region point (point-max))
9796
9797     (cond
9798      ((eq type 'newnym))
9799      ((eq type 'remail)
9800       (tinypgp-r-post-usenet-body-convert
9801        group-list phost rb rtype header-block)))
9802
9803     (ti::pmin) (insert "To: " phost-email "\n") ;Set destination
9804
9805     (mail-mode)                  ;This is not a news message any more.
9806     (unless tinypgp-mode (tinypgp-mode 1))
9807
9808     (list phost-email group-list)))
9809
9810 ;;}}}
9811
9812 ;;{{{ newnym: misc
9813
9814 ;;; ........................................................ &r-newnym ...
9815
9816 ;;; ----------------------------------------------------------------------
9817 ;;;
9818 (defsubst tinypgp-newnym-read-word ()
9819   "Read newnym configuration command word."
9820   (let* (word)
9821     (save-excursion
9822       (when (char= (char-syntax (following-char)) ?\ ) ;Sitting on whitespace
9823         (backward-char 1))
9824       (when (setq word (ti::buffer-read-space-word))
9825         (ti::string-match "[^-+=]+" 0 word)))))
9826
9827 ;;; ----------------------------------------------------------------------
9828 ;;;
9829 (defsubst tinypgp-newnym-list (&optional mode force)
9830   "Return ELTS for all 'newnym'.
9831 Normally once the list has been generated; it is stored to hash.
9832
9833 Input:
9834
9835   MODE      nil    = return full configuration list
9836             'alias = return alias name list
9837   FORCE     reread Levien table content and update hash.
9838
9839 References:
9840   `tinypgp-:r-levien-table'"
9841   (let* ((list  (tinypgp-hash 'remail 'get 'newnym)))
9842     (tinypgp-r-init-maybe)
9843     (when (or force (null list))
9844       (or tinypgp-:r-levien-table
9845           (error "TinyPgp: Levien list is nil."))
9846
9847       (setq list (tinypgp-r-get-list "newnym" tinypgp-:r-levien-table))
9848       (tinypgp-hash 'remail 'put 'newnym list)
9849       (tinypgp-hash 'remail 'put 'newnym-alias (mapcar 'car list)))
9850     (cond                               ;No other choices yet
9851      ((eq mode 'alias)
9852       (setq list (tinypgp-hash 'remail 'get 'newnym-alias))))
9853     list))
9854
9855 ;;; ----------------------------------------------------------------------
9856 ;;;
9857 (defsubst tinypgp-r-format-email-address (account remailer-entry)
9858   "Return address that has ACCOUNT@site.com derived from REMAILER-ENTRY.
9859 The remailer-entry is one of the entries in `tinypgp-:r-levien-table'"
9860
9861   (let* ((email (nth 1 remailer-entry)))
9862     (if (null (string-match "^[^@]+" email))
9863         (error "TinyPgp Internal error. Call \\[tinypgp-r-init] or maintainer."))
9864     ;;  Set address to "help@..."
9865     ;;
9866     (ti::replace-match 0 account email)))
9867
9868 ;;; ----------------------------------------------------------------------
9869 ;;;
9870 (defsubst tinypgp-newnym-ask-server (&optional prompt)
9871   "Ask newnym server name with completion and PROMPT."
9872   (tinypgp-r-init-maybe)
9873   (or (get 'tinypgp-:r-newnym-default-account-table 'default-server)
9874       (completing-read
9875        (or "Newnym account domain: " prompt)
9876        (ti::list-to-assoc-menu (tinypgp-newnym-list 'alias))
9877        nil
9878        'match)))
9879
9880 ;;; ----------------------------------------------------------------------
9881 ;;;
9882 (defun tinypgp-newnym-file-stamp-name (server account)
9883   "Return Stamp file name according to SERVER and ACCOUNT."
9884   (concat tinypgp-:r-newnym-stamp-file-prefix
9885           (ti::string-mangle (concat server account))))
9886
9887 ;;; ----------------------------------------------------------------------
9888 ;;;
9889 (defun tinypgp-newnym-file-stamp (server account)
9890   "Stamp Newnym file with with SERVER and ACCOUNT."
9891   (let* ((file (tinypgp-newnym-file-stamp-name server account)))
9892     (if (and (file-exists-p file)
9893              (not (file-writable-p file)))
9894         (set-file-modes file (ti::file-mode-make-writable (file-modes file))))
9895     (ti::file-touch file)
9896     (ti::file-mode-protect file)))
9897
9898 ;;; ----------------------------------------------------------------------
9899 ;;;
9900 (defun tinypgp-newnym-account-expiry-warnings ()
9901   "Print possible account expiry warnings.
9902 References:
9903  `tinypgp-:r-newnym-default-account-table'"
9904   (interactive)
9905   (let* ((limit 100)                ;It's actually 120, but we use 100
9906          server account
9907          days
9908          file
9909          ret)
9910     (dolist (elt tinypgp-:r-newnym-default-account-table)
9911
9912       (setq server   (nth 1 elt)
9913             account  (nth 2 elt)
9914             file     (tinypgp-newnym-file-stamp-name server account))
9915
9916 ;;;      (setq F file S server A account)
9917 ;;;      (ti::d! (file-exists-p file) account server file)
9918
9919       (cond
9920        ((null (file-exists-p file))
9921         (message "TinyPgp Warning: No stamp file for %s %s, Creating..."
9922                  server
9923                  account)
9924         (tinypgp-newnym-file-stamp server account))
9925        (t
9926         (setq days (ti::file-days-old file)
9927               ret  (format "%s %s: %d" ret account (- limit days)))
9928         (when (> days limit)
9929           (message
9930            "Tinypgp Newnym stamp is %d days old, account may expire: %s %s"
9931            days
9932            server
9933            account)
9934           (sit-for 3)))))
9935     (when ret
9936       (message ret))))
9937
9938 ;;; ----------------------------------------------------------------------
9939 ;;;
9940 (defsubst tinypgp-newnym-ask-account ()
9941   "Ask newnym Account name."
9942   (tinypgp-r-init-maybe)
9943   (let* (nym)
9944     (setq
9945      nym
9946      (or (get 'tinypgp-:r-newnym-default-account-table 'default-account)
9947          (if (ti::nil-p
9948               (setq nym
9949                     (read-from-minibuffer
9950                      "Nym account login name: "
9951                      nil nil nil)))
9952              'tinypgp-:history-newnym-account
9953            (error "TinyPgp: Empty not accepted.")
9954            nym)))
9955     nym))
9956
9957 ;;; ----------------------------------------------------------------------
9958 ;;;
9959 (defun tinypgp-newnym-ask-srv-acc (&optional confirm-msg)
9960   "Ask '(server account) with optional CONFIRM-MSG."
9961   (tinypgp-r-init-maybe)
9962   (let* (srv
9963          acc)
9964     (if confirm-msg
9965         (or (y-or-n-p confirm-msg)
9966             (error "Abort")))
9967     (setq srv (tinypgp-newnym-ask-server))
9968     (setq acc (tinypgp-newnym-ask-account))
9969     (list srv acc)))
9970
9971 ;;; ----------------------------------------------------------------------
9972 ;;;
9973 (defun tinypgp-newnym-ask-srv-acc-arg (&optional confirm-msg)
9974   "Ask '(server account prefix_arg) with CONFIRM-MSG."
9975   (tinypgp-r-init-maybe)
9976   (if confirm-msg
9977       (or (y-or-n-p confirm-msg)
9978           (error "Abort")))
9979   (list
9980    (tinypgp-newnym-ask-server)
9981    (tinypgp-newnym-ask-account)
9982    current-prefix-arg))
9983
9984 ;;; ----------------------------------------------------------------------
9985 ;;;
9986 (defsubst tinypgp-r-sendmail-create-buffer (name &optional subject)
9987   "Create mail buffer. The old buffer is killed.
9988 Input:
9989   NAME     buffre name. Kill eny existing buffer with NAME without query.
9990   SUBJECT  Message subject."
9991   (ti::kill-buffer-safe name)
9992   (with-current-buffer (tinypgp-ti::temp-buffer 'mail "NONE" (or subject ""))
9993     (rename-buffer name)
9994     (buffer-enable-undo)
9995     (setq tinypgp-:r-mode-indication-flag 'newnym)
9996     (tinypgpd "tinypgp-r-sendmail-create-buffer" name (current-buffer))
9997     (current-buffer)))
9998
9999 ;;; ----------------------------------------------------------------------
10000 ;;;
10001 (eval-and-compile
10002   (defun tinypgp-newnym-sendmail-fmacro-1 (func doc account subject msg)
10003     "Use `tinypgp-newnym-sendmail-fmacro' instead.
10004 See FUNC DOC ACCOUNT SUBJECT MSG there."
10005     (let* ((sym (intern (symbol-name (` (, func))))))
10006       (`
10007        (defun (, sym)  (alias &optional verb)
10008          (, doc)
10009          (interactive (list (tinypgp-newnym-ask-server)))
10010          (ti::verb)
10011          (tinypgp-r-init-maybe)
10012          (tinypgp-r-server-macro alias (, account)
10013                                  (ti::mail-sendmail-macro email (, subject) 'send (insert "empty"))
10014                                  (if verb
10015                                      (message "'%s' request sent to %s, wait for answer."
10016                                               (, msg) email))))))))
10017
10018 ;;; ----------------------------------------------------------------------
10019 ;;;
10020 (put 'tinypgp-newnym-sendmail-fmacro 'lisp-indent-function 0)
10021 (defmacro tinypgp-newnym-sendmail-fmacro (func doc account subject msg)
10022   "Create interactive function that sends mail to remailer.
10023 Input:
10024
10025   FUNC          Created function name
10026   DOC           Function's doc string
10027   ACCOUNT       the account name where to send email request
10028   SUBJECT       Subject for email
10029   MSG           Notification message to interactive user e.g. 'create'."
10030   (` (, (tinypgp-newnym-sendmail-fmacro-1
10031          func doc account subject msg ))))
10032
10033 ;;}}}
10034 ;;{{{ newnym: keys; menus
10035
10036 ;;; ................................................... &newnym-mode ...
10037
10038 (defun tinypgp-newnym-mode-define-menu ()
10039   "Define menus."
10040   (easy-menu-define
10041     tinypgp-:newnym-mode-menu (if (ti::xemacs-p)
10042                                   nil
10043                                 tinypgp-:newnym-mode-map)
10044     "TinyPgp Newnym management menu"
10045     (list
10046      tinypgp-:newnym-mode-menu-name
10047      ["Nym-Commands: Electric tab"   tinypgp-newnym-mode-electric-tab        t]
10048      ["Nym-Commands: Go to."         tinypgp-newnym-mode-nym-commands-goto           t]
10049      ["Reply-Block:  Add"            tinypgp-newnym-mode-reply-block         t]
10050      ["Reply-Block:  Kill"           tinypgp-newnym-mode-reply-block-kill            t]
10051      ["Public-key:   Add"            tinypgp-newnym-mode-public-key          t]
10052      ["Public-key:   Kill"           tinypgp-newnym-mode-public-key-kill     t]
10053      ["Mode description"             tinypgp-newnym-mode-describe                    t]
10054      "----")))
10055
10056 ;;; ----------------------------------------------------------------------
10057 ;;;
10058 (defun tinypgp-newnym-mode-define-keys ()
10059   "Define keys."
10060   (let* ((p    tinypgp-:newnym-mode-prefix-key)
10061          (map  tinypgp-:newnym-mode-map))
10062     (define-key map "\t"                'tinypgp-newnym-mode-electric-tab)
10063     (define-key map (concat p "\t")     'tinypgp-newnym-mode-nym-commands-goto)
10064     (define-key map (concat p "p")      'tinypgp-newnym-mode-public-key)
10065     (define-key map (concat p "P")      'tinypgp-newnym-mode-public-key-kill)
10066     (define-key map (concat p "r")      'tinypgp-newnym-mode-reply-block)
10067     (define-key map (concat p "R")      'tinypgp-newnym-mode-reply-block-kill)
10068     (define-key map (concat p "?")      'tinypgp-newnym-mode-describe)))
10069
10070 ;;}}}
10071 ;;{{{ newnym: Mode functions
10072
10073 ;;; ----------------------------------------------------------------------
10074 ;;;
10075 ;;;
10076 (ti::macrof-minor-mode
10077  tinypgp-newnym-mode                    ;1
10078  "Newnym account management help mode.
10079 You turn this mode on in mail buffer and it helps you to
10080 compose message to nym account. The most interesting command probably
10081 is `tinypgp-newnym-mode-electric-tab'; which works as follows
10082
10083   If cursor is anywhere else that at the line Nym-Commands:, then the
10084   original tab function is called.
10085
10086 Nym-Commands: create +acksend +fin  +
10087 |             |     |             |  |
10088 |             |     |             |  complete all commands
10089 |             |     |             complete command 'fin'
10090 |             |     Show default setting or example (previous word)
10091 |             |     *
10092 |             Show command help and advance to '*'.
10093 If the cursor is over word Nym-Commands:, then advance forward to first
10094 command word.
10095
10096 In hooks you should use functions
10097
10098   `turn-on-tinypgp-newnym-mode'
10099   `turn-off-tinypgp-newnym-mode'
10100
10101 Mode description:
10102 \\{tinypgp-:newnym-mode-map}
10103 "
10104  tinypgp-install-modes                  ;3
10105  tinypgp-newnym-mode                    ;4
10106  tinypgp-:newnym-mode-name
10107
10108  tinypgp-:newnym-mode-prefix-key        ;5
10109  tinypgp-:newnym-mode-menu              ;6
10110
10111  nil                                    ;7
10112  "Newnym acocunt handling"              ;8
10113  tinypgp-:newnym-mode-hook              ;
10114
10115  (progn
10116    (tinypgp-update-modeline)))
10117
10118 (defun turn-on-tinypgp-newnym-mode ()
10119   "Newnym mode on."
10120   (tinypgp-newnym-mode 1))
10121
10122 (defun turn-off-tinypgp-newnym-mode ()
10123   "Newnym mode off."
10124   (tinypgp-newnym-mode 0))
10125
10126 ;;; .............................................. &newnym-interactive ...
10127
10128 ;;; ----------------------------------------------------------------------
10129 ;;;
10130 (defun tinypgp-newnym-mode-describe ()
10131   "Describe mode."
10132   (interactive)
10133   (describe-function 'tinypgp-newnym-mode))
10134
10135 ;;; ----------------------------------------------------------------------
10136 ;;;
10137 (defun tinypgp-newnym-mode-electric-tab ()
10138   "Compose newnym commands if cursor is on field Nym-Commands.
10139 Otherwise call original mode's tab key. See description of this command
10140 from `tinypgp-newnym-mode'."
10141   (interactive)
10142   (let* ((tbl tinypgp-:newnym-cmd-table)
10143          elt
10144          word)
10145     (cond
10146      ((null
10147        (save-excursion (beginning-of-line) (looking-at "Nym-Commands:")))
10148       ;;  Turn mode off and call original tab key.
10149       ;;
10150       (let* (tinypgp-newnym-mode)
10151         (call-interactively (key-binding "\t"))))
10152      (t
10153       (setq word (tinypgp-newnym-read-word))
10154
10155       (cond
10156        ;; ................................................... beg line ...
10157        ((and (not (ti::nil-p word))
10158              ;;   the "-" terminates word; because it is [+-] option,
10159              ;;   that's why we have to test separate words.
10160              (member word '("Nym" "Commands:")))
10161         (skip-chars-forward "^ \t\n")
10162         (skip-chars-forward " \t"))
10163        ;; ............................................... complete all ...
10164        ((and (ti::nil-p word)   ;User wrote [+-] and wants to complete
10165              (ti::char-in-list-case (preceding-char) '(?+ ?-)))
10166         (setq word (completing-read "Insert Command: " tbl))
10167         (if (not (ti::nil-p word))
10168             (insert word)))
10169
10170        ;; ............................................... example show ...
10171        ((and (not (ti::nil-p word))
10172              (setq elt (assoc word tbl)) ;Full match
10173              ;; after word that is full match; on whitespace
10174              (ti::char-in-list-case (following-char) '(?\ ?\t ?\n)))
10175         (message (nth 2 elt)))
10176
10177        ;; ........................................... full match; help ...
10178        ((and (not (ti::nil-p word))
10179              (setq elt (assoc word tbl))) ;Full match
10180         (message (nth 1 elt))
10181         (skip-chars-forward "^ \t\n"))
10182
10183        ;; ........................................... partial complete ...
10184        ((and (not (ti::nil-p word))     ;Partial
10185              (setq elt (all-completions word tbl)))
10186         (cond
10187          ((eq 1 (length elt))           ;one match
10188           (skip-chars-forward "^ \t\n")
10189           (delete-backward-char (length word))
10190           (insert (car elt)))
10191          (t                             ;many completions
10192           (message (ti::list-to-string elt)))))
10193
10194        ;; .............................................. nothing works ...
10195        (t
10196         ;; User is sitting on whitespace and nothing is nearby
10197         ;; "Nym-Commands:  "
10198         (message "Write [+-] before options. Complete with TAB.")))))))
10199
10200 ;;; ----------------------------------------------------------------------
10201 ;;;
10202 (defun tinypgp-newnym-mode-nym-commands-goto ()
10203   "Goto Nym-Commands: forward or add that field if it does not exist."
10204   (interactive)
10205   (let* ((fld   "Nym-Commands: ")
10206          (point (if (re-search-forward fld nil t)
10207                     (match-end 0)
10208                   (save-excursion       ;Wrap
10209                     (ti::pmin)
10210                     (if (re-search-forward fld nil t)
10211                         (match-end 0))))))
10212     (if point
10213         (goto-char point)
10214       ;; No such field; add one. Put after From field.
10215       ;;
10216       ;; Config:
10217       ;; From:
10218       ;; Nym-Commands:
10219       ;;
10220       ;;
10221       (ti::mail-text-start 'move)
10222       (cond
10223        ((re-search-forward "From:")     (forward-line 1))
10224        ((re-search-forward "Config:")   (forward-line 1)))
10225       (insert fld "\n")
10226       (backward-char 1))))
10227
10228 ;;; ----------------------------------------------------------------------
10229 ;;;
10230 (defun tinypgp-newnym-mode-public-key-kill ()
10231   "Kill Public-Key field."
10232   (interactive)
10233   (tinypgp-newnym-mode-public-key nil 'kill))
10234
10235 ;;; ----------------------------------------------------------------------
10236 ;;;
10237 (defun tinypgp-newnym-mode-public-key (key-id &optional kill)
10238   "Insert Public-Key field and PGP key block to the end.
10239 If there already exist Public-Key tag, then insert pgp key block after it
10240 by possibly deleting old pgp key block.
10241
10242 Input:
10243   KEY-ID    key-id matching public key
10244   KILL      if non-nil prefix arg, kill the public key block"
10245   (interactive
10246    (let* ((default (save-excursion
10247                      (ti::mail-text-start 'move)
10248                      ;;  find the From command field and suggest
10249                      ;;  inserting pgp key-id amtching it
10250                      ;;
10251                      (ti::mail-get-field "From" 'any)))
10252           ret)
10253      (unless current-prefix-arg         ;Don't ask if arg given
10254        (setq
10255         ret
10256         (read-from-minibuffer "Insert pgp key matching key-id: "
10257                               (if (not (ti::nil-p default))
10258                                   (ti::string-remove-whitespace default))))
10259        (if (ti::nil-p ret)
10260            (error "TinyPgp: Empty not accepted.")))
10261
10262      (list ret current-prefix-arg)))
10263   (let* ((fld "Public-Key:")
10264          stat)
10265     (ti::save-with-marker-macro
10266       (ti::mail-text-start 'move)
10267       (setq stat (re-search-forward fld nil t))
10268
10269       (cond
10270        ((and kill stat)
10271         (ti::buffer-kill-line))
10272
10273        ((null kill)
10274         (if stat
10275             (forward-line 1)
10276           (ti::pmax)
10277           (insert fld "\n"))))
10278
10279       (ti::mail-pgp-block-area-kill-forward 'pkey 'move)
10280
10281       (when (null kill)
10282         (tinypgp-key-extract-to-point key-id 'raw)))))
10283
10284 ;;; ----------------------------------------------------------------------
10285 ;;;
10286 (defun tinypgp-newnym-mode-reply-block-kill (&optional insert remailer)
10287   "Kill Reply-Block or INSERT (or replace with) matching REMAILER."
10288   (interactive)
10289   (let* ((fld "Reply-Block:")
10290          stat)
10291     (ti::save-with-marker-macro
10292       (ti::mail-text-start 'move)
10293       (setq stat (re-search-forward fld nil t))
10294
10295       (cond
10296        ((and insert (null stat))
10297         (ti::pmax)
10298         (insert fld "\n"))
10299        ((and insert
10300              stat
10301              (save-excursion            ;Previous reply block?
10302                (forward-line 1)         ;Peek next line
10303                (looking-at "::\n")))
10304         (forward-line 1)
10305         (delete-region (point) (point-max)))
10306        ((and (null insert) stat)
10307         (ti::buffer-kill-line)
10308         (if (looking-at "::\n")
10309             (delete-region (point) (point-max)))))
10310
10311       (when insert
10312         (tinypgp-r-reply-block-insert  remailer)))))
10313
10314 ;;; ----------------------------------------------------------------------
10315 ;;;
10316 (defun tinypgp-newnym-mode-reply-block (remailer &optional verb)
10317   "Insert Reply-Block field and REMAILER block to the end.
10318 If there already exist Reply-Block tag, then insert block after it
10319 by possibly deleting old block.
10320
10321 Input:
10322   REMAILER  The reply block must have been created beforehand and
10323             it must be included in `tinypgp-:r-reply-block-table'
10324   VERB      Verbose messages."
10325   (interactive (list (tinypgp-ask-reply-block-remailer)))
10326   (ti::verb)
10327   (tinypgp-newnym-mode-reply-block-kill 'insert remailer)
10328   (if verb
10329       (message "Tinypgp: '%s' reply block inserted" remailer)))
10330
10331 ;;}}}
10332 ;;{{{ newnym: misc, interactive(delete; create; toggle)
10333
10334 ;;; ............................................ &r-newnym-interactive ...
10335
10336 ;;; ----------------------------------------------------------------------
10337 ;;;
10338 (defun tinypgp-newnym-default-set (completion-name)
10339   "Set default newnym server and account according to COMPLETION-NAME.
10340 The name must be found from table `tinypgp-:r-newnym-default-account-table'."
10341   (interactive
10342    (list
10343     (if (null tinypgp-:r-newnym-default-account-table)
10344         (error "TinyPgp: tinypgp-:r-newnym-default-account-table not defined.")
10345       (completing-read
10346        "Default Newnym selection: "
10347        tinypgp-:r-newnym-default-account-table
10348        nil
10349        'match))))
10350   (let* ((sym 'tinypgp-:r-newnym-default-account-table)
10351          (elt (assoc completion-name (symbol-value sym))))
10352     (when elt
10353       (put sym 'default-completion  completion-name)
10354       (put sym 'default-server   (nth 1 elt))
10355       (put sym 'original-server  (nth 1 elt))
10356       (put sym 'default-account  (nth 2 elt))
10357       (put sym 'original-account (nth 2 elt))
10358       (if (interactive-p)
10359           (message "TinyPgp: Default newnym server and account now: %s %s"
10360                    (nth 1 elt) (nth 2 elt)  ))
10361       (tinypgp-update-modeline)
10362       elt)))
10363
10364 ;;; ----------------------------------------------------------------------
10365 ;;;
10366 (defun tinypgp-newnym-default-toggle (&optional arg verb)
10367   "Toggle setting and resetting default newnym account.
10368 Set and restore variable's `tinypgp-:r-newnym-default-account-table' properties
10369 'default-server and 'default-account.
10370
10371 ARG behaves like mode arg.
10372
10373   nil  toggle
10374   0    set values to nil
10375   1    restore values.
10376   9    Force re-reading values now. You have to call this if you chnage the
10377        contents of the values during session manually.
10378
10379 VERB allows verbose messages."
10380   (interactive "P")
10381
10382   (if (null tinypgp-:r-newnym-default-account-table)
10383       (error "TinyPgp: tinypgp-:r-newnym-default-account-table not defined."))
10384
10385   (let* ((sym   'tinypgp-:r-newnym-default-account-table)
10386          (srv   (get sym 'default-server))
10387          (acc   (get sym 'default-account))
10388          (force (eq arg 9))
10389          msg)
10390     (ti::verb)
10391     ;; Not recorded? Record original value
10392     ;;
10393     (when (or force (null (get sym 'original-server)))
10394       (put sym 'original-server srv))
10395
10396     (when (or force (null (get sym 'original-account)))
10397       (put sym 'original-account acc))
10398
10399     (cond
10400      ((memq arg '(9))
10401       (setq msg (format "Default newnym parameters updated: %s %s"
10402                         srv acc)))
10403
10404      ((memq arg '(0 -1))
10405       (put sym 'default-server  nil)
10406       (put sym 'default-account nil)
10407       (setq msg (format "Default newnym parameters off.")))
10408
10409      (t                                 ;Toggle
10410       (cond
10411        (srv
10412         (put sym 'default-server  nil)
10413         (put sym 'default-account nil))
10414        (t
10415         (put sym 'default-server  (get sym 'original-server))
10416         (put sym 'default-account (get sym 'original-account))))
10417       (setq msg (format "Default newnym server and account now: %s %s"
10418                         (or (get sym 'original-server)  "nil")
10419                         (or (get sym 'original-account) "nil")))))
10420
10421     (tinypgp-update-modeline)
10422     (if verb
10423         (message msg))
10424     msg))
10425
10426 ;;; ----------------------------------------------------------------------
10427 ;;;
10428 (tinypgp-newnym-sendmail-fmacro
10429  tinypgp-newnym-get-pgp-key
10430  "Get PGP key via email from remailer."
10431  "remailer-key" "Send PGP key"  "PGP key get")
10432
10433 (tinypgp-newnym-sendmail-fmacro
10434  tinypgp-newnym-get-used-list
10435  "Get list of used 'newnym' account names."
10436  "list" "Send used account list" "Used")
10437
10438 ;;; ----------------------------------------------------------------------
10439 ;;;
10440 (defun tinypgp-newnym-help-verbose (&optional arg)
10441   "Call `tinypgp-nymserver-help' as interactive would with ARG."
10442   (let* ((a (tinypgp-newnym-help-i-args arg)))
10443     (tinypgp-newnym-help (nth 0 a) (nth 1 a))))
10444
10445 ;;; ----------------------------------------------------------------------
10446 ;;;
10447 (defun tinypgp-newnym-help-i-args (&optional arg)
10448   "Ask arrgs for `tinypgp-newnym-help'. ARG is prefix arg."
10449   (let* ((list   (tinypgp-newnym-list)))
10450     (when (or (not (stringp tinypgp-:r-newnym-help-file))
10451               (null (file-exists-p tinypgp-:r-newnym-help-file))
10452               current-prefix-arg)
10453       (if (null list)
10454           (error "\
10455 TinyPgp: No 'newnym' type remailers in `tinypgp-:r-levien-table'."))
10456
10457       (list
10458        'mail-req
10459        (tinypgp-newnym-ask-server "Send help request to newnym: ")))))
10460
10461 ;;; ----------------------------------------------------------------------
10462 ;;;
10463 (defun tinypgp-newnym-help (&optional mail-req nym-alias-name verb)
10464   "Print newnym remailer help or send the help request via mail.
10465
10466 Input:
10467   MAIL-REQ          send mail request [current-prefix-arg]
10468   NYM-ALIAS-NAME    from where to ask the help file.
10469   VERB              verbose messages"
10470   (interactive (tinypgp-newnym-help-i-args current-prefix-arg))
10471   (let* ((file  tinypgp-:r-newnym-help-file)
10472          (elt   (if nym-alias-name
10473                     (assoc nym-alias-name tinypgp-:r-levien-table)))
10474          email)
10475     (ti::verb)
10476     (cond
10477      (mail-req
10478       (if (null elt)
10479           (error "TinyPgp: Cannot find ELT for '%s'" nym-alias-name))
10480
10481       ;; Set address to "help@..."
10482       (setq email (nth 1 elt))
10483
10484       (if (null (string-match "^[^@]+" email))
10485           (error "TinyPgp Internal error. Call \\[tinypgp-r-init]"))
10486
10487       (setq email (ti::replace-match 0 "help" email))
10488
10489       (ti::mail-sendmail-macro email "help" 'send (insert "help\n"))
10490       (if verb
10491           (message
10492            "Email request sent to '%s'.%s"
10493            email
10494            (if file ""
10495              "Update tinypgp-:r-newnym-help-file when you get answer."))))
10496
10497      ((and file
10498            (file-exists-p file))
10499       (pop-to-buffer (find-file-noselect file)))
10500
10501      (t
10502       (error "TinyPgp: Don't know what to do. %s %s "
10503              mail-req nym-alias-name)))))
10504
10505 ;;; ----------------------------------------------------------------------
10506 ;;;
10507 (defun tinypgp-newnym-config-insert
10508   (server nym-name &optional command pgp-key remailer)
10509   "Insert Config request to mail buffer. Mail body is supposed to be empty.
10510
10511 Input:
10512
10513   SERVER        newnym server alias name, like 'weasel'
10514   NYM-NAME      account name i the newnym server
10515   COMMAND       commands to send
10516   PGP-KEY       PGP key block.
10517                 if 'string' insert as is
10518                 if buffer pointer, insert buffer contents
10519                 if symbol; call pgp to find key from keyrings matching symbol.
10520
10521   REMAILER      Reply block
10522                 if 'string', then insert as is
10523                 if buffer pointer, then insert buffer content.
10524                 if symbol, it must be remailer alias name to use for
10525                 reply block. The remailer reply block is then
10526                 inserted from file pointed by `tinypgp-:r-reply-block-table'."
10527   (interactive
10528    (list
10529     (tinypgp-newnym-ask-server)
10530     (read-from-minibuffer "Nym account name: ")))
10531   (tinypgp-r-init-maybe)
10532   (let* ((fid   "tinypgp-newnym-config-insert:")
10533          list)
10534
10535     (tinypgpd fid "in:" server nym-name  command pgp-key remailer)
10536     ;; ... ... ... ... ... ... ... ... ... ... ... ... compose request ...
10537     (tinypgp-r-server-macro server "config"
10538
10539                             (ti::mail-kill-field "^To:" email)
10540                             (ti::mail-text-start 'move)
10541
10542                             (insert
10543                              "Config:\n"
10544                              "From: " (or nym-name "") "\n"
10545                              "Nym-Commands: "  (or command "") "\n")
10546
10547                             (when pgp-key
10548                               (insert "Public-Key:\n")
10549                               (cond
10550                                ((bufferp pgp-key) (insert-buffer pgp-key))
10551                                ((stringp pgp-key) (insert pgp-key))
10552
10553                                ((symbolp pgp-key)
10554                                 (tinypgp-key-extract-to-point (symbol-name pgp-key) 'raw)
10555                                 ;; check that PGP public key definition contains <> email
10556                                 ;; to this host.
10557                                 ;;
10558                                 (with-current-buffer tinypgp-:buffer-tmp-shell
10559                                   (setq list (ti::mail-email-find-region))
10560                                   (when (or (null list)
10561                                             (not (string-match
10562                                                   (replace-regexp-in-string ".*@" "" email 0)
10563                                                   ;;  Take first email from key-id
10564                                                   (or (car list)
10565                                                       (progn
10566                                                         (pop-to-buffer (current-buffer))
10567                                                         (error "\
10568 TinyPgp: no email found from pgp key?"))))))
10569                                     (pop-to-buffer (current-buffer))
10570                                     (error "TinyPgp: PGP user ID '%s' does not refer to domain '%s'"
10571                                            pgp-key email))))
10572
10573                                ((error "TinyPgp: Oops, wrong argument..."))))
10574
10575                             (when remailer
10576                               (insert "Reply-Block:\n")
10577                               (cond
10578                                ((bufferp remailer) (insert-buffer remailer))
10579                                ((stringp remailer) (insert remailer))
10580                                ((symbolp remailer)
10581                                 (tinypgp-r-reply-block-insert (symbol-name remailer)))
10582                                ((error "TinyPgp: Oops, wrong argument...")))
10583                               (insert "\n**\n")
10584                               (ti::pmax)))))
10585
10586 ;;; ----------------------------------------------------------------------
10587 ;;;
10588 (defun tinypgp-newnym-config-sendmail-template (server account &optional verb)
10589   "Create mail buffer and inset newnym' configuration template.
10590 Input:
10591
10592   SERVER    newnym server
10593   ACCOUNT   login account
10594   VERB      verbose, show buffer. Interactive call sets this.
10595
10596 Return:
10597   buffer pointer"
10598   (interactive
10599    (list
10600     (tinypgp-newnym-ask-server)
10601     (tinypgp-newnym-ask-account)))
10602   (tinypgp-r-init-maybe)
10603   (let* (buffer)
10604     (ti::verb)
10605     (with-current-buffer (setq buffer
10606                                (tinypgp-r-sendmail-create-buffer
10607                                 tinypgp-:buffer-newnym
10608                                 "Config request"))
10609       (tinypgp-newnym-config-insert server account)
10610       (turn-on-tinypgp-mode)
10611       (turn-on-tinypgp-newnym-mode)
10612       (tinypgp-newnym-mode-nym-commands-goto))
10613     (when verb
10614       (switch-to-buffer buffer))
10615     buffer))
10616
10617 ;;; ----------------------------------------------------------------------
10618 ;;;
10619 (defun tinypgpg-newnym-account-request
10620   (server account cmd &optional pgp-key remailer send)
10621   "Set up all necessary things to send command to newnym server account.
10622
10623 Input:
10624
10625   SERVER    newnym server alias
10626   ACCOUNT   newnym account name
10627   CMD       Nym-Comands's field content
10628
10629   PGP-KEY   If t, then inser pgp-key matching ACCOUNT
10630
10631             It symbol but not t, Email address string which
10632             matches the key-id from PGP key -- that key is sent to newnym.
10633
10634   REMAILER  Use this remailer's reply block. You must have created this
10635             beforehand with `tinypgp-r-reply-block-basic' and stored
10636             it to file pointed by `tinypgp-:r-reply-block-table'.
10637   SEND      if non-nil, encrypt and send the message.
10638
10639 Return:
10640   mail buffer pointer if SEND is nil"
10641   (let* ((fid   "tinypgpg-newnym-account-request: ")
10642          buffer
10643          to)
10644     (tinypgpd fid "ARGS" server account (current-buffer))
10645     ;; ... ... ... ... ... ... ... ... ... ... ... ... ... mail buffer ...
10646     (tinypgp-r-server-macro server account
10647                             (ti::mail-sendmail-pure-env-macro
10648                              (setq buffer (tinypgp-r-sendmail-create-buffer
10649                                            tinypgp-:buffer-newnym
10650                                            "Account request"))
10651                              ;;  The window excursion is needed so that nothing fancy happens
10652                              ;;  when we send mail. User doesn't want his windows changed
10653                              ;;
10654                              (save-window-excursion
10655                                (save-excursion
10656                                  (set-buffer buffer)
10657                                  (tinypgpd fid server account email info)
10658                                  (if (eq t pgp-key)
10659                                      (setq pgp-key (make-symbol email)))
10660
10661                                  (tinypgp-newnym-config-insert server account cmd pgp-key remailer)
10662
10663                                  (if (null send)
10664                                      buffer
10665                                    (make-local-variable 'tinypgp-:auto-action-table)
10666                                    (setq tinypgp-:auto-action-table nil)
10667                                    (ti::mail-sendmail-reset-send-hooks)
10668
10669                                    (tinypgp-save-state-macro
10670                                     (setq tinypgp-:user-now email)
10671                                     (tinypgp-password-set (format "Newnym Encrypt password: "))
10672                                     (setq to  (mail-fetch-field "to"))
10673                                     (tinypgp-encrypt-mail (ti::string-remove-whitespace to) nil))
10674                                    (mail-send-and-exit nil))))))))
10675
10676 ;;; ----------------------------------------------------------------------
10677 ;;;
10678 (defun tinypgp-newnym-delete (server account &optional verb)
10679   "Send to newbyn SERVER a ACCOUNT delete request. VERB."
10680   (interactive
10681    (tinypgp-newnym-ask-srv-acc
10682     "Are you sure you want to send DELETE request? "))
10683   (ti::verb)
10684   (tinypgp-r-init-maybe)
10685   (pop-to-buffer
10686    (tinypgpg-newnym-account-request server account "delete" nil nil))
10687   (if verb (message "Newnym Delete request sent.")))
10688
10689 ;;; ----------------------------------------------------------------------
10690 ;;;
10691 (defun tinypgp-newnym-create-i-args ()
10692   "Ask arguments to `tinypgp-newnym-create'."
10693   (let* ((site (get 'tinypgp-:r-newnym-default-account-table 'default-server))
10694          desc
10695          remailer
10696          srv-account
10697          login)
10698     (tinypgp-r-init-maybe)
10699     (message "You should check free Nym login names first...ok?")
10700     (sit-for 2)
10701
10702     (setq srv-account (tinypgp-newnym-ask-srv-acc))
10703
10704     (if (ti::nil-p
10705          (setq
10706           login
10707           (read-from-minibuffer
10708            (format
10709             "[%s] Create Nym Login: "
10710             site))))
10711         (error "Abort."))
10712
10713     (if (ti::nil-p
10714          (setq
10715           desc
10716           (read-from-minibuffer
10717            (format
10718             "[%s] Describe Nym login name: "
10719             site))))
10720         (error "TinyPgp: Empty not accepted."))
10721
10722     (setq remailer
10723           (tinypgp-ask-reply-block-remailer
10724            (format
10725             "[%s] Select Reply block of remailer: "
10726             site)))
10727
10728     (list (nth 0 srv-account)
10729           login
10730           desc
10731           remailer)))
10732
10733 ;;; ----------------------------------------------------------------------
10734 ;;;
10735 (defun tinypgp-newnym-create (server account desc remailer &optional verb)
10736   "Send to newbyn SERVER a ACCOUNT delete request.
10737
10738 Note:
10739
10740   Before you call this function, make sure you have created new key
10741   with 'pgp -kg' and that its key-id line contain email address
10742   <yournym@remail.domain.com>
10743
10744 Input:
10745
10746   SERVER    newnym server (alias) name
10747   ACCOUNT   account name in newnym
10748   DESC      account description
10749   REMAILER  remailer's reply block to submit to newnym server.
10750   VERB      Verbose messages. Shows the buffer and turns on
10751             `tinypgp-mode' and `tinypgp-newnym-mode`."
10752   (interactive
10753    (progn
10754      (tinypgpd "tinypgp-newnym-create: INTERACTIVE")
10755
10756      (or
10757       (y-or-n-p
10758        "\
10759 Do have created the ncessary PGP keys for newnym account? (see manual)")
10760       ;; Umph; again some impatient user selected this choice without readin
10761       ;; the newnym documentation....
10762       (error "TinyPgp: Please read the newnym remailer manual first."))
10763      (tinypgp-newnym-create-i-args)))
10764   (tinypgpd "tinypgp-newnym-create: in" server account desc remailer verb)
10765   (tinypgp-r-init-maybe)
10766   (let* ()
10767     (ti::verb)
10768     ;; ... ... ... ... ... ... ... ... ... ... ... ... ... mail buffer ...
10769     (with-current-buffer (tinypgpg-newnym-account-request
10770                           server account
10771                           (format "create +acksend +fingerkey name=\"%s\"" desc)
10772                           t
10773                           (make-symbol remailer))
10774
10775       (when verb
10776         (turn-on-tinypgp-mode)
10777         (switch-to-buffer (current-buffer)) ;Now visible to user
10778         (ti::mail-text-start 'move)
10779
10780         (turn-on-tinypgp-newnym-mode)
10781         (ti::mail-mime-turn-off-mode)
10782         (tinypgp-email-substitution-toggle 0) ;; Config request
10783 ;;;     (tinypgp-auto-action-toggle 0)       ;; No auto action here by default
10784
10785         ;;  We havae to "account", bwecause 1pass needs to be signed
10786         ;;  with the "account" key. Store the active pgp user information
10787         ;;  to local variables, so that we can restore the user in mail send
10788         ;;  hook
10789         ;;
10790
10791         (make-local-variable 'tinypgp-pgp-user-original)
10792         (make-local-variable 'tinypgp-pgp-user-now)
10793
10794         (defconst tinypgp-pgp-user-original   tinypgp-:user-now)
10795         (defconst tinypgp-pgp-user-now        account)
10796         (setq     tinypgp-:user-now           account)
10797
10798         ;;  Warn about this change, because user may kill the buffer
10799         ;;  and the active pgp user still stays "nym" login.
10800         ;;
10801         (message "Active PGP user changed to: %s" account) (sleep-for 1.5)
10802
10803         (ti::read-char-safe-until
10804          (substitute-command-keys
10805           (concat
10806            "Check all; do 1pass Encrypt-Sign with NymKey: "
10807            "\\[tinypgp-encrypt-mail-sign] [press to continue]")))))))
10808
10809 ;;; ----------------------------------------------------------------------
10810 ;;;
10811 (defun tinypgp-newnym-post (&optional server account verb)
10812   "Convert current message into Nym post ueing SERVER and ACCOUNT. VERB.
10813 The message can be newsgroup post or regular email."
10814   (interactive
10815    (progn
10816      (tinypgp-r-init-maybe)
10817      (list
10818       (tinypgp-newnym-ask-server)
10819       (tinypgp-newnym-ask-account))))
10820   (tinypgp-r-init-maybe)
10821   (let* ((subj      (mail-fetch-field    "Subject"))
10822          (news      (ti::mail-news-buffer-p))
10823          (hdr-blk   "")
10824          hash-headers to
10825          hdr
10826          ret)
10827     (ti::verb)
10828
10829     (tinypgp-r-server-macro server "send"
10830                             (cond
10831                              (news
10832                               (setq ret (tinypgp-r-post-usenet 'newnym))
10833                               (ti::mail-kill-field "To")
10834                               (ti::mail-kill-field "Subject")
10835                               (ti::mail-kill-field "From")
10836                               ;;  Rest of the headers without "To" field.
10837                               ;;
10838                               (setq hdr (buffer-substring (point-min) (ti::mail-hmax)))
10839
10840                               ;;  Now send to newnym server
10841                               ;;
10842                               (ti::pmin)
10843                               (insert "To: " email "\n"
10844                                       "Subject: message\n")
10845
10846                               (ti::mail-text-start 'move)
10847                               (insert "From: " account "\n"
10848                                       "To: " (or (eval tinypgp-:r-newnym-mail2news-address)
10849                                                  (error "TinyPgp: no newnym mail2news gateway?"))
10850                                       "\n"
10851                                       "subject: " subj "\n")
10852
10853                               (insert hdr)
10854                               (insert "Newsgroups: " (ti::list-to-string (nth 1 ret)) "\n\n")
10855                               (ti::mail-kill-field-in-body '("fcc" "gcc")))
10856                              (t
10857                               (setq to (mail-fetch-field       "to"))
10858                               (tinypgp-header-kill)
10859                               ;;  Save all headers because they are inserted into body
10860                               ;;
10861                               (if (setq hash-headers
10862                                         (tinypgp-header-move-to-body 'move-to-body 'no-ins))
10863                                   (setq hdr-blk      (mapconcat 'concat hash-headers "")))
10864                               (ti::mail-kill-field "To" email)
10865                               (ti::pmin) (insert "To: " email "\n")
10866
10867                               (ti::mail-text-start 'move)
10868                               (insert "From: " account "\n"
10869                                       "To: " to "\n"
10870                                       hdr-blk))))
10871     (when verb
10872       (unless tinypgp-newnym-mode (turn-on-tinypgp-newnym-mode))
10873       ;; (tinypgp-auto-action-update-modeline)
10874       (message
10875        (substitute-command-keys
10876         (concat
10877          "Nym-Commands can be set per message basis, press "
10878          "\\[tinypgp-newnym-mode-nym-commands-goto] and "
10879          "\\[tinypgp-newnym-mode-electric-tab]"))))))
10880
10881 ;;}}}
10882 ;;{{{ newnym: interactive requests
10883
10884 ;;; ------------------------------------------------------ &newnym-req ---
10885 ;;;
10886 (eval-and-compile
10887   (defun tinypgp-newnym-req-fmacro-1 (func req)
10888     "Use `tinypgp-newnym-req-fmacro' instead. See FUNC REQ there."
10889     (let* ((sym (intern (symbol-name (` (, func))))))
10890       (`
10891        (defun (, sym)  (server account &optional plus verb)
10892          "Send to newnym SERVER ACCOUNT an minus(default) or PLUS request. VERB."
10893          (interactive (tinypgp-newnym-ask-srv-acc-arg))
10894          (ti::verb)
10895          (setq plus (concat (if plus "+" "-") (, req)))
10896          (tinypgpg-newnym-account-request
10897           server account plus  nil nil 'send)
10898          (tinypgp-newnym-file-stamp server account)
10899          (when verb
10900            (message "[%s] Newnym request sent: %s" server plus)
10901            ;; If mouse pressed, don't wipe message immediately
10902            (sleep-for 1)))))))
10903
10904 ;;; ----------------------------------------------------------------------
10905 ;;;
10906 (put 'tinypgp-newnym-req-fmacro 'lisp-indent-function 0)
10907 (defmacro tinypgp-newnym-req-fmacro (func req)
10908   "Create interactive function that sends newnym request.
10909 Input:
10910
10911   FUNC  Created function name
10912   REQ   request to send; without +- option at front."
10913   (` (, (tinypgp-newnym-req-fmacro-1 func req))))
10914
10915 ;;; ----------------------------------------------------------------------
10916 ;;; We have to tell the autoloads by hand; because the functions are
10917 ;;; created by separate macro.
10918 ;;;
10919 ;;;###autoload (autoload 'tinypgp-newnym-req-acksend    "tinypgp" "" t)
10920 ;;;###autoload (autoload 'tinypgp-newnym-req-sigsend    "tinypgp" "" t)
10921 ;;;###autoload (autoload 'tinypgp-newnym-req-cryptrecv  "tinypgp" "" t)
10922 ;;;###autoload (autoload 'tinypgp-newnym-req-fixedsize  "tinypgp" "" t)
10923 ;;;###autoload (autoload 'tinypgp-newnym-req-disable    "tinypgp" "" t)
10924 ;;;###autoload (autoload 'tinypgp-newnym-req-fingerkey  "tinypgp" "" t)
10925 ;;;###autoload (autoload 'tinypgp-newnym-req-nobcc      "tinypgp" "" t)
10926
10927 (tinypgp-newnym-req-fmacro tinypgp-newnym-req-acksend   "acksend")
10928 (tinypgp-newnym-req-fmacro tinypgp-newnym-req-sigsend   "sigsend")
10929 (tinypgp-newnym-req-fmacro tinypgp-newnym-req-cryptrecv "cryptrecv")
10930 (tinypgp-newnym-req-fmacro tinypgp-newnym-req-fixedsize "fixedsize")
10931 (tinypgp-newnym-req-fmacro tinypgp-newnym-req-disable   "disable")
10932 (tinypgp-newnym-req-fmacro tinypgp-newnym-req-fingerkey "fingerkey")
10933 (tinypgp-newnym-req-fmacro tinypgp-newnym-req-nobcc     "nobcc")
10934
10935 ;;}}}
10936
10937 ;;{{{ Nymserver: misc
10938
10939 ;;; .................................................. &nymserver-misc ...
10940 ;;; anon.nymserver.com successor of anon.penet.fi
10941
10942 ;;; ----------------------------------------------------------------------
10943 ;;;
10944 (defun tinypgp-nymserver-mail-p (&optional alias)
10945   "Check if there is Anon X-headers in the buffers. ALIAS."
10946   (setq alias (car (car tinypgp-:nymserver-table)))
10947   (and
10948    (ti::re-search-check "^X-Anon-Password\\|^X-Anon-To")
10949    (ti::re-search-check (format "^To:.*%s" alias))))
10950
10951 ;;; ----------------------------------------------------------------------
10952 ;;;
10953 (defsubst tinypgp-nymserver-service-elt (alias)
10954   "Return service entries or call error is no such ALIAS."
10955   (or (assoc alias tinypgp-:nymserver-table)
10956       (error "TinyPgp: No server alias '%s'" alias)))
10957
10958 ;;; ----------------------------------------------------------------------
10959 ;;;
10960 (defsubst tinypgp-nymserver-mailto (alias)
10961   "Return address where user can send mail so that it gets anynymized. ALIAS."
10962   (or (nth 3 (assoc alias tinypgp-:nymserver-table))
10963       (error "TinyPgp: No post email address")))
10964
10965 ;;; ----------------------------------------------------------------------
10966 ;;;
10967 (defsubst tinypgp-nymserver-address (string alias)
10968   "Return nymserver email address prepended with STRING as account name. ALIAS.
10969
10970 Return:
10971   STRING@NYMSERVER-ADDRESS"
10972   (concat
10973    string
10974    (ti::string-match
10975     "\\(@.*\\)" 1
10976     (nth 2 (assoc alias tinypgp-:nymserver-table)))))
10977
10978 ;;; ----------------------------------------------------------------------
10979 ;;;
10980 (defun tinypgp-nymserver-ask (&optional msg)
10981   "Ask server alias name with MSG."
10982   (if nil                               ;disabled now
10983       (completing-read
10984        (or msg "Use pent server: ")
10985        (ti::list-to-assoc-menu (mapcar 'car tinypgp-:nymserver-table))
10986        nil
10987        'match)
10988     ;; 1997-02-13 Jari aalto
10989     ;; - We don't support other nymserver accounts currently
10990     ;;
10991     (car (car tinypgp-:nymserver-table))))
10992
10993 ;;; ----------------------------------------------------------------------
10994 ;;;
10995 (defun tinypgp-nymserver-password (alias)
10996   "Return password or nil for ALIAS."
10997   (let* ((elt      (assoc alias tinypgp-:nymserver-account-table))
10998          (pass     (nth 2 elt)))
10999     pass))
11000
11001 ;;; ----------------------------------------------------------------------
11002 ;;;
11003 (defun tinypgp-nymserver-sendmail (action alias &optional verb arg1 arg2)
11004   "Send ACTION mail to nymserver ALIAS.
11005 Mail will be encrypted if `tinypgp-:nymserver-request-encrypt' is non-nil.
11006 See variables documentation for more detailed usage.
11007
11008 Input:
11009   ACTION ALIAS VERB ARG1 ARG2
11010
11011 Note:
11012   following variables are bound to nil to prevent any interference when
11013   sending mail commands.
11014
11015   `mail-archive-file-name'
11016   `mail-default-headers'
11017   `mail-mode-hook'
11018   `mail-setup-hook'"
11019   (let* ((elt       (assoc alias tinypgp-:nymserver-account-table))
11020          (account   (or (nth 1 elt)
11021                         (error "TinyPgp: No account")))
11022          (pass      (or (nth 2 elt)
11023                         (error "TinyPgp: No account password")))
11024          (my-from   (nth 4 elt))
11025
11026          (fld1      "X-Anon-Password: ")
11027          (fld2      "X-Anon-Subject: ")
11028          (encrypt   tinypgp-:nymserver-request-encrypt)
11029
11030          ;; Make sure email substitution mode is on when we send
11031          ;; mail to anon server. User may have forgotten it off
11032
11033          (tinypgp-:read-email-after-hook
11034           (or (get 'tinypgp-:read-email-after-hook 'original)
11035
11036               ;; if the above fails, that means that the 'original
11037               ;; property is not used yet and not available.
11038
11039               tinypgp-:read-email-after-hook))
11040
11041          (email     (tinypgp-nymserver-address (symbol-name action) alias))
11042          (enc-key   (car (tinypgp-key-id-conversion email)))
11043          subject
11044          buffer)
11045
11046     (tinypgpd "tinypgp-nymserver-sendmail in: " action alias verb arg1 arg2)
11047
11048     (save-window-excursion
11049       (cond
11050        ((memq action '(finger ping remove help abuse))
11051         (ti::mail-sendmail-macro  email "None" 'send
11052                                   (insert fld2 (or arg1 "No subject data") "\n")
11053
11054                                   ;; This field will confuse Nymserver server. Remove it
11055                                   ;;
11056                                   (ti::mail-kill-field "Reply-To")
11057                                   (if my-from (ti::mail-add-field "From"  my-from "To"))
11058
11059                                   (if encrypt (tinypgp-encrypt-mail-find-keyring enc-key))))
11060 ;;;       (pop-to-buffer (current-buffer)) (ti::d! 101)
11061
11062        ;; .. .. .. .. .. .. .. .. .. .. .. .. .. .. ..  upload pgp key . .
11063        ((eq action 'newpgp)
11064         (unless arg1                    ;Nor a remove request?
11065           (with-current-buffer (setq buffer (tinypgp-ti::temp-buffer 'finger))
11066             (erase-buffer)
11067             (tinypgp-key-extract-to-point account)
11068
11069             (ti::pmin)
11070             (if (re-search-forward "matching keys found" nil t)
11071                 (error "TinyPgp: [%s' didn't match exactly." arg1))))
11072
11073         (ti::mail-sendmail-macro  email "No subject" 'send
11074                                   (if my-from (ti::mail-add-field "From"  my-from "To"))
11075
11076                                   (insert fld1 pass    "\n")
11077
11078 ;;;       (pop-to-buffer (current-buffer)) (ti::d! 10)
11079
11080                                   (if (string= "remove" arg1)
11081                                       (insert fld2 "remove" "\n")
11082                                     (insert-buffer buffer))
11083
11084                                   (if encrypt
11085                                       (tinypgp-encrypt-mail-find-keyring enc-key))))
11086
11087        ;; .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. plan and sig . .
11088        ((memq action '(newplan newsig))
11089         (ti::mail-sendmail-macro  email "No subject" 'send
11090                                   (insert fld1 pass "\n")
11091
11092                                   (ti::mail-kill-field "Reply-To")
11093                                   (if my-from (ti::mail-add-field "From"  my-from "To"))
11094
11095                                   (if (string= "remove" arg1)
11096                                       (insert fld2 "remove" "\n")
11097                                     (insert-file arg1))
11098
11099                                   (if encrypt
11100                                       (tinypgp-encrypt-mail-find-keyring enc-key))))
11101
11102        ;; .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. ..  flags . .
11103        ((memq action '(paranoid newalias nick
11104                                 newpassword vacation noarchive
11105                                 newaddress setnon
11106                                 pgpencrypt pgpsign sendmix))
11107         (setq subject (or arg1 "No subject")) ;this is the new alias name
11108         (ti::mail-sendmail-macro  email "No subject" 'send
11109                                   (insert fld1 pass "\n"
11110                                           fld2 subject "\n")
11111
11112                                   (ti::mail-kill-field "Reply-To")
11113                                   (if my-from (ti::mail-add-field "From"  my-from "To"))
11114
11115 ;;;       (pop-to-buffer (current-buffer)) (ti::d! 10)
11116                                   (if encrypt (tinypgp-encrypt-mail-find-keyring enc-key))))
11117 ;;;       (pop-to-buffer (current-buffer)) (ti::d! 10)
11118        (t
11119         (error "TinyPgp: unknown action '%s'" action)))
11120       (if verb (message "Nymserver: %s request sent."
11121                         (capitalize (symbol-name action)))))))
11122
11123 ;;; ----------------------------------------------------------------------
11124 ;;;
11125 (defun tinypgp-nymserver-create-1 (email)
11126   "Send EMAIL to create account."
11127   (interactive)
11128   (ti::read-char-safe-until
11129    "[press] Store received account info into tinypgp-:nymserver-account-table.")
11130   (ti::mail-sendmail-macro email "No subject" 'send))
11131
11132 ;;}}}
11133 ;;{{{ Nymserver: interactive
11134
11135 ;;; ----------------------------------------------------------------------
11136 ;;;
11137 (defun tinypgp-nymserver-post (alias &optional verb)
11138   "Convert message so that it can be posted to through nymserver. ALIAS VERB."
11139   (interactive
11140    (list
11141     (progn
11142       (tinypgp-nymserver-i-enable)
11143       (tinypgp-nymserver-ask))))
11144
11145   (let* ((srv    (tinypgp-nymserver-service-elt alias))
11146          (mailto (or (nth 3 srv)
11147                      (error "TinyPgp: No server mailto address.")))
11148          (grp-limit (nth 4 srv))
11149
11150          (elt   (or (assoc alias tinypgp-:nymserver-account-table)
11151                     (error "TinyPgp: Unknown server %s" alias)))
11152 ;;;      (email (or (nth 1 elt)
11153 ;;;                 (error "No account email")))
11154
11155          (pass  (or (nth 2 elt)
11156                     (error "TinyPgp: No account password")))
11157          (name      (nth 3 elt))
11158          (my-from   (nth 4 elt))
11159
11160          (fld1      "X-Anon-Password: ")
11161          (fld2      "X-Anon-To: ")
11162          (fld3      "X-Anon-Name: ")
11163          (fld4      "X-Anon-Subject: ")
11164 ;;;      (fld-ref   "X-Anon-references: ") references
11165          to subject
11166          hlist
11167          grp)
11168
11169     (ti::verb)
11170
11171     (unless (ti::mail-mail-p)
11172       (error "TinyPgp: This is not email buffer."))
11173
11174     (setq to        (mail-fetch-field    "to")
11175           subject   (mail-fetch-field    "subject")
11176           hlist     (delete 'newsgroups (ti::mail-required-headers)))
11177
11178     (when   (ti::nil-p subject)
11179       (error "TinyPgp: No subject. Aborted"))
11180
11181     (ti::save-with-marker-macro
11182       (ti::mail-text-start 'move)
11183       (if (looking-at "X-Anon")
11184           (if verb
11185               (message "Already in anon post format."))
11186
11187         (cond
11188          ((not (ti::nil-p to))          ;regular email message
11189
11190           ;;  tinymail.el / we have to add 2 spaces to the beginning of field
11191           ;;  so that CC tracking goes off.
11192           ;;
11193           (ti::mail-kill-field "to" (concat "  " mailto))
11194           (if my-from (ti::mail-add-field "From"  my-from "To"))
11195
11196           (insert fld1 pass "\n"
11197                   fld2 to   "\n"
11198                   (if name (concat fld3 name "\n") "")
11199                   fld4
11200                   subject "\n")
11201           (tinypgp-update-modeline))
11202
11203          ((not (ti::nil-p (setq grp (mail-fetch-field "newsgroups"))))
11204           (if (and grp-limit
11205                    (> (count-char-in-string ?, grp) grp-limit))
11206               (error "\
11207 TinyPgp: Too many newsgroups, only %d allowed" grp-limit))
11208
11209 ;;;       (setq references (mail-fetch-field "references"))
11210           (push 'in-reply-to  hlist )
11211           (ti::mail-kill-non-rfc-fields hlist)
11212
11213           (ti::mail-add-field "To"  mailto)
11214           (when my-from
11215             ;; it may be possible that this field is there already,
11216             ;; kill it first
11217             ;;
11218             (ti::mail-kill-field "^From:")
11219             (ti::mail-add-field "From"  my-from  "To"))
11220
11221           (ti::mail-text-start 'move)
11222           (insert fld1 pass "\n"
11223                   fld2 grp  "\n"
11224                   (if name (concat fld3 name "\n") "")
11225                   fld4
11226                   subject "\n")
11227           (tinypgp-update-modeline))
11228
11229          (t
11230           (if verb
11231               (error "\
11232 TinyPgp: Don't know what to do: To or Newsgroup field empty."))))
11233         (ti::mail-kill-field "subject" " None")
11234
11235         ;;  Add 'cutmarks' so that all the rest of the text are
11236         ;;  ripped.
11237         ;;
11238         (ti::pmax)
11239         (if (bolp)
11240             (insert "--")
11241           (insert "\n--"))))
11242
11243     (run-hooks 'tinypgp-:nymserver-post-hook)))
11244
11245 ;;; ----------------------------------------------------------------------
11246 ;;;
11247 (defun tinypgp-nymserver-send ()
11248   "Handle sending mail addressed to Nymserver.
11249 This function is called after C -c C -c to sned the mail.
11250 If there are no multiple recipients, this function does nothing
11251
11252 Return:
11253   nil
11254   t"
11255   (let* ((fid      "tinypgp-nymserver-send: ")
11256          (email    "anon@anon.nymserver.com")
11257          (to        (mail-fetch-field    "to"))
11258          (cc        (mail-fetch-field    "cc"))
11259          (fcc       (mail-fetch-field    "fcc"))
11260          (subject   (mail-fetch-field    "subject"))
11261          (elist     (delete
11262                      email
11263                      (append
11264                       (ti::mail-email-from-string to)
11265                       (if cc (ti::mail-email-from-string cc)))))
11266
11267          (enc-key   (car (tinypgp-key-id-conversion email)))
11268          (encrypt   tinypgp-:nymserver-request-encrypt)
11269
11270          (len       (length elist))
11271 ;;;      (i         0)
11272          (send-flag t)
11273
11274          message-body
11275          ret)
11276
11277     ;;  - Nymserver doesn't accept CC or many addresses in To field,
11278     ;;    it can only have one X-anon-To destination.
11279     ;;  - What we do here is, that we copy the message and send it
11280     ;;    individually to each destination
11281     ;;  - We need confirmation for this
11282
11283     (when (or (> len 1)
11284               ;;  If there is CC, then automatically suppose multiple
11285               ;;  recipients. The To field is already in X-Anon-To
11286               ;;  So this CC makes at least 2 recipients.
11287               ;;
11288               cc)
11289       (tinypgpd fid subject to cc fcc elist)
11290
11291       ;;  The X-Anon-To is inside PGP envelope, we can't use this message
11292       ;;  body to CC it to others.
11293       ;;
11294       (if (ti::mail-pgp-encrypted-p 'double-check)
11295           (error "\
11296 TinyPgp: You have CC in Nymserver mail. Can't process encrypted message."))
11297
11298       (if (null
11299            (y-or-n-p
11300             (format
11301              "CC %d: You have multiple anon recipients, are you sure? "
11302              len)))
11303           (error "Abort.")
11304         (setq message-body
11305               (buffer-substring (ti::mail-text-start) (point-max)))
11306         (dolist (elt elist)
11307           (ti::mail-sendmail-macro email "None" send-flag
11308                                    (insert message-body)
11309                                    (pop-to-buffer (current-buffer))
11310                                    (ti::pmin)
11311                                    (re-search-forward "X-Anon-To:\\(.*\\)")
11312                                    (ti::replace-match 1 (concat " " elt))
11313                                    (pop-to-buffer (current-buffer))
11314 ;;;         (incf  i) (message "Sending-quick %d/%d %s" i len elt)
11315                                    (if encrypt
11316                                        (tinypgp-encrypt-mail-find-keyring enc-key))))
11317         (ti::read-char-safe-until
11318          "[press]Anon CC copies sent, now sending this mail buffer.")
11319         (ti::mail-kill-field "cc")
11320         (if encrypt
11321             (tinypgp-encrypt-mail-find-keyring enc-key))
11322         (setq ret t)))
11323     ret))
11324
11325 ;;; ----------------------------------------------------------------------
11326 ;;;
11327 (defun tinypgp-nymserver-create (alias)
11328   "Send account create request. ALIAS."
11329   (interactive (list (tinypgp-nymserver-ask)))
11330   (let ((srv (tinypgp-nymserver-service-elt alias)))
11331     (if (yes-or-no-p
11332          "Are you absolutely sure you want to send 'create' request ")
11333         (funcall (nth 1 srv) (nth 1 srv)))))
11334
11335 ;;; ----------------------------------------------------------------------
11336 ;;;
11337 (defun tinypgp-nymserver-remove (alias)
11338   "Remove your anonymous account. ALIAS."
11339   (interactive
11340    (list
11341     (progn
11342       (tinypgp-nymserver-i-enable)
11343       (tinypgp-nymserver-ask))))
11344   (if (yes-or-no-p
11345        "Are you absolutely sure you want to terminate anonymous account ")
11346       (tinypgp-nymserver-sendmail 'remove alias (interactive-p))))
11347
11348 ;;; ----------------------------------------------------------------------
11349 ;;; Hm. This function does not have paramaeter 'alias'.
11350 ;;; So it's not general purpose for other accounts
11351 ;;; #todo: Should rethink it sometime.
11352 ;;;
11353 (defun tinypgp-nymserver-finger (account)
11354   "Finger account's email address for its configuration.
11355 If ACCOUNT is in format vanity.an@site or vanity.na@site.com, it is converted
11356 into vanity@site.com before sending finger request."
11357   (interactive
11358    (progn
11359 ;;;     (tinypgp-nymserver-i-enable)
11360      (let* ((elt            (assoc (tinypgp-nymserver-ask)
11361                                    tinypgp-:nymserver-account-table))
11362             (from           (car-safe
11363                              (ti::mail-email-from-string
11364                               (or (mail-fetch-field "from") ""))))
11365             (account        (nth 1 elt))
11366             (list           (if account
11367                                 (ti::list-to-assoc-menu (list account)))))
11368        ;;  If user has reveived mail from anNNN@anon.nymserver.com
11369        ;;  Then we offer to finger that account too
11370        ;;
11371        (when (and from (string-match "an[0-9]@\\|\\.[an][na]@" from))
11372          (setq list (ti::list-to-assoc-menu
11373                      (if account
11374                          (list from account)
11375                        (list from))))
11376          (setq account from))
11377
11378        (list
11379         (completing-read
11380          "Finger nymserver account [give email address]: "
11381          list
11382          nil
11383          nil
11384          account)))))
11385
11386   ;;  Use may press <empty> RET in completing-read
11387
11388   (if (not (string-match "@" account))
11389       (error "TinyPgp: Need email address."))
11390
11391   ;; silent converion to 'an' format
11392
11393   (setq account (ti::mail-nymserver-email-convert account))
11394
11395   (tinypgp-nymserver-sendmail
11396    'finger (tinypgp-nymserver-ask) (interactive-p) account))
11397
11398 ;;; ----------------------------------------------------------------------
11399 ;;;
11400 (defun tinypgp-nymserver-abuse (alias)
11401   "Send ABUSE request. ALIAS."
11402   (interactive (list (tinypgp-nymserver-ask)))
11403   (let* ((buffer "*mail-nymserver-abuse*"))
11404     (ti::kill-buffer-safe buffer)
11405     (when (y-or-n-p "Nymserver: Are you sure you want to report ABUSE? ")
11406       (ti::mail-sendmail-macro
11407        (tinypgp-nymserver-address "abuse" alias)
11408        "ABUSE"
11409        nil
11410        (rename-buffer buffer)
11411        (pop-to-buffer (current-buffer))
11412        (message "Write message and possibly encrypt it.")))))
11413
11414 ;;; ----------------------------------------------------------------------
11415 ;;;
11416 (defun tinypgp-nymserver-ping (alias)
11417   "Send Ping request. ALIAS.
11418 In order to send ping, you have to be sending
11419 mail FROM AN ACCOUNT WHERE YOU SENT the create command. You can't send ping
11420 from any other location."
11421   (interactive
11422    (progn
11423      (tinypgp-nymserver-i-enable)
11424      (list (tinypgp-nymserver-ask))))
11425   (tinypgp-nymserver-sendmail 'ping alias (interactive-p)))
11426
11427 ;;; ----------------------------------------------------------------------
11428 ;;;
11429 (defun tinypgp-nymserver-paranoid (alias)
11430   "Toggle paranoid setting. ALIAS."
11431   (interactive
11432    (progn
11433      (tinypgp-nymserver-i-enable)
11434      (list (tinypgp-nymserver-ask))))
11435   (tinypgp-nymserver-sendmail 'paranoid alias (interactive-p)))
11436
11437 ;;; ----------------------------------------------------------------------
11438 ;;;
11439 (defun tinypgp-nymserver-vacation (alias)
11440   "Toggle vacation setting. ALIAS."
11441   (interactive
11442    (progn
11443      (tinypgp-nymserver-i-enable)
11444      (list (tinypgp-nymserver-ask))))
11445   (tinypgp-nymserver-sendmail 'vacation alias (interactive-p)))
11446
11447 ;;; ----------------------------------------------------------------------
11448 ;;;
11449 (defun tinypgp-nymserver-noarchive (alias)
11450   "Toggle USENET achive setting. ALIAS."
11451   (interactive
11452    (progn
11453      (tinypgp-nymserver-i-enable)
11454      (list (tinypgp-nymserver-ask))))
11455   (tinypgp-nymserver-sendmail 'noarchive alias (interactive-p)))
11456
11457 ;;; ----------------------------------------------------------------------
11458 ;;;
11459 (defun tinypgp-nymserver-setnon (alias)
11460   "Toggle anNNN/naNNN mode when you get private mail. ALIAS."
11461   (interactive
11462    (progn
11463      (tinypgp-nymserver-i-enable)
11464      (list (tinypgp-nymserver-ask))))
11465   (tinypgp-nymserver-sendmail 'setnon alias (interactive-p)))
11466
11467 ;;; ----------------------------------------------------------------------
11468 ;;;
11469 (defun tinypgp-nymserver-newplan (alias file)
11470   "ALIAS. Upload plan FILE. If file is 'remove' then remove plan."
11471   (interactive
11472    (progn
11473      (tinypgp-nymserver-i-enable)
11474      (list
11475       (tinypgp-nymserver-ask)
11476       (if (y-or-n-p "y = upload .plan, n = remove plan" )
11477           (call-interactively
11478            '(lambda (arg) (interactive "fNymserver plan file: ") arg))
11479         "remove"))))
11480   (tinypgp-nymserver-sendmail 'newplan alias (interactive-p) file))
11481
11482 ;;; ----------------------------------------------------------------------
11483 ;;;
11484 (defun tinypgp-nymserver-newsig (alias file)
11485   "ALIAS. Upload signature FILE. If file is 'remove' then remove signature."
11486   (interactive
11487    (progn
11488      (tinypgp-nymserver-i-enable)
11489      (list
11490       (tinypgp-nymserver-ask)
11491       (if (y-or-n-p "y = upload .signature, n = remove plan" )
11492           (call-interactively
11493            '(lambda (arg) (interactive "fNymserver signature file: ") arg))
11494         "remove"))))
11495   (tinypgp-nymserver-sendmail 'newsig alias (interactive-p) file))
11496
11497 ;;; ----------------------------------------------------------------------
11498 ;;;
11499 (defun tinypgp-nymserver-newaddress (alias new)
11500   "ALIAS. Change your mailbox address.
11501 You must be mailing from the NEW ADDRESS currently."
11502   (interactive
11503    (progn
11504      (tinypgp-nymserver-i-enable)
11505      (list
11506       (tinypgp-nymserver-ask)
11507       (read-from-minibuffer
11508        "[You must be in NEW site now] Your old address: "))))
11509   (if (ti::nil-p new)                  ;User may have pressed ENTER...
11510       (error "TinyPgp: No address."))
11511   (tinypgp-nymserver-sendmail 'newaddress alias (interactive-p) new))
11512
11513 ;;; ----------------------------------------------------------------------
11514 ;;;
11515 (defun tinypgp-nymserver-newalias (alias name)
11516   "ALIAS NAME. Change you anNNN@ account to NEWALIAS@."
11517   (interactive
11518    (progn
11519      (tinypgp-nymserver-i-enable)
11520      (list
11521       (tinypgp-nymserver-ask)
11522       (read-from-minibuffer
11523        "newalias request; vanity alias [word]: "))))
11524   (if (or (< (length name) 3)
11525           (> (length name) 15))
11526       (error "TinyPgp: Invalid string size [3-15]; %s has %d characters."
11527              name (length name)))
11528   (tinypgp-nymserver-sendmail 'newalias alias (interactive-p) name))
11529
11530 ;;; ----------------------------------------------------------------------
11531 ;;;
11532 (defun tinypgp-nymserver-nickname (alias name)
11533   "ALIAS. Change you nick NAME that appears in anon post From field."
11534   (interactive
11535    (progn
11536      (tinypgp-nymserver-i-enable)
11537      (list
11538       (tinypgp-nymserver-ask)
11539       (read-from-minibuffer "Nickname [string or word 'remove']: "))))
11540   (tinypgp-nymserver-sendmail 'nick alias (interactive-p) name))
11541
11542 ;;; ----------------------------------------------------------------------
11543 ;;;
11544 (defun tinypgp-nymserver-newpassword (alias password)
11545   "ALIAS. Change your PASSWORD."
11546   (interactive
11547    (progn
11548      (tinypgp-nymserver-i-enable)
11549      (list
11550       (tinypgp-nymserver-ask)
11551       (ti::compat-read-password "New nymserver password: "))))
11552   (tinypgp-nymserver-sendmail 'newpassword alias nil password)
11553   (ti::read-char-safe-until
11554    "Update your password _now_ to tinypgp-:nymserver-account-table"))
11555
11556 ;;; ----------------------------------------------------------------------
11557 ;;;
11558 (defun tinypgp-nymserver-pgp-upload (alias &optional remove)
11559   "ALIAS. Upload or REMOVE pgp key. Before you call this commaand note:
11560
11561 o You must have created the PGP public key for your Nymserver account.
11562 o You must have defined the `tinypgp-:nymserver-account-table'; the key
11563   uploaded must have the email address.
11564 o If you change your vanity name, remember to start all over(New key,
11565   and update table)"
11566   (interactive
11567    (progn
11568      (tinypgp-nymserver-i-enable)
11569      (list
11570       (tinypgp-nymserver-ask)
11571       (not (y-or-n-p
11572             "Y = upload your PGP key to Anon account [N = remove] ")))))
11573   (tinypgp-nymserver-sendmail 'newpgp alias (interactive-p) remove))
11574
11575 ;;; ----------------------------------------------------------------------
11576 ;;;
11577 (defun tinypgp-nymserver-pgp-encrypt (alias)
11578   "Toggle receiving PGP encryped mail. ALIAS.
11579 You have to upload PGP key first with \\[tinypgp-nymserver-pgp-upload]"
11580   (interactive
11581    (progn
11582      (tinypgp-nymserver-i-enable)
11583      (list (tinypgp-nymserver-ask))))
11584   (tinypgp-nymserver-sendmail 'pgpencrypt alias (interactive-p)))
11585
11586 ;;; ----------------------------------------------------------------------
11587 ;;;
11588 (defun tinypgp-nymserver-pgp-sign (alias)
11589   "Turn on/off PGP siging. ALIAS."
11590   (interactive
11591    (progn
11592      (tinypgp-nymserver-i-enable)
11593      (list (tinypgp-nymserver-ask))))
11594   (tinypgp-nymserver-sendmail 'pgpsign alias (interactive-p)))
11595
11596 ;;; ----------------------------------------------------------------------
11597 ;;;
11598 (defun tinypgp-nymserver-pgp-sendmix (alias)
11599   "Turn on/off Mixmaster support. ALIAS."
11600   (interactive
11601    (progn
11602      (tinypgp-nymserver-i-enable)
11603      (list (tinypgp-nymserver-ask))))
11604   (tinypgp-nymserver-sendmail 'sendmix alias (interactive-p)))
11605
11606 ;;; ----------------------------------------------------------------------
11607 ;;;
11608 (defun tinypgp-nymserver-help-i-args (arg)
11609   "Ask args for `tinypgp-nymserver-help' using ARG."
11610   (list
11611    (tinypgp-nymserver-ask)
11612    arg))
11613
11614 ;;; ----------------------------------------------------------------------
11615 ;;;
11616 (defun tinypgp-nymserver-help-verbose (&optional arg)
11617   "Call `tinypgp-nymserver-help' as interactive would with ARG."
11618   (let* ((a (tinypgp-nymserver-help-i-args arg)))
11619     (tinypgp-nymserver-help (nth 0 a) (nth 1 a))))
11620
11621 ;;; ----------------------------------------------------------------------
11622 ;;;
11623 (defun tinypgp-nymserver-help (alias &optional mail-req verb)
11624   "Print help or send the help request via mail.
11625
11626 Input:
11627   ALIAS             ,from where to ask the help file.
11628   MAIL-REQ          ,send mail request [current-prefix-arg]
11629   VERB              ,verbose messages"
11630   (interactive  (tinypgp-nymserver-help-i-args current-prefix-arg))
11631   (let* ((elt   (assoc alias tinypgp-:nymserver-account-table))
11632          (file  (or (nth 5 elt) "_#_#")))
11633     (ti::verb)
11634     (cond
11635      (mail-req
11636       (tinypgp-nymserver-sendmail 'help alias verb))
11637      (t
11638       (cond
11639        ((file-exists-p file)
11640         (pop-to-buffer (find-file-noselect file)))
11641
11642        ((not (file-exists-p file))
11643         (error "TinyPgp: File not exists %s" file))
11644
11645        (t
11646         (message "No HELP file defied in tinypgp-:nymserver-account-table")
11647         (sit-for 2)
11648         (message " You get the help file, when you create account.")))))))
11649
11650 ;;}}}
11651
11652 ;;{{{ misc: ask
11653
11654 ;;; ........................................................... &r-ask ...
11655
11656 ;;; ----------------------------------------------------------------------
11657 ;;;
11658 (defun tinypgp-ask-reply-block-remailer (&optional msg)
11659   "Ask which remailer's reply block to use. Return remailer.
11660 References:
11661    `tinypgp-:r-reply-block-tab.le'"
11662   (or tinypgp-:r-reply-block-table
11663       (error "TinyPgp tinypgp-:r-reply-block-table is empty."))
11664   (completing-read
11665    (or msg "Select Reply block of remailer: ")
11666    (ti::list-to-assoc-menu (mapcar 'car tinypgp-:r-reply-block-table))
11667    nil
11668    'match))
11669
11670 ;;; ----------------------------------------------------------------------
11671 ;;;
11672 (defun tinypgp-ask-remailer (&optional msg)
11673   "Select REMAILER with optional MSG."
11674   (let* (list)
11675     (tinypgp-r-init-maybe)
11676     (unless (setq list
11677                   (ti::list-to-assoc-menu
11678                    (mapcar 'car tinypgp-:r-host-table)))
11679       (error "TinyPgp Internal error, tinypgp-:r-host-table is nil."))
11680     (completing-read
11681      (or msg "Select remailer: ")
11682      list
11683      nil 'match
11684      nil
11685      'tinypgp-:r-history)))
11686
11687 ;;; ----------------------------------------------------------------------
11688 ;;;
11689 (defun tinypgp-ask-email-keyserver (&optional msg)
11690   "Ask which email keyserver to use using MSG."
11691   (tinypgp-alias2name
11692    (completing-read
11693     (or msg "Email key server: ")
11694     (ti::list-to-assoc-menu (mapcar 'car tinypgp-:keyserver-mail-table))
11695     nil
11696     'match-it
11697     (car (car tinypgp-:keyserver-mail-table)))
11698    tinypgp-:keyserver-mail-table))
11699
11700 ;;; ----------------------------------------------------------------------
11701 ;;;
11702 (defun tinypgp-ask-http-keyserver ()
11703   "Ask which http keyserver to use. Return keyserver elt."
11704   (let* (elt)
11705     (setq
11706      elt
11707      (assoc
11708       (completing-read
11709        "Key server: "
11710        (ti::list-to-assoc-menu (mapcar 'car tinypgp-:keyserver-http-table))
11711        nil 'match
11712        (or (tinypgp-hash 'keyserver 'get 'used nil 'global) ;; last used
11713            (car (car tinypgp-:keyserver-http-table))) ;; or first in list
11714        'tinypgp-:history-http-keyserver)
11715       tinypgp-:keyserver-http-table))
11716
11717     ;;  Remember the last used keyserver
11718     ;;
11719     (tinypgp-hash 'keyserver 'put 'used (car-safe elt) 'global)
11720     (tinypgp-hash 'keyserver 'put 'elt elt 'global)
11721     elt))
11722
11723 ;;; ----------------------------------------------------------------------
11724 ;;;
11725 (defun tinypgp-ask-remail-args (&optional msg)
11726   "Ask remail arguments for REMAILER with crypt key ask MSG.
11727 Return:
11728  '(remailer-elt latent key)"
11729   (let (remailer
11730         remailer-elt
11731         latent
11732         key)
11733
11734     (setq remailer (tinypgp-ask-remailer))
11735     (setq remailer-elt (tinypgp-r-elt-remailer remailer))
11736
11737     (if (string-match "ek" (nth 2 remailer-elt)) ;Supports this ?
11738         (if (ti::nil-p
11739              (setq
11740               key (read-from-minibuffer
11741                    "Use crypt key: ")))
11742             (setq key nil)))
11743
11744     (if (string-match "latent" (nth 2 remailer-elt))
11745         (cond
11746          ((ti::nil-p
11747            (setq
11748             latent (read-from-minibuffer
11749                     "Latent time e.g. +0:00r [empty = no latent]: ")))
11750           (setq latent nil))
11751          (t                             ;Some checkings
11752           (setq latent (ti::string-remove-whitespace latent))
11753           (or (string-match "^\\+[0-9]:[0-9][0-9]r?$" latent)
11754               (error "TinyPgp: Invalid latent time format '%s'" latent)))))
11755     (list remailer-elt  latent key)))
11756
11757 ;;; ----------------------------------------------------------------------
11758 ;;;
11759 (defun tinypgp-i-args-decrypt ()
11760   "Ask suitable decrypt password and return decrypt type.
11761 This function tries to determine if it should ask conventional password of
11762 pgp password by looking at the pgp stream.
11763
11764 Return:
11765   string            decrypt-type"
11766   (let* ((fid       "tinypgp-i-args-decrypt: ")
11767          (c-point   (ti::mail-pgp-encrypted-p))
11768          (tlist     (ti::list-to-assoc-menu '("pgp" "base64" "conventional")))
11769          (type      "pgp")
11770          var-sym)
11771     (tinypgpd fid c-point)
11772
11773     (unless c-point
11774       ;;  couldn't find "Encrypted: PGP" tag, ask type then
11775       ;;
11776       (setq type
11777             (and tinypgp-:pgp-encrypted-p-function
11778                  (funcall tinypgp-:pgp-encrypted-p-function)))
11779
11780       ;;  See if the type was set to sensible value. Ask from
11781       ;;  user if it wasn't
11782       ;;
11783       (if (or (not (stringp type))
11784               (not (assoc type tlist)))
11785           (setq type (completing-read
11786                       "Decrypt type: " tlist nil 'match "pgp"))))
11787
11788     (cond
11789      ((string= type "conventional")
11790       (setq var-sym type)
11791       (ti::vector-table-get  tinypgp-:hash-password var-sym 'allocate)
11792       (ti::vector-table-property
11793        tinypgp-:hash-password var-sym 'password nil 'force)
11794       (tinypgp-password-set nil 'conventional))
11795
11796      ((string= type "pgp")
11797       (tinypgp-save-state-macro
11798        (tinypgp-user-change-macro
11799         ;;  Now We are right user to ask the PGP pass phrase
11800         ;;
11801         (tinypgp-ask-pass-phrase-decrypt)))))
11802     type))
11803
11804 ;;}}}
11805 ;;{{{ PGP entry i-macros
11806
11807 ;;; ........................................................ &i-macros ...
11808 ;;; functions that are normally used in (interactive) spec.
11809 ;;;
11810
11811 ;;; ----------------------------------------------------------------------
11812 ;;;
11813 (defun tinypgp-i-args-read-email
11814   (&optional barf-if-not-email-buffer prompt history-sym)
11815   "Read email addresses from buffer or ask from use with completion.
11816
11817 Input:
11818
11819  BARF-IF-NOT-EMAIL-BUFFER   as name says
11820  PROMPT                     display this string
11821  HISTORY-SYM                use this history"
11822   (let* ((fid  "tinypgp-i-args-read-email:")
11823          to-field
11824          ret
11825          init
11826          tmp)
11827
11828     (tinypgpd fid "in: " barf-if-not-email-buffer prompt)
11829
11830     (if (and barf-if-not-email-buffer
11831              (not (ti::mail-mail-p)))
11832         (error "TinyPgp: This is not an mail buffer."))
11833
11834     (or tinypgp-:pgp-email-list-completions ;make sure this exist
11835         (tinypgp-update-mail-abbrevs))
11836
11837     (cond
11838      ((and (string-match "news\\|message\\|mail" (symbol-name  major-mode))
11839            (not (ti::nil-p
11840                  (mail-fetch-field      "To")))) ;Just check this
11841
11842       (setq to-field (ti::mail-get-all-email-addresses
11843                       nil
11844                       tinypgp-:pgp-email-abbrev-list))
11845
11846       (tinypgpd fid "cond1: to-field" to-field)
11847
11848       ;;  Slim down "Mr. ABC <abc@com>" --> "abc@com"
11849       ;;
11850       (setq to-field
11851             (mapcar
11852              (function
11853               (lambda (x)
11854                 (ti::string-remove-whitespace
11855                  (ti::remove-properties (tinypgp-email-or-string x)))))
11856              to-field))
11857
11858       (setq ret to-field)
11859
11860       ;;   Confirm only if there is multiple recipients
11861       ;;   07.03.97 I have disbled the confimation with 'and'.
11862       ;;
11863       (if (> (length to-field) 1)
11864           (and
11865            nil
11866            (ti::read-char-safe-until
11867             (format "%d email recipients found. Press to continue."
11868                     (length to-field))))
11869         ;;  See if point in on line that has email
11870         ;;
11871         (when
11872             (setq
11873              tmp
11874              (car-safe (ti::mail-email-from-string
11875                         (ti::remove-properties (ti::read-current-line)))))
11876           (push tmp to-field)
11877           (setq tmp
11878                 (completing-read
11879                  "You were on email line, use it? [empty=skip]: "
11880                  (ti::list-to-assoc-menu to-field) nil nil
11881                  tmp))
11882
11883           (if (not (ti::nil-p tmp))
11884               (setq ret tmp)))))
11885
11886      (t
11887       (setq init
11888             (ti::string-remove-whitespace
11889              (or (ti::mail-get-field "Request-Remailing-To" 'any)
11890                  (ti::mail-get-field "Anon-To" 'any)
11891                  tinypgp-:user-now)))
11892
11893       (tinypgpd fid "cond t: ")
11894       (setq
11895        ret
11896        (completing-read
11897         (or prompt "User: ")
11898         tinypgp-:pgp-email-list-completions
11899         nil nil
11900         init
11901         (or history-sym
11902             'tinypgp-:history-email)))
11903       (setq ret (tinypgp-email-or-string ret))
11904       (if ret
11905           (setq ret (ti::string-remove-whitespace ret)))))
11906
11907     (tinypgpd fid "hook call: " ret)
11908
11909     (setq ret (tinypgp-key-id-conversion ret))
11910
11911     (tinypgpd fid "RET: " ret)
11912
11913     ret))
11914
11915 ;;; ----------------------------------------------------------------------
11916 ;;;
11917 (defun tinypgp-i-args-pass-phrase (&optional msg)
11918   "The MSG defaults to asking signing pass phrase."
11919   (tinypgp-password-set
11920    (format "[%s] %s"
11921            (or tinypgp-:user-now
11922                (error "TinyPgp Internal error: current pgp user unknown."))
11923            (or msg
11924                "Sign pass phrase: "))))
11925
11926 ;;; ----------------------------------------------------------------------
11927 ;;;
11928 (defun tinypgp-ask-pass-phrase-decrypt ()
11929   "See `tinypgp-i-args-pass-phrase'."
11930   (tinypgp-i-args-pass-phrase "Decrypt pass phrase: "))
11931
11932 ;;; ----------------------------------------------------------------------
11933 ;;;
11934 (defun tinypgp-i-args-reg-email (&optional prompt barf-not-mail-buffer)
11935   "Read region + String. PROMPT BARF-NOT-MAIL-BUFFER."
11936   (ti::i-macro-region-body
11937     (tinypgp-i-args-read-email barf-not-mail-buffer)))
11938
11939 ;;}}}
11940 ;;{{{ PGP entry command macros, email,exe
11941
11942 ;;; ----------------------------------------------------------------------
11943 ;;;
11944 (put 'tinypgp-cmd-macro-email 'lisp-indent-function 1)
11945 (defmacro tinypgp-cmd-macro-email (message &rest body)
11946   "(MESSAGE &rest BODY). Select email body or whole buffer.
11947
11948 You must locally define variable `beg' `end' in let statement
11949 before using this macro."
11950   (`
11951    (cond
11952     ((or (ti::mail-text-start)
11953          (progn
11954            ;;  The region is defined beforehand, now.
11955            ;;
11956            (setq beg (point-min)  end (point-max))
11957            (y-or-n-p
11958             (format "Not a mail buffer, %s whole buffer? "
11959                     (or (, message) "Use")))))
11960      (,@ body)))))
11961
11962 ;;; ----------------------------------------------------------------------
11963 ;;;
11964 (put 'tinypgp-cmd-macro 'lisp-indent-function 3)
11965 (defmacro tinypgp-cmd-macro
11966   (cmd user password &optional msg reg options mode-specific &rest body)
11967   "Common command macro for all PGP commands.
11968 Macro, used to contruct user command. CMD and USER must be
11969 variables. You must bound 'beg' and 'end' variables before calling this
11970 macro.
11971
11972 Args:
11973
11974   (cmd user password &optional msg reg options &rest body mode-specific)
11975
11976 Input:
11977
11978   CMD USER PASSWORD     parameters. CMD is symbol for logical command
11979
11980   MSG                   message shown to user before initiating command
11981
11982   REG                   non-nil = put results to register instead
11983                         of replacing the region with pgp output.
11984
11985   OPTIONS               extra switched that are added to the pgp command.
11986
11987   MODE-SPECIFIC         If non-nil, Do not run mode specific actions.
11988
11989   BODY                  code to execute when real pgp command is known.
11990                         If there is no body, then execute the command
11991                         that is found from table.
11992
11993                         Body must assign the result of command to
11994                         macro variable 'ReS'
11995
11996                         The default command executed in macro is, where
11997                         Rcmd is the real shell command. However the
11998                         command can still contains macros that start
11999                         like #MACRONAME.
12000
12001                         (tinypgp-binary-do-command-region Rcmd beg end msg (, reg))
12002
12003 Hooks:
12004   `tinypgp-before-do-cmd-region-hook'
12005   `tinypgp-after-do-cmd-region-hook'"
12006   (`
12007    (let* ((FiD   "tinypgp-cmd-macro: ")
12008           (Rcmd  (tinypgp-binary-get-cmd (, cmd) (, options))) ;Real command
12009           (enter-buffer (current-buffer))
12010           (msg   (if (or verb (interactive-p))
12011                      (, msg)))
12012           edit-buffer
12013           ReS
12014           beg-mark
12015           end-mark)
12016
12017      ;;  VM: edit mode changes the current buffer
12018      ;;  Gnus: sometimes we must clone the buffer (nntp doesn't allow edit)
12019
12020      (unless (, mode-specific)
12021        (tinypgp-mode-specific-control-before
12022         (, cmd) (, user)  msg (, reg)))
12023
12024      (tinypgpd FiD "in:" enter-buffer
12025                beg end
12026                "CMD" (, cmd)
12027                "USER" (, user)
12028                "pass" (, password)
12029                msg
12030                "register" (, reg)
12031                "MODE-SPEC" (, mode-specific))
12032
12033      (setq edit-buffer (current-buffer))
12034      (tinypgpd FiD "EDIT-BUFFER" major-mode edit-buffer)
12035
12036      ;; .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. . setting markers ..
12037      (cond
12038       ((eq (, cmd) 'decrypt)
12039        (setq ReS (save-excursion (ti::pmin) (ti::mail-pgp-block-area 'msg)))
12040        (goto-char (or
12041                    ;;  This checks "encrypted: PGP" tag.
12042                    (ti::mail-pgp-encrypted-p)
12043                    ;;  Nope, there was none, use this.
12044                    ;;
12045                    (car ReS)))
12046
12047        (setq beg-mark (point-marker))
12048        (goto-char (cdr ReS)) (setq end-mark (point-marker))
12049        (tinypgpd FiD "DECRYPT marks" beg-mark end-mark)
12050        (setq ReS nil))
12051       (t
12052        ;;   If user hasn't set END variable, we suppose
12053        ;;   rest of the buffer. It is important that END variable
12054        ;;   gets set here when MAIL message is handled, because
12055        ;;   only now the message is trimmed and whitespaces
12056        ;;   removed
12057        ;;
12058        (if (null end)
12059            (setq end (point-max)))
12060
12061        (if (null beg)
12062            (setq beg (if (ti::mail-mail-p)
12063                          (ti::mail-text-start)
12064                        (point-min))))
12065
12066        ;;  We use markers, because hook is called and it
12067        ;;  may change the buffer content. The area must still be
12068        ;;  available for us after changes.
12069        ;;
12070        (save-excursion
12071          (goto-char beg) (setq beg-mark (point-marker))
12072          (goto-char end) (setq end-mark (point-marker)))))
12073
12074      (tinypgpd FiD "BEG END" beg end "MARKER-BEGIN" beg-mark end-mark
12075                (current-buffer))
12076      (tinypgpd FiD (buffer-substring beg-mark end-mark))
12077
12078      ;; .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. . user funcall ..
12079
12080      (if tinypgp-:cmd-macro-before-hook
12081          (run-hook-with-args-until-success 'tinypgp-:cmd-macro-before-hook
12082                                            (, cmd) (, user) msg (, reg)))
12083
12084      ;; .. .. .. .. .. .. .. .. .. .. .. .. .. .. ..  checking markers ..
12085
12086      (if (or (null (setq beg (marker-position beg-mark)))
12087              (null (setq end (marker-position end-mark)))
12088              (eq beg end))              ;This is error too.
12089          (error "\
12090 TinyPgp: tinypgp-:cmd-macro-before-hook modified text too much."))
12091
12092      (setq beg-mark nil end-mark nil)   ;kill the markers
12093
12094      (if ReS (setq ReS nil))            ;NoOp XE ByteComp silencer
12095
12096      (if (null (, user))
12097          (setq (, user) (user-login-name)))
12098
12099      ;; .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. . make command ..
12100
12101      (setq Rcmd (tinypgp-cmd-compose Rcmd (, user) ))
12102
12103      (tinypgpd FiD "vars:" "USER" (, user)
12104                "CUR-BUF" (current-buffer) beg end
12105                "CMD" Rcmd
12106                "BODY-NIL" (equal 'nil (quote (, body))))
12107
12108 ;;;     (ti::d! "Doing COMMAND" beg end (current-buffer))
12109
12110      ;; .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. . DO ACTION ..
12111      ;;     Check if BODY is omitted
12112
12113      (cond
12114       ((equal 'nil (quote (, body)))
12115        (setq
12116         ReS
12117         (if (or (tinypgp-backend-pgp2-p)
12118                 (tinypgp-backend-gpg-p))
12119             (tinypgp-binary-do-command-region
12120              Rcmd
12121              beg
12122              end
12123              (tinypgp-hash 'mode-specific 'get 'buffer-edit nil 'global)
12124              msg
12125              (, reg))
12126           (tinypgp-binary-do-command-region-with-expect
12127            Rcmd
12128            beg end
12129            (tinypgp-hash 'mode-specific 'get 'buffer-edit nil 'global)
12130            msg
12131            (, reg)))))
12132
12133       (t
12134        (,@ body)))
12135
12136      (tinypgp-binary-header-field-fix (, cmd) 'force)
12137
12138      ;; .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. ..  results ..
12139 ;;;     (setq PTR ReS)
12140
12141      (when (, reg)                      ;Save results
12142        (set-register
12143         tinypgp-:register
12144         (tinypgp-binary-get-result-as-string ReS)))
12145
12146      (tinypgpd FiD "cmd-macro done. calling mode specific...")
12147
12148      (if tinypgp-:cmd-macro-after-hook
12149          (run-hook-with-args-until-success 'tinypgp-:cmd-macro-after-hook
12150                                            (, cmd) (, user) msg (, reg)))
12151
12152      (tinypgpd "cmd-macro out:")
12153      ReS)))
12154
12155 ;;}}}
12156 ;;{{{ PGP exe command compose
12157
12158 ;;; ................................................. &command-compose ...
12159
12160 ;;; ----------------------------------------------------------------------
12161 ;;;
12162 (defun tinypgp-cmd-compose (cmd user &optional password args)
12163   "Compose PGP command.
12164
12165 Input:
12166
12167   CMD       list of strings which may contain #TAGS
12168             '(binary base-command-set options)
12169   USER
12170   PASSWORD
12171   ARGS"
12172   (let* ((cat  (if (eq (tinypgp-backend-type) 'win32)
12173                    "type "
12174                  "cat "))
12175          (binary-type (tinypgp-backend-type))
12176          (binary      (car cmd))
12177          tmp)
12178
12179     (setq cmd (format "%s %s" (nth 1 cmd) (or (nth 2 cmd) "")))
12180
12181     ;;  Decide where to put the binary itself. Is there a token #bin
12182     ;;  where to put it?
12183
12184     (cond
12185      ((string-match "#bin" cmd)
12186       (setq cmd (ti::replace-match 0 binary cmd)))
12187      (t
12188       (setq cmd (concat binary " " cmd))))
12189
12190     (if tinypgp-:pgp-command-compose-function
12191         (setq cmd (funcall tinypgp-:pgp-command-compose-function cmd)))
12192
12193     (tinypgpd "[cmd-compose] in: USER"
12194               tinypgp-:user-now "PRING" tinypgp-:pubring-now)
12195
12196     (tinypgpd "[cmd-compose] in: cmd"
12197               cmd "USER" user "PASS" password )
12198
12199     (unless (stringp tinypgp-:pubring-now)
12200       (error "TinyPgp: no current pubring? tinypgp-:pubring-now"))
12201
12202     (unless (file-exists-p tinypgp-:pubring-now)
12203       (error "TinyPgp: %s (tinypgp-:pubring-now) does not exist."))
12204
12205     (tinypgpd "[cmd-compose] in2: global user, pring"
12206               tinypgp-:user-now tinypgp-:pubring-now )
12207
12208     (unless (stringp tinypgp-:user-now) ;;  make sure this variable exists
12209       (error "TinyPgp: user is unknown."))
12210
12211     (when (string-match "#PUBRING" cmd)
12212       (setq cmd (ti::replace-match
12213                  0
12214                  (concat "+pubring="
12215                          (tinypgp-expand-file-name
12216                           tinypgp-:pubring-now binary-type)
12217                          " ")
12218                  cmd)))
12219
12220     (when (string-match "#PGP-USER" cmd)
12221       (setq cmd (ti::replace-match
12222                  0 (concat
12223                     "-u \""
12224                     ;; Always treat this as list
12225                     (ti::list-to-string (ti::list-make tinypgp-:user-now))
12226                     "\" ")
12227                  cmd)))
12228
12229     (when (and user
12230                (string-match "#USER" cmd))
12231
12232       ;;  With PGP 2: -u "user"
12233       ;;  With pgp 5: -u user
12234
12235       (setq tmp (if (or (tinypgp-backend-pgp2-p)
12236                         (tinypgp-backend-gpg-p))
12237                     "\""
12238                   ""))
12239       (setq cmd (ti::replace-match
12240                  0 (concat "-u " tmp
12241                            ;; Always treat this as list
12242                            (ti::list-to-string (ti::list-make user ))
12243                            tmp " ")
12244                  cmd)))
12245
12246     (when (string-match "#OUT-FILE" cmd)
12247       (setq cmd (ti::replace-match
12248                  0
12249                  (concat "-o "
12250                          (tinypgp-expand-file-name
12251                           tinypgp-:file-output binary-type)
12252                          " ")
12253                  cmd)))
12254
12255     (when (and user
12256                (string-match "#MUSER" cmd))
12257       (cond
12258        ((tinypgp-backend-pgp2-p)
12259         (let ((type (save-match-data (tinypgp-binary-get-version 'symbol))))
12260           (cond
12261            ((eq type 'international)
12262             (setq cmd
12263                   (ti::replace-match
12264                    0
12265                    (concat
12266                     "-@"
12267                     (tinypgp-expand-file-name
12268                      tinypgp-:file-user-list binary-type)
12269                     " ")
12270                    cmd)))
12271            (t                           ;doesn't know -@ switch
12272             (setq cmd
12273                   (ti::replace-match
12274                    0
12275                    (format "`%s %s`"
12276                            cat
12277                            (tinypgp-expand-file-name
12278                             tinypgp-:file-user-list binary-type))
12279                    cmd))))
12280           (tinypgp-file-control 'users-write user)))
12281        (t ;; pgp 5.x
12282         (setq tmp "")
12283         (dolist (elt user)
12284           (setq tmp (concat tmp " -r " elt)))
12285
12286         (setq cmd (ti::replace-match 0 tmp cmd))
12287         (tinypgpd "[cmd-compose] #MUSER" user cmd))))
12288
12289     ;; ........................................................... other ...
12290     ;; These are called from tinypgp-binary-do-command-region when parameters
12291     ;; are better known.
12292
12293     (when (and args (string-match "#PIPE" cmd))
12294       ;; REST ARGS 1 = pipe file
12295       ;;
12296       (setq cmd (ti::replace-match
12297                  0
12298                  (concat cat
12299                          (tinypgp-expand-file-name
12300                           (or (nth 0 args)
12301                               tinypgp-:file-source)
12302                           binary-type)
12303                          " | ")
12304                  cmd)))
12305
12306     (when (string-match "#SOURCE-FILE" cmd)
12307       (let ((file (or (nth 0 args)
12308                       tinypgp-:file-source)))
12309         ;; ARGS = filename
12310         ;;
12311         (setq cmd (ti::replace-match
12312                    0
12313                    (concat " "
12314                            (tinypgp-expand-file-name file binary-type)
12315                            " ")
12316                    cmd))))
12317
12318     ;; .......................................................... password ...
12319
12320     (when (string-match "#password" cmd)
12321       (when (ti::nil-p password)
12322         (setq password (tinypgp-password-get)))
12323
12324       (when (null password)
12325         (error
12326          "TinyPgp Internal error: Command composing failed. No passwd."))
12327
12328       (when (tinypgp-backend-gpg-p)
12329         (setq cmd (ti::replace-match
12330                    0
12331                    (concat "\""  password "\" | ") cmd)))
12332
12333       (when (tinypgp-backend-pgp2-p)
12334         (if (or nil                     ;Enabled now!
12335                 (null tinypgp-:password-protection))
12336             (setq cmd (ti::replace-match
12337                        0
12338                        (concat "-z\""  password "\" ") cmd))
12339
12340           (setq cmd (ti::replace-match 0 nil cmd))
12341           (tinypgp-file-control 'password-write password)
12342
12343           ;;  PGP gets the password from file descriptor 3. This way
12344           ;;  'ps' listing doesn't show the password like it does
12345           ;;  with -z option
12346           ;;
12347           (setq cmd (format (concat "PGPPASSFD=3; export PGPPASSFD; "
12348                                     " #PIPE %s  3< %s ")
12349                             cmd
12350                             (tinypgp-expand-file-name
12351                              tinypgp-:file-password binary-type))))))
12352
12353     (tinypgpd "[cmd-compose] out: "
12354               cmd  tinypgp-:pgp-command-compose-function )
12355
12356     cmd))
12357
12358 ;;}}}
12359 ;;{{{ PGP exe result, general, macros, error
12360
12361 ;;; ........................................................ &pgp-core ...
12362
12363 ;;; ----------------------------------------------------------------------
12364 ;;;
12365 (defun tinypgp-binary-header-field-set (field value)
12366   "Set FIELD with VALUE in PGP Signature header."
12367   (ti::pmax)
12368   (when (or (re-search-backward (ti::mail-pgp-signature-begin-line) nil t)
12369             (re-search-backward (ti::mail-pgp-msg-begin-line) nil t))
12370     (tinypgpd "tinypgp-binary-header-field-set: " field value)
12371     (cond
12372      ((re-search-forward field nil t)
12373       (delete-region (point) (line-end-position))
12374       (insert " " value)
12375       (forward-line 1))
12376      ((re-search-forward "^[ \t]*$")    ;Must exist
12377       (insert field " " value "\n")))))
12378
12379 ;;; ----------------------------------------------------------------------
12380 ;;;
12381 (defun tinypgp-binary-header-field-fix (command &optional force)
12382   "Change PGP headers for COMMAND. Optionally FORCE in spite of backend.
12383 In Windows NT not all the command line options cannot passed
12384 with the call, so we patch resulte manually."
12385   (when (and (or force
12386                  (ti::win32-p)
12387                  (not (tinypgp-backend-pgp2-p)))
12388              (ti::re-search-check (ti::mail-pgp-signature-begin-line)))
12389     (save-excursion
12390       (let* ((comment
12391               (get 'tinypgp-:pgp-binary-interactive-option 'comment)))
12392         (when (eq command 'sign)
12393           ;; (tinypgp-binary-header-field-set "Charset:" tinypgp-:pgp-binary-charset)
12394           (if comment
12395               (tinypgp-binary-header-field-set "Comment:" comment)))))))
12396
12397 ;;; ----------------------------------------------------------------------
12398 ;;;
12399 (put 'tinypgp-excute-in-tmp 'lisp-indent-function 2)
12400 (defmacro tinypgp-excute-in-tmp (beg end &rest body)
12401   "Copy region BEG END from current buffer and execute BODY.
12402 Uses buffer `tinypgp-:buffer-tmp-shell'."
12403   (`
12404    (let* ((ob  (current-buffer))
12405           (tmp (tinypgp-ti::temp-buffer 'shell)))
12406      (with-current-buffer tmp
12407        (insert-buffer-substring ob (, beg) (, end))
12408        (tinypgp-x-headers-deinstall)
12409        (,@ body)))))
12410
12411 ;;; ----------------------------------------------------------------------
12412 ;;;
12413 (defsubst tinypgp-binary1-command-table (cmd)
12414   "Return right command table"
12415   (cond
12416    ((eq 'pgp2 (tinypgp-backend-now))
12417     (assq cmd tinypgp-:pgp-command-table))
12418    ((eq 'gpg (tinypgp-backend-now))
12419     (assq cmd tinypgp-:gpg-command-table))
12420    (t
12421     (assq cmd tinypgp-:pgp-command-table5))))
12422
12423 ;;; ----------------------------------------------------------------------
12424 ;;; http://www.pgpi.org/products/pgp/versions/freeware/
12425 ;;; => Unix => PGP 2.6.3i => Download PGP 2.6.3i
12426 ;;; => Download PGP 2.6.3i source code
12427 ;;;
12428 ;;; Win32/Cygwin compile command:
12429 ;;;
12430 ;;; cd /tmp
12431 ;;; gzip -dc pgp263is.tar.gz | tar -xvf
12432 ;;; tar -xvf pgp263ii.tar
12433 ;;; cd src/
12434 ;;; make -f makefile CFLAGS='-DUNIX -DPORTABLE' CC=gcc linux
12435 ;;;
12436 (defun tinypgp-binary-path-set (&optional verb)
12437   "Define backend properties in variable `tinypgp-:pgp-binary'.
12438
12439 This function stores the executable paths in variable
12440 `tinypgp-:pgp-binary'."
12441   (interactive)
12442   (let  ((fid   "tinypgp-binary-path-set: ")
12443          (list  '("pgpk" "pgpv" "pgpe" "pgps"))
12444          (ext    (if (ti::win32-p)
12445                      ".exe"
12446                    ""))
12447          (cygwin-root (ti::win32-cygwin-p))
12448          (search (delete "." exec-path))
12449          (count  0)
12450          exe
12451          str
12452          path)
12453
12454     (ti::verb)
12455
12456     ;; Clear all first
12457
12458     (dolist (sym '(pgp-set
12459                    pgp
12460                    pgp2-type
12461                    pgp5-type
12462                    gpg-type
12463                    gpg
12464                    pgpk pgpv pgpo pgpe))
12465       (put 'tinypgp-:pgp-binary sym nil))
12466
12467     ;; ......................................................... 2.6.x ...
12468
12469     (cond
12470      ((setq path (ti::file-get-load-path (concat "pgp" ext) search 'all))
12471       (dolist (bin (ti::list-make path))
12472
12473         ;;  Is this really 2.6.x? The PGP 5.x kit may contain binary
12474         ;;  "pgp" too
12475
12476         (setq str (ti::mail-pgp-exe-version-string bin))
12477         (tinypgpd fid "Verifying 2.6" bin  str)
12478
12479         (when (stringp str)
12480           (cond
12481            ((string-match "2\\.6" str)
12482             (put 'tinypgp-:pgp-binary 'pgp bin)
12483             (put 'tinypgp-:pgp-binary 'pgp-backends '(pgp2))
12484
12485             ;;  It is impossible to say if the pgp.exe is Cygwin
12486             ;;  compiled or pure DOS version, because "pgp -h" gives
12487             ;;  identical message.
12488             ;;
12489             ;;  The cygwin status is needed, because it affects
12490             ;;  how file names are passed.
12491             ;;
12492             ;;  It is supposed that "cygwin version" WILL reside under
12493             ;;  Cygwin hierarchy. This test fails if user uses
12494             ;;  mount points that refer to external disks
12495
12496             (let* ((cygwin-p (and cygwin-root
12497                                   (string-match
12498                                    (ti::file-path-to-unix cygwin-root)
12499                                    (ti::file-path-to-unix bin))))
12500                    (type  (if (and (ti::win32-p)
12501                                    (not cygwin-p))
12502                               'win32
12503                             'unix)))
12504               (put 'tinypgp-:pgp-binary 'pgp2-type type))
12505             (return))
12506            (t
12507             (message "TinyPgp: `pgp' found but that's not 2.6 version"))))))
12508
12509      (verb
12510       (message "Tinypgp: Hm, no pgp 2.x binary found.")
12511       (sit-for 1)))
12512
12513     ;; ........................................................... GPG ...
12514
12515     (cond
12516      ((setq path (ti::file-get-load-path (concat "gpg" ext) search 'all))
12517       (dolist (bin (ti::list-make path))
12518
12519         (setq str (ti::mail-pgp-exe-version-string bin))
12520         (tinypgpd fid "Verifying GPG 1.x" bin  str)
12521
12522         (when (stringp str)
12523           (cond
12524            ((string-match "1\\." str)
12525             (put 'tinypgp-:pgp-binary 'gpg bin)
12526             (put 'tinypgp-:pgp-binary
12527                  'pgp-backends
12528                  (append '(gpg) (tinypgp-backend-list)))
12529
12530             ;;  It is impossible to say if the gpg.exe is Cygwin
12531             ;;  compiled or pure DOS version, because "pgp -h" gives
12532             ;;  identical message.
12533
12534             (let* ((cygwin-p (and cygwin-root
12535                                   (string-match
12536                                    (ti::file-path-to-unix cygwin-root)
12537                                    (ti::file-path-to-unix bin))))
12538                    (type  (if (and (ti::win32-p)
12539                                    (not cygwin-p))
12540                               'win32
12541                             'unix)))
12542               (put 'tinypgp-:pgp-binary 'gpg-type type))
12543             (return))
12544            (t
12545             (message "TinyPgp: `gpg' found but that's not 1.x version"))))))
12546
12547      (verb
12548       (message "Tinypgp: Hm, no gpg 1.x binary found.")
12549       (sit-for 1)))
12550
12551     ;; ........................................................... 5.x ...
12552
12553     (dolist (bin list)
12554       (setq exe  (concat bin ext)
12555             path (ti::file-get-load-path exe search 'all))
12556       (cond
12557        ((null path)
12558         (when verb
12559           (message "TinyPgp: Can't find PGP[56] executable %s:%s" exe search))
12560         (tinypgpd fid "Verifying 5.x FAILED" exe path))
12561        (path
12562         (dolist (binary (ti::list-make path))
12563
12564           ;;  #todo: what should be done to multiple occurrances of BIN?
12565
12566           (tinypgpd fid "Verifying 5.x" binary)
12567           (incf count)
12568           (put 'tinypgp-:pgp-binary (intern bin) binary)))))
12569
12570     ;;  if all pgp 5.x executables were found; then installation went okay
12571
12572     (when (eq count 4)
12573       (setq    list (tinypgp-backend-list))
12574       (add-to-list 'list 'pgp5)
12575       (put     'tinypgp-:pgp-binary 'pgp-backends list))
12576
12577     (tinypgpd
12578      fid
12579      "count"     count
12580      "extension" ext
12581      "pgp-set"   (tinypgp-backend-list)
12582      "pgp"       (get 'tinypgp-:pgp-binary 'pgp)
12583      "pgpk"      (get 'tinypgp-:pgp-binary 'pgpk))
12584
12585     (if verb
12586         (message "Tinypgp: found %s"
12587                  (or
12588                   (and (tinypgp-backend-list)
12589                        (mapconcat
12590                         (function (lambda (elt) (symbol-name elt)))
12591                         (tinypgp-backend-list)
12592                         " "))
12593                   "(nothing)")))
12594
12595     (tinypgp-backend-list)))
12596
12597 ;;; ----------------------------------------------------------------------
12598 ;;;
12599 (defun tinypgp-backend-select (backend &optional verb)
12600   "Select BACKEND 'pgp2 or 'pgp5 executables for use. VERB."
12601   (interactive
12602    (let* ((list (mapcar
12603                  (function
12604                   (lambda (elt)
12605                     (cons
12606                      (symbol-name elt)
12607                      elt)))
12608                  (tinypgp-backend-list)))
12609           ret)
12610      (setq ret (completing-read "Select pgp: " list nil 'match))
12611      (list (cdr (assoc ret list)))))
12612
12613   (let* ((fid "tinypgp-backend-select: ")
12614          secring
12615          pubring)
12616
12617     (ti::verb)
12618
12619     ;;  Check that arg is part of known list
12620     (unless (member backend (tinypgp-backend-list))
12621       (error
12622        "\
12623 TinyPgp: Feature %s is not configured or available: Call tinypgp-binary-path-set"
12624        backend))
12625
12626     (put 'tinypgp-:pgp-binary 'pgp-now backend)
12627
12628     (setq secring (tinypgp-secring-file))
12629     (unless (file-exists-p secring)
12630       (error "\
12631 TinyPgp: Secring %s does not exist. See tinypgp-:file-secring %s" secring))
12632
12633     (setq pubring (tinypgp-pubring-default))
12634     (unless (file-exists-p pubring)
12635       (error
12636        "\
12637 TinyPgp: Can't find pubring %s. Check tinypgp-:pubring-table for backend %s"
12638        pubring
12639        backend))
12640
12641     (setq tinypgp-:pubring-now pubring)
12642
12643     ;; Each time backend is changed, the cache must be updated and
12644
12645     (tinypgp-key-cache-remove-entry-last)
12646     (setq tinypgp-:key-cache nil)
12647     (tinypgp-key-cache-save 'load)
12648
12649     (tinypgpd fid backend pubring secring)
12650     (tinypgp-update-modeline)
12651
12652     (if verb
12653         (message "Tinypgp: backend %s" (symbol-name backend)))
12654
12655     secring))
12656
12657 ;;; ----------------------------------------------------------------------
12658 ;;;
12659 (defun tinypgp-variable-state-control (&optional restore)
12660   "Save or RESTORE variables. Used when changing backends."
12661   (let* ((opt (get 'tinypgp-:pgp-binary-interactive-option 'original)))
12662     ;;  PGP 5.x doesn't know +comment option.
12663
12664     (cond
12665      (restore
12666       (setq tinypgp-:pgp-binary-interactive-option opt))
12667      (t
12668       (put 'tinypgp-:pgp-binary-interactive-option 'original
12669            tinypgp-:pgp-binary-interactive-option)
12670       (setq tinypgp-:pgp-binary-interactive-option nil)))))
12671
12672 ;;; ----------------------------------------------------------------------
12673 ;;;
12674 (defun tinypgp-backend-select-pgp2 ()
12675   "Select pgp 2.6.x backend"
12676   (interactive)
12677   (tinypgp-variable-state-control 'restore)
12678   (tinypgp-backend-select 'pgp2 (interactive-p)))
12679
12680 ;;; ----------------------------------------------------------------------
12681 ;;;
12682 (defun tinypgp-backend-select-pgp5  ()
12683   "Select pgp 5.x backend"
12684   (interactive)
12685   (tinypgp-variable-state-control)
12686   (tinypgp-backend-select 'pgp5 (interactive-p)))
12687
12688 ;;; ----------------------------------------------------------------------
12689 ;;;
12690 (defun tinypgp-backend-select-auto ()
12691   "Select pgp 2 if it exists else use pgp 5. Otherwise flag error."
12692   (let* ((list (get 'tinypgp-:pgp-binary 'pgp-backends)))
12693     (cond
12694      ((memq 'pgp2 list)
12695       (tinypgp-backend-select-pgp2))
12696      ((memq 'pgp5 list)
12697       (tinypgp-backend-select-pgp5))
12698      (t
12699       (error "\
12700 Check PATH for pgp executable(s): maybe tinypgp-binary-path-set failed.")))))
12701
12702 ;;; ----------------------------------------------------------------------
12703 ;;;
12704 (defun tinypgp-backend-set-for-action  (action &rest args)
12705   "Select right backend for ACTION.
12706 Action may be 'remail 'newnym  'nymserv or 'pgp
12707 Die if can't select right backend."
12708   (when (memq action '(remail newnym nymserv))
12709     (unless (tinypgp-backend-pgp2-p)
12710       (unless (tinypgp-backend-exist-pgp2)
12711         (error "Pgp 2 not available for Action %s" action))
12712       (tinypgp-backend-select-pgp2))))
12713
12714 ;;; ----------------------------------------------------------------------
12715 ;;;
12716 (defun tinypgp-binary1 (cmd)
12717   "Return right pgp executable for COMMAND type 'encrypt ...."
12718   (interactive)
12719   (let* (ret)
12720     (setq
12721      ret
12722      (cond
12723       ((tinypgp-backend-pgp2-p)
12724        (get 'tinypgp-:pgp-binary 'pgp))
12725
12726       ((tinypgp-backend-gpg-p)
12727        (get 'tinypgp-:pgp-binary 'gpg))
12728
12729       ((eq 'pgp5 (tinypgp-backend-now))
12730        (cond
12731         ((memq cmd '(sign
12732                      sign-detach))
12733          (get 'tinypgp-:pgp-binary 'pgps))
12734
12735         ((memq cmd '(encrypt
12736                      encrypt-sign
12737                      encrypt-info
12738                      crypt))
12739          (get 'tinypgp-:pgp-binary 'pgpe))
12740
12741         ((memq cmd '(decrypt
12742                      decrypt-base64))
12743          (get 'tinypgp-:pgp-binary 'pgpv))
12744
12745         ((eq cmd 'verify)
12746          (get 'tinypgp-:pgp-binary 'pgpv))
12747
12748         ((string-match "key" (symbol-name cmd))
12749          (get 'tinypgp-:pgp-binary 'pgpk))))))
12750
12751     (if (or (not (stringp ret))
12752             (not (file-exists-p ret)))
12753         (error "Install failure: Please run tinypgp-binary-path-set (%s)" cmd))
12754
12755     ;;  In WinNT the maximum command length is 255, so we can't
12756     ;;  afford to use absolute path here. (It would have been faster)
12757     ;;
12758
12759     (if (ti::win32-p)
12760         (file-name-nondirectory ret)
12761       ret)))
12762
12763 ;;; ----------------------------------------------------------------------
12764 ;;;
12765 (defun tinypgp-binary-get-cmd (cmd &optional options)
12766   "Return pgp shell command according to logical CMD with appended OPTIONS."
12767   (let* ((exe (tinypgp-binary1 cmd))
12768          (elt (tinypgp-binary1-command-table cmd)))
12769     (if (null elt)
12770         (error "PGP exe command error: No logical command in table '%s'" cmd)
12771       (list
12772        exe
12773        (nth 1 elt)
12774        options))))
12775
12776 ;;; ----------------------------------------------------------------------
12777 ;;;
12778 (defmacro tinypgp-binary-result-data-win32 (beg end)
12779   "Set result of PGP2 in WindowsNt shell buffer.
12780 In unix the output is printed so that 1)stderr 2)results
12781 but in Windows NT it could be printed in reverse order.
12782
12783 We check here if the data is put to the beginning of the buffer,
12784 before the PGP logo.
12785
12786 Variables BEG and END are modified if data starts from `point-min'."
12787   (`
12788    (progn
12789      ;;  1) If variables are both nil
12790      ;;  2) they are equal
12791      ;;
12792      (when (or (not (and (, beg) (, end)))
12793                (eq (, beg) (, end)))
12794        (save-excursion
12795          (ti::pmin)
12796          ;;   No configuration file found.
12797          ;;   \aPretty Good Privacy(tm) 2.6.3ia -
12798          ;;
12799          (when (and (re-search-forward
12800                      (concat
12801                       "^config.txt: \\|"
12802                       "^No configuration file found.$\\|"
12803                       "\C-g?Pretty Good Privacy(tm)")
12804                      nil t)
12805                     (prog1 t (beginning-of-line))
12806                     (not (eq (point) (point-min))))
12807            (setq beg (point-min) end (point))))))))
12808
12809 ;;; ----------------------------------------------------------------------
12810 ;;;
12811 (put 'tinypgp-binary-get-result-re1-macro 'lisp-indent-function 1)
12812 (defmacro tinypgp-binary-get-result-re1-macro (options &rest body)
12813   "If case-sensitive REGEXP match, execute BODY.
12814 The OPTIONS is a list containing an alist of options:
12815
12816 '((regexp  REGEXP)            - Search REGEXP
12817   (loop    [t|nil]))          - if LOOP is t, run while loop for REGEXP"
12818   (`
12819    (with-current-buffer tinypgp-:buffer-tmp-shell
12820      (let (case-fold-search             ;Case sensitive matching
12821            (re   (nth 1 (assq 'regexp (, options))))
12822            (loop (nth 1 (assq 'loop (, options)))))
12823        (ti::pmin)
12824        (when (re-search-forward re nil t)
12825          (if loop
12826              (while (re-search-forward re nil t)))
12827          (tinypgpd "exe-get-result-re1-macro:" (match-string 0) )
12828          (,@ body))))))
12829
12830 ;;; ----------------------------------------------------------------------
12831 ;;;
12832 (defsubst tinypgp-binary-insert-command-log (&optional point cmd)
12833   "Insert last command log into POINT[current point] or insert CMD."
12834   (if point (goto-char point))
12835
12836   (setq cmd
12837         (if cmd
12838             (prin1-to-string cmd)
12839           (prin1-to-string tinypgp-:last-pgp-exe-command)))
12840
12841   (insert "\n\nTinyPgp report, last command and parameters:\n\n"
12842
12843           "explicit-shell-file-name: "
12844           (or explicit-shell-file-name "<>") "\n"
12845
12846           "shell-file-name         : " (or shell-file-name "<>") "\n"
12847           "command length          : " (int-to-string (length cmd)) "\n\n"
12848
12849           cmd
12850
12851           "\n"))
12852
12853 ;;}}}
12854 ;;{{{ PGP exe result get,check
12855
12856 ;;; ----------------------------------------------------------------------
12857 ;;;
12858 (defun tinypgp-binary-check-error (&optional ignore-output-error cmd buffer)
12859   "Return non-nil, if the PGP output is not valid.
12860
12861 Input:
12862
12863   IGNORE-OUTPUT-ERROR   this skips checking the output: --- TAGS
12864   CMD                   command used
12865   BUFFER                Where the pgp output is
12866
12867 References:
12868   `tinypgp-:error'      stored error message"
12869   (let ( ;;  the re-ok does not produce re-block, but it's still valid
12870         ;;  pgp answer, not an error condition.
12871
12872         (fid                   "tinypgp-binary-check-error:" )
12873         (re-ok                 (concat
12874                                 "Good signature \\(from\\|made\\)"
12875                                 "\\|Bad signature from"
12876                                 "\\|Pass phrase +\\(is\\|appears\\) +good"
12877                                 "\\|WARNING: +"))
12878         (re-block              "-----BEGIN.*PGP")
12879         (re                    tinypgp-:pgp-binary-error-regexp)
12880         case-fold-search) ;; Case is important here !!
12881
12882     (or buffer
12883         (setq buffer tinypgp-:buffer-tmp-shell))
12884
12885     (setq tinypgp-:error nil)
12886
12887     ;;  - See if buffer DOES not contain ok sign, then GO AND
12888     ;;    check error. Once I have message where
12889     ;;    "You do not have the secret" was written in message body.
12890     ;;    and that was not an error condition.
12891
12892     (with-current-buffer buffer
12893       (unless (and (ti::re-search-check
12894                     "^Pass phrase is good.  Just a moment[.][.]+")
12895
12896                    ;;  Funny; The previous message is ouputted, but
12897                    ;;  if one pass encryption&sign fails; this is message
12898                    ;;  will be seen. Make3 sure we don't see it.
12899                    ;;
12900                    ;; Including "pgp-lst"...
12901                    ;; Pass phrase is good.  Just a moment....
12902                    ;; ^GKey matching userid 'a@b.if' not found
12903                    ;; in file '/aa7bb/ring-all.pgp'
12904                    ;;
12905                    ;; ^GCannot find the public key matching userid 'a@b.if'
12906                    ;; This user will not be able to decrypt this message.
12907                    ;; ^GEncryption error
12908
12909                    (null (ti::re-search-check "Encryption error$")))
12910         (tinypgp-binary-get-result-re1-macro (list (list 'regexp re))
12911                                              (tinypgpd fid "MB" (match-beginning 0) "ME" (match-end 0)
12912                                                        (current-buffer))
12913                                              (tinypgp-highlight 'match 0 nil tinypgp-:face-error nil
12914                                                                 (match-beginning 0)
12915                                                                 (match-end 0))
12916                                              (setq tinypgp-:error (ti::remove-properties (ti::read-current-line)))
12917                                              (tinypgp-binary-insert-command-log (point-max) cmd))))
12918
12919     (unless ignore-output-error
12920       (with-current-buffer buffer
12921         (when (and (null tinypgp-:error) ;Not already set?
12922                    (not (ti::re-search-check re-ok 0 '(point-min)))
12923                    (not (ti::re-search-check re-block 0 '(point-min))))
12924           (setq tinypgp-:error "Internal error. No output from PGP.")
12925           (tinypgp-binary-insert-command-log (point-max) cmd))))
12926
12927     ;;  If this was encryption and it failed, then remove entry from
12928     ;;  cache.
12929
12930     (if tinypgp-:error
12931         (tinypgp-key-cache-remove-entry tinypgp-:error))
12932
12933     (tinypgpd fid "RET" tinypgp-:error )
12934
12935     tinypgp-:error))
12936
12937 ;;; ----------------------------------------------------------------------
12938 ;;;
12939 (defun tinypgp-binary-get-result (&optional buffer)
12940   "Return the result of PGP output from BUFFER or `tinypgp-:buffer-tmp-shell'.
12941 Look for markers -----BEGIN PGP, -----END PGP.
12942 Return:
12943   '(buffer beg end)"
12944   (let* ((re1 "[.]*\\(-----BEGIN.*PGP\\)")
12945          (re2 "^-----END.*PGP")
12946          beg
12947          ret)
12948     (with-current-buffer (or buffer tinypgp-:buffer-tmp-shell)
12949       (ti::pmin)
12950       (when (re-search-forward re1 nil t)
12951         (setq beg (match-beginning 1))
12952         (ti::pmax)
12953         (when (re-search-backward re2 nil t)
12954           (setq ret (list (current-buffer) beg (line-end-position))))))
12955     (tinypgpd "exe-get-result ret: " ret )
12956     ret))
12957
12958 ;;; ----------------------------------------------------------------------
12959 ;;;
12960 (defun tinypgp-binary-get-result-decrypt (&optional buffer)
12961   "Read BUFFER after decrypt and sign (international version).
12962
12963 Return position of result in buffer.
12964   '(buffer beg end)"
12965   (let* (ret
12966          tmp)
12967     ;; Note how international version spits string "pass phrase",
12968     ;; and US version doesn't
12969     ;; +++++++++++++++++++++++++++
12970     ;;
12971     ;; International version - not for use in the USA. Does not useRSAREF.
12972     ;; Current time: 1997/05/19 12:10 GMT
12973     ;; Pass phrase is good.  Just a moment....-----BEGIN PGP SIGNED
12974     ;;
12975     ;;
12976     ;; Export of this software may be restricted by the U.S. government.
12977     ;; Current time: 1997/05/16 20:40 GMT
12978     ;; Pass phrase is good.
12979     ;; Key for user ID: xxxxk
12980     ;; 768-bit key, Key ID xxxx
12981     ;; Also known as:
12982     ;; Also known as:
12983     ;; Just a moment....-----BEGIN PGP SIGNED MESSAGE-----
12984
12985     ;; note: When you call command -seatf; encrypt and sign in one pass,
12986     ;; the output is bit different.
12987     ;; +++++++++++++++++++++++++++
12988     ;;
12989     ;;  International version - not for use in the USA. Does not use RSAREF.
12990     ;;  Current time: 1997/06/26 20:29 GMT
12991     ;;
12992     ;;  Including "/users/jaalto/.pgp/pgp-lst"...
12993     ;;  Pass phrase is good.  Just a moment....
12994     ;;  Key for user ID: Foo <foo@example.com>
12995     ;;  512-bit key, key ID 47141D35, created 1996/06/03
12996     ;;  Also known as: Jari Aalto, Finland <ssjaaa@uta.fi>
12997     ;;  .-----BEGIN PGP MESSAGE-----
12998     ;;  Version: 2.6.3ia
12999     ;;  Comment: Processed by Emacs TinyPgp.el 1.222
13000     ;;
13001     ;;  hEwDwLrt1UcUHTUBAgCFBDvkHJ7dEffIGiqyPi2WtdOPwWQ+Duw6/be/7FjJYEUV
13002
13003     (tinypgp-binary-get-result-re1-macro ; -seatf
13004      '((regexp "Pass phrase is good.  Just a moment[.]+"))
13005      (when (and (save-excursion
13006                   (forward-line 1)
13007                   (looking-at  ".*Key for user ID:"))
13008                 (re-search-forward (ti::mail-pgp-msg-begin-line) nil t))
13009        (setq
13010         tmp "-seatf[1]"
13011         ret (list (current-buffer) (match-beginning 0) (point-max)))))
13012
13013     (unless ret
13014       (tinypgp-binary-get-result-re1-macro
13015        (list
13016         (list
13017          'regexp
13018          (concat
13019           "Pass phrase is good.  Just a moment[.]+"
13020           ;; #todo: warning handling in decrypting
13021           ;;
13022           "\\|WARNING: Can't find.*can't check signature integrity.*\n")))
13023        (setq
13024         tmp "[2]"
13025         ret (list (current-buffer) (point) (point-max)))))
13026
13027     (unless ret
13028       ;;  This is from conventional decrypt
13029       (tinypgp-binary-get-result-re1-macro
13030        '((regexp "Pass phrase appears good\\. \\."))
13031        (setq
13032         tmp "[3]"
13033         ret (list (current-buffer) (point) (point-max)))))
13034
13035     ;; gpg: encrypted with 1024-bit ELG-E key, ID E7114155, created 2002-01-15
13036     ;;    "foo <foo@some.com>"
13037     ;; <THE MESSAGE FOLLOWS>
13038
13039     (unless ret
13040       ;;  This is from conventional decrypt
13041       (tinypgp-binary-get-result-re1-macro
13042        '((regexp "^gpg: encrypted with.*[\r\n\]+.*[\r\n\][\r\n\]?"))
13043        (setq
13044         tmp "[gpg]"
13045         ret (list (current-buffer) (point) (point-max)))))
13046
13047     ;;  GPG is different. It will not give any indication if
13048     ;;  Pass phrase was good. It simply decrypted the message and
13049     ;;  possibly gave warnings:
13050     ;;  gpg: Please note that you don't have secure memory on this system
13051     ;;  gpg: Warning: unsafe permissions on file "~/.gnupg/options"
13052     ;;  gpg: Warning: unsafe permissions on file "~/.gnupg/random_seed"
13053     ;;  gpg: Warning: unsafe permissions on file "~/.gnupg/secring.gpg"
13054     ;;  gpg: Warning: unsafe permissions on file "~/.gnupg/pubring.gpg"
13055     ;;  <THE MESSAGE FOLLOWS>
13056
13057     (unless ret
13058       ;;  This is from conventional decrypt
13059       (tinypgp-binary-get-result-re1-macro
13060        '((regexp "^gpg: Warning:.*[\r\n]")
13061          (loop   t))
13062        (setq
13063         tmp "[gpg]"
13064         ret (list (current-buffer) (point) (point-max)))))
13065
13066     (tinypgpd "exe-get-result-decrypt ret: " tmp ret )
13067     ret))
13068
13069 ;;; ----------------------------------------------------------------------
13070 ;;;
13071 (defun tinypgp-binary-get-result-encrypt-info (&optional buffer)
13072   "Return pointer to block 'This message can only be read by:'"
13073   (with-current-buffer (or buffer tinypgp-:buffer-tmp-shell)
13074     (ti::pmin)
13075     (when (re-search-forward
13076            "This message can only be read by:" nil t)
13077       (beginning-of-line)
13078       (let* ((beg (point)))
13079         (or (re-search-forward "^[ \t]*$" nil t) (ti::pmax))
13080         (beginning-of-line)
13081         (list (current-buffer) beg (point))))))
13082
13083 ;;; ----------------------------------------------------------------------
13084 ;;;
13085 ;;; This message can only be read by:
13086 ;;;   keyID: EFDB16AD
13087 ;;;   foo <foo@some.com>
13088 ;;;
13089 (defun tinypgp-binary-get-result-encrypt-info-list (&optional pointer)
13090   "Return list of users in 'This message can only be read by:'.
13091 POINTER is region where to read the results: (buffer beg end)"
13092   (interactive)
13093   (let* (list)
13094     (or pointer
13095         (setq pointer (tinypgp-binary-get-result-encrypt-info)))
13096     (when pointer
13097       (with-current-buffer (car pointer)
13098         (goto-char (nth 1 pointer))
13099         (forward-line 1)
13100         (while (or (looking-at ".*keyID: +\\(.*\\)")
13101                    (looking-at "^ +\\(.*\\)"))
13102           (push (ti::remove-properties (match-string 1)) list)
13103           (forward-line 1))))
13104     list))
13105
13106 ;;; ----------------------------------------------------------------------
13107 ;;;
13108 (defun tinypgp-binary-get-result-verify-status (&optional buffer)
13109   "Return result STRING after verify from BUFFER."
13110   (tinypgp-binary-get-result-re1-macro
13111    (list
13112     (list
13113      'regexp
13114      (concat "Good signature \\(from\\|made\\)"
13115
13116              ;;  This warning is preceeded by lines:
13117              ;;  File has signature.  Public key is required to check...
13118              ;;  Key matching expected Key ID 1CEB1F55 not found
13119              ;;
13120              "\\|WARNING: Can't find the right public"
13121              "\\|Bad signature from"
13122              "\\|Key matching.*not found")))
13123    (if (or (tinypgp-backend-pgp2-p)
13124            (tinypgp-backend-gpg-p))
13125        (ti::read-current-line)
13126      (forward-line 1)
13127
13128      (let* ((case-fold-search t)
13129             (id  (ti::buffer-match ".*key +id +\\([0-9A-Z]+\\)" 1))
13130             list)
13131        (forward-line 1)
13132        (setq list
13133              (ti::mail-email-find-region
13134               (point)
13135               (progn (forward-line 5) (point))))
13136        (format "Good signature from %s%s"
13137                (if id (format " %s " id)  "")
13138                (if list
13139                    (ti::list-to-string list)
13140                  "<unknown>"))))))
13141
13142 ;;; ----------------------------------------------------------------------
13143 ;;;
13144 (defun tinypgp-binary-get-result-using-function (function &optional buffer)
13145   "Call FUNCTION with arg BUFFER and return result in string format.
13146 Function is the one that returns `pointer' object, like
13147 `tinypgp-binary-get-result-verify'"
13148   (let* ((pointer (funcall function buffer)))
13149     (when pointer
13150       (inline (tinypgp-binary-get-result-as-string pointer)))))
13151
13152 ;;; ----------------------------------------------------------------------
13153 ;;;
13154 (defun tinypgp-binary-insert-pointer-data (pointer &optional beg)
13155   "Read POINTER '(buffer beg end) and insert data to point.
13156 Input:
13157   pointer   '(BUFFER BEG END)
13158   beg       flag, keep poin in beginnning instead of end of inserted data.
13159 "
13160   (if (not (eq 3 (length pointer)))
13161       (error "Invalid pointer")
13162     (let ((point (point)))
13163       (insert-buffer-substring (car pointer) (nth 1 pointer) (nth 2 pointer))
13164       (if beg
13165           (goto-char point)))))
13166
13167 ;;; ----------------------------------------------------------------------
13168 ;;;
13169 (defun tinypgp-binary-get-result-as-string (pointer)
13170   "Read string from POINTER '(buffer beg end)."
13171   (with-current-buffer (car pointer)
13172     (buffer-substring (nth 1 pointer) (nth 2 pointer))))
13173
13174 ;;; ----------------------------------------------------------------------
13175 ;;; File has signature.  Public key is required to check signature.
13176 ;;; .
13177 ;;; Good signature from user "XXX xxx <xxx@example.com>
13178 ;;; Signature made 1998/03/04 08:22 GMT using 512-bit key, key ID 47141D35
13179 ;;; PGP-DATA-FOLLOWS
13180 ;;;
13181 (defun tinypgp-binary-get-result-verify (&optional buffer)
13182   "Return result after verify from BUFFER. '(buffer beg end)."
13183   (let ((fid   "tinypgp-binary-get-result-verify")
13184         ret
13185         beg
13186         end)
13187     (tinypgp-binary-get-result-re1-macro
13188      (list
13189       (list
13190        'regexp
13191        (concat "Good signature \\(from\\|made\\)"
13192                "\\|Bad signature"
13193                ;;  This warning is preceeded by lines:
13194                ;;  File has signature.  Public key is required to check...
13195                ;;  Key matching expected Key ID 1CEB1F55 not found
13196                ;;
13197                "\\|WARNING: Can't find the right public")))
13198      (re-search-forward "Signature made" nil t)
13199
13200      (if (or (tinypgp-backend-pgp2-p)
13201              (tinypgp-backend-gpg-p)
13202              (forward-line 1)
13203              (goto-char (tinypgp-hash 'expect 'get 'point nil 'global)))
13204
13205          (setq beg (point)
13206                end (point-max))
13207
13208        (if (or (tinypgp-backend-pgp2-p)
13209                (tinypgp-backend-gpg-p))
13210            (tinypgp-binary-result-data-win32 beg end))
13211
13212        ;; Sometimes PGP says this:
13213        ;;
13214        ;; Looking for next packet in '/users/jaalto/junk/pgptemp.$00'...
13215        ;;
13216        ;; File has signature.  Public key is required to check signature.
13217        ;;
13218        ;; File '/users/jaalto/junk/pgptemp.$01' has signature, but with no text.
13219
13220        (when (re-search-forward "Looking for next packet in '" nil t)
13221          (beginning-of-line)
13222          (setq end (point)))
13223
13224        (setq ret (list (current-buffer) beg end)))
13225
13226      (tinypgpd fid  "POINTER" ret)
13227      ret)))
13228
13229 ;;; ----------------------------------------------------------------------
13230 ;;;
13231 (defun tinypgp-binary-get-result-base64 (&optional buffer)
13232   "Get contents after the 'Signature made 1996/11 ...' from BUFFER.
13233 Return:
13234   pointer   '(buffer beg end)"
13235   (let (ret)
13236     (tinypgp-binary-get-result-re1-macro
13237      '((regexp "^Good signature from"))
13238      ;; Good signature from user
13239      ;; Signature made 1996/11/07
13240      ;; DATA-HERE
13241      ;;
13242      (forward-line 2)
13243      (setq ret (list (current-buffer) (point) (point-max))))
13244     ret))
13245
13246 ;;; ----------------------------------------------------------------------
13247 ;;;
13248 (defun tinypgp-binary-get-result-key-add (&optional buffer)
13249   "Return result of key adding from BUFFER."
13250   (interactive)
13251   (let (ret
13252         list)
13253     (cond
13254      ((tinypgp-binary-get-result-re1-macro
13255        (list
13256         (list
13257          'regexp
13258          (concat
13259           "you need a newer version of PGP"
13260           "\\|Bad ASCII armor"
13261           "\\|^No +keys found\\|.*added.*\\|ERROR: Bkad ASCII armor.*"
13262           "\\|.*error\\|No new keys or signatures")))
13263        (setq ret (ti::read-current-line))))
13264      ((with-current-buffer tinypgp-:buffer-tmp-shell
13265         (ti::pmin)
13266         (setq list (ti::buffer-grep-lines "new key(s)")))
13267       (setq ret (format "%d New keys added." (length list)))))
13268
13269     ret))
13270
13271 ;;; ----------------------------------------------------------------------
13272 ;;;
13273 (defun tinypgp-binary-get-result-key-sign (&optional buffer)
13274   "Return result of key signing from BUFFER."
13275   (interactive)
13276   (let (ret)
13277     (cond
13278      ((tinypgp-binary-get-result-re1-macro
13279        (list
13280         (list
13281          'regexp
13282          (concat
13283           "^No +keys found\\|ERROR\\|.*error"
13284           "\\|Key is already signed by")))
13285        (setq ret (ti::read-current-line)))))
13286     ret))
13287
13288 ;;; ----------------------------------------------------------------------
13289 ;;;
13290 (defun tinypgp-binary-get-result-key-remove (&optional buffer)
13291   "Return result of key remove from BUFFER."
13292   (let (ret)
13293     (cond
13294      ((tinypgp-binary-get-result-re1-macro
13295        (list
13296         (list
13297          'regexp
13298          (concat
13299           ;;  PGP can't remove key if it asks this
13300           ;;
13301           ;;  Key has more than one user ID.
13302           ;;  Do you want to remove the whole key (y/N)? << WAITS HERE
13303           ;;
13304           "^Key has more than one user ID"
13305           "\\|Keyring remove error")))
13306        (setq ret (ti::read-current-line)))))
13307     ret))
13308
13309 ;;; ----------------------------------------------------------------------
13310 ;;;
13311 (defun tinypgp-binary-exit-code-ok-p (number)
13312   "Check if exit code NUMBER is ok."
13313   (if (and (tinypgp-backend-pgp2-p)
13314            (memq number '(0 1)))
13315       t
13316     nil))
13317
13318 ;;; ----------------------------------------------------------------------
13319 ;;;
13320 (defun tinypgp-binary-exit-status-entry (number)
13321   "Check PGP's exit code NUMBER and return appropriate error message."
13322   (let* ((table  tinypgp-:pgp-binary-exit-code-table)
13323          elt)
13324     (cond
13325      ((tinypgp-backend-pgp2-p)
13326       (setq elt  (cdr (assq 'pgp2 table)))))
13327     ;; (unless elt (error "Unknown PGP executable."))
13328     (assq number elt)))
13329
13330 ;;; ----------------------------------------------------------------------
13331 ;;;
13332 (defun tinypgp-binary-handle-result (&optional status)
13333   "Show `tinypgp-:buffer-tmp-shell' buffer if error, otherwise return result.
13334 STATUS is Shell processes exit code.
13335
13336 Return
13337  '(buffer beg end)   or call error"
13338   (tinypgpd "tinypgp-binary-handle-result: in" status)
13339   (let* ((fid    "tinypgp-binary-handle-result")
13340          (action (tinypgp-hash 'action 'get 'now nil 'global))
13341          (elt    (if status (tinypgp-binary-exit-status-entry status)))
13342 ;;;      (sym    (if elt (nth 1 elt)))
13343 ;;;      (re     (if elt (nth 2 elt)))
13344          (ok     (if status (tinypgp-binary-exit-code-ok-p status)))
13345          error
13346          ret)
13347
13348     (tinypgpd fid "Status" status "OK"  ok )
13349
13350     ;;  There is one case where pgp return 0 status(ok): encrypt with
13351     ;;  multiple keys, but some key is not found from keyring.
13352     ;; --> I'd say this is fatal error
13353     ;;
13354     ;;  That's why we always check the verbal results in spite of STATUS
13355
13356     (setq error (tinypgp-binary-check-error))
13357
13358     (unless error
13359       (setq ret (or
13360                  ;;  verifying the message also unpacks
13361                  ;;  encrypted message if sig was good
13362                  ;;
13363                  (tinypgp-binary-get-result-verify)
13364
13365                  (tinypgp-binary-get-result)
13366                  (and (string-match "decrypt" (symbol-name action))
13367                       (tinypgp-binary-get-result-decrypt)))))
13368
13369     (tinypgpd fid
13370               "STATUS" status
13371               "elt" elt
13372               "error" error
13373               "POINTER" ret
13374               "ACTION" action)
13375
13376     (cond
13377      ((and (null error)
13378            (not (null ret)))
13379       ret)
13380      (t
13381       (tinypgp-error (or error "No PGP output or error; huh?"))))))
13382
13383 ;;}}}
13384 ;;{{{ PGP exe
13385
13386 ;;; ----------------------------------------------------------------------
13387 ;;;
13388 (defun tinypgp-binary-command-region-fix (cmd pointer)
13389   "If the CMD failed when PGP asked random bits, fix it. POINTER is PGP data."
13390   (tinypgpd "tinypgp-binary-command-region-fix in:" pointer )
13391   (with-current-buffer (car pointer)
13392     (when (ti::re-search-check
13393            "We need to generate \\([0-9]+\\)"  0 '(point-min))
13394       (tinypgpd "tinypgp-binary-command-region-fix done:" pointer "\n")
13395       (tinypgp-error "randseed.bin must be generated."))))
13396
13397 ;;; ----------------------------------------------------------------------
13398 ;;;
13399 (defsubst tinypgp-send  (string)
13400   "Send STRING to open expect process."
13401   (expect-send (concat string (if (ti::win32-p) "\r" "\n"))))
13402
13403 ;;; ---------------------------------------------------------- &engine ---
13404 ;;;
13405 (defun tinypgp-binary-do-command-region-with-expect
13406   (cmd beg end o-buffer &optional msg ret-ptr)
13407   "Execute shell CMD on region BEG END with USER.
13408
13409 Input:
13410
13411   CMD           str, full PGP command.
13412   BEG           int, region beg to feed to PGP
13413   END           int, region end to feed to PGP
13414   O-BUFFER      bfr, original buffer where BEG END are
13415   MSG           str, message
13416   RET-PTR       flag, instead of replacing previous content return pointer
13417
13418 Return:
13419
13420   REGION END REPLACED   point at beg, if ret-ptr = nil
13421   POINTER               '(buffer beg end) if ret-ptr = non-nil"
13422   (let* ((fid           "tinypgp-binary-do-command-region-with-expect: ")
13423          (binary-process-input t)
13424          (out-p         (string-match "-o\\|#OUT" cmd))
13425          (orig-buffer   (current-buffer))
13426          pgp-error
13427          split
13428          bin-name
13429          args
13430          expect-start
13431          process pass
13432          out-buffer
13433          point
13434
13435          ret
13436          pointer)
13437
13438     (if (null binary-process-input)     ;quiet ByteCompiler
13439         (setq binary-process-input nil))
13440
13441     (tinypgp-hash 'expect 'put 'process nil 'global)
13442
13443     (tinypgp-do-shell-env
13444      (tinypgp-excute-in-tmp beg end     ;results in temp buffer
13445
13446                             (if msg
13447                                 (message msg))
13448
13449                             (tinypgp-file-control 'all-kill)
13450
13451                             (ti::pmin)
13452                             (tinypgp-file-control 'source-write)
13453
13454                             (cond
13455                              ((string-match "#PIPE" cmd)
13456                               (setq cmd (tinypgp-cmd-compose cmd nil nil '(nil))))
13457                              ((string-match "#SOURCE-FILE" cmd)
13458                               (setq cmd (tinypgp-cmd-compose cmd nil nil '(nil)))))
13459
13460                             ;;  If this command requires password, it contains marker #password
13461                             ;;  --> get the password from cache or ask from user.
13462
13463                             (when (string-match "#password" cmd)
13464                               (setq cmd   (ti::replace-match 0 nil cmd) ;; Delete tag from command
13465                                     pass  (tinypgp-password-get)))
13466
13467                             ;; The command is given as plain string. Explode it to individual
13468                             ;; arguments "pgp -s +batchmode=1" --> '("pgpg" "-s" "+batchmode=1")
13469
13470                             (setq split         (split-string cmd "[ ]+")
13471                                   bin-name      (nth 0 split)
13472                                   args          (cdr split)
13473                                   out-buffer    (current-buffer))
13474
13475                             (setq tinypgp-:last-pgp-exe-command cmd)
13476
13477                             (tinypgpd fid "in:"
13478                                       "COMMAND"  cmd
13479                                       "CURRENT"  (current-buffer)
13480                                       "ORIG"     orig-buffer
13481                                       beg end
13482                                       "min-max" (point-min) (point-max)
13483                                       "MSG"     msg
13484                                       "RET-PTR" ret-ptr
13485                                       "BIN"     bin-name
13486                                       "ARGS"    args
13487                                       "CMD"     cmd)
13488
13489                             (erase-buffer)
13490
13491                             (setq expect-start (point-max)
13492                                   process (apply
13493                                            'start-process
13494                                            "PGP"
13495                                            out-buffer
13496                                            bin-name
13497                                            args))
13498
13499                             (unwind-protect
13500                                 (with-expect process
13501
13502                                              (unless (ti::win32-p) ;; Unix is slower than NT, add delay
13503                                                (sit-for 0.3))
13504
13505                                              (expect-cond
13506
13507                                               ;; Error!  Unable to load string ENTER_PASSPHRASE
13508
13509                                               ("Enter pass phrase:\\|ENTER_PASSPHRASE"
13510                                                (tinypgpd "Expect: triggered password prompt, sending it...")
13511                                                (unless (stringp pass)
13512                                                  (delete-process process)
13513                                                  (tinypgp-error "Internal error. No pass phrase available."))
13514                                                (sit-for 0.3) ;Small delay so that PGP is ready
13515                                                (tinypgp-send pass)
13516
13517                                                (expect-cond
13518                                                 ("Error: Bad pass phrase."
13519                                                  (interrupt-process process)
13520                                                  (setq pgp-error 'bad-pass-phrase))
13521
13522                                                 ("Enter pass phrase:"
13523                                                  (interrupt-process process)
13524                                                  (setq pgp-error 'bad-pass-ohrase))
13525
13526                                                 ("Cannot decrypt message.  It can only be decrypted by:"
13527                                                  (interrupt-process process)
13528                                                  (setq pgp-error 'cannot-decrypt)))))
13529
13530                                              ;;  WRN:  WARNING: The above key is not trusted to belong to:
13531                                              ;;  WRN:  Mr. Foo <foo.site.com>
13532                                              ;;  QRY:  Do you want to use the key with this name? [y/N]
13533
13534                                              (unless pgp-error
13535                                                (expect-cond
13536                                                 ("Do you want to use the key with this name"
13537                                                  (tinypgpd "Expect: Use this kay ok...")
13538                                                  (tinypgp-send "y"))))
13539
13540                                              (unless pgp-error
13541                                                (expect-cond
13542                                                 (exit
13543                                                  (delete-process process))
13544
13545                                                 (timeout
13546                                                  (tinypgpd "Expect: timeout")
13547                                                  (delete-process process)
13548                                                  (error
13549                                                   (substitute-command-keys
13550                                                    (concat
13551                                                     "Expect: timeout occurred: send bug report "
13552                                                     "\\[tinypgp-submit-bug-report]"))))
13553
13554                                                 )) ;; expect-cond
13555
13556                                              ;;  Killing killed process won't hurt. Make sure the
13557                                              ;;  Expect-cond didn't fall through.
13558
13559                                              (delete-process process)
13560
13561                                              ;; ......................................... read results ...
13562
13563                                              (cond
13564                                               (pgp-error
13565                                                (tinypgpd "Expect: Terminated on error" pgp-error)
13566                                                (tinypgp-error
13567                                                 (format "Expect error %s" (symbol-name pgp-error))))
13568
13569                                               ((null out-p)
13570                                                (insert "\n")
13571                                                (setq point (point)))
13572
13573                                               (t
13574                                                (tinypgpd "Expect: reading input"
13575                                                          (current-buffer)
13576                                                          out-buffer
13577                                                          tinypgp-:file-output)
13578
13579                                                ;;  Expect may move us out of the buffer
13580
13581                                                (unless (eq (current-buffer) out-buffer)
13582                                                  (if (buffer-live-p (get-buffer out-buffer))
13583                                                      (set-buffer out-buffer)
13584                                                    (error "Expect: Can't insert data: buffer has changed")))
13585
13586                                                ;;  point is nil if there was no output file in
13587                                                ;;  this command, so the eq test will work in those
13588                                                ;;  cases too.
13589
13590                                                (if (eq (point) point)
13591                                                    (tinypgp-error "Expect: no output from PGP"))
13592
13593                                                (insert "\n")
13594                                                (setq point (point))
13595
13596                                                (if (file-exists-p tinypgp-:file-output)
13597                                                    (insert-file-contents tinypgp-:file-output)
13598                                                  (if (buffer-live-p (get-buffer out-buffer))
13599                                                      (pop-to-buffer out-buffer)
13600                                                    (error "No expected output-file %s "
13601                                                           tinypgp-:file-output))))) ;; end of cond
13602
13603                                              ;; ...................................... handle results ...
13604
13605                                              (tinypgp-hash 'expect 'put 'point point 'global)
13606
13607                                              ;;   Remove possible ^M chars
13608
13609                                              (ti::buffer-lf-to-crlf 'dos2Unix 'doReadOnly)
13610                                              (setq pointer (list (current-buffer) point (point-max)))
13611
13612                                              (tinypgpd "Expect: pointer" pointer)
13613
13614                                              (when (eq point (point-max))
13615                                                (tinypgp-error "No output from pgp"))
13616
13617                                              (tinypgp-file-control 'source-kill)))))
13618
13619     (unless (eq (current-buffer) orig-buffer) ;Restore buffer we left
13620       (set-buffer orig-buffer))
13621
13622     (cond
13623      (ret-ptr
13624       (setq ret pointer))
13625      (t
13626       (goto-char beg)
13627       (delete-region beg end)
13628       (insert-buffer-substring
13629        (car pointer) (nth 1 pointer) (nth 2 pointer))
13630       (goto-char beg)))
13631
13632     ret))
13633
13634 ;;; ---------------------------------------------------------- &engine ---
13635 ;;;
13636 (defun tinypgp-binary-do-command-region
13637   (cmd beg end o-buffer &optional msg ret-ptr)
13638   "Execute shell CMD on region BEG END with USER.
13639
13640 Input:
13641
13642   CMD           string,  full PGP command.
13643   BEG           integer, region beg to feed to PGP
13644   END           integer, region end to feed to PGP
13645   O-BUFFER      buffer,  original buffer where BEG END are
13646   MSG           string,  message
13647   RET-PTR       flag,    instead of replacing previous content return pointer
13648
13649 Return:
13650
13651   REGION END REPLACED   point at beg, if ret-ptr = nil
13652   POINTER               '(buffer beg end) if ret-ptr = non-nil
13653
13654 References:
13655
13656   `tinypgp-:pgp-sh-exe'
13657   `tinypgp-:last-pgp-exe-command'
13658   `tinypgp-:file-output'
13659   `tinypgp-:file-source'"
13660   (let* ((fid           "tinypgp-binary-do-command-region: ")
13661          (action        (tinypgp-hash 'action 'get 'now nil 'global))
13662          (loop          t)
13663          (final-newline "\n")
13664          (binary-process-input t)
13665          status
13666          ret pointer pointer-orig)
13667
13668     (if (null binary-process-input)     ;quiet ByteCompiler
13669         (setq binary-process-input nil))
13670
13671     (tinypgp-do-shell-env
13672
13673      (if msg
13674          (message msg))
13675
13676      (tinypgpd fid "in:" (current-buffer)
13677                beg end  "min-max" (point-min) (point-max)
13678                "MSG" msg
13679                "ACTION" action
13680                ret-ptr)
13681
13682      ;; ... ... ... ... ... ... ... ... ... ... ... ... ...  loop start ...
13683      (while loop                        ;If we should repeat the task?
13684        (setq loop nil)
13685        (tinypgpd fid "loop-beg" loop (current-buffer) cmd "\n")
13686
13687        (tinypgp-excute-in-tmp beg end   ;results in temp buffer
13688
13689 ;;;      (pop-to-buffer (current-buffer)) (ti::d! "DOING PGP")
13690
13691                               (setq pointer-orig (list (current-buffer) (point-min) (point-max)))
13692
13693                               (ti::pmin)
13694                               (tinypgp-file-control 'source-write)
13695
13696                               ;;  PGP: Cannot use INPUT file as a parameter to pgp, but
13697                               ;;  we must feed the file through pipe to pgp. Fix some
13698                               ;;  commands.
13699
13700                               (when (tinypgp-backend-pgp2-p)
13701                                 (cond
13702                                  ((string-match "#PIPE" cmd)
13703                                   (setq cmd (tinypgp-cmd-compose cmd nil nil '(nil))))
13704                                  ((string-match "#SOURCE-FILE" cmd)
13705                                   (setq cmd  (ti::replace-match 0 nil cmd))
13706                                   (setq cmd  (concat " #PIPE " cmd))
13707                                   (setq cmd (tinypgp-cmd-compose cmd nil nil '(nil))))
13708                                  (t
13709                                   (setq cmd (concat " #PIPE " cmd))
13710                                   (setq cmd (tinypgp-cmd-compose cmd nil nil '(nil))))))
13711
13712                               (tinypgpd fid "last-cmd:" (current-buffer) cmd )
13713
13714                               (setq tinypgp-:last-pgp-exe-command cmd)
13715
13716                               (if tinypgp-:do-command-region-before-hook
13717                                   (run-hook-with-args-until-success
13718                                    'tinypgp-:do-command-region-before-hook
13719                                    cmd msg ret-ptr))
13720
13721                               (erase-buffer)
13722
13723                               ;; ............................................. save command ...
13724
13725                               (when nil ;;  only t if development version
13726                                 (with-temp-buffer
13727                                   (let ((file "~/.tinypgp-cmd"))
13728                                     (insert cmd "\n")
13729                                     (write-region (point-min) (point-max) file)
13730                                     (ti::file-mode-protect file))))
13731
13732                               ;; .............................................. run command ...
13733
13734                               (ti::file-delete-safe tinypgp-:file-output)
13735
13736                               (setq status
13737                                     (shell-command cmd (current-buffer)))
13738
13739                               ;;  If there is output file (which was not sent stdout),
13740                               ;;  then read it. This happens with GPG, which is unable to send
13741                               ;;  to stdout, if stdin is used for password.
13742
13743                               (when (file-exists-p tinypgp-:file-output)
13744                                 (ti::pmax)
13745                                 (tinypgpd fid "READING OUTPUT FILE" tinypgp-:file-output)
13746                                 (insert-file-contents-literally tinypgp-:file-output))
13747
13748                               (tinypgpd fid "SHELL-STATUS" status)
13749
13750                               (if tinypgp-:do-command-region-after-hook
13751                                   (run-hook-with-args-until-success
13752                                    'tinypgp-:do-command-region-after-hook
13753                                    cmd msg ret-ptr))
13754
13755                               ;;   sometimes PGP need new randseed file, this generates it
13756                               ;;   and runs the command again.
13757                               ;;
13758                               ;;   WinNT: If PGP tries to ask for ranadseed, it hangs whole emacs.
13759
13760                               (when (and t ;enable for now..
13761                                          (not (ti::win32-p))
13762                                          (tinypgp-binary-command-region-fix cmd pointer-orig))
13763                                 (setq loop t))
13764
13765                               ;;  Arggh, When decrypting message in WinNT with 2.6.x The output
13766                               ;;  is not correct: there is extra "..." at the end of DATA.
13767                               ;;
13768                               ;;     Pass phase is good. Just a moment...DATA-DATA
13769                               ;;     ...
13770
13771                               (when (ti::win32-p)
13772                                 (ti::pmax)
13773                                 (if (not (eq 0 (skip-chars-backward ".")))
13774                                     (delete-region (point) (line-end-position))))
13775
13776                               ;;   Remove possible ^M chars
13777                               (ti::buffer-lf-to-crlf 'dos2Unix 'force)))
13778
13779      ;; ... ... ... ... ... ... ... ... ... ... ... ... ... .. loop end ...
13780
13781 ;;;    (tinypgp-binary-insert-command-log)
13782 ;;;     (pop-to-buffer (car pointer-orig)) (ti::d! 1234)
13783
13784      (setq pointer (tinypgp-binary-handle-result status))
13785
13786      ;;     We kill these only after the results have been examined,
13787      ;;     because user may want to check the contents if error happend.
13788
13789      (tinypgp-file-control 'password-kill) ;Remove password file
13790      ;;     (tinypgp-file-control 'source-kill)
13791
13792      ;;  For some reason PGP does not output final newline
13793      ;;  after its TAGS. Check this and add it, otherwise replacing
13794      ;;  the buffer content doesn't go right.
13795
13796      (when pointer
13797        (with-current-buffer (car pointer)
13798          (when (string= "---"
13799                         (buffer-substring
13800                          (nth 1 pointer) (+  3 (nth 1 pointer))))
13801            (goto-char (nth 2 pointer))
13802            (insert final-newline)
13803            (setq pointer
13804                  (list (current-buffer)
13805                        (nth 1 pointer)
13806                        (1+ (nth 2 pointer)))))))
13807      (cond
13808       (ret-ptr
13809        (setq ret pointer))
13810       (t
13811        (goto-char beg)
13812        (delete-region beg end)
13813        (insert-buffer-substring
13814         (car pointer) (nth 1 pointer) (nth 2 pointer))
13815        (goto-char beg)))
13816      ret)))
13817
13818 ;;}}}
13819
13820 ;;{{{ PGP public key 'find by'
13821
13822 ;;; ..................................................... &pgp-key-get ...
13823
13824 ;;; ----------------------------------------------------------------------
13825 ;;;
13826 (defun tinypgp-finger-discard-by-regexp (string-or-list)
13827   "Discards some email addresses from STRING-OR-LIST.
13828 See variable `tinypgp-:finger-discard-email-hook'"
13829   (let (ret)
13830     (tinypgpd "[tinypgp-:finger-discard-email-hook] in:"
13831               tinypgp-:finger-discard-by-regexp "#" string-or-list )
13832
13833     (when string-or-list
13834       (if (not (stringp tinypgp-:finger-discard-by-regexp))
13835           (setq ret string-or-list)
13836         (dolist (x (ti::list-make string-or-list))
13837           (if (string-match tinypgp-:finger-discard-by-regexp x)
13838               (tinypgpd "[tinypgp-:finger-discard-email-hook doing]:" x )
13839             (push x ret)))))
13840     (nreverse ret)))
13841
13842 ;;; ----------------------------------------------------------------------
13843 ;;;
13844 (defun tinypgp-key-network-spawn (mode &optional arg1 arg2 verb)
13845   "Get key by fingering EMAIL.
13846 Examine the returned information and ask user help if there is more than
13847 one public key.
13848
13849 Input:
13850
13851   MODE          'finger
13852   ARG1 ARG2     if 'finger then arg1 is email
13853                 if 'http   then arg1 is host, arg2 is command
13854   VERB          flag, verbose messages.
13855
13856 Return:
13857
13858  string         if only one public key
13859  (string)       internal finger error string
13860
13861 References:
13862
13863  `tinypgp-:buffer-tmp-shell'     ,results of finger
13864  `tinypgp-:last-network-error'   ,if error happened."
13865   (let ((fid      "tinypgp-key-network-spawn:")
13866         (buffer   (tinypgp-ti::temp-buffer 'finger))
13867         (email    arg1)                 ;if command is finger
13868         stat
13869         data
13870         data2
13871         len
13872         ret)
13873
13874     (tinypgpd fid "in:" mode arg1 arg2 verb)
13875
13876     (setq tinypgp-:last-network-error nil)
13877
13878     (cond
13879      ((eq mode 'finger)
13880       (setq stat (ti::process-finger email nil nil buffer verb)))
13881      (t
13882       (error "Wrong mode '%s' " mode)))
13883
13884     (cond
13885      ((stringp stat)
13886       (setq tinypgp-:last-network-error stat)
13887       (setq ret (list stat)))
13888
13889      ((bufferp stat)
13890       (ti::mail-pgp-trim-buffer)        ;Remove garbage around keys.
13891
13892       (or (setq data
13893                 (ti::mail-pgpk-public-get-region  nil nil buffer))
13894           (setq data2
13895                 (ti::mail-pgpk-public-get-region  nil nil buffer 'relax)))
13896
13897       (when data2
13898         (setq data data2))
13899
13900       ;; I don't think people undertand this mail very well,
13901       ;; they only know how to do -kxa and -kv, not -fkxa
13902       ;;
13903 ;;;     (if (y-or-n-p
13904 ;;;          (concat
13905 ;;;           "Public key found, but not in full -fakx format "
13906 ;;;           "Send email notice? "))
13907 ;;;         (tinypgp-sendmail email 'pk-no-full-format))
13908
13909       (setq len (length data))
13910
13911       (cond
13912        ((and (eq  1 len)                ;only 1 public key found
13913              (not
13914               (null
13915                ;;  P-key block must not me empty
13916                (setq ret (nth 1 (car data))))))
13917         ret)
13918
13919        ((null data)
13920         (ti::read-char-safe-until
13921          "finger ok, but no Public key in his ~/.plan file.[press]")
13922         (setq ret nil))
13923
13924        (t
13925         ;; #todo
13926 ;;;     (ti::d! "FSTAT" stat  (length data))
13927         (error "Multiple keys not implemented yet.")))))
13928
13929     (tinypgpd fid email ret )
13930     ret))
13931
13932 ;;; ----------------------------------------------------------------------
13933 ;;;
13934 (defun tinypgp-key-finger-guess-email ()
13935   "Check Whole buffer for PGP email address.
13936 Return:
13937   nil                   Nothing cound
13938   email"
13939   (let* ((set           "[^ \t\n<=\"';:]+")
13940          (email-re      (concat "\\(" set "@" set "\\)"))
13941          ;;  finger ssjaaa@uta.fi | pgp -fka for pgp key
13942          ;;
13943          (kaf-re        "[ \t]*|[ \t]*pgp[ \t]+-\\(fka\\|kaf\\|afk\\|fak\\)")
13944          email
13945          line
13946          list)
13947
13948     (save-excursion
13949       (cond
13950
13951        ((and
13952          buffer-read-only               ;Incoming message RMAIL
13953          (ti::pmin)
13954          ;; X-Pgp-Signed:
13955          ;;     access-type=Finger; Address=foo@site.com;
13956          ;;
13957          (setq list   (tinypgp-xpgp-get-info))
13958          (setq email (assoc "address" list))))
13959
13960        ((and
13961          (ti::pmin)
13962          ;;  If's faster first look for simple regexp, and match
13963          ;;  it against complex regexp
13964          ;;
13965          (re-search-forward kaf-re nil t)
13966          (setq line (ti::read-current-line))
13967          (string-match (concat email-re kaf-re) line)
13968          (setq email (ti::remove-properties (match-string 1 line)))))
13969
13970        ((and
13971          (ti::pmin)
13972          (re-search-forward
13973           (concat
13974            "public.*key.*@\\|@.*public.*key"
13975
13976            ;; |Boudewijn Visser|E-mail:visser@ph.tn.tudelft.nl |finger for |
13977            ;; |University of Technology                        |PGP-key    |
13978            ;;
13979            "\\|@.*finger\\|finger.*@"
13980
13981            ;;  steve*windsong.demon.co.uk (for which PGP is preferred)
13982            ;;
13983            "\\|@.*pgp.*prefered\\|pgp.*prefered.*@")
13984           nil t)
13985          (setq line (ti::read-current-line))
13986          (string-match email-re line)
13987          (setq email (ti::remove-properties (match-string 1 line)))))))
13988
13989     (tinypgpd "tinypgp-key-finger-guess-email out:" email )
13990
13991     email))
13992
13993 ;;; ----------------------------------------------------------------------
13994 ;;;
13995 (defun tinypgp-key-finger-add (email &optional no-ask)
13996   "Ask where to store the public key for EMAIL; optionally NO-ASK.
13997
13998 Return
13999   non-nil     if added
14000   nil"
14001   (let ((finger-buffer      tinypgp-:buffer-tmp-finger)
14002         ans)
14003     (cond
14004      (no-ask
14005       ;;  Put into temporary keyring ... #todo
14006       (error "Not supported no-ask"))
14007      (email
14008       (setq ans
14009             (tinypgp-pubring-alias2file
14010              (tinypgp-pubring-complete
14011               (format
14012                "%s: Store the public key to pubring[empty=cancel]: "
14013                (or (car-safe (ti::mail-email-from-string email))
14014                    (ti::string-left email 20))))))
14015       (if (ti::nil-p ans)
14016           (setq ans nil)
14017         ;; #todo, should add the key to keyring.
14018         ;;
14019         (with-current-buffer finger-buffer
14020           ;;  (tinypgp-key-add-region-interactive)
14021           (tinypgp-key-add-region-batch (point-min) (point-max)))
14022 ;;;     (ti::d! "Cacheing finger>>" ans)
14023         ;;  email, keyring
14024         (tinypgp-key-cache 'put email ans))))
14025     ans))
14026
14027 ;;; ----------------------------------------------------------------------
14028 ;;;
14029 (defun tinypgp-key-find-by-finger-verbose (email-list)
14030   "EMAIL-LIST. See `tinypgp-key-find-by-finger'."
14031   (tinypgp-key-find-by-finger email-list nil 'verb))
14032
14033 ;;; ----------------------------------------------------------------------
14034 ;;;
14035 (defun tinypgp-key-find-by-finger (&optional email-list no-ask  verb)
14036   "Find a PGP key using finger.
14037
14038 The exact references searched are like:
14039
14040   finger foo@site.com for pgp public key
14041   finger foo@site.com | pgp -fka
14042   ...
14043
14044 If finger fails then user is offered a list of all email
14045 addresses and each one selected is fingered.
14046
14047 Input:
14048   EMAIL-LIST        ,if this is given, then do not search
14049                      current buffer for email addresses.
14050                      All entries that do not contain @ are filtered out.
14051                      This can be string list or single string
14052   NO-ASK            ,store all fingered keys without asking
14053                      to current keyring.
14054   VERB              ,enable verbose messages
14055
14056 Return:
14057   string    ,pgp publick key block
14058   nil"
14059   (interactive)
14060   (tinypgpd "tinypgp-key-find-by-finger in:")
14061   (let* (email
14062          stat
14063          ans
14064          list
14065          ret)
14066
14067     (ti::verb)
14068
14069     ;; ... ... ... ... ... ... ... ... ... ... ...  exact match search ...
14070
14071     (if email-list
14072         (setq list (ti::list-make email-list))
14073
14074       ;; ... ... ... ... ... ... ... ... ... ... ... .. list not given . .
14075       (setq email (tinypgp-key-finger-guess-email)
14076             email (tinypgp-email-discard-default list)
14077             email (tinypgp-finger-email-filter email))
14078
14079       (if (ti::listp email)
14080           (setq email (car email)))
14081
14082       (when email                       ;Try adding the exact match
14083         (setq ret (tinypgp-key-network-spawn 'finger email nil verb)))
14084
14085       (if (stringp ret)
14086           (setq ret (tinypgp-key-finger-add email))
14087         (setq list
14088               (tinypgp-email-find-region
14089                (point-min)
14090                ;;  For large buffers, look only the start
14091                ;;  of buffer. The point-min offset is
14092                ;;  needed because buffer may be narrowed (RMAIL)
14093                ;;
14094                (if (> (point-max) (+ (point-min) 1000))
14095                    (+ (point-min) 1000)
14096                  (point-max))))))
14097
14098     (if (and list tinypgp-:finger-discard-email-hook)
14099         (setq list (run-hook-with-args-until-success
14100                     'tinypgp-:finger-discard-email-hook list)))
14101
14102     (when list
14103       (setq list (tinypgp-email-discard-default list))
14104       (setq email (car-safe list)))
14105
14106     ;; ... ... ... ... ... ... ... ... ... ... ... ... . loop-finger . .
14107     (while (and list
14108                 (not (stringp ret))
14109                 (not (ti::nil-p email)))
14110
14111       (when (null no-ask)
14112         (setq
14113          ans
14114          (completing-read
14115           (format "%sFinger [e(x)it, !, empty=skip]: "
14116                   (if (> (length list) 1)
14117                       (format "%d: " (length list)) ""))
14118           (ti::list-to-assoc-menu list) nil nil email))
14119
14120         (cond
14121          ((string= "!" ans)
14122           (setq no-ask t))
14123
14124          ((string= "x" ans)
14125           (setq list  nil
14126                 email nil))
14127
14128          ((ti::nil-p ans)
14129           (setq email nil))
14130
14131          (t
14132           (setq email ans))))
14133
14134       ;; ... ... ... ... ... ... ... ... ... ... ... ... ... results ...
14135
14136       (when (not (ti::nil-p email))
14137         (setq stat (tinypgp-key-network-spawn 'finger email nil t))
14138
14139         (cond
14140          ((and (ti::listp stat)  verb)
14141           (message (format "[press]Finger internal error: %s" (car stat)))
14142           (sit-for 3)
14143           (discard-input))
14144
14145          ((stringp stat)
14146           (setq ret stat)
14147           (if verb
14148               (message "Fingered PGP key found."))))
14149         ;;  Used, remove
14150         (setq list (delete email list)))
14151
14152       ;; ................................................ go to next ...
14153       (unless ret                       ;not found yet?
14154         (if email
14155             (setq list (delete email list)))
14156         (setq  email (car list)
14157                list  (cdr list))))
14158
14159     (if ret
14160         (tinypgp-key-finger-add email no-ask))
14161
14162     (tinypgpd "tinypgp-key-find-by-finger out:" ret )
14163
14164     ret))
14165
14166 ;;; ----------------------------------------------------------------------
14167 ;;;
14168 (defun tinypgp-key-http-study-buffer (&optional buffer)
14169   "Search public key from HTTP keyserver request result BUFFER."
14170   (let* ()
14171     (tinypgpd "tinypgp-key-http-study-buffer in: " buffer (current-buffer))
14172     (with-current-buffer buffer
14173       (ti::mail-pgp-trim-buffer))))
14174
14175 ;;; ----------------------------------------------------------------------
14176 ;;;
14177 (defun tinypgp-key-find-by-http-url-verbose (&rest args) ;Called from hook
14178   "Call `tinypgp-key-find-by-http-url' interactively."
14179   (call-interactively 'tinypgp-key-find-by-http-url))
14180
14181 ;;; ----------------------------------------------------------------------
14182 ;;;
14183 (defun tinypgp-key-find-by-http-url (url &optional verb)
14184   "Send http request and try to read key from URL page. VERB.
14185
14186 Interactive call note:
14187
14188   This function searches only X-Pgp field for possible key location
14189   pointer in format Access-type=URL; URL=http://me.org/~me/pgp.html"
14190   (interactive
14191    (list (tinypgp-xpgp-key-address
14192           'http
14193           "(http) X-Pgp information is not present.")))
14194
14195   (let* ((fid       "tinypgp-key-find-by-http-url: ")
14196          (buffer    (tinypgp-ti::temp-buffer 'http))
14197          (obuffer   (current-buffer))
14198          (win-count (length (ti::window-list)))
14199          stat
14200          ret)
14201
14202     (ti::verb)
14203     (tinypgpd fid  "URL" url "VERB" verb)
14204
14205     (when (stringp url)
14206       (setq stat (ti::process-http-request url nil nil buffer verb)))
14207
14208     (tinypgpd fid "STAT" stat buffer)
14209
14210     (cond
14211      ((and (nth 1 stat)
14212            verb)
14213       (message "Http internal error: %s" stat)
14214       (sit-for 2)
14215       (discard-input))
14216
14217      ((bufferp (setq stat (car stat)))
14218       (pop-to-buffer stat)
14219       (ti::pmin)
14220       (if (setq
14221            stat
14222            (cond
14223             ((ti::mail-pgp-public-key-p (point-min))
14224              (if verb
14225                  (call-interactively 'tinypgp-key-add-region-batch)
14226                (tinypgp-key-add-region-batch (point-min) (point-max))))))
14227           ;;
14228           ;; See tinypgp-key-add-region-batch documentation
14229           ;;
14230           (setq ret tinypgp-:return-value)
14231
14232         ;;  If user had only 1 window visible, make this 'new' buffer
14233         ;;  small. But if he had more windows, don't shrink the
14234         ;;  just shown buffer (it shocks if your window settings are
14235         ;;  modified !)
14236         ;;
14237         (when (eq win-count 1)
14238           (shrink-window-if-larger-than-buffer))
14239
14240         ;; Keep cursor in the original buffer
14241         ;;
14242         (pop-to-buffer obuffer)
14243
14244         (if verb
14245             (message "Http request didn't find public key."))))) ;cond end
14246     ret))
14247
14248 ;;; ----------------------------------------------------------------------
14249 ;;;
14250 (defun tinypgp-key-find-by-http-keyserver-i-args (&optional string)
14251   "Ask args for function `tinypgp-key-find-by-http-keyserver'.
14252 If STRING is already know then do not ask for it.
14253
14254 Return:
14255   (srv cmd str)"
14256   (let* ((fid       "tinypgp-key-find-by-http-keyserver: ")
14257          (dummy     (tinypgpd fid "in: "))
14258
14259          (to-field  (if buffer-read-only ;; RMAIL VM
14260                         (mail-fetch-field        "from")
14261                       (mail-fetch-field  "to"))) ;; mail buffer
14262
14263          (line-end-position      (or (ti::mail-hmax) (point-max)))
14264
14265          (elist     (tinypgp-email-find-region
14266                      (point-min)
14267
14268                      ;;  Search up till character limit 3000
14269                      (if (> line-end-position (+ (point-min) 3000))
14270                          (+ (point-min)3000) line-end-position)))
14271          (key-id     (tinypgp-key-id-find))
14272          elt
14273          srv
14274          cmd)
14275
14276     (if dummy (setq dummy t))           ;No-op, byte-comp silencer.
14277
14278     (tinypgpd fid to-field key-id elist
14279               (current-buffer) (point-min) line-end-position)
14280
14281     (if to-field
14282         (setq to-field (car (ti::mail-email-from-string to-field))))
14283
14284     (if (setq elt (tinypgp-ask-http-keyserver))
14285         (setq srv (nth 0 elt)
14286               cmd (nth 1 elt))
14287       (error "Internal."))              ;should not happen
14288
14289     (if key-id                        ;Add this to completion list too
14290         (push key-id elist))
14291
14292     (or string
14293         (setq string
14294               (completing-read
14295                "Search string, no spaces: "
14296                (ti::list-to-assoc-menu elist) nil nil
14297                (if key-id
14298                    key-id
14299                  (ti::remove-properties
14300                   (or to-field (ti::buffer-read-space-word))))
14301                'tinypgp-:history-http-keyserver-string)))
14302     (list srv cmd string)))
14303
14304 ;;; ----------------------------------------------------------------------
14305 ;;;
14306 (defun tinypgp-key-find-by-http-keyserver-verbose (string)
14307   "See `tinypgp-key-find-by-http-keyserver'. STRING."
14308   (let ((a (tinypgp-key-find-by-http-keyserver-i-args string)))
14309     (tinypgp-key-find-by-http-keyserver (nth 0 a) (nth 1 a) string 'verb)))
14310
14311 ;;; ----------------------------------------------------------------------
14312 ;;;
14313 (defun tinypgp-key-find-by-http-keyserver
14314   (server command string &optional verb)
14315   "Send http request to keyserver to get a key.
14316
14317 Interactive note:
14318
14319   All email addresses are read from `point-min' to end of
14320   current line where your cursor sits. The default search string
14321   offered is read from the To field but you can delete the prompt
14322   and enter other found email addresses via Tab completion.
14323
14324 Functional note:
14325
14326   Please understand that waiting for a HTTP response may be painfully
14327   slow many times. If you can, prefer the finger and instruct
14328   poeople to include their publick key information in the
14329   $HOME/.plan file in full -fkax format.
14330
14331 Input:
14332
14333   SERVER        www.xx.com
14334   COMMAND       command to run in server
14335   STRING        the search string without spaces. If this parameter is nil
14336                 or contains spaces, thi function returns immediately.
14337   VERB          Verbose messages.
14338
14339 Return:
14340
14341   keyring       If htttp call succeeded and key was inserted to some keyring
14342   nil           no keys added or found"
14343   (interactive (tinypgp-key-find-by-http-keyserver-i-args))
14344   (tinypgpd "tinypgp-key-find-by-http-keyserver in: " string )
14345
14346   (unless (ti::nil-p string)
14347     (let* ((cmd      (format (concat "http://%s" command) server string)))
14348       (ti::verb)
14349       (tinypgpd "tinypgp-key-find-by-http-keyserver cmd: " cmd)
14350       (tinypgp-key-find-by-http-url cmd verb))))
14351
14352 ;;; ----------------------------------------------------------------------
14353 ;;;
14354 (defun tinypgp-key-find-by-http-guess ()
14355   "Select X-pgp URL if it exists or suggest keyserver search.
14356 This function is stricly for interactive use."
14357   (interactive)
14358   (let* ((url (tinypgp-xpgp-key-address 'http))
14359          tried
14360          ret)
14361     (if (and url
14362              (setq tried (y-or-n-p "X-Pgp key url found; obey it ")))
14363         (setq ret (tinypgp-key-find-by-http-url url 'verb)))
14364
14365     (unless ret
14366       (cond
14367        (tried
14368         (message "No luck, Inform person about possible defective X-URL")
14369         (sit-for 1.5))
14370        (t
14371         (setq ret (call-interactively 'tinypgp-key-find-by-http-keyserver)))))
14372     ret))
14373
14374 ;;; ----------------------------------------------------------------------
14375 ;;;
14376 (defun tinypgp-key-find-by-email (email-srv string)
14377   "Send email to nearest Public key mail service to get the Key.
14378 Notice that this sends _mail_ and doesn't return any values.
14379
14380 This function should not be put into any key find nook, but
14381 called by user with clear intention to find key as last resort.
14382
14383 Input:
14384   EMAIL-SRV     full string placed in To: field where to send the
14385                 request.
14386   STRING        what to request from the server normally
14387                 \"FirstName Surname\""
14388   (interactive
14389    (let (srv
14390          string)
14391      (setq srv (tinypgp-ask-email-keyserver))
14392      (setq                              ;ARG 2
14393       string
14394       (read-from-minibuffer "Search string [firstname surname]: "))
14395      (list srv string)))
14396
14397   ;; ... ... ... ... ... ... ... ... ... ... ... ... .. function start . .
14398   (let* (cmd)
14399
14400     (if (or (ti::nil-p email-srv)
14401             (ti::nil-p string)
14402             (not (string-match "@" email-srv)))
14403         (error "Invalid arguments."))
14404
14405     (setq cmd (format "GET %s" string))
14406
14407     (ti::mail-sendmail-macro  email-srv cmd 'send
14408                               (insert cmd "\n"))))
14409
14410 ;;; ----------------------------------------------------------------------
14411 ;;; - We don't make this a macro! It could be installed into hooks...
14412 ;;;
14413 (defun tinypgp-key-find-by-cache (string &optional who)
14414   "Check cache for STRING.
14415
14416 Input:
14417   STRING   string to find
14418   WHO      who calls this function (for debug purposes)
14419
14420 Return:
14421   pubring
14422   nil"
14423   (tinypgpd "tinypgp-key-find-by-cache: " string who)
14424   (if (stringp string)
14425       (tinypgp-key-cache 'get string)))
14426
14427 ;;; ----------------------------------------------------------------------
14428 ;;;
14429 (defsubst tinypgp-key-cache-update (&optional user)
14430   "Update cache with current USER/pubring parameters."
14431   (setq user (or user tinypgp-:user-now))
14432
14433   (tinypgpd "tinypgp-key-cache-update: " user tinypgp-:pubring-now )
14434
14435   ;;  The USER must at least contain 3 character, it's no use to
14436   ;;  cache 2 character user, because that may be a bug in program
14437   ;;
14438   (if (> (length user) 2)
14439       (tinypgp-key-cache 'put user tinypgp-:pubring-now)
14440     (error "TinyPgp: cache update internal error %s" user)))
14441
14442 ;;; ----------------------------------------------------------------------
14443 ;;;
14444 (defun tinypgp-key-find-by-keyrings-1 (string-or-list)
14445   "Search all keyrings and cache.
14446
14447 Input:
14448   STRING-OR-LIST    string or list of search strings, first one found
14449                     is used.
14450
14451 Return:
14452  (string . keyring) STRING is the one in string-or-list that was found
14453                     first.
14454  nil"
14455   (let* ((tinypgp-:pubring-now  tinypgp-:pubring-now)
14456          (fid                   "tinypgp-key-find-by-keyrings-1:")
14457          list
14458          kring
14459          ret
14460          search-string)
14461     (tinypgpd fid "in:" string-or-list)
14462     (setq string-or-list (ti::list-make string-or-list))
14463
14464     (dolist (search-string string-or-list) ;; #todo: Can't use dolist/2 loop
14465       (setq list (tinypgp-pubring-list))
14466
14467       (tinypgp-save-state-macro
14468        (with-current-buffer (tinypgp-ti::temp-buffer 'shell)
14469          (dolist (kring list) ;; #todo: Can't use dolist/2 loop
14470            (if (not (file-exists-p kring))
14471                (error "\
14472 Check tinypgp-:pubring-table/Config error, no exist '%s'" kring))
14473
14474            (setq tinypgp-:pubring-now kring) ;Search this
14475
14476            (when (tinypgp-key-info-insert search-string)
14477              ;;  That's it, stop the loop by setting list to nil
14478              (setq ret  (cons search-string kring)
14479                    string-or-list  nil   ;Stop loop 1
14480                    list            nil)  ;Stop loop 2
14481              (tinypgp-key-cache 'put search-string kring))))))
14482     (tinypgpd fid "out:" search-string kring ret)
14483     ret))
14484
14485 ;;; ----------------------------------------------------------------------
14486 ;;;
14487 (defun tinypgp-key-find-by-keyrings-verbose (string)
14488   "See `tinypgp-key-find-by-keyrings'. STRING."
14489   (tinypgp-key-find-by-keyrings string 'verb))
14490
14491 (defun tinypgp-key-find-by-keyrings (string &optional verb)
14492   "Try all available keyrings and try to find the public key.
14493 If pubring file searched does not exist, signal error.
14494
14495 Input:
14496
14497   STRING    ,search string
14498   VERB      ,if non-nil, then ask for search string if STRING search fails.
14499
14500 Note:
14501
14502   This function caches the pubring and string information
14503   The cache is always looked first, before doing any outside search.
14504
14505 Sets global
14506
14507   `tinypgp-:return-value' and property 'find-by-keyrings
14508
14509   If you call this function with argument VERB
14510   user can change the search STRING. if the user's string is found
14511   from the keyrings then the original STRING is changed. The
14512   property has value nil if STRING is original or
14513   it has the user's input value if that match was found.
14514
14515   You need the information if you try to encrypt with key
14516   xxx@foo.site.com and user changes it to 'doodle'. Then if
14517   'doodle' is found, you should use that for encryption and not
14518   the original xxx@foo.site.com
14519
14520 Return:
14521
14522   string    public keyring
14523   nil"
14524   (let ((fid  "tinypgp-key-find-by-keyrings:")
14525         (loop t)
14526         ret)
14527
14528     (tinypgpd "tinypgp-key-find-by-keyrings in:" string )
14529     (put 'tinypgp-:return-value 'find-by-keyrings nil)
14530
14531     (while (and loop (null ret))
14532       (setq loop nil)                   ;User sets this 't' if retry
14533
14534       (or (setq ret (tinypgp-key-find-by-keyrings-1 string))
14535           (and verb
14536                (ti::mail-mail-p)
14537                (progn
14538                  (message "\
14539 Hm, Consider using tinypgp-email-substitution-add in tinypgp rc file: TO hdr")
14540                  (sit-for 5)
14541
14542                  (setq
14543                   string
14544                   (completing-read
14545                    (format
14546                     "[%s] No keyring, try another string? : "
14547                     string)
14548                    (ti::list-to-assoc-menu (tinypgp-email-make-choices string))))
14549                  (if (ti::nil-p string) ;RET pressed --> ""
14550                      nil
14551                    (setq loop t)
14552                    (tinypgpd fid "RETRY" string)
14553                    (setq ret (tinypgp-key-find-by-keyrings-1 string)))))))
14554
14555     ;;  tinypgp-key-find-by-keyrings-1 return cons cell
14556     ;;
14557     (when (ti::listp ret)
14558       (put 'tinypgp-:return-value 'find-by-keyrings (car ret))
14559       (setq ret (cdr ret)))
14560
14561 ;;;    (ti::d! "fbk" (get 'tinypgp-:return-value 'find-by-keyrings))
14562     (tinypgpd "tinypgp-key-find-by-keyrings out:" string ret )
14563     ret))
14564
14565 ;;; ----------------------------------------------------------------------
14566 ;;;
14567 (defun tinypgp-key-find-by-guess (string &optional verb)
14568   "Try to determine where to get the Public key-id STRING.
14569 For best results, the STRING should be in 0xFFFFF format to
14570 uniquely match single person. Second best choice is full email address.
14571 VERB activates verbose messages.
14572
14573 The order of search depends on the variable:
14574
14575     `tinypgp-:find-by-guess-hook'
14576
14577 Which is list of functions."
14578   (interactive
14579    (list
14580     (ti::string-remove-whitespace
14581      (read-from-minibuffer
14582       "Search string: "
14583       (ti::string-remove-whitespace
14584        (or (ti::mail-get-field "from" nil 'null-mode)
14585            (ti::mail-get-field "to"   nil 'null-mode)))))))
14586   (let* ((fid "tinypgp-key-find-by-guess:")
14587          ret)
14588     (ti::verb)
14589     (if (ti::nil-p string) (error "Invalid arg"))
14590
14591     ;;  Is there substitution for this ?
14592     ;;
14593     (setq ret (car-safe (tinypgp-key-id-conversion string)))
14594     (tinypgpd fid "in: STRING" string "key-subst" ret verb)
14595
14596     (if ret (setq string ret))
14597
14598     (tinypgpd fid "RUN HOOKS" tinypgp-:find-by-guess-hook)
14599
14600     (setq ret (run-hook-with-args-until-success
14601                'tinypgp-:find-by-guess-hook string))
14602
14603     (if ret (tinypgp-key-cache 'put string ret))
14604
14605     (when verb
14606       (cond
14607        (ret
14608         ;;  maybe the previous call cached they KEY whose indicator "k"
14609         ;;  is not shown in modeline. Show "k" now
14610         ;;
14611         (tinypgp-update-modeline)
14612         (message "TinyPgp Guess found: [%s] keyring %s"
14613                  string
14614                  (file-name-nondirectory ret)))
14615        (t
14616         (message "TinyPgp Guess failure: (maybe converted) %s" string))))
14617     ret))
14618
14619 ;;}}}
14620 ;;{{{ PGP key management
14621
14622 ;;; ......................................................... &pgp-key ...
14623
14624 ;;; ----------------------------------------------------------------------
14625 ;;;
14626 (defun tinypgp-key-ring-at-point (&optional alias)
14627   "See if there is keyring by looking backward.
14628 First empty line terminates search. Eg.
14629
14630 Key ring: '/users/jaalto/.pgp/pubring.pgp', looking for
14631 user ID \"foo@site.com\".
14632 Type Bits/KeyID    Date       User ID
14633 pub  1024/20378F71 1995/08/19 Mr. foo  <foo@site.com>
14634
14635 Input:
14636  ALIAS   ,flag, return keyring alias name"
14637   (let (ret)
14638     (save-excursion
14639
14640       ;;  move away from empty line
14641       ;;
14642       (if (looking-at "^[ \t]*$")
14643           (forward-line -1))
14644
14645       (while (and (not (bobp))
14646                   (not (looking-at "^[ \t]*$"))
14647                   (null ret))
14648         (if (looking-at ".*Key ring:[ \t]+'\\([^']+\\)")
14649             (setq ret (match-string 1)))
14650         (forward-line -1)))
14651
14652     (if alias
14653         (setq ret (tinypgp-pubring-file2alias ret)))
14654
14655     ret))
14656
14657 ;;; ----------------------------------------------------------------------
14658 ;;;
14659 (defsubst tinypgp-key-trust-ask (&optional id)
14660   "Ask trust parameter. If user gives empty line, 'undefined' is returned.
14661 ID is user-id."
14662   (let ((ans
14663          (completing-read
14664           (format "%s%strust parameter? " (or id "") (if id " " ""))
14665           (ti::list-to-assoc-menu
14666            '("undefined" "untrusted" "marginal" "complete"))
14667           nil 'match-it
14668           "undefined")))
14669     (if (ti::nil-p ans)
14670         "undefined"
14671       ans)))
14672
14673 ;;; ----------------------------------------------------------------------
14674 ;;;
14675 (defun tinypgp-key-info-insert-current-user ()
14676   "Insert current user's key information to point.
14677 The current pubring is set temporarily to first
14678 entry in `tinypgp-pubring-table'."
14679   (tinypgp-save-state-macro
14680    (setq tinypgp-:pubring-now (nth 1 (car (tinypgp-pubring-table))))
14681    (tinypgp-key-info-insert tinypgp-:user-now 'verb)))
14682
14683 ;;; ----------------------------------------------------------------------
14684 ;;;
14685 (defun tinypgp-key-info-insert (string &optional verb)
14686   "Run pgp -kvc to get key information matching the STRING.
14687 Insert the content to current point. VERB allows verbose messages.
14688
14689 References:
14690   `tinypgp-:buffer-tmp-shell'
14691
14692 Return:
14693   t         something inserted
14694   nil       error condition"
14695   (interactive
14696    (list
14697     (read-from-minibuffer
14698      (format "insert key matching [pubring: '%s']: "
14699              (or (tinypgp-pubring-file2alias tinypgp-:pubring-now)
14700                  "<unknown>")))))
14701
14702   (barf-if-buffer-read-only)
14703   (tinypgpd "tinypgp-key-info-insert in: " string verb )
14704
14705   (let* ((bcmd  (tinypgp-binary-get-cmd 'key-info)) ;;base command
14706          (cmd   (tinypgp-cmd-compose bcmd nil nil '(nil)))
14707          (fid   "tinypgp-key-info-insert: ")
14708          shell-cmd
14709          buffer
14710          ret)
14711
14712     (ti::verb)
14713
14714     (cond
14715      ((and (string-match "[ \t]" string) (ti::win32-p))
14716       (error "STRING must not contain whitespace in WInNT"))
14717      (t
14718       (setq string (format "\"%s\"" string))))
14719
14720     (tinypgp-do-shell-env
14721      (with-current-buffer (setq buffer (tinypgp-ti::temp-buffer 'shell))
14722        (setq shell-cmd (format "%s %s" cmd string))
14723        (tinypgpd fid "run: " shell-cmd)
14724        (shell-command shell-cmd buffer)
14725        ;;       (pop-to-buffer (current-buffer)) (ti::d! "::key" string)
14726
14727        (ti::pmin)
14728        (cond
14729         ((re-search-forward "0 matching keys found\\." nil t)
14730          (if verb
14731              (message "0 matching keys found.")))
14732         (t
14733          (setq ret t)))))
14734
14735     (if ret
14736         (insert-buffer buffer))
14737
14738     (tinypgpd fid "out: " ret )
14739
14740     ret))
14741
14742 ;;; ----------------------------------------------------------------------
14743 ;;;
14744 (defun tinypgp-key-info-at-point-show (string &optional pubring-list)
14745   "Find match using STRING from current keyring or PUBRING-LIST.
14746 When called interactively, read space-separated-word
14747 under point and find matches from current keyring and
14748 show them in temporary buffer."
14749   (interactive
14750    (let (str)
14751      (setq str
14752            (read-from-minibuffer
14753             "Display key info matching: "
14754             (if (null (setq str (ti::buffer-read-word "-0-9a-zA-Z@.")))
14755                 ""
14756               ;; If  underlying word is Key-id 12345678, then
14757               ;; prepend 0x to it because that is only valid search string
14758               ;;
14759               (if (and (eq (length str) 8)
14760                        (string-match "^[0-9A-Z]+$" str))
14761                   (concat "0x" str)
14762                 (ti::string-left str 35)))
14763             nil
14764             nil
14765             'tinypgp-:history-key-info))
14766      (list str (tinypgp-pubring-list))))
14767
14768   (let ((tmp   (tinypgp-ti::temp-buffer 'show)))
14769     (if (not (stringp string))
14770         (error "Arg error")
14771
14772       (with-current-buffer tmp
14773         (tinypgp-save-state-macro
14774          (dolist (elt pubring-list)
14775            (setq tinypgp-:pubring-now elt)
14776
14777            (insert "\n" elt ":")
14778
14779            (beginning-of-line)
14780            (if (looking-at "^.*/\\(.*:\\)")
14781                (tinypgp-highlight 'match 1))
14782            (end-of-line)  (insert "\n")
14783
14784            (tinypgp-key-info-insert string)
14785            (ti::pmax))))
14786       (pop-to-buffer tmp)
14787       (ti::pmin))))
14788
14789 ;;; ----------------------------------------------------------------------
14790 ;;;
14791 (defun tinypgp-key-add-region-batch (beg end &optional noerr verb)
14792   "Add all public keys in region to active keyring.
14793 The region is handled by PGP directly. No checkings are done here.
14794
14795 Input:
14796
14797   BEG END   region
14798   NOERR     if nil, then signal error if PGP reports error.
14799   VERB      allow verbose messages
14800
14801 Interactive call:
14802
14803   The region is cecked for public key. If none exist offer using
14804   whole buffer.
14805
14806 Sets global:
14807   `tinypgp-:return-value'   pubring where the key was inserted
14808
14809 Return:
14810
14811   string
14812   nil           no keys were added"
14813
14814   (interactive
14815    (progn
14816      (ti::compat-activate-region)       ;Make sure user sees region
14817      ;; Check this before going further
14818      (if (null (ti::mail-pgp-public-key-p (point-min)))
14819          (error "No public key area in buffer"))
14820      (ti::i-macro-region-ask
14821       "No region selected, use whole buffer for key insert? ")))
14822
14823   (tinypgpd "tinypgp-key-add-region-batch in: pring"
14824             tinypgp-:pubring-now (current-buffer) )
14825
14826   (let* ((tinypgp-:pubring-now tinypgp-:pubring-now) ;make local copy
14827          (logical-cmd 'key-add)
14828          (bcmd      (tinypgp-binary-get-cmd logical-cmd)) ;;base command
14829          (copy      (tinypgp-ti::temp-buffer))
14830          (buffer    (tinypgp-ti::temp-buffer 'shell))
14831          (i         0)
14832          cmd
14833          pring
14834          ret)
14835
14836     (ti::verb)
14837     (tinypgpd "tinypgp-key-add-region-batch in:"
14838               (current-buffer) beg end bcmd cmd )
14839
14840     ;; .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. . verbose part ..
14841     ;;  Many times there may be old region active and user doesn't
14842     ;;  realize that,. Do little check first...
14843
14844     (when verb
14845       (when (and (not (ti::narrow-safe beg end
14846                         (ti::mail-pgp-public-key-p (point-min))))
14847                  (y-or-n-p
14848                   (concat
14849                    "Can't find public key block in region.. "
14850                    "Use full buffer [C-g to abort]")))
14851         (setq beg (point-min)  end (point-max)))
14852
14853       (if (setq pring (tinypgp-pubring-ask))
14854           (setq tinypgp-:pubring-now pring)))
14855
14856     ;; Only now can we compose the command: pubring is known or
14857     ;; set by user.
14858     ;;
14859     (setq tinypgp-:return-value tinypgp-:pubring-now)
14860     (setq cmd (tinypgp-cmd-compose bcmd nil nil '(nil)))
14861
14862     ;; .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. do it ..
14863     (tinypgp-do-shell-env
14864      (save-window-excursion
14865        (append-to-buffer copy beg end)
14866        (append-to-buffer buffer beg end)
14867        (with-current-buffer buffer
14868 ;;;      (pop-to-buffer (current-buffer)) (ti::d! 12345)
14869          ;;   Remove spaces: "intended PGP key", but only if there is
14870          ;;   only one key. Ignore "chop" if there is multiple keys.
14871          ;;
14872          (ti::pmin)
14873          (while (re-search-forward (ti::mail-pgp-pkey-begin-line) nil t) (incf  i))
14874          (if (eq 1 i) (ti::mail-pgp-chop-region (point-min) (point-max)))
14875
14876          ;;  If there is error situation, the "after" hook runs.
14877          (tinypgp-mode-specific-control-before logical-cmd)
14878
14879          (shell-command-on-region       ;This shows the buffer, gawk!
14880           (point-min) (point-max) (format "%s " cmd) buffer))))
14881
14882     ;; .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. ..  results ..
14883     (setq ret (tinypgp-binary-get-result-key-add))
14884     (when (and verb ret)
14885       (message "Key add note: %s" ret))
14886
14887     (when (and (stringp ret)
14888                (string-match "error" ret))
14889       (if noerr
14890           (setq ret nil)
14891         (tinypgp-error ret)))
14892
14893     (when (and (stringp ret)
14894                (string-match "No keys found" ret))
14895       (setq ret nil))
14896
14897     ret))
14898
14899 ;;; ----------------------------------------------------------------------
14900 ;;;
14901 (defun tinypgp-key-add-region-interactive (beg end)
14902   "Parse BEG END and ask if key should be added to the active keyring."
14903   (interactive (ti::i-macro-region-ask))
14904   (tinypgpd "tinypgp-key-add-region-interactive in: pring"
14905             tinypgp-:pubring-now  (current-buffer) beg end )
14906   (let ((data   (ti::mail-pgpk-public-get-region
14907                  nil nil tinypgp-:buffer-tmp-shell))
14908         (verb  (interactive-p))
14909         id
14910         pkey)
14911 ;;;     trust
14912
14913     (tinypgp-unfinished-function)
14914     (cond
14915      ((null data)
14916       (if verb
14917           (message
14918            "'Key for user ID:' tags not found to signify public key blocks.")))
14919      (t
14920       (dolist (elt data)
14921         (setq id (nth 0 elt)   pkey (nth 1 elt))
14922         (cond
14923          ((null pkey)
14924           (ti::read-char-safe
14925            (format "Public key empty: %s" (or id "<id not known>"))))
14926
14927          ((y-or-n-p (format"Add: %s" id))
14928 ;;;       (setq trust (tinypgp-key-trust-ask id))
14929           (with-current-buffer (tinypgp-ti::temp-buffer)
14930             (insert pkey)
14931             (tinypgp-key-add-region-batch (point-min) (point-max))
14932             (error "#todo trust not set."))))))
14933
14934 )));;; ----------------------------------------------------------------------
14935 ;;; Called by TM.el
14936 ;;;
14937 (defun tinypgp-key-extract-to-point-current-user ()
14938   "Extract `tinypgp-:user-now' key to current point."
14939   (tinypgp-key-extract-to-point  tinypgp-:user-now))
14940
14941 ;;; ----------------------------------------------------------------------
14942 ;;;
14943 (defun tinypgp-key-extract-to-point (string &optional raw noerr)
14944   "Insert public key matching STRING to current point.
14945
14946 Note:
14947
14948  If Pgp extracts file to some temporary file, that file will be deleted
14949  automatically, because the key will be available from emacs buffer.
14950  This prevents temporary files accumulating in your tmp directory.
14951  Also the line that containbs sentence
14952
14953     Key extracted to file '/users/xxx/junk/pgptemp.$07'.
14954
14955  is removed from the shell output buffer before yanking.
14956
14957 References:
14958
14959  `tinypgp-:buffer-tmp-shell'
14960
14961 Input:
14962
14963  STRING     string to search
14964  RAW        only insert the PGP block
14965  NOERR      if non-nil no error is signalled is string is not found,
14966             also the output is _not_ inserted to the current point,
14967             but returned.
14968
14969 Return:
14970
14971  string
14972  nil"
14973   (interactive
14974    (list
14975     (read-from-minibuffer "Insert public key matching: " tinypgp-:user-now)
14976     current-prefix-arg))
14977
14978   (barf-if-buffer-read-only)
14979   (tinypgpd "tinypgp-key-extract-to-point in: pring" tinypgp-:pubring-now )
14980   (let* ((fid   "tinypgp-key-extract-to-point:")
14981          (bcmd  (tinypgp-binary-get-cmd 'key-extract))
14982          (out   (tinypgp-ti::temp-buffer 'shell))
14983
14984          cmd
14985          kring
14986          ret)
14987
14988     (tinypgpd fid "in:" (current-buffer) string noerr )
14989
14990     (unless (setq kring  (tinypgp-key-find-by-keyrings string))
14991       (error "No PGP key for '%s'" string))
14992
14993     (tinypgpd fid "cmd,out,kring" cmd out kring )
14994
14995     (tinypgp-save-state-macro
14996      (setq tinypgp-:pubring-now kring)
14997      (setq cmd (tinypgp-cmd-compose bcmd nil nil '(nil)))
14998      (setq cmd (format "%s '%s'" cmd string)))
14999
15000     (tinypgp-do-shell-env (shell-command cmd out))
15001
15002     (with-current-buffer out
15003       (ti::pmin)
15004       (when (and (null (setq ret (ti::mail-pgp-pkey-read raw 'kill-file)))
15005                  (null noerr))
15006         ;;  Remove cache entry, maybe user has moved the key
15007         ;;  to another keyring?
15008         ;;
15009         (tinypgp-key-cache-remove-entry string)
15010         (pop-to-buffer out)
15011         (error "\
15012 PGP error; Maybe cache has old keyring information? Check cache.")))
15013
15014     (when (and ret
15015                (null noerr))
15016       (insert ret))
15017
15018     (tinypgpd fid "out:" ret )
15019
15020     ret))
15021
15022 ;;; ----------------------------------------------------------------------
15023 ;;;
15024 (defun tinypgp-key-delete-region (beg end &optional mode plist verb)
15025   "Remove all keys from keyring that are found from region.
15026 The picked key items are:
15027 o   all email addresses
15028 o   All regular pgp key lines \"pub   512/47141D35 1996/06/03 ...\"
15029
15030 In interactive or verb mode, all removed KeyId's used are marked
15031 with overlays after command completes. Overlays have property '(owner tinypgp)
15032
15033 Input:
15034  BEG END
15035  MODE       nil         = key id 0x based deletion
15036             1 or 'email = key id email based deletion
15037             2 or 'any   = both methods used.
15038  PLIST      list of pubring filenames to touch.
15039             Interactive call:
15040               all public keyring are stepped through;
15041               permission to use the pubring is asked from user.
15042             Lisp call:
15043               If this list oi nil, active pubring is used
15044  VERB       Enable verbose asking/message mode.
15045
15046 If VERB is non-nil, error is generated if it happens. if VERB is nil,
15047 then the possible error string is returned."
15048   (interactive
15049    (let* ((plist  (list tinypgp-:pubring-now))
15050           (kring  (or (tinypgp-key-ring-at-point 'alias)
15051                       (tinypgp-pubring-file2alias tinypgp-:pubring-now)))
15052           ans
15053           reg)
15054      (if (not (region-active-p))
15055          (error "Region not selected.")
15056        (setq reg (ti::i-macro-region-ask)))
15057
15058      (setq
15059       ans
15060       (tinypgp-pubring-complete
15061        (format
15062         (concat
15063          "%sDel keys from all prings or one ring? "
15064          "[empty=all] ")
15065         (cond
15066          ((eq 1   current-prefix-arg) "@: ")
15067          ((eq 2   current-prefix-arg) "0x@: ")
15068          ((eq nil current-prefix-arg) "0x: ")
15069          (t
15070           (error "No such prefix arg mode"))))
15071        kring))
15072
15073      (if (not (ti::nil-p ans))
15074          (setq plist (list (tinypgp-pubring-alias2file ans)))
15075        (setq plist (tinypgp-pubring-list)))
15076
15077      (list
15078       (nth 0 reg) (nth 1 reg)
15079       current-prefix-arg
15080       plist)))
15081
15082   (tinypgpd "tinypgp-key-delete-region in: " beg end mode plist verb )
15083   (let* ((buffer-orig   (current-buffer))
15084          (BCMD          (tinypgp-binary-get-cmd 'key-delete)) ;base command
15085          (delete-count  0)
15086          buffer
15087          buffer-shell
15088          bcmd
15089          cmd
15090          list1 list2  email-list keyid-list
15091          elt elt2
15092          err err1 err2
15093          permission)
15094
15095     (ti::verb)
15096     ;; #todo: use comint to delete keys ?
15097     ;;
15098 ;;;    (error "PGP can't use batch mode...needs new implementation.")
15099
15100     (tinypgpd "tinypgp-key-delete-region in: BCMD " BCMD)
15101     (if (null plist)                    ;Set default value
15102         (setq plist tinypgp-:pubring-now))
15103
15104     (setq plist (ti::list-make plist))  ;make sure it is list
15105
15106     (if (and verb
15107              (not (y-or-n-p
15108                    "TinyPgp: are you sure about this (region right)? ")))
15109         (error "Aborted."))
15110
15111     ;; ... ... ... ... ... ... ... ... ... ... ... ... ... ...  narrow ...
15112     ;;  We narrow so that highlighting finds right matches
15113     ;;
15114     (ti::narrow-safe beg end
15115       (tinypgp-run-in-tmp-buffer nil
15116                                  (cond  ;Gather key-ids first
15117                                   ((memq mode '(nil 2 any))
15118                                    (setq keyid-list
15119                                          (ti::mail-pgpk-id-0x-lines-in-region (point-min) (point-max))))
15120                                   ((memq mode '(1 email))
15121                                    (setq email-list (tinypgp-email-find-region (point-min) (point-max))))
15122                                   (t
15123                                    (error "Unknown mode %s" mode))))
15124
15125       (and verb (tinypgp-highlight 'delete-all))
15126
15127       (tinypgp-do-shell-env
15128        (tinypgp-save-state-macro
15129         (setq  buffer          (tinypgp-ti::temp-buffer)
15130                buffer-shell    (tinypgp-ti::temp-buffer 'shell))
15131         (with-current-buffer buffer
15132           (dolist (pring plist)
15133
15134             (setq tinypgp-:pubring-now pring)
15135             (setq list1 email-list  list2 keyid-list)
15136
15137             (tinypgpd "email-list"  list1  "keyid-list" list2)
15138
15139             ;; ... ... ... ... ... ... ... ... ... ... ... . user-ask  ..
15140             (when (and verb
15141                        (not (string= "!" (or permission ""))))
15142               (setq permission
15143                     (read-from-minibuffer
15144                      (format
15145                       (concat
15146                        "Keyring %s "
15147                        "[ret=ok, !=all, s=skip]: ")
15148                       (file-name-nondirectory pring)))))
15149
15150             ;; ... ... ... ... ... ... ... ... ... ...  user-response  ..
15151             (while (and
15152                     (member permission '("!" ""))
15153                     (null err)
15154                     (or list1 list2))
15155               (setq elt nil elt2 nil)
15156               (setq bcmd  (tinypgp-cmd-compose BCMD nil nil '(nil)))
15157               ;; ... ... ... ... ... ... ... ... ... ... ... .. email ..
15158               (when list1
15159                 (setq elt (pop list1))
15160                 (when elt
15161                   (setq cmd (format "%s '%s'" bcmd elt))
15162                   (shell-command cmd buffer-shell)
15163                   (tinypgpd "tinypgp-key-delete-region shell: " cmd )
15164                   (incf  delete-count)
15165                   ;;
15166                   ;;  "Key not found in keyring"
15167                   ;;  But that's no error and we don't report it.
15168                   ;;
15169                   (setq err1 (tinypgp-binary-check-error 'ignore-output cmd))
15170                   (when (and verb err1)  (tinypgp-error err1))))
15171
15172               ;; ... ... ... ... ... ... ... ... ... ... ... ... . 0x ..
15173               (when list2
15174                 (setq elt2 (pop list2))
15175                 (when (stringp elt2)
15176                   (setq cmd (format "%s '0x%s'" bcmd elt2))
15177                   (shell-command cmd buffer-shell)
15178                   (incf  delete-count)
15179                   (tinypgpd "tinypgp-key-delete-region shell: " cmd )
15180                   (setq err1 (tinypgp-binary-check-error 'ignore-output cmd))
15181                   (when (and verb err2)  (tinypgp-error err2))))
15182
15183               (tinypgpd "tinypgp-key-delete-region do: " pring
15184                         elt elt2 err1 err2 )
15185
15186               ;;  Highlight the line so that user sees it was processed.
15187               ;;
15188               (if (and verb  (or elt elt2))
15189                   (with-current-buffer buffer-orig
15190                     (if elt  (tinypgp-highlight elt))
15191                     (if elt2 (tinypgp-highlight elt2 nil nil 'region))))))))
15192
15193 ))    ;; ... ... ... ... ... ... ... ... ... ... ... ... ... ... message ...
15194     (when (and verb (null err))
15195       (cond
15196        ((zerop delete-count)
15197         (message "TinyPgp: Hm. It appears that no keys were found to delete."))
15198        (t
15199         (message "TinyPgp: Deleted keys have been marked with color. [%d]"
15200                  delete-count))))
15201
15202     (when (and verb
15203                (setq err (tinypgp-binary-get-result-key-remove buffer-shell)))
15204       (pop-to-buffer buffer-shell)
15205       (error "TinyPgp: Key remove problem; remove manually "))
15206
15207     err))
15208
15209 ;;; ----------------------------------------------------------------------
15210 ;;;
15211 (defun tinypgp-key-sign-1 (your-keyid her-keyid &optional noerr)
15212   "Sign key-id to current pubring.
15213
15214 Input:
15215  YOUR-KEYID HER-KEYID NOERR"
15216   (tinypgpd "tinypgp-key-sign-1 in: " your-keyid her-keyid noerr )
15217   (let* ((BCMD          (tinypgp-binary-get-cmd 'key-sign)) ;base command
15218          (bcmd          (tinypgp-cmd-compose BCMD nil nil '(nil)))
15219          (buffer-shell  (tinypgp-ti::temp-buffer 'shell))
15220          stat
15221          cmd)
15222     (tinypgp-unfinished-function)
15223     (setq cmd (format "%s %s" bcmd your-keyid her-keyid))
15224     (error "#todo") (ti::d! (ti::string-right cmd 50))
15225     (shell-command cmd buffer-shell)
15226
15227     ;; #todo: check results of signing
15228     ;;
15229     (if (setq stat (tinypgp-binary-get-result-key-sign))
15230         stat stat)))
15231
15232 ;;; ----------------------------------------------------------------------
15233 ;;;
15234 (defun tinypgp-key-sign-0x-forward (&optional verb)
15235   "Sign current 0x key forward. VERB.
15236 The lines must contain valid key info entry extracted from pubring."
15237   (interactive)
15238   (let (keyid
15239         line)
15240     (error "#todo")
15241     (tinypgpd "tinypgp-key-sign-0x-forward in:")
15242     (ti::verb)
15243
15244     (when (and (ti::mail-pgp-re-search 'kpub)
15245                (setq keyid (match-string 1)))
15246       (setq line (buffer-substring (match-end 0) (line-end-position)))
15247
15248       (if (or (null verb)
15249               (and verb
15250                    (y-or-n-p
15251                     (format "Sign key %s , %s: " line keyid ))))
15252           (tinypgp-save-state-macro
15253            (tinypgp-user-in-use-confirm
15254             (tinypgp-key-sign-1 tinypgp-:user-now keyid)))))))
15255
15256 ;;; ----------------------------------------------------------------------
15257 ;;;
15258 (defun tinypgp-key-mode-set-trust (mode)
15259   "Set the trust MODE on current key/email in the line or point."
15260   (interactive "*r")
15261   (let* ()
15262     (cond
15263      ((eq mode 'undefined))
15264      ((eq mode 'untrusted))
15265      ((eq mode 'marginal))
15266      ((eq mode 'complete)))))
15267
15268 ;;}}}
15269 ;;{{{ PGP main code
15270
15271 ;;; ............................................................. &pgp ...
15272
15273 ;;; ----------------------------------------------------------------------
15274 ;;;
15275 (defun tinypgp-delete-processes (&optional verb)
15276   "Kill all PGP processes found from `process-list'. VERB."
15277   (interactive)
15278   (let* ((count 0))
15279     (ti::verb)
15280     (dolist (elt (process-list))
15281       (when (string-match "pgp" (prin1-to-string elt))
15282         (incf count)
15283         (delete-process elt)))
15284     (if verb
15285         (message "TinyPgp: %d processes deleted" count))
15286
15287     ;; Return t if processes were deleted.
15288     (not (eq count 0))))
15289
15290 ;;; ----------------------------------------------------------------------
15291 ;;;
15292 (defun tinypgp-signature-user-info ()
15293   "Return User's X-Pgp information.
15294
15295 References:
15296   `tinypgp-:xpgp-user-info'
15297
15298 Return:
15299   nil
15300   string"
15301   (let ((ret (if (stringp  tinypgp-:xpgp-user-info)
15302                  tinypgp-:xpgp-user-info
15303                (eval tinypgp-:xpgp-user-info))))
15304     (if (ti::nil-p ret)
15305         nil
15306       ret)))
15307
15308 ;;; ----------------------------------------------------------------------
15309 ;;;
15310 (defun tinypgp-signature-move-to-header (&optional just-delete no-cnv)
15311   "Move Normal PGP signature to email headers.
15312 If there is no PGP signature info, do nothing.
15313 Works for read-only buffers too.
15314
15315 You can call this function only after you have composed the
15316 message and attached the normal PGP signature.
15317
15318 Input:
15319   JUST-DELETE   delete Normal PGP signature: do not move.
15320   NO-CNV        Do not convert '- -' to '-' when deleting old signature."
15321   (tinypgpd "tinypgp-signature-move-to-header in:" just-delete)
15322   (let* (buffer-read-only
15323          (fid           "tinypgp-signature-move-to-header:")
15324          (hlist         tinypgp-:header-sign-smf-info)
15325          (psig          "X-Pgp-Signed")
15326
15327          data
15328          hdr-smf
15329          user-info
15330          sig-fld
15331
15332          sig-list
15333          info-list
15334          fld
15335          str)
15336
15337     (when (and (null just-delete)
15338                (setq data               ;only if there is PGP
15339                      (save-excursion
15340                        (ti::pmin) (ti::mail-pgp-signature-normal-info))))
15341       (setq hdr-smf (if hlist
15342                         (concat
15343                          "SignedHeaders="
15344                          (mapconcat
15345                           'concat
15346                           (nth 1 tinypgp-:header-sign-smf-info)
15347                           ", ")
15348                          ";")))
15349
15350       (tinypgpd fid "DATA" data
15351                 "HDR-SMF" hdr-smf tinypgp-:header-sign-smf-info)
15352       ;;  moving signature in buffer is not really a modification
15353       ;;
15354       (with-buffer-modified
15355         (ti::save-with-marker-macro
15356           (setq info-list (nth 1 data)
15357                 sig-list  (nth 2 data))
15358
15359 ;;;     (setq I info-list S sig-list)
15360 ;;;     (ti::d! I B E)
15361
15362           (tinypgpd  fid "INFO-LIST" info-list "SIG-LIST" sig-list)
15363
15364           (unless just-delete
15365             (setq user-info (tinypgp-signature-user-info))
15366
15367             (dolist (elt info-list)
15368               ;; For each PGP id, we just use that ID as
15369               ;; additional header name.
15370               ;;
15371               (when (string-match "\\(.*\\):[ \t]+\\(.*\\)" elt)
15372                 (setq fld (match-string 1 elt)
15373                       str (match-string 2 elt))
15374
15375                 (if (string-match "Version\\|Charset" fld)
15376                     (setq sig-fld (format "%s%s=%s; "
15377                                           (or sig-fld "")
15378                                           fld str)))))
15379
15380             (setq sig-fld (format "%sSignature=\n" sig-fld))
15381
15382             (dolist (elt sig-list)
15383               ;; Last one Must have terminating colon
15384               ;;
15385               (if (null (cdr sig-list))
15386                   (setq sig-fld (format "%s  \"%s\";\n" sig-fld elt))
15387                 (setq sig-fld (format "%s  \"%s\"\n" sig-fld elt))))
15388
15389             (tinypgpd  fid "SIG-FLD" sig-fld)
15390
15391             (setq str
15392                   (concat (if user-info (concat user-info "\n  " ) " ")
15393                           (if hdr-smf
15394                               ;; Fit in the same line?
15395                               ;;
15396                               (cond
15397                                ((< (+ (length hdr-smf) (length sig-fld))
15398                                    ;;  If there is no user info, then
15399                                    ;;  these fields go directly after
15400                                    ;;  X-Pgp-Signed:  (value 60)
15401                                    ;;
15402                                    (if user-info 77 60))
15403                                 (concat hdr-smf sig-fld "\n  "))
15404
15405                                ((< (length hdr-smf) 40)
15406                                 (concat hdr-smf " \n  " sig-fld))
15407
15408                                (t
15409                                 (concat "\n  " hdr-smf "\n  " sig-fld)))
15410                             sig-fld)))
15411             (ti::mail-add-field psig str)))))
15412
15413     ;;  We can do this without knowing if there is PGP sig,
15414     ;;  The previous statements already got rid of it
15415     ;;  Remove the traditional signature.
15416     ;;
15417     (ti::mail-pgp-signature-remove nil no-cnv)
15418
15419     (tinypgpd fid "out: hooks" tinypgp-:sig-to-header-hook)
15420
15421     (if tinypgp-:sig-to-header-hook
15422         (run-hook-with-args-until-success 'tinypgp-:sig-to-header-hook))))
15423
15424 ;;; ----------------------------------------------------------------------
15425 ;;; The parameter 'delete' is optional, because
15426 ;;; - we may want to convert Headers to INFO block
15427 ;;; - do something when the block is there
15428 ;;;   remove that blocka.
15429 ;;;
15430 ;;; And we don't have no Moving back to headers.
15431 ;;;
15432 (defun tinypgp-signature-from-header (&optional just-delete)
15433   "Convert X-Pgp signature to regular PGP signature.
15434
15435 Input:
15436   JUST-DELETE      do not move but delete header signature info."
15437   (let* ((fid           "tinypgp-signature-from-header:" )
15438          (pbase         "X-Pgp-")
15439          (sig-b-line    (ti::mail-pgp-re  (ti::mail-pgp-signature-begin-line)))
15440          (sig-e-line    (tinypgp-cnv (ti::mail-pgp-signed-end-line)))
15441          buffer-read-only
15442
15443          data
15444          hdr-smf
15445          sig-list
15446          info-list
15447          beg
15448          end)
15449
15450     (tinypgpd fid "in:" "DEL FLAG" just-delete )
15451
15452     (cond
15453      (just-delete
15454       ;;  Old v2.xx x-pgp standard
15455       ;;
15456       (setq sig-list '("^X-Pgp-Charset" "^X-Pgp-Version"
15457                        "^X-Pgp-Signed"  "^X-Pgp-Comment"))
15458       (dolist (elt sig-list) (ti::mail-kill-field elt))
15459       (ti::mail-pgp-signature-remove))
15460
15461      ((setq data (ti::mail-pgp-signature-header-info))
15462       (tinypgpd fid "X-pgp" data)
15463       (ti::save-with-marker-macro
15464         (ti::mail-pgp-signature-remove 'add)
15465         (setq beg       (car (nth 0 data)) ;headers are here
15466               end       (cdr (nth 0 data))
15467               info-list (nth 1 data)
15468               sig-list  (nth 2 data))
15469
15470         (ti::pmin)
15471         (when (setq hdr-smf (tinypgp-header-sign-make-smf 'xpgp))
15472           (ti::mail-text-start 'move)
15473           (forward-line 2)
15474           (insert (car hdr-smf)))
15475         (re-search-forward sig-b-line)
15476
15477         (forward-line 1)
15478         ;; There must be absolutely nothing after it.
15479         ;;
15480         (delete-region (point) (point-max))
15481
15482         (unless just-delete
15483 ;;;       (insert sig-b-line "\n")
15484           (dolist (elt info-list)
15485             (setq elt (replace-regexp-in-string (concat "^" pbase) "" elt))
15486             (insert elt "\n"))
15487
15488           (insert "\n")                 ;blank line
15489           (dolist (elt sig-list) (insert elt "\n"))
15490
15491           (insert sig-e-line "\n"))
15492
15493 ;;;     (ti::d! "DEL" beg end delete)
15494
15495         (if (and beg end)
15496             (delete-region beg end)
15497           ;;  v3.xx has only one heder field
15498           (ti::mail-kill-field "^X-Pgp-signed"))
15499
15500         (run-hooks 'tinypgp-:sig-from-header-hook))))))
15501
15502 ;;; ----------------------------------------------------------------------
15503 ;;;
15504 (defun tinypgp-signature-move-to-header-maybe (&optional verb)
15505   "If current mode is mail or news then move signature to header.
15506 But only if this is not a remailer message.
15507
15508 Input:
15509   VERB      Verbose messages.
15510
15511 References:
15512   `tinypgp-:xpgp-signing-mode'
15513   `tinypgp-:header-sign-table'       ,overrides all"
15514   (tinypgpd "tinypgp-signature-move-to-header-maybe in:")
15515
15516   (let* ((fid   "tinypgp-signature-move-to-header-maybe:")
15517          elt
15518          (tinypgp-:xpgp-signing-mode    ;take local copy
15519           tinypgp-:xpgp-signing-mode)
15520          (allowed  (tinypgp-mail-buffer-p))
15521          (remail   (or (ti::mail-pgp-remail-p)
15522                        tinypgp-:r-mode-indication-flag))
15523
15524          (do-it   tinypgp-:xpgp-signing-mode)
15525          (count   (tinypgp-hash 'sign 'get 'sign-remind-counter nil 'global)))
15526     (tinypgpd fid "ALLOWED" allowed "DO" do-it "REMAIL" remail)
15527
15528     (when (and
15529            allowed do-it
15530            (null remail)
15531            (if (setq elt (tinypgp-header-sign-active-list))
15532                (null (nth 2 elt))   ;if this entry is NIL then proceed
15533              t))
15534
15535       (tinypgp-signature-move-to-header nil 'no-cnv)
15536
15537       (when verb
15538         (unless (integerp count)
15539           (setq count 0)
15540           (tinypgp-hash 'sign 'put 'sign-remind-counter 0 'global))
15541
15542         (incf  count)
15543         ;;
15544         ;;  Display message every 5th time
15545         ;;
15546         (when (eq 0 (% count 5))
15547           (setq count 0)
15548           (message
15549            (concat
15550             "Do not modify buffer, otherwise "
15551             "PGP signature must be generated again.")))
15552         (tinypgp-hash 'sign 'put 'sign-remind-counter count 'global)))
15553     (tinypgpd fid "out:")))
15554
15555 ;;}}}
15556 ;;{{{ secring management
15557
15558 ;;; ......................................................... &secring ...
15559
15560 ;;; ----------------------------------------------------------------------
15561 ;;;
15562 (defun tinypgp-secring-file ()
15563   "Return current backends secring."
15564   (or (cdr (assq (tinypgp-backend-now) tinypgp-:file-secring ))
15565       (error "No secring in tinypgp-:file-secring")))
15566
15567 ;;; ----------------------------------------------------------------------
15568 ;;;
15569 (defun tinypgp-crypt-command-get (from to password)
15570   "Return 'crypt' command for files FROM TO using PASSWORD."
15571   ;;  Store to property so that we don't have to ask it again
15572   ;;
15573   (let* ((fid   "tinypgp-crypt-command")
15574          (sym   'tinypgp-:pgp-binary)
15575          crypt)
15576     (unless (setq crypt (get sym 'crypt))
15577       (setq crypt (or (executable-find "crypt")
15578                       (error "Can't find 'crypt' on `exec-path'.")))
15579       (put sym 'crypt crypt))
15580     (unless (and (stringp from) (stringp to) (stringp password))
15581       (error "Invalid crypt command parameters."))
15582
15583     (tinypgpd fid crypt from to)
15584     (format "%s %s < %s > %s" crypt password from to)))
15585
15586 ;;; ----------------------------------------------------------------------
15587 ;;;
15588 (defun tinypgp-crypt-do-with-pgp (from to password &optional comment)
15589   "Use PGP to conventionally crypt file.
15590
15591 Input:
15592
15593   FROM          source file
15594   TO            destination file
15595   PASSWORD      crypt password
15596   COMMENT       the +comment string. Default is
15597                 'FILE is conventionally encrypted.'
15598                 Set to \"\" if you don't want comment.
15599
15600 Note:
15601
15602   If the FROM file is pgp armored, it will be assumed that it is already
15603   encrypted conventionally and that it should be restored. If the file
15604   has no ascii armor, then it will be crypted.
15605
15606   So, depending on input file, the file is either locked or unlocked.
15607   You don't get double conventional encryption if you specify FROM
15608   as already crypted file."
15609   (let* ((fid       "tinypgp-crypt-do-with-pgp")
15610          (buffer    (tinypgp-ti::temp-buffer 'shell))
15611          (opt       tinypgp-:pgp-command-options)
15612          (pgp-exe   (tinypgp-binary1 'crypt))
15613
15614          ;;  in case there is error these hooks are called to
15615          ;;  restore buffer. But because this function deals with
15616          ;;  files; no emacs buffer is involved. Prevent
15617          ;;  calling these functions.
15618          ;;
15619          tinypgp-:cmd-macro-after-hook
15620          encrypted-p
15621          cmd
15622          err)
15623
15624     (tinypgpd fid "in:" from to "comment:" comment)
15625
15626     (if (not (file-exists-p from))
15627         (error "no FROM file"))
15628
15629     (if (file-exists-p to)
15630         (delete-file to))
15631
15632     (or (stringp comment)
15633         (setq comment
15634               (format "Conventionally crypted %s" from)))
15635
15636     ;;  We have to know if the file is already crypted to select right
15637     ;;  command. We only read part of the file to determine if it has ascii
15638     ;;  armor
15639
15640     (with-current-buffer buffer
15641       (insert-file-contents from nil 0 300)
15642       (setq encrypted-p (ti::mail-pgp-re-search 'msg))
15643       (erase-buffer))
15644
15645     (tinypgpd fid "ENCRYPTED stat" encrypted-p)
15646
15647     ;; cat T     | pgp +comment="Crypted secring.pgp" -caf -z foo > T.asc
15648     ;; cat T.asc | pgp -f -z foo > T
15649
15650     (cond
15651      (encrypted-p
15652       (setq cmd (format
15653                  "%s %s | %s -f -z %s %s +batch > %s "
15654                  (if (ti::win32-p) "type " "cat ")
15655                  from
15656                  pgp-exe
15657                  password
15658                  opt
15659                  to))
15660       (tinypgpd fid "CRYPT --> regular ."))
15661      (t
15662       (setq cmd (format
15663                  "%s %s | %s -caf -z %s %s +batch %s > %s"
15664                  (if (ti::win32-p) "type " "cat ")
15665                  from
15666
15667                  pgp-exe
15668                  password
15669                  opt
15670                  (if (not (ti::nil-p comment))
15671                      (format "+comment=\"%s\"" comment)
15672                    "")
15673                  to))
15674       (tinypgpd fid "REGULAR --> crypt" cmd)))
15675
15676     (setq tinypgp-:last-pgp-exe-command cmd)
15677     (shell-command cmd buffer)
15678     (when (setq err (tinypgp-binary-check-error 'ignore-output))
15679       (tinypgp-error err)
15680       err)))
15681
15682 ;;; ----------------------------------------------------------------------
15683 ;;;
15684 (defun tinypgp-crypt-do-with-crypt (from to password)
15685   "Crypt FROM source TO destination using PASSWORD using 'crypt'."
15686   ;;
15687   ;;  Maybe I add something here later.
15688   ;;  It's too bad that we can't check if the (de)crypting was done
15689   ;;  with right password. The 'crypt' command won't tell success or
15690   ;;  failure so be _sure_ you type it right in the prompt.
15691   ;;
15692   (tinypgpd "tinypgp-crypt-do-with-crypt" from to)
15693   (shell-command (tinypgp-crypt-command-get from to password)))
15694
15695 ;;; ----------------------------------------------------------------------
15696 ;;;
15697 (defun tinypgp-crypt-do (from to password)
15698   "Crypt FROM source TO destination using PASSWORD."
15699   (funcall tinypgp-:secring-crypt-function from to password))
15700
15701 ;;; ----------------------------------------------------------------------
15702 ;;;
15703 (defun tinypgp-ask-secring-password (&optional force)
15704   "Ask secring password. Return old or FORCE asking again."
15705   (let* ((sym   'tinypgp-:hash)
15706          (ret   (get sym 'secring-passwd)))
15707     (when (or force (null ret))
15708       (setq ret (ti::compat-read-password "Password for secring: "))
15709       (put sym 'secring-passwd ret))
15710     ret))
15711
15712 ;;; ----------------------------------------------------------------------
15713 ;;;
15714 (defun tinypgp-secring (&optional set)
15715   "Return secring from memory or set secring from current buffer.
15716 SET can be
15717   'kill    Empty secring from memory
15718   non-nil  read buffer content into memory as secring
15719   nil      return secring from memory."
15720
15721   (cond
15722    ((null set)
15723     (get 'tinypgp-:hash 'secring))
15724    ((eq set 'kill)
15725     (put 'tinypgp-:hash 'secring nil))
15726    (t
15727     (put 'tinypgp-:hash 'secring (buffer-string)))))
15728
15729 ;;; ----------------------------------------------------------------------
15730 ;;;
15731 (defun tinypgp-secring-use ()
15732   "Make sure we have secring available."
15733   (let* ((fid     "tinypgp-secring-use")
15734          (secring (tinypgp-secring-file))
15735          (enc     tinypgp-:file-secring-encrypted)
15736          pass)
15737     (tinypgpd fid)
15738     (when (not (file-exists-p secring)) ;Ahem, it's encrypted...
15739
15740       (if (not (file-exists-p enc)) ;Nope, something is very wrong here
15741           (error "Panic, no secring! Pull out your backup..."))
15742
15743       (cond
15744        ((and (file-exists-p enc)        ;In memory
15745              (tinypgp-secring))
15746         (tinypgpd fid "Write")
15747         (tinypgp-secring-crypt-read nil 'write))
15748        ((and (file-exists-p enc)
15749              (null (tinypgp-secring)))  ;Not in Memory
15750         (tinypgpd fid "read & rrite")
15751         (setq pass (tinypgp-ask-secring-password))
15752         (tinypgp-secring-crypt-read pass)
15753         (tinypgp-secring-crypt-read nil 'write))))))
15754
15755 ;;; ----------------------------------------------------------------------
15756 ;;; Why I dind't use PGP? because I can't control to what file it
15757 ;;; produces the output. It always writes to .pgp or .asc (-a) and
15758 ;;; that not very friendly.
15759 ;;;
15760 (defun tinypgp-secring-crypt (password &optional decrypt)
15761   "Conventionally encrypt secrig with PASSWORD secring.
15762 This function doesn't use PGP, but calls external 'crypt' command.
15763 If DECRYPT is non-nil, move encrypted secring back.
15764
15765 Caution: Make backup first. This fuction deletes or modifies the
15766 secring.pgp !!
15767
15768 References:
15769   `tinypgp-:file-secring-encrypted'"
15770   (interactive
15771    (list
15772     (ti::compat-read-password
15773      (format "[%s] Secring password: "
15774              (if current-prefix-arg "decrypt" "encrypt")))
15775     current-prefix-arg))
15776   (let* ((fid    "tinypgp-secring-crypt")
15777          (from   (if decrypt
15778                      tinypgp-:file-secring-encrypted
15779                    (tinypgp-secring-file)))
15780          (to    (if decrypt
15781                     (tinypgp-secring-file)
15782                   tinypgp-:file-secring-encrypted)))
15783     (tinypgpd fid "in:" decrypt from to)
15784     (if (not (file-exists-p from))
15785         (error "Fatal condition, no file: %s" from))
15786
15787     ;;  If this fails; then we can't execute crypt command that
15788     ;;  overwrites file.
15789     ;;
15790     (if (file-exists-p to)
15791         (delete-file to))
15792
15793     (tinypgp-crypt-do from to password)
15794
15795     (if (interactive-p)
15796         (message "Secring %s"
15797                  (if decrypt
15798                      "decrypted"
15799                    "encrypted")))))
15800
15801 ;;; ----------------------------------------------------------------------
15802 ;;;
15803 (defun tinypgp-secring-crypt-read (&optional password write force)
15804   "Read encrypted secring, open it, and put to to memory.
15805 If file already exists in memory, do nothing.
15806
15807 Input:
15808
15809   PASSWORD  password string
15810   WRITE     write secring from memory to (tinypgp-secring-file)
15811   FORCE     If non-nil force reading encrypted secring to memory"
15812   (let* ((fid       "tinypgp-secring-crypt-read")
15813          (secring   (tinypgp-secring-file))
15814          (from      tinypgp-:file-secring-encrypted)
15815          (to        tinypgp-:file-source))
15816     (tinypgpd fid (if write "WRITE" "READ") force)
15817     (cond
15818      (write
15819       (if (null (setq from (tinypgp-secring)))
15820           (error "Read secring first to memory."))
15821       (with-temp-buffer
15822         (erase-buffer)
15823         (insert from)
15824         (tinypgp-secring 'read-to-memory)
15825         (write-region (point-min) (point-max) secring)))
15826      (t
15827       ;; ........................................................ read ...
15828       (when (or (not (tinypgp-secring))
15829                 (null force))
15830         (unless (file-exists-p from)
15831           (error "There is no encrypted secring."))
15832
15833         (if (file-exists-p to)
15834             (delete-file to))
15835
15836         (tinypgp-crypt-do from to password)
15837
15838         (unwind-protect
15839             (progn
15840               (with-temp-buffer
15841                 (erase-buffer)
15842                 (insert-file-contents to)
15843                 (if (ti::buffer-empty-p)
15844                     (error "No results after opening encrypted secring?"))
15845                 (tinypgp-secring 'read-to-memory)))
15846           (tinypgp-file-control 'source-kill)))))))
15847
15848 ;;; ----------------------------------------------------------------------
15849 ;;;
15850 (defun tinypgp-secring-crypt-maybe ()
15851   "Make encrypted secring if it doesn't exist already."
15852   (unless (file-exists-p (tinypgp-secring-file))
15853     (call-interactively 'tinypgp-secring-crypt)))
15854
15855 ;;; ----------------------------------------------------------------------
15856 ;;;
15857 (defun tinypgp-secring-kill-maybe ()
15858   "Kill secring.pgp if there is encrypted keyring.
15859 `tinypgp-:secring-crypt-mode' must be non-nil too."
15860   (when (and tinypgp-:secring-crypt-mode
15861              (file-exists-p (tinypgp-secring-file)))
15862     (delete-file (tinypgp-secring-file))))
15863
15864 ;;; ----------------------------------------------------------------------
15865 ;;;
15866 (defun tinypgp-secring-restore-maybe ()
15867   "Restore (tinypgp-secring-file) if there is encrypted keyring.
15868 If there already is (tinypgp-secring-file) then do nothing."
15869   (unless (file-exists-p (tinypgp-secring-file))
15870     ;;  - Be sure that there exists encrypted secring in the disk
15871     ;;  - We may have the secring in the memory, but nevertheless
15872     ;;    I must require that is also in disk.
15873     ;;
15874     (when (or (file-exists-p tinypgp-:file-secring-encrypted)
15875               (error "Can't find encrypted scring?"))
15876       (tinypgp-secring-crypt (tinypgp-ask-secring-password) 'restore))))
15877
15878 ;;; ----------------------------------------------------------------------
15879 ;;;
15880 (defun tinypgp-secring-backup (file password &optional verb)
15881   "Backup (tinypgp-secring-file) in crypted format to FILE with PASSWORD.
15882 Previous FILE is deleted. VERB."
15883   (interactive
15884    (progn
15885      (let* ((default-directory (concat (tinypgp-path ".") "/")))
15886        (list
15887         (read-file-name "Backup secring to: ")
15888         (ti::compat-read-password "Backup password: ")))))
15889   (let* ((from  (tinypgp-secring-file)))
15890     (ti::verb)
15891     (unless (file-exists-p from)
15892       (error "There is no secring to be backed up."))
15893     (if (file-exists-p file) (delete-file file))
15894
15895     (prog1
15896         (tinypgp-crypt-do from file password)
15897       (if (not (file-exists-p file))
15898           (error "Couldn't make backup."))
15899       (if verb
15900           (message "TinyPgp: secring backup done.")))))
15901
15902 ;;; ----------------------------------------------------------------------
15903 ;;;
15904 (defun tinypgp-secring-crypt-mode-detect ()
15905   "Set correct `tinypgp-:secring-crypt-mode'."
15906   (if (and tinypgp-:secring-crypt-mode
15907            (not (file-exists-p tinypgp-:file-secring-encrypted)))
15908       (setq tinypgp-:secring-crypt-mode nil))
15909
15910   ;; If mode is off; then this condition must be true
15911   ;; - there must be secring.pgp
15912   ;; - there must not be secring.enc
15913
15914   (if (null tinypgp-:secring-crypt-mode)
15915       (cond
15916        ((file-exists-p tinypgp-:file-secring-encrypted)
15917         (setq tinypgp-:secring-crypt-mode t))
15918        ((or (not (file-exists-p (tinypgp-secring-file) )) ;; .pgp missing
15919             (file-exists-p tinypgp-:file-secring-encrypted)) ;; .enc found
15920         (error "Fatal, no secring.pgp or secring.enc found."))))
15921   tinypgp-:secring-crypt-mode)
15922
15923 ;;; ----------------------------------------------------------------------
15924 ;;;
15925 (defun tinypgp-secring-crypt-expire-password (&optional verb)
15926   "Reset the secring password so that you can change it. VERB.
15927 The password is set once when you turn on crypt mode
15928 with `tinypgp-secring-crypt-mode-toggle' and it never chages during the
15929 lifetime of program.
15930
15931 However if you want to change the password; you must
15932 o  turn off the crypt mode
15933 o  call this function
15934 o  turn on the crypt mode"
15935   (ti::verb)
15936 ;;;  (or (tinypgp-secring-crypt-mode-detect)
15937 ;;;      (error
15938 ;;;       (substitute-command-keys
15939 ;;;        "\
15940 ;;;Can't expire secring password: Use \\[tinypgp-secring-crypt-mode-toggle]")))
15941 ;;;
15942
15943   (let* ((pass (get 'tinypgp-:hash 'secring-passwd)))
15944     (if (stringp pass) (fillarray pass ?\0))
15945     (put 'tinypgp-:hash 'secring-passwd nil)
15946     (when verb
15947       (message "TinyPgp: Secring Password expired."))))
15948
15949 ;;; ----------------------------------------------------------------------
15950 ;;;
15951 (defun tinypgp-secring-crypt-mode-toggle (arg &optional verb)
15952   "Toggle using crypted secring.
15953
15954 Input:
15955
15956    ARG      Mode arg. nil = toggle, 0 = off, 1 = on.
15957    VERB     If non-nil, print verbose messages.
15958
15959 Caution
15960
15961    Before turning on this mode make backup of your keyring removable media.
15962    Prefer ancrypting that backup too, otherwise you have defeated the
15963    purpose of this mode by letting people to access your secring
15964    in some other readable file. See command \\[tinypgp-secring-backup]
15965
15966    See also \\[tinypgp-secring-crypt-expire-password]
15967
15968 Description
15969
15970     When this mode is enabled. You secring is immediately moved to
15971     conventionally encrypted format if it already isn't crypted.
15972     The ecrypted secring is located at `tinypgp-:file-secring-encrypted'
15973     and (tinypgp-secring-file), `Secring' , is deleted.
15974
15975     When programs needs the secring it temporarily opens the encrypted
15976     secring and write to `Secring'. When the PGP operation
15977     that needed secring is over, the `Secring' is removed.
15978
15979     If you are in multi-user environment, be aware that all your files
15980     are propable taped due to regular backups in the file system.
15981     Thus your PGP keys are available to the sysadm.
15982
15983     And even if your're in single user environment, somebody may sit
15984     down to your computer console and copy the secring.pgp withing
15985     seconds.
15986
15987     If you're paranoid at all, you keep this mode permanently on by
15988     setting `tinypgp-:secring-crypt-mode' to t.
15989
15990 Files
15991
15992     When you turn on the mode the `Secring' is deleted and
15993     encrypted `tinypgp-:file-secring-encrypted'. When you turn off this
15994     mode reverse happens and `Secring' is restored.
15995
15996 Note
15997
15998     Turning on or off this mode causes a slight delay because
15999     the command to encyprt or decypt the password is called.
16000
16001     While the mode is active, you cannot use all pgp commands
16002     from the shell command prompt because there is no secring.pgp
16003     directly available. Eg. if you want to generate new key, which
16004     modifies secring; you should turn off this mode to temprarily
16005     reveal secring.pgp.
16006
16007 Return:
16008    value of `tinypgp-:secring-crypt-mode'"
16009   (interactive "P")
16010   (let* ((fid  "tinypgp-secring-crypt-mode-toggle")
16011          old-mode)
16012
16013     (ti::verb)
16014     (tinypgpd fid "in:" arg)
16015     (setq old-mode (tinypgp-secring-crypt-mode-detect))
16016     (ti::bool-toggle tinypgp-:secring-crypt-mode arg)
16017     (tinypgpd fid "ARG" arg "MODE" old-mode tinypgp-:secring-crypt-mode verb)
16018
16019     ;;  If MODE was ON; and we were called with parameter 1,
16020     ;;  then do nothing; because mode hasn't changed.
16021
16022     (when (not (eq old-mode tinypgp-:secring-crypt-mode))
16023       ;;   When mode is turned off
16024       ;;   o   Remove secring from memory, because user may now change it
16025       ;;       on disk.
16026       ;;   When mode is on
16027       ;;   o   Read it from disk to memory. Secring is nor in encrypted
16028       ;;       format on disk.
16029
16030       (cond
16031        (tinypgp-:secring-crypt-mode
16032         ;;  Display messages so that user doesn't get nervous. This
16033         ;;  may take 1-3 seconds.
16034         ;;
16035         (when verb (message "Secring conversion in progress...2"))
16036         (tinypgp-secring-crypt (tinypgp-ask-secring-password))
16037         (tinypgp-secring-kill-maybe)
16038         (when verb (message "Secring conversion in progress...1"))
16039         (tinypgp-secring-crypt-read (tinypgp-ask-secring-password)))
16040        (t
16041         (when verb (message "Secring conversion in progress..."))
16042         (tinypgp-secring-restore-maybe)
16043         ;;  We must delete this
16044         ;;  o  In many places program checks if this exist; but because
16045         ;;     mode is off it should not be used. Safest is to destroy it.
16046         ;;  o  If user starts adding new secret keys; he turns this mode off
16047         ;;     --> he should see just regular secring.pgp and not get confused
16048         ;;     by secring.enc
16049         ;;
16050         (delete-file tinypgp-:file-secring-encrypted)
16051         (tinypgp-secring 'kill))))
16052
16053     (tinypgp-secring-crypt-mode-detect)
16054
16055     (when verb
16056       (message
16057        (concat "TinyPgp: SECRING encrypt mode: "
16058                (if tinypgp-:secring-crypt-mode
16059                    "on" "off")
16060                (if (null tinypgp-:secring-crypt-mode)
16061                    (concat ". "
16062                            (file-name-nondirectory
16063                             (tinypgp-secring-file))
16064                            " restored")))))
16065
16066     (tinypgp-update-modeline)
16067     tinypgp-:secring-crypt-mode))
16068
16069 ;;}}}
16070 ;;{{{ interactive, guess next action
16071
16072 ;;; .................................................... &guess-action ...
16073
16074 ;;; ----------------------------------------------------------------------
16075 ;;; - If you have used vc.el, then you know why this function ....
16076 ;;;
16077 (defun tinypgp-next-action-mail (&optional arg)
16078   "Try to guess next action. ARG is passed to called function.
16079 If buffer has auto action active or if function cannot guess what
16080 to do, this command does nothing.
16081
16082 In mail buffer,
16083
16084 o  If buffer is read-only, try to decrypt it. We suppose that the
16085    buffer is used by some mail reader.
16086 o  -- Check if there is only one email in TO field. If the
16087       user is cached (you have previously encrypted message to him),
16088       then ask permission to encrypt the message.
16089    -- Sign the message
16090
16091 In some other buffer:
16092
16093 o  If not signed, sign.
16094 o  If signed, verify and if that reveals inner folders, open them all.
16095 o  If encrypted, decrypt. (Mail buffers are ignored, because you can't
16096    decrypt other users encrypted message.)
16097
16098 Prefix argument:
16099
16100 o  Is passed to decrypt command"
16101   (interactive "P")
16102   (tinypgpd "tinypgp-next-action-mail in:" arg)
16103   (let ((auto-action-pending (and (not buffer-read-only)
16104                                   (tinypgp-auto-action-p)
16105                                   (tinypgp-hash 'auto-action 'get 'user-mode)))
16106         (fid        "tinypgp-next-action-mail: ")
16107         pring
16108         to
16109         type)
16110
16111     (tinypgpd fid "auto action:" auto-action-pending )
16112
16113     (cond
16114      (auto-action-pending
16115       (message "TinyPgp.el ...note, auto action is pending."))
16116      (t
16117       (cond
16118        ;; ... ... ... ... ... ... ... ... ... ... ... ... ...  regular ..
16119        ((not (ti::mail-mail-p))         ;not a mail buffer
16120         (tinypgpd fid "non-mail buffer start:")
16121
16122         (cond
16123          ((not (ti::mail-pgp-signed-p))
16124           (tinypgpd fid "regular not pgp-signed:")
16125           (tinypgp-sign-region (point-min) (point-max)))
16126
16127          ((ti::mail-pgp-signed-p)
16128
16129           (tinypgpd fid "regular signed:")
16130           (while (or (if (ti::mail-pgp-signed-p) (setq type 'sign))
16131                      (if (ti::mail-pgp-p)        (setq type 'other)))
16132             (tinypgpd fid "regular; envelope" type)
16133
16134             (cond
16135              ((eq type 'sign)
16136               (tinypgp-verify-region (point-min) (point-max)))
16137              ((eq type 'other)
16138
16139               ;;  When we verify message...
16140               ;;  a)  an encrypted message envelope surfaces
16141               ;;  b)  it was base64 signed -> regular text
16142               ;;  c)  signed
16143
16144               (tinypgp-decrypt-region
16145                (point-min) (point-max)
16146                (car (tinypgp-i-args-decrypt)))))))))
16147
16148        ;; ... ... ... ... ... ... ... ... ... ... ... ... ... ... mail ..
16149
16150        ((ti::mail-mail-p)
16151         (setq to (mail-fetch-field "to"))
16152
16153         (tinypgpd fid "mail: to" to
16154                   "see pgp? " (ti::mail-pgp-p)
16155                   "multi ,? " (count-char-in-string ?, (or to "")))
16156
16157         (cond
16158          ((and (not buffer-read-only)
16159                (not (ti::nil-p to))           ;; Must have TO email
16160                (null (ti::mail-pgp-p))        ;; No PGP yet, okay...
16161                (eq (count-char-in-string ?, to) 0) ;; only one email?
16162                (setq to (car-safe (ti::mail-email-from-string to)))
16163                ;;  Have we sent encrypted mail to him?
16164                ;;
16165                (setq pring (tinypgp-key-find-by-cache to)))
16166           (tinypgpd fid "mail: 1 encrypt")
16167           (tinypgp-save-state-macro
16168            (setq tinypgp-:pubring-now pring)
16169            (call-interactively 'tinypgp-encrypt-mail)))
16170
16171          ((and (ti::mail-pgp-signed-p)
16172                (ti::mail-pgp-encrypted-p 'double-check))
16173           (tinypgpd fid "mail: verify/decrypt")
16174           (call-interactively 'tinypgp-verify-mail)
16175           (sit-for 1.7)              ;let user see "Good signature..."
16176           (tinypgp-decrypt-mail-verbose (quote arg)))
16177
16178          ((and (null buffer-read-only)
16179                (not (ti::mail-pgp-headers-p))
16180                (not (ti::mail-pgp-signed-p)))
16181           (tinypgpd fid "mail: sign")
16182           (call-interactively 'tinypgp-sign-mail))
16183
16184          ((and (ti::mail-pgp-signed-p)
16185                (not (ti::mail-pgp-encrypted-p 'message-tag-too)))
16186           (tinypgpd fid "mail: 3")
16187           (call-interactively 'tinypgp-verify-mail))) ;Cond end
16188
16189         ;; .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. ..
16190         ;;
16191         ;;  Still pgp ? Maybe we should decrypt it ?
16192         ;;  But what if this is mail that is meant to be sent to
16193         ;;  someone else --> we assume that non-read-only buffer
16194         ;;  is mail to someone else
16195         ;;
16196         ;;  This is looped two times because:
16197         ;;  - Nym account sends use [ENCRYPT [conventional CRYPT]] envelope
16198         ;;  - Loop1 open CRYPT envelope and the second loop checks
16199         ;;    is there was still real encrypted message (by your nym key)
16200         ;;
16201         ;;  but I don't dare...2 envelopes should suffice.
16202
16203         (while (and buffer-read-only
16204                     (not (ti::mail-pgp-signed-p))
16205                     (ti::mail-pgp-p))
16206           (tinypgpd fid "mail: still pgp")
16207           (tinypgp-decrypt-mail-verbose (quote arg)))
16208
16209         (goto-char (ti::mail-text-start))))))))
16210       ;; ... ... ... ... ... ... ... ... ... ... ... ... ... mail end ..
16211
16212 ;;}}}
16213 ;;{{{ signing
16214
16215 ;;; ......................................................... &signing ...
16216
16217 ;;; ----------------------------------------------------------------------
16218 ;;;
16219 (defun tinypgp-sign-modify-check ()
16220   "Detect if signed message is modified.
16221 References:
16222   `tinypgp-:sign-data'"
16223   (let* ((mail  (ti::mail-mail-p))
16224          (mime  (ti::mail-mime-maybe-p)))
16225     (when (and mail
16226                (not mime)
16227                (ti::mail-pgp-headers-p)
16228                (tinypgp-sign-data-same-p))
16229       (message "TinyPgp: Body changed, signature invalid; resigning...")
16230       (sit-for 0.7)
16231       (tinypgp-sign-loose-info)
16232       (call-interactively 'tinypgp-sign-mail))
16233
16234     (tinypgpd "sign-modify-check:" (current-buffer) "MAIL" mail "MIME"
16235               (ti::mail-message-length)
16236               tinypgp-:sign-data)
16237     ;;  hook return value
16238     nil))
16239
16240 ;;; ----------------------------------------------------------------------
16241 ;;;
16242 (defun tinypgp-sign-mail-auto-p ()
16243   "Check if auto signing would happen."
16244   (and tinypgp-mode
16245        (not (ti::mail-pgp-signed-p))
16246        (not (ti::mail-mime-maybe-p))
16247        (null tinypgp-:r-mode-indication-flag)
16248        (or (null tinypgp-:sign-mail-p-function)
16249            (funcall tinypgp-:sign-mail-p-function))))
16250
16251 ;;; ----------------------------------------------------------------------
16252 ;;;
16253 (defun tinypgp-sign-mail-func ()
16254   "Maybe sign current buffer. This function is called from hooks.
16255 If buffer is already signed or remailer action is in progress,
16256 do nothing.
16257
16258 References:
16259   `tinypgp-:sign-mail-p-function'"
16260   (if (inline (tinypgp-sign-mail-auto-p))
16261       (call-interactively 'tinypgp-sign-mail)))
16262
16263 ;;; ----------------------------------------------------------------------
16264 ;;; on/off function can be used in hooks
16265 ;;;
16266 (defun tinypgp-sign-mail-auto-mode-on ()
16267   "Turn on automatic signing."
16268   (tinypgp-sign-mail-auto-mode 1))
16269
16270 (defun tinypgp-sign-mail-auto-mode-off ()
16271   "Turn off automatic signing."
16272   (tinypgp-sign-mail-auto-mode 0))
16273
16274 ;;; ----------------------------------------------------------------------
16275 ;;;
16276 ;;;###autoload
16277 (defun tinypgp-sign-mail-auto-mode (&optional arg)
16278   "Toggle autosigning mode according to ARG.
16279
16280 Input:
16281   0, -1     off
16282   nil       toggle
16283   t, 1      on
16284
16285   'push-on  Record previous value and turn on  auto signing.
16286   'push-off Record previous value and turn off auto signing.
16287   'pop      pop previous autosign value.
16288
16289 Return:
16290   nil       autosigning off
16291   non-nil   autosigning on"
16292   (interactive)
16293   (let* ((fid           "tinypgp-sign-mail-auto-mode")
16294          (stack         (get 'tinypgp-sign-mail-auto-mode 'stack))
16295          (func          'tinypgp-sign-mail-func)
16296          (hooks         tinypgp-:mail-send-hook-list)
16297          (now-on-p      (tinypgp-sign-mail-auto-mode-on-p))
16298          remove)
16299
16300     (tinypgpd fid arg)
16301
16302     ;; ......................................................... stack ...
16303     (when (and (not (null arg))
16304                (symbolp arg))
16305       (cond
16306        ((eq arg 'push-on)
16307         (push now-on-p stack)
16308         (setq arg 1))
16309
16310        ((eq arg 'push-off)
16311         (push now-on-p stack)
16312         (setq arg 0))
16313
16314        ((eq arg 'pop)
16315         (if (not (ti::listp stack))
16316             (error "Nothing to pop from stack.")
16317           (setq arg (car stack))
16318           (setq stack (cdr stack))))
16319        (t
16320         (error "Not known arg")))
16321       (put 'tinypgp-sign-mail-auto-mode 'stack stack))
16322
16323     (tinypgpd fid arg "STACK" stack)
16324
16325     ;; ...................................................... mode arg ...
16326     (cond
16327      ((null arg)
16328       (if now-on-p
16329           (setq remove t)))
16330
16331      ((memq arg '(0 -1))
16332       (setq remove t)))
16333
16334     (ti::add-hooks hooks func remove)
16335     (tinypgp-update-modeline)
16336
16337     (if (interactive-p)
16338         (message
16339          (format
16340           "TinyPgp: mail auto signing mode %s"
16341           (if remove "off" "on"))))
16342
16343     remove))
16344
16345 ;;; ----------------------------------------------------------------------
16346 ;;;
16347 ;;;###autoload
16348 (defun tinypgp-sign-loose-info (&optional verb)
16349   "Loose signature info.
16350 Input:
16351   VERB          Verbose messages."
16352   (interactive)
16353   (let* (tinypgp-:sig-to-header-hook    ;must be disabled for now
16354          (allow   (tinypgp-mail-buffer-p)))
16355     (ti::verb)
16356     (when (and allow
16357                (ti::mail-pgp-headers-p))
16358       (ti::mail-kill-field "X-Pgp-Signed"))
16359     (ti::save-with-marker-macro
16360       (tinypgp-signature-from-header 'just-delete))
16361
16362     (when (and verb (null allow))
16363       (message "PGP action maybe partially completed...") (sit-for 2))
16364
16365     (run-hooks 'tinypgp-:sign-loose-info-hook)
16366     (if verb
16367         (message "PGP signing information deleted."))
16368     t))
16369
16370 ;;; ----------------------------------------------------------------------
16371 ;;; - parameters BEG and END _must_ be nil
16372 ;;;
16373 ;;;###autoload
16374 (defun tinypgp-sign-mail (&optional register user options verb noxpgp)
16375   "Sign message in mail buffer.
16376
16377 Input:
16378
16379   REGISTER      flag, if non-bil store the signature to register.
16380                 This is the prefix arg user passes to program.
16381                 This will automatically turn off X-pgp.
16382   USER          key-id
16383   VERB          allow verbose messages
16384   NOXPGP        Prohibit X-Pgp
16385
16386 Notes:
16387
16388   if VERB is non-nil (set in interactive call), the pubring is
16389   changed if it the information is on the cache."
16390   (interactive
16391    (progn
16392      (tinypgp-hash 'action 'put 'now    'sign 'global)
16393      (tinypgp-hash 'action 'put 'detail 'mail 'global)
16394
16395      (tinypgpd "tinypgp-sign-mail: interactive")
16396
16397      (tinypgp-user-change-macro
16398       (list
16399        current-prefix-arg
16400        tinypgp-:user-now
16401        (eval tinypgp-:pgp-binary-interactive-option)
16402        t
16403        current-prefix-arg))))
16404
16405   (barf-if-buffer-read-only)
16406   (tinypgp-i-args-pass-phrase)
16407
16408   (let* ((fid               "tinypgp-sign-mail: ")
16409          (tinypgp-:pubring-now tinypgp-:pubring-now)
16410          (signed-p           (ti::mail-pgp-signed-conventional-p))
16411          (signed-xpgp-p      (ti::mail-pgp-signed-xpgp-p))
16412          (signed-multi-p     (ti::mail-pgp-signed-conventional-multi-p))
16413          (mail-p             (ti::mail-mail-p))
16414          (write-point        (point))
16415          beg
16416          write-mark
16417          write-line
16418          write-col
16419          sign-user
16420          buffer
16421          hdr-smf
16422          pring
16423          end)
16424
16425     (ti::verb)
16426     (tinypgp-hash 'action 'put 'now 'sign 'global)
16427     (tinypgp-hash 'action 'put 'detail 'mail 'global)
16428
16429     (tinypgpd fid "signed" signed-p signed-xpgp-p signed-multi-p
16430               "mail-p" mail-p
16431               "User:" user verb
16432               (current-buffer)
16433               (buffer-name))
16434
16435     ;;  Note: It sis very unfortunate that the signature separator
16436     ;;  is "-- ". Thazt extra space will be gone below, because we trim
16437     ;;  the message before signing it.
16438     ;;
16439     ;;  To my opinion it's more important to trim the message than
16440     ;;  preserve trailing spaces at the end of lines.
16441
16442     (tinypgp-add-signature-if-signing)
16443     (ti::mail-trim-buffer)
16444
16445     (ti::mail-pgp-header-kill-in-body)
16446
16447     ;;  Actually; someone else could have signed using X-pgp,
16448     ;;  and when we sign the message, the Right Thing would be
16449     ;;  - check if X-pgp is ours --> remove it. If not, then convert
16450     ;;    it to regular pgp signature.
16451     ;;  - add out signing (if there is regular signature, then
16452     ;;    do ot use X-pgp)
16453
16454     (when signed-xpgp-p (tinypgp-sign-loose-info))
16455
16456     (save-excursion
16457       (goto-char (if mail-p
16458                      (ti::mail-text-start)
16459                    (point-min)))
16460       (setq beg (point)))
16461
16462     (if (or (eq beg (point-max))
16463             (and mail-p                 ;Check only mail buffer
16464                  (save-excursion
16465                    (goto-char (or beg (point-min)))
16466                    ;; there must be text, not just emptly lines
16467                    ;;
16468                    (null (re-search-forward "[^ \t\n]" nil t)))))
16469         (error "Nothing to do, no text found."))
16470
16471     (tinypgp-save-state-macro
16472      ;; Turn this off if buffer is not mail or if there already is signature
16473      (when (or (not mail-p)
16474                signed-p)
16475        (setq tinypgp-:xpgp-signing-mode nil))
16476
16477      (when verb
16478        (if (null (setq pring (tinypgp-key-find-by-cache tinypgp-:user-now)))
16479            (tinypgp-pubring-in-use-confirm)
16480          (setq tinypgp-:pubring-now pring)))
16481
16482      (tinypgpd fid "PRING NOW" tinypgp-:pubring-now pring)
16483
16484      ;; ... ... ... ... ... ... ... ... ... ... ... ...  tmp buffer ...
16485
16486      (tinypgp-mode-specific-control-before 'sign tinypgp-:user-now)
16487
16488      (tinypgp-run-in-tmp-buffer nil
16489                                 (tinypgp-user-change-macro
16490                                  (tinypgp-set-session-parameters 'sign)
16491
16492                                  (goto-char write-point)
16493                                  (setq buffer     (current-buffer)
16494                                        sign-user  tinypgp-:user-now ;Save this value
16495                                        write-mark (point-marker)
16496                                        write-line (ti::read-current-line)
16497                                        write-col  (current-column))
16498                                  ;; ............................................ do signing ...
16499 ;;;       (ti::d! "::sign do" tinypgp-:pubring-now)
16500                                  (tinypgp-cmd-macro-email "sign"
16501                                                           (cond
16502                                                            ((and (ti::mail-mail-p)
16503                                                                  (setq hdr-smf (tinypgp-header-sign-make-smf)))
16504                                                             (goto-char beg)
16505                                                             (insert (car hdr-smf))))
16506
16507                                                           (tinypgp-cmd-macro 'sign user nil
16508                                                                              "Signing..." register options 'no-mode-funcs)
16509
16510                                                           ;;        (pop-to-buffer (current-buffer))  (ti::d! "::sign done")
16511
16512                                                           (tinypgp-signature-move-to-header-maybe verb)
16513                                                           (setq write-point (marker-position write-mark)
16514                                                                 ;; kill marker
16515                                                                 write-mark  nil))))
16516      ;; ........................................... signing end ...
16517
16518 ;;;      (tinypgp-mode-specific-control-after 'sign tinypgp-:user-now nil nil nil)
16519
16520      ;;  - Copy signed data to original buffer.
16521      ;;  - restore original write position: this is tricky because the
16522      ;;    buffer has changed: Search line string and goto column OR
16523      ;;    got to marker position.
16524      ;;
16525      (unless register
16526        (erase-buffer)
16527        (insert-buffer buffer)
16528        (ti::pmin)
16529        (if (and (not (ti::nil-p write-line)) ; can't search empty line
16530                 (search-forward write-line nil 'noerr))
16531            (move-to-column write-col)
16532          ;;  This doesn't necessarily succeed to preserve position,
16533          ;;  but it's better than nothing.
16534          ;;
16535          (goto-char write-point)
16536          ;; If this changes, signing is not valid
16537          (tinypgp-sign-data-set)))
16538
16539      ;; ............................................. verbose message ...
16540      (when verb
16541        (message "%sSigned with key: %s"
16542                 (if register
16543                     (format "[Result in register %c] " tinypgp-:register)
16544                   "")
16545                 sign-user)
16546        (sit-for 1))
16547
16548      t)))
16549
16550 ;;; ----------------------------------------------------------------------
16551 ;;;
16552 (defun tinypgp-sign-mail-base64 (&optional register )
16553   "Uuencode message with pgp.
16554 Store output to `tinypgp-:register' if REGISTER is non-nil.
16555 This function turns off clearsig, so that mail is signed, compressed,
16556 and uuencoded in base64."
16557   (interactive
16558    (progn
16559      (barf-if-buffer-read-only)
16560      (list
16561       current-prefix-arg)))
16562   (tinypgp-i-args-pass-phrase "[Base64] Sign pass phrase: ")
16563   (tinypgp-hash 'action 'put 'now 'sign 'global)
16564   (let* ((beg  (or (ti::mail-text-start) (point-min)))
16565          (end  (point-max)))
16566     (if (eq beg end)
16567         (error "TinyPgp: sign mase64, There is no text in message body."))
16568     (tinypgp-sign-region-base64 beg end register nil (interactive-p))))
16569
16570 ;;; ----------------------------------------------------------------------
16571 ;;;
16572 (defun tinypgp-sign-base64-insert-file (file &optional options)
16573   "Insert uuencoded FILE into point using OPTIONS.
16574 This function inserts the given file into point and turns
16575 off clearsig, so that the file is signed, compressed, and uuencoded
16576 in base64.
16577
16578 It is encouraged that insert big files with this function
16579 to the buffer when you're going to send them via email."
16580   (interactive "*f[base64 sign] Insert file: ")
16581   (let ((buffer (tinypgp-ti::temp-buffer 'finger)) ;This is free for us.
16582         comment
16583         size)
16584     (barf-if-buffer-read-only)
16585     (tinypgp-hash 'action 'put 'now 'sign 'global)
16586     ;;  Hm. This should be interactive part...
16587     ;;
16588     (tinypgp-i-args-pass-phrase)
16589
16590     ;; Insert file leaves point before the file, but we need to know
16591     ;; where it ends...
16592     ;;
16593     (with-current-buffer buffer
16594       (insert-file-contents file)
16595
16596       (unless options
16597         (setq size (/ (buffer-size) 1000)) ;in kilos
16598         (setq
16599          comment
16600          (format
16601           "Base64 signed. File: %s uncompresses to approx. %s"
16602           (file-name-nondirectory file)
16603
16604           (if (eq 0 size)               ;Hm. very small file
16605               (format "%dbytex" (buffer-size))
16606             (format "%dK" size)))))
16607
16608       ;;  In Unix we pass the option directly to pgp.
16609       ;;  This way UNDO can undo whole PGP response at once
16610       ;;
16611       (when (and comment (not (ti::win32-p)))
16612         (setq options (format "+comment=\"%s\"" comment)))
16613
16614       (tinypgp-sign-region-base64 (point-min) (point-max) nil options)
16615
16616       ;;  But in Windows we have to manually patch the genrated output.
16617       ;;  You have to ress twice UNDO to get original text
16618
16619       (when (and comment
16620                  (or (not (tinypgp-backend-pgp2-p))
16621                      (ti::win32-p)))
16622         (tinypgp-binary-header-field-set "Comment:" comment))
16623
16624       (ti::pmin)
16625       (run-hook-with-args-until-success
16626        'tinypgp-:insert-file-sign-base64-hook
16627        file))
16628     (insert-buffer buffer)
16629     ;; It may be big file, don't leave into emacs
16630     (ti::erase-buffer buffer)))
16631
16632 ;;; ----------------------------------------------------------------------
16633 ;;;
16634 (defun tinypgp-sign-region-base64
16635   (beg end &optional register options verb )
16636   "Sign as base64 (uuencode).
16637
16638 Input:
16639
16640  BEG END
16641  REGISTER       if non-nil; then store contents to `tinypgp-:register'
16642  OPTIONS        option string passed to pgp.
16643  VERB           Verbose messages.
16644
16645 This function turns off clearsig, so that region is signed,
16646 compressed, and uuencoded in base64."
16647   (interactive
16648    (progn
16649      (barf-if-buffer-read-only)
16650      (list
16651       (region-beginning) (region-end)
16652       current-prefix-arg)))
16653   (ti::verb)
16654   (barf-if-buffer-read-only)
16655   (tinypgp-i-args-pass-phrase "Region Sign base64 pass phrase:" )
16656
16657   (tinypgp-hash 'action 'put 'now    'sign 'global)
16658   (tinypgp-hash 'action 'put 'detail 'base64 'global)
16659
16660   (let* ((orig-opt options)
16661          (comment
16662           (concat
16663            "base64 signed. "
16664            "run signature verify to to dearmor to clear text. ")))
16665
16666     (when (and (null orig-opt) (not (ti::win32-p)))
16667       (setq options (format "+comment=\"%s\"" comment)))
16668
16669     ;; Add user options to the end
16670     ;;
16671     (setq options (concat "+clearsig=off " options))
16672     (tinypgp-sign-region beg end verb options nil register )
16673
16674     (when (and (null orig-opt) (ti::win32-p))
16675       (tinypgp-binary-header-field-set "Comment:" comment)))
16676
16677   (if (and verb register)
16678       (message
16679        (substitute-command-keys
16680         (format
16681          (concat
16682           "Results in register `%c'. View it with "
16683           "\\[tinypgp-view-register]")
16684          tinypgp-:register)))))
16685
16686 ;;; ----------------------------------------------------------------------
16687 ;;;
16688 (defun  tinypgp-sign-mail-mime  ()
16689   "Sign buffer as PGP/MIME using SEMI or TM.
16690 Function activates mime mode if needed."
16691   (interactive)
16692
16693   (unless (ti::re-search-check mail-header-separator)
16694     (error "Tinypgp: MPGP/MIME Must have mail buffer."))
16695
16696   (tinypgpd "tinypgp-sign-mail-mime: MIME-P" (ti::mail-mime-feature-p))
16697
16698   (when (ti::mail-mime-feature-p)
16699     (ti::mail-mime-turn-on-mode))
16700
16701   (unless (ti::mail-mime-sign-region)
16702     (error "Can't sign PGP/MIME. TM or SEMI is not active."))
16703
16704   (ti::mail-mime-turn-off-mode))
16705
16706 ;;; ----------------------------------------------------------------------
16707 ;;;
16708 (defun tinypgp-sign-mail-detached ()
16709   "Create detached signature to register `tinypgp-:register' using PASSWORD."
16710   (interactive)
16711   (tinypgp-i-args-pass-phrase "Detach sign password: ")
16712   (let* ((beg  (ti::mail-text-start))
16713          (end  (point-max)))
16714     (if (eq beg end)
16715         (error "TinyPgp: sign detached, There is no text in message body."))
16716     (tinypgp-sign-region-detached beg end (interactive-p))))
16717
16718 ;;; ----------------------------------------------------------------------
16719 ;;;
16720 (defun tinypgp-sign-region-detached
16721   (beg end &optional verb options noerr)
16722   "Put detached signature to register `tinypgp-:register'.
16723
16724 Input:
16725
16726   BEG END   region
16727   VERB      verbose messages
16728   OPTIONS   additional option string for PGP
16729   NOERR     do not call error
16730
16731 Note:
16732    If verb is non-nil, correct keyring containing the key is
16733    first set according to `tinypgp-:user-now' before signing."
16734   (interactive
16735    (progn
16736      (if (null (region-active-p))
16737          (error "region not active"))
16738      (list
16739       (region-beginning)
16740       (region-end)
16741       t
16742       nil)))
16743
16744   (let* ((fid "tinypgp-sign-region-detached:"))
16745     (ti::verb)
16746     (tinypgp-i-args-pass-phrase "Region detach sign pass phrase: ")
16747     (tinypgpd fid "in:" beg end verb options noerr)
16748
16749     (tinypgp-hash 'action 'put 'now    'sign   'global)
16750     (tinypgp-hash 'action 'put 'detail 'detach 'global)
16751
16752     ;;  This is an ugly hack, but the previous SIGN options are replaced
16753     ;;  with the new ones. User options are added before -bfast.
16754
16755     (setq options (format "%s %s" (or (eval options) "")
16756                           (if (tinypgp-backend-pgp2-p)
16757                               " -bfast "
16758                             " -b -atv ")))
16759
16760     (set-register tinypgp-:register nil) ;Clear it
16761
16762     (tinypgp-sign-region beg end verb options nil 'register 'as-is)
16763
16764     (if verb
16765         (message "Detached signature in register '%s'"
16766                  (char-to-string tinypgp-:register)))))
16767
16768 ;;; ----------------------------------------------------------------------
16769 ;;;
16770 ;;;###autoload
16771 (defun tinypgp-sign-region
16772   (beg end &optional verb options noerr register as-is)
16773   "Sign region.
16774
16775 Input:
16776
16777   BEG END       ints, region
16778   VERB          flag, verbose messages
16779   OPTIONS       string, flags to add to the real pgp command.
16780   NOERR         flag, return nil or t only
16781   REGISTER      flag, save results to register
16782   AS-IS         flag, if non-nil. no buffer modification is done.
16783                 Normally would delete whitespaces at the end of lines.
16784 "
16785   (interactive
16786    (progn
16787      (barf-if-buffer-read-only)
16788      (if (null (region-active-p))
16789          (error "region not active"))
16790      (list
16791       (region-beginning)
16792       (region-end)
16793       t
16794       nil
16795       nil
16796       current-prefix-arg)))
16797
16798   (let ((fid  "tinypgp-sign-region:")
16799         ret)
16800     (barf-if-buffer-read-only)
16801     (tinypgp-i-args-pass-phrase "Sign region pass phrase:")
16802
16803     (tinypgp-hash 'action 'put 'now 'sign 'global)
16804     (tinypgp-hash 'action 'put 'detail 'region 'global)
16805
16806     (unless as-is
16807       (ti::buffer-trim-blanks beg end)) ;EOL whitespace strip
16808
16809     (tinypgpd fid "in:" beg end verb options)
16810
16811     (tinypgp-save-state-macro
16812      (tinypgp-user-change-macro
16813       (cond
16814        ((null noerr)
16815         (tinypgp-set-pgp-env-macro tinypgp-:user-now 'verb
16816                                    (tinypgp-cmd-macro 'sign tinypgp-:user-now nil
16817                                                       "Signing..." register options))
16818         (setq ret t))
16819
16820        (t
16821         (ignore-errors
16822           (tinypgp-set-pgp-env-macro tinypgp-:user-now 'verb
16823                                      (tinypgp-cmd-macro 'sign tinypgp-:user-now nil
16824                                                         "Signing..." register options))
16825           (setq ret t))))))
16826
16827     (when ret
16828       (tinypgp-key-cache-update)
16829       (tinypgp-sign-data-set))
16830
16831     ret))
16832
16833 ;;}}}
16834 ;;{{{ interactive, verifying
16835
16836 ;;; ....................................................... &verifying ...
16837
16838 ;;; ----------------------------------------------------------------------
16839 ;;;
16840 (defun tinypgp-verify-maybe-fetch-key (status-string)
16841   "If verify fails, asks if we should try to fetch key.
16842
16843 Input:
16844   STATUS-STRING     ,the result of verify
16845
16846 Return:
16847   t                 ,if key fetch tried.
16848   nil"
16849   (let* ((fid  "tinypgp-verify-maybe-fetch-key:")
16850          (tinypgp-:find-by-guess-hook (copy-list tinypgp-:find-by-guess-hook))
16851          key-id)
16852     ;;  We already tried these methods, there is finger
16853     ;;  and http left
16854     (setq tinypgp-:find-by-guess-hook
16855           (delq
16856            'tinypgp-key-find-by-cache
16857            (delq
16858             'tinypgp-key-find-by-keyrings-verbose
16859             tinypgp-:find-by-guess-hook)))
16860
16861     (when (setq key-id
16862                 (ti::string-match "ID \\([^ \t]+\\) not found"
16863                                   1 status-string))
16864
16865       ;; Key matching expected Key ID C4AF0331 not found in file
16866       ;; '/home/xxx/.pgp/pubring.pgp'.
16867
16868       (tinypgpd fid "status" status-string key-id)
16869
16870       (when (y-or-n-p
16871              (format "Can't verify: fetch key for %s ? "
16872                      key-id))
16873         (tinypgp-key-find-by-guess key-id)
16874         t))))
16875
16876 ;;; ----------------------------------------------------------------------
16877 ;;;
16878 (defun tinypgp-verify-region (beg end &optional no-replace verb)
16879   "Verify message in region.
16880
16881 If signature is good and there is some PGP message inside it,
16882 say encrypted to you, then message is replaced
16883 with the output of PGP. In short: message is unpacked.
16884
16885 If there is no PGP, this function does nothing.
16886
16887 Input:
16888
16889   BEG END       region which is feed to PGP. If both are nil, then whole
16890                 buffer is used.
16891
16892   NO-REPLACE    If non-nil prefix argument, the result is put into
16893                 register instead. RBEG and REND are replace position beg
16894                 and end points. They default to BEG and END. These
16895                 arguments are useful if you feed whole buffer to PGP but
16896                 want the replace tho happen only in cerating region.
16897   VERB          Verbose messages
16898
16899 References:
16900   `tinypgp-:verify-before-hook'
16901   `tinypgp-:verify-after-hook'"
16902   (interactive "r")
16903   (tinypgpd "tinypgp-verify-region in:" no-replace verb)
16904
16905   (let* ((cmd       (tinypgp-binary-get-cmd 'verify))
16906          (fid       "tinypgp-verify-region: ")
16907          (sig-holder (ignore-errors
16908                        (or (car-safe
16909                             (ti::mail-email-from-string
16910                              (mail-fetch-field "from")))
16911                            ;;  Maybe this is mail message that user has
16912                            ;;  just signed and he want to varify it himself
16913                            tinypgp-:user-now)))
16914          (do-it        t)
16915          stat
16916          region
16917          pring
16918          msg
16919          ret
16920 ;;;      stat
16921          info)
16922
16923     (ti::verb)
16924
16925     (tinypgp-hash 'action 'put 'now      'verify    'global)
16926     (tinypgp-hash 'action 'put 'no-replace no-replace 'global)
16927
16928     (setq msg (if verb
16929                   "Verifying signature..."
16930                 nil))
16931
16932     (if (null (ti::mail-pgp-p))
16933         (if verb (message "No PGP tags found."))
16934
16935       (run-hook-with-args-until-success
16936        'tinypgp-:verify-before-hook 'verify beg end)
16937
16938       ;;    Because we have our own hooks, we can use the
16939       ;;    command macro, because if we'd call it see what happens:
16940       ;;
16941       ;;    V-B-hook
16942       ;;      macro (macro-B-hook macro-E-hook)
16943       ;;    V-E-hook
16944       ;;
16945       ;;    The macro-E-hook would e.g. cease rmail-edit-mode
16946       ;;    already. That's why we don't use the macro here at all.
16947
16948       (tinypgpd fid "verb sig-holder"  verb sig-holder "BEG" beg end )
16949
16950       (tinypgp-save-state-macro
16951        (when (and verb sig-holder)
16952          (if (or (setq pring (tinypgp-key-find-by-keyrings
16953                               (tinypgp-key-id-conversion sig-holder)))
16954                  ;;   Hmmm, User's email weren't found, find HEX key-id
16955                  ;;   from base64 signature them. This is slower way
16956                  ;;
16957                  (and (setq info (ti::mail-pgp-stream-forward-and-study t))
16958                       (setq sig-holder
16959                             (concat "0x"
16960                                     (ti::mail-pgp-stream-data-elt
16961                                      info 'key-id)))
16962                       (setq pring
16963                             (tinypgp-key-find-by-keyrings
16964                              (tinypgp-key-id-conversion sig-holder)))
16965                       (message "\
16966 Need From addr -- key-id conversion: use `tinypgp-email-substitution-add'")
16967                       (sit-for 5)))
16968              (setq tinypgp-:pubring-now pring)
16969            (tinypgpd fid "--Can't find key-id from keyrings")
16970            (if (null
16971                 (setq
16972                  do-it
16973                  (y-or-n-p
16974                   (format "Can't find %s from keyrings, call pgp anyway?"
16975                           sig-holder))))
16976                (setq stat (format "ID %s not found" sig-holder)))))
16977
16978        ;; .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. . action ..
16979        (when do-it
16980          (tinypgpd fid "DO-IT" cmd beg end (current-buffer))
16981          (setq cmd (tinypgp-cmd-compose cmd nil))
16982          (if (or (tinypgp-backend-pgp2-p)
16983                  (tinypgp-backend-gpg-p))
16984              (setq ret (tinypgp-binary-do-command-region
16985                         cmd beg end (current-buffer) msg 'string))
16986            (setq ret (tinypgp-binary-do-command-region-with-expect
16987                       cmd beg end (current-buffer) msg 'string))))
16988
16989        ) ;;save-state
16990
16991       ;; .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. result . .
16992
16993       ;;  Was it encrypted + signed message? The result removes
16994       ;;  the signature around the region
16995       ;;
16996       (cond
16997        (no-replace
16998         (if verb
16999             (setq ret "Good signature. Results unpacked to register.")))
17000        (t
17001         (cond
17002          ((save-excursion               ;Normal PGP signing
17003             (ti::mail-hmax 'move)
17004             (setq region
17005                   (or
17006                    (ti::mail-pgp-block-area 'signed)
17007                    ;;  Base64 signed then
17008                    (ti::mail-pgp-block-area 'msg)))))
17009          ((and (ti::mail-pgp-headers-p) ;X-Pgp signed message?
17010                (save-excursion
17011                  (ti::mail-text-start 'move)
17012
17013                  ;;  Message is not yet verified if this is found
17014                  ;;
17015                  (not (re-search-forward "^--+BEGIN.*PGP" nil t))))
17016           (setq region (cons (ti::mail-text-start) (point-max))))
17017          (t
17018           (error "\
17019 Cannot find PGP signature. Already verified or signature hidden?")))
17020
17021         (tinypgpd "REGION" region (current-buffer))
17022
17023         (delete-region (car region) (cdr region))
17024         (goto-char (car region) )
17025         (tinypgp-binary-insert-pointer-data ret 'beg)
17026
17027         (setq ret
17028               (tinypgp-binary-get-result-using-function
17029                'tinypgp-binary-get-result-verify))
17030
17031 ;;;     (setq stat (or (tinypgp-binary-get-result-verify-status) ""))
17032         (when (and (null no-replace) (ti::mail-pgp-headers-p))
17033           ;;  We must remove the X-Pgp too.
17034           ;;
17035           (tinypgp-signature-from-header 'just-remove-all))))
17036
17037       (run-hook-with-args-until-success
17038        'tinypgp-:verify-after-hook 'verify beg end ret)
17039
17040       (setq stat (or stat
17041                      (tinypgp-binary-get-result-verify-status)
17042                      ""))
17043       (cond
17044        ((and verb (tinypgp-verify-maybe-fetch-key stat))
17045         nil)                            ;Nothing more to do
17046        (verb
17047         (setq msg (or (tinypgp-binary-get-result-verify-status)
17048                       "<unknown verify status>"))
17049         (if (fboundp tinypgp-:verify-message-function)
17050             (funcall tinypgp-:verify-message-function msg)
17051           (message msg)))))
17052     (tinypgpd fid "out: " ret "stat" stat)
17053
17054     ret))
17055
17056 ;;; ----------------------------------------------------------------------
17057 ;;;
17058 (defun tinypgp-verify-detached-signature (file key-id &optional pring verb)
17059   "Verify detached signature in current buffer against file on disk.
17060
17061 Input:
17062
17063   FILE
17064   KEY-ID    If this string has '@' e.g.  'mister foo <qf@site.com>'
17065             the key-id is automatically shortened to 'qf@site.com'.
17066   PRING     If nil; all pubrings are searched to contain key-id and if none
17067             found, funtion calls error. The found keyring is used to call
17068             pgp with option +pubring
17069   VERB      Verbose messages.
17070
17071 Return:
17072
17073   nbr       PGP error code
17074   nil       verify successfull.
17075
17076 References:
17077   `tinypgp-:buffer-tmp-shell'   pgp response"
17078
17079   (interactive
17080    (let* ((data (ti::mail-pgp-stream-forward-and-study 'search 'any))
17081           (type (car data))
17082           (key-id  (and (eq type  'signed)
17083                         (ti::mail-pgp-stream-data-elt data 'key-id))))
17084      (if (not (stringp key-id))
17085          (error "Can't find key id from PGP stream?")
17086        (setq key-id (concat "0x" key-id)))
17087
17088      (list
17089       (read-file-name "Verify detach signed file: " nil nil t)
17090       key-id)))
17091   (let* ((fid "tinypgp-verify-detached-signature:")
17092          out
17093          status
17094          email)
17095     (ti::verb)
17096     (tinypgp-hash 'action 'put 'now 'verify 'global)
17097     (if (and (string-match "@" key-id)
17098              (setq email (car-safe (ti::mail-email-from-string key-id))))
17099         (setq key-id email))
17100
17101     (tinypgpd fid "in:" file key-id "OPT" pring verb)
17102
17103     (setq file (tinypgp-expand-file-name file))
17104     ;;  First we have to know in what pubring the key is in, because
17105     ;;  PGP needs pubring when it checks the key.
17106     ;;
17107     (or pring
17108         (or (setq pring (tinypgp-key-find-by-cache key-id))
17109             (setq pring (tinypgp-key-find-by-keyrings key-id)))
17110         (error "Can't find '%s' from any pubring." key-id))
17111     (tinypgpd fid "pring" pring)
17112
17113     (setq out    (tinypgp-ti::temp-buffer 'shell))
17114     (save-excursion (ti::pmin) (tinypgp-file-control 'source-write))
17115
17116     ;;  call-process-region
17117     ;;              START END PROGRAM
17118     ;;    &optional DELETE DESTINATION DISPLAY
17119     ;;    &rest     ARGS
17120     ;;
17121     ;;  % pgp sig-file original-file
17122     ;;
17123     (setq
17124      status
17125      (call-process-region (point-min) (point-max) "pgp"
17126
17127                           (not 'text-delete)
17128                           out
17129                           (not 'constant-display)
17130
17131                           tinypgp-:file-source
17132                           file
17133                           (format "+pubring=%s" pring)))
17134     (tinypgp-file-control 'source-kill)
17135
17136 ;;;    (pop-to-buffer (current-buffer)) (ti::d!  orig-file pring)
17137 ;;;    (pop-to-buffer out)
17138
17139     (if verb
17140         (message (or (tinypgp-binary-get-result-verify-status)
17141                      (and (pop-to-buffer out)
17142                           "<unknown verify results>"))))
17143
17144     ;;  Convert 0(pgp ok) to nil(lisp ok) return code
17145     ;;
17146     (if (eq 0 status)
17147         nil
17148       status)))
17149
17150 ;;; ----------------------------------------------------------------------
17151 ;;; - parameters BEG and end _must_ be nil
17152 ;;;
17153 (defun tinypgp-verify-mail (&optional no-replace verb)
17154   "Verify message in mail buffer. See `tinypgp-verify-region' for more details.
17155
17156 Input:
17157   NO-REPLACE    flag, store results to `tinypgp-:register'
17158   VERB          flag, display verbose messages"
17159   (interactive "P")
17160   (let ((fid   "tinypgp-verify-mail:")
17161         hidden
17162         stat)
17163
17164     (ti::verb)
17165     (tinypgp-hash 'action 'put 'now      'verify    'global)
17166     (tinypgp-hash 'action 'put 'no-replace no-replace 'global)
17167
17168     (tinypgpd fid "in:" no-replace verb)
17169
17170     (when (tinypgp-hidden-p)
17171       (tinypgp-hide 'show)
17172       (setq hidden t))
17173
17174     (tinypgp-verify-region
17175      nil nil                     ;it is not a good idea to pass region
17176      no-replace
17177      verb)
17178
17179     (setq stat (or (tinypgp-binary-get-result-verify-status)
17180                    ""))
17181     (when (and (null no-replace)
17182                (ti::mail-pgp-headers-p)
17183                (not (string-match "bad\\|not found" stat)))
17184       ;;  We must remove the X-Pgp signed fields, if the status was ok
17185       ;;
17186       (tinypgp-signature-from-header 'just-delete))
17187
17188     (if hidden
17189         (tinypgp-hide))))
17190
17191 ;;}}}
17192 ;;{{{ interactive, encrypting
17193
17194 ;;; .......................................................... &encypt ...
17195
17196 (defun tinypgp-encrypt-add-remailer-tag ()
17197   "Add' Encrypted: PGP' remailer tag to the point in mail mode buffers."
17198   (if (ti::mail-mail-mode-p)
17199       (insert "::\nEncrypted: PGP\n\n")))
17200
17201 ;;; ----------------------------------------------------------------------
17202 ;;;
17203 (defun tinypgp-encrypt-allowed-check ()
17204   "In certains situations it is not allowed to encrypt the mail message.
17205 Check those cases and call error."
17206   (let* ()
17207     (cond
17208      ((and (tinypgp-nymserver-mail-p)
17209            (or (string-match "," (or (mail-fetch-field  "To") ""))
17210                (mail-fetch-field        "CC")))
17211       (error "\
17212 Impossible to encrypt Nymserver mail to multiple recipients.")))))
17213
17214 ;;; ----------------------------------------------------------------------
17215 ;;;
17216 (defun tinypgp-encrypt-by-cache (string func &rest args)
17217   "If the STRING is found from cache, encrypt with FUNC and ARGS.
17218
17219 Return:
17220   t
17221   nil"
17222   (tinypgpd "tinypgp-encrypt-by-cache: " string func args )
17223   (let* ((pring (tinypgp-key-find-by-cache string)))
17224     ;; # todo: not tested
17225     (when pring
17226       (tinypgp-save-state-macro
17227        (setq tinypgp-:pubring-now pring)
17228        (apply func args)
17229        t))))
17230
17231 ;;; ----------------------------------------------------------------------
17232 ;;;
17233 (defun  tinypgp-encrypt-mail-mime  ()
17234   "Sign buffer as PGP/MIME using SEMI or TM."
17235   (interactive)
17236
17237   (unless (ti::re-search-check mail-header-separator)
17238     (error "Tinypgp: PGP/MIME needs mail buffer."))
17239
17240   (tinypgpd "tinypgp-encrypt-mail-mime: MIME-P" (ti::mail-mime-feature-p))
17241
17242   (when (ti::mail-mime-feature-p)
17243     (ti::mail-mime-turn-on-mode))
17244
17245   (unless (or (not (ti::mail-mime-feature-p))
17246               (ti::mail-mime-encrypt-region))
17247     (error "Can't encrypt PGP/MIME. TM or SEMI is not active."))
17248   (ti::mail-mime-turn-off-mode))
17249
17250 ;;; ----------------------------------------------------------------------
17251 ;;;
17252 (defun tinypgp-encrypt-mail-verbose (&optional arg)
17253   "Call `tinypgp-encrypt-mail' like user would with ARG."
17254   (eval
17255    (`
17256     (tinypgp-encrypt-mail
17257      (,@ (tinypgp-encrypt-mail-i-args arg nil 'bquote))))))
17258
17259 ;;; ----------------------------------------------------------------------
17260 ;;;
17261 (defun tinypgp-encrypt-mail-find-keyring (single &optional sign-pwd)
17262   "Find keyring for SINGLE key-id and encrypt and optionally use SIGN-PWD."
17263   (tinypgp-encrypt-mail single nil sign-pwd nil 'verb))
17264
17265 ;;; ----------------------------------------------------------------------
17266 ;;; - parameters BEG and end _must_ be nil
17267 ;;;
17268 ;;;###autoload
17269 (defun tinypgp-encrypt-mail-sign
17270   (single-or-list &optional no-replace sign-pwd options verb noerr)
17271   "See `tinypgp-encrypt-mail'. Raise parameter 'sign'.
17272 SINGLE-OR-LIST NO-REPLACE SIGN-PWD OPTIONS VERB NOERR."
17273   (interactive (tinypgp-encrypt-mail-i-args
17274                 current-prefix-arg
17275                 'pwd))
17276   (ti::verb)
17277   (tinypgp-encrypt-mail
17278    single-or-list no-replace sign-pwd options verb noerr))
17279
17280 ;;; ----------------------------------------------------------------------
17281 ;;;
17282 (defun tinypgp-encrypt-mail-i-args (&optional arg pwd bquote)
17283   "Read args for `tinypgp-encrypt-mail'.
17284 Input:
17285   ARG        prefix arg
17286   PWD        If non-nil, ask password
17287   BQUOTE     If you call this function in macro which uses ,@ you must
17288              set this flag to non-nil"
17289   (tinypgpd "tinypgp-encrypt-mail-i-args")
17290
17291   (list
17292    (if bquote
17293        ;;  We need to protect this list or else Backquote
17294        ;;  tries to call first element as a function
17295        ;;
17296        (quote (tinypgp-i-args-read-email nil "Encrypt to: "))
17297      (tinypgp-i-args-read-email nil "Encrypt to: "))
17298    (or arg current-prefix-arg)
17299    pwd
17300    (if (null tinypgp-:r-mode-indication-flag)
17301        (eval tinypgp-:pgp-binary-interactive-option))))
17302
17303 ;;; ----------------------------------------------------------------------
17304 ;;; - parameters BEG and end _must_ be nil
17305 ;;;
17306 ;;;###autoload
17307 (defun tinypgp-encrypt-mail
17308   (single-or-list &optional no-replace sign-flag options verb noerr)
17309   "Encrypt mail buffer.
17310
17311 Input:
17312
17313   SINGLE-OR-LIST    List of key-ids. Interactive call reads To,CC,BCC.
17314   NO-REPLACE        prefix arg, store result to `tinypgp-:register'.
17315   SIGN-FLAG         if non-nil, sign at the same time as you encrypt.
17316   OPTIONS           Additional pgp option string.
17317   VERB              If non-nil, verbose messages.
17318   NOERR             If non-nil, do not call error.
17319
17320 Function call note:
17321
17322   [interactive]
17323   In case the EMAIL address you're sending doesn't have entry in your
17324   keyring, but you know that person has a PGP public key, then
17325   please remove the email address prior calling this function and
17326   it will prompt you a string to match for USER.
17327
17328   If this function is called interactively, it tries to set right
17329   pubring by querying cache and other keyrings (user prompted)
17330   Also the `tinypgp-:pgp-binary-interactive-option' is suppressed if
17331   `tinypgp-:r-mode-indication-flag' is non-nil
17332
17333   Normally the To field's address is read and used for encryption.
17334   However, if you are _on_ line that has email address in format
17335   <foo@site.com> then your are asked if you want to use this email
17336   instead. You can complete between this and To address.
17337
17338   [when called as lisp function]
17339   Be sure to take precaution when passing OPTIONS if the message is
17340   sent to remailer. Any extra keyword, like 'Comment:'
17341   may reveal your identity.
17342
17343   SINGLE-OR-LIST is not processed with `tinypgp-key-id-conversion'.
17344   You should call it manually if you want to respect user's
17345   substitution definitions.
17346
17347   [Genenal note]
17348   If there are multiple recipiens in the To, CC, BCC field the
17349   last keyring in the `tinypgp-pubring-table' is used when doing the
17350   encryption.
17351
17352 Input:
17353
17354   single-or-list    list of email addresses or KEY ID's
17355   no-replace        flag, do not replace area with encryption
17356   options           string, extra options passed to pgp exe
17357   verb              flag, allow printing messages."
17358   (interactive (tinypgp-encrypt-mail-i-args current-prefix-arg))
17359   (let* ((fid       "tinypgp-encrypt-mail:")
17360          (beg-text  (ti::mail-text-start))
17361          beg
17362          end
17363          elt)
17364
17365     (ti::verb)
17366     (tinypgp-hash 'action 'put 'now      'encrypt   'global)
17367     (tinypgp-hash 'action 'put 'detail   nil        'global)
17368     (tinypgp-hash 'action 'put 'no-replace no-replace 'global)
17369
17370     (tinypgp-encrypt-allowed-check)
17371
17372     (put 'tinypgp-:return-value 'find-by-keyrings nil) ;reset
17373
17374     (tinypgpd "tinypgp-encrypt-mail in: "
17375               single-or-list
17376               "no-rep"  no-replace
17377               "1pass"   sign-flag
17378               "options" options
17379               "verb"    verb
17380               "BEG" beg (point-max))
17381
17382     (unless single-or-list
17383       (error "single-or-list is empty"))
17384
17385     (if (eq beg-text (point-max))
17386         (error "Nothing to do, no text found."))
17387
17388     (setq single-or-list (tinypgp-user-list single-or-list))
17389
17390     ;; .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. ..  do it . .
17391     (setq single-or-list (ti::list-make single-or-list))
17392
17393     (tinypgp-cmd-macro-email "Encrypt"
17394                              (tinypgp-set-pgp-env-macro single-or-list 'verb
17395
17396                                                         ;;  See the tinypgp-key-find-by-keyrings function.
17397                                                         ;;  Effective encrypt key may have changed
17398
17399                                                         (when (setq elt (get 'tinypgp-:return-value 'find-by-keyrings))
17400                                                           (tinypgpd "tinypgp-encrypt-mail: KEY CHANGED " elt )
17401                                                           (setq single-or-list (ti::list-make elt)))
17402
17403                                                         ;;  Beacuse the Encrypt and signing is done
17404                                                         ;;  in 'One pass' both keys must be in same pubring.
17405
17406                                                         (when sign-flag
17407                                                           (tinypgpd fid "1pass: PUBRING CHANGED TO BIG")
17408                                                           (tinypgp-hash 'action 'put '1pass nil 'global)
17409                                                           (tinypgp-pubring-set-big))
17410
17411                                                         ;; single-or-list will be changed if it is nil.
17412                                                         ;; --> user login name
17413
17414                                                         (tinypgp-cmd-macro
17415                                                          (if sign-flag 'encrypt-sign 'encrypt)
17416                                                          single-or-list
17417                                                          nil
17418                                                          "Encrypting...." no-replace options)
17419
17420                                                         ;; If all went ok, then we update cache, user XXX in in pubring YYY
17421                                                         ;; All users must be in same pubring otherwise the previous command
17422                                                         ;; didn't succeed.
17423
17424                                                         (dolist (elt single-or-list)
17425                                                           (when (stringp elt)
17426                                                             (tinypgp-key-cache 'put elt tinypgp-:pubring-now)))))
17427
17428     ;; .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. . results . .
17429
17430     (when (and (null no-replace)
17431                (null buffer-read-only)
17432                tinypgp-:encrypt-after-function)
17433       (if (ti::mail-mail-p)
17434           (goto-char (ti::mail-text-start)) ;ignore other buffers
17435         (ti::pmin))
17436
17437       (ti::save-with-marker-macro
17438         (funcall tinypgp-:encrypt-after-function)))
17439
17440     (when verb
17441       (message
17442        "%d: Encrypted to %s %s"
17443        (length single-or-list)
17444        (ti::list-to-string single-or-list)
17445        (if (null sign-flag) ""
17446          (format "and signed [%s]" tinypgp-:user-now)))
17447       ;;  Make sure this is seen
17448       (sleep-for 2))))
17449
17450 ;;; ----------------------------------------------------------------------
17451 ;;;
17452 (defun tinypgp-encrypt-region-i-args (&optional pwd)
17453   "Ask arguments for `tinypgp-encrypt-region-i-args' possibly also asking PWD."
17454   (ti::list-merge-elements
17455    (tinypgp-i-args-reg-email "Encrypt to: ")
17456    current-prefix-arg
17457    (if pwd (tinypgp-password-set
17458             (format "[%s] Sign password: " tinypgp-:user-now)))
17459    (if (null tinypgp-:r-mode-indication-flag)
17460        (eval tinypgp-:pgp-binary-interactive-option))))
17461
17462 ;;; ----------------------------------------------------------------------
17463 ;;;
17464 ;;;###autoload
17465 (defun tinypgp-encrypt-region-sign
17466   (beg end user &optional no-replace sign-pwd options verb)
17467   "Same as `tinypgp-encrypt-region' but raise 'sign' parameter.
17468 BEG END USER NO-REPLACE SIGN-PWD OPTIONS VERB"
17469   (interactive (tinypgp-encrypt-region-i-args 'pwd))
17470   (ti::verb)
17471   (tinypgp-encrypt-region
17472    beg end user no-replace sign-pwd options verb))
17473
17474 ;;; ----------------------------------------------------------------------
17475 ;;;
17476 ;;;###autoload
17477 (defun tinypgp-encrypt-region
17478   (beg end user &optional no-replace sign-pwd options verb)
17479   "Encrypt region.
17480
17481 Input:
17482
17483   BEG END       region
17484   USER          key-id (possibly email) or list of keyIds.
17485   NO-REPLACE    prefix arg, store results to `tinypgp-:register'
17486   SIGN-PWD      if non-nil string, Sign at the same time as you encrypt.
17487   OPTIONS       Additional option string for PGP.
17488   VERB          If non-nil, Verbose messages."
17489   (interactive (tinypgp-encrypt-region-i-args))
17490   (tinypgpd "tinypgp-encrypt-region in:"
17491             beg end user "replace" no-replace options verb)
17492
17493   (ti::verb)
17494   (tinypgp-encrypt-allowed-check)
17495   (tinypgp-password-set (format "[%s] Encrypt password: " tinypgp-:user-now))
17496
17497   (tinypgp-hash 'action 'put 'now               'encrypt    'global)
17498   (tinypgp-hash 'action 'put 'no-replace        no-replace  'global)
17499
17500   (setq user (tinypgp-user-list user))
17501
17502   (tinypgp-set-pgp-env-macro user 'verb
17503                              (tinypgp-cmd-macro
17504                               (if sign-pwd 'encrypt-sign 'encrypt )
17505                               user
17506                               sign-pwd
17507                               "Encrypting...." no-replace options))
17508
17509   ;; If all went ok, then we update cache, use XXX in in pubring YYY
17510   (tinypgp-key-cache-update (car (ti::list-make user))))
17511
17512 ;;; ----------------------------------------------------------------------
17513 ;;;
17514 (defun tinypgp-encrypt-info  (&optional register verb)
17515   "Check encrypted message and who can read it.
17516 If Flag REGISTER is non-nil store results to `tinypgp-:register'. VERB."
17517   (interactive)
17518   (let* ((user tinypgp-:user-primary)
17519          ptr
17520          list
17521          str
17522          beg
17523          end)
17524     (ti::verb)
17525     (ignore-errors                      ;We know this generates error.
17526       (tinypgp-set-pgp-env-macro user 'verb
17527                                  (tinypgp-cmd-macro
17528                                   'encrypt-info
17529                                   user
17530                                   nil
17531                                   "Checking encrypt users...." 'no-replace (not 'options))))
17532     (setq ptr (tinypgp-binary-get-result-encrypt-info))
17533
17534     (cond
17535      ((null ptr)
17536       (message
17537        "TinyPgp: Can't find list of encrypt users. Maybe not encrypted."))
17538      (register
17539       (with-current-buffer (car ptr)
17540         (set-register tinypgp-:register
17541                       (buffer-substring (nth 1 ptr) (nth 2 ptr))))
17542       (if verb
17543           (message "Encrypt info in register '%s'"
17544                    (char-to-string tinypgp-:register))))
17545      (t
17546       (setq list (tinypgp-binary-get-result-encrypt-info-list ptr)
17547             str  (ti::list-to-string list ","))
17548
17549       (if (< (length str) 75)
17550           (message "Encrypt: %s" str)
17551         ;;  Hm, Doesn't fit in echo area, so display in another window
17552         (tinypgp-ti::temp-buffer 'show)
17553         (display-buffer tinypgp-:buffer-tmp-show)
17554         (with-current-buffer (car ptr)
17555           (append-to-buffer tinypgp-:buffer-tmp-show
17556                             (nth 1 ptr) (nth 2 ptr))))))))
17557
17558 ;;}}}
17559 ;;{{{ interactive, decrypting
17560
17561 ;;; .......................................................... &decypt ...
17562
17563 ;;; ----------------------------------------------------------------------
17564 ;;;
17565 (defun tinypgp-decrypt-signed-base64
17566   (beg end user &optional no-replace verb)
17567   "Decrypt conventinally signed but base64 coded text.
17568
17569 Input:
17570
17571   BEG END       region
17572   USER          key-id string (possibly email)
17573   NO-REPLACE    store results to `tinypgp-:register'
17574   VERB          Verbose messages."
17575   (let* ((fid  "tinypgp-decrypt-signed-base64: ")
17576          pointer
17577          file-out
17578          file-write)
17579
17580     (ti::verb)
17581     (tinypgp-hash 'action 'put 'now 'decrypt 'global)
17582     (setq file-out (ti::mail-pgp-comment-file-p beg))
17583
17584     (tinypgpd fid "in:" beg end user no-replace verb)
17585
17586     (when file-out
17587       (setq
17588        file-write
17589        (read-file-name
17590         "Base64 block save contents to file: "
17591         nil (concat default-directory file-out) nil file-out))
17592       (cond
17593        ((ti::nil-p file-write)
17594         (setq file-write nil))
17595
17596        ((not (file-exists-p (file-name-directory file-write)))
17597         (error "No such directory %s" file-write))
17598
17599        ((file-exists-p file-write)
17600         (if (y-or-n-p "File exists, overwrite?")
17601             (delete-file file-write)
17602           (error "Abort.")))))
17603
17604     (if file-write
17605         (setq no-replace t))
17606
17607     (tinypgp-cmd-macro 'decrypt-base64 user nil "Decrypting..." no-replace)
17608
17609     ;; The result of PGP is not delimited by any
17610     ;; --- TAG, so we cannot request replace now, but read the contents
17611     ;; by hand first
17612     ;;
17613     (with-current-buffer tinypgp-:buffer-tmp-shell
17614       (setq   pointer (tinypgp-binary-get-result-base64))
17615       (unless pointer (tinypgp-error "No output from PGP.")))
17616
17617     (cond
17618      (file-write
17619       (with-current-buffer (tinypgp-ti::temp-buffer)
17620         (tinypgp-binary-insert-pointer-data pointer)
17621         (write-region (point-min) (point-max) file-write)
17622         (erase-buffer))
17623       (message "Wrote %s" file-write))
17624      (no-replace
17625       (set-register tinypgp-:register
17626                     (tinypgp-binary-get-result-as-string pointer)))
17627      (t
17628       (delete-region beg end)
17629       (tinypgp-binary-insert-pointer-data pointer)))))
17630
17631 ;;; ----------------------------------------------------------------------
17632 ;;;
17633 (defun tinypgp-decrypt-arg-function (arg)
17634   "See how we should interpret the passed prefix ARG.
17635 If buffer is read-only, then assume, that it may be MAIL buffer
17636 or the like and honor the variable `tinypgp-:decrypt-arg-interpretation'
17637
17638 If buffer is not read-only. return ARG as is."
17639   (if (not buffer-read-only)            ;regular buffer
17640       arg
17641
17642     ;; This may be MAIL buffer, because it is read only,
17643     ;; see how user want the arg to be intepreted.
17644
17645     (if (null tinypgp-:decrypt-arg-interpretation)
17646         arg                             ;as is
17647       (if arg                           ;reverse sense
17648           nil
17649         tinypgp-:decrypt-arg-interpretation))))
17650
17651 ;;; ----------------------------------------------------------------------
17652 ;;;
17653 (defun tinypgp-decrypt-mail-verbose (&optional prefix-arg)
17654   "Call `tinypgp-decrypt-mail' like user would with PREFIX-ARG."
17655   ;;  Loonks cryptic? Not really, because i-args returns a
17656   ;;  list and tinypgp-decrypt-mail needs individual args,
17657   ;;  we use eval + backquote to construct command that
17658   ;;  turns list into individual args before
17659   ;;  it calls tinypgp-decrypt-mail.
17660   ;;
17661   ;;  Got it? No? Then you must learn backquote syntax first.
17662   ;;
17663   (eval
17664    (` (tinypgp-decrypt-mail
17665        (,@ (tinypgp-decrypt-mail-i-args prefix-arg))))))
17666
17667 ;;; ----------------------------------------------------------------------
17668 ;;;
17669 (defun tinypgp-decrypt-mail-i-args (&optional arg)
17670   "Ask args to function `tinypgp-decrypt-mail'.
17671 ARG passed can be `current-prefix-arg' if that is known."
17672   (tinypgpd "tinypgp-decrypt-mail-i-args: ")
17673   (tinypgp-hash 'action 'put 'now 'decrypt 'global)
17674
17675   (if (null (ti::mail-pgp-p))
17676       (error "Nothing to do. No pgp found."))
17677
17678   (list
17679    (funcall tinypgp-:pgp-decrypt-arg-function arg)
17680    (tinypgp-i-args-decrypt)
17681    ;; c-point
17682    nil))
17683
17684 ;;; ----------------------------------------------------------------------
17685 ;;;
17686 ;;;###autoload
17687 (defun tinypgp-decrypt-mail (&optional no-replace type verb)
17688   "Decrypt mail buffer.
17689 The PGP data in the buffer is detected by reading the CTB bits:
17690 see pgpformat.doc in pgp documentation.
17691
17692 Input:
17693
17694   NO-REPLACE    flag, prefix arg instructs to show the cotent in
17695                 separate buffer. See refrerence note too.
17696                 If this is 'preview and verb argument is nil-nil,
17697                 then automatically show content is different buffer.
17698
17699   TYPE          nil or \"pgp\" --> PGP encrypted
17700                 \"base64\" --> base64 signed and
17701                 \"conventional\" --> encrypted with conventional key.
17702
17703   VERB          Verbose mode.
17704
17705 References:
17706
17707   `tinypgp-:pgp-encrypted-p-function'
17708   `tinypgp-:decrypt-arg-interpretation'     for interactive calls
17709   `tinypgp-:pgp-decrypt-arg-function'     for interactive calls
17710   `tinypgp-:user-identity-table'"
17711
17712   (interactive (tinypgp-decrypt-mail-i-args current-prefix-arg))
17713   (tinypgpd "tinypgp-decrypt-mail in:" no-replace type verb)
17714
17715   (let* ((fid       "tinypgp-decrypt-mail:")
17716          (region    (save-excursion (ti::pmin) (ti::mail-pgp-block-area 'msg)))
17717          (beg       (car-safe region))
17718          (end       (cdr-safe region))
17719          (buffer    (current-buffer))
17720          stat)
17721
17722     (ti::verb)
17723
17724     (tinypgp-hash 'action 'put 'now      'decrypt   'global)
17725     (tinypgp-hash 'action 'put 'type     type       'global)
17726     (tinypgp-hash 'action 'put 'no-replace no-replace 'global)
17727
17728     (if (null region)
17729         (error "No PGP encrypt block found."))
17730
17731     (tinypgp-save-state-macro
17732      (tinypgpd fid "user" tinypgp-:user-now)
17733
17734      ;; ... ... ... ... ... ... ... ... ... ... ...  normally encrypted ...
17735
17736      (cond
17737       ((member type '("conventional" "pgp"))
17738        (tinypgp-save-state-macro
17739         (tinypgp-user-change-macro
17740          (tinypgp-cmd-macro-email "Decrypt"
17741                                   (tinypgp-decrypt-region beg end no-replace type verb)))))
17742
17743       ;; ... ... ... ... ... ... ... ... ... ... ... ... ... ... base64  ..
17744
17745       ((member type '("base64"))
17746
17747        (when no-replace
17748          (setq buffer (tinypgp-ti::temp-buffer))
17749          (append-to-buffer buffer beg end))
17750
17751        (with-current-buffer buffer
17752
17753          ;; There may be several blocks, open them all.
17754          ;; This is the first one.
17755
17756          (tinypgp-decrypt-signed-base64 beg end nil no-replace)
17757          (while (and (setq region
17758                            (save-excursion
17759                              (goto-char end)
17760                              (ti::mail-pgp-block-area 'msg)))
17761                      (setq beg (car region) end (cdr region)))
17762            (tinypgp-decrypt-signed-base64 beg end nil no-replace))))
17763       (t
17764        (error "Unkown decrypt type '%s'" type))))
17765
17766     (goto-char (ti::mail-text-start))
17767
17768     ;;    The message may have been encrypted and signed (one pass).
17769     ;;    Check it too.
17770
17771     (when (and verb
17772                (setq stat (tinypgp-binary-get-result-verify-status)))
17773       (message "[was signed] %s" stat))
17774
17775     (tinypgp-hash 'action 'put 'type nil 'global) ;Clear this
17776     (tinypgpd "tinypgp-decrypt-mail out: user" tinypgp-:user-now)))
17777
17778 ;;; ----------------------------------------------------------------------
17779 ;;;
17780 ;;;###autoload
17781 (defun tinypgp-decrypt-region (beg end &optional no-replace type verb)
17782   "Decrypt region. Signal error is there is no decrypt message.
17783
17784 Input:
17785
17786   BEG END       int, region
17787   NO-REPLACE    flag, store contents to `tinypgp-:register'.
17788                 If values is 'review and verb is non-nil, also display
17789                 content in separate buffer. Calls `tinypgp-view-register'
17790   TYPE          string, Decrypt type: conventional, base64 or pgp
17791   VERB          flag, verbose messages"
17792   (interactive
17793    (progn
17794      (tinypgpd "tinypgp-decrypt-region interactive")
17795      (ti::list-merge-elements
17796       (ti::i-macro-region-body)
17797       current-prefix-arg
17798       'iact
17799       (tinypgp-i-args-decrypt))))
17800
17801   (let* ((fid  "tinypgp-decrypt-region")
17802          user)                          ;Must be defined due to macro
17803
17804     (tinypgpd fid "in:" beg end no-replace type verb (current-buffer))
17805
17806     (tinypgp-hash 'action 'put 'now     'decrypt    'global)
17807     (tinypgp-hash 'action 'put 'type     type       'global)
17808     (tinypgp-hash 'action 'put 'no-replace no-replace 'global)
17809
17810     (if (null (save-excursion (ti::pmin) (ti::mail-pgp-block-area 'msg)))
17811         (error "No PGP encrypt block found."))
17812
17813     (tinypgpd fid "in:" beg end no-replace verb)
17814     (tinypgp-cmd-macro 'decrypt user  nil "Decrypting..." no-replace)
17815
17816     (when (and no-replace verb)
17817       (or (get-buffer-window tinypgp-:buffer-view t) ;already visible
17818           (eq no-replace 'preview)
17819           (y-or-n-p "View content in temp buffer? "))
17820       (tinypgp-view-register))
17821
17822     (tinypgp-hash 'action 'put 'type nil 'global)))
17823
17824 ;;}}}
17825 ;;{{{ interactive: regular crypting
17826
17827 ;;; ............................................................ &cypt ...
17828
17829 ;;; ----------------------------------------------------------------------
17830 ;;;
17831 ;;;###autoload
17832 (defun tinypgp-crypt-mail (password &optional no-replace comment verb)
17833   "Crypt mail buffer.
17834
17835 Input:
17836
17837   PASSWORD      pass phrase
17838   NO-REPLACE    store contents to `tinypgp-:register'.
17839   COMMENT       Additional comment added
17840   VERB          verbose messages"
17841   (interactive
17842    (list
17843     (ti::compat-read-password "Crypt password: ")
17844     current-prefix-arg))
17845   (let* ((beg  (ti::mail-text-start))
17846          (end  (point-max))
17847          (verb (or verb (interactive-p))))
17848     (tinypgp-hash 'action 'put 'now 'crypt 'global)
17849     (tinypgp-crypt-region beg end password no-replace comment verb)))
17850
17851 ;;; ----------------------------------------------------------------------
17852 ;;;
17853 ;;;###autoload
17854 (defun tinypgp-crypt-region
17855   (beg end password &optional no-replace comment verb)
17856   "Crypt region.
17857
17858 Input:
17859
17860   BEG END       region
17861   PASSWORD      pass phrase
17862   NO-REPLACE    store contents to `tinypgp-:register'.
17863   COMMENT       The comment string.
17864   VERB          verbose messages"
17865   (interactive
17866    (progn
17867      (barf-if-buffer-read-only)
17868      (ti::i-macro-region-body
17869        (read-from-minibuffer "Crypt password: ")
17870        current-prefix-arg
17871        "")))
17872
17873   (let* ((obuffer (current-buffer)))
17874     (tinypgp-hash 'action 'put 'now 'crypt 'global)
17875
17876     (with-current-buffer (tinypgp-ti::temp-buffer)
17877       (insert-buffer-substring obuffer beg end)
17878       (ti::pmin) (tinypgp-file-control 'source-write)
17879
17880       (tinypgp-crypt-do-with-pgp
17881        tinypgp-:file-source tinypgp-:file-output password (or comment ""))
17882
17883       (cond
17884        (no-replace
17885         (erase-buffer)
17886         (insert-file-contents tinypgp-:file-output)
17887         (set-register tinypgp-:register (buffer-string)))
17888        (t
17889         (with-current-buffer obuffer
17890           (delete-region beg end) (goto-char beg)
17891           (insert-file-contents tinypgp-:file-output)))))
17892     (tinypgp-file-control 'source-kill)))
17893
17894 ;;}}}
17895 ;;{{{ interactive, extra, header toggle
17896
17897 ;;; ..................................................... &interactive ...
17898
17899 ;;; ----------------------------------------------------------------------
17900 ;;;
17901 ;;;###autoload
17902 (defun tinypgp-xpgp-header-mode-toggle (&optional arg)
17903   "Toggle X-pgp header mode with ARG.
17904
17905 References
17906   `tinypgp-:header-sign-table'     ,this variable overrides the signing mode."
17907   (interactive "P")
17908   (ti::bool-toggle tinypgp-:xpgp-signing-mode arg)
17909   (if (interactive-p)
17910       (message
17911        (concat "TinyPgp: X-Pgp header mode: "
17912                (if tinypgp-:xpgp-signing-mode
17913                    "on" "off"))))
17914
17915   (tinypgp-update-modeline)
17916   tinypgp-:xpgp-signing-mode)           ;return the changed value
17917
17918 ;;; ----------------------------------------------------------------------
17919 ;;;
17920 ;;;###autoload
17921 (defun tinypgp-xpgp-header-toggle ()
17922   "Togle moving signature FROM/TO headers."
17923   (interactive)
17924   (cond
17925    ((null (tinypgp-mail-buffer-p 'message)))
17926    (t
17927     (ti::save-line-column-macro nil nil ;preserve user's position
17928       (with-buffer-modified
17929         (cond
17930          ((ti::mail-pgp-headers-p)
17931           (tinypgp-signature-from-header))
17932          ((ti::mail-pgp-normal-p)
17933           (tinypgp-signature-move-to-header nil 'no-cnv))
17934          (t
17935           (message "No PGP signature found..."))))))))
17936
17937 ;;; ----------------------------------------------------------------------
17938 ;;;
17939 (defun tinypgp-hide-gnus (&optional unhide)
17940   "Hide or UNHIDE pgp signature in GNUS."
17941   (let* ((buffer (if (boundp 'gnus-article-buffer)
17942                      ;; Silence byteComp.
17943                      (symbol-value 'gnus-article-buffer))))
17944     (when (stringp buffer)
17945       (with-current-buffer buffer
17946         (tinypgp-hide)))))
17947
17948 ;;; ----------------------------------------------------------------------
17949 ;;;
17950 (defun tinypgp-hide (&optional unhide)
17951   "Hide PGP signatures, optionally UNHIDE."
17952   (ti::mail-pgp-signature-normal-do-region
17953    (tinypgp-invisible-region area-beg area-end  unhide)
17954    ;; return value on success
17955    t))
17956
17957 ;;; ----------------------------------------------------------------------
17958 ;;;
17959 (defun tinypgp-show ()
17960   "Show PGP signature."
17961   (tinypgp-hide 'show))
17962
17963 ;;; ----------------------------------------------------------------------
17964 ;;;
17965 ;;;###autoload
17966 (defun tinypgp-hide-show-toggle ()
17967   "Togle hiding and showing the PGP signature."
17968   (interactive)
17969   (let* (ret)
17970     (setq ret
17971           (if (tinypgp-hidden-p)
17972               (tinypgp-show)
17973             (tinypgp-hide)))
17974     (if (and (interactive-p)
17975              (null ret))
17976         (message "No signature found to un/hide"))))
17977
17978 ;;}}}
17979 ;;{{{ interactive, keyserver submit
17980
17981 ;;; ................................................ &keyserver-submit ...
17982
17983 ;;; ----------------------------------------------------------------------
17984 ;;;
17985 (defun tinypgp-keysrv-send-email-command (email command &optional arg)
17986   "Send to EMAIL address a keyserver COMMAND with ARG.
17987 The COMMAND is placed in the subject line. If command is 'add' then
17988 the current buffer is sent to keyserver.
17989
17990 See keyserver documentation for more up to date command definitions:
17991
17992 Command                Message body contains
17993 --------------------------------------------------------------------
17994 ADD            Your PGP public key (key to add is body of msg) (-ka)
17995 INDEX          List all PGP keys the server knows about (-kv)
17996 VERBOSE INDEX  List all PGP keys, verbose format (-kvv)
17997 GET            Get the whole public key ring (-kxa *)
17998 GET <userid>   Get just that one key (-kxa <userid>)
17999 MGET <userid>  Get all keys which match <userid>
18000 LAST <n>       Get all keys uploaded during last <n> days
18001 --------------------------------------------------------------------"
18002   (interactive
18003    (let* ((obuffer  (current-buffer))
18004           arg1
18005           arg2
18006           arg3
18007           elt)
18008      (setq arg1 (tinypgp-ask-email-keyserver))
18009      (setq arg2 (completing-read
18010                  "Send command: "
18011                  (ti::list-to-assoc-menu
18012                   '("help" "add" "index" "verbose index" "get"
18013                     "mget" "last"))))
18014
18015      (if (setq elt
18016                (assoc
18017                 arg2
18018                 '(("get" . "<userid>")
18019                   ("mget" . "<userid>")
18020                   ("last" . "<nbr of days>"))))
18021          (setq
18022           arg3
18023           (read-from-minibuffer
18024            (format "%s, possible additional parameter %s: "
18025                    arg2 (cdr elt)))))
18026
18027      (list arg1 arg2 arg3)))
18028
18029   ;; .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. . interactive end ..
18030   (let ((obuffer  (current-buffer))
18031         insert-flag)
18032
18033     (if (ti::nil-p email)    (error "email is invalid."))
18034     (if (ti::nil-p command)  (error "command is invalid."))
18035
18036     (cond
18037      ((string= "index" command)
18038       (if (null (y-or-n-p "\
18039 Really List all PGP keys the server knows about (-kv)? "))
18040           (error "Abort.")))
18041
18042      ((string= "verbose index" command)
18043       (if (null (y-or-n-p "\
18044 Really  List all PGP keys, verbose format (-kvv) "))
18045           (error "Abort.")))
18046
18047      ((string= "get" command)
18048       (if (null (y-or-n-p "\
18049 Really Get the whole public key ring (-kxa *) "))
18050           (error "Abort.")))
18051
18052      ((string= "mget" command)
18053       (if (null (y-or-n-p (format "\
18054 Really Get all keys which match <userid %s> " arg)))
18055           (error "Abort.")))
18056
18057      ((and (string= "add" command)
18058            (save-excursion
18059              (ti::pmin)
18060              (unless (ti::mail-pgp-public-key-p)
18061                (error "I can't send this buffer, no public key found."))
18062              t))
18063       (setq insert-flag t))
18064
18065      ((member command '("help" "last"))
18066       nil)
18067
18068      (t
18069       (error "unsupported command %s to %s" command email)))
18070
18071     (ti::mail-sendmail-macro email command 'send
18072 ;;;       (pop-to-buffer (current-buffer)) (ti::d! "__ksrv")
18073                              (if insert-flag
18074                                  (insert-buffer obuffer)))))
18075
18076 ;;}}}
18077 ;;{{{ interactive: misc
18078
18079 ;;; ........................................................... &imisc ...
18080
18081 ;;; ----------------------------------------------------------------------
18082 ;;;
18083 (defun tinypgp-pgp-stream-forward-study (&optional verb)
18084   "Find PGP stream and display information from it. VERB.
18085 The information is stored to `tinypgp-:register'.
18086
18087 Interactive call note:
18088
18089   If can't find stream forward, then go to `point-min' and try searching
18090   again."
18091   (interactive)
18092   (let* (info)
18093     (ti::verb)
18094     (if (setq info (ti::mail-pgp-stream-forward-info 'search 'any))
18095         (set-register tinypgp-:register info)
18096       (setq info "Can't intepret/find PGP stream."))
18097     (message info)))
18098
18099 ;;}}}
18100 ;;{{{ examples
18101
18102 ;;; ........................................................ &examples ...
18103 ;;; - Rip code with tinylib.el/ti::package-rip-magic
18104 ;;; - Here is how I control PGP message sending: For company mail,
18105 ;;;   I don't use PGP, but for outside wordl I use quite often.
18106 ;;; - Do not use autosigning if you decide to use this kind of control.
18107
18108 ;;* (add-hook 'mail-send-hook   'my-tinypgp-ask-if-send-pgp-mail)
18109
18110 ;;* ;;; ----------------------------------------------------------------------
18111 ;;* ;;;
18112 ;;* (defun my-tinypgp-ask-if-send-pgp-mail  ()
18113 ;;*   "See if we should ask to sign the mail with PGP.
18114 ;;* - If there is already PGP blocks, do nothing.
18115 ;;* - If these are local host email addresses, do not ask PGP signing.
18116 ;;* "
18117 ;;*   (require 'tinylibmail)
18118 ;;*   (save-excursion
18119 ;;*     (let* ((to              (or (mail-fetch-field "to") ""))
18120 ;;*        (subject     (or (mail-fetch-field "subject") ""))
18121 ;;*        ;;  Exclude my local host addresses, Anon and remail posts
18122 ;;*
18123 ;;*        (skip-address-p
18124 ;;*         (or (string-match (concat
18125 ;;*                            "ntc\\|nokia\\|tne[0-9]\\|[an][na][0-9]"
18126 ;;*                            "\\|remail\\|@anon"
18127 ;;*                            )
18128 ;;*                           to)
18129 ;;*             ;;    local mail addresses do not have @ --> skip PGP
18130 ;;*             ;;    TO field does not exist in news article
18131 ;;*
18132 ;;*             (not (string-match "@" to))
18133 ;;*             ))
18134 ;;*        (mime        (ti::re-search-check
18135 ;;*                      "^--[[]\\|^--+Multi\\|--pgp-"
18136 ;;*                      0 '(ti::pmin)))
18137 ;;*        (diff        (ti::re-search-check
18138 ;;*                      "diff[ \t]+-[ucr]\\|^--- .*199[0-9]"))
18139 ;;*        pgp-ask-no
18140 ;;*        start
18141 ;;*        )
18142 ;;*       (defvar my-:pgp-previous-mail-subject nil)
18143 ;;* _
18144 ;;* _
18145 ;;*       ;; .............................................. untabify maybe ...
18146 ;;*       ;; Remove TABS; so that receiver can see the text as written
18147 ;;*
18148 ;;*       (when (and (null diff)                ;Skip diff message
18149 ;;*              (not (ti::mail-pgp-encrypted-p))       ;already encrypted
18150 ;;*              (not (ti::mail-pgp-p)) ;or other pgp
18151 ;;*              )
18152 ;;*     (untabify (ti::mail-text-start) (point-max))
18153 ;;*     )
18154 ;;* _
18155 ;;*       ;; ........................................ should we sign this? ...
18156 ;;*       ;; Raise flag if NO.
18157 ;;*       ;;
18158 ;;*       (setq pgp-ask-no
18159 ;;*         (or (not (featurep 'tinypgp))
18160 ;;*             mime
18161 ;;*             diff
18162 ;;*             skip-address-p
18163 ;;*             ;;  In news this function is called twice, prevent asking
18164 ;;*             ;;  in the second time.
18165 ;;*             ;;
18166 ;;*             (string= (or my-:pgp-previous-mail-subject "") subject)
18167 ;;*             ))
18168 ;;* _
18169 ;;*       ;; ............................................ do signing maybe ...
18170 ;;*       (when (and (null (ti::mail-pgp-p))            ;no previous pgp
18171 ;;*              (null pgp-ask-no)              ;Not a special message
18172 ;;*              (y-or-n-p "PGP sign message? ")
18173 ;;*              )
18174 ;;*     (call-interactively 'tinypgp-sign-mail))
18175 ;;* _
18176 ;;*       ;;  - Well, I just want to have confirmation after C-c C-c
18177 ;;*       ;;  - Many times I have changed my mind, or missed something I
18178 ;;*       ;;    should have added. At this point there is a short break to
18179 ;;*       ;;    have a glimpse on the message
18180 ;;*       ;;  - I want to see the "Subject", because I may have auto-replied
18181 ;;*       ;;    and started talking about whole different things -->
18182 ;;*       ;;    I should have chnaged the subject. This way I don't
18183 ;;*       ;;    forgot to change it.
18184 ;;*
18185 ;;*       (if (null (y-or-n-p (concat "Sending msg: " subject  " ")))
18186 ;;*       (error "Abort"))
18187 ;;* _
18188 ;;*       (setq my-:pgp-previous-mail-subject subject)
18189 ;;*       nil                           ;hook return value
18190 ;;*       )))
18191
18192 ;;}}}
18193 ;;{{{ final install
18194
18195 (setq tinypgp-:debug t)
18196 (when (null debug-on-error)
18197   (setq debug-on-error t))
18198
18199 (tinypgp-install)
18200 (tinypgp-install-modes) ;;  Do this every time when package is loaded
18201 (tinypgp-install-to-current-emacs)
18202
18203 ;;  Until this package is labelled Alpha
18204
18205 (unless (featurep 'tinypgp)
18206   (setq debug-on-error t)
18207   (tinypgp-initial-message))
18208
18209 (tinypgp-newnym-account-expiry-warnings) ;when Newnym defined
18210
18211 (provide   'tinypgp)
18212 (run-hooks 'tinypgp-:load-hook)
18213
18214 (error "TinyPgpg is no longer maintained. It will be removed in newar future.")
18215
18216 ;;}}}
18217
18218 ;;; tinypgp.el ends here