*** empty log message ***
[gnus] / lisp / ietf-drums.el
1 ;;; ietf-drums.el --- Functions for parsing RFC822bis headers
2 ;; Copyright (C) 1998 Free Software Foundation, Inc.
3
4 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
5 ;; This file is part of GNU Emacs.
6
7 ;; GNU Emacs is free software; you can redistribute it and/or modify
8 ;; it under the terms of the GNU General Public License as published by
9 ;; the Free Software Foundation; either version 2, or (at your option)
10 ;; any later version.
11
12 ;; GNU Emacs is distributed in the hope that it will be useful,
13 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 ;; GNU General Public License for more details.
16
17 ;; You should have received a copy of the GNU General Public License
18 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
19 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 ;; Boston, MA 02111-1307, USA.
21
22 ;;; Commentary:
23
24 ;; DRUMS is an IETF Working Group that works (or worked) on the
25 ;; successor to RFC822, "Standard For The Format Of Arpa Internet Text
26 ;; Messages".  This library is based on
27 ;; draft-ietf-drums-msg-fmt-05.txt, released on 1998-08-05.
28
29 ;;; Code:
30
31 (require 'time-date)
32 (require 'mm-util)
33
34 (defvar ietf-drums-no-ws-ctl-token "\001-\010\013\014\016-\037\177"
35   "US-ASCII control characters excluding CR, LF and white space.")
36 (defvar ietf-drums-text-token "\001-\011\013\014\016-\177"
37   "US-ASCII characters exlcuding CR and LF.")
38 (defvar ietf-drums-specials-token "()<>[]:;@\\,.\""
39   "Special characters.")
40 (defvar ietf-drums-quote-token "\\"
41   "Quote character.")
42 (defvar ietf-drums-wsp-token " \t"
43   "White space.")
44 (defvar ietf-drums-fws-regexp
45   (concat "[" ietf-drums-wsp-token "]*\n[" ietf-drums-wsp-token "]+")
46   "Folding white space.")
47 (defvar ietf-drums-atext-token "-^a-zA-Z0-9!#$%&'*+/=?_`{|}~"
48   "Textual token.")
49 (defvar ietf-drums-dot-atext-token "-^a-zA-Z0-9!#$%&'*+/=?_`{|}~."
50   "Textual token including full stop.")
51 (defvar ietf-drums-qtext-token
52   (concat ietf-drums-no-ws-ctl-token "\041\043-\133\135-\177")
53   "Non-white-space control characaters, plus the rest of ASCII excluding backslash and doublequote.")
54 (defvar ietf-drums-tspecials "][()<>@,;:\\\"/?="
55   "Tspecials.")
56
57 (defvar ietf-drums-syntax-table
58   (let ((table (copy-syntax-table emacs-lisp-mode-syntax-table)))
59     (modify-syntax-entry ?\\ "/" table)
60     (modify-syntax-entry ?< "(" table)
61     (modify-syntax-entry ?> ")" table)
62     (modify-syntax-entry ?@ "w" table)
63     (modify-syntax-entry ?/ "w" table)
64     (modify-syntax-entry ?= " " table)
65     (modify-syntax-entry ?* " " table)
66     (modify-syntax-entry ?\; " " table)
67     (modify-syntax-entry ?\' " " table)
68     table))
69
70 (defun ietf-drums-token-to-list (token)
71   "Translate TOKEN into a list of characters."
72   (let ((i 0)
73         b e c out range)
74     (while (< i (length token))
75       (setq c (mm-char-int (aref token i)))
76       (incf i)
77       (cond
78        ((eq c (mm-char-int ?-))
79         (if b
80             (setq range t)
81           (push c out)))
82        (range
83         (while (<= b c)
84           (push (mm-make-char 'ascii b) out)
85           (incf b))
86         (setq range nil))
87        ((= i (length token))
88         (push (mm-make-char 'ascii c) out))
89        (t
90         (setq b c))))
91     (nreverse out)))
92
93 (defsubst ietf-drums-init (string)
94   (set-syntax-table ietf-drums-syntax-table)
95   (insert string)
96   (ietf-drums-unfold-fws)
97   (goto-char (point-min)))
98
99 (defun ietf-drums-remove-comments (string)
100   "Remove comments from STRING."
101   (with-temp-buffer
102     (let (c)
103       (ietf-drums-init string)
104       (while (not (eobp))
105         (setq c (following-char))
106         (cond
107          ((eq c ?\")
108           (forward-sexp 1))
109          ((eq c ?\()
110           (delete-region (point) (progn (forward-sexp 1) (point))))
111          (t
112           (forward-char 1))))
113       (buffer-string))))
114
115 (defun ietf-drums-remove-whitespace (string)
116   "Remove comments from STRING."
117   (with-temp-buffer
118     (ietf-drums-init string)
119     (let (c)
120       (while (not (eobp))
121         (setq c (following-char))
122         (cond
123          ((eq c ?\")
124           (forward-sexp 1))
125          ((eq c ?\()
126           (forward-sexp 1))
127          ((memq c '(? ?\t ?\n))
128           (delete-char 1))
129          (t
130           (forward-char 1))))
131       (buffer-string))))
132
133 (defun ietf-drums-get-comment (string)
134   "Return the first comment in STRING."
135   (with-temp-buffer
136     (ietf-drums-init string)
137     (let (result c)
138       (while (not (eobp))
139         (setq c (following-char))
140         (cond
141          ((eq c ?\")
142           (forward-sexp 1))
143          ((eq c ?\()
144           (setq result
145                 (buffer-substring
146                  (1+ (point))
147                  (progn (forward-sexp 1) (1- (point))))))
148          (t
149           (forward-char 1))))
150       result)))
151
152 (defun ietf-drums-parse-address (string)
153   "Parse STRING and return a MAILBOX / DISPLAY-NAME pair."
154   (with-temp-buffer
155     (let (display-name mailbox c display-string)
156       (ietf-drums-init string)
157       (while (not (eobp))
158         (setq c (following-char))
159         (cond
160          ((or (eq c ? )
161               (eq c ?\t))
162           (forward-char 1))
163          ((eq c ?\()
164           (forward-sexp 1))
165          ((eq c ?\")
166           (push (buffer-substring
167                  (1+ (point)) (progn (forward-sexp 1) (1- (point))))
168                 display-name))
169          ((looking-at (concat "[" ietf-drums-atext-token "@" "]"))
170           (push (buffer-substring (point) (progn (forward-sexp 1) (point)))
171                 display-name))
172          ((eq c ?<)
173           (setq mailbox
174                 (ietf-drums-remove-whitespace
175                  (ietf-drums-remove-comments
176                   (buffer-substring
177                    (1+ (point))
178                    (progn (forward-sexp 1) (1- (point))))))))
179          (t (error "Unknown symbol: %c" c))))
180       ;; If we found no display-name, then we look for comments.
181       (if display-name
182           (setq display-string
183                 (mapconcat 'identity (reverse display-name) " "))
184         (setq display-string (ietf-drums-get-comment string)))
185       (if (not mailbox)
186           (when (string-match "@" display-string)
187             (cons
188              (mapconcat 'identity (nreverse display-name) "")
189              (ietf-drums-get-comment string)))
190         (cons mailbox display-string)))))
191
192 (defun ietf-drums-parse-addresses (string)
193   "Parse STRING and return a list of MAILBOX / DISPLAY-NAME pairs."
194   (with-temp-buffer
195     (ietf-drums-init string)
196     (let ((beg (point))
197           pairs c)
198       (while (not (eobp))
199         (setq c (following-char))
200         (cond
201          ((memq c '(?\" ?< ?\())
202           (forward-sexp 1))
203          ((eq c ?,)
204           (push (ietf-drums-parse-address (buffer-substring beg (point)))
205                 pairs)
206           (forward-char 1)
207           (setq beg (point)))
208          (t
209           (forward-char 1))))
210       (push (ietf-drums-parse-address (buffer-substring beg (point)))
211             pairs)
212       (nreverse pairs))))
213
214 (defun ietf-drums-unfold-fws ()
215   "Unfold folding white space in the current buffer."
216   (goto-char (point-min))
217   (while (re-search-forward ietf-drums-fws-regexp nil t)
218     (replace-match " " t t))
219   (goto-char (point-min)))
220
221 (defun ietf-drums-parse-date (string)
222   "Return an Emacs time spec from STRING."
223   (apply 'encode-time (parse-time-string string)))
224
225 (defun ietf-drums-narrow-to-header ()
226   "Narrow to the header section in the current buffer."
227   (narrow-to-region
228    (goto-char (point-min))
229    (if (search-forward "\n\n" nil 1)
230        (1- (point))
231      (point-max)))
232   (goto-char (point-min)))
233
234 (defun ietf-drums-quote-string (string)
235   "Quote string if it needs quoting to be displayed in a header."
236   (if (string-match (concat "[^" ietf-drums-atext-token "]") string)
237       (concat "\"" string "\"")
238     string))
239
240 (provide 'ietf-drums)
241
242 ;;; ietf-drums.el ends here