|
|
1.1 root 1: ;; Utility functions used both by rmail and rnews
2: ;; Copyright (C) 1985 Free Software Foundation, Inc.
3:
4: ;; This file is part of GNU Emacs.
5:
6: ;; GNU Emacs is free software; you can redistribute it and/or modify
7: ;; it under the terms of the GNU General Public License as published by
8: ;; the Free Software Foundation; either version 1, or (at your option)
9: ;; any later version.
10:
11: ;; GNU Emacs is distributed in the hope that it will be useful,
12: ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
13: ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14: ;; GNU General Public License for more details.
15:
16: ;; You should have received a copy of the GNU General Public License
17: ;; along with GNU Emacs; see the file COPYING. If not, write to
18: ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
19:
20:
21: (provide 'mail-utils)
22:
23: ;; should be in loaddefs
24: (defvar mail-use-rfc822 nil
25: "*If non-nil, use a full, hairy RFC822 parser on mail addresses.
26: Otherwise, (the default) use a smaller, somewhat faster and
27: often-correct parser.")
28:
29: (defun mail-string-delete (string start end)
30: "Returns a string containing all of STRING except the part
31: from START (inclusive) to END (exclusive)."
32: (if (null end) (substring string 0 start)
33: (concat (substring string 0 start)
34: (substring string end nil))))
35:
36: (defun mail-strip-quoted-names (address)
37: "Delete comments and quoted strings in an address list ADDRESS.
38: Also delete leading/trailing whitespace and replace FOO <BAR> with just BAR.
39: Return a modified address list."
40: (if (null address)
41: nil
42: (if mail-use-rfc822
43: (progn (require 'rfc822)
44: (mapconcat 'identity (rfc822-addresses address) ", "))
45: (let (pos)
46: ;; Strip rfc822 comments (within parens).
47: ;; Understand properly the effect of backslashes and string quotes.
48: (let (instring (depth 0) start)
49: (setq pos -1)
50: (while pos
51: (cond ((< pos 0))
52: ((= (aref address pos) ?\\)
53: (setq pos (1+ pos)))
54: ((= (aref address pos) ?\")
55: (setq instring (not instring)))
56: (instring nil)
57: ((= (aref address pos) ?\()
58: (if (= depth 0) (setq start pos))
59: (setq depth (1+ depth)))
60: ((= (aref address pos) ?\))
61: (setq depth (1- depth))
62: (if (= depth 0)
63: (setq address (mail-string-delete address start (1+ pos))
64: pos (1- start)))))
65: (setq pos (string-match "[\"\\()]" address (1+ pos)))))
66:
67: ;; strip surrounding whitespace
68: (string-match "\\`[ \t\n]*" address)
69: (setq address (substring address
70: (match-end 0)
71: (string-match "[ \t\n]*\\'" address
72: (match-end 0))))
73:
74: ;; Strip whitespace before commas.
75: (let (instring)
76: (setq pos -1)
77: (while pos
78: (cond ((< pos 0))
79: ((= (aref address pos) ?\\)
80: (setq pos (1+ pos)))
81: ((= (aref address pos) ?\")
82: (setq instring (not instring)))
83: (instring nil)
84: ((eq (string-match "[ \t]*," address pos) pos)
85: (setq address (mail-string-delete address pos
86: (1- (match-end 0))))))
87: (setq pos (string-match "[ \t,\"\\]" address (1+ pos)))))
88:
89: ;; strip `quoted' names (This is supposed to hack `"Foo Bar" <bar@host>')
90: (setq pos 0)
91: (while (setq pos (string-match
92: "[ \t]*\"\\([^\"\\]\\|\\\\.\\|\\\\\n\\)*\"[ \t\n]*"
93: address pos))
94: ;; If the next thing is "@", we have "foo bar"@host. Leave it.
95: (if (and (> (length address) (match-end 0))
96: (= (aref address (match-end 0)) ?@))
97: (setq pos (match-end 0))
98: (setq address
99: (mail-string-delete address
100: pos (match-end 0)))))
101: ;; Retain only part of address in <> delims, if there is such a thing.
102: (while (setq pos (string-match "\\(,\\|\\`\\)[^,]*<\\([^>,]*>\\)"
103: address))
104: (let ((junk-beg (match-end 1))
105: (junk-end (match-beginning 2))
106: (close (match-end 0)))
107: (setq address (mail-string-delete address (1- close) close))
108: (setq address (mail-string-delete address junk-beg junk-end))))
109: address))))
110:
111: (or (and (boundp 'rmail-default-dont-reply-to-names)
112: (not (null rmail-default-dont-reply-to-names)))
113: (setq rmail-default-dont-reply-to-names "info-"))
114:
115: ; rmail-dont-reply-to-names is defined in loaddefs
116: (defun rmail-dont-reply-to (userids)
117: "Returns string of mail addresses USERIDS sans any recipients
118: that start with matches for rmail-dont-reply-to-names.
119: Usenet paths ending in an element that matches are removed also."
120: (if (null rmail-dont-reply-to-names)
121: (setq rmail-dont-reply-to-names
122: (concat (if rmail-default-dont-reply-to-names
123: (concat rmail-default-dont-reply-to-names "\\|")
124: "")
125: (concat (regexp-quote
126: (or (getenv "USER") (getenv "LOGNAME")
127: (user-login-name)))
128: "\\>"))))
129: (let ((match (concat "\\(^\\|,\\)[ \t\n]*\\([^,\n]*!\\|\\)\\("
130: rmail-dont-reply-to-names
131: "\\)"))
132: (case-fold-search t)
133: pos epos)
134: (while (setq pos (string-match match userids))
135: (if (> pos 0) (setq pos (1+ pos)))
136: (setq epos
137: (if (string-match "[ \t\n,]+" userids (match-end 0))
138: (match-end 0)
139: (length userids)))
140: (setq userids
141: (mail-string-delete
142: userids pos epos)))
143: ;; get rid of any trailing commas
144: (if (setq pos (string-match "[ ,\t\n]*\\'" userids))
145: (setq userids (substring userids 0 pos)))
146: ;; remove leading spaces. they bother me.
147: (if (string-match "\\s *" userids)
148: (substring userids (match-end 0))
149: userids)))
150:
151: (defun mail-fetch-field (field-name &optional last all)
152: "Return the value of the header field FIELD.
153: The buffer is expected to be narrowed to just the headers of the message.
154: If 2nd arg LAST is non-nil, use the last such field if there are several.
155: If 3rd arg ALL is non-nil, concatenate all such fields, with commas between."
156: (save-excursion
157: (goto-char (point-min))
158: (let ((case-fold-search t)
159: (name (concat "^" (regexp-quote field-name) "[ \t]*:[ \t]*")))
160: (goto-char (point-min))
161: (if all
162: (let ((value ""))
163: (while (re-search-forward name nil t)
164: (let ((opoint (point)))
165: (while (progn (forward-line 1)
166: (looking-at "[ \t]")))
167: (setq value (concat value
168: (if (string= value "") "" ", ")
169: (buffer-substring opoint (1- (point)))))))
170: (and (not (string= value "")) value))
171: (if (re-search-forward name nil t)
172: (progn
173: (if last (while (re-search-forward name nil t)))
174: (let ((opoint (point)))
175: (while (progn (forward-line 1)
176: (looking-at "[ \t]")))
177: (buffer-substring opoint (1- (point))))))))))
178:
179: ;; Parse a list of tokens separated by commas.
180: ;; It runs from point to the end of the visible part of the buffer.
181: ;; Whitespace before or after tokens is ignored,
182: ;; but whitespace within tokens is kept.
183: (defun mail-parse-comma-list ()
184: (let (accumulated
185: beg)
186: (skip-chars-forward " ")
187: (while (not (eobp))
188: (setq beg (point))
189: (skip-chars-forward "^,")
190: (skip-chars-backward " ")
191: (setq accumulated
192: (cons (buffer-substring beg (point))
193: accumulated))
194: (skip-chars-forward "^,")
195: (skip-chars-forward ", "))
196: accumulated))
197:
198: (defun mail-comma-list-regexp (labels)
199: (let (pos)
200: (setq pos (or (string-match "[^ \t]" labels) 0))
201: ;; Remove leading and trailing whitespace.
202: (setq labels (substring labels pos (string-match "[ \t]*$" labels pos)))
203: ;; Change each comma to \|, and flush surrounding whitespace.
204: (while (setq pos (string-match "[ \t]*,[ \t]*" labels))
205: (setq labels
206: (concat (substring labels 0 pos)
207: "\\|"
208: (substring labels (match-end 0))))))
209: labels)
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.