+
+;;; @ parameter value encoder
+;;;
+
+(defun mime-divide-extended-parameter (name value)
+ "Divide MIME parameter value \"NAME=VALUE\" into segments.
+Each of \" NAME*n*=SEGMENT_n\;\" will be no more than 78 characters.
+Return value is a list of string when division is performed, otherwise
+return value is just a string."
+ ;; `limit' must be more than (length "CHARSET'LANGUAGE'%XX").
+ ;;
+ ;; Since MIME spec does not limit either length of CHARSET or length
+ ;; of LANGUAGE, we choose 30 for minimum `limit' based on the longest
+ ;; name of charset that Emacs supports ("ISO-2022-CN-EXT"; 15 chars).
+ ;;
+ ;; Anyway, if `name' is too long, we will ignore 78 chars limit.
+ (let ((limit (max (- 78 4 (length name)) 30))); (length " *=;") => 4
+ (if (> limit (length value))
+ value
+ (let ((count 0)
+ result)
+ (setq limit (max (- limit 2) 30)) ; (length "*n") => 2
+ (with-temp-buffer
+ (set-buffer-multibyte nil)
+ (insert value)
+ (while (> (point-max) limit)
+ (goto-char (- limit 3)) ; (length "%XX") => 3
+ (cond
+ ((eq (char-after) ?%)
+ (forward-char 3))
+ ((progn
+ (forward-char)
+ (eq (char-after) ?%)))
+ ((progn
+ (forward-char)
+ (eq (char-after) ?%)))
+ (t
+ (forward-char)))
+ (setq result (cons (prog1 (buffer-substring (point-min)(point))
+ (delete-region (point-min)(point)))
+ result)
+ count (1+ count))
+ (when (zerop (% count 10))
+ (setq limit (max (1- limit) 30))))
+ (nreverse
+ (cons (buffer-substring (point-min)(point-max))
+ result)))))))
+
+(defun mime-encode-extended-parameter (name value)
+ "Encode MIME parameter value \"NAME=VALUE\" as an extended-parameter.
+If encoding is unnecessary, return nil.
+If division is performed, return value is a list of string, otherwise
+return value is just a string."
+ (let ((language (get-text-property 0 'mime-language value)))
+ (when (or language
+ (string-match "[^ -~]" value)) ; Nonmatching printable US-ASCII.
+ (with-temp-buffer
+ (let ((charset (find-mime-charset-by-charsets
+ (find-charset-string value))))
+ ;; I believe that `encode-mime-charset-string' of mcs-e20.el should
+ ;; be independent of the value of `enable-multibyte-characters'.
+ ;; -- shuhei
+ (set-buffer-multibyte t)
+ (setq value (encode-mime-charset-string value charset))
+ (set-buffer-multibyte nil)
+ (insert value)
+ (goto-char (point-min))
+ (insert (symbol-name charset)
+ ?'
+ (if language (symbol-name language) "")
+ ?')
+ (while (re-search-forward mime-non-attribute-char-regexp nil t)
+ (insert (prog1 (format "%%%02X" (char-int
+ (char-after (1- (point)))))
+ (delete-region (1- (point))(point)))))
+ (mime-divide-extended-parameter name (buffer-string)))))))
+
+(defun mime-divide-regular-parameter (name value)
+ "Divide MIME parameter value \"NAME=VALUE\" into segments.
+Each of \" NAME*n=SEGMENT_n\;\" will be no more than 78 characters.
+Return value is a list of string when division is performed, otherwise
+just a string is returned."
+ (let ((limit (max (- (eval-when-compile (- 78 (length " =\"\";")))
+ (length name))
+ 30)))
+ (if (> limit (length value))
+ (concat "\"" value "\"")
+ (let ((count 0)
+ result)
+ (setq limit (max (- limit 2) 30)) ; (length "*n") => 2
+ (setq limit (1- limit)) ; XXX
+ (with-temp-buffer
+ (set-buffer-multibyte nil)
+ (insert value)
+ (while (> (point-max) limit)
+ (goto-char (point-min))
+ (while (< (point) limit)
+ (when (eq (char-after) ?\\)
+ (forward-char))
+ (forward-char))
+ (setq result (cons (concat "\""
+ (prog1 (buffer-substring
+ (point-min)(point))
+ (delete-region
+ (point-min)(point)))
+ "\"")
+ result)
+ count (1+ count))
+ (when (zerop (% count 10))
+ (setq limit (max (1- limit) 30))))
+ (nreverse
+ (cons (concat "\""
+ (buffer-substring (point-min)(point-max))
+ "\"")
+ result)))))))
+
+(defun mime-encode-regular-parameter (name value)
+ "Encode MIME parameter value \"NAME=VALUE\" as a regular-parameter.
+If division is performed, return value is a list of string, otherwise
+return value is just a string."
+ (with-temp-buffer
+ (set-buffer-multibyte nil)
+ (insert value)
+ (goto-char (point-min))
+ (while (not (eobp))
+ (when (memq (char-after) '(?\\ ?\"))
+ (insert ?\\))
+ (forward-char 1))
+ (mime-divide-regular-parameter name (buffer-string))))
+
+(defun mime-encode-parameters (params)
+ "Encode PARAMS plist with MIME Parameter-Value Extensions.
+Return value is an alist of MIME parameter values."
+ (let (name value encoded result)
+ (while params
+ (setq name (car params)
+ value (car (cdr params))
+ params (cdr (cdr params)))
+ (cond
+ ;; first two clauses are for backward compatibility,
+ ;; especially for "ftp.in" in the distribution.
+ ((not (string-match (eval-when-compile
+ (concat "^\\(" mime-attribute-char-regexp "+\\)"
+ "\\(\\*[0-9]+\\)?" ; continuation
+ "\\(\\*\\)?$")) ; charset/language
+ name))
+ ;; invalid parameter name.
+ ;; XXX: Should we signal an error?
+ )
+ ((> (match-end 0) (match-end 1))
+ ;; this parameter value is already encoded.
+ (setq result (cons (cons name
+ (if (match-beginning 3)
+ ;; extended-parameter
+ value
+ ;; regular-parameter
+ (std11-wrap-as-quoted-string value)))
+ result)))
+ ((setq encoded (mime-encode-extended-parameter name value))
+ ;; extended-parameter
+ (if (stringp encoded)
+ (setq result (cons (cons (concat name "*") encoded) result))
+ ;; with continuation
+ (let ((section 0))
+ (while encoded
+ (setq result (cons (cons (concat name
+ "*" (int-to-string section)
+ "*")
+ (car encoded))
+ result)
+ section (1+ section)
+ encoded(cdr encoded))))))
+ (t
+ ;; regular-parameter
+ (setq encoded (mime-encode-regular-parameter name value))
+ (if (stringp encoded)
+ (setq result (cons (cons name encoded) result))
+ ;; with continuation
+ (let ((section 0))
+ (while encoded
+ (setq result (cons (cons (concat name
+ "*" (int-to-string section))
+ (car encoded))
+ result)
+ section (1+ section)
+ encoded (cdr encoded))))))))
+ (nreverse result)))
+
+
+;;; @ field parser
+;;;
+