diff options
Diffstat (limited to 'lisp/gnus/rfc2231.el')
-rw-r--r-- | lisp/gnus/rfc2231.el | 223 |
1 files changed, 123 insertions, 100 deletions
diff --git a/lisp/gnus/rfc2231.el b/lisp/gnus/rfc2231.el index fb2d070328e..7b4cf2447f4 100644 --- a/lisp/gnus/rfc2231.el +++ b/lisp/gnus/rfc2231.el @@ -41,22 +41,19 @@ N.B. This is in violation with RFC2047, but it seem to be in common use." (rfc2231-parse-string (rfc2047-decode-string string))) -(defun rfc2231-parse-string (string) +(defun rfc2231-parse-string (string &optional signal-error) "Parse STRING and return a list. The list will be on the form - `(name (attribute . value) (attribute . value)...)" + `(name (attribute . value) (attribute . value)...)'. + +If the optional SIGNAL-ERROR is non-nil, signal an error when this +function fails in parsing of parameters." (with-temp-buffer (let ((ttoken (ietf-drums-token-to-list ietf-drums-text-token)) (stoken (ietf-drums-token-to-list ietf-drums-tspecials)) (ntoken (ietf-drums-token-to-list "0-9")) - (prev-value "") - display-name mailbox c display-string parameters - attribute value type subtype number encoded - prev-attribute prev-encoded) - ;; Some mailer (e.g. Thunderbird 1.5) doesn't terminate each - ;; line with semicolon when folding a long parameter value. - (while (string-match "\\([^\t\n\r ;]\\)[\t ]*\r?\n[\t ]+" string) - (setq string (replace-match "\\1;\n " nil nil string))) + c type attribute encoded number prev-attribute vals + prev-encoded parameters value) (ietf-drums-init (mail-header-remove-whitespace (mail-header-remove-comments string))) (let ((table (copy-syntax-table ietf-drums-syntax-table))) @@ -74,63 +71,76 @@ The list will be on the form (setq type (downcase (buffer-substring (point) (progn (forward-sexp 1) (point))))) ;; Do the params - (while (not (eobp)) - (setq c (char-after)) - (unless (eq c ?\;) - (error "Invalid header: %s" string)) - (forward-char 1) - ;; If c in nil, then this is an invalid header, but - ;; since elm generates invalid headers on this form, - ;; we allow it. - (when (setq c (char-after)) - (if (and (memq c ttoken) - (not (memq c stoken))) - (setq attribute - (intern - (downcase - (buffer-substring - (point) (progn (forward-sexp 1) (point)))))) - (error "Invalid header: %s" string)) - (setq c (char-after)) - (when (eq c ?*) - (forward-char 1) - (setq c (char-after)) - (if (not (memq c ntoken)) - (setq encoded t - number nil) - (setq number - (string-to-number - (buffer-substring - (point) (progn (forward-sexp 1) (point))))) + (condition-case err + (progn + (while (not (eobp)) (setq c (char-after)) - (when (eq c ?*) - (setq encoded t) + (unless (eq c ?\;) + (error "Invalid header: %s" string)) + (forward-char 1) + ;; If c in nil, then this is an invalid header, but + ;; since elm generates invalid headers on this form, + ;; we allow it. + (when (setq c (char-after)) + (if (and (memq c ttoken) + (not (memq c stoken))) + (setq attribute + (intern + (downcase + (buffer-substring + (point) (progn (forward-sexp 1) (point)))))) + (error "Invalid header: %s" string)) + (setq c (char-after)) + (if (eq c ?*) + (progn + (forward-char 1) + (setq c (char-after)) + (if (not (memq c ntoken)) + (setq encoded t + number nil) + (setq number + (string-to-number + (buffer-substring + (point) (progn (forward-sexp 1) (point))))) + (setq c (char-after)) + (when (eq c ?*) + (setq encoded t) + (forward-char 1) + (setq c (char-after))))) + (setq number nil + encoded nil)) + ;; See if we have any previous continuations. + (when (and prev-attribute + (not (eq prev-attribute attribute))) + (setq vals + (mapconcat 'cdr (sort vals 'car-less-than-car) "")) + (push (cons prev-attribute + (if prev-encoded + (rfc2231-decode-encoded-string vals) + vals)) + parameters) + (setq prev-attribute nil + vals nil + prev-encoded nil)) + (unless (eq c ?=) + (error "Invalid header: %s" string)) (forward-char 1) - (setq c (char-after))))) - ;; See if we have any previous continuations. - (when (and prev-attribute - (not (eq prev-attribute attribute))) - (push (cons prev-attribute - (if prev-encoded - (rfc2231-decode-encoded-string prev-value) - prev-value)) - parameters) - (setq prev-attribute nil - prev-value "" - prev-encoded nil)) - (unless (eq c ?=) - (error "Invalid header: %s" string)) - (forward-char 1) - (setq c (char-after)) - (cond - ((eq c ?\") - (setq value - (buffer-substring (1+ (point)) - (progn (forward-sexp 1) (1- (point)))))) - ((and (or (memq c ttoken) - (> c ?\177)) ;; EXTENSION: Support non-ascii chars. - (not (memq c stoken))) - (setq value (buffer-substring + (setq c (char-after)) + (cond + ((eq c ?\") + (setq value (buffer-substring (1+ (point)) + (progn + (forward-sexp 1) + (1- (point))))) + (when encoded + (setq value (mapconcat (lambda (c) (format "%%%02x" c)) + value "")))) + ((and (or (memq c ttoken) + ;; EXTENSION: Support non-ascii chars. + (> c ?\177)) + (not (memq c stoken))) + (setq value + (buffer-substring (point) (progn (forward-sexp) @@ -142,59 +152,72 @@ The list will be on the form (forward-char 1) (forward-sexp)) (point))))) - (t - (error "Invalid header: %s" string))) - (if number - (setq prev-attribute attribute - prev-value (concat prev-value value) - prev-encoded encoded) - (push (cons attribute - (if encoded - (rfc2231-decode-encoded-string value) - value)) - parameters)))) + (t + (error "Invalid header: %s" string))) + (if number + (progn + (push (cons number value) vals) + (setq prev-attribute attribute + prev-encoded encoded)) + (push (cons attribute + (if encoded + (rfc2231-decode-encoded-string value) + value)) + parameters)))) - ;; Take care of any final continuations. - (when prev-attribute - (push (cons prev-attribute - (if prev-encoded - (rfc2231-decode-encoded-string prev-value) - prev-value)) - parameters)) + ;; Take care of any final continuations. + (when prev-attribute + (setq vals (mapconcat 'cdr (sort vals 'car-less-than-car) "")) + (push (cons prev-attribute + (if prev-encoded + (rfc2231-decode-encoded-string vals) + vals)) + parameters))) + (error + (setq parameters nil) + (if signal-error + (signal (car err) (cdr err)) + ;;(message "%s" (error-message-string err)) + ))) (when type `(,type ,@(nreverse parameters))))))) (defun rfc2231-decode-encoded-string (string) "Decode an RFC2231-encoded string. -These look like \"us-ascii'en-us'This%20is%20%2A%2A%2Afun%2A%2A%2A\"." - (with-temp-buffer - (let ((elems (split-string string "'"))) - ;; The encoded string may contain zero to two single-quote - ;; marks. This should give us the encoded word stripped - ;; of any preceding values. - (insert (car (last elems))) +These look like: + \"us-ascii'en-us'This%20is%20%2A%2A%2Afun%2A%2A%2A\", + \"us-ascii''This%20is%20%2A%2A%2Afun%2A%2A%2A\", + \"'en-us'This%20is%20%2A%2A%2Afun%2A%2A%2A\", + \"''This%20is%20%2A%2A%2Afun%2A%2A%2A\", or + \"This is ***fun***\"." + (string-match "\\`\\(\\([^']+\\)?'\\([^']+\\)?'\\)?\\(.+\\)" string) + (let ((coding-system (mm-charset-to-coding-system (match-string 2 string))) + ;;(language (match-string 3 string)) + (value (match-string 4 string))) + (mm-with-multibyte-buffer + (insert value) (goto-char (point-min)) (while (search-forward "%" nil t) (insert (prog1 (string-to-number (buffer-substring (point) (+ (point) 2)) 16) (delete-region (1- (point)) (+ (point) 2))))) - ;; Encode using the charset, if any. - (when (and (mm-multibyte-p) - (> (length elems) 1) - (not (equal (intern (downcase (car elems))) 'us-ascii))) - (mm-decode-coding-region (point-min) (point-max) - (intern (downcase (car elems))))) + ;; Decode using the charset, if any. + (unless (memq coding-system '(nil ascii)) + (mm-decode-coding-region (point-min) (point-max) coding-system)) (buffer-string)))) (defun rfc2231-encode-string (param value) - "Return and PARAM=VALUE string encoded according to RFC2231." + "Return and PARAM=VALUE string encoded according to RFC2231. +Use `mml-insert-parameter' or `mml-insert-parameter-string' to insert +the result of this function." (let ((control (ietf-drums-token-to-list ietf-drums-no-ws-ctl-token)) (tspecial (ietf-drums-token-to-list ietf-drums-tspecials)) (special (ietf-drums-token-to-list "*'%\n\t")) (ascii (ietf-drums-token-to-list ietf-drums-text-token)) (num -1) + ;; Don't make lines exceeding 76 column. (limit (- 74 (length param))) spacep encodep charsetp charset broken) (with-temp-buffer @@ -241,17 +264,17 @@ These look like \"us-ascii'en-us'This%20is%20%2A%2A%2Afun%2A%2A%2A\"." (if (not broken) (insert param "*=") (while (not (eobp)) - (insert (if (>= num 0) " " "\n ") + (insert (if (>= num 0) " " "") param "*" (format "%d" (incf num)) "*=") (forward-line 1)))) (spacep (goto-char (point-min)) - (insert "\n " param "=\"") + (insert param "=\"") (goto-char (point-max)) (insert "\"")) (t (goto-char (point-min)) - (insert "\n " param "="))) + (insert param "="))) (buffer-string)))) (provide 'rfc2231) |