1 ;;; mess-lcl.el --- Control message format with recipient's locale
2 ;; Copyright (C) 1996,97,98 Free Software Foundation, Inc.
4 ;; Author: Keiichi Suzuki <keiichi@nanap.org>
5 ;; Keywords: mail, news, MIME
7 ;; This file is part of GNU Emacs.
9 ;; GNU Emacs is free software; you can redistribute it and/or modify
10 ;; it under the terms of the GNU General Public License as published by
11 ;; the Free Software Foundation; either version 2, or (at your option)
14 ;; GNU Emacs is distributed in the hope that it will be useful,
15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 ;; GNU General Public License for more details.
19 ;; You should have received a copy of the GNU General Public License
20 ;; along with GNU Emacs; see the file COPYING. If not, write to the
21 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 ;; Boston, MA 02111-1307, USA.
26 ;; This module controls message format with recipient's locale.
36 (defgroup message-locale '((message-encode-function custom-variable))
37 "Control message format with recipient."
38 :link '(custom-manual "(message)Top")
41 (defcustom message-locale-default nil
42 "Default locale for sending message."
43 :group 'message-locale
46 (defcustom message-locale-detect-for-mail nil
47 "*A function called to detect locale from recipient mail address."
48 :group 'message-locale
51 (defcustom message-locale-detect-for-news
52 'message-locale-detect-with-newsgroup-alist
53 "*A function called to detect locale from newsgroup."
54 :group 'message-locale
57 (defcustom message-mime-charset-recover-function
58 'message-mime-charset-recover-by-ask
59 "A function called to recover \
60 when could not found legal MIME charset for sending message."
61 :type '(radio (function-item message-mime-charset-recover-by-ask)
62 (function :tag "Other"))
63 :group 'message-locale)
65 (defvar message-locale-newsgroup-alist
69 (defvar message-locale-mail-address-alist nil)
71 (defcustom message-mime-charset-recover-ask-function
72 'message-mime-charset-recover-ask-y-or-n
73 "A function called to ask MIME charset.
74 This funtion will by called from \`message-mime-charset-recover-by-ask\'."
75 :type '(radio (function-item message-mime-charset-recover-ask-y-or-n)
76 (function-item message-mime-charset-recover-ask-charset)
77 (function :tag "Other"))
78 :group 'message-locale)
80 (defvar message-locale-mime-charsets-alist
81 '((fj . (us-ascii iso-2022-jp iso-2022-jp-2))
85 (defface message-illegal-charsets-face
87 (:foreground "black" :background "red"))
89 (:bold t :underline t)))
90 "Face used for displaying illegal charset."
91 :group 'message-faces)
93 (defface message-warning-charsets-face
95 (:foreground "black" :background "yellow"))
97 (:bold t :underline t)))
98 "Face used for displaying illegal charset."
99 :group 'message-faces)
102 ;;; Internal variable.
103 (defvar message-locale-args nil)
107 ;;; Utility functions.
109 (defun message-set-charsets-face (charsets face &optional start end)
110 (or start (setq start (point-min)))
111 (or end (setq end (point-max)))
115 (while (< (point) end)
116 (if (memq (charset-after) charsets)
117 (let ((start (point)))
121 (while (and (< (point) end)
122 (memq (charset-after) charsets))
124 (put-text-property start (point) 'face face))
128 (defmacro message-locale-args (symbol)
129 `(cdr (assq (quote ,symbol) message-locale-args))
132 (defmacro message-locale-args-set (symbol val)
133 `(setq message-locale-args
134 (put-alist (quote ,symbol) ,val message-locale-args))
137 (defmacro message-locale-args-original (symbol)
138 `(or (message-locale-args ,symbol) ,symbol)
141 (defmacro message-locale-args-original-set (symbol)
142 `(message-locale-args-set ,symbol ,symbol)
146 ;;; Call from message.el
148 (defun message-locale-maybe-encode ()
149 "Control MIME encoding for message sending.
151 If would you like to control MIME encoding with recipient's locale,
152 then set this function to `message-encode-function'."
153 (when message-mime-mode
154 ;; Inherit the buffer local variable `mime-edit-pgp-processing'.
155 (let ((pgp-processing (with-current-buffer message-edit-buffer
156 mime-edit-pgp-processing)))
157 (setq mime-edit-pgp-processing pgp-processing))
158 (run-hooks 'mime-edit-translate-hook))
159 (let ((locale-list (message-locale-detect)))
160 (when message-mime-mode
161 (let ((message-save-encoder message-save-encoder)
162 (default-mime-charset-detect-method-for-write
163 default-mime-charset-detect-method-for-write)
164 (charsets-mime-charset-alist charsets-mime-charset-alist)
166 (message-locale-setup-mime-charset locale-list)
167 (when (catch 'mime-edit-error
169 (mime-edit-pgp-enclose-buffer)
170 (mime-edit-translate-body)))
171 (error "Translation error!")))
173 (run-hooks 'mime-edit-exit-hook))))
178 (defun message-locale-detect ()
179 (when (or message-locale-detect-for-news
180 message-locale-detect-for-mail)
183 (message-narrow-to-head)
185 (when message-locale-detect-for-news
188 (funcall message-locale-detect-for-news
189 (and (string-match "[^ \t]+" newsgroup)
190 (match-string 0 newsgroup))))
191 (message-tokenize-header
192 (message-fetch-field "newsgroups")))))
193 (when message-locale-detect-for-mail
194 (let ((field-list '("to" "cc" "bcc")))
195 (while (car field-list)
200 (funcall message-locale-detect-for-mail
202 (cdr (std11-extract-address-components
204 (message-tokenize-header
205 (message-fetch-field (pop field-list)))))))))
206 (setq lc (delq nil lc))
208 (setq dest (cons (car lc) dest)
209 lc (delq (car lc) lc)))
211 (and message-locale-default (list message-locale-default)))
214 (defun message-locale-detect-with-newsgroup-alist (newsgroup)
215 (let ((rest message-locale-newsgroup-alist)
217 (while (and (not done)
219 (when (string-match (car (car rest)) newsgroup)
220 (setq done (car rest)))
221 (setq rest (cdr rest)))
225 (defun message-locale-detect-with-mail-address-alist (address)
226 (let ((rest message-locale-mail-address-alist)
228 (while (and (not done)
230 (when (string-match (car (car rest)) address)
231 (setq done (car rest)))
232 (setq rest (cdr rest)))
237 ;;; Control MIME charset with recipient's locale.
239 (defun message-locale-setup-mime-charset (locale-list)
240 (message-locale-args-original-set charsets-mime-charset-alist)
241 (message-locale-args-original-set
242 default-mime-charset-detect-method-for-write)
243 (setq default-mime-charset-detect-method-for-write
244 (or message-mime-charset-recover-function
245 default-mime-charset-detect-method-for-write)
246 message-save-encoder 'message-locale-mime-save-encoder)
248 (while (and charsets-mime-charset-alist
250 (unless (setq locale-cs
251 (assq (car locale-list)
252 message-locale-mime-charsets-alist))
253 (error "Unknown locale \`%s\'. Add locale to \`%s\'."
255 'message-locale-mime-charsets-alist))
256 (setq locale-cs (cdr locale-cs)
257 charsets-mime-charset-alist (delq nil
260 (and (memq (cdr cs) locale-cs)
262 charsets-mime-charset-alist))
263 locale-list (cdr locale-list))
267 ;;; Recover MIME charset.
269 (defun message-mime-charset-recover-by-ask (type charsets &rest args)
270 (let ((default-charset
271 (let ((charsets-mime-charset-alist
272 (message-locale-args-original charsets-mime-charset-alist)))
273 (charsets-to-mime-charset charsets)))
277 (save-window-excursion
278 (when (eq type 'region)
279 (narrow-to-region (car args) (car (cdr args)))
280 (message-mime-highlight-illegal-chars charsets)
281 (pop-to-buffer (current-buffer) nil t)
284 (funcall message-mime-charset-recover-ask-function
287 default-mime-charset-for-write)))
289 (intern (downcase charset))
290 (throw 'message-sending-cancel t)))))))
292 (defun message-mime-charset-recover-ask-y-or-n (default-charset charsets)
293 (and (y-or-n-p (format "MIME charset %s is selected. OK? "
297 (defun message-mime-charset-recover-ask-charset (default-charset charsets)
300 (list (upcase (symbol-name cs))))
301 (mime-charset-list)))
305 (completing-read "What MIME charset: "
306 alist nil t default-charset))
307 (when (string= charset "")
311 (defun message-mime-highlight-illegal-chars (charsets)
312 (when charsets-mime-charset-alist
318 (when (<= (length x) min)
325 (unless (memq y (car x))
329 (when (<= (length x) min)
330 (setq min (length x))
332 charsets-mime-charset-alist)))))
333 top cs done rest errors warns list)
334 (while (setq top (pop delta-lists))
335 (while (setq cs (pop top))
339 (while (setq rest (pop list))
340 (if (setq rest (memq cs rest))
346 (put-text-property (point-min) (point-max) 'face nil)
347 (if (setq top (message-set-charsets-face
349 'message-illegal-charsets-face))
350 (message-set-charsets-face warns 'message-warning-charsets-face)
351 (setq top (message-set-charsets-face
352 warns 'message-warning-charsets-face)))
355 (goto-char (point-min))))))
357 ;;; @ for MIME Edit mode
359 (defun message-locale-mime-save-encoder (orig-buf)
360 (when (with-current-buffer orig-buf mime-edit-mode-flag)
361 (let ((charsets-mime-charset-alist
362 (message-locale-args-original charsets-mime-charset-alist))
363 (default-mime-charset-detect-method-for-write
364 (message-locale-args-original
365 default-mime-charset-detect-method-for-write)))
366 (mime-edit-translate-body)
367 (mime-edit-translate-header)
370 (run-hooks 'mess-lcl-load-hook)
374 ;;; mess-lcl.el ends here