* gnus-agent.el (gnus-agent-regenerate-group): New function.
[gnus] / lisp / rfc2047.el
1 ;;; rfc2047.el --- Functions for encoding and decoding rfc2047 messages
2 ;; Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
3
4 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
5 ;;      MORIOKA Tomohiko <morioka@jaist.ac.jp>
6 ;; This file is part of GNU Emacs.
7
8 ;; GNU Emacs is free software; you can redistribute it and/or modify
9 ;; it under the terms of the GNU General Public License as published by
10 ;; the Free Software Foundation; either version 2, or (at your option)
11 ;; any later version.
12
13 ;; GNU Emacs is distributed in the hope that it will be useful,
14 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 ;; GNU General Public License for more details.
17
18 ;; You should have received a copy of the GNU General Public License
19 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
20 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 ;; Boston, MA 02111-1307, USA.
22
23 ;;; Commentary:
24
25 ;; RFC 2047 is "MIME (Multipurpose Internet Mail Extensions) Part
26 ;; Three:  Message Header Extensions for Non-ASCII Text".
27
28 ;;; Code:
29
30 (eval-when-compile (require 'cl))
31
32 (require 'qp)
33 (require 'mm-util)
34 (require 'ietf-drums)
35 (require 'mail-prsvr)
36 (require 'base64)
37 ;; Fixme: Avoid this (for gnus-point-at-...) mm dependence on gnus.
38 (require 'gnus-util)
39 (autoload 'mm-body-7-or-8 "mm-bodies")
40
41 (defvar rfc2047-header-encoding-alist
42   '(("Newsgroups" . nil)
43     ("Message-ID" . nil)
44     ("\\(Resent-\\)?\\(From\\|Cc\\|To\\|Bcc\\|Reply-To\\|Sender\\)" .
45      "-A-Za-z0-9!*+/=_")
46     (t . mime))
47   "*Header/encoding method alist.
48 The list is traversed sequentially.  The keys can either be
49 header regexps or t.
50
51 The values can be:
52
53 1) nil, in which case no encoding is done;
54 2) `mime', in which case the header will be encoded according to RFC2047;
55 3) a charset, in which case it will be encoded as that charset;
56 4) `default', in which case the field will be encoded as the rest
57    of the article.
58 5) a string, like `mime', expect for using it as word-chars.")
59
60 (defvar rfc2047-charset-encoding-alist
61   '((us-ascii . nil)
62     (iso-8859-1 . Q)
63     (iso-8859-2 . Q)
64     (iso-8859-3 . Q)
65     (iso-8859-4 . Q)
66     (iso-8859-5 . B)
67     (koi8-r . B)
68     (iso-8859-7 . Q)
69     (iso-8859-8 . Q)
70     (iso-8859-9 . Q)
71     (iso-8859-14 . Q)
72     (iso-8859-15 . Q)
73     (iso-2022-jp . B)
74     (iso-2022-kr . B)
75     (gb2312 . B)
76     (big5 . B)
77     (cn-big5 . B)
78     (cn-gb . B)
79     (cn-gb-2312 . B)
80     (euc-kr . B)
81     (iso-2022-jp-2 . B)
82     (iso-2022-int-1 . B))
83   "Alist of MIME charsets to RFC2047 encodings.
84 Valid encodings are nil, `Q' and `B'.")
85
86 (defvar rfc2047-encoding-function-alist
87   '((Q . rfc2047-q-encode-region)
88     (B . rfc2047-b-encode-region)
89     (nil . ignore))
90   "Alist of RFC2047 encodings to encoding functions.")
91
92 (defvar rfc2047-q-encoding-alist
93   '(("\\(Resent-\\)?\\(From\\|Cc\\|To\\|Bcc\\|Reply-To\\|Sender\\):"
94      . "-A-Za-z0-9!*+/" )
95     ;; = (\075), _ (\137), ? (\077) are used in the encoded word.
96     ;; Avoid using 8bit characters.
97     ;; Equivalent to "^\000-\007\011\013\015-\037\200-\377=_?"
98     ("." . "\010\012\014\040-\074\076\100-\136\140-\177"))
99   "Alist of header regexps and valid Q characters.")
100
101 ;;;
102 ;;; Functions for encoding RFC2047 messages
103 ;;;
104
105 (defun rfc2047-narrow-to-field ()
106   "Narrow the buffer to the header on the current line."
107   (beginning-of-line)
108   (narrow-to-region
109    (point)
110    (progn
111      (forward-line 1)
112      (if (re-search-forward "^[^ \n\t]" nil t)
113          (progn
114            (beginning-of-line)
115            (point))
116        (point-max))))
117   (goto-char (point-min)))
118
119 (defun rfc2047-field-value ()
120   "Return the value of the field at point."
121   (save-excursion
122     (save-restriction
123       (rfc2047-narrow-to-field)
124       (re-search-forward ":[ \t\n]*" nil t)
125       (buffer-substring (point) (point-max)))))
126
127 (defun rfc2047-encode-message-header ()
128   "Encode the message header according to `rfc2047-header-encoding-alist'.
129 Should be called narrowed to the head of the message."
130   (interactive "*")
131   (save-excursion
132     (goto-char (point-min))
133     (let (alist elem method)
134       (while (not (eobp))
135         (save-restriction
136           (rfc2047-narrow-to-field)
137           (if (not (rfc2047-encodable-p))
138               (prog1
139                 (if (and (eq (mm-body-7-or-8) '8bit)
140                          (mm-multibyte-p)
141                          (mm-coding-system-p
142                           (car message-posting-charset)))
143                     ;; 8 bit must be decoded.
144                     ;; Is message-posting-charset a coding system?
145                     (mm-encode-coding-region
146                      (point-min) (point-max)
147                      (car message-posting-charset))
148                   nil)
149                 ;; No encoding necessary, but folding is nice
150                 (rfc2047-fold-region
151                  (save-excursion
152                    (goto-char (point-min))
153                    (skip-chars-forward "^:")
154                    (when (looking-at ": ")
155                      (forward-char 2))
156                    (point))
157                  (point-max)))
158             ;; We found something that may perhaps be encoded.
159             (setq method nil
160                   alist rfc2047-header-encoding-alist)
161             (while (setq elem (pop alist))
162               (when (or (and (stringp (car elem))
163                              (looking-at (car elem)))
164                         (eq (car elem) t))
165                 (setq alist nil
166                       method (cdr elem))))
167             (cond
168              ((stringp method)
169               (rfc2047-encode-region (point-min) (point-max) method))
170              ((eq method 'mime)
171               (rfc2047-encode-region (point-min) (point-max)))
172              ((eq method 'default)
173               (if (and (featurep 'mule)
174                        (if (boundp 'default-enable-multibyte-characters)
175                            default-enable-multibyte-characters)
176                        mail-parse-charset)
177                   (mm-encode-coding-region (point-min) (point-max)
178                                            mail-parse-charset)))
179              ;; We get this when CC'ing messsages to newsgroups with
180              ;; 8-bit names.  The group name mail copy just get
181              ;; unconditionally encoded.  Previously, it would ask
182              ;; whether to encode, which was quite confusing for the
183              ;; user.  If the new behaviour is wrong, tell me. I have
184              ;; left the old code commented out below.
185              ;; -- Per Abrahamsen <abraham@dina.kvl.dk> Date: 2001-10-07.
186              ((null method)
187               (when (delq 'ascii 
188                           (mm-find-charset-region (point-min) (point-max)))
189                 (rfc2047-encode-region (point-min) (point-max))))
190 ;;;          ((null method)
191 ;;;           (and (delq 'ascii
192 ;;;                      (mm-find-charset-region (point-min)
193 ;;;                                              (point-max)))
194 ;;;                (if (or (message-options-get
195 ;;;                         'rfc2047-encode-message-header-encode-any)
196 ;;;                        (message-options-set
197 ;;;                         'rfc2047-encode-message-header-encode-any
198 ;;;                         (y-or-n-p
199 ;;;                          "Some texts are not encoded. Encode anyway?")))
200 ;;;                    (rfc2047-encode-region (point-min) (point-max))
201 ;;;                  (error "Cannot send unencoded text"))))
202              ((mm-coding-system-p method)
203               (if (and (featurep 'mule)
204                        (if (boundp 'default-enable-multibyte-characters)
205                            default-enable-multibyte-characters))
206                   (mm-encode-coding-region (point-min) (point-max) method)))
207              ;; Hm.
208              (t)))
209           (goto-char (point-max)))))))
210
211 ;; Fixme: This, and the require below may not be the Right Thing, but
212 ;; should be safe just before release.  -- fx 2001-02-08
213 (eval-when-compile (defvar message-posting-charset))
214
215 (defun rfc2047-encodable-p ()
216   "Return non-nil if any characters in current buffer need encoding in headers.
217 The buffer may be narrowed."
218   (require 'message)                    ; for message-posting-charset
219   (let ((charsets
220          (mapcar
221           'mm-mime-charset
222           (mm-find-charset-region (point-min) (point-max))))
223         (cs (list 'us-ascii (car message-posting-charset)))
224         found)
225     (while charsets
226       (unless (memq (pop&nbs