+ (expand-file-name
+ (or keyfile
+ (smime-get-key-by-email
+ (gnus-completing-read
+ "Decipher using key"
+ smime-keys nil (car-safe (car-safe smime-keys)))))))))
+
+;; Various operations
+
+(defun smime-new-details-buffer ()
+ (with-current-buffer (get-buffer-create smime-details-buffer)
+ (erase-buffer)))
+
+(defun smime-pkcs7-region (b e)
+ "Convert S/MIME message between points B and E into a PKCS7 message."
+ (smime-new-details-buffer)
+ (when (smime-call-openssl-region b e smime-details-buffer "smime" "-pk7out")
+ (delete-region b e)
+ (insert-buffer-substring smime-details-buffer)
+ t))
+
+(defun smime-pkcs7-certificates-region (b e)
+ "Extract any certificates enclosed in PKCS7 message between points B and E."
+ (smime-new-details-buffer)
+ (when (smime-call-openssl-region
+ b e smime-details-buffer "pkcs7" "-print_certs" "-text")
+ (delete-region b e)
+ (insert-buffer-substring smime-details-buffer)
+ t))
+
+(defun smime-pkcs7-email-region (b e)
+ "Get email addresses contained in certificate between points B and E.
+A string or a list of strings is returned."
+ (smime-new-details-buffer)
+ (when (smime-call-openssl-region
+ b e smime-details-buffer "x509" "-email" "-noout")
+ (delete-region b e)
+ (insert-buffer-substring smime-details-buffer)
+ t))
+
+;; Utility functions
+
+(defun smime-get-certfiles (keyfile keys)
+ (if keys
+ (let ((curkey (car keys))
+ (otherkeys (cdr keys)))
+ (if (string= keyfile (cadr curkey))
+ (caddr curkey)
+ (smime-get-certfiles keyfile otherkeys)))))
+
+(defun smime-buffer-as-string-region (b e)
+ "Return each line in region between B and E as a list of strings."
+ (save-excursion
+ (goto-char b)
+ (let (res)
+ (while (< (point) e)
+ (let ((str (buffer-substring (point) (point-at-eol))))
+ (unless (string= "" str)
+ (push str res)))
+ (forward-line))
+ res)))
+
+;; Find certificates
+
+(defun smime-mail-to-domain (mailaddr)
+ (if (string-match "@" mailaddr)
+ (replace-match "." 'fixedcase 'literal mailaddr)
+ mailaddr))
+
+(defun smime-cert-by-dns (mail)
+ "Find certificate via DNS for address MAIL."
+ (let* ((dig-dns-server smime-dns-server)
+ (digbuf (dig-invoke (smime-mail-to-domain mail) "cert" nil nil "+vc"))
+ (retbuf (generate-new-buffer (format "*certificate for %s*" mail)))
+ (certrr (with-current-buffer digbuf
+ (dig-extract-rr (smime-mail-to-domain mail) "cert")))
+ (cert (and certrr (dig-rr-get-pkix-cert certrr))))
+ (if cert
+ (with-current-buffer retbuf
+ (insert "-----BEGIN CERTIFICATE-----\n")
+ (let ((i 0) (len (length cert)))
+ (while (> (- len 64) i)
+ (insert (substring cert i (+ i 64)) "\n")
+ (setq i (+ i 64)))
+ (insert (substring cert i len) "\n"))
+ (insert "-----END CERTIFICATE-----\n"))
+ (kill-buffer retbuf)
+ (setq retbuf nil))
+ (kill-buffer digbuf)
+ retbuf))
+
+(defun smime-cert-by-ldap-1 (mail host)
+ "Get cetificate for MAIL from the ldap server at HOST."
+ (let ((ldapresult
+ (funcall
+ (if (featurep 'xemacs)
+ (progn
+ (require 'smime-ldap)
+ 'smime-ldap-search)
+ 'ldap-search)
+ (concat "mail=" mail)
+ host '("userCertificate") nil))
+ (retbuf (generate-new-buffer (format "*certificate for %s*" mail)))
+ cert)
+ (if (and (>= (length ldapresult) 1)
+ (> (length (cadaar ldapresult)) 0))
+ (with-current-buffer retbuf
+ ;; Certificates on LDAP servers _should_ be in DER format,
+ ;; but there are some servers out there that distributes the
+ ;; certificates in PEM format (with or without
+ ;; header/footer) so we try to handle them anyway.
+ (if (or (string= (substring (cadaar ldapresult) 0 27)
+ "-----BEGIN CERTIFICATE-----")
+ (string= (substring (cadaar ldapresult) 0 3)
+ "MII"))
+ (setq cert
+ (smime-replace-in-string
+ (cadaar ldapresult)
+ (concat "\\(\n\\|\r\\|-----BEGIN CERTIFICATE-----\\|"
+ "-----END CERTIFICATE-----\\)")
+ "" t))
+ (setq cert (base64-encode-string (cadaar ldapresult) t)))
+ (insert "-----BEGIN CERTIFICATE-----\n")
+ (let ((i 0) (len (length cert)))
+ (while (> (- len 64) i)
+ (insert (substring cert i (+ i 64)) "\n")
+ (setq i (+ i 64)))
+ (insert (substring cert i len) "\n"))
+ (insert "-----END CERTIFICATE-----\n"))
+ (kill-buffer retbuf)
+ (setq retbuf nil))
+ retbuf))
+
+(defun smime-cert-by-ldap (mail)
+ "Find certificate via LDAP for address MAIL."
+ (if smime-ldap-host-list
+ (catch 'certbuf
+ (dolist (host smime-ldap-host-list)
+ (let ((retbuf (smime-cert-by-ldap-1 mail host)))
+ (when retbuf
+ (throw 'certbuf retbuf)))))))