Import Oort Gnus v0.16.
[elisp/gnus.git-] / contrib / gnus-idna.el
1 ;;; gnus-idna.el --- Internationalized domain names support for Gnus.
2
3 ;; Copyright (C) 2003 Free Software Foundation, Inc.
4
5 ;; Author: Simon Josefsson
6 ;; Keywords: news, mail
7
8 ;; This file is part of GNU Emacs.
9
10 ;; GNU Emacs is free software; you can redistribute it and/or modify
11 ;; it under the terms of the GNU General Public License as published by
12 ;; the Free Software Foundation; either version 2, or (at your option)
13 ;; any later version.
14
15 ;; GNU Emacs is distributed in the hope that it will be useful,
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 ;; GNU General Public License for more details.
19
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
22 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 ;; Boston, MA 02111-1307, USA.
24
25 ;;; Commentary:
26
27 ;; This package implement crude support for internationalized
28 ;; (non-ASCII) domain names in Gnus.  It is meant as a proof of
29 ;; concept.
30
31 ;; Theory of Operation:
32
33 ;; RFC 2822 RHS's inside the From:, To:, and CC: headers are encoded
34 ;; using IDNA ToASCII() when you send mail using Message.  The hook
35 ;; used is message-send-hook.
36 ;;
37 ;; For incoming articles, when QP in headers are decoded, it searches
38 ;; for "xn--" prefixes and decode them using IDNA ToUnicode().  The
39 ;; hook used is gnus-article-decode-hook.
40
41 ;; Usage:
42
43 ;; Simply put (require 'gnus-idna) in your ~/.gnus or ~/.emacs and it
44 ;; should work.  You need to install GNU Libidn (0.1.11 or later) and
45 ;; make sure the idna.el installed by it is found by emacs.
46
47 ;;; Code:
48
49 (require 'gnus)
50 (require 'rfc822)
51 (require 'idna)
52
53 (eval-and-compile
54   (cond
55    ((fboundp 'replace-in-string)
56     (defalias 'gnus-replace-in-string 'replace-in-string))
57    ((fboundp 'replace-regexp-in-string)
58     (defun gnus-replace-in-string  (string regexp newtext &optional literal)
59       (replace-regexp-in-string regexp newtext string nil literal)))
60    (t
61     (defun gnus-replace-in-string (string regexp newtext &optional literal)
62       (let ((start 0) tail)
63         (while (string-match regexp string start)
64           (setq tail (- (length string) (match-end 0)))
65           (setq string (replace-match newtext nil literal string))
66           (setq start (- (length string) tail))))
67       string))))
68
69 (defun gnus-idna-to-ascii-rhs-1 (header)
70   (save-excursion
71     (save-restriction
72       (let (address header-data new-header-data rhs ace)
73         (message-narrow-to-head)
74         (setq header-data (message-fetch-field header))
75         (when header-data
76           (dolist (element (message-tokenize-header header-data))
77             (setq address (car (rfc822-addresses element)))
78             (when (string-match "\\(.*\\)@\\([^@]+\\)" address)
79               (setq ace (if (setq rhs (match-string 2 address))
80                             (idna-to-ascii rhs)))
81               (push (if (string= rhs ace)
82                         element
83                       (gnus-replace-in-string
84                        element (regexp-quote rhs) ace t))
85                     new-header-data)))
86           (message-remove-header header)
87           (message-position-on-field header)
88           (dolist (addr (reverse new-header-data))
89             (insert addr ", "))
90           (when new-header-data
91             (delete-backward-char 2)))))))
92
93 (defun gnus-idna-to-ascii-rhs ()
94   (gnus-idna-to-ascii-rhs-1 "From")
95   (gnus-idna-to-ascii-rhs-1 "To")
96   (gnus-idna-to-ascii-rhs-1 "Cc"))
97
98 (add-hook 'message-send-hook 'gnus-idna-to-ascii-rhs)
99
100 (defun gnus-idna-to-unicode-rhs ()
101   (let ((inhibit-point-motion-hooks t)
102         buffer-read-only)
103     (goto-char (point-min))
104     (while (re-search-forward "xn--.*[ \t\n\r.,<>()@!]" nil t)
105       ;(or (eobp) (forward-char))
106       (let (ace unicode)
107         (when (setq ace (match-string 0))
108           (setq unicode (idna-to-unicode ace))
109           (unless (string= ace unicode)
110             (replace-match unicode)))))))
111
112 (add-hook 'gnus-article-decode-hook 'gnus-idna-to-unicode-rhs 'append)
113
114 (provide 'gnus-idna)
115
116 ;; gnus-idna.el ends here