home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 2: Applications / Linux Cubed Series 2 - Applications.iso / editors / emacs / xemacs / xemacs-1.006 / xemacs-1 / lib / xemacs-19.13 / lisp / packages / mailcrypt.el < prev    next >
Encoding:
Text File  |  1995-06-13  |  38.1 KB  |  1,145 lines

  1. ;; mailcrypt.el v2.4beta, mail encryption with RIPEM and PGP
  2. ;; Copyright (C) 1993  Jin Choi <jsc@mit.edu>
  3. ;; Any comments or suggestions welcome.
  4. ;; Inspired by pgp.el, by Gray Watson <gray@antaire.com>.
  5.  
  6. ;; LCD Archive Entry:
  7. ;; mailcrypt|Jin S Choi|jsc@mit.edu|
  8. ;; Encryption/decryption for mail using RIPEM or PGP. Supports RMAIL, VM, mh-e|
  9. ;; 13-Jun-1994|2.4beta|~/interfaces/mailcrypt.el.Z|
  10.  
  11. ;;{{{ Licensing
  12. ;; This file is intended to be used with GNU Emacs.
  13.  
  14. ;; This program is free software; you can redistribute it and/or modify
  15. ;; it under the terms of the GNU General Public License as published by
  16. ;; the Free Software Foundation; either version 2, or (at your option)
  17. ;; any later version.
  18.  
  19. ;; This program is distributed in the hope that it will be useful,
  20. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  21. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  22. ;; GNU General Public License for more details.
  23.  
  24. ;; You should have received a copy of the GNU General Public License
  25. ;; along with GNU Emacs; see the file COPYING.  If not, write to
  26. ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  27. ;;}}}
  28.  
  29. ;;{{{ TODO
  30. ;; * Interface for view-mode in xemacs has changed, how annoying. Must fix.
  31. ;; * Cleanup of temp files is pgp specific. Make more general.
  32. ;; * Include support for auto-decryption/verification.
  33. ;; * Support X-PGP-SIGNED header used by npgp.el.
  34. ;; Not really mailcrypt problems, but...
  35. ;; * Fix problem with mh-e not observing value of mail-header-separator.
  36. ;;}}}
  37.  
  38. ;;{{{ Change Log
  39. ;;{{{ Changes from 1.6:
  40. ;; * Decrypting a signed message in RMAIL adds a verified tag to the message.
  41. ;; * mc-sign-message takes an optional argument specifying which key to use,
  42. ;;   for people who have multiple private keys.
  43. ;; * Added mc-{pre,post}-{de,en}cryption-hooks.
  44. ;; * Additions to docstrings of the major functions and `mailcrypt-*' aliases
  45. ;;   for the same.
  46. ;; * Added cleanup for possible temp files left over if a process was
  47. ;;   interrupted.
  48. ;; * Easier installation instructions.
  49. ;; * Lots of little bug fixes from all over. Too many to list
  50. ;;   individual credits, but I've tried to include all of them. Thanks
  51. ;;   to all who sent them in, especially to John T Kohl who fixed an
  52. ;;   especially trying problem.
  53. ;; * Another optional argument to mc-insert-public-key that allows the
  54. ;;   user to specify which public key to insert when called with a
  55. ;;   prefix argument.
  56. ;; * Tons of changes from Paul Furnanz <paul_furnanz@rainbow.mentorg.com>:
  57. ;; 1) Use the itimer package instead of the timer package if it exists.
  58. ;;    This makes the password deactivation code work for Lemacs as well
  59. ;;    as emacs 19.
  60. ;; 2) Fractured the code, so that there is a single function to use
  61. ;;    when calling the encryption program.  The new function is
  62. ;;    mc-process-region.  The function copies all data to a temporary
  63. ;;    buffer, and does the work there.  This way if you do an undo after
  64. ;;    an encryption or signing, your password is not visible on the
  65. ;;    screen. 
  66. ;; 3) All process output goes to the *MailCrypt* buffer.  No longer use
  67. ;;    a separate buffer for decryption, encryption, verification, ...
  68. ;;    This allows the user to always look at the *MailCrypt* buffer to
  69. ;;    see what pgp or ripem said.
  70. ;; 4) No longer call mc-temp-display.  Use display-buffer if there is a
  71. ;;    reason to show the buffer (like an error occured).
  72. ;; 5) Try to print more useful messages.
  73. ;; 6) If an error occurs on encryption, the message is left unchanged.
  74. ;;    No reason to undo.
  75. ;;}}}
  76. ;;{{{ Changes from 1.5:
  77. ;; * Changed mc-temp-display to just dump into a temp buffer, without
  78. ;;   any fancy display stuff. Pick up show-temp.el if you liked the
  79. ;;   display stuff (or uncomment the old mc-temp-buffer and remove the
  80. ;;   new version).
  81. ;; * Provided a generic read mode function to call in hooks, like the
  82. ;;   generic write mode function that was already there.
  83. ;; * Fixed bug in regexp that prevented compilation under recent
  84. ;;   versions of FSF emacs.
  85. ;; * Narrow to headers when extracting default recipients for encryption
  86. ;;   to avoid pulling in recipients of included messages.
  87. ;; * Use `fillarray' to overwrite passwords with nulls before deactivation
  88. ;;   for increased security.
  89. ;; * Load mail-extr.el to get mail-extract-address-components defined.
  90. ;; Thanks to Kevin Rodgers <kevin@traffic.den.mmc.com> for the following
  91. ;; improvements.
  92. ;; * Quoted an unquoted lambda expression that prevented optimized 
  93. ;;   compilation under emacs 18.
  94. ;; * Used `nconc' instead of `append' in various places to save on 
  95. ;;   garbage collection.
  96. ;; * Modified mc-split to run more efficiently.
  97. ;;}}}
  98. ;;{{{ Changes from 1.4:
  99. ;; * Call mail-extract-address-components on the recipients if we guessed
  100. ;;   them from the header fields.
  101. ;; * If you don't replace a message with its decrypted version, it will now
  102. ;;   pop you into a view buffer with the contents of the message.
  103. ;; * Added support for mh-e, contributed by Fritz Knabe <Fritz.Knabe@ecrc.de>
  104. ;; * Fixed bug in snarfing keys from menubar under GNUS.
  105. ;; * Fixed RIPEM verification problem, thanks to Sergey Gleizer
  106. ;;   <sgleizer@cs.nmsu.edu>.
  107. ;;}}}
  108. ;;{{{ Changes from 1.3:
  109. ;; * Temp display function does not barf on F-keys or mouse events.
  110. ;;     Thanks to Jonathan Stigelman <stig@key.amdahl.com>
  111. ;; * Lucid emacs menu support provided by William Perry <wmperry@indiana.edu>
  112. ;; * Cited signed messages would interfere with signature 
  113. ;;    verification; fixed.
  114. ;;}}}
  115. ;;{{{ Changes from 1.2:
  116. ;; * Added menu bar support for emacs 19.
  117. ;; * Added GNUS support thanks to Samuel Druker <samuel@telmar.com>.
  118. ;;}}}
  119. ;;{{{ Changes from 1.1:
  120. ;; * Added recipients field to mc-encrypt-message.
  121. ;;}}}
  122. ;;{{{ Changes from 1.0:
  123. ;; * Fixed batchmode bug in decryption, where unsigned messages would return
  124. ;;   with exit code of 1.
  125. ;;}}}
  126. ;;{{{ Changes from 0.3b:
  127. ;; * Only set PGPPASSFD when needed, so PGP won't break when used
  128. ;;   in shell mode.
  129. ;; * Use call-process-region instead of shell-command-on-region in order
  130. ;;   to detect exit codes.
  131. ;; * Changed mc-temp-display to not use the kill ring.
  132. ;; * Bug fixes.
  133. ;;}}}
  134. ;;{{{ Changes from 0.2b:
  135. ;; * Prompts for replacement in mc-rmail-decrypt-message.
  136. ;; * Bug fixes.
  137. ;;}}}
  138. ;;{{{ Changes from 0.1b:
  139. ;; * Several bug fixes.
  140. ;; Contributed by Jason Merrill <jason@cygnus.com>:
  141. ;; * VM mailreader support
  142. ;; * Support for addresses with spaces and <>'s in them
  143. ;; * Support for using an explicit path for the pgp executable
  144. ;; * Key management functions
  145. ;; * The ability to avoid some of the prompts when encrypting
  146. ;; * Assumes mc-default-scheme unless prefixed
  147. ;;}}}
  148.  
  149. ;;}}}
  150.  
  151. ;;{{{ Usage:
  152.  
  153. ;;{{{ Installation:
  154.  
  155. ;; To use, put something like the following elisp into your .emacs file.
  156. ;; You may want to set some of the user variables there as well,
  157. ;; particularly mc-default-scheme.
  158.  
  159. ;; Currently supported modes are RMAIL, VM, mh-e, and gnus. Check out
  160. ;; the section on mode specific functions to see what hooks you can bind to.
  161.  
  162. ;;(autoload 'mc-install-write-mode "mailcrypt" nil t)
  163. ;;(autoload 'mc-install-read-mode "mailcrypt" nil t)
  164.  
  165. ;;(add-hook 'mail-mode-hook 'mc-install-write-mode)  ; for writing modes
  166. ;;(add-hook 'rmail-mode-hook 'mc-install-read-mode)  ; for reading modes
  167.  
  168.  
  169. ;; hooks to use:
  170. ;; PACKAGE     READ HOOK        WRITE HOOK
  171. ;; -------    ---------        ----------
  172. ;; rmail:     rmail-mode-hook        mail-mode-hook
  173. ;; vm:        vm-mode-hook        mail-mode-hook
  174. ;; mh-e:    mh-folder-mode-hook    mh-letter-mode-hook
  175. ;; gnus:    gnus-summary-mode-hook    news-reply-mode-hook
  176.  
  177. ;;{{{ Installation functions; you can ignore these.
  178.  
  179. ;;;###autoload
  180. (defun mc-install-write-mode ()
  181.   (if (eq window-system 'x)
  182.       (mc-create-write-menu-bar))
  183.   (local-set-key "\C-ce" 'mc-encrypt-message)
  184.   (local-set-key "\C-cs" 'mc-sign-message)
  185.   (local-set-key "\C-ca" 'mc-insert-public-key))
  186.  
  187. ;;;###autoload
  188. (defun mc-install-read-mode ()
  189.   (let ((decrypt (nth 0 (cdr (assoc major-mode mc-modes-alist))))
  190.     (verify (nth 1 (cdr (assoc major-mode mc-modes-alist))))
  191.     (snarf (nth 2 (cdr (assoc major-mode mc-modes-alist)))))
  192.     (if (not (and decrypt verify))
  193.     (error "Decrypt, verify functions not defined for this major mode."))
  194.     (if (not snarf)
  195.     (setq snarf 'mc-snarf-keys))
  196.     (local-set-key "\C-cd" decrypt)
  197.     (local-set-key "\C-cv" verify)
  198.     (local-set-key "\C-ca" snarf))
  199.   (if (eq window-system 'x)
  200.       (mc-create-read-menu-bar)))
  201. ;;}}}
  202.  
  203. ;;}}}
  204. ;;{{{ Security Considerations
  205.  
  206. ;; I've tried to write this with security in mind, especially in
  207. ;; regard to the passphrase used to encrypt the private key.
  208.  
  209. ;; No passphrase is ever passed by command line or environment
  210. ;; variable. The passphrase may be temporarily stored into an elisp
  211. ;; variable to allow multiple encryptions/decryptions within a short
  212. ;; period of time without having to type it in each time. It will
  213. ;; deactivate automatically some time after its last use (default one
  214. ;; minute; see `mc-passwd-timeout') if you are running emacs 19. This
  215. ;; is to prevent someone from walking up to your computer while you're
  216. ;; gone and looking up your passphrase. If you are using an older
  217. ;; version of emacs, you can either set mc-passwd-timeout to nil,
  218. ;; which disables passphrase cacheing, or manually deactivate your
  219. ;; passphrase when you are done with it by typing `M-x mc-deactivate-passwd'.
  220.  
  221. ;; The passphrase may still be visible shortly after entry as lossage
  222. ;; (the last 100 characters entered can be displayed by typing 
  223. ;; `C-h l'). I've taken no steps to deal with this, as I don't think
  224. ;; anything *can* be done. If you are the paranoid type, make sure you
  225. ;; type at least a hundred keys after entering your passphrase before
  226. ;; you leave your emacs unattended.
  227.  
  228. ;; If you are truly security conscious, you should, of course, never
  229. ;; leave your computer unattended while you're logged in....
  230.  
  231. ;;}}}
  232. ;;{{{ CAVEAT:
  233.  
  234. ;; This code breaks if you have "Verbose=0" in your config.txt for PGP.
  235. ;; Thanks to Ciamac Moallemi (ciamac@hplms2.hpl.hp.com) for pointing this out.
  236.  
  237. ;; This was written under emacs v19. Its behavior under older versions
  238. ;; of emacs is untested. If something breaks under emacs 18, please
  239. ;; feel free to fix it and send me patches.
  240. ;;}}}
  241. ;;{{{ Note:
  242. ;; The funny triple braces you see are used by `folding-mode', a minor
  243. ;; mode by Jamie Lokier, available from the elisp archive.
  244. ;;}}}
  245.  
  246. ;;}}}
  247.  
  248.  
  249. ;;{{{ Load some required packages
  250. (require 'comint)
  251. (require 'mail-utils)
  252. (eval-when-compile
  253.   (condition-case nil
  254.       (require 'vm)
  255.     (error nil)))
  256. (require 'mail-extr)
  257.  
  258. ;; Load the timer package if we're running non-Lucid emacs 19,
  259. ;; so that (featurep 'timer) returns t later on.
  260. (if (and (string-match "^19" emacs-version)
  261.      (not (string-match "Lucid\\|XEmacs" emacs-version)))
  262.     (require 'timer))
  263.  
  264. ;; mailcrypt packages
  265. ;;XEmacs - inline this thing...(require 'mc-pgp)
  266. ;; This is the mailcrypt package for PGP.
  267. ;;; Place it somewhere in your load path as mc-pgp.el.
  268.  
  269. ;;; ------------------------------------------------------------------------
  270. (defvar mc-pgp-user-id (user-login-name) "*Your PGP user ID.")
  271. (defvar mc-pgp-always-sign nil "*Always sign encrypted PGP messages.")
  272. (defvar mc-pgp-path "pgp" "*The PGP executable.")
  273.  
  274. (defconst mc-pgp-msg-begin-line "-----BEGIN PGP MESSAGE-----"
  275.   "Text for start of PGP message delimiter.")
  276. (defconst mc-pgp-msg-end-line "-----END PGP MESSAGE-----"
  277.   "Text for end of PGP message delimiter.")
  278. (defconst mc-pgp-signed-begin-line "-----BEGIN PGP SIGNED MESSAGE-----"
  279.   "Text for start of PGP signed messages.")
  280. (defconst mc-pgp-signed-end-line "-----END PGP SIGNATURE-----"
  281.   "Text for end of PGP signed messages.")
  282. (defconst mc-pgp-key-begin-line "-----BEGIN PGP PUBLIC KEY BLOCK-----"
  283.   "Text for start of PGP public key.")
  284. (defconst mc-pgp-key-end-line "-----END PGP PUBLIC KEY BLOCK-----"
  285.   "Text for end of PGP public key.")
  286. (defconst mc-pgp-error-re "^\\(ERROR\\|WARNING\\):.*"
  287.   "Regular expression matching an error from PGP")
  288. (defconst mc-pgp-sigok-re "^.*Good signature.*"
  289.   "Regular expression matching a PGP signature validation message")
  290. (defconst mc-pgp-newkey-re "\\(No\\|[0-9]\\)+\\s-+new.*"
  291.   "Regular expression matching a PGP signature snarf message")
  292.  
  293.  
  294. (defun mc-pgp-encrypt-region (recipients start end)
  295.   (let ((process-environment process-environment)
  296.     (buffer (get-buffer-create mc-buffer-name))
  297.     args signed-p)
  298.     (and mc-encrypt-for-me
  299.      (setq recipients (cons mc-pgp-user-id recipients)))
  300.     (setq args (list "+batchmode" "-feat"))
  301.     (if (or mc-pgp-always-sign (y-or-n-p "Sign the message? "))
  302.     (setq signed-p t
  303.           args (nconc args (list "-su" mc-pgp-user-id))))
  304.     (setq args (nconc args recipients))
  305.     
  306.     ;; Don't need to ask for the passphrase if not signing.
  307.     (if signed-p
  308.     (setq process-environment
  309.           (cons "PGPPASSFD=0"
  310.             process-environment)))
  311.     (message "Encrypting...")
  312.     (if (not (mc-process-region start end
  313.                 (and signed-p "PGP Password: ")
  314.                 mc-pgp-path args
  315.                 buffer mc-pgp-msg-begin-line t))
  316.     (progn
  317.       (mc-display-buffer buffer)
  318.       (mc-message mc-pgp-error-re buffer "Error while encrypting" t)))))
  319.  
  320.  
  321. (defun mc-pgp-decrypt-region (start end)
  322.   ;; returns a pair (SUCCEEDED . VERIFIED) where SUCCEEDED is t if
  323.   ;; the encryption succeeded and verified is t if there was a valid signature
  324.   (let ((process-environment 
  325.      (cons "PGPPASSFD=0" process-environment))
  326.     (buffer (get-buffer-create mc-buffer-name))
  327.     retval)
  328.     (message "Decrypting...")
  329.     (if (mc-process-region
  330.      start end "PGP Password: "
  331.      mc-pgp-path '("-f")
  332.      buffer
  333.      (and (null buffer-read-only)
  334.           '("^Signature made.*\n" "Just a moment\\.+")))
  335.     (progn
  336.       (if buffer-read-only
  337.           (pop-to-buffer buffer))
  338.       (cons t (mc-message mc-pgp-sigok-re buffer "Decrypted.")))
  339.       (mc-display-buffer buffer)
  340.       (mc-message mc-pgp-error-re buffer "Error decrypting buffer")
  341.       (cons nil nil))))
  342.  
  343. (defun mc-pgp-sign-region (start end &optional withkey)
  344.   (let ((process-environment (cons "PGPPASSFD=0" process-environment))
  345.     (buffer (get-buffer-create mc-buffer-name))
  346.     (user-id (or withkey mc-pgp-user-id)))
  347.     (message "Signing...")
  348.     (if (not (mc-process-region start end "PGP Password: "
  349.                 mc-pgp-path (list "-fast" "+clearsig=on"
  350.                           "+batchmode"
  351.                           "-u" user-id)
  352.                 buffer "^Just a moment\\.+"))
  353.     (progn
  354.       (mc-display-buffer buffer)
  355.       (mc-message mc-pgp-error-re buffer "PGP signing failed" t)))))
  356.  
  357.  
  358. (defun mc-pgp-verify-region (start end)
  359.   (let ((buffer (get-buffer-create mc-buffer-name)))
  360.     (message "Verifying...")
  361.     (if (mc-process-region start end nil
  362.                mc-pgp-path '("+batchmode" "-f") buffer)
  363.     (prog1
  364.         t
  365.       (mc-message mc-pgp-sigok-re buffer "Good signature"))
  366.       (mc-display-buffer buffer)
  367.       (mc-message mc-pgp-error-re buffer "Error verifying PGP signature")
  368.       nil)))
  369.  
  370. (defun mc-pgp-insert-public-key (userid)
  371.   (let ((buffer (get-buffer-create mc-buffer-name)))
  372.     (if (not (mc-process-region (point) (point) nil
  373.                 mc-pgp-path
  374.                 (list "+batchmode" "-kxaf" userid)
  375.                 buffer
  376.                 mc-pgp-key-begin-line t))
  377.     (mc-message mc-pgp-error-re buffer
  378.             "Error including signature" t))))
  379.  
  380.  
  381. (defun mc-pgp-snarf-key (start end)
  382.   (let ((buffer (get-buffer-create mc-buffer-name)))
  383.     (message "Snarfing...")
  384.     (if (mc-process-region start end nil
  385.                mc-pgp-path '("+batchmode" "-kaf")
  386.                buffer)
  387.     (mc-message mc-pgp-newkey-re buffer
  388.             "No new keys found")
  389.       (mc-display-buffer buffer)
  390.       (mc-message mc-pgp-error-re buffer "Error snarfing PGP key" t))))
  391.  
  392. (defvar mc-scheme-pgp
  393.   (list
  394.    (cons 'encryption-func         'mc-pgp-encrypt-region)
  395.    (cons 'decryption-func        'mc-pgp-decrypt-region)
  396.    (cons 'signing-func        'mc-pgp-sign-region)
  397.    (cons 'verification-func     'mc-pgp-verify-region)
  398.    (cons 'key-insertion-func     'mc-pgp-insert-public-key)
  399.    (cons 'snarf-func        'mc-pgp-snarf-key)
  400.    (cons 'msg-begin-line         mc-pgp-msg-begin-line)
  401.    (cons 'msg-end-line         mc-pgp-msg-end-line)
  402.    (cons 'signed-begin-line     mc-pgp-signed-begin-line)
  403.    (cons 'signed-end-line         mc-pgp-signed-end-line)
  404.    (cons 'key-begin-line         mc-pgp-key-begin-line)
  405.    (cons 'key-end-line         mc-pgp-key-end-line)
  406.    (cons 'user-id    mc-pgp-user-id)))
  407.  
  408. (provide 'mc-pgp)
  409.  
  410. ;;}}}
  411. ;;{{{ User variables.
  412.  
  413. (defvar mc-default-scheme mc-scheme-pgp "*Default encryption scheme to use.")
  414. (defvar mc-passwd-timeout 60
  415.   "*Time to deactivate password in seconds after a use.
  416. nil or 0 means deactivate immediately.  If the only timer package available
  417. is the 'timer' package, then this can be a string in timer format.")
  418.  
  419. (defvar mc-ripem-user-id (or (getenv "RIPEM_USER_NAME")
  420.                  (user-full-name) "*Your RIPEM user ID."))
  421.  
  422. (defvar mc-always-replace nil "*Decrypt messages in place without prompting.")
  423. (defvar mc-use-default-recipients nil
  424.   "*Assume that the message should be encoded for everyone listed in the To:
  425. and Cc: fields.")
  426. (defvar mc-encrypt-for-me nil
  427.   "*Encrypt all outgoing messages with user's public key.")
  428.  
  429. (defvar mc-pre-encryption-hook nil 
  430.   "*List of hook functions to run immediately before encrypting.")
  431. (defvar mc-post-encryption-hook nil 
  432.   "*List of hook functions to run after encrypting.")
  433. (defvar mc-pre-decryption-hook nil 
  434.   "*List of hook functions to run immediately before decrypting.")
  435. (defvar mc-post-decryption-hook nil 
  436.   "*List of hook functions to run after decrypting.")
  437.  
  438.  
  439. ;;}}}
  440. ;;{{{ Program variables and constants.
  441.  
  442. (defvar mc-timer nil "Timer object for password deactivation.")
  443.  
  444. (defvar mc-passwd nil "Your secret key passphrase.")
  445.  
  446. ;; You might consider interposing a program such as below, which
  447. ;; refuses to let pgp get hold of a terminal; this makes it work
  448. ;; better as a slave process:
  449. ;;
  450. ;;#include <unistd.h>
  451. ;;#include <sys/types.h>
  452. ;;#include <sys/wait.h>
  453. ;;/*
  454. ;; * call setsid() in child
  455. ;; * to revoke controlling terminal, then execvp pgp with args.
  456. ;; */
  457. ;;main(int argc, char *argv[])
  458. ;;{
  459. ;;    pid_t pid;
  460. ;;    int status;
  461. ;;    pid = fork();
  462. ;;    if (pid == 0) {
  463. ;;    /* child */
  464. ;;    if (setsid() == -1)
  465. ;;        perror("setsid");
  466. ;;    execvp("pgp", argv);
  467. ;;    perror("cannot execvp pgp");
  468. ;;    exit(1);
  469. ;;    } else if (pid > 0) {
  470. ;;    waitpid(pid, &status, 0);
  471. ;;    exit(WEXITSTATUS(status));
  472. ;;    } else {
  473. ;;    perror("fork");
  474. ;;    exit(1);
  475. ;;    }
  476. ;;}
  477.  
  478.  
  479. (defconst mc-buffer-name "*MailCrypt*"
  480.   "Name of temporary buffer for mailcrypt")
  481.  
  482. (defvar mc-schemes
  483.   (list
  484.    (cons "pgp" mc-scheme-pgp)))
  485.  
  486. ;;}}}
  487. ;;{{{ Utility functions.
  488.  
  489. (defun mc-message-delimiter-positions (start-re end-re &optional begin)
  490.   ;; Returns pair of integers (START . END) that delimit message marked off
  491.   ;; by the regular expressions start-re and end-re. Optional argument BEGIN
  492.   ;; determines where we should start looking from.
  493.   (if (null begin)
  494.       (setq begin (point-min)))
  495.   (goto-char begin)
  496.   (let (start retval bad-re)
  497.     (catch 'notfound
  498.       (save-excursion
  499.     (goto-char (point-min))
  500.     (or (re-search-forward (concat "^" start-re) nil t)
  501.         (throw 'notfound nil))
  502.     (setq start (match-beginning 0))
  503.     (or (re-search-forward (concat "^" end-re "\n") nil t)
  504.         (throw 'notfound nil))
  505.     (cons start (point))))))
  506.  
  507.  
  508. (defun mc-split (regexp str)
  509.   "Splits STR into a list of elements which were separated by REGEXP,
  510. stripping initial and trailing whitespace."
  511.   (let ((data (match-data))
  512.     (retval '())
  513.     beg end)
  514.     (unwind-protect
  515.     (progn
  516.       (string-match "[ \t\n]*" str)    ; Will always match at 0
  517.       (setq beg (match-end 0))
  518.       ;; This will break if there are newlines in str XXX
  519.       (setq end (string-match "[ \t\n]*$" str))
  520.       (while (string-match regexp str beg)
  521.         (setq retval
  522.           (cons (substring str beg (match-beginning 0)) 
  523.             retval))
  524.         (setq beg (match-end 0)))
  525.       (if (not (= (length str) beg)) ; Not end
  526.           (setq retval (cons (substring str beg end) retval)))
  527.       (nreverse retval))
  528.       (store-match-data data))))
  529.  
  530. (defun mc-temp-display (beg end &optional name)
  531.   (let (tmp)
  532.     (if (not name)
  533.     (setq name mc-buffer-name))
  534.     (if (string-match name "*ERROR*")
  535.     (progn
  536.       (message "mailcrypt: An error occured!  See *ERROR* buffer.")
  537.       (beep)))
  538.     (setq tmp (buffer-substring beg end))
  539.     (delete-region beg end)
  540.     (save-excursion
  541.       (save-window-excursion
  542.     (with-output-to-temp-buffer name
  543.       (princ tmp))))))
  544.  
  545. ;;(defun mc-temp-display (beg end &optional name)
  546. ;;  (let (tmp)
  547. ;;    (if (not name)
  548. ;;    (setq name "*Mailcrypt Temp*"))
  549. ;;    (setq tmp (buffer-substring beg end))
  550. ;;    (delete-region beg end)
  551. ;;    (save-excursion
  552. ;;      (set-buffer (generate-new-buffer name))
  553. ;;      (insert tmp)
  554. ;;      (goto-char (point-min))
  555. ;;      (save-window-excursion
  556. ;;    (shrink-window-if-larger-than-buffer 
  557. ;;     (display-buffer (current-buffer)))
  558. ;;    (message "Press any key to remove the %s window." name)
  559. ;;    (cond ((and (string-match "19\\." emacs-version)
  560. ;;            (not (string-match "XEmacs" (emacs-version))))
  561. ;;           (read-event))
  562. ;;          (t
  563. ;;           (read-char)))
  564. ;;    (kill-buffer (current-buffer))))))
  565.  
  566. (defun mc-display-buffer (buffer)
  567.   "Like display-buffer, but always display top of the buffer."
  568.   (save-excursion
  569.     (set-buffer buffer)
  570.     (goto-char (point-min))
  571.     (display-buffer buffer)))
  572.  
  573. (defun mc-message (msg &optional buffer default iserr)
  574.   ;; returns t if we used msg, nil if we used default
  575.   (let ((retval t))
  576.     (if buffer
  577.     (setq msg
  578.           (save-excursion
  579.         (set-buffer buffer)
  580.         (goto-char (point-min))
  581.         (if (re-search-forward msg nil t)
  582.             (buffer-substring (match-beginning 0) (match-end 0))
  583.           (setq retval nil)
  584.           default))))
  585.     (prog1
  586.     retval
  587.       (if iserr
  588.       (mc-deactivate-passwd))    ; in case error is bad passphrase
  589.       (and msg (message msg)))))
  590.  
  591. (defun mc-process-region (beg end passwd program args &optional buffer
  592.                   copy keep)
  593.   (if (stringp copy)
  594.       (setq copy (list copy)))
  595.   (let ((oldbuf (current-buffer))
  596.     mybuf result)
  597.     (unwind-protect
  598.     (progn
  599.       (setq mybuf (or buffer (generate-new-buffer " mailcrypt temp")))
  600.       (set-buffer mybuf)
  601.       (erase-buffer)
  602.       (buffer-disable-undo mybuf)
  603.       (if passwd
  604.           (progn
  605.         (insert (mc-activate-passwd passwd) "\n")
  606.         (or mc-passwd-timeout (mc-deactivate-passwd))))
  607.       (insert-buffer-substring oldbuf beg end)
  608.  
  609.       ;; Catch a quit signal so we can clean up any
  610.       ;; temp files lying around if the user nukes us.
  611.       (setq result (condition-case nil
  612.                (apply 'call-process-region
  613.                   (nconc (list (point-min) (point-max)
  614.                            program
  615.                            t t nil)
  616.                      args))
  617.              (quit
  618.               ;; don't let the user interrupt the cleanup
  619.               (let ((inhibit-quit t))
  620.                 (shell-command "rm -f pgptemp.*")
  621.                 (setq quit-flag nil)
  622.                 "Stopped at user request"))))
  623.       ;; CRNL -> NL
  624.       (goto-char (point-min)) 
  625.       (while (search-forward "\r\n" nil t)
  626.         (forward-char -1)
  627.         (delete-char -1))
  628.       
  629.       (cond ((stringp result)    ;process terminated somehow
  630.          (message "Mailcrypt process died abnormally: '%s'" result)
  631.          (sit-for 2)
  632.          nil)
  633.         ((zerop result)
  634.          (prog1
  635.              t
  636.            (if copy
  637.                (let (start)
  638.              (goto-char (point-min))
  639.              (and (listp copy)
  640.                   (let ((c copy))
  641.                 (while (and c
  642.                         (null (re-search-forward (car c) 
  643.                                      nil t)))
  644.                   (setq c (cdr c)))
  645.                 c)
  646.                   keep (goto-char (match-beginning 0)))
  647.              (setq start (point))
  648.              (save-excursion
  649.                (set-buffer oldbuf)
  650.                (delete-region beg end)
  651.                (goto-char beg)
  652.                (insert-buffer-substring mybuf start))
  653.              (delete-region start (point-max))))))
  654.         (t
  655.          nil)))
  656.       (set-buffer oldbuf)
  657.       (and mybuf (or (null result) (null buffer)) (kill-buffer mybuf)))))
  658.  
  659. ;;}}}
  660. ;;{{{ Passphrase management
  661.  
  662. (defun mc-activate-passwd (prompt)
  663.   (cond ((featurep 'itimer)
  664.      (if mc-timer (delete-itimer mc-timer))
  665.      (setq mc-timer (if mc-passwd-timeout
  666.                 (start-itimer "mc-itimer" 'mc-deactivate-passwd
  667.                       mc-passwd-timeout))))
  668.     ((featurep 'timer)
  669.      (let ((string-time (if (integerp mc-passwd-timeout)
  670.                 (format "%d sec" mc-passwd-timeout)
  671.                   mc-passwd-timeout)))
  672.        (if mc-timer (cancel-timer mc-timer))
  673.        (setq mc-timer (if string-time
  674.                   (run-at-time string-time 
  675.                        nil 'mc-deactivate-passwd)
  676.                 nil)))))
  677.   (if (not mc-passwd)
  678.       (setq mc-passwd (comint-read-noecho prompt)))
  679.   mc-passwd)
  680.  
  681. ;;;###autoload
  682. (defun mc-deactivate-passwd ()
  683.   "*Deactivates the passphrase."
  684.   (interactive)
  685.   (and mc-timer (fboundp 'cancel-timer) (cancel-timer mc-timer))
  686.   (and (stringp mc-passwd) (fillarray mc-passwd 0))
  687.   (setq mc-passwd nil)
  688.   (message "password deactivated"))
  689.  
  690. ;;}}}
  691. ;;{{{ Encryption
  692.  
  693. (defun mc-cleanup-recipient-headers (str)
  694.   ;; Takes a comma separated string of recipients to encrypt for and,
  695.   ;; assuming they were possibly extracted from the headers of a reply,
  696.   ;; returns a list of the address components.
  697.   (mapcar (function
  698.        (lambda (x)
  699.          (car (cdr (mail-extract-address-components x)))))
  700.       (mc-split "\\([ \t\n]*,[ \t\n]*\\)+" str)))
  701.  
  702. ;;;###autoload
  703. (defun mc-encrypt-message (&optional recipients scheme)
  704.   "*Encrypt the message to RECIPIENTS using the given encryption SCHEME.
  705. RECIPIENTS is a comma separated string. If SCHEME is nil, use the value
  706. of `mc-default-scheme'. Returns t on success, nil otherwise.
  707.  
  708. By default, this function is bound to `C-c e' in mail composing modes."
  709.   (interactive
  710.    (if current-prefix-arg
  711.        (list nil
  712.          (cdr (assoc (completing-read "Encryption Scheme: " mc-schemes)
  713.              mc-schemes)))))
  714.   
  715.   (run-hooks 'mc-pre-encryption-hook)
  716.   (let ((default-recipients
  717.       (save-restriction
  718.         (goto-char (point-min))
  719.         (search-forward mail-header-separator)
  720.         (narrow-to-region (point-min) (point))
  721.         (concat (mail-fetch-field "to" nil t) ", "
  722.             (mail-fetch-field "bcc" nil t) ", "
  723.             (mail-fetch-field "cc" nil t)))))
  724.     
  725.     (or scheme (setq scheme mc-default-scheme))
  726.     (setq recipients
  727.       (cond (recipients        ; given as function argument
  728.          (mc-split "\\([ \t\n]*,[ \t\n]*\\)+" recipients))
  729.         (mc-use-default-recipients
  730.          (mc-cleanup-recipient-headers default-recipients))
  731.         (t            ; prompt for it
  732.          (mc-cleanup-recipient-headers
  733.           (read-from-minibuffer "Recipients: " default-recipients)))))
  734.     
  735.     (or recipients
  736.     (error "No recipients!"))
  737.  
  738.     (goto-char (point-min))
  739.     (search-forward (concat "\n" mail-header-separator "\n"))
  740.     (if (mc-encrypt-region scheme recipients
  741.                            (point) (point-max))
  742.         (progn
  743.           (run-hooks 'mc-post-encryption-hook)
  744.           t)
  745.       nil)))
  746.  
  747. (defsubst mc-encrypt-region (scheme recipients start end)
  748.   ;; Encrypt region with SCHEME between START and END for
  749.   ;; RECIPIENTS using BUFFER.
  750.   (funcall (cdr (assoc 'encryption-func scheme)) recipients start end))
  751.  
  752. ;;}}}
  753. ;;{{{ Decryption
  754.  
  755. ;;;###autoload
  756. (defun mc-decrypt-message ()
  757.   "*Decrypt whatever message is in the current buffer.
  758. Returns a pair (SUCCEEDED . VERIFIED) where SUCCEEDED is t if the encryption
  759. succeeded and VERIFIED is t if it had a valid signature.
  760.  
  761. By default, this function is bound to `C-c d' in reading modes."
  762.   (interactive)
  763.   (let ((schemes mc-schemes)
  764.     limits scheme)
  765.     (while (and schemes
  766.         (setq scheme (car schemes))
  767.         (not (setq limits
  768.                (mc-message-delimiter-positions
  769.                 (cdr (assoc 'msg-begin-line scheme))
  770.                 (cdr (assoc 'msg-end-line scheme))))))
  771.       (setq schemes (cdr schemes)))
  772.  
  773.     (if (null limits)
  774.         (error "Found no encrypted message in this buffer.")
  775.       (run-hooks 'mc-pre-decryption-hook)
  776.       (let ((resultval (funcall (cdr (assoc 'decryption-func scheme)) 
  777.                                 (car limits) (cdr limits))))
  778.         (goto-char (point-min))
  779.         (if (car resultval) ; decryption succeeded
  780.             (run-hooks 'mc-post-decryption-hook))
  781.         resultval))))
  782. ;;}}}  
  783. ;;{{{ Signing
  784.  
  785. ;;;###autoload
  786. (defun mc-sign-message (&optional withkey scheme)
  787.   "*Clear sign the message.
  788. With one prefix arg, prompts for private key to use, with two prefix args,
  789. also prompts for encryption scheme to use.
  790.  
  791. By default, this function is bound to `C-c s' in composition modes."
  792.   (interactive
  793.    (let (arglist)
  794.      (if (not (and (listp current-prefix-arg)
  795.            (numberp (car current-prefix-arg))))
  796.      nil
  797.        (if (>= (car current-prefix-arg) 16)
  798.        (setq arglist (cons (cdr (assoc
  799.                      (completing-read "Encryption Scheme: "
  800.                               mc-schemes)
  801.                      mc-schemes))
  802.                    arglist)))
  803.        (if (>= (car current-prefix-arg) 4)
  804.        (setq arglist (cons (read-string "User ID: ") arglist))))
  805.      arglist))
  806.   (or scheme (setq scheme mc-default-scheme))
  807.   (let (start)
  808.     (goto-char (point-min))
  809.     (search-forward (concat "\n" mail-header-separator "\n"))
  810.     (funcall (cdr (assoc 'signing-func scheme))
  811.          (point) (point-max) withkey)))
  812.  
  813. ;;}}}
  814. ;;{{{ Signature verification
  815.  
  816. ;;{{{ mc-verify-signature
  817.  
  818. ;;;###autoload
  819. (defun mc-verify-signature ()
  820.   "*Verify the signature of the signed message in the current buffer.
  821. Show the result as a message in the minibuffer. Returns t if the signature
  822. is verified.
  823.  
  824. By default, this function is bound to `C-c v' in reading modes."
  825.   (interactive)
  826.   (let ((schemes mc-schemes)
  827.     limits scheme)
  828.     (while (and schemes
  829.         (setq scheme (car schemes))
  830.         (not (setq limits
  831.                (mc-message-delimiter-positions
  832.                 (cdr (assoc 'signed-begin-line scheme))
  833.                 (cdr (assoc 'signed-end-line scheme))))))
  834.       (setq schemes (cdr schemes)))
  835.  
  836.     (if (null limits)
  837.     (error "Found no signed message in this buffer.")
  838.       (funcall (cdr (assoc 'verification-func scheme))
  839.            (car limits) (cdr limits)))))
  840. ;;}}}
  841.  
  842. ;;}}}
  843. ;;{{{ Key management
  844.  
  845. ;;{{{ mc-insert-public-key
  846.  
  847. ;;;###autoload
  848. (defun mc-insert-public-key (&optional userid scheme)
  849.   "*Insert your public key at the end of the current buffer.
  850. With one prefix arg, prompts for user id to use. With two prefix
  851. args, prompts for encryption scheme."
  852.   (interactive
  853.    (let (arglist)
  854.      (if (not (and (listp current-prefix-arg)
  855.            (numberp (car current-prefix-arg))))
  856.      nil
  857.        (if (>= (car current-prefix-arg) 16)
  858.        (setq arglist
  859.          (cons (cdr (assoc (completing-read "Encryption Scheme: "
  860.                             mc-schemes)
  861.                    mc-schemes))
  862.                arglist)))
  863.        (if (>= (car current-prefix-arg) 4)
  864.        (setq arglist (cons (read-string "User ID: ") arglist))))
  865.      arglist))
  866.   (or scheme (setq scheme mc-default-scheme))
  867.   (or userid (setq userid (cdr (assoc 'user-id scheme))))
  868.  
  869.   (goto-char (point-max))
  870.   (if (not (bolp))
  871.       (insert "\n"))
  872.   (funcall (cdr (assoc 'key-insertion-func scheme)) userid))
  873. ;;}}}
  874. ;;{{{ mc-snarf-keys
  875.  
  876. ;;;###autoload
  877. (defun mc-snarf-keys ()
  878.   "*Add the first public key in the buffer to your keyring.
  879. TODO: add ALL the keys in the buffer."
  880.   (interactive)
  881.   (let ((schemes mc-schemes)
  882.     (start (point-min))
  883.     limits scheme)
  884.     (while (and schemes
  885.         (setq scheme (car schemes))
  886.         (not (setq limits
  887.                (mc-message-delimiter-positions
  888.                 (cdr (assoc 'key-begin-line scheme))
  889.                 (cdr (assoc 'key-end-line scheme))
  890.                 start))))
  891.       (setq schemes (cdr schemes)))
  892.     (if (null limits)
  893.     (error "Found no public key to snarf in this buffer.")
  894.       (funcall (cdr (assoc 'snarf-func scheme)) 
  895.            (car limits) (cdr limits)))))
  896. ;;}}}
  897.  
  898. ;;}}}
  899. ;;{{{ Mode specific functions
  900.  
  901. (defvar mc-modes-alist
  902.   (list (cons 'rmail-mode (list 'mc-rmail-decrypt-message
  903.                 'mc-rmail-verify-signature))
  904.     (cons 'vm-mode (list 'mc-vm-decrypt-message
  905.                  'mc-vm-verify-signature))
  906.     (cons 'mh-folder-mode (list 'mc-mh-decrypt-message
  907.                     'mc-mh-verify-signature
  908.                     'mc-mh-snarf-keys))
  909.     (cons 'gnus-summary-mode (list 'mc-gnus-summary-decrypt-message
  910.                        'mc-gnus-summary-verify-signature
  911.                        'mc-gnus-summary-snarf-keys)))
  912.   "*Association list to specify mode specific functions for reading.
  913. Entries are of the form (MODE . (DECRYPT VERIFY SNARF)).
  914. The SNARF is optional and defaults to `mc-snarf-keys'.")
  915.  
  916. ;;{{{ RMAIL
  917. ;;;###autoload
  918. (defun mc-rmail-verify-signature ()
  919.   "*Verify the signature in the current message."
  920.   (interactive)
  921.   (if (not (equal mode-name "RMAIL"))
  922.       (error "mc-rmail-verify-signature called in a non-RMAIL buffer"))
  923.   (if (mc-verify-signature)
  924.       (rmail-add-label "verified")))
  925.  
  926. ;;;###autoload
  927. (defun mc-rmail-decrypt-message ()
  928.   "*Decrypt the contents of this message"
  929.   (interactive)
  930.   (let ((oldbuf (current-buffer))
  931.     noerr
  932.     decryption-result)
  933.     (if (not (equal mode-name "RMAIL"))
  934.     (error "mc-rmail-decrypt-message called in a non-RMAIL buffer"))
  935.     (rmail-edit-current-message)
  936.     (cond ((not (progn
  937.           (setq decryption-result (mc-decrypt-message))
  938.           (car decryption-result)))
  939.        (message "Decryption failed.")
  940.        (rmail-abort-edit))
  941.       ((or mc-always-replace
  942.            (y-or-n-p "Replace encrypted message with decrypted? "))
  943.        (rmail-cease-edit)
  944.        (rmail-kill-label "edited")
  945.        (rmail-add-label "decrypted")
  946.        (if (cdr decryption-result)
  947.            (rmail-add-label "verified")))
  948.       (t
  949.        (let ((tmp (generate-new-buffer "*Mailcrypt Viewing*")))
  950.          (copy-to-buffer tmp (point-min) (point-max))
  951.          (rmail-abort-edit)
  952.          (switch-to-buffer tmp t)
  953.          (view-mode oldbuf 'kill-buffer))))))
  954.  
  955. ;;}}}
  956. ;;{{{ VM
  957. ;;;###autoload
  958. (defun mc-vm-verify-signature ()
  959.   "*Verify the signature in the current VM message"
  960.   (interactive)
  961.   (if (interactive-p)
  962.       (vm-follow-summary-cursor))
  963.   (vm-select-folder-buffer)
  964.   (vm-check-for-killed-summary)
  965.   (vm-error-if-folder-empty)
  966.   (mc-verify-signature))
  967.  
  968. ;;;###autoload
  969. (defun mc-vm-decrypt-message ()
  970.   "*Decrypt the contents of the current VM message"
  971.   (interactive)
  972.   (let ((oldbuf (current-buffer))
  973.     decryption-result)
  974.     (if (interactive-p)
  975.     (vm-follow-summary-cursor))
  976.     (vm-select-folder-buffer)
  977.     (vm-check-for-killed-summary)
  978.     (vm-error-if-folder-read-only)
  979.     (vm-error-if-folder-empty)
  980.     (vm-edit-message)
  981.     (cond ((not (prog1
  982.                     (car (mc-decrypt-message))
  983.                   (sit-for 1))) ; give it time to show the edit window
  984.            (message "Decryption failed.")
  985.            (vm-edit-message-abort))
  986.           ((or mc-always-replace
  987.                (y-or-n-p "Replace encrypted message with decrypted? "))
  988.            (vm-edit-message-end))
  989.           (t
  990.            (let ((tmp (generate-new-buffer "*Mailcrypt Viewing*")))
  991.              (copy-to-buffer tmp (point-min) (point-max))
  992.              (vm-edit-message-abort)
  993.              (switch-to-buffer tmp t)
  994.              (view-mode oldbuf 'kill-buffer))))))
  995.  
  996. ;;}}}
  997. ;;{{{ GNUS
  998.  
  999. ;;;###autoload
  1000. (defun mc-gnus-summary-verify-signature ()
  1001.   (interactive)
  1002.   (gnus-summary-select-article gnus-save-all-headers gnus-save-all-headers)
  1003.   (gnus-eval-in-buffer-window gnus-article-buffer
  1004.     (save-restriction (widen) (mc-verify-signature))))
  1005.  
  1006. ;;;###autoload
  1007. (defun mc-gnus-summary-snarf-keys ()
  1008.   (interactive)
  1009.   (gnus-summary-select-article gnus-save-all-headers gnus-save-all-headers)
  1010.   (gnus-eval-in-buffer-window gnus-article-buffer
  1011.     (save-restriction (widen) (mc-snarf-keys))))
  1012.  
  1013. ;;;###autoload
  1014. (defun mc-gnus-summary-decrypt-message ()
  1015.   (interactive)
  1016.   (gnus-summary-select-article gnus-save-all-headers gnus-save-all-headers)
  1017.   (gnus-eval-in-buffer-window gnus-article-buffer
  1018.     (save-restriction (widen) (mc-decrypt-message))))
  1019.  
  1020. ;;}}}        
  1021. ;;{{{ MH
  1022.  
  1023. ;;;###autoload
  1024. (defun mc-mh-decrypt-message (decrypt-on-disk)
  1025.   "*Decrypt the contents of the current MH message in the show buffer.
  1026. With prefix arg, decrypt the message on disk as well."
  1027.   (interactive "P")
  1028.   (let* ((msg (mh-get-msg-num t))
  1029.      (msg-filename (mh-msg-filename msg))
  1030.      (show-buffer (get-buffer mh-show-buffer))
  1031.      decrypt-okay)
  1032.     (setq decrypt-on-disk (or mc-always-replace decrypt-on-disk))
  1033.     (if decrypt-on-disk
  1034.     (progn
  1035.       (save-excursion
  1036.         (set-buffer (create-file-buffer msg-filename))
  1037.         (insert-file-contents msg-filename t)
  1038.         (if (setq decrypt-okay (car (mc-decrypt-message)))
  1039.         (save-buffer)
  1040.           (message "Decryption failed.")
  1041.           (set-buffer-modified-p nil))
  1042.         (kill-buffer nil))
  1043.       (if decrypt-okay
  1044.           (if (and show-buffer
  1045.                (equal msg-filename (buffer-file-name show-buffer)))
  1046.           (save-excursion
  1047.             (save-window-excursion
  1048.               (mh-invalidate-show-buffer)))))
  1049.       (mh-show msg))
  1050.       (mh-show msg)
  1051.       (save-excursion
  1052.     (set-buffer mh-show-buffer)
  1053.     (if (setq decrypt-okay (car (mc-decrypt-message)))
  1054.         (progn
  1055.           (goto-char (point-min))
  1056.           (set-buffer-modified-p nil))
  1057.       (message "Decryption failed.")))
  1058.       (if (not decrypt-okay)
  1059.       (progn
  1060.         (mh-invalidate-show-buffer)
  1061.         (mh-show msg))))))
  1062.  
  1063. ;;;###autoload
  1064. (defun mc-mh-verify-signature ()
  1065.   "*Verify the signature in the current MH message."
  1066.   (interactive)
  1067.   (let ((msg (mh-get-msg-num t)))
  1068.     (mh-show msg)
  1069.     (save-excursion
  1070.       (set-buffer mh-show-buffer)
  1071.       (mc-verify-signature))))
  1072.  
  1073. ;;;###autoload
  1074. (defun mc-mh-snarf-keys ()
  1075.   (interactive)
  1076.   (mh-show (mh-get-msg-num t))
  1077.   (save-excursion
  1078.     (set-buffer mh-show-buffer)
  1079.     (mc-snarf-keys)))
  1080.  
  1081.  
  1082. ;;}}}
  1083.  
  1084. ;;}}}
  1085. ;;{{{ Menubar stuff
  1086.  
  1087. (defun mc-create-read-menu-bar ()
  1088.   ;; Create a menu bar entry for reading modes.
  1089.   (let ((decrypt (nth 0 (cdr (assoc major-mode mc-modes-alist))))
  1090.     (verify (nth 1 (cdr (assoc major-mode mc-modes-alist))))
  1091.     (snarf (nth 2 (cdr (assoc major-mode mc-modes-alist)))))
  1092.     (if (not (and decrypt verify))
  1093.     (error "Decrypt and verify functions not defined for this major mode."))
  1094.     (if (not snarf)
  1095.     (setq snarf 'mc-snarf-keys))
  1096.     (if (string-match "XEmacs" (emacs-version))
  1097.     (let ((x (list "Mailcrypt"
  1098.                (vector "Decrypt Message" decrypt t)
  1099.                (vector "Verify Signature" verify t)
  1100.                (vector "Snarf Public Key" snarf t))))
  1101.       (set-buffer-menubar current-menubar)
  1102.       (add-menu nil "Mailcrypt" (cdr x)))
  1103.       (local-set-key [menu-bar mailcrypt]
  1104.              (cons "Mailcrypt" (make-sparse-keymap "Mailcrypt")))
  1105.       (local-set-key [menu-bar mailcrypt decrypt]
  1106.              (cons "Decrypt Message" decrypt))
  1107.       (local-set-key [menu-bar mailcrypt verify]
  1108.              (cons "Verify Signature" verify))
  1109.       (local-set-key [menu-bar mailcrypt snarf]
  1110.              (cons "Snarf Public Key" snarf)))))
  1111.  
  1112. (defun mc-create-write-menu-bar ()
  1113.   ;; Create a menu bar entry for writing modes.
  1114.   (if (string-match "Lucid\\|XEmacs" (emacs-version))
  1115.       (let ((x (list "Mailcrypt"
  1116.              (vector "Encrypt Message" 'mc-encrypt-message t)
  1117.              (vector "Sign Message" 'mc-sign-message t)
  1118.              (vector "Insert Public Key" 'mc-insert-public-key t))))
  1119.     (set-buffer-menubar current-menubar)
  1120.     (add-menu nil "Mailcrypt" (cdr x)))
  1121.     (local-set-key [menu-bar mailcrypt]
  1122.            (cons "Mailcrypt" (make-sparse-keymap "Mailcrypt")))
  1123.     (local-set-key [menu-bar mailcrypt encrypt]
  1124.            (cons "Encrypt Message" 'mc-encrypt-message))
  1125.     (local-set-key [menu-bar mailcrypt sign]
  1126.            (cons "Sign Message" 'mc-sign-message))
  1127.     (local-set-key [menu-bar mailcrypt insert]
  1128.            (cons "Insert Public Key" 'mc-insert-public-key))))
  1129.  
  1130. ;;}}}
  1131. ;;{{{ Define several aliases so that an apropos on `mailcrypt' will
  1132. ;; return something.
  1133. (fset 'mailcrypt-encrypt-message 'mc-encrypt-message)
  1134. (fset 'mailcrypt-decrypt-message 'mc-decrypt-message)
  1135. (fset 'mailcrypt-sign-message 'mc-sign-message)
  1136. (fset 'mailcrypt-verify-signature 'mc-verify-signature)
  1137. (fset 'mailcrypt-insert-public-keys 'mc-insert-public-key)
  1138. (fset 'mailcrypt-snarf-keys 'mc-snarf-keys)
  1139. ;;}}}
  1140.  
  1141. (provide 'mailcrypt)
  1142.  
  1143.  
  1144.  
  1145.