0344956093031ce4b43875fe9cca498218f73dca
[elisp/gnus.git-] / lisp / drums.el
1 ;;; 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
33 (defvar drums-no-ws-ctl-token "\001-\010\013\014\016-\037\177"
34   "US-ASCII control characters excluding CR, LF and white space.")
35 (defvar drums-text-token "\001-\011\013\014\016-\177"
36   "US-ASCII characters exlcuding CR and LF.")
37 (defvar drums-specials-token "()<>[]:;@\\,.\""
38   "Special characters.")
39 (defvar drums-quote-token "\\"
40   "Quote character.")
41 (defvar drums-wsp-token " \t"
42   "White space.")
43 (defvar drums-fws-regexp
44   (concat "[" drums-wsp-token "]*\n[" drums-wsp-token "]+")
45   "Folding white space.")
46 (defvar drums-atext-token "-^a-zA-Z0-9!#$%&'*+/=?_`{|}~"
47   "Textual token.")
48 (defvar drums-dot-atext-token "-^a-zA-Z0-9!#$%&'*+/=?_`{|}~."
49   "Textual token including full stop.")
50 (defvar drums-qtext-token
51   (concat drums-no-ws-ctl-token "\041\043-\133\135-\177")
52   "Non-white-space control characaters, plus the rest of ASCII excluding backslash and doublequote.")
53   
54 (defvar drums-syntax-table
55   (let ((table (copy-syntax-table emacs-lisp-mode-syntax-table)))
56     (modify-syntax-entry ?\\ "/" table)
57     (modify-syntax-entry ?< "(" table)
58     (modify-syntax-entry ?> ")" table)
59     (modify-syntax-entry ?( "(" table)
60     (modify-syntax-entry ?) ")" table)
61     table))
62
63 (defsubst drums-init (string)
64   (set-syntax-table drums-syntax-table)
65   (insert string)
66   (drums-unfold-fws)
67   (goto-char (point-min)))
68
69 (defun drums-remove-comments (string)
70   "Remove comments from STRING."
71   (with-temp-buffer
72     (let (c)
73       (drums-init string)
74       (while (not (eobp))
75         (setq c (following-char))
76         (cond
77          ((eq c ?\")
78           (forward-sexp 1))
79          ((eq c ?\()
80           (delete-region (point) (progn (forward-sexp 1) (point))))
81          (t
82           (forward-char 1))))
83       (buffer-string))))
84
85 (defun drums-remove-whitespace (string)
86   "Remove comments from STRING."
87   (with-temp-buffer
88     (drums-init string)
89     (let (c)
90       (while (not (eobp))
91         (setq c (following-char))
92         (cond
93          ((eq c ?\")
94           (forward-sexp 1))
95          ((memq c '(? ?\t))
96           (delete-char 1))
97          (t
98           (forward-char 1))))
99       (buffer-string))))
100
101 (defun drums-get-comment (string)
102   "Return the first comment in STRING."
103   (with-temp-buffer
104     (drums-init string)
105     (let (result c)
106       (while (not (eobp))
107         (setq c (following-char))
108         (cond
109          ((eq c ?\")
110           (forward-sexp 1))
111          ((eq c ?\()
112           (setq result
113                 (buffer-substring
114                  (1+ (point))
115                  (progn (forward-sexp 1) (1- (point))))))
116          (t
117           (forward-char 1))))
118       result)))
119
120 (defun drums-parse-address (string)
121   "Parse STRING and return a MAILBOX / DISPLAY-NAME pair."
122   (with-temp-buffer
123     (let (display-name mailbox c display-string)
124       (drums-init string)
125       (while (not (eobp))
126         (setq c (following-char))
127         (cond
128          ((or (eq c ? )
129               (eq c ?\t))
130           (forward-char 1))
131          ((eq c ?\()
132           (forward-sexp 1))
133          ((eq c ?\")
134           (push (buffer-substring
135                  (1+ (point)) (progn (forward-sexp 1) (1- (point))))
136                 display-name))
137          ((looking-at (concat "[" drums-atext-token "@" "]"))
138           (push (buffer-substring (point) (progn (forward-sexp 1) (point)))
139                 display-name))
140          ((eq c ?<)
141           (setq mailbox
142                 (drums-remove-whitespace
143                  (drums-remove-comments
144                   (buffer-substring
145                    (1+ (point))
146                    (progn (forward-sexp 1) (1- (point))))))))
147          (t (error "Unknown symbol: %c" c))))
148       ;; If we found no display-name, then we look for comments.
149       (if display-name
150           (setq display-string
151                 (mapconcat 'identity (reverse display-name) " "))
152         (setq display-string (drums-get-comment string)))
153       (if (not mailbox)
154           (when (string-match "@" display-string)
155             (cons
156              (mapconcat 'identity (nreverse display-name) "")
157              (drums-get-comment string)))
158         (cons mailbox display-name)))))
159
160 (defun drums-parse-addresses (string)
161   "Parse STRING and return a list of MAILBOX / DISPLAY-NAME pairs."
162   (with-temp-buffer
163     (drums-init string)
164     (let ((beg (point))
165           pairs c)
166       (while (not (eobp))
167         (setq c (following-char))
168         (cond
169          ((memq c '(?\" ?< ?\())
170           (forward-sexp 1))
171          ((eq c ?,)
172           (push (drums-parse-address (buffer-substring beg (1- (point))))
173                 pairs)
174           (setq beg (point)))
175          (t
176           (forward-char 1))))
177       (nreverse pairs))))
178
179 (defun drums-unfold-fws ()
180   "Unfold folding white space in the current buffer."
181   (goto-char (point-min))
182   (while (re-search-forward drums-fws-regexp nil t)
183     (replace-match " " t t))
184   (goto-char (point-min)))
185
186 (defun drums-parse-date (string)
187   "Return an Emacs time spec from STRING."
188   (apply 'encode-time (parse-time-string string)))
189     
190 (provide 'drums)
191
192 ;;; drums.el ends here