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 (assoc (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)
63 '(ew:raw-us-texts-tok)))
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 'result) (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))
86 (lambda () (if (null tlist) '(0)
87 (prog1 (car tlist) (setq tlist (cdr tlist)))))
88 (lambda (msg tok) (message "parse error: %s%s : %s" msg tok anchor)))))
90 (defun ew-decode-none (anchor frag end eword-filter)
91 (while (not (eq frag end))
92 (put frag 'result (funcall ew-decode-us-ascii (symbol-name frag)))
93 (setq frag (get frag 'next-frag))))
95 (defun ew-decode-generic (anchor start end
100 (let ((frag start) result buff type f)
101 (while (not (eq frag end))
102 (setq type (get frag 'type))
104 ((and (memq type eword)
105 (ew-proper-eword-p frag))
107 (setq result (ew-rappend result
108 (funcall decode-others
111 (let ((first frag) (ewords (list frag)))
113 (setq f (get frag 'next-frag))
114 (while (and (not (eq f end))
115 (memq (get f 'type) gap))
116 (setq f (get f 'next-frag)))
117 (and (not (eq f end))
118 (ew-proper-eword-p f)))
119 (setq ewords (ew-rcons* ewords f)
121 (while (not (eq first frag))
122 (put first 'result "")
123 (setq first (get first 'next-frag)))
124 (put frag 'result "")
125 (setq result (ew-rappend result
126 (funcall decode-ewords
130 (setq buff (cons frag buff))
131 (put frag 'result ""))
133 (error "unexpected token: %s (%s)" frag type)))
134 (setq frag (get frag 'next-frag)))
136 (setq result (ew-rappend result (funcall decode-others (nreverse buff)))))
138 (apply 'ew-quote-concat (nreverse result)))
141 (defun ew-decode-generic-others (frags puncts quotes targets)
142 (let (result buff frag type tmp)
144 (setq frag (car frags)
145 type (get frag 'type)
150 (setq buff (nreverse buff)
151 tmp (funcall ew-decode-us-ascii
152 (mapconcat 'car buff "")))
153 (if (ew-contain-non-ascii-p tmp)
154 (setq result (ew-rcons* result tmp))
155 (setq result (ew-rcons*
157 (funcall ew-decode-us-ascii
158 (mapconcat 'cdr buff "")))))
160 (setq result (ew-rcons*
162 (symbol-name frag))))
164 (setq buff (ew-rcons*
166 (cons (substring (symbol-name frag) 1)
167 (symbol-name frag)))))
169 (setq buff (ew-rcons*
171 (cons (symbol-name frag)
172 (symbol-name frag)))))
174 (error "something wrong: unexpected token: %s (%s)" frag type))))
176 (setq buff (nreverse buff)
177 tmp (funcall ew-decode-us-ascii
178 (mapconcat 'car buff "")))
179 (if (ew-contain-non-ascii-p tmp)
180 (setq result (ew-rcons* result tmp))
181 (setq result (ew-rcons*
183 (funcall ew-decode-us-ascii
184 (mapconcat 'cdr buff "")))))
188 (defun ew-decode-unstructured-ewords (ewords eword-filter)
191 (setq result (ew-rcons*
193 (list (ew-decode-eword (symbol-name (car ewords))
196 ewords (cdr ewords)))
199 (defun ew-decode-unstructured-others (frags)
202 (setq result (ew-rcons*
204 (symbol-name (car frags)))
206 (list (funcall ew-decode-us-ascii
207 (apply 'concat (nreverse result))))))
209 (defun ew-decode-unstructured (anchor start end eword-filter)
212 'ew-decode-unstructured-ewords
213 'ew-decode-unstructured-others
214 '(ew:raw-us-texts-tok)
217 '(ew:raw-us-texts-tok
222 (defun ew-decode-phrase-ewords (ewords eword-filter)
223 (let ((qs (eq (get (car ewords) 'type) 'ew:raw-qs-texts-tok))
227 (setq result (ew-rcons*
229 (list (ew-decode-eword (symbol-name (car ewords))
232 require-quoting (or require-quoting
233 (string-match "[][()<>@,;:\\\".\000-\037]"
235 ewords (cdr ewords)))
238 (funcall (if qs 'ew-embed-in-quoted-string 'ew-embed-in-phrase)
239 (apply 'ew-quote-concat
243 (defun ew-decode-phrase-others (frags)
244 (ew-decode-generic-others
246 '(ew:raw-qs-begin-tok
248 '(ew:raw-qs-qfold-tok
255 ew:raw-qs-fold-tok)))
257 (defun ew-decode-phrase (anchor start end eword-filter)
260 'ew-decode-phrase-ewords
261 'ew-decode-phrase-others
262 (if ew-decode-quoted-encoded-word
263 '(ew:raw-atom-tok ew:raw-qs-texts-tok)
279 (defun ew-decode-comment-ewords (ewords eword-filter)
280 (let (require-quoting
283 (setq result (ew-rcons*
285 (list (ew-decode-eword (symbol-name (car ewords))
288 require-quoting (or require-quoting
289 (string-match "[()\\\\]" (caar result)))
290 ewords (cdr ewords)))
294 (apply 'ew-quote-concat
298 (defun ew-decode-comment-others (frags)
299 (ew-decode-generic-others
302 '(ew:raw-cm-qfold-tok
304 '(ew:raw-cm-texts-tok
306 ew:raw-cm-fold-tok)))
308 (defun ew-decode-comment (anchor start end eword-filter)
311 'ew-decode-comment-ewords
312 'ew-decode-comment-others
313 '(ew:raw-cm-texts-tok)
316 '(ew:raw-cm-texts-tok
325 (defun ew-embed-in-phrase (str)
326 (concat "\"" (ew-embed-in-quoted-string str) "\""))
328 (defun ew-embed-in-quoted-string (str)
329 (ew-quote-as-quoted-pair str '(?\\ ?\")))
331 (defun ew-embed-in-comment (str)
332 (ew-quote-as-quoted-pair str '(?\\ ?\( ?\))))
334 (defun ew-quote-as-quoted-pair (str specials)
335 (let ((i 0) (j 0) (l (length str)) result)
337 (when (member (aref str j) specials)
338 (setq result (ew-rcons*
345 (setq result (ew-rcons*
348 (apply 'concat (nreverse result))))
352 (defun ew-proper-eword-p (frag)
354 (or ew-ignore-75bytes-limit
355 (<= (length (symbol-name frag)) 75))
356 (or ew-ignore-76bytes-limit
357 (<= (get frag 'line-length) 76))
359 ((eq (get frag 'type) 'ew:raw-cm-texts-tok)
360 (ew-eword-p (symbol-name frag)))
361 ((eq (get frag 'type) 'ew:raw-qs-texts-tok)
362 (ew-eword-p (symbol-name frag)))
363 ((eq (get frag 'type) 'ew:raw-atom-tok)
365 (or ew-permit-sticked-comment
367 (not (ew-comment-frag-p (get frag 'prev-frag)))
368 (not (ew-comment-frag-p (get frag 'next-frag)))))
369 (or ew-permit-sticked-special
371 (or (ew-comment-frag-p (get frag 'prev-frag))
372 (not (ew-special-frag-p (get frag 'prev-frag))))
373 (or (ew-comment-frag-p (get frag 'next-frag))
374 (not (ew-special-frag-p (get frag 'next-frag))))))
375 (ew-eword-p (symbol-name frag))))
376 ((eq (get frag 'type) 'ew:raw-us-texts-tok)
378 (or ew-permit-sticked-special
379 (not (ew-special-frag-p (get frag 'prev-frag))))
380 (ew-eword-p (symbol-name frag))))
384 (defun ew-contain-non-ascii-p (str)
385 (not (eq (charsets-to-mime-charset (find-charset-string str)) 'us-ascii)))
389 (ew-decode-field "To" " =?US-ASCII?Q?phrase?= <akr@jaist.ac.jp>")
390 (ew-decode-field "To" " =?US-ASCII?Q?phrase?= < =?US-ASCII?Q?akr?= @jaist.ac.jp>")
391 (ew-decode-field "To" " =?US-ASCII?Q?akr?= @jaist.ac.jp")
392 (ew-decode-field "Subject" " =?ISO-2022-JP?B?GyRCJCIbKEI=?=")
393 (ew-decode-field "Content-Type" " text/vnd.latex-z(=?US-ASCII?Q?What=3F?=);charset=ISO-2022-JP")
395 (ew-decode-field "To" " =?US-ASCII?Q?A=22B=5CC?= <akr@jaist.ac.jp>")
396 (let ((ew-decode-quoted-encoded-word t))
397 (ew-decode-field "To" " \"=?US-ASCII?Q?A=22B=5CC?=\" <akr@jaist.ac.jp>"))
399 (ew-decode-field "To" " akr@jaist.ac.jp (=?US-ASCII?Q?=28A=29B=5C?=)")
401 (ew-decode-field "To" "\"A\\BC\e$B\\\"\\\\\e(B\" <foo@bar>")
402 (ew-decode-field "To" "\"A\\BC\" <foo@bar>")
403 (ew-decode-field "To" "\"\e\\$\\B\\$\\\"\e\\(\\B\" <foo@bar>")