+;;;###autoload
+(defun epg-start-sign-keys (context keys &optional local)
+ "Initiate an sign keys operation.
+
+If you use this function, you will need to wait for the completion of
+`epg-gpg-program' by using `epg-wait-for-completion' and call
+`epg-reset' to clear a temporaly output file.
+If you are unsure, use synchronous version of this function
+`epg-sign-keys' instead."
+ (epg-context-set-operation context 'sign-keys)
+ (epg-context-set-result context nil)
+ (epg--start context (cons (if local
+ "--lsign-key"
+ "--sign-key")
+ (mapcar
+ (lambda (key)
+ (epg-sub-key-id
+ (car (epg-key-sub-key-list key))))
+ keys))))
+
+;;;###autoload
+(defun epg-sign-keys (context keys &optional local)
+ "Sign KEYS from the key ring."
+ (unwind-protect
+ (progn
+ (epg-start-sign-keys context keys local)
+ (epg-wait-for-completion context)
+ (if (epg-context-result-for context 'error)
+ (error "Sign keys failed: %S"
+ (epg-context-result-for context 'error))))
+ (epg-reset context)))
+
+;;;###autoload
+(defun epg-start-generate-key (context parameters)
+ "Initiate a key generation.
+PARAMETERS specifies parameters for the key.
+
+If you use this function, you will need to wait for the completion of
+`epg-gpg-program' by using `epg-wait-for-completion' and call
+`epg-reset' to clear a temporaly output file.
+If you are unsure, use synchronous version of this function
+`epg-generate-key-from-file' or `epg-generate-key-from-string' instead."
+ (epg-context-set-operation context 'generate-key)
+ (epg-context-set-result context nil)
+ (if (epg-data-file parameters)
+ (epg--start context (list "--batch" "--genkey"
+ (epg-data-file parameters)))
+ (epg--start context '("--batch" "--genkey"))
+ (if (eq (process-status (epg-context-process context)) 'run)
+ (process-send-string (epg-context-process context)
+ (epg-data-string parameters)))
+ (if (eq (process-status (epg-context-process context)) 'run)
+ (process-send-eof (epg-context-process context)))))
+
+;;;###autoload
+(defun epg-generate-key-from-file (context parameters)
+ "Generate a new key pair.
+PARAMETERS is a file which tells how to create the key."
+ (unwind-protect
+ (progn
+ (epg-start-generate-key context (epg-make-data-from-file parameters))
+ (epg-wait-for-completion context)
+ (if (epg-context-result-for context 'error)
+ (error "Generate key failed: %S"
+ (epg-context-result-for context 'error))))
+ (epg-reset context)))
+
+;;;###autoload
+(defun epg-generate-key-from-string (context parameters)
+ "Generate a new key pair.
+PARAMETERS is a string which tells how to create the key."
+ (unwind-protect
+ (progn
+ (epg-start-generate-key context (epg-make-data-from-string parameters))
+ (epg-wait-for-completion context)
+ (if (epg-context-result-for context 'error)
+ (error "Generate key failed: %S"
+ (epg-context-result-for context 'error))))
+ (epg-reset context)))
+
+(defun epg--decode-hexstring (string)
+ (let ((index 0))
+ (while (eq index (string-match "[0-9A-Fa-f][0-9A-Fa-f]" string index))
+ (setq string (replace-match "\\x\\&" t nil string)
+ index (+ index 4)))
+ (car (read-from-string (concat "\"" string "\"")))))
+
+(defun epg--decode-quotedstring (string)
+ (let ((index 0))
+ (while (string-match "\\\\\\(\\([,=+<>#;\\\"]\\)\\|\
+\\([0-9A-Fa-f][0-9A-Fa-f]\\)\\|\\(.\\)\\)"
+ string index)
+ (if (match-beginning 2)
+ (setq string (replace-match "\\2" t nil string)
+ index (1+ index))
+ (if (match-beginning 3)
+ (setq string (replace-match "\\x\\3" t nil string)
+ index (+ index 4))
+ (setq string (replace-match "\\\\\\\\\\4" t nil string)
+ index (+ index 3)))))
+ (car (read-from-string (concat "\"" string "\"")))))
+
+(defun epg-dn-from-string (string)
+ "Parse STRING as LADPv3 Distinguished Names (RFC2253).
+The return value is an alist mapping from types to values."
+ (let ((index 0)
+ (length (length string))
+ alist type value group)
+ (while (< index length)
+ (if (eq index (string-match "[ \t\n\r]*" string index))
+ (setq index (match-end 0)))
+ (if (eq index (string-match
+ "\\([0-9]+\\(\\.[0-9]+\\)*\\)\[ \t\n\r]*=[ \t\n\r]*"
+ string index))
+ (setq type (match-string 1 string)
+ index (match-end 0))
+ (if (eq index (string-match "\\([0-9A-Za-z]+\\)[ \t\n\r]*=[ \t\n\r]*"
+ string index))
+ (setq type (match-string 1 string)
+ index (match-end 0))))
+ (unless type
+ (error "Invalid type"))
+ (if (eq index (string-match
+ "\\([^,=+<>#;\\\"]\\|\\\\.\\)+"
+ string index))
+ (setq index (match-end 0)
+ value (epg--decode-quotedstring (match-string 0 string)))
+ (if (eq index (string-match "#\\([0-9A-Fa-f]+\\)" string index))
+ (setq index (match-end 0)
+ value (epg--decode-hexstring (match-string 1 string)))
+ (if (eq index (string-match "\"\\([^\\\"]\\|\\\\.\\)*\""
+ string index))
+ (setq index (match-end 0)
+ value (epg--decode-quotedstring
+ (match-string 0 string))))))
+ (if group
+ (if (stringp (car (car alist)))
+ (setcar alist (list (cons type value) (car alist)))
+ (setcar alist (cons (cons type value) (car alist))))
+ (if (consp (car (car alist)))
+ (setcar alist (nreverse (car alist))))
+ (setq alist (cons (cons type value) alist)
+ type nil
+ value nil))
+ (if (eq index (string-match "[ \t\n\r]*\\([,;+]\\)" string index))
+ (setq index (match-end 0)
+ group (eq (aref string (match-beginning 1)) ?+))))
+ (nreverse alist)))
+
+(defun epg-decode-dn (alist)
+ "Convert ALIST returned by `epg-dn-from-string' to a human readable form.
+Type names are resolved using `epg-dn-type-alist'."
+ (mapconcat
+ (lambda (rdn)
+ (if (stringp (car rdn))
+ (let ((entry (assoc (car rdn) epg-dn-type-alist)))
+ (if entry
+ (format "%s=%s" (cdr entry) (cdr rdn))
+ (format "%s=%s" (car rdn) (cdr rdn))))
+ (concat "(" (epg-decode-dn rdn) ")")))
+ alist
+ ", "))
+