1 ;;; quoted encoded word library
7 ;; This library provides functions operating strings embedding
8 ;; unencodable encoded words.
10 ;;;type embedded-pattern denoted-pattern
11 ;; Type-0 =?(QQQ)*A?B?C?= =?(Q)*A?B?C?=
12 ;; Type-1 =?(QQQ)*QA?B?C?= Decode =?(Q)*A?B?C?= as encoded-word
13 ;; Type-2 =?(QQQ)*QQA?B?C?= =?(Q)*A?B?C?
15 ;; Q : quoting character '+'.
16 ;; A : token. But it does not start with quoting character.
20 (defconst ew-quoting-char ?+)
21 (defconst ew-quoting-char-singleton (list ew-quoting-char))
22 (defconst ew-quoting-chars-regexp
23 (concat (regexp-quote (char-to-string ew-quoting-char)) "*"))
25 (defconst ew-token-regexp "[-!#-'*+0-9A-Z^-~]+")
26 (defconst ew-encoded-text-regexp "[!->@-~]+")
27 (defconst ew-encoded-word-regexp
28 (concat (regexp-quote "=?")
29 "\\(" ew-token-regexp "\\)"
31 "\\(" ew-token-regexp "\\)"
33 "\\(" ew-encoded-text-regexp "\\)"
36 (defconst ew-type2-regexp
37 (concat (regexp-quote "=?")
38 "\\(" ew-token-regexp "\\)"
40 "\\(" ew-token-regexp "\\)"
42 "\\(" ew-encoded-text-regexp "\\)"
48 (defun ew-quoting-char-seq (num)
49 (make-string num ew-quoting-char))
52 (ew-quote-concat str))
54 (defun ew-concat (&rest args)
55 (apply 'ew-quote-concat (mapcar 'list args)))
57 (defun ew-quote-concat (&rest args)
58 (let (result raws tmp)
64 (setq raws (cons tmp raws)))
66 ;; quoted encoded word embedding strings
67 (let (str start eword-start charset-start quoting-end eword-end l q r)
71 (while (string-match ew-encoded-word-regexp str start)
72 (setq eword-start (match-beginning 0)
73 charset-start (match-beginning 1)
74 eword-end (match-end 0))
75 (string-match ew-quoting-chars-regexp str charset-start)
76 (setq quoting-end (match-end 0)
77 l (- quoting-end charset-start)
85 (substring str start charset-start)
86 (ew-quoting-char-seq q)
87 (substring str quoting-end eword-end))))
92 (substring str start charset-start)
93 (ew-quoting-char-seq q)
94 (substring str quoting-end (1- eword-end)))))
99 (substring str start eword-start))
103 (ew-quote-sole (apply 'concat (nreverse raws)) t)
104 (substring str eword-start eword-end))
106 (setq start eword-end))
107 (setq raws (ew-rcons* raws (substring str start))
110 (error "ew-quote-concat: %s" tmp)))
111 (setq args (cdr args)))
115 (ew-quote-sole (apply 'concat (nreverse raws)) nil)))
116 (apply 'concat (nreverse result))))
118 (defun ew-quote-sole (str gen-type2)
119 (let (result (start 0) charset-start quoting-end eword-end l)
120 (while (string-match ew-encoded-word-regexp str start)
121 (setq charset-start (match-beginning 1)
122 eword-end (match-end 0))
123 (string-match ew-quoting-chars-regexp str charset-start)
124 (setq quoting-end (match-end 0)
125 l (* (- quoting-end charset-start) 3)
129 (substring str start charset-start)
130 (ew-quoting-char-seq l)
131 (substring str quoting-end eword-end))
134 (string-match ew-type2-regexp str start))
136 (setq charset-start (match-beginning 1)
137 eword-end (match-end 0))
138 (string-match ew-quoting-chars-regexp str charset-start)
139 (setq quoting-end (match-end 0)
140 l (* (- quoting-end charset-start) 3)
144 (substring str start charset-start)
145 (ew-quoting-char-seq (+ l 2))
146 (substring str quoting-end eword-end)
148 (setq result (ew-rcons* result (substring str start))))
149 (apply 'concat (nreverse result))))
151 (defun ew-quote-eword (charset encoding encoded-text)
152 (string-match ew-quoting-chars-regexp charset)
155 (ew-quoting-char-seq (* (- (match-end 0) (match-beginning 0)) 3))
156 (substring charset (match-end 0))
163 (defun ew-encode-crlf (str)
166 (end (length str)) result ms me)
167 (while (string-match "\\(\r\n\\)+" str mstart)
168 (setq ms (match-beginning 0)
171 (when (and (< me end)
172 (member (aref str me) '(?\t ?\ )))
175 (setq result (ew-rcons* result
176 (substring str sstart ms)
180 (setq result (ew-rcons* result "=0D=0A")
182 (setq result (ew-rcons* result "?="))))
184 (setq result (ew-rcons* result
185 (substring str sstart))))
186 (apply 'concat (nreverse result))))
190 (ew-quote-concat "aaa=?A?B?C?=ccc") ;"aaa=?A?B?C?=ccc"
191 (ew-quote-concat "aaa=?+A?B?C?=ccc") ;"aaa=?+++A?B?C?=ccc"
192 (ew-quote-concat '("aaa=?A?B?C?=ccc")) ;"aaa=?A?B?C?=ccc"
193 (ew-quote-concat '("aaa=?+++A?B?C?=ccc")) ;"aaa=?+++A?B?C?=ccc"
194 (ew-quote-concat "aaa=?+A?B" "?C?=ccc") ;"aaa=?+++A?B?C?=ccc"
195 (ew-quote-concat "a=?+A?B?C?" '("=?+US-ASCII?Q?z?=")) ;"a=?+++++A?B?C?==?+US-ASCII?Q?z?="
196 (ew-quote-concat "a=?+A?B?C?=?+D?E?F?" '("=?+US-ASCII?Q?z?=")) ;"a=?+++A?B?C?=?+D?E?F?=?+US-ASCII?Q?z?="
197 (ew-quote-concat "a=?+A?B?C?=?+D?E?F?=?+G?H?I?" '("=?+US-ASCII?Q?z?=")) ;"a=?+++A?B?C?=?+D?E?F?=?+++++G?H?I?==?+US-ASCII?Q?z?="
198 (ew-quote-concat '("a=?++A?B?C?==?+++A?B?C?=c")) ;"a=?A?B?C?=?+A?B?C?=c"