+(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
+ ", "))
+