Sync with semi-1_13.
[elisp/semi.git] / mime-mc.el
index c09bd8f..4782504 100644 (file)
@@ -1,4 +1,4 @@
-;;; mime-mc.el --- Mailcrypt interface for SEMI
+;;; mime-mc.el --- Mailcrypt interface for SEMI -*- coding: iso-8859-4; -*-
 
 ;; Copyright (C) 1996,1997,1998,1999 MORIOKA Tomohiko
 
 
 ;;; Code:
 
+(require 'alist)
+(require 'std11)
+(require 'semi-def)
+(require 'mime-def)
+(require 'mailcrypt)
+
 (eval-when-compile
   (load "expect" t)
   )
 
-(require 'semi-def)
-(require 'mailcrypt)
-
 (eval-and-compile
   (mapcar
    (function (lambda (elem) (apply 'autoload elem)))
    '(
      (mc-gpg-debug-print       "mc-gpg")
+
      (mc-gpg-encrypt-region    "mc-gpg")
+     (mc-gpg-fetch-key         "mc-gpg")
      (mc-gpg-lookup-key                "mc-gpg")
+     (mc-gpg-sign-region       "mc-gpg")
+
      (mc-pgp50-encrypt-region  "mc-pgp5")
+     (mc-pgp50-fetch-key       "mc-pgp5")
      (mc-pgp50-lookup-key      "mc-pgp5")
+     (mc-pgp50-sign-region     "mc-pgp5")
+
      (mc-pgp-encrypt-region    "mc-pgp")
+     (mc-pgp-fetch-key         "mc-pgp")
      (mc-pgp-lookup-key                "mc-pgp")
+     (mc-pgp-sign-region       "mc-pgp")
+
      (mc-snarf-keys            "mc-toplev")
      )))
 
-(defvar mc-gpg-comment)
+(defgroup mime-mc nil
+  "Mailcrypt interface for SEMI."
+  :prefix "mime-mc-"
+  :group 'mime)
+
+(defcustom mime-mc-shell-file-name "/bin/sh"
+  "File name to load inferior shells from.  Bourne shell or its equivalent
+\(not tcsh) is needed for \"2>\"."
+  :group 'mime-mc
+  :type 'file)
+
+(defcustom mime-mc-shell-command-switch "-c"
+  "Switch used to have the shell execute its command line argument."
+  :group 'mime-mc
+  :type 'string)
+
+(defcustom mime-mc-omit-micalg nil
+  "Non-nil value means to omit the micalg parameter for multipart/signed.
+See draft-yamamoto-openpgp-mime-00.txt (OpenPGP/MIME) for more information."
+  :group 'mime-mc
+  :type 'boolean)
+
+(defcustom mime-mc-comment-alist
+  (let ((product-name (mime-product-name mime-user-interface-product))
+       (version (mapconcat
+                 (function number-to-string)
+                 (mime-product-version mime-user-interface-product)
+                 "."))
+       (codename (mime-product-code-name mime-user-interface-product))
+       string)
+    (while (string-match "ò" codename)
+      (setq codename (replace-match "o" t nil codename)))
+    (while (string-match "þ" codename)
+      (setq codename (replace-match "u" t nil codename)))
+    (setq string (format "Processed by Mailcrypt %s under %s %s%s"
+                        mc-version product-name version
+                        (if (string-match "^[ -~]+$" codename)
+                            (concat " - \"" codename "\"")
+                          "")))
+    (list (cons 'gpg string)
+         (cons 'pgp50 string)
+         (cons 'pgp string)))
+  "Alist of the schemes and strings of the comment field to appear in ASCII
+armor output."
+  :group 'mime-mc
+  :type '(repeat (cons :format "%v"
+                      (choice (choice-item :tag "GnuPG" gpg)
+                              (choice-item :tag "PGP 5.0i" pgp50)
+                              (choice-item :tag "PGP 2.6" pgp))
+                      (string :tag "Comment"))))
+
+(defvar mime-mc-symbol-format-alist
+  '((comment           . "mc-%s-comment")
+    (fetch-key         . "mc-%s-fetch-key")
+    (insert-key                . "mc-%s-insert-public-key")
+    (mime-encrypt      . "mime-mc-%s-encrypt-region")
+    (mime-sign         . "mime-mc-%s-sign-region")
+    (scheme            . "mc-scheme-%s")
+    (traditional-sign  . "mc-%s-sign-region")
+    )
+  "Alist of service names and corresponding format strings.")
+
+(defmacro mime-mc-symbol (service)
+  (` (intern
+      (format (cdr (assq (, service) mime-mc-symbol-format-alist))
+             pgp-version))))
+
+(defmacro mime-mc-comment ()
+  "Return a string of the comment field."
+  '(or (cdr (assq pgp-version mime-mc-comment-alist))
+       (symbol-value (mime-mc-symbol 'comment))
+       ))
+
+
+;;; @ Internal variable
+;;;
+
+(defvar mime-mc-micalg-alist nil
+  "Alist of KeyID and the value of message integrity check algorithm.")
+
+
+;;; @ External variables (for avoid byte compile warnings)
+;;;
+
 (defvar mc-gpg-extra-args)
 (defvar mc-gpg-path)
 (defvar mc-gpg-user-id)
-(defvar mc-pgp50-comment)
 (defvar mc-pgp50-pgps-path)
 (defvar mc-pgp50-user-id)
-(defvar mc-pgp-comment)
 (defvar mc-pgp-path)
 (defvar mc-pgp-user-id)
 
@@ -91,53 +185,133 @@ VERSION should be a string or a symbol."
     (message "PGP version set to %s." (car (rassq pgp-version table)))
     ))
 
-(defun mime-mc-insert-public-key (&optional userid scheme)
-  (mc-insert-public-key
-   userid
-   (or scheme (intern (format "mc-scheme-%s" pgp-version)))
-   ))
+(defun mime-mc-replace-comment-field (comment &optional start end)
+  (let ((regexp (if (eq 'pgp pgp-version)
+                   "-----BEGIN PGP.*-----\nVersion:"
+                 "^-----BEGIN PGP.*\n")))
+    (save-excursion
+      (save-restriction
+       (narrow-to-region (or start (point-min)) (or end (point-max)))
+       (goto-char (point-min))
+       (while (re-search-forward regexp nil t)
+         (forward-line 1)
+         (save-restriction
+           (narrow-to-region (point)
+                             (if (search-forward "\n\n" nil t)
+                                 (point)
+                               (point-max)))
+           (goto-char (point-min))
+           (if (re-search-forward "^Comment:.*$" nil t)
+               (replace-match (concat "Comment: " comment))
+             )))
+       (point-max)))))
 
 (defun mime-mc-verify ()
-  (let ((mc-default-scheme (intern (format "mc-scheme-%s" pgp-version))))
+  "Verify a message in the current buffer. Exact behavior depends on
+current major mode."
+  (let ((mc-default-scheme (mime-mc-symbol 'scheme)))
     (mc-verify)
     ))
 
 (defun mime-mc-decrypt ()
-  (let ((mc-default-scheme (intern (format "mc-scheme-%s" pgp-version))))
-    (mc-decrypt)
-    ))
+  "Decrypt a message in the current buffer. Exact behavior depends on
+current major mode."
+  (let ((mc-default-scheme (mime-mc-symbol 'scheme)))
+    (if (eq 'mc-scheme-gpg mc-default-scheme)
+       (condition-case nil
+           (mc-decrypt)
+         (error
+          (let ((ofunc (symbol-function 'mc-gpg-decrypt-region)))
+            (message "\"mc-gpg.el\" may be broken.  Trying to fix it...")
+            (sit-for 1)
+            (defun mc-gpg-decrypt-region (start end &optional id)
+              (funcall ofunc start end (or id mc-gpg-user-id)))
+            (unwind-protect
+                (mc-decrypt)
+              (fset 'mc-gpg-decrypt-region ofunc)))))
+      (mc-decrypt)
+      )))
+
+(defun mime-mc-fetch-key (&optional id)
+  "Attempt to fetch a key for addition to PGP or GnuPG keyring.
+Interactively, prompt for string matching key to fetch.
+
+Non-interactively, ID must be a pair.  The CAR must be a bare Email
+address and the CDR a keyID (with \"0x\" prefix).  Either, but not
+both, may be nil.
+
+Return t if we think we were successful; nil otherwise.  Note that nil
+is not necessarily an error, since we may have merely fired off an Email
+request for the key."
+  (funcall (mime-mc-symbol 'fetch-key) id)
+  )
 
 (defun mime-mc-snarf-keys ()
-  (let ((mc-default-scheme (intern (format "mc-scheme-%s" pgp-version))))
+  "Add all public keys in the buffer to your keyring."
+  (let ((mc-default-scheme (mime-mc-symbol 'scheme)))
     (mc-snarf-keys)
     ))
 
+(defun mime-mc-sign-region (start end &optional id unclear boundary)
+  (funcall (mime-mc-symbol 'mime-sign) start end id unclear boundary)
+  )
+
+(defun mime-mc-traditional-sign-region (start end &optional id unclear)
+  (funcall (mime-mc-symbol 'traditional-sign) start end id unclear)
+  )
+
+(defun mime-mc-encrypt-region (recipients start end &optional id sign)
+  (funcall (mime-mc-symbol 'mime-encrypt) recipients start end id sign)
+  )
+
+(defun mime-mc-insert-public-key (&optional userid)
+  "Insert your public key at point."
+  (or (fboundp (mime-mc-symbol 'insert-key))
+      (load (concat "mc-" (cdr (assq pgp-version '((gpg . "gpg")
+                                                  (pgp50 . "pgp5")
+                                                  (pgp . "pgp")))))))
+  (let ((mc-comment (mime-mc-symbol 'comment))
+       (comment (mime-mc-comment))
+       (scheme (mime-mc-symbol 'scheme)))
+    (eval (` (let (((, mc-comment) (if (, comment) "DUMMY")))
+              (mc-insert-public-key (, userid) (quote (, scheme)))
+              )))
+    (if comment
+       (mime-mc-replace-comment-field comment)
+      )))
+
 
 ;;; @ GnuPG functions
 ;;;
 
 (defun mime-mc-gpg-process-region
-  (beg end passwd program args parser bufferdummy boundary)
+  (beg end passwd program args parser bufferdummy &optional boundary comment)
+  "Similar to `mc-gpg-process-region', however enclose an processed data
+with BOUNDARY if it is specified and replace the comment field with the
+optional argument COMMENT if it is specified."
   (let ((obuf (current-buffer))
        (process-connection-type nil)
-       (shell-file-name "/bin/sh") ;; ??? force? need sh (not tcsh) for "2>"
+       (shell-file-name mime-mc-shell-file-name)
+       (shell-command-switch mime-mc-shell-command-switch)
        ; other local vars
-       mybuf
+       mybuf 
        stderr-tempfilename stderr-buf
        status-tempfilename status-buf
        proc rc status parser-result
        )
-    (mc-gpg-debug-print (format
-                        "(mc-gpg-process-region beg=%s end=%s passwd=%s program=%s args=%s parser=%s bufferdummy=%s)"
-                        beg end passwd program args parser bufferdummy))
-    (setq stderr-tempfilename
+    (mc-gpg-debug-print (format 
+       "(mime-mc-gpg-process-region beg=%s end=%s passwd=%s program=%s args=%s parser=%s bufferdummy=%s boundary=%s comment=%s)"
+       beg end passwd program args parser bufferdummy boundary comment))
+    (setq stderr-tempfilename 
          (make-temp-name (expand-file-name "mailcrypt-gpg-stderr-"
                                            mc-temp-directory)))
-    (setq status-tempfilename
+    (setq status-tempfilename 
          (make-temp-name (expand-file-name "mailcrypt-gpg-status-"
                                            mc-temp-directory)))
     (unwind-protect
-       (progn
+       (catch ;; Returns non-nil if success, otherwise nil with error message.
+           'mime-mc-gpg-process-region-done
+
          ;; get output places ready
          (setq mybuf (get-buffer-create " *mailcrypt stdout temp"))
          (set-buffer mybuf)
@@ -151,17 +325,21 @@ VERSION should be a string or a symbol."
          (setq args (append (list (concat "3>" status-tempfilename)) args))
          (setq args (append '("--status-fd" "3") args))
 
+         (if comment
+             (setq args (append '("--comment" "DUMMY") args))
+           )
+
          (if mc-gpg-extra-args
              (setq args (append mc-gpg-extra-args args)))
 
-         (mc-gpg-debug-print (format "prog is %s, args are %s"
-                                     program
-                                     (mapconcat '(lambda (x)
-                                                   (format "'%s'" x))
+         (mc-gpg-debug-print (format "prog is %s, args are %s" 
+                                     program 
+                                     (mapconcat '(lambda (x) 
+                                                   (format "'%s'" x)) 
                                                 args " ")))
 
          (setq proc
-               (apply 'start-process-shell-command "*GPG*" mybuf
+               (apply 'start-process-shell-command "*GPG*" mybuf 
                       program args))
          ;; send in passwd if necessary
          (if passwd
@@ -196,12 +374,18 @@ VERSION should be a string or a symbol."
          ;; ponder process death: signal, not just rc!=0
          (if (or (eq 'stop status) (eq 'signal status))
              ;; process died
-             (error "%s exited abnormally: '%s'" program rc) ;;is rc a string?
-           )
+             (progn
+               (message
+                "%s exited abnormally: '%s'" program rc) ;; is rc a string?
+               (throw 'mime-mc-gpg-process-region-done nil)
+               ))
 
          (if (= 127 rc)
-             (error "%s could not be found" program) ;; at least on my system
-           )
+             (progn
+               (message
+                "%s could not be found" program) ;; at least on my system
+               (throw 'mime-mc-gpg-process-region-done nil)
+               ))
 
          ;; fill stderr buf
          (setq stderr-buf (get-buffer-create " *mailcrypt stderr temp"))
@@ -217,9 +401,23 @@ VERSION should be a string or a symbol."
          (erase-buffer)
          (insert-file-contents status-tempfilename)
 
-         ;; feed the parser
+         ;; replace comment string
          (set-buffer mybuf)
-         (setq parser-result (funcall parser mybuf stderr-buf status-buf rc))
+         (if comment
+             (mime-mc-replace-comment-field comment)
+           )
+
+         ;; feed the parser
+         (condition-case err
+             (setq parser-result
+                   (if (boundp 'mc-gpg-handle-pre095)
+                       (funcall parser mybuf stderr-buf status-buf rc)
+                     (funcall parser mybuf stderr-buf status-buf rc nil))
+                   )
+           (error
+            (message "%s" err)
+            (throw 'mime-mc-gpg-process-region-done nil)
+            ))
          (mc-gpg-debug-print (format " parser returned %s" parser-result))
 
          ;; what did the parser tell us?
@@ -277,99 +475,173 @@ Content-Transfer-Encoding: 7bit
        passwd args key
        (parser (function mc-gpg-insert-parser))
        (pgp-path mc-gpg-path)
+       micalg
+       (comment (mime-mc-comment))
        )
-    (setq key (mc-gpg-lookup-key (or id mc-gpg-user-id)))
+    (setq key (mc-gpg-lookup-key (or id mc-gpg-user-id) 'sign))
     (setq passwd
          (mc-activate-passwd
-          (cdr key)
-          (format "GnuPG passphrase for %s (%s): " (car key) (cdr key))))
-    (setq args
-         (cons
-          (if boundary
-              "--detach-sign"
-            (if unclear
-                "--sign"
-              "--clearsign"))
-          (list "--passphrase-fd" "0"
-                "--armor" "--batch" "--textmode" "--verbose"
-                "--local-user" (cdr key))))
-    (if mc-gpg-comment
-       (setq args (nconc args
-                         (list "--comment"
-                               (format "\"%s\"" mc-gpg-comment))))
-      )
-    (if (and boundary
-            (string-match "^pgp-" boundary))
-       (setq boundary
-             (concat "gpg-" (substring boundary (match-end 0))))
-      )
-    (message "Signing as %s ..." (car key))
-    (if (mime-mc-gpg-process-region
-        start end passwd pgp-path args parser buffer boundary)
+          (car key)
+          (format "GPG passphrase for %s (%s): " (car key) (cdr key))))
+    (setq args (cons
+               (if boundary
+                   "--detach-sign"
+                 (if unclear
+                     "--sign"
+                   "--clearsign")
+                 )
+               (list "--armor" "--batch" "--verbose"
+                     "--local-user" (cdr key))
+               ))
+    (if boundary
        (progn
-         (if boundary
-             (progn
+         (if (string-match "^pgp-" boundary)
+             (setq boundary
+                   (concat "gpg-" (substring boundary (match-end 0))))
+           )
+         (if (not (or mime-mc-omit-micalg
+                      (setq micalg
+                            (cdr (assoc (cdr key) mime-mc-micalg-alist)))
+                      ))
+             (with-temp-buffer
+               (message "Detecting the value of `micalg'...")
+               (insert "\n")
+               (if (let ((mc-passwd-timeout 60)) ;; Don't deactivate passwd.
+                     (mime-mc-gpg-process-region
+                      1 2 passwd pgp-path
+                      (list "--clearsign" "--armor" "--batch"
+                            "--verbose" "--local-user" (cdr key))
+                      parser buffer nil)
+                     )
+                   (progn
+                     (std11-narrow-to-header)
+                     (setq micalg
+                           (downcase (or (std11-fetch-field "Hash") "md5"))
+                           )
+                     (set-alist 'mime-mc-micalg-alist (cdr key) micalg)
+                     )
+                 (or mc-passwd-timeout (mc-deactivate-passwd t))
+                 ))
+           )))
+    (if (or mime-mc-omit-micalg micalg)
+       (let ((cur (current-buffer))
+             result)
+         (message "Signing as %s ..." (car key))
+         (if (with-temp-buffer
+               (insert-buffer-substring cur start end)
                (goto-char (point-min))
-               (insert
-                (format "\
+               (while (progn
+                        (end-of-line)
+                        (not (eobp)))
+                 (insert "\r")
+                 (forward-line 1))
+               (prog1
+                   (mime-mc-gpg-process-region (point-min) (point-max)
+                                               passwd pgp-path args parser
+                                               buffer boundary comment)
+                 (goto-char (point-min))
+                 (while (search-forward "\r\n" nil t)
+                   (forward-char -2)
+                   (delete-char 1))
+                 (setq result (buffer-string))))
+             (progn
+               (delete-region (goto-char start) end)
+               (insert result)
+               (if boundary
+                   (progn
+                     (goto-char (point-min))
+                     (insert
+                      (format "\
 --[[multipart/signed; protocol=\"application/pgp-signature\";
- boundary=\"%s\"; micalg=pgp-sha1][7bit]]\n" boundary))
-               ))
-         (message "Signing as %s ... Done." (car key))
-         t)
+ boundary=\"%s\"%s][7bit]]\n"
+                              boundary
+                              (if mime-mc-omit-micalg
+                                  ""
+                                (concat "; micalg=pgp-" micalg)
+                                )
+                              ))))
+               (message "Signing as %s ... Done." (car key))
+               t)
+           nil)
+         )
       nil)))
 
 (defun mime-mc-gpg-encrypt-region (recipients start end &optional id sign)
   (if (not (fboundp 'mc-gpg-encrypt-region))
       (load "mc-gpg")
     )
-  (let ((mc-pgp-always-sign (if (eq sign 'maybe)
-                               mc-pgp-always-sign
-                             'never)))
-    (mc-gpg-encrypt-region
-     (mc-split "\\([ \t\n]*,[ \t\n]*\\)+" recipients)
-     start end id nil)
-    ))
+  (let* ((mc-pgp-always-sign (if (eq sign 'maybe)
+                                mc-pgp-always-sign
+                              'never))
+        (comment (mime-mc-comment))
+        (mc-gpg-comment (if comment "DUMMY")))
+    (prog1
+       (mc-gpg-encrypt-region
+        (mc-split "\\([ \t\n]*,[ \t\n]*\\)+" recipients)
+        start end id nil)
+      (if comment
+         (mime-mc-replace-comment-field comment)
+       ))))
 
 
 ;;; @ PGP 5.0i functions
 ;;;
 
 (defun mime-mc-pgp50-process-region
-  (beg end passwd program args parser &optional buffer boundary)
+  (beg end passwd program args parser &optional buffer boundary comment)
+  "Similar to `mc-pgp50-process-region', however enclose an processed data
+with BOUNDARY if it is specified and replace the comment field with the
+optional argument COMMENT if it is specified."
   (let ((obuf (current-buffer))
        (process-connection-type nil)
-       (shell-file-name "/bin/sh")
+       (shell-file-name mime-mc-shell-file-name)
+       (shell-command-switch mime-mc-shell-command-switch)
        mybuf result rgn proc results)
+    (if comment
+       (setq args (cons "+comment=DUMMY" args))
+      )
     (unwind-protect
-       (progn
+       (catch ;; Returns non-nil if success, otherwise nil with error message.
+           'mime-mc-pgp50-process-region-done
+
          (setq mybuf (or buffer (generate-new-buffer " *mailcrypt temp")))
          (set-buffer mybuf)
          (erase-buffer)
          (set-buffer obuf)
          (buffer-disable-undo mybuf)
          (setq proc
-               (apply 'start-process-shell-command "*PGP*" mybuf program
+               (apply 'start-process-shell-command "*PGP*" mybuf program 
                       "2>&1" args))
 
          ;; Now hand the process to the parser, which returns the exit
          ;; status of the dead process and the limits of the region
          ;; containing the PGP results.
-         (setq results (funcall parser proc obuf beg end mybuf passwd))
+         (condition-case err
+             (setq results (funcall parser proc obuf beg end mybuf passwd))
+           (error
+            (message "%s" err)
+            (throw 'mime-mc-pgp50-process-region-done nil)
+            ))
          (setq result  (car results))
          (setq rgn     (cadr results))
 
          ;; Hack to force a status_notify() in Emacs 19.29
          (set-buffer mybuf)
 
+         ;; replace comment string
+         (if (and comment (consp rgn))
+             (setcdr rgn (mime-mc-replace-comment-field
+                          comment (car rgn) (cdr rgn)))
+           )
+
          ;; Hurm.  FIXME; must get better result codes.
          (if (stringp result)
              (mc-message result))
 
-         ;; If the parser found something, migrate it to the old
-         ;; buffer.  In particular, the parser's job is to return
-         ;; a cons of the form ( beg . end ) delimited the result
-         ;; of PGP in the new buffer.
+           ;; If the parser found something, migrate it to the old
+           ;; buffer.  In particular, the parser's job is to return
+           ;; a cons of the form ( beg . end ) delimited the result
+           ;; of PGP in the new buffer.
          (if (consp rgn)
              (progn
                (set-buffer obuf)
@@ -520,6 +792,8 @@ Content-Transfer-Encoding: 7bit
                    (function mime-mc-pgp50-sign-parser)
                  (function mc-pgp50-sign-parser)))
        (pgp-path mc-pgp50-pgps-path)
+       micalg
+       (comment (mime-mc-comment))
        )
     (setq key (mc-pgp50-lookup-key (or id mc-pgp50-user-id)))
     (setq passwd
@@ -527,31 +801,59 @@ Content-Transfer-Encoding: 7bit
           (cdr key)
           (format "PGP passphrase for %s (%s): " (car key) (cdr key))))
     (setenv "PGPPASSFD" "0")
-    (setq args
-         (cons
-          (if boundary
-              "-fbat"
-            "-fat")
-          (list "+verbose=1" "+language=us"
-                (format "+clearsig=%s" (if unclear "off" "on"))
-                "+batchmode" "-u" (cdr key))))
-    (if mc-pgp50-comment
-       (setq args (cons (format "+comment=\"%s\"" mc-pgp50-comment) args))
+    (setq args (if boundary
+                  (list "-fbat" "+verbose=1" "+language=us" "+batchmode"
+                        "-u" (cdr key))
+                (list "-fat" "+verbose=1" "+language=us"
+                      (format "+clearsig=%s" (if unclear "off" "on"))
+                      "+batchmode" "-u" (cdr key))
+                ))
+    (if (and boundary
+            (not (or mime-mc-omit-micalg
+                     (setq micalg
+                           (cdr (assoc (cdr key) mime-mc-micalg-alist)))
+                     )))
+       (with-temp-buffer
+         (message "Detecting the value of `micalg'...")
+         (insert "\n")
+         (if (let ((mc-passwd-timeout 60)) ;; Don't deactivate passwd.
+               (mime-mc-pgp50-process-region
+                1 2 passwd pgp-path
+                (list "-fat" "+verbose=1" "+language=us" "+clearsig=on"
+                      "+batchmode" "-u" (cdr key))
+                (function mc-pgp50-sign-parser) buffer nil)
+               )
+             (progn
+               (std11-narrow-to-header)
+               (setq micalg (downcase (or (std11-fetch-field "Hash") "md5")))
+               (set-alist 'mime-mc-micalg-alist (cdr key) micalg)
+               )
+           (or mc-passwd-timeout (mc-deactivate-passwd t))
+           ))
       )
-    (message "Signing as %s ..." (car key))
-    (if (mime-mc-pgp50-process-region
-        start end passwd pgp-path args parser buffer boundary)
+    (if (or mime-mc-omit-micalg micalg)
        (progn
-         (if boundary
+         (message "Signing as %s ..." (car key))
+         (if (mime-mc-pgp50-process-region
+              start end passwd pgp-path args parser buffer boundary comment)
              (progn
-               (goto-char (point-min))
-               (insert
-                (format "\
+               (if boundary
+                   (progn
+                     (goto-char (point-min))
+                     (insert
+                      (format "\
 --[[multipart/signed; protocol=\"application/pgp-signature\";
- boundary=\"%s\"; micalg=pgp-sha1][7bit]]\n" boundary))
-               ))
-         (message "Signing as %s ... Done." (car key))
-         t)
+ boundary=\"%s\"%s][7bit]]\n"
+                              boundary
+                              (if mime-mc-omit-micalg
+                                  ""
+                                (concat "; micalg=pgp-" micalg)
+                                )
+                              ))))
+               (message "Signing as %s ... Done." (car key))
+               t)
+           nil)
+         )
       nil)))
 
 (defun mime-mc-pgp50-encrypt-region (recipients start end &optional id sign)
@@ -560,21 +862,32 @@ Content-Transfer-Encoding: 7bit
     )
   (let ((mc-pgp-always-sign (if (eq sign 'maybe)
                                mc-pgp-always-sign
-                             'never)))
-    (mc-pgp50-encrypt-region
-     (mc-split "\\([ \t\n]*,[ \t\n]*\\)+" recipients)
-     start end id nil)
-    ))
+                             'never))
+       (comment (mime-mc-comment))
+       (mc-pgp50-comment "DUMMY"))
+    (prog1
+       (mc-pgp50-encrypt-region
+        (mc-split "\\([ \t\n]*,[ \t\n]*\\)+" recipients)
+        start end id nil)
+      (if comment
+         (mime-mc-replace-comment-field comment)
+       ))))
 
 
 ;;; @ PGP 2.6 functions
 ;;;
 
 (defun mime-mc-process-region
-  (beg end passwd program args parser &optional buffer boundary)
+  (beg end passwd program args parser &optional buffer boundary comment)
+  "Similar to `mc-pgp-process-region', however enclose an processed data
+with BOUNDARY if it is specified and replace the comment field with the
+optional argument COMMENT if it is specified."
   (let ((obuf (current-buffer))
        (process-connection-type nil)
        mybuf result rgn proc)
+    (if comment
+       (setq args (cons "+comment=DUMMY" args))
+      )
     (unwind-protect
        (progn
          (setq mybuf (or buffer (generate-new-buffer " *mailcrypt temp")))
@@ -606,6 +919,10 @@ Content-Transfer-Encoding: 7bit
          ;; Hurm.  FIXME; must get better result codes.
          (if (stringp result)
              (error "%s exited abnormally: '%s'" program result)
+           ;; replace comment string
+           (if comment
+               (mime-mc-replace-comment-field comment)
+             )
            (setq rgn (funcall parser result))
            ;; If the parser found something, migrate it
            (if (consp rgn)
@@ -649,6 +966,7 @@ Content-Transfer-Encoding: 7bit
        passwd args key
        (parser (function mc-pgp-generic-parser))
        (pgp-path mc-pgp-path)
+       (comment (mime-mc-comment))
        )
     (setq key (mc-pgp-lookup-key (or id mc-pgp-user-id)))
     (setq passwd
@@ -664,12 +982,9 @@ Content-Transfer-Encoding: 7bit
           (list "+verbose=1" "+language=en"
                 (format "+clearsig=%s" (if unclear "off" "on"))
                 "+batchmode" "-u" (cdr key))))
-    (if mc-pgp-comment
-       (setq args (cons (format "+comment=%s" mc-pgp-comment) args))
-      )
     (message "Signing as %s ..." (car key))
     (if (mime-mc-process-region
-        start end passwd pgp-path args parser buffer boundary)
+        start end passwd pgp-path args parser buffer boundary comment)
        (progn
          (if boundary
              (progn
@@ -677,8 +992,13 @@ Content-Transfer-Encoding: 7bit
                (insert
                 (format "\
 --[[multipart/signed; protocol=\"application/pgp-signature\";
- boundary=\"%s\"; micalg=pgp-md5][7bit]]\n" boundary))
-               ))
+ boundary=\"%s\"%s][7bit]]\n"
+                        boundary
+                        (if mime-mc-omit-micalg
+                            ""
+                          "; micalg=pgp-md5"
+                          )
+                        ))))
          (message "Signing as %s ... Done." (car key))
          t)
       nil)))
@@ -689,11 +1009,16 @@ Content-Transfer-Encoding: 7bit
     )
   (let ((mc-pgp-always-sign (if (eq sign 'maybe)
                                mc-pgp-always-sign
-                             'never)))
-    (mc-pgp-encrypt-region
-     (mc-split "\\([ \t\n]*,[ \t\n]*\\)+" recipients)
-     start end id nil)
-    ))
+                             'never))
+       (comment (mime-mc-comment))
+       (mc-pgp-comment "DUMMY"))
+    (prog1
+       (mc-pgp-encrypt-region
+        (mc-split "\\([ \t\n]*,[ \t\n]*\\)+" recipients)
+        start end id nil)
+      (if comment
+         (mime-mc-replace-comment-field comment)
+       ))))
 
 
 ;;; @ end