aboutsummaryrefslogtreecommitdiffstats
path: root/lisp/gnus
diff options
context:
space:
mode:
authorMiles Bader2005-03-30 08:14:32 +0000
committerMiles Bader2005-03-30 08:14:32 +0000
commit10ace8ea53395cc0ca656080cc3e828febc39b34 (patch)
tree76c630eeaaeb80f46baa34c8af29ff0b41abfd4b /lisp/gnus
parent96a29ab7a8e391db9078d1ffc0c76faffb470a1b (diff)
downloademacs-10ace8ea53395cc0ca656080cc3e828febc39b34.tar.gz
emacs-10ace8ea53395cc0ca656080cc3e828febc39b34.zip
Revision: miles@gnu.org--gnu-2005/emacs--cvs-trunk--0--patch-220
Merge from gnus--rel--5.10 Patches applied: * gnus--rel--5.10 (patch 45-52) - Update from CVS - Update from CVS: texi Makefile.in CVS keyw cruft - Update from CVS: ChangeLog tweaks 2005-03-29 Reiner Steib <Reiner.Steib@gmx.de> * etc/gnus-refcard.tex, etc/gnus-logo.eps: New files. 2005-03-25 Katsumi Yamaoka <yamaoka@jpl.org> * lisp/gnus/message.el (message-resend): Bind rfc2047-encode-encoded-words. * lisp/gnus/mm-util.el (mm-replace-in-string): New function. (mm-xemacs-find-mime-charset-1): Ignore errors while loading latin-unity, which cannot be used with XEmacs 21.1. * lisp/gnus/rfc2047.el (rfc2047-encode-function-alist): Rename from rfc2047-encoding-function-alist in order to avoid conflicting with the old version. (rfc2047-encode-message-header): Remove useless goto-char. (rfc2047-encodable-p): Don't move point. (rfc2047-syntax-table): Treat `(' and `)' as is. (rfc2047-encode-region): Concatenate words containing non-ASCII characters in structured fields; don't encode space-delimited ASCII words even in unstructured fields; don't break words at char-category boundaries; encode encoded words in structured fields; treat text within parentheses as special; show the original text when error has occurred; move point to the end of the region after encoding, suggested by IRIE Tetsuya <irie@t.email.ne.jp>; treat backslash-quoted characters as non-special; check carefully whether to encode special characters; fix some kind of misconfigured headers; signal a real error if debug-on-quit or debug-on-error is non-nil; don't infloop, suggested by Hiroshi Fujishima <pooh@nature.tsukuba.ac.jp>; assume the close parenthesis may be included in the encoded word; encode bogus delimiters. (rfc2047-encode-string): Use mm-with-multibyte-buffer. (rfc2047-encode-max-chars): New variable. (rfc2047-encode-1): New function. (rfc2047-encode): Use it; encode text so that it occupies the maximum width within 76-column; work correctly on Q encoding for iso-2022-* charsets; fold the line before encoding; don't append a space if the encoded word includes close parenthesis. (rfc2047-fold-region): Use existing whitespace for LWSP; make it sure not to break a line just after the header name. (rfc2047-b-encode-region): Remove. (rfc2047-b-encode-string): New function. (rfc2047-q-encode-region): Remove. (rfc2047-q-encode-string): New function. (rfc2047-encode-parameter): New function. (rfc2047-encoded-word-regexp): Don't use shy group. (rfc2047-decode-region): Follow rfc2047-encoded-word-regexp change. (rfc2047-parse-and-decode): Ditto. (rfc2047-decode): Treat the ascii coding-system as raw-text by default. 2005-03-25 Lars Magne Ingebrigtsen <larsi@gnus.org> * lisp/gnus/rfc2047.el (rfc2047-encode-encoded-words): New variable. (rfc2047-field-value): Strip props. (rfc2047-encode-message-header): Disabled header folding -- not all headers can be folded, and this should be done by the message composition mode. Probably. I think. (rfc2047-encodable-p): Say that =? needs encoding. (rfc2047-encode-region): Encode =? strings. 2005-03-25 Jesper Harder <harder@ifa.au.dk> * lisp/gnus/rfc2047.el (rfc2047-encoded-word-regexp): Support RFC 2231 language tags; remove unnecessary '+'. Reported by Stefan Wiens <s.wi@gmx.net>. (rfc2047-decode-string): Don't cons a string unnecessarily. (rfc2047-parse-and-decode, rfc2047-decode): Use a character for the encoding to avoid consing a string. (rfc2047-decode): Use mm-subst-char-in-string instead of mm-replace-chars-in-string. 2005-03-25 TSUCHIYA Masatoshi <tsuchiya@namazu.org> * lisp/gnus/rfc2047.el (rfc2047-encode): Use uppercase letters to specify encodings of MIME-encoded words, in order to improve interoperability with several broken MUAs. 2005-03-21 Reiner Steib <Reiner.Steib@gmx.de> * lisp/gnus/gnus-srvr.el (gnus-browse-select-group): Add NUMBER argument and pass it to `gnus-browse-read-group'. (gnus-browse-read-group): Add NUMBER argument and pass it to `gnus-group-read-ephemeral-group'. * lisp/gnus/gnus-group.el (gnus-group-read-ephemeral-group): Add NUMBER argument and pass it to `gnus-group-read-group'. 2005-03-19 Aidan Kehoe <kehoea@parhasard.net> * lisp/gnus/mm-util.el (mm-xemacs-find-mime-charset): Only call mm-xemacs-find-mime-charset-1 if we have the mule feature available at runtime. 2005-03-25 Katsumi Yamaoka <yamaoka@jpl.org> * man/emacs-mime.texi (Display Customization): Markup fixes. (rfc2047): Update. 2005-03-23 Reiner Steib <Reiner.Steib@gmx.de> * man/gnus-faq.texi: Replaced with auto-generated version.
Diffstat (limited to 'lisp/gnus')
-rw-r--r--lisp/gnus/ChangeLog91
-rw-r--r--lisp/gnus/gnus-group.el6
-rw-r--r--lisp/gnus/gnus-srvr.el19
-rw-r--r--lisp/gnus/message.el3
-rw-r--r--lisp/gnus/mm-util.el30
-rw-r--r--lisp/gnus/rfc2047.el641
6 files changed, 546 insertions, 244 deletions
diff --git a/lisp/gnus/ChangeLog b/lisp/gnus/ChangeLog
index 3c7c3d3d5c4..fe2fcab6643 100644
--- a/lisp/gnus/ChangeLog
+++ b/lisp/gnus/ChangeLog
@@ -1,3 +1,94 @@
12005-03-25 Katsumi Yamaoka <yamaoka@jpl.org>
2
3 * message.el (message-resend): Bind rfc2047-encode-encoded-words.
4
5 * mm-util.el (mm-replace-in-string): New function.
6 (mm-xemacs-find-mime-charset-1): Ignore errors while loading
7 latin-unity, which cannot be used with XEmacs 21.1.
8
9 * rfc2047.el (rfc2047-encode-function-alist): Rename from
10 rfc2047-encoding-function-alist in order to avoid conflicting with
11 the old version.
12 (rfc2047-encode-message-header): Remove useless goto-char.
13 (rfc2047-encodable-p): Don't move point.
14 (rfc2047-syntax-table): Treat `(' and `)' as is.
15 (rfc2047-encode-region): Concatenate words containing non-ASCII
16 characters in structured fields; don't encode space-delimited
17 ASCII words even in unstructured fields; don't break words at
18 char-category boundaries; encode encoded words in structured
19 fields; treat text within parentheses as special; show the
20 original text when error has occurred; move point to the end of
21 the region after encoding, suggested by IRIE Tetsuya
22 <irie@t.email.ne.jp>; treat backslash-quoted characters as
23 non-special; check carefully whether to encode special characters;
24 fix some kind of misconfigured headers; signal a real error if
25 debug-on-quit or debug-on-error is non-nil; don't infloop,
26 suggested by Hiroshi Fujishima <pooh@nature.tsukuba.ac.jp>; assume
27 the close parenthesis may be included in the encoded word; encode
28 bogus delimiters.
29 (rfc2047-encode-string): Use mm-with-multibyte-buffer.
30 (rfc2047-encode-max-chars): New variable.
31 (rfc2047-encode-1): New function.
32 (rfc2047-encode): Use it; encode text so that it occupies the
33 maximum width within 76-column; work correctly on Q encoding for
34 iso-2022-* charsets; fold the line before encoding; don't append a
35 space if the encoded word includes close parenthesis.
36 (rfc2047-fold-region): Use existing whitespace for LWSP; make it
37 sure not to break a line just after the header name.
38 (rfc2047-b-encode-region): Remove.
39 (rfc2047-b-encode-string): New function.
40 (rfc2047-q-encode-region): Remove.
41 (rfc2047-q-encode-string): New function.
42 (rfc2047-encode-parameter): New function.
43 (rfc2047-encoded-word-regexp): Don't use shy group.
44 (rfc2047-decode-region): Follow rfc2047-encoded-word-regexp change.
45 (rfc2047-parse-and-decode): Ditto.
46 (rfc2047-decode): Treat the ascii coding-system as raw-text by
47 default.
48
492005-03-25 Lars Magne Ingebrigtsen <larsi@gnus.org>
50
51 * rfc2047.el (rfc2047-encode-encoded-words): New variable.
52 (rfc2047-field-value): Strip props.
53 (rfc2047-encode-message-header): Disabled header folding -- not
54 all headers can be folded, and this should be done by the message
55 composition mode. Probably. I think.
56 (rfc2047-encodable-p): Say that =? needs encoding.
57 (rfc2047-encode-region): Encode =? strings.
58
592005-03-25 Jesper Harder <harder@ifa.au.dk>
60
61 * rfc2047.el (rfc2047-encoded-word-regexp): Support RFC 2231
62 language tags; remove unnecessary '+'. Reported by Stefan Wiens
63 <s.wi@gmx.net>.
64 (rfc2047-decode-string): Don't cons a string unnecessarily.
65 (rfc2047-parse-and-decode, rfc2047-decode): Use a character for
66 the encoding to avoid consing a string.
67 (rfc2047-decode): Use mm-subst-char-in-string instead of
68 mm-replace-chars-in-string.
69
702005-03-25 TSUCHIYA Masatoshi <tsuchiya@namazu.org>
71
72 * rfc2047.el (rfc2047-encode): Use uppercase letters to specify
73 encodings of MIME-encoded words, in order to improve
74 interoperability with several broken MUAs.
75
762005-03-21 Reiner Steib <Reiner.Steib@gmx.de>
77
78 * gnus-srvr.el (gnus-browse-select-group): Add NUMBER argument and
79 pass it to `gnus-browse-read-group'.
80 (gnus-browse-read-group): Add NUMBER argument and pass it to
81 `gnus-group-read-ephemeral-group'.
82
83 * gnus-group.el (gnus-group-read-ephemeral-group): Add NUMBER
84 argument and pass it to `gnus-group-read-group'.
85
862005-03-19 Aidan Kehoe <kehoea@parhasard.net>
87
88 * mm-util.el (mm-xemacs-find-mime-charset): Only call
89 mm-xemacs-find-mime-charset-1 if we have the mule feature
90 available at runtime.
91
12005-03-25 Werner Lemberg <wl@gnu.org> 922005-03-25 Werner Lemberg <wl@gnu.org>
2 93
3 * nnmaildir.el: Replace `illegal' with `invalid'. 94 * nnmaildir.el: Replace `illegal' with `invalid'.
diff --git a/lisp/gnus/gnus-group.el b/lisp/gnus/gnus-group.el
index 767bdacb78e..6d38626998c 100644
--- a/lisp/gnus/gnus-group.el
+++ b/lisp/gnus/gnus-group.el
@@ -1984,7 +1984,8 @@ confirmation is required."
1984(defun gnus-group-read-ephemeral-group (group method &optional activate 1984(defun gnus-group-read-ephemeral-group (group method &optional activate
1985 quit-config request-only 1985 quit-config request-only
1986 select-articles 1986 select-articles
1987 parameters) 1987 parameters
1988 number)
1988 "Read GROUP from METHOD as an ephemeral group. 1989 "Read GROUP from METHOD as an ephemeral group.
1989If ACTIVATE, request the group first. 1990If ACTIVATE, request the group first.
1990If QUIT-CONFIG, use that window configuration when exiting from the 1991If QUIT-CONFIG, use that window configuration when exiting from the
@@ -1992,6 +1993,7 @@ ephemeral group.
1992If REQUEST-ONLY, don't actually read the group; just request it. 1993If REQUEST-ONLY, don't actually read the group; just request it.
1993If SELECT-ARTICLES, only select those articles. 1994If SELECT-ARTICLES, only select those articles.
1994If PARAMETERS, use those as the group parameters. 1995If PARAMETERS, use those as the group parameters.
1996If NUMBER, fetch this number of articles.
1995 1997
1996Return the name of the group if selection was successful." 1998Return the name of the group if selection was successful."
1997 (interactive 1999 (interactive
@@ -2039,7 +2041,7 @@ Return the name of the group if selection was successful."
2039 (when (let ((gnus-large-newsgroup gnus-large-ephemeral-newsgroup) 2041 (when (let ((gnus-large-newsgroup gnus-large-ephemeral-newsgroup)
2040 (gnus-fetch-old-headers 2042 (gnus-fetch-old-headers
2041 gnus-fetch-old-ephemeral-headers)) 2043 gnus-fetch-old-ephemeral-headers))
2042 (gnus-group-read-group t t group select-articles)) 2044 (gnus-group-read-group (or number t) t group select-articles))
2043 group) 2045 group)
2044 ;;(error nil) 2046 ;;(error nil)
2045 (quit 2047 (quit
diff --git a/lisp/gnus/gnus-srvr.el b/lisp/gnus/gnus-srvr.el
index e8c7d354145..7b3c033fddb 100644
--- a/lisp/gnus/gnus-srvr.el
+++ b/lisp/gnus/gnus-srvr.el
@@ -851,23 +851,26 @@ buffer.
851 (setq buffer-read-only t) 851 (setq buffer-read-only t)
852 (gnus-run-hooks 'gnus-browse-mode-hook)) 852 (gnus-run-hooks 'gnus-browse-mode-hook))
853 853
854(defun gnus-browse-read-group (&optional no-article) 854(defun gnus-browse-read-group (&optional no-article number)
855 "Enter the group at the current line." 855 "Enter the group at the current line.
856 (interactive) 856If NUMBER, fetch this number of articles."
857 (interactive "P")
857 (let ((group (gnus-browse-group-name))) 858 (let ((group (gnus-browse-group-name)))
858 (if (or (not (gnus-get-info group)) 859 (if (or (not (gnus-get-info group))
859 (gnus-ephemeral-group-p group)) 860 (gnus-ephemeral-group-p group))
860 (unless (gnus-group-read-ephemeral-group 861 (unless (gnus-group-read-ephemeral-group
861 group gnus-browse-current-method nil 862 group gnus-browse-current-method nil
862 (cons (current-buffer) 'browse)) 863 (cons (current-buffer) 'browse)
864 nil nil nil number)
863 (error "Couldn't enter %s" group)) 865 (error "Couldn't enter %s" group))
864 (unless (gnus-group-read-group nil no-article group) 866 (unless (gnus-group-read-group nil no-article group)
865 (error "Couldn't enter %s" group))))) 867 (error "Couldn't enter %s" group)))))
866 868
867(defun gnus-browse-select-group () 869(defun gnus-browse-select-group (&optional number)
868 "Select the current group." 870 "Select the current group.
869 (interactive) 871If NUMBER, fetch this number of articles."
870 (gnus-browse-read-group 'no)) 872 (interactive "P")
873 (gnus-browse-read-group 'no number))
871 874
872(defun gnus-browse-next-group (n) 875(defun gnus-browse-next-group (n)
873 "Go to the next group." 876 "Go to the next group."
diff --git a/lisp/gnus/message.el b/lisp/gnus/message.el
index de56fe2be96..9edbce2620e 100644
--- a/lisp/gnus/message.el
+++ b/lisp/gnus/message.el
@@ -6364,7 +6364,8 @@ Optional DIGEST will use digest to forward."
6364 (replace-match "X-From-Line: ")) 6364 (replace-match "X-From-Line: "))
6365 ;; Send it. 6365 ;; Send it.
6366 (let ((message-inhibit-body-encoding t) 6366 (let ((message-inhibit-body-encoding t)
6367 message-required-mail-headers) 6367 message-required-mail-headers
6368 rfc2047-encode-encoded-words)
6368 (message-send-mail)) 6369 (message-send-mail))
6369 (kill-buffer (current-buffer))) 6370 (kill-buffer (current-buffer)))
6370 (message "Resending message to %s...done" address))) 6371 (message "Resending message to %s...done" address)))
diff --git a/lisp/gnus/mm-util.el b/lisp/gnus/mm-util.el
index 5b4200d6d52..3be6444f18f 100644
--- a/lisp/gnus/mm-util.el
+++ b/lisp/gnus/mm-util.el
@@ -86,6 +86,32 @@
86 (multibyte-char-to-unibyte . identity)))) 86 (multibyte-char-to-unibyte . identity))))
87 87
88(eval-and-compile 88(eval-and-compile
89 (cond
90 ((fboundp 'replace-in-string)
91 (defalias 'mm-replace-in-string 'replace-in-string))
92 ((fboundp 'replace-regexp-in-string)
93 (defun mm-replace-in-string (string regexp newtext &optional literal)
94 "Replace all matches for REGEXP with NEWTEXT in STRING.
95If LITERAL is non-nil, insert NEWTEXT literally. Return a new
96string containing the replacements.
97
98This is a compatibility function for different Emacsen."
99 (replace-regexp-in-string regexp newtext string nil literal)))
100 (t
101 (defun mm-replace-in-string (string regexp newtext &optional literal)
102 "Replace all matches for REGEXP with NEWTEXT in STRING.
103If LITERAL is non-nil, insert NEWTEXT literally. Return a new
104string containing the replacements.
105
106This is a compatibility function for different Emacsen."
107 (let ((start 0) tail)
108 (while (string-match regexp string start)
109 (setq tail (- (length string) (match-end 0)))
110 (setq string (replace-match newtext nil literal string))
111 (setq start (- (length string) tail))))
112 string))))
113
114(eval-and-compile
89 (defalias 'mm-char-or-char-int-p 115 (defalias 'mm-char-or-char-int-p
90 (cond 116 (cond
91 ((fboundp 'char-or-char-int-p) 'char-or-char-int-p) 117 ((fboundp 'char-or-char-int-p) 'char-or-char-int-p)
@@ -606,7 +632,7 @@ But this is very much a corner case, so don't worry about it."
606 632
607 ;; Load the Latin Unity library, if available. 633 ;; Load the Latin Unity library, if available.
608 (when (and (not (featurep 'latin-unity)) (locate-library "latin-unity")) 634 (when (and (not (featurep 'latin-unity)) (locate-library "latin-unity"))
609 (require 'latin-unity)) 635 (ignore-errors (require 'latin-unity)))
610 636
611 ;; Now, can we use it? 637 ;; Now, can we use it?
612 (if (featurep 'latin-unity) 638 (if (featurep 'latin-unity)
@@ -651,7 +677,7 @@ But this is very much a corner case, so don't worry about it."
651 677
652(defmacro mm-xemacs-find-mime-charset (begin end) 678(defmacro mm-xemacs-find-mime-charset (begin end)
653 (when (featurep 'xemacs) 679 (when (featurep 'xemacs)
654 `(mm-xemacs-find-mime-charset-1 ,begin ,end))) 680 `(and (featurep 'mule) (mm-xemacs-find-mime-charset-1 ,begin ,end))))
655 681
656(defun mm-find-mime-charset-region (b e &optional hack-charsets) 682(defun mm-find-mime-charset-region (b e &optional hack-charsets)
657 "Return the MIME charsets needed to encode the region between B and E. 683 "Return the MIME charsets needed to encode the region between B and E.
diff --git a/lisp/gnus/rfc2047.el b/lisp/gnus/rfc2047.el
index 6086f422abd..538e22e0f88 100644
--- a/lisp/gnus/rfc2047.el
+++ b/lisp/gnus/rfc2047.el
@@ -119,12 +119,15 @@ The values can be:
119Valid encodings are nil, `Q' and `B'. These indicate binary (no) encoding, 119Valid encodings are nil, `Q' and `B'. These indicate binary (no) encoding,
120quoted-printable and base64 respectively.") 120quoted-printable and base64 respectively.")
121 121
122(defvar rfc2047-encoding-function-alist 122(defvar rfc2047-encode-function-alist
123 '((Q . rfc2047-q-encode-region) 123 '((Q . rfc2047-q-encode-string)
124 (B . rfc2047-b-encode-region) 124 (B . rfc2047-b-encode-string)
125 (nil . ignore)) 125 (nil . identity))
126 "Alist of RFC2047 encodings to encoding functions.") 126 "Alist of RFC2047 encodings to encoding functions.")
127 127
128(defvar rfc2047-encode-encoded-words t
129 "Whether encoded words should be encoded again.")
130
128;;; 131;;;
129;;; Functions for encoding RFC2047 messages 132;;; Functions for encoding RFC2047 messages
130;;; 133;;;
@@ -166,7 +169,7 @@ This is either `base64' or `quoted-printable'."
166 (save-restriction 169 (save-restriction
167 (rfc2047-narrow-to-field) 170 (rfc2047-narrow-to-field)
168 (re-search-forward ":[ \t\n]*" nil t) 171 (re-search-forward ":[ \t\n]*" nil t)
169 (buffer-substring (point) (point-max))))) 172 (buffer-substring-no-properties (point) (point-max)))))
170 173
171(defvar rfc2047-encoding-type 'address-mime 174(defvar rfc2047-encoding-type 'address-mime
172 "The type of encoding done by `rfc2047-encode-region'. 175 "The type of encoding done by `rfc2047-encode-region'.
@@ -186,24 +189,25 @@ Should be called narrowed to the head of the message."
186 (rfc2047-narrow-to-field) 189 (rfc2047-narrow-to-field)
187 (if (not (rfc2047-encodable-p)) 190 (if (not (rfc2047-encodable-p))
188 (prog1 191 (prog1
189 (if (and (eq (mm-body-7-or-8) '8bit) 192 (if (and (eq (mm-body-7-or-8) '8bit)
190 (mm-multibyte-p) 193 (mm-multibyte-p)
191 (mm-coding-system-p 194 (mm-coding-system-p
192 (car message-posting-charset))) 195 (car message-posting-charset)))
193 ;; 8 bit must be decoded. 196 ;; 8 bit must be decoded.
194 (mm-encode-coding-region 197 (mm-encode-coding-region
195 (point-min) (point-max) 198 (point-min) (point-max)
196 (mm-charset-to-coding-system 199 (mm-charset-to-coding-system
197 (car message-posting-charset)))) 200 (car message-posting-charset))))
198 ;; No encoding necessary, but folding is nice 201 ;; No encoding necessary, but folding is nice
199 (rfc2047-fold-region 202 (when nil
200 (save-excursion 203 (rfc2047-fold-region
201 (goto-char (point-min)) 204 (save-excursion
202 (skip-chars-forward "^:") 205 (goto-char (point-min))
203 (when (looking-at ": ") 206 (skip-chars-forward "^:")
204 (forward-char 2)) 207 (when (looking-at ": ")
205 (point)) 208 (forward-char 2))
206 (point-max))) 209 (point))
210 (point-max))))
207 ;; We found something that may perhaps be encoded. 211 ;; We found something that may perhaps be encoded.
208 (setq method nil 212 (setq method nil
209 alist rfc2047-header-encoding-alist) 213 alist rfc2047-header-encoding-alist)
@@ -213,7 +217,6 @@ Should be called narrowed to the head of the message."
213 (eq (car elem) t)) 217 (eq (car elem) t))
214 (setq alist nil 218 (setq alist nil
215 method (cdr elem)))) 219 method (cdr elem))))
216 (goto-char (point-min))
217 (re-search-forward "^[^:]+: *" nil t) 220 (re-search-forward "^[^:]+: *" nil t)
218 (cond 221 (cond
219 ((eq method 'address-mime) 222 ((eq method 'address-mime)
@@ -267,8 +270,13 @@ The buffer may be narrowed."
267 (require 'message) ; for message-posting-charset 270 (require 'message) ; for message-posting-charset
268 (let ((charsets 271 (let ((charsets
269 (mm-find-mime-charset-region (point-min) (point-max)))) 272 (mm-find-mime-charset-region (point-min) (point-max))))
270 (and charsets 273 (goto-char (point-min))
271 (not (equal charsets (list (car message-posting-charset))))))) 274 (or (and rfc2047-encode-encoded-words
275 (prog1
276 (search-forward "=?" nil t)
277 (goto-char (point-min))))
278 (and charsets
279 (not (equal charsets (list (car message-posting-charset))))))))
272 280
273;; Use this syntax table when parsing into regions that may need 281;; Use this syntax table when parsing into regions that may need
274;; encoding. Double quotes are string delimiters, backslash is 282;; encoding. Double quotes are string delimiters, backslash is
@@ -292,8 +300,8 @@ The buffer may be narrowed."
292 table)))) 300 table))))
293 (modify-syntax-entry ?\\ "\\" table) 301 (modify-syntax-entry ?\\ "\\" table)
294 (modify-syntax-entry ?\" "\"" table) 302 (modify-syntax-entry ?\" "\"" table)
295 (modify-syntax-entry ?\( "." table) 303 (modify-syntax-entry ?\( "(" table)
296 (modify-syntax-entry ?\) "." table) 304 (modify-syntax-entry ?\) ")" table)
297 (modify-syntax-entry ?\< "." table) 305 (modify-syntax-entry ?\< "." table)
298 (modify-syntax-entry ?\> "." table) 306 (modify-syntax-entry ?\> "." table)
299 (modify-syntax-entry ?\[ "." table) 307 (modify-syntax-entry ?\[ "." table)
@@ -310,183 +318,341 @@ By default, the region is treated as containing RFC2822 addresses.
310Dynamically bind `rfc2047-encoding-type' to change that." 318Dynamically bind `rfc2047-encoding-type' to change that."
311 (save-restriction 319 (save-restriction
312 (narrow-to-region b e) 320 (narrow-to-region b e)
313 (if (eq 'mime rfc2047-encoding-type) 321 (let ((encodable-regexp (if rfc2047-encode-encoded-words
314 ;; Simple case. Treat as single word after any initial ASCII 322 "[^\000-\177]+\\|=\\?"
315 ;; part and before any tailing ASCII part. The leading ASCII 323 "[^\000-\177]+"))
316 ;; is relevant for instance in Subject headers with `Re:' for 324 start ; start of current token
317 ;; interoperability with non-MIME clients, and we might as 325 end begin csyntax
318 ;; well avoid the tail too. 326 ;; Whether there's an encoded word before the current token,
319 (progn 327 ;; either immediately or separated by space.
320 (goto-char (point-min)) 328 last-encoded
321 ;; Does it need encoding? 329 (orig-text (buffer-substring-no-properties b e)))
322 (skip-chars-forward "\000-\177") 330 (if (eq 'mime rfc2047-encoding-type)
323 (unless (eobp) 331 ;; Simple case. Continuous words in which all those contain
324 (skip-chars-backward "^ \n") ; beginning of space-delimited word 332 ;; non-ASCII characters are encoded collectively. Encoding
325 (rfc2047-encode (point) (progn 333 ;; ASCII words, including `Re:' used in Subject headers, is
326 (goto-char e) 334 ;; avoided for interoperability with non-MIME clients and
327 (skip-chars-backward "\000-\177") 335 ;; for making it easy to find keywords.
328 (skip-chars-forward "^ \n") 336 (progn
329 ;; end of space-delimited word 337 (goto-char (point-min))
330 (point))))) 338 (while (progn (skip-chars-forward " \t\n")
331 ;; `address-mime' case -- take care of quoted words, comments. 339 (not (eobp)))
332 (with-syntax-table rfc2047-syntax-table 340 (setq start (point))
333 (let ((start) ; start of current token 341 (while (and (looking-at "[ \t\n]*\\([^ \t\n]+\\)")
334 end ; end of current token 342 (progn
335 ;; Whether there's an encoded word before the current 343 (setq end (match-end 0))
336 ;; token, either immediately or separated by space. 344 (re-search-forward encodable-regexp end t)))
337 last-encoded) 345 (goto-char end))
346 (if (> (point) start)
347 (rfc2047-encode start (point))
348 (goto-char end))))
349 ;; `address-mime' case -- take care of quoted words, comments.
350 (with-syntax-table rfc2047-syntax-table
338 (goto-char (point-min)) 351 (goto-char (point-min))
339 (condition-case nil ; in case of unbalanced quotes 352 (condition-case err ; in case of unbalanced quotes
340 ;; Look for rfc2822-style: sequences of atoms, quoted 353 ;; Look for rfc2822-style: sequences of atoms, quoted
341 ;; strings, specials, whitespace. (Specials mustn't be 354 ;; strings, specials, whitespace. (Specials mustn't be
342 ;; encoded.) 355 ;; encoded.)
343 (while (not (eobp)) 356 (while (not (eobp))
344 (setq start (point))
345 ;; Skip whitespace. 357 ;; Skip whitespace.
346 (unless (= 0 (skip-chars-forward " \t\n")) 358 (skip-chars-forward " \t\n")
347 (setq start (point))) 359 (setq start (point))
348 (cond 360 (cond
349 ((not (char-after))) ; eob 361 ((not (char-after))) ; eob
350 ;; else token start 362 ;; else token start
351 ((eq ?\" (char-syntax (char-after))) 363 ((eq ?\" (setq csyntax (char-syntax (char-after))))
352 ;; Quoted word. 364 ;; Quoted word.
353 (forward-sexp) 365 (forward-sexp)
354 (setq end (point)) 366 (setq end (point))
355 ;; Does it need encoding? 367 ;; Does it need encoding?
356 (goto-char start) 368 (goto-char start)
357 (skip-chars-forward "\000-\177" end) 369 (if (re-search-forward encodable-regexp end 'move)
358 (if (= end (point)) 370 ;; It needs encoding. Strip the quotes first,
359 (setq last-encoded nil) 371 ;; since encoded words can't occur in quotes.
360 ;; It needs encoding. Strip the quotes first, 372 (progn
361 ;; since encoded words can't occur in quotes. 373 (goto-char end)
362 (goto-char end) 374 (delete-backward-char 1)
363 (delete-backward-char 1) 375 (goto-char start)
364 (goto-char start) 376 (delete-char 1)
365 (delete-char 1) 377 (when last-encoded
366 (when last-encoded 378 ;; There was a preceding quoted word. We need
367 ;; There was a preceding quoted word. We need 379 ;; to include any separating whitespace in this
368 ;; to include any separating whitespace in this 380 ;; word to avoid it getting lost.
369 ;; word to avoid it getting lost. 381 (skip-chars-backward " \t")
370 (skip-chars-backward " \t") 382 ;; A space is needed between the encoded words.
371 ;; A space is needed between the encoded words. 383 (insert ? )
372 (insert ? ) 384 (setq start (point)
373 (setq start (point) 385 end (1+ end)))
374 end (1+ end))) 386 ;; Adjust the end position for the deleted quotes.
375 ;; Adjust the end position for the deleted quotes. 387 (rfc2047-encode start (- end 2))
376 (rfc2047-encode start (- end 2)) 388 (setq last-encoded t)) ; record that it was encoded
377 (setq last-encoded t))) ; record that it was encoded 389 (setq last-encoded nil)))
378 ((eq ?. (char-syntax (char-after))) 390 ((eq ?. csyntax)
379 ;; Skip other delimiters, but record that they've 391 ;; Skip other delimiters, but record that they've
380 ;; potentially separated quoted words. 392 ;; potentially separated quoted words.
381 (forward-char) 393 (forward-char)
382 (setq last-encoded nil)) 394 (setq last-encoded nil))
395 ((eq ?\) csyntax)
396 (error "Unbalanced parentheses"))
397 ((eq ?\( csyntax)
398 ;; Look for the end of parentheses.
399 (forward-list)
400 ;; Encode text as an unstructured field.
401 (let ((rfc2047-encoding-type 'mime))
402 (rfc2047-encode-region (1+ start) (1- (point))))
403 (skip-chars-forward ")"))
383 (t ; normal token/whitespace sequence 404 (t ; normal token/whitespace sequence
384 ;; Find the end. 405 ;; Find the end.
385 (forward-word 1) 406 ;; Skip one ASCII word, or encode continuous words
386 (skip-chars-backward " \t") 407 ;; in which all those contain non-ASCII characters.
408 (setq end nil)
409 (while (not (or end (eobp)))
410 (when (looking-at "[\000-\177]+")
411 (setq begin (point)
412 end (match-end 0))
413 (when (progn
414 (while (and (or (re-search-forward
415 "[ \t\n]\\|\\Sw" end 'move)
416 (setq end nil))
417 (eq ?\\ (char-syntax (char-before))))
418 ;; Skip backslash-quoted characters.
419 (forward-char))
420 end)
421 (setq end (match-beginning 0))
422 (if rfc2047-encode-encoded-words
423 (progn
424 (goto-char begin)
425 (when (search-forward "=?" end 'move)
426 (goto-char (match-beginning 0))
427 (setq end nil)))
428 (goto-char end))))
429 ;; Where the value nil of `end' means there may be
430 ;; text to have to be encoded following the point.
431 ;; Otherwise, the point reached to the end of ASCII
432 ;; words separated by whitespace or a special char.
433 (unless end
434 (when (looking-at encodable-regexp)
435 (goto-char (setq begin (match-end 0)))
436 (while (and (looking-at "[ \t\n]+\\([^ \t\n]+\\)")
437 (setq end (match-end 0))
438 (progn
439 (while (re-search-forward
440 encodable-regexp end t))
441 (< begin (point)))
442 (goto-char begin)
443 (or (not (re-search-forward "\\Sw" end t))
444 (progn
445 (goto-char (match-beginning 0))
446 nil)))
447 (goto-char end))
448 (when (looking-at "[^ \t\n]+")
449 (setq end (match-end 0))
450 (if (re-search-forward "\\Sw+" end t)
451 ;; There are special characters better
452 ;; to be encoded so that MTAs may parse
453 ;; them safely.
454 (cond ((= end (point)))
455 ((looking-at (concat "\\sw*\\("
456 encodable-regexp
457 "\\)"))
458 (setq end nil))
459 (t
460 (goto-char (1- (match-end 0)))
461 (unless (= (point) (match-beginning 0))
462 ;; Separate encodable text and
463 ;; delimiter.
464 (insert " "))))
465 (goto-char end)
466 (skip-chars-forward " \t\n")
467 (if (and (looking-at "[^ \t\n]+")
468 (string-match encodable-regexp
469 (match-string 0)))
470 (setq end nil)
471 (goto-char end)))))))
472 (skip-chars-backward " \t\n")
387 (setq end (point)) 473 (setq end (point))
388 ;; Deal with encoding and leading space as for
389 ;; quoted words.
390 (goto-char start) 474 (goto-char start)
391 (skip-chars-forward "\000-\177" end) 475 (if (re-search-forward encodable-regexp end 'move)
392 (if (= end (point)) 476 (progn
393 (setq last-encoded nil) 477 (unless (memq (char-before start) '(nil ?\t ? ))
394 (when last-encoded 478 (if (progn
395 (goto-char start) 479 (goto-char start)
396 (skip-chars-backward " \t") 480 (skip-chars-backward "^ \t\n")
397 (insert ? ) 481 (and (looking-at "\\Sw+")
398 (setq start (point) 482 (= (match-end 0) start)))
399 end (1+ end))) 483 ;; Also encode bogus delimiters.
400 (rfc2047-encode start end) 484 (setq start (point))
401 (setq last-encoded t))))) 485 ;; Separate encodable text and delimiter.
486 (goto-char start)
487 (insert " ")
488 (setq start (1+ start)
489 end (1+ end))))
490 (rfc2047-encode start end)
491 (setq last-encoded t))
492 (setq last-encoded nil)))))
402 (error 493 (error
403 (error "Invalid data for rfc2047 encoding: %s" 494 (if (or debug-on-quit debug-on-error)
404 (buffer-substring b e))))))) 495 (signal (car err) (cdr err))
405 (rfc2047-fold-region b (point)))) 496 (error "Invalid data for rfc2047 encoding: %s"
497 (mm-replace-in-string orig-text "[ \t\n]+" " "))))))))
498 (rfc2047-fold-region b (point))
499 (goto-char (point-max))))
406 500
407(defun rfc2047-encode-string (string) 501(defun rfc2047-encode-string (string)
408 "Encode words in STRING. 502 "Encode words in STRING.
409By default, the string is treated as containing addresses (see 503By default, the string is treated as containing addresses (see
410`rfc2047-encoding-type')." 504`rfc2047-encoding-type')."
411 (with-temp-buffer 505 (mm-with-multibyte-buffer
412 (insert string) 506 (insert string)
413 (rfc2047-encode-region (point-min) (point-max)) 507 (rfc2047-encode-region (point-min) (point-max))
414 (buffer-string))) 508 (buffer-string)))
415 509
510(defvar rfc2047-encode-max-chars 76
511 "Maximum characters of each header line that contain encoded-words.
512If it is nil, encoded-words will not be folded. Too small value may
513cause an error. Don't change this for no particular reason.")
514
515(defun rfc2047-encode-1 (column string cs encoder start crest tail
516 &optional eword)
517 "Subroutine used by `rfc2047-encode'."
518 (cond ((string-equal string "")
519 (or eword ""))
520 ((not rfc2047-encode-max-chars)
521 (concat start
522 (funcall encoder (if cs
523 (mm-encode-coding-string string cs)
524 string))
525 "?="))
526 ((>= column rfc2047-encode-max-chars)
527 (when eword
528 (cond ((string-match "\n[ \t]+\\'" eword)
529 ;; Reomove a superfluous empty line.
530 (setq eword (substring eword 0 (match-beginning 0))))
531 ((string-match "(+\\'" eword)
532 ;; Break the line before the open parenthesis.
533 (setq crest (concat crest (match-string 0 eword))
534 eword (substring eword 0 (match-beginning 0))))))
535 (rfc2047-encode-1 (length crest) string cs encoder start " " tail
536 (concat eword "\n" crest)))
537 (t
538 (let ((index 0)
539 (limit (1- (length string)))
540 (prev "")
541 next len)
542 (while (and prev
543 (<= index limit))
544 (setq next (concat start
545 (funcall encoder
546 (if cs
547 (mm-encode-coding-string
548 (substring string 0 (1+ index))
549 cs)
550 (substring string 0 (1+ index))))
551 "?=")
552 len (+ column (length next)))
553 (if (> len rfc2047-encode-max-chars)
554 (setq next prev
555 prev nil)
556 (if (or (< index limit)
557 (<= (+ len (or (string-match "\n" tail)
558 (length tail)))
559 rfc2047-encode-max-chars))
560 (setq prev next
561 index (1+ index))
562 (if (string-match "\\`)+" tail)
563 ;; Break the line after the close parenthesis.
564 (setq tail (concat (substring tail 0 (match-end 0))
565 "\n "
566 (substring tail (match-end 0)))
567 prev next
568 index (1+ index))
569 (setq next prev
570 prev nil)))))
571 (if (> index limit)
572 (concat eword next tail)
573 (if (= 0 index)
574 (if (and eword
575 (string-match "(+\\'" eword))
576 (setq crest (concat crest (match-string 0 eword))
577 eword (substring eword 0 (match-beginning 0)))
578 (setq eword (concat eword next)))
579 (setq crest " "
580 eword (concat eword next)))
581 (when (string-match "\n[ \t]+\\'" eword)
582 ;; Reomove a superfluous empty line.
583 (setq eword (substring eword 0 (match-beginning 0))))
584 (rfc2047-encode-1 (length crest) (substring string index)
585 cs encoder start " " tail
586 (concat eword "\n" crest)))))))
587
416(defun rfc2047-encode (b e) 588(defun rfc2047-encode (b e)
417 "Encode the word(s) in the region B to E. 589 "Encode the word(s) in the region B to E.
418By default, the region is treated as containing addresses (see 590Point moves to the end of the region."
419`rfc2047-encoding-type')." 591 (let ((mime-charset (or (mm-find-mime-charset-region b e) (list 'us-ascii)))
420 (let* ((mime-charset (mm-find-mime-charset-region b e)) 592 cs encoding tail crest eword)
421 (cs (if (> (length mime-charset) 1) 593 (cond ((> (length mime-charset) 1)
422 ;; Fixme: Instead of this, try to break region into 594 (error "Can't rfc2047-encode `%s'"
423 ;; parts that can be encoded separately. 595 (buffer-substring-no-properties b e)))
424 (error "Can't rfc2047-encode `%s'" 596 ((= (length mime-charset) 1)
425 (buffer-substring b e)) 597 (setq mime-charset (car mime-charset)
426 (setq mime-charset (car mime-charset)) 598 cs (mm-charset-to-coding-system mime-charset))
427 (mm-charset-to-coding-system mime-charset))) 599 (unless (and (mm-multibyte-p)
428 ;; Fixme: Better, calculate the number of non-ASCII 600 (mm-coding-system-p cs))
429 ;; characters, at least for 8-bit charsets. 601 (setq cs nil))
430 (encoding (or (cdr (assq mime-charset 602 (save-restriction
603 (narrow-to-region b e)
604 (setq encoding
605 (or (cdr (assq mime-charset
431 rfc2047-charset-encoding-alist)) 606 rfc2047-charset-encoding-alist))
432 ;; For the charsets that don't have a preferred 607 ;; For the charsets that don't have a preferred
433 ;; encoding, choose the one that's shorter. 608 ;; encoding, choose the one that's shorter.
434 (save-restriction 609 (if (eq (rfc2047-qp-or-base64) 'base64)
435 (narrow-to-region b e) 610 'B
436 (if (eq (rfc2047-qp-or-base64) 'base64) 611 'Q)))
437 'B 612 (widen)
438 'Q)))) 613 (goto-char e)
439 (start (concat 614 (skip-chars-forward "^ \t\n")
440 "=?" (downcase (symbol-name mime-charset)) "?" 615 ;; `tail' may contain a close parenthesis.
441 (downcase (symbol-name encoding)) "?")) 616 (setq tail (buffer-substring-no-properties e (point)))
442 (factor (case mime-charset 617 (goto-char b)
443 ((iso-8859-5 iso-8859-7 iso-8859-8 koi8-r) 1) 618 (setq b (point-marker)
444 ((big5 gb2312 euc-kr) 2) 619 e (set-marker (make-marker) e))
445 (utf-8 4) 620 (rfc2047-fold-region (rfc2047-point-at-bol) b)
446 (t 8))) 621 (goto-char b)
447 (pre (- b (save-restriction 622 (skip-chars-backward "^ \t\n")
448 (widen) 623 (unless (= 0 (skip-chars-backward " \t"))
449 (rfc2047-point-at-bol)))) 624 ;; `crest' may contain whitespace and an open parenthesis.
450 ;; encoded-words must not be longer than 75 characters, 625 (setq crest (buffer-substring-no-properties (point) b)))
451 ;; including charset, encoding etc. This leaves us with 626 (setq eword (rfc2047-encode-1
452 ;; 75 - (length start) - 2 - 2 characters. The last 2 is for 627 (- b (rfc2047-point-at-bol))
453 ;; possible base64 padding. In the worst case (iso-2022-*) 628 (mm-replace-in-string
454 ;; each character expands to 8 bytes which is expanded by a 629 (buffer-substring-no-properties b e)
455 ;; factor of 4/3 by base64 encoding. 630 "\n\\([ \t]?\\)" "\\1")
456 (length (floor (- 75 (length start) 4) (* factor (/ 4.0 3.0)))) 631 cs
457 ;; Limit line length to 76 characters. 632 (or (cdr (assq encoding
458 (length1 (max 1 (floor (- 76 (length start) 4 pre) 633 rfc2047-encode-function-alist))
459 (* factor (/ 4.0 3.0))))) 634 'identity)
460 (first t)) 635 (concat "=?" (downcase (symbol-name mime-charset))
461 (if mime-charset 636 "?" (upcase (symbol-name encoding)) "?")
462 (save-restriction 637 (or crest " ")
463 (narrow-to-region b e) 638 tail))
464 (when (eq encoding 'B) 639 (delete-region (if (eq (aref eword 0) ?\n)
465 ;; break into lines before encoding 640 (if (bolp)
466 (goto-char (point-min)) 641 ;; The line was folded before encoding.
467 (while (not (eobp)) 642 (1- (point))
468 (if first 643 (point))
469 (progn 644 (goto-char b))
470 (goto-char (min (point-max) (+ length1 (point)))) 645 (+ e (length tail)))
471 (setq first nil)) 646 ;; `eword' contains `crest' and `tail'.
472 (goto-char (min (point-max) (+ length (point))))) 647 (insert eword)
473 (unless (eobp) 648 (set-marker b nil)
474 (insert ?\n))) 649 (set-marker e nil)
475 (setq first t)) 650 (unless (or (/= 0 (length tail))
476 (if (and (mm-multibyte-p) 651 (eobp)
477 (mm-coding-system-p cs)) 652 (looking-at "[ \t\n)]"))
478 (mm-encode-coding-region (point-min) (point-max) cs)) 653 (insert " "))))
479 (funcall (cdr (assq encoding rfc2047-encoding-function-alist)) 654 (t
480 (point-min) (point-max)) 655 (goto-char e)))))
481 (goto-char (point-min))
482 (while (not (eobp))
483 (unless first
484 (insert ? ))
485 (setq first nil)
486 (insert start)
487 (end-of-line)
488 (insert "?=")
489 (forward-line 1))))))
490 656
491(defun rfc2047-fold-field () 657(defun rfc2047-fold-field ()
492 "Fold the current header field." 658 "Fold the current header field."
@@ -512,6 +678,7 @@ By default, the region is treated as containing addresses (see
512 (goto-char (or break qword-break)) 678 (goto-char (or break qword-break))
513 (setq break nil 679 (setq break nil
514 qword-break nil) 680 qword-break nil)
681 (skip-chars-backward " \t")
515 (if (looking-at "[ \t]") 682 (if (looking-at "[ \t]")
516 (insert ?\n) 683 (insert ?\n)
517 (insert "\n ")) 684 (insert "\n "))
@@ -533,10 +700,8 @@ By default, the region is treated as containing addresses (see
533 (forward-char 1)) 700 (forward-char 1))
534 ((memq (char-after) '(? ?\t)) 701 ((memq (char-after) '(? ?\t))
535 (skip-chars-forward " \t") 702 (skip-chars-forward " \t")
536 (if first 703 (unless first ;; Don't break just after the header name.
537 ;; Don't break just after the header name. 704 (setq break (point))))
538 (setq first nil)
539 (setq break (1- (point)))))
540 ((not break) 705 ((not break)
541 (if (not (looking-at "=\\?[^=]")) 706 (if (not (looking-at "=\\?[^=]"))
542 (if (eq (char-after) ?=) 707 (if (eq (char-after) ?=)
@@ -547,15 +712,17 @@ By default, the region is treated as containing addresses (see
547 (setq qword-break (point))) 712 (setq qword-break (point)))
548 (skip-chars-forward "^ \t\n\r"))) 713 (skip-chars-forward "^ \t\n\r")))
549 (t 714 (t
550 (skip-chars-forward "^ \t\n\r")))) 715 (skip-chars-forward "^ \t\n\r")))
716 (setq first nil))
551 (when (and (or break qword-break) 717 (when (and (or break qword-break)
552 (> (- (point) bol) 76)) 718 (> (- (point) bol) 76))
553 (goto-char (or break qword-break)) 719 (goto-char (or break qword-break))
554 (setq break nil 720 (setq break nil
555 qword-break nil) 721 qword-break nil)
556 (if (looking-at "[ \t]") 722 (if (or (> 0 (skip-chars-backward " \t"))
557 (insert ?\n) 723 (looking-at "[ \t]"))
558 (insert "\n ")) 724 (insert ?\n)
725 (insert "\n "))
559 (setq bol (1- (point))) 726 (setq bol (1- (point)))
560 ;; Don't break before the first non-LWSP characters. 727 ;; Don't break before the first non-LWSP characters.
561 (skip-chars-forward " \t") 728 (skip-chars-forward " \t")
@@ -590,48 +757,48 @@ By default, the region is treated as containing addresses (see
590 (setq eol (rfc2047-point-at-eol)) 757 (setq eol (rfc2047-point-at-eol))
591 (forward-line 1))))) 758 (forward-line 1)))))
592 759
593(defun rfc2047-b-encode-region (b e) 760(defun rfc2047-b-encode-string (string)
594 "Base64-encode the header contained in region B to E." 761 "Base64-encode the header contained in STRING."
595 (save-restriction 762 (base64-encode-string string t))
596 (narrow-to-region (goto-char b) e) 763
597 (while (not (eobp)) 764(defun rfc2047-q-encode-string (string)
598 (base64-encode-region (point) (progn (end-of-line) (point)) t) 765 "Quoted-printable-encode the header in STRING."
599 (if (and (bolp) (eolp)) 766 (mm-with-unibyte-buffer
600 (delete-backward-char 1)) 767 (insert string)
601 (forward-line)))) 768 (quoted-printable-encode-region
602 769 (point-min) (point-max) nil
603(defun rfc2047-q-encode-region (b e) 770 ;; = (\075), _ (\137), ? (\077) are used in the encoded word.
604 "Quoted-printable-encode the header in region B to E." 771 ;; Avoid using 8bit characters.
605 (save-excursion 772 ;; This list excludes `especials' (see the RFC2047 syntax),
606 (save-restriction 773 ;; meaning that some characters in non-structured fields will
607 (narrow-to-region (goto-char b) e) 774 ;; get encoded when they con't need to be. The following is
608 (let ((bol (save-restriction 775 ;; what it used to be.
609 (widen) 776 ;;; ;; Equivalent to "^\000-\007\011\013\015-\037\200-\377=_?"
610 (rfc2047-point-at-bol)))) 777 ;;; "\010\012\014\040-\074\076\100-\136\140-\177")
611 (quoted-printable-encode-region 778 "-\b\n\f !#-'*+0-9A-Z\\^`-~\d")
612 b e nil 779 (subst-char-in-region (point-min) (point-max) ? ?_)
613 ;; = (\075), _ (\137), ? (\077) are used in the encoded word. 780 (buffer-string)))
614 ;; Avoid using 8bit characters. 781
615 ;; This list excludes `especials' (see the RFC2047 syntax), 782(defun rfc2047-encode-parameter (param value)
616 ;; meaning that some characters in non-structured fields will 783 "Return and PARAM=VALUE string encoded in the RFC2047-like style.
617 ;; get encoded when they con't need to be. The following is 784This is a replacement for the `rfc2231-encode-string' function.
618 ;; what it used to be. 785
619;;; ;; Equivalent to "^\000-\007\011\013\015-\037\200-\377=_?" 786When attaching files as MIME parts, we should use the RFC2231 encoding
620;;; "\010\012\014\040-\074\076\100-\136\140-\177") 787to specify the file names containing non-ASCII characters. However,
621 "-\b\n\f !#-'*+0-9A-Z\\^`-~\d") 788many mail softwares don't support it in practice and recipients won't
622 (subst-char-in-region (point-min) (point-max) ? ?_) 789be able to extract files with correct names. Instead, the RFC2047-like
623 ;; The size of QP encapsulation is about 20, so set limit to 790encoding is acceptable generally. This function provides the very
624 ;; 56=76-20. 791RFC2047-like encoding, resigning to such a regrettable trend. To use
625 (unless (< (- (point-max) (point-min)) 56) 792it, put the following line in your ~/.gnus.el file:
626 ;; Don't break if it could fit in one line. 793
627 ;; Let rfc2047-encode-region break it later. 794\(defalias 'mail-header-encode-parameter 'rfc2047-encode-parameter)
628 (goto-char (1+ (point-min))) 795"
629 (while (and (not (bobp)) (not (eobp))) 796 (let* ((rfc2047-encoding-type 'mime)
630 (goto-char (min (point-max) (+ 56 bol))) 797 (rfc2047-encode-max-chars nil)
631 (search-backward "=" (- (point) 2) t) 798 (string (rfc2047-encode-string value)))
632 (unless (or (bobp) (eobp)) 799 (if (string-match (concat "[" ietf-drums-tspecials "]") string)
633 (insert ?\n) 800 (format "%s=%S" param string)
634 (setq bol (point))))))))) 801 (concat param "=" string))))
635 802
636;;; 803;;;
637;;; Functions for decoding RFC2047 messages 804;;; Functions for decoding RFC2047 messages
@@ -639,8 +806,8 @@ By default, the region is treated as containing addresses (see
639 806
640(eval-and-compile 807(eval-and-compile
641 (defconst rfc2047-encoded-word-regexp 808 (defconst rfc2047-encoded-word-regexp
642 "=\\?\\([^][\000-\040()<>@,\;:\\\"/?.=]+\\)\\?\\(B\\|Q\\)\ 809 "=\\?\\([^][\000-\040()<>@,\;:*\\\"/?.=]+\\)\\(\\*[^?]+\\)?\
643\\?\\([!->@-~ +]*\\)\\?=")) 810\\?\\(B\\|Q\\)\\?\\([!->@-~ ]*\\)\\?="))
644 811
645(defvar rfc2047-quote-decoded-words-containing-tspecials nil 812(defvar rfc2047-quote-decoded-words-containing-tspecials nil
646 "If non-nil, quote decoded words containing special characters.") 813 "If non-nil, quote decoded words containing special characters.")
@@ -671,7 +838,7 @@ By default, the region is treated as containing addresses (see
671 "\\(\n?[ \t]\\)+" 838 "\\(\n?[ \t]\\)+"
672 "\\(" rfc2047-encoded-word-regexp "\\)")) 839 "\\(" rfc2047-encoded-word-regexp "\\)"))
673 nil t) 840 nil t)
674 (delete-region (goto-char (match-end 1)) (match-beginning 6))) 841 (delete-region (goto-char (match-end 1)) (match-beginning 7)))
675 ;; Decode the encoded words. 842 ;; Decode the encoded words.
676 (setq b (goto-char (point-min))) 843 (setq b (goto-char (point-min)))
677 (while (re-search-forward rfc2047-encoded-word-regexp nil t) 844 (while (re-search-forward rfc2047-encoded-word-regexp nil t)
@@ -774,7 +941,20 @@ By default, the region is treated as containing addresses (see
774 mail-parse-charset 941 mail-parse-charset
775 (not (eq mail-parse-charset 'us-ascii)) 942 (not (eq mail-parse-charset 'us-ascii))
776 (not (eq mail-parse-charset 'gnus-decoded))) 943 (not (eq mail-parse-charset 'gnus-decoded)))
777 (mm-decode-coding-string string mail-parse-charset) 944 ;; `decode-coding-string' in Emacs offers a third optional
945 ;; arg NOCOPY to avoid consing a new string if the decoding
946 ;; is "trivial". Unfortunately it currently doesn't
947 ;; consider anything else than a `nil' coding system
948 ;; trivial.
949 ;; `rfc2047-decode-string' is called multiple times for each
950 ;; article during summary buffer generation, and we really
951 ;; want to avoid unnecessary consing. So we bypass
952 ;; `decode-coding-string' if the string is purely ASCII.
953 (if (and (fboundp 'detect-coding-string)
954 ;; string is purely ASCII
955 (eq (detect-coding-string string t) 'undecided))
956 string
957 (mm-decode-coding-string string mail-parse-charset))
778 (mm-string-as-multibyte string))))) 958 (mm-string-as-multibyte string)))))
779 959
780(defun rfc2047-parse-and-decode (word) 960(defun rfc2047-parse-and-decode (word)
@@ -787,8 +967,8 @@ decodable."
787 (condition-case nil 967 (condition-case nil
788 (rfc2047-decode 968 (rfc2047-decode
789 (match-string 1 word) 969 (match-string 1 word)
790 (upcase (match-string 2 word)) 970 (string-to-char (match-string 3 word))
791 (match-string 3 word)) 971 (match-string 4 word))
792 (error word)) 972 (error word))
793 word))) ; un-decodable 973 word))) ; un-decodable
794 974
@@ -809,7 +989,7 @@ decodable."
809 989
810(defun rfc2047-decode (charset encoding string) 990(defun rfc2047-decode (charset encoding string)
811 "Decode STRING from the given MIME CHARSET in the given ENCODING. 991 "Decode STRING from the given MIME CHARSET in the given ENCODING.
812Valid ENCODINGs are \"B\" and \"Q\". 992Valid ENCODINGs are the characters \"B\" and \"Q\".
813If your Emacs implementation can't decode CHARSET, return nil." 993If your Emacs implementation can't decode CHARSET, return nil."
814 (if (stringp charset) 994 (if (stringp charset)
815 (setq charset (intern (downcase charset)))) 995 (setq charset (intern (downcase charset))))
@@ -824,18 +1004,17 @@ If your Emacs implementation can't decode CHARSET, return nil."
824 (memq 'gnus-unknown mail-parse-ignored-charsets)) 1004 (memq 'gnus-unknown mail-parse-ignored-charsets))
825 (setq cs (mm-charset-to-coding-system mail-parse-charset))) 1005 (setq cs (mm-charset-to-coding-system mail-parse-charset)))
826 (when cs 1006 (when cs
827 (when (and (eq cs 'ascii) 1007 (when (eq cs 'ascii)
828 mail-parse-charset) 1008 (setq cs (or mail-parse-charset 'raw-text)))
829 (setq cs mail-parse-charset))
830 (mm-decode-coding-string 1009 (mm-decode-coding-string
831 (cond 1010 (cond
832 ((equal "B" encoding) 1011 ((char-equal ?B encoding)
833 (base64-decode-string 1012 (base64-decode-string
834 (rfc2047-pad-base64 string))) 1013 (rfc2047-pad-base64 string)))
835 ((equal "Q" encoding) 1014 ((char-equal ?Q encoding)
836 (quoted-printable-decode-string 1015 (quoted-printable-decode-string
837 (mm-replace-chars-in-string string ?_ ? ))) 1016 (mm-subst-char-in-string ?_ ? string t)))
838 (t (error "Invalid encoding: %s" encoding))) 1017 (t (error "Invalid encoding: %c" encoding)))
839 cs)))) 1018 cs))))
840 1019
841(provide 'rfc2047) 1020(provide 'rfc2047)