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 (if (catch 'mime-edit-error
169 (mime-edit-pgp-enclose-buffer)
170 (mime-edit-translate-body)
172 (error "Translation error!")
175 (run-hooks 'mime-edit-exit-hook)
181 (defun message-locale-detect ()
182 (when (or message-locale-detect-for-news
183 message-locale-detect-for-mail)
186 (message-narrow-to-head)
188 (when message-locale-detect-for-news
191 (funcall message-locale-detect-for-news
192 (and (string-match "[^ \t]+" newsgroup)
193 (match-string 0 newsgroup))))
194 (message-tokenize-header
195 (message-fetch-field "newsgroups")))))
196 (when message-locale-detect-for-mail
197 (let ((field-list '("to" "cc" "bcc")))
198 (while (car field-list)
203 (funcall message-locale-detect-for-mail
205 (cdr (std11-extract-address-components
207 (message-tokenize-header
208 (message-fetch-field (pop field-list)))))))))
209 (setq lc (delq nil lc))
211 (setq dest (cons (car lc) dest)
212 lc (delq (car lc) lc)))
214 (and message-locale-default (list message-locale-default)))
217 (defun message-locale-detect-with-newsgroup-alist (newsgroup)
218 (let ((rest message-locale-newsgroup-alist)
220 (while (and (not done)
222 (when (string-match (car (car rest)) newsgroup)
223 (setq done (car rest)))
224 (setq rest (cdr rest)))
228 (defun message-locale-detect-with-mail-address-alist (address)
229 (let ((rest message-locale-mail-address-alist)
231 (while (and (not done)
233 (when (string-match (car (car rest)) address)
234 (setq done (car rest)))
235 (setq rest (cdr rest)))
240 ;;; Control MIME charset with recipient's locale.
242 (defun message-locale-setup-mime-charset (locale-list)
243 (message-locale-args-original-set charsets-mime-charset-alist)
244 (message-locale-args-original-set
245 default-mime-charset-detect-method-for-write)
246 (setq default-mime-charset-detect-method-for-write
247 (or message-mime-charset-recover-function
248 default-mime-charset-detect-method-for-write)
249 message-save-encoder 'message-locale-mime-save-encoder)
251 (while (and charsets-mime-charset-alist
253 (unless (setq locale-cs
254 (assq (car locale-list)
255 message-locale-mime-charsets-alist))
256 (error "Unknown locale \`%s\'. Add locale to \`%s\'."
258 'message-locale-mime-charsets-alist))
259 (setq locale-cs (cdr locale-cs)
260 charsets-mime-charset-alist (delq nil
263 (and (memq (cdr cs) locale-cs)
265 charsets-mime-charset-alist))
266 locale-list (cdr locale-list))
270 ;;; Recover MIME charset.
272 (defun message-mime-charset-recover-by-ask (type charsets &rest args)
273 (let ((default-charset
274 (let ((charsets-mime-charset-alist
275 (message-locale-args-original charsets-mime-charset-alist)))
276 (charsets-to-mime-charset charsets)))
280 (save-window-excursion
281 (when (eq type 'region)
282 (narrow-to-region (car args) (car (cdr args)))
283 (message-mime-highlight-illegal-chars charsets)
284 (pop-to-buffer (current-buffer) nil t)
287 (funcall message-mime-charset-recover-ask-function
290 default-mime-charset-for-write)))
292 (intern (downcase charset))
293 (error "Canceled.")))))))
295 (defun message-mime-charset-recover-ask-y-or-n (default-charset charsets)
296 (or (y-or-n-p (format "MIME charset %s is selected. OK? "
301 (defun message-mime-charset-recover-ask-charset (default-charset charsets)
304 (list (upcase (symbol-name cs))))
305 (mime-charset-list)))
309 (completing-read "What MIME charset: "
310 alist nil t default-charset))
311 (when (string= charset "")
315 (defun message-mime-highlight-illegal-chars (charsets)
316 (when charsets-mime-charset-alist
322 (when (<= (length x) min)
329 (unless (memq y (car x))
333 (when (<= (length x) min)
334 (setq min (length x))
336 charsets-mime-charset-alist)))))
337 top cs done rest errors warns list)
338 (while (setq top (pop delta-lists))
339 (while (setq cs (pop top))
343 (while (setq rest (pop list))
344 (if (setq rest (memq cs rest))
350 (put-text-property (point-min) (point-max) 'face nil)
351 (if (setq top (message-set-charsets-face
353 'message-illegal-charsets-face))
354 (message-set-charsets-face warns 'message-warning-charsets-face)
355 (setq top (message-set-charsets-face
356 warns 'message-warning-charsets-face)))
359 (goto-char (point-min))))))
361 ;;; @ for MIME Edit mode
363 (defun message-locale-mime-save-encoder (orig-buf)
364 (when (with-current-buffer orig-buf mime-edit-mode-flag)
365 (let ((charsets-mime-charset-alist
366 (message-locale-args-original charsets-mime-charset-alist))
367 (default-mime-charset-detect-method-for-write
368 (message-locale-args-original
369 default-mime-charset-detect-method-for-write)))
370 (mime-edit-translate-body)
371 (mime-edit-translate-header)
374 (run-hooks 'mess-lcl-load-hook)
378 ;;; mess-lcl.el ends here