9 (defun ew-decode-field (field-name field-body &optional eword-filter)
10 "Decode MIME RFC2047 encoded-words in a field.
11 FIELD-NAME is a name of the field such as \"To\", \"Subject\" etc. and
12 used to selecting syntax of body of the field and deciding first
13 column of body of the field.
14 FIELD-BODY is a body of the field.
16 If FIELD-BODY has multiple lines, each line is separated by CRLF as
17 pure network representation. Also if the result has multiple lines,
18 each line is separated by CRLF.
20 If EWORD-FILTER is non-nil, it should be closure. it is called for
21 each successful decoded encoded-word with decoded string as a
22 argument. The return value of EWORD-FILTER is used as decoding result
23 instead of its argument."
24 (let ((tmp (assoc (downcase field-name) ew-decode-field-syntax-alist))
25 frag-anchor frag1 frag2 decode)
28 (setq tmp ew-decode-field-default-syntax))
29 (setq frag-anchor (funcall (car tmp) (1+ (length field-name)) field-body))
30 ;;(setq zzz frag-anchor)
31 (when (and (eq (car tmp) 'ew-scan-unibyte-unstructured)
32 ew-decode-sticked-encoded-word)
33 (ew-separate-eword (get frag-anchor 'next-frag)
35 '(ew:raw-us-texts-tok)))
37 (ew-mark (cdr tmp) frag-anchor))
38 (setq frag1 (get frag-anchor 'next-frag))
39 (while (not (eq frag1 frag-anchor))
40 (setq decode (get frag1 'decode))
41 (setq frag2 (get frag1 'next-frag))
42 (while (and (not (eq frag2 frag-anchor))
43 (eq decode (get frag2 'decode)))
44 (setq frag2 (get frag2 'next-frag)))
45 (funcall decode frag-anchor frag1 frag2 eword-filter)
47 (mapconcat (lambda (frag) (or (get frag 'result) (symbol-name frag)))
48 (ew-frag-list frag-anchor) "")))
50 (defun ew-mark (tag anchor)
51 (let ((tlist (cons (list (symbol-value tag)) (ew-pair-list anchor))))
52 ;;(insert (format "%s" tlist))
54 (lambda () (if (null tlist) '(0)
55 (prog1 (car tlist) (setq tlist (cdr tlist)))))
56 (lambda (msg tok) (message "parse error: %s%s : %s" msg tok anchor)))))
58 (defun ew-decode-none (anchor frag end eword-filter)
59 (while (not (eq frag end))
60 (put frag 'result (funcall ew-decode-us-ascii (symbol-name frag)))
61 (setq frag (get frag 'next-frag))))
63 (defun ew-decode-generic (anchor start end
68 (let ((frag start) result buff type f)
69 (while (not (eq frag end))
70 (setq type (get frag 'type))
72 ((and (memq type eword)
73 (ew-proper-eword-p frag))
75 (setq result (ew-rappend result
76 (funcall decode-others
79 (let ((first frag) (ewords (list frag)))
81 (setq f (get frag 'next-frag))
82 (while (and (not (eq f end))
83 (memq (get f 'type) gap))
84 (setq f (get f 'next-frag)))
86 (ew-proper-eword-p f)))
87 (setq ewords (ew-rcons* ewords f)
89 (while (not (eq first frag))
90 (put first 'result "")
91 (setq first (get first 'next-frag)))
93 (setq result (ew-rappend result
94 (funcall decode-ewords
98 (setq buff (cons frag buff))
99 (put frag 'result ""))
101 (error "unexpected token: %s (%s)" frag type)))
102 (setq frag (get frag 'next-frag)))
104 (setq result (ew-rappend result (funcall decode-others (nreverse buff)))))
106 (apply 'ew-quote-concat (nreverse result)))
109 (defun ew-decode-generic-others (frags puncts quotes targets)
110 (let (result buff frag type tmp)
112 (setq frag (car frags)
113 type (get frag 'type)
118 (setq buff (nreverse buff)
119 tmp (funcall ew-decode-us-ascii
120 (mapconcat 'car buff "")))
121 (if (ew-contain-non-ascii-p tmp)
122 (setq result (ew-rcons* result tmp))
123 (setq result (ew-rcons*
125 (funcall ew-decode-us-ascii
126 (mapconcat 'cdr buff "")))))
128 (setq result (ew-rcons*
130 (symbol-name frag))))
132 (setq buff (ew-rcons*
134 (cons (substring (symbol-name frag) 1)
135 (symbol-name frag)))))
137 (setq buff (ew-rcons*
139 (cons (symbol-name frag)
140 (symbol-name frag)))))
142 (error "something wrong: unexpected token: %s (%s)" frag type))))
144 (setq buff (nreverse buff)
145 tmp (funcall ew-decode-us-ascii
146 (mapconcat 'car buff "")))
147 (if (ew-contain-non-ascii-p tmp)
148 (setq result (ew-rcons* result tmp))
149 (setq result (ew-rcons*
151 (funcall ew-decode-us-ascii
152 (mapconcat 'cdr buff "")))))
156 (defun ew-decode-unstructured-ewords (ewords eword-filter)
159 (setq result (ew-rcons*
161 (list (ew-decode-eword (symbol-name (car ewords))
164 ewords (cdr ewords)))
167 (defun ew-decode-unstructured-others (frags)
170 (setq result (ew-rcons*
172 (symbol-name (car frags)))
174 (list (funcall ew-decode-us-ascii
175 (apply 'concat (nreverse result))))))
177 (defun ew-decode-unstructured (anchor start end eword-filter)
180 'ew-decode-unstructured-ewords
181 'ew-decode-unstructured-others
182 '(ew:raw-us-texts-tok)
185 '(ew:raw-us-texts-tok
190 (defun ew-decode-phrase-ewords (ewords eword-filter)
191 (let ((qs (eq (get (car ewords) 'type) 'ew:raw-qs-texts-tok))
195 (setq result (ew-rcons*
197 (list (ew-decode-eword (symbol-name (car ewords))
200 require-quoting (or require-quoting
201 (string-match "[][()<>@,;:\\\".\000-\037]"
203 ewords (cdr ewords)))
206 (funcall (if qs 'ew-embed-in-quoted-string 'ew-embed-in-phrase)
207 (apply 'ew-quote-concat
211 (defun ew-decode-phrase-others (frags)
212 (ew-decode-generic-others
214 '(ew:raw-qs-begin-tok
216 '(ew:raw-qs-qfold-tok
223 ew:raw-qs-fold-tok)))
225 (defun ew-decode-phrase (anchor start end eword-filter)
228 'ew-decode-phrase-ewords
229 'ew-decode-phrase-others
230 (if ew-decode-quoted-encoded-word
231 '(ew:raw-atom-tok ew:raw-qs-texts-tok)
247 (defun ew-decode-comment-ewords (ewords eword-filter)
248 (let (require-quoting
251 (setq result (ew-rcons*
253 (list (ew-decode-eword (symbol-name (car ewords))
256 require-quoting (or require-quoting
257 (string-match "[()\\\\]" (caar result)))
258 ewords (cdr ewords)))
262 (apply 'ew-quote-concat
266 (defun ew-decode-comment-others (frags)
267 (ew-decode-generic-others
270 '(ew:raw-cm-qfold-tok
272 '(ew:raw-cm-texts-tok
274 ew:raw-cm-fold-tok)))
276 (defun ew-decode-comment (anchor start end eword-filter)
279 'ew-decode-comment-ewords
280 'ew-decode-comment-others
281 '(ew:raw-cm-texts-tok)
284 '(ew:raw-cm-texts-tok
293 (defun ew-embed-in-phrase (str)
294 (concat "\"" (ew-embed-in-quoted-string str) "\""))
296 (defun ew-embed-in-quoted-string (str)
297 (ew-quote-as-quoted-pair str '(?\\ ?\")))
299 (defun ew-embed-in-comment (str)
300 (ew-quote-as-quoted-pair str '(?\\ ?\( ?\))))
302 (defun ew-quote-as-quoted-pair (str specials)
303 (let ((i 0) (j 0) (l (length str)) result)
305 (when (member (aref str j) specials)
306 (setq result (ew-rcons*
313 (setq result (ew-rcons*
316 (apply 'concat (nreverse result))))
320 (defun ew-proper-eword-p (frag)
322 (or ew-ignore-75bytes-limit
323 (<= (length (symbol-name frag)) 75))
324 (or ew-ignore-76bytes-limit
325 (<= (get frag 'line-length) 76))
327 ((eq (get frag 'type) 'ew:raw-cm-texts-tok)
328 (ew-eword-p (symbol-name frag)))
329 ((eq (get frag 'type) 'ew:raw-qs-texts-tok)
330 (ew-eword-p (symbol-name frag)))
331 ((eq (get frag 'type) 'ew:raw-atom-tok)
333 (or ew-permit-sticked-comment
335 (not (ew-comment-frag-p (get frag 'prev-frag)))
336 (not (ew-comment-frag-p (get frag 'next-frag)))))
337 (or ew-permit-sticked-special
339 (or (ew-comment-frag-p (get frag 'prev-frag))
340 (not (ew-special-frag-p (get frag 'prev-frag))))
341 (or (ew-comment-frag-p (get frag 'next-frag))
342 (not (ew-special-frag-p (get frag 'next-frag))))))
343 (ew-eword-p (symbol-name frag))))
344 ((eq (get frag 'type) 'ew:raw-us-texts-tok)
346 (or ew-permit-sticked-special
347 (not (ew-special-frag-p (get frag 'prev-frag))))
348 (ew-eword-p (symbol-name frag))))
352 (defun ew-contain-non-ascii-p (str)
353 (not (eq (charsets-to-mime-charset (find-charset-string str)) 'us-ascii)))
357 (ew-decode-field "To" " =?US-ASCII?Q?phrase?= <akr@jaist.ac.jp>")
358 (ew-decode-field "To" " =?US-ASCII?Q?phrase?= < =?US-ASCII?Q?akr?= @jaist.ac.jp>")
359 (ew-decode-field "To" " =?US-ASCII?Q?akr?= @jaist.ac.jp")
360 (ew-decode-field "Subject" " =?ISO-2022-JP?B?GyRCJCIbKEI=?=")
361 (ew-decode-field "Content-Type" " text/vnd.latex-z(=?US-ASCII?Q?What=3F?=);charset=ISO-2022-JP")
363 (ew-decode-field "To" " =?US-ASCII?Q?A=22B=5CC?= <akr@jaist.ac.jp>")
364 (let ((ew-decode-quoted-encoded-word t))
365 (ew-decode-field "To" " \"=?US-ASCII?Q?A=22B=5CC?=\" <akr@jaist.ac.jp>"))
367 (ew-decode-field "To" " akr@jaist.ac.jp (=?US-ASCII?Q?=28A=29B=5C?=)")
369 (ew-decode-field "To" "\"A\\BC\e$B\\\"\\\\\e(B\" <foo@bar>")
370 (ew-decode-field "To" "\"A\\BC\" <foo@bar>")
371 (ew-decode-field "To" "\"\e\\$\\B\\$\\\"\e\\(\\B\" <foo@bar>")