10 (defvar ew-decode-field-cache-buf '())
11 (defvar ew-decode-field-cache-num 300)
13 (defun ew-decode-field (field-name field-body &optional eword-filter)
14 "Decode MIME RFC2047 encoded-words in a field.
15 FIELD-NAME is a name of the field such as \"To\", \"Subject\" etc. and
16 used to selecting syntax of body of the field and deciding first
17 column of body of the field.
18 FIELD-BODY is a body of the field.
20 If FIELD-BODY has multiple lines, each line is separated by CRLF as
21 pure network representation. Also if the result has multiple lines,
22 each line is separated by CRLF.
24 If EWORD-FILTER is non-nil, it should be closure. it is called for
25 each successful decoded encoded-word with decoded string as a
26 argument. The return value of EWORD-FILTER is used as decoding result
27 instead of its argument."
28 (let* ((key (ew-cons* field-name field-body eword-filter
29 (ew-dynamic-options)))
30 (tmp (assoc key ew-decode-field-cache-buf)))
34 (setq tmp (nthcdr ew-decode-field-cache-num
35 ew-decode-field-cache-buf))
38 (setcdr (cdr tmp) ew-decode-field-cache-buf)
39 (setq ew-decode-field-cache-buf (cdr tmp))
41 (setq ew-decode-field-cache-buf
43 ew-decode-field-cache-buf)))
44 (setcar (car ew-decode-field-cache-buf) key)
45 (setcdr (car ew-decode-field-cache-buf)
46 (ew-decode-field-no-cache
47 field-name field-body eword-filter))
48 (cdar ew-decode-field-cache-buf)))))
50 (defun ew-decode-field-no-cache (field-name field-body &optional eword-filter)
51 "No caching version of ew-decode-field."
52 (let ((tmp (assq (intern (downcase field-name)) ew-decode-field-syntax-alist))
53 frag-anchor frag1 frag2 decode)
56 (setq tmp ew-decode-field-default-syntax))
57 (setq frag-anchor (funcall (car tmp) (1+ (length field-name)) field-body))
58 ;;(setq zzz frag-anchor)
59 (when (and (eq (car tmp) 'ew-scan-unibyte-unstructured)
60 ew-decode-sticked-encoded-word)
61 (ew-separate-eword (get frag-anchor 'next-frag)
65 (ew-mark (cdr tmp) frag-anchor))
66 (setq frag1 (get frag-anchor 'next-frag))
67 (while (not (eq frag1 frag-anchor))
68 (setq decode (get frag1 'decode))
69 (setq frag2 (get frag1 'next-frag))
70 (while (and (not (eq frag2 frag-anchor))
71 (eq decode (get frag2 'decode)))
72 (setq frag2 (get frag2 'next-frag)))
73 (funcall decode frag-anchor frag1 frag2 eword-filter)
75 (setq frag1 (get frag-anchor 'prev-frag)
77 (while (not (eq frag1 frag-anchor))
78 (setq tmp (cons (or (get frag1 'decoded) (symbol-name frag1)) tmp)
79 frag1 (get frag1 'prev-frag)))
82 (defun ew-mark (tag anchor)
83 (let ((tlist (cons (list (symbol-value tag)) (ew-pair-list anchor))))
84 ;;(insert (format "%s" tlist))
89 (prog1 (car tlist) (setq tlist (cdr tlist)))))
91 (message "%s%s : %s" msg tok anchor)
92 (when (< 0 ew-parse-error-sit-for-seconds)
93 (sit-for ew-parse-error-sit-for-seconds))))))
95 (defun ew-decode-us-ascii (str)
96 (decode-mime-charset-string str ew-default-mime-charset 'LF))
98 (defun ew-decode-none (anchor frag end eword-filter)
99 (while (not (eq frag end))
100 (put frag 'decoded (ew-decode-us-ascii (symbol-name frag)))
101 (setq frag (get frag 'next-frag))))
103 (defun ew-decode-generic (anchor start end
108 (let ((frag start) result buff type f)
109 (while (not (eq frag end))
110 (setq type (get frag 'type))
112 ((and (memq type eword)
113 (ew-proper-eword-p frag))
115 (setq result (ew-rappend result
116 (funcall decode-others
119 (let ((first frag) (ewords (list frag)))
121 (setq f (get frag 'next-frag))
122 (while (and (not (eq f end))
123 (memq (get f 'type) gap))
124 (setq f (get f 'next-frag)))
125 (and (not (eq f end))
126 (ew-proper-eword-p f)))
127 (setq ewords (ew-rcons* ewords f)
129 (while (not (eq first frag))
130 (put first 'decoded "")
131 (setq first (get first 'next-frag)))
132 (put frag 'decoded "")
133 (setq result (ew-rappend result
134 (funcall decode-ewords
138 (setq buff (cons frag buff))
139 (put frag 'decoded ""))
141 (error "unexpected token: %s (%s)" frag type)))
142 (setq frag (get frag 'next-frag)))
144 (setq result (ew-rappend result (funcall decode-others (nreverse buff)))))
146 (apply 'ew-quote-concat (nreverse result)))
149 (defun ew-decode-generic-others (frags puncts quotes targets)
150 (let (result buff frag type tmp)
152 (setq frag (car frags)
153 type (get frag 'type)
158 (setq buff (nreverse buff)
159 tmp (ew-decode-us-ascii
160 (mapconcat 'car buff "")))
161 (if (ew-contain-non-ascii-p tmp)
162 (setq result (ew-rcons* result tmp))
163 (setq result (ew-rcons*
166 (mapconcat 'cdr buff "")))))
168 (setq result (ew-rcons*
170 (symbol-name frag))))
172 (setq buff (ew-rcons*
174 (cons (substring (symbol-name frag) 1)
175 (symbol-name frag)))))
177 (setq buff (ew-rcons*
179 (cons (symbol-name frag)
180 (symbol-name frag)))))
182 (error "something wrong: unexpected token: %s (%s)" frag type))))
184 (setq buff (nreverse buff)
185 tmp (ew-decode-us-ascii
186 (mapconcat 'car buff "")))
187 (if (ew-contain-non-ascii-p tmp)
188 (setq result (ew-rcons* result tmp))
189 (setq result (ew-rcons*
192 (mapconcat 'cdr buff "")))))
196 (defun ew-decode-unstructured-ewords (ewords eword-filter)
199 (setq result (ew-rcons*
201 (list (ew-decode-eword (symbol-name (car ewords))
204 ewords (cdr ewords)))
207 (defun ew-decode-unstructured-others (frags)
210 (setq result (ew-rcons*
212 (symbol-name (car frags)))
214 (list (ew-decode-us-ascii
215 (apply 'concat (nreverse result))))))
217 (defun ew-decode-unstructured (anchor start end eword-filter)
220 'ew-decode-unstructured-ewords
221 'ew-decode-unstructured-others
230 (defun ew-decode-phrase-ewords (ewords eword-filter)
231 (let ((qs (eq (get (car ewords) 'type) 'ew:qs-texts))
235 (setq result (ew-rcons*
237 (list (ew-decode-eword (symbol-name (car ewords))
240 require-quoting (or require-quoting
241 (string-match "[][()<>@,;:\\\".\000-\037]"
243 ewords (cdr ewords)))
246 (funcall (if qs 'ew-embed-in-quoted-string 'ew-embed-in-phrase)
247 (apply 'ew-quote-concat
251 (defun ew-decode-phrase-others (frags)
252 (ew-decode-generic-others
265 (defun ew-decode-phrase (anchor start end eword-filter)
268 'ew-decode-phrase-ewords
269 'ew-decode-phrase-others
270 (if ew-decode-quoted-encoded-word
271 '(ew:atom ew:qs-texts)
287 (defun ew-decode-comment-ewords (ewords eword-filter)
288 (let (require-quoting
291 (setq result (ew-rcons*
293 (list (ew-decode-eword (symbol-name (car ewords))
296 require-quoting (or require-quoting
297 (string-match "[()\\\\]" (caar result)))
298 ewords (cdr ewords)))
302 (apply 'ew-quote-concat
306 (defun ew-decode-comment-others (frags)
307 (ew-decode-generic-others
316 (defun ew-decode-comment (anchor start end eword-filter)
319 'ew-decode-comment-ewords
320 'ew-decode-comment-others
333 (defun ew-embed-in-phrase (str)
334 (concat "\"" (ew-embed-in-quoted-string str) "\""))
336 (defun ew-embed-in-quoted-string (str)
337 (ew-quote-as-quoted-pair str '(?\\ ?\")))
339 (defun ew-embed-in-comment (str)
340 (ew-quote-as-quoted-pair str '(?\\ ?\( ?\))))
342 (defun ew-quote-as-quoted-pair (str specials)
343 (let ((i 0) (j 0) (l (length str)) result)
345 (when (member (aref str j) specials)
346 (setq result (ew-rcons*
353 (setq result (ew-rcons*
356 (apply 'concat (nreverse result))))
360 (defun ew-proper-eword-p (frag)
362 (or ew-ignore-75bytes-limit
363 (<= (length (symbol-name frag)) 75))
364 (or ew-ignore-76bytes-limit
365 (<= (get frag 'line-length) 76))
367 ((eq (get frag 'type) 'ew:cm-texts)
368 (ew-eword-p (symbol-name frag)))
369 ((eq (get frag 'type) 'ew:qs-texts)
370 (ew-eword-p (symbol-name frag)))
371 ((eq (get frag 'type) 'ew:atom)
373 (or ew-permit-sticked-comment
375 (not (ew-comment-frag-p (get frag 'prev-frag)))
376 (not (ew-comment-frag-p (get frag 'next-frag)))))
377 (or ew-permit-sticked-special
379 (or (ew-comment-frag-p (get frag 'prev-frag))
380 (not (ew-special-frag-p (get frag 'prev-frag))))
381 (or (ew-comment-frag-p (get frag 'next-frag))
382 (not (ew-special-frag-p (get frag 'next-frag))))))
383 (ew-eword-p (symbol-name frag))))
384 ((eq (get frag 'type) 'ew:us-texts)
386 (or ew-permit-sticked-special
387 (not (ew-special-frag-p (get frag 'prev-frag))))
388 (ew-eword-p (symbol-name frag))))
392 (defun ew-contain-non-ascii-p (str)
393 (not (eq (charsets-to-mime-charset (find-charset-string str)) 'us-ascii)))
397 (ew-decode-field "To" " =?US-ASCII?Q?phrase?= <akr@jaist.ac.jp>")
398 (ew-decode-field "To" " =?US-ASCII?Q?phrase?= < =?US-ASCII?Q?akr?= @jaist.ac.jp>")
399 (ew-decode-field "To" " =?US-ASCII?Q?akr?= @jaist.ac.jp")
400 (ew-decode-field "Subject" " =?ISO-2022-JP?B?GyRCJCIbKEI=?=")
401 (ew-decode-field "Content-Type" " text/vnd.latex-z(=?US-ASCII?Q?What=3F?=);charset=ISO-2022-JP")
403 (ew-decode-field "To" " =?US-ASCII?Q?A=22B=5CC?= <akr@jaist.ac.jp>")
404 (let ((ew-decode-quoted-encoded-word t))
405 (ew-decode-field "To" " \"=?US-ASCII?Q?A=22B=5CC?=\" <akr@jaist.ac.jp>"))
407 (ew-decode-field "To" " akr@jaist.ac.jp (=?US-ASCII?Q?=28A=29B=5C?=)")
409 (ew-decode-field "To" "\"A\\BC\e$B\\\"\\\\\e(B\" <foo@bar>")
410 (ew-decode-field "To" "\"A\\BC\" <foo@bar>")
411 (ew-decode-field "To" "\"\e\\$\\B\\$\\\"\e\\(\\B\" <foo@bar>")