comparison lisp/gnus/message.el @ 70:131b0175ea99 r20-0b30

Import from CVS: tag r20-0b30
author cvs
date Mon, 13 Aug 2007 09:02:59 +0200
parents 8b8b7f3559a2
children 0d2f883870bc
comparison
equal deleted inserted replaced
69:804d1389bcd6 70:131b0175ea99
1 ;;; message.el --- composing mail and news messages 1 ;;; message.el --- composing mail and news messages
2 ;; Copyright (C) 1996,97 Free Software Foundation, Inc. 2 ;; Copyright (C) 1996 Free Software Foundation, Inc.
3 3
4 ;; Author: Lars Magne Ingebrigtsen <larsi@ifi.uio.no> 4 ;; Author: Lars Magne Ingebrigtsen <larsi@ifi.uio.no>
5 ;; Keywords: mail, news 5 ;; Keywords: mail, news
6 6
7 ;; This file is part of GNU Emacs. 7 ;; This file is part of GNU Emacs.
27 ;; consists mainly of large chunks of code from the sendmail.el, 27 ;; consists mainly of large chunks of code from the sendmail.el,
28 ;; gnus-msg.el and rnewspost.el files. 28 ;; gnus-msg.el and rnewspost.el files.
29 29
30 ;;; Code: 30 ;;; Code:
31 31
32 (require 'cl) 32 (eval-when-compile
33 (require 'cl))
33 (require 'mailheader) 34 (require 'mailheader)
34 (require 'rmail) 35 (require 'rmail)
35 (require 'nnheader) 36 (require 'nnheader)
36 (require 'timezone) 37 (require 'timezone)
37 (require 'easymenu) 38 (require 'easymenu)
38 (require 'custom)
39 (if (string-match "XEmacs\\|Lucid" emacs-version) 39 (if (string-match "XEmacs\\|Lucid" emacs-version)
40 (require 'mail-abbrevs) 40 (require 'mail-abbrevs)
41 (require 'mailabbrev)) 41 (require 'mailabbrev))
42 42
43 (defgroup message '((user-mail-address custom-variable) 43 (defvar message-directory "~/Mail/"
44 (user-full-name custom-variable)) 44 "*Directory from which all other mail file variables are derived.")
45 "Mail and news message composing." 45
46 :link '(custom-manual "(message)Top") 46 (defvar message-max-buffers 10
47 :group 'mail 47 "*How many buffers to keep before starting to kill them off.")
48 :group 'news) 48
49 49 (defvar message-send-rename-function nil
50 (put 'user-mail-address 'custom-type 'string) 50 "Function called to rename the buffer after sending it.")
51 (put 'user-full-name 'custom-type 'string) 51
52 52 ;;;###autoload
53 (defgroup message-various nil 53 (defvar message-fcc-handler-function 'rmail-output
54 "Various Message Variables"
55 :link '(custom-manual "(message)Various Message Variables")
56 :group 'message)
57
58 (defgroup message-buffers nil
59 "Message Buffers"
60 :link '(custom-manual "(message)Message Buffers")
61 :group 'message)
62
63 (defgroup message-sending nil
64 "Message Sending"
65 :link '(custom-manual "(message)Sending Variables")
66 :group 'message)
67
68 (defgroup message-interface nil
69 "Message Interface"
70 :link '(custom-manual "(message)Interface")
71 :group 'message)
72
73 (defgroup message-forwarding nil
74 "Message Forwarding"
75 :link '(custom-manual "(message)Forwarding")
76 :group 'message-interface)
77
78 (defgroup message-insertion nil
79 "Message Insertion"
80 :link '(custom-manual "(message)Insertion")
81 :group 'message)
82
83 (defgroup message-headers nil
84 "Message Headers"
85 :link '(custom-manual "(message)Message Headers")
86 :group 'message)
87
88 (defgroup message-news nil
89 "Composing News Messages"
90 :group 'message)
91
92 (defgroup message-mail nil
93 "Composing Mail Messages"
94 :group 'message)
95
96 (defgroup message-faces nil
97 "Faces used for message composing."
98 :group 'message
99 :group 'faces)
100
101 (defcustom message-directory "~/Mail/"
102 "*Directory from which all other mail file variables are derived."
103 :group 'message-various
104 :type 'directory)
105
106 (defcustom message-max-buffers 10
107 "*How many buffers to keep before starting to kill them off."
108 :group 'message-buffers
109 :type 'integer)
110
111 (defcustom message-send-rename-function nil
112 "Function called to rename the buffer after sending it."
113 :group 'message-buffers
114 :type 'function)
115
116 (defcustom message-fcc-handler-function 'message-output
117 "*A function called to save outgoing articles. 54 "*A function called to save outgoing articles.
118 This function will be called with the name of the file to store the 55 This function will be called with the name of the file to store the
119 article in. The default function is `message-output' which saves in Unix 56 article in. The default function is `rmail-output' which saves in Unix
120 mailbox format." 57 mailbox format.")
121 :type '(radio (function-item message-output) 58
122 (function :tag "Other")) 59 ;;;###autoload
123 :group 'message-sending) 60 (defvar message-courtesy-message
124 61 "The following message is a courtesy copy of an article\nthat has been posted as well.\n\n"
125 (defcustom message-courtesy-message
126 "The following message is a courtesy copy of an article\nthat has been posted to %s as well.\n\n"
127 "*This is inserted at the start of a mailed copy of a posted message. 62 "*This is inserted at the start of a mailed copy of a posted message.
128 If the string contains the format spec \"%s\", the Newsgroups 63 If this variable is nil, no such courtesy message will be added.")
129 the article has been posted to will be inserted there. 64
130 If this variable is nil, no such courtesy message will be added." 65 ;;;###autoload
131 :group 'message-sending 66 (defvar message-ignored-bounced-headers "^\\(Received\\|Return-Path\\):"
132 :type 'string) 67 "*Regexp that matches headers to be removed in resent bounced mail.")
133 68
134 (defcustom message-ignored-bounced-headers "^\\(Received\\|Return-Path\\):" 69 ;;;###autoload
135 "*Regexp that matches headers to be removed in resent bounced mail." 70 (defvar message-from-style 'default
136 :group 'message-interface
137 :type 'regexp)
138
139 ;;;###autoload
140 (defcustom message-from-style 'default
141 "*Specifies how \"From\" headers look. 71 "*Specifies how \"From\" headers look.
142 72
143 If `nil', they contain just the return address like: 73 If `nil', they contain just the return address like:
144 king@grassland.com 74 king@grassland.com
145 If `parens', they look like: 75 If `parens', they look like:
146 king@grassland.com (Elvis Parsley) 76 king@grassland.com (Elvis Parsley)
147 If `angles', they look like: 77 If `angles', they look like:
148 Elvis Parsley <king@grassland.com> 78 Elvis Parsley <king@grassland.com>
149 79
150 Otherwise, most addresses look like `angles', but they look like 80 Otherwise, most addresses look like `angles', but they look like
151 `parens' if `angles' would need quoting and `parens' would not." 81 `parens' if `angles' would need quoting and `parens' would not.")
152 :type '(choice (const :tag "simple" nil) 82
153 (const parens) 83 ;;;###autoload
154 (const angles) 84 (defvar message-syntax-checks nil
155 (const default))
156 :group 'message-headers)
157
158 (defcustom message-syntax-checks nil
159 ;; Guess this one shouldn't be easy to customize...
160 "Controls what syntax checks should not be performed on outgoing posts. 85 "Controls what syntax checks should not be performed on outgoing posts.
161 To disable checking of long signatures, for instance, add 86 To disable checking of long signatures, for instance, add
162 `(signature . disabled)' to this list. 87 `(signature . disabled)' to this list.
163 88
164 Don't touch this variable unless you really know what you're doing. 89 Don't touch this variable unless you really know what you're doing.
165 90
166 Checks include subject-cmsg multiple-headers sendsys message-id from 91 Checks include subject-cmsg multiple-headers sendsys message-id from
167 long-lines control-chars size new-text redirected-followup signature 92 long-lines control-chars size new-text redirected-followup signature
168 approved sender empty empty-headers message-id from subject 93 approved sender empty empty-headers message-id from subject.")
169 shorten-followup-to existing-newsgroups." 94
170 :group 'message-news) 95 ;;;###autoload
171 96 (defvar message-required-news-headers
172 (defcustom message-required-news-headers 97 '(From Newsgroups Subject Date Message-ID
173 '(From Newsgroups Subject Date Message-ID 98 (optional . Organization) Lines
174 (optional . Organization) Lines
175 (optional . X-Newsreader)) 99 (optional . X-Newsreader))
176 "Headers to be generated or prompted for when posting an article. 100 "*Headers to be generated or prompted for when posting an article.
177 RFC977 and RFC1036 require From, Date, Newsgroups, Subject, 101 RFC977 and RFC1036 require From, Date, Newsgroups, Subject,
178 Message-ID. Organization, Lines, In-Reply-To, Expires, and 102 Message-ID. Organization, Lines, In-Reply-To, Expires, and
179 X-Newsreader are optional. If don't you want message to insert some 103 X-Newsreader are optional. If don't you want message to insert some
180 header, remove it from this list." 104 header, remove it from this list.")
181 :group 'message-news 105
182 :group 'message-headers 106 ;;;###autoload
183 :type '(repeat sexp)) 107 (defvar message-required-mail-headers
184
185 (defcustom message-required-mail-headers
186 '(From Subject Date (optional . In-Reply-To) Message-ID Lines 108 '(From Subject Date (optional . In-Reply-To) Message-ID Lines
187 (optional . X-Mailer)) 109 (optional . X-Mailer))
188 "Headers to be generated or prompted for when mailing a message. 110 "*Headers to be generated or prompted for when mailing a message.
189 RFC822 required that From, Date, To, Subject and Message-ID be 111 RFC822 required that From, Date, To, Subject and Message-ID be
190 included. Organization, Lines and X-Mailer are optional." 112 included. Organization, Lines and X-Mailer are optional.")
191 :group 'message-mail 113
192 :group 'message-headers 114 ;;;###autoload
193 :type '(repeat sexp)) 115 (defvar message-deletable-headers '(Message-ID Date)
194 116 "*Headers to be deleted if they already exist and were generated by message previously.")
195 (defcustom message-deletable-headers '(Message-ID Date Lines) 117
196 "Headers to be deleted if they already exist and were generated by message previously." 118 ;;;###autoload
197 :group 'message-headers 119 (defvar message-ignored-news-headers
198 :type 'sexp) 120 "^NNTP-Posting-Host:\\|^Xref:\\|^Bcc:\\|^Gcc:\\|^Fcc:"
199 121 "*Regexp of headers to be removed unconditionally before posting.")
200 (defcustom message-ignored-news-headers 122
201 "^NNTP-Posting-Host:\\|^Xref:\\|^Bcc:\\|^Gcc:\\|^Fcc:\\|^Resent-Fcc:" 123 ;;;###autoload
202 "*Regexp of headers to be removed unconditionally before posting." 124 (defvar message-ignored-mail-headers "^Gcc:\\|^Fcc:"
203 :group 'message-news 125 "*Regexp of headers to be removed unconditionally before mailing.")
204 :group 'message-headers 126
205 :type 'regexp) 127 ;;;###autoload
206 128 (defvar message-ignored-supersedes-headers "^Path:\\|^Date\\|^NNTP-Posting-Host:\\|^Xref:\\|^Lines:\\|^Received:\\|^X-From-Line:\\|Return-Path:\\|^Supersedes:"
207 (defcustom message-ignored-mail-headers "^Gcc:\\|^Fcc:\\|^Resent-Fcc:"
208 "*Regexp of headers to be removed unconditionally before mailing."
209 :group 'message-mail
210 :group 'message-headers
211 :type 'regexp)
212
213 (defcustom message-ignored-supersedes-headers "^Path:\\|^Date\\|^NNTP-Posting-Host:\\|^Xref:\\|^Lines:\\|^Received:\\|^X-From-Line:\\|Return-Path:\\|^Supersedes:"
214 "*Header lines matching this regexp will be deleted before posting. 129 "*Header lines matching this regexp will be deleted before posting.
215 It's best to delete old Path and Date headers before posting to avoid 130 It's best to delete old Path and Date headers before posting to avoid
216 any confusion." 131 any confusion.")
217 :group 'message-interface 132
218 :type 'regexp) 133 ;;;###autoload
219 134 (defvar message-signature-separator "^-- *$"
220 ;;;###autoload 135 "Regexp matching the signature separator.")
221 (defcustom message-signature-separator "^-- *$" 136
222 "Regexp matching the signature separator." 137 ;;;###autoload
223 :type 'regexp 138 (defvar message-interactive nil
224 :group 'message-various)
225
226 (defcustom message-elide-elipsis "\n[...]\n\n"
227 "*The string which is inserted for elided text.")
228
229 (defcustom message-interactive nil
230 "Non-nil means when sending a message wait for and display errors. 139 "Non-nil means when sending a message wait for and display errors.
231 nil means let mailer mail back a message to report errors." 140 nil means let mailer mail back a message to report errors.")
232 :group 'message-sending 141
233 :group 'message-mail 142 ;;;###autoload
234 :type 'boolean) 143 (defvar message-generate-new-buffers t
235
236 (defcustom message-generate-new-buffers t
237 "*Non-nil means that a new message buffer will be created whenever `mail-setup' is called. 144 "*Non-nil means that a new message buffer will be created whenever `mail-setup' is called.
238 If this is a function, call that function with three parameters: The type, 145 If this is a function, call that function with three parameters: The type,
239 the to address and the group name. (Any of these may be nil.) The function 146 the to address and the group name. (Any of these may be nil.) The function
240 should return the new buffer name." 147 should return the new buffer name.")
241 :group 'message-buffers 148
242 :type '(choice (const :tag "off" nil) 149 ;;;###autoload
243 (const :tag "on" t) 150 (defvar message-kill-buffer-on-exit nil
244 (function fun))) 151 "*Non-nil means that the message buffer will be killed after sending a message.")
245
246 (defcustom message-kill-buffer-on-exit nil
247 "*Non-nil means that the message buffer will be killed after sending a message."
248 :group 'message-buffers
249 :type 'boolean)
250 152
251 (defvar gnus-local-organization) 153 (defvar gnus-local-organization)
252 (defcustom message-user-organization 154 (defvar message-user-organization
253 (or (and (boundp 'gnus-local-organization) 155 (or (and (boundp 'gnus-local-organization)
254 (stringp gnus-local-organization)
255 gnus-local-organization) 156 gnus-local-organization)
256 (getenv "ORGANIZATION") 157 (getenv "ORGANIZATION")
257 t) 158 t)
258 "*String to be used as an Organization header. 159 "*String to be used as an Organization header.
259 If t, use `message-user-organization-file'." 160 If t, use `message-user-organization-file'.")
260 :group 'message-headers 161
261 :type '(choice string 162 ;;;###autoload
262 (const :tag "consult file" t))) 163 (defvar message-user-organization-file "/usr/lib/news/organization"
263 164 "*Local news organization file.")
264 ;;;###autoload 165
265 (defcustom message-user-organization-file "/usr/lib/news/organization" 166 (defvar message-autosave-directory "~/"
266 "*Local news organization file."
267 :type 'file
268 :group 'message-headers)
269
270 (defcustom message-autosave-directory "~/"
271 ; (concat (file-name-as-directory message-directory) "drafts/") 167 ; (concat (file-name-as-directory message-directory) "drafts/")
272 "*Directory where message autosaves buffers. 168 "*Directory where message autosaves buffers.
273 If nil, message won't autosave." 169 If nil, message won't autosave.")
274 :group 'message-buffers 170
275 :type 'directory) 171 (defvar message-forward-start-separator
276
277 (defcustom message-forward-start-separator
278 "------- Start of forwarded message -------\n" 172 "------- Start of forwarded message -------\n"
279 "*Delimiter inserted before forwarded messages." 173 "*Delimiter inserted before forwarded messages.")
280 :group 'message-forwarding 174
281 :type 'string) 175 (defvar message-forward-end-separator
282
283 (defcustom message-forward-end-separator
284 "------- End of forwarded message -------\n" 176 "------- End of forwarded message -------\n"
285 "*Delimiter inserted after forwarded messages." 177 "*Delimiter inserted after forwarded messages.")
286 :group 'message-forwarding 178
287 :type 'string) 179 ;;;###autoload
288 180 (defvar message-signature-before-forwarded-message t
289 (defcustom message-signature-before-forwarded-message t 181 "*If non-nil, put the signature before any included forwarded message.")
290 "*If non-nil, put the signature before any included forwarded message." 182
291 :group 'message-forwarding 183 ;;;###autoload
292 :type 'boolean) 184 (defvar message-included-forward-headers
293
294 (defcustom message-included-forward-headers
295 "^From:\\|^Newsgroups:\\|^Subject:\\|^Date:\\|^Followup-To:\\|^Reply-To:\\|^Organization:\\|^Summary:\\|^Keywords:\\|^To:\\|^Cc:\\|^Posted-To:\\|^Mail-Copies-To:\\|^Apparently-To:\\|^Gnus-Warning:\\|^Resent-\\|^Message-ID:\\|^References:" 185 "^From:\\|^Newsgroups:\\|^Subject:\\|^Date:\\|^Followup-To:\\|^Reply-To:\\|^Organization:\\|^Summary:\\|^Keywords:\\|^To:\\|^Cc:\\|^Posted-To:\\|^Mail-Copies-To:\\|^Apparently-To:\\|^Gnus-Warning:\\|^Resent-\\|^Message-ID:\\|^References:"
296 "*Regexp matching headers to be included in forwarded messages." 186 "*Regexp matching headers to be included in forwarded messages.")
297 :group 'message-forwarding 187
298 :type 'regexp) 188 ;;;###autoload
299 189 (defvar message-ignored-resent-headers "^Return-receipt"
300 (defcustom message-ignored-resent-headers "^Return-receipt" 190 "*All headers that match this regexp will be deleted when resending a message.")
301 "*All headers that match this regexp will be deleted when resending a message." 191
302 :group 'message-interface 192 ;;;###autoload
303 :type 'regexp) 193 (defvar message-ignored-cited-headers "."
304 194 "Delete these headers from the messages you yank.")
305 (defcustom message-ignored-cited-headers "."
306 "*Delete these headers from the messages you yank."
307 :group 'message-insertion
308 :type 'regexp)
309
310 (defcustom message-cancel-message "I am canceling my own article."
311 "Message to be inserted in the cancel message."
312 :group 'message-interface
313 :type 'string)
314 195
315 ;; Useful to set in site-init.el 196 ;; Useful to set in site-init.el
316 ;;;###autoload 197 ;;;###autoload
317 (defcustom message-send-mail-function 'message-send-mail-with-sendmail 198 (defvar message-send-mail-function 'message-send-mail-with-sendmail
318 "Function to call to send the current buffer as mail. 199 "Function to call to send the current buffer as mail.
319 The headers should be delimited by a line whose contents match the 200 The headers should be delimited by a line whose contents match the
320 variable `mail-header-separator'. 201 variable `mail-header-separator'.
321 202
322 Legal values include `message-send-mail-with-sendmail' (the default), 203 Legal values include `message-send-mail-with-mh' and
323 `message-send-mail-with-mh' and `message-send-mail-with-qmail'." 204 `message-send-mail-with-sendmail', which is the default.")
324 :type '(radio (function-item message-send-mail-with-sendmail) 205
325 (function-item message-send-mail-with-mh) 206 ;;;###autoload
326 (function-item message-send-mail-with-qmail) 207 (defvar message-send-news-function 'message-send-news
327 (function :tag "Other"))
328 :group 'message-sending
329 :group 'message-mail)
330
331 (defcustom message-send-news-function 'message-send-news
332 "Function to call to send the current buffer as news. 208 "Function to call to send the current buffer as news.
333 The headers should be delimited by a line whose contents match the 209 The headers should be delimited by a line whose contents match the
334 variable `mail-header-separator'." 210 variable `mail-header-separator'.")
335 :group 'message-sending 211
336 :group 'message-news 212 ;;;###autoload
337 :type 'function) 213 (defvar message-reply-to-function nil
338
339 (defcustom message-reply-to-function nil
340 "Function that should return a list of headers. 214 "Function that should return a list of headers.
341 This function should pick out addresses from the To, Cc, and From headers 215 This function should pick out addresses from the To, Cc, and From headers
342 and respond with new To and Cc headers." 216 and respond with new To and Cc headers.")
343 :group 'message-interface 217
344 :type 'function) 218 ;;;###autoload
345 219 (defvar message-wide-reply-to-function nil
346 (defcustom message-wide-reply-to-function nil
347 "Function that should return a list of headers. 220 "Function that should return a list of headers.
348 This function should pick out addresses from the To, Cc, and From headers 221 This function should pick out addresses from the To, Cc, and From headers
349 and respond with new To and Cc headers." 222 and respond with new To and Cc headers.")
350 :group 'message-interface 223
351 :type 'function) 224 ;;;###autoload
352 225 (defvar message-followup-to-function nil
353 (defcustom message-followup-to-function nil
354 "Function that should return a list of headers. 226 "Function that should return a list of headers.
355 This function should pick out addresses from the To, Cc, and From headers 227 This function should pick out addresses from the To, Cc, and From headers
356 and respond with new To and Cc headers." 228 and respond with new To and Cc headers.")
357 :group 'message-interface 229
358 :type 'function) 230 ;;;###autoload
359 231 (defvar message-use-followup-to 'ask
360 (defcustom message-use-followup-to 'ask
361 "*Specifies what to do with Followup-To header. 232 "*Specifies what to do with Followup-To header.
362 If nil, always ignore the header. If it is t, use its value, but 233 If nil, ignore the header. If it is t, use its value, but query before
363 query before using the \"poster\" value. If it is the symbol `ask', 234 using the \"poster\" value. If it is the symbol `ask', query the user
364 always query the user whether to use the value. If it is the symbol 235 whether to ignore the \"poster\" value. If it is the symbol `use',
365 `use', always use the value." 236 always use the value.")
366 :group 'message-interface
367 :type '(choice (const :tag "ignore" nil)
368 (const use)
369 (const ask)))
370
371 ;; stuff relating to broken sendmail in MMDF
372 (defcustom message-sendmail-f-is-evil nil
373 "*Non-nil means that \"-f username\" should not be added to the sendmail
374 command line, because it is even more evil than leaving it out."
375 :group 'message-sending
376 :type 'boolean)
377
378 ;; qmail-related stuff
379 (defcustom message-qmail-inject-program "/var/qmail/bin/qmail-inject"
380 "Location of the qmail-inject program."
381 :group 'message-sending
382 :type 'file)
383
384 (defcustom message-qmail-inject-args nil
385 "Arguments passed to qmail-inject programs.
386 This should be a list of strings, one string for each argument.
387
388 For e.g., if you wish to set the envelope sender address so that bounces
389 go to the right place or to deal with listserv's usage of that address, you
390 might set this variable to '(\"-f\" \"you@some.where\")."
391 :group 'message-sending
392 :type '(repeat string))
393 237
394 (defvar gnus-post-method) 238 (defvar gnus-post-method)
395 (defvar gnus-select-method) 239 (defvar gnus-select-method)
396 (defcustom message-post-method 240 ;;;###autoload
241 (defvar message-post-method
397 (cond ((and (boundp 'gnus-post-method) 242 (cond ((and (boundp 'gnus-post-method)
398 gnus-post-method) 243 gnus-post-method)
399 gnus-post-method) 244 gnus-post-method)
400 ((boundp 'gnus-select-method) 245 ((boundp 'gnus-select-method)
401 gnus-select-method) 246 gnus-select-method)
402 (t '(nnspool ""))) 247 (t '(nnspool "")))
403 "Method used to post news." 248 "Method used to post news.")
404 :group 'message-news 249
405 :group 'message-sending 250 ;;;###autoload
406 ;; This should be the `gnus-select-method' widget, but that might 251 (defvar message-generate-headers-first nil
407 ;; create a dependence to `gnus.el'. 252 "*If non-nil, generate all possible headers before composing.")
408 :type 'sexp) 253
409 254 (defvar message-setup-hook nil
410 (defcustom message-generate-headers-first nil
411 "*If non-nil, generate all possible headers before composing."
412 :group 'message-headers
413 :type 'boolean)
414
415 (defcustom message-setup-hook nil
416 "Normal hook, run each time a new outgoing message is initialized. 255 "Normal hook, run each time a new outgoing message is initialized.
417 The function `message-setup' runs this hook." 256 The function `message-setup' runs this hook.")
418 :group 'message-various 257
419 :type 'hook) 258 (defvar message-signature-setup-hook nil
420
421 (defcustom message-signature-setup-hook nil
422 "Normal hook, run each time a new outgoing message is initialized. 259 "Normal hook, run each time a new outgoing message is initialized.
423 It is run after the headers have been inserted and before 260 It is run after the headers have been inserted and before
424 the signature is inserted." 261 the signature is inserted.")
425 :group 'message-various 262
426 :type 'hook) 263 (defvar message-mode-hook nil
427 264 "Hook run in message mode buffers.")
428 (defcustom message-mode-hook nil 265
429 "Hook run in message mode buffers." 266 (defvar message-header-hook nil
430 :group 'message-various 267 "Hook run in a message mode buffer narrowed to the headers.")
431 :type 'hook) 268
432 269 (defvar message-header-setup-hook nil
433 (defcustom message-header-hook nil 270 "Hook called narrowed to the headers when setting up a message buffer.")
434 "Hook run in a message mode buffer narrowed to the headers." 271
435 :group 'message-various 272 ;;;###autoload
436 :type 'hook) 273 (defvar message-citation-line-function 'message-insert-citation-line
437 274 "*Function called to insert the \"Whomever writes:\" line.")
438 (defcustom message-header-setup-hook nil 275
439 "Hook called narrowed to the headers when setting up a message 276 ;;;###autoload
440 buffer." 277 (defvar message-yank-prefix "> "
441 :group 'message-various
442 :type 'hook)
443
444 ;;;###autoload
445 (defcustom message-citation-line-function 'message-insert-citation-line
446 "*Function called to insert the \"Whomever writes:\" line."
447 :type 'function
448 :group 'message-insertion)
449
450 ;;;###autoload
451 (defcustom message-yank-prefix "> "
452 "*Prefix inserted on the lines of yanked messages. 278 "*Prefix inserted on the lines of yanked messages.
453 nil means use indentation." 279 nil means use indentation.")
454 :type 'string 280
455 :group 'message-insertion) 281 (defvar message-indentation-spaces 3
456
457 (defcustom message-indentation-spaces 3
458 "*Number of spaces to insert at the beginning of each cited line. 282 "*Number of spaces to insert at the beginning of each cited line.
459 Used by `message-yank-original' via `message-yank-cite'." 283 Used by `message-yank-original' via `message-yank-cite'.")
460 :group 'message-insertion 284
461 :type 'integer) 285 ;;;###autoload
462 286 (defvar message-cite-function 'message-cite-original
463 ;;;###autoload 287 "*Function for citing an original message.")
464 (defcustom message-cite-function 288
465 (if (and (boundp 'mail-citation-hook) 289 ;;;###autoload
466 mail-citation-hook) 290 (defvar message-indent-citation-function 'message-indent-citation
467 mail-citation-hook
468 'message-cite-original)
469 "*Function for citing an original message."
470 :type '(radio (function-item message-cite-original)
471 (function-item sc-cite-original)
472 (function :tag "Other"))
473 :group 'message-insertion)
474
475 ;;;###autoload
476 (defcustom message-indent-citation-function 'message-indent-citation
477 "*Function for modifying a citation just inserted in the mail buffer. 291 "*Function for modifying a citation just inserted in the mail buffer.
478 This can also be a list of functions. Each function can find the 292 This can also be a list of functions. Each function can find the
479 citation between (point) and (mark t). And each function should leave 293 citation between (point) and (mark t). And each function should leave
480 point and mark around the citation text as modified." 294 point and mark around the citation text as modified.")
481 :type 'function
482 :group 'message-insertion)
483 295
484 (defvar message-abbrevs-loaded nil) 296 (defvar message-abbrevs-loaded nil)
485 297
486 ;;;###autoload 298 ;;;###autoload
487 (defcustom message-signature t 299 (defvar message-signature t
488 "*String to be inserted at the end of the message buffer. 300 "*String to be inserted at the end of the message buffer.
489 If t, the `message-signature-file' file will be inserted instead. 301 If t, the `message-signature-file' file will be inserted instead.
490 If a function, the result from the function will be used instead. 302 If a function, the result from the function will be used instead.
491 If a form, the result from the form will be used instead." 303 If a form, the result from the form will be used instead.")
492 :type 'sexp 304
493 :group 'message-insertion) 305 ;;;###autoload
494 306 (defvar message-signature-file "~/.signature"
495 ;;;###autoload 307 "*File containing the text inserted at end of message. buffer.")
496 (defcustom message-signature-file "~/.signature" 308
497 "*File containing the text inserted at end of message buffer." 309 (defvar message-distribution-function nil
498 :type 'file 310 "*Function called to return a Distribution header.")
499 :group 'message-insertion) 311
500 312 (defvar message-expires 14
501 (defcustom message-distribution-function nil 313 "*Number of days before your article expires.")
502 "*Function called to return a Distribution header." 314
503 :group 'message-news 315 (defvar message-user-path nil
504 :group 'message-headers
505 :type 'function)
506
507 (defcustom message-expires 14
508 "Number of days before your article expires."
509 :group 'message-news
510 :group 'message-headers
511 :link '(custom-manual "(message)News Headers")
512 :type 'integer)
513
514 (defcustom message-user-path nil
515 "If nil, use the NNTP server name in the Path header. 316 "If nil, use the NNTP server name in the Path header.
516 If stringp, use this; if non-nil, use no host name (user name only)." 317 If stringp, use this; if non-nil, use no host name (user name only).")
517 :group 'message-news
518 :group 'message-headers
519 :link '(custom-manual "(message)News Headers")
520 :type '(choice (const :tag "nntp" nil)
521 (string :tag "name")
522 (sexp :tag "none" :format "%t" t)))
523 318
524 (defvar message-reply-buffer nil) 319 (defvar message-reply-buffer nil)
525 (defvar message-reply-headers nil) 320 (defvar message-reply-headers nil)
526 (defvar message-newsreader nil) 321 (defvar message-newsreader nil)
527 (defvar message-mailer nil) 322 (defvar message-mailer nil)
534 (defvar message-kill-actions nil 329 (defvar message-kill-actions nil
535 "A list of actions to be performed before killing a message buffer.") 330 "A list of actions to be performed before killing a message buffer.")
536 (defvar message-postpone-actions nil 331 (defvar message-postpone-actions nil
537 "A list of actions to be performed after postponing a message.") 332 "A list of actions to be performed after postponing a message.")
538 333
539 (defcustom message-default-headers "" 334 ;;;###autoload
335 (defvar message-default-headers nil
540 "*A string containing header lines to be inserted in outgoing messages. 336 "*A string containing header lines to be inserted in outgoing messages.
541 It is inserted before you edit the message, so you can edit or delete 337 It is inserted before you edit the message, so you can edit or delete
542 these lines." 338 these lines.")
543 :group 'message-headers 339
544 :type 'string) 340 ;;;###autoload
545 341 (defvar message-default-mail-headers nil
546 (defcustom message-default-mail-headers "" 342 "*A string of header lines to be inserted in outgoing mails.")
547 "*A string of header lines to be inserted in outgoing mails." 343
548 :group 'message-headers 344 ;;;###autoload
549 :group 'message-mail 345 (defvar message-default-news-headers nil
550 :type 'string) 346 "*A string of header lines to be inserted in outgoing news articles.")
551
552 (defcustom message-default-news-headers ""
553 "*A string of header lines to be inserted in outgoing news
554 articles."
555 :group 'message-headers
556 :group 'message-news
557 :type 'string)
558 347
559 ;; Note: could use /usr/ucb/mail instead of sendmail; 348 ;; Note: could use /usr/ucb/mail instead of sendmail;
560 ;; options -t, and -v if not interactive. 349 ;; options -t, and -v if not interactive.
561 (defcustom message-mailer-swallows-blank-line 350 (defvar message-mailer-swallows-blank-line
562 (if (and (string-match "sparc-sun-sunos\\(\\'\\|[^5]\\)" 351 (if (and (string-match "sparc-sun-sunos\\(\\'\\|[^5]\\)"
563 system-configuration) 352 system-configuration)
564 (file-readable-p "/etc/sendmail.cf") 353 (file-readable-p "/etc/sendmail.cf")
565 (let ((buffer (get-buffer-create " *temp*"))) 354 (let ((buffer (get-buffer-create " *temp*")))
566 (unwind-protect 355 (unwind-protect
567 (save-excursion 356 (save-excursion
570 (goto-char (point-min)) 359 (goto-char (point-min))
571 (let ((case-fold-search nil)) 360 (let ((case-fold-search nil))
572 (re-search-forward "^OR\\>" nil t))) 361 (re-search-forward "^OR\\>" nil t)))
573 (kill-buffer buffer)))) 362 (kill-buffer buffer))))
574 ;; According to RFC822, "The field-name must be composed of printable 363 ;; According to RFC822, "The field-name must be composed of printable
575 ;; ASCII characters (i. e., characters that have decimal values between 364 ;; ASCII characters (i.e. characters that have decimal values between
576 ;; 33 and 126, except colon)", i. e., any chars except ctl chars, 365 ;; 33 and 126, except colon)", i.e. any chars except ctl chars,
577 ;; space, or colon. 366 ;; space, or colon.
578 '(looking-at "[ \t]\\|[][!\"#$%&'()*+,-./0-9;<=>?@A-Z\\\\^_`a-z{|}~]+:")) 367 '(looking-at "[ \t]\\|[][!\"#$%&'()*+,-./0-9;<=>?@A-Z\\\\^_`a-z{|}~]+:"))
579 "Set this non-nil if the system's mailer runs the header and body together. 368 "Set this non-nil if the system's mailer runs the header and body together.
580 \(This problem exists on Sunos 4 when sendmail is run in remote mode.) 369 \(This problem exists on Sunos 4 when sendmail is run in remote mode.)
581 The value should be an expression to test whether the problem will 370 The value should be an expression to test whether the problem will
582 actually occur." 371 actually occur.")
583 :group 'message-sending 372
584 :type 'sexp) 373 (defvar message-mode-syntax-table
585
586 (ignore-errors
587 (define-mail-user-agent 'message-user-agent
588 'message-mail 'message-send-and-exit
589 'message-kill-buffer 'message-send-hook))
590
591 (defvar message-mh-deletable-headers '(Message-ID Date Lines Sender)
592 "If non-nil, delete the deletable headers before feeding to mh.")
593
594 ;;; Internal variables.
595 ;;; Well, not really internal.
596
597 (defvar message-mode-syntax-table
598 (let ((table (copy-syntax-table text-mode-syntax-table))) 374 (let ((table (copy-syntax-table text-mode-syntax-table)))
599 (modify-syntax-entry ?% ". " table) 375 (modify-syntax-entry ?% ". " table)
600 table) 376 table)
601 "Syntax table used while in Message mode.") 377 "Syntax table used while in Message mode.")
602 378
603 (defvar message-mode-abbrev-table text-mode-abbrev-table 379 (defvar message-mode-abbrev-table text-mode-abbrev-table
604 "Abbrev table used in Message mode buffers. 380 "Abbrev table used in Message mode buffers.
605 Defaults to `text-mode-abbrev-table'.") 381 Defaults to `text-mode-abbrev-table'.")
606 (defgroup message-headers nil
607 "Message headers."
608 :link '(custom-manual "(message)Variables")
609 :group 'message)
610
611 (defface message-header-to-face
612 '((((class color)
613 (background dark))
614 (:foreground "green2" :bold t))
615 (((class color)
616 (background light))
617 (:foreground "MidnightBlue" :bold t))
618 (t
619 (:bold t :italic t)))
620 "Face used for displaying From headers."
621 :group 'message-faces)
622
623 (defface message-header-cc-face
624 '((((class color)
625 (background dark))
626 (:foreground "green4" :bold t))
627 (((class color)
628 (background light))
629 (:foreground "MidnightBlue"))
630 (t
631 (:bold t)))
632 "Face used for displaying Cc headers."
633 :group 'message-faces)
634
635 (defface message-header-subject-face
636 '((((class color)
637 (background dark))
638 (:foreground "green3"))
639 (((class color)
640 (background light))
641 (:foreground "navy blue" :bold t))
642 (t
643 (:bold t)))
644 "Face used for displaying subject headers."
645 :group 'message-faces)
646
647 (defface message-header-newsgroups-face
648 '((((class color)
649 (background dark))
650 (:foreground "yellow" :bold t :italic t))
651 (((class color)
652 (background light))
653 (:foreground "blue4" :bold t :italic t))
654 (t
655 (:bold t :italic t)))
656 "Face used for displaying newsgroups headers."
657 :group 'message-faces)
658
659 (defface message-header-other-face
660 '((((class color)
661 (background dark))
662 (:foreground "red4"))
663 (((class color)
664 (background light))
665 (:foreground "steel blue"))
666 (t
667 (:bold t :italic t)))
668 "Face used for displaying newsgroups headers."
669 :group 'message-faces)
670
671 (defface message-header-name-face
672 '((((class color)
673 (background dark))
674 (:foreground "DarkGreen"))
675 (((class color)
676 (background light))
677 (:foreground "cornflower blue"))
678 (t
679 (:bold t)))
680 "Face used for displaying header names."
681 :group 'message-faces)
682
683 (defface message-header-xheader-face
684 '((((class color)
685 (background dark))
686 (:foreground "blue"))
687 (((class color)
688 (background light))
689 (:foreground "blue"))
690 (t
691 (:bold t)))
692 "Face used for displaying X-Header headers."
693 :group 'message-faces)
694
695 (defface message-separator-face
696 '((((class color)
697 (background dark))
698 (:foreground "blue4"))
699 (((class color)
700 (background light))
701 (:foreground "brown"))
702 (t
703 (:bold t)))
704 "Face used for displaying the separator."
705 :group 'message-faces)
706
707 (defface message-cited-text-face
708 '((((class color)
709 (background dark))
710 (:foreground "red"))
711 (((class color)
712 (background light))
713 (:foreground "red"))
714 (t
715 (:bold t)))
716 "Face used for displaying cited text names."
717 :group 'message-faces)
718 382
719 (defvar message-font-lock-keywords 383 (defvar message-font-lock-keywords
720 (let* ((cite-prefix "A-Za-z") 384 (let* ((cite-prefix "A-Za-z") (cite-suffix (concat cite-prefix "0-9_.@-")))
721 (cite-suffix (concat cite-prefix "0-9_.@-")) 385 (list '("^To:" . font-lock-function-name-face)
722 (content "[ \t]*\\(.+\\(\n[ \t].*\\)*\\)")) 386 '("^[GBF]?[Cc][Cc]:\\|^Reply-To:" . font-lock-keyword-face)
723 `((,(concat "^\\(To:\\)" content) 387 '("^\\(Subject:\\)[ \t]*\\(.+\\)?"
724 (1 'message-header-name-face) 388 (1 font-lock-comment-face) (2 font-lock-type-face nil t))
725 (2 'message-header-to-face nil t)) 389 (list (concat "^\\(" (regexp-quote mail-header-separator) "\\)$")
726 (,(concat "^\\(^[GBF]?[Cc][Cc]:\\|^Reply-To:\\)" content) 390 1 'font-lock-comment-face)
727 (1 'message-header-name-face) 391 (cons (concat "^[ \t]*"
728 (2 'message-header-cc-face nil t)) 392 "\\([" cite-prefix "]+[" cite-suffix "]*\\)?"
729 (,(concat "^\\(Subject:\\)" content) 393 "[>|}].*")
730 (1 'message-header-name-face) 394 'font-lock-reference-face)
731 (2 'message-header-subject-face nil t)) 395 '("^\\(X-[A-Za-z0-9-]+\\|In-reply-to\\):.*"
732 (,(concat "^\\(Newsgroups:\\|Followup-to:\\)" content) 396 . font-lock-string-face)))
733 (1 'message-header-name-face)
734 (2 'message-header-newsgroups-face nil t))
735 (,(concat "^\\([^: \n\t]+:\\)" content)
736 (1 'message-header-name-face)
737 (2 'message-header-other-face nil t))
738 (,(concat "^\\(X-[A-Za-z0-9-]+\\|In-Reply-To\\):" content)
739 (1 'message-header-name-face)
740 (2 'message-header-name-face))
741 (,(concat "^\\(" (regexp-quote mail-header-separator) "\\)$")
742 1 'message-separator-face)
743 (,(concat "^[ \t]*"
744 "\\([" cite-prefix "]+[" cite-suffix "]*\\)?"
745 "[>|}].*")
746 (0 'message-cited-text-face))))
747 "Additional expressions to highlight in Message mode.") 397 "Additional expressions to highlight in Message mode.")
748 398
749 (defvar message-face-alist 399 (defvar message-face-alist
750 '((bold . bold-region) 400 '((bold . bold-region)
751 (underline . underline-region) 401 (underline . underline-region)
752 (default . (lambda (b e) 402 (default . (lambda (b e)
753 (unbold-region b e) 403 (unbold-region b e)
754 (ununderline-region b e)))) 404 (ununderline-region b e))))
755 "Alist of mail and news faces for facemenu. 405 "Alist of mail and news faces for facemenu.
756 The cdr of ech entry is a function for applying the face to a region.") 406 The cdr of ech entry is a function for applying the face to a region.")
757 407
758 (defcustom message-send-hook nil 408 (defvar message-send-hook nil
759 "Hook run before sending messages." 409 "Hook run before sending messages.")
760 :group 'message-various 410
761 :options '(ispell-message) 411 (defvar message-sent-hook nil
762 :type 'hook) 412 "Hook run after sending messages.")
763
764 (defcustom message-send-mail-hook nil
765 "Hook run before sending mail messages."
766 :group 'message-various
767 :type 'hook)
768
769 (defcustom message-send-news-hook nil
770 "Hook run before sending news messages."
771 :group 'message-various
772 :type 'hook)
773
774 (defcustom message-sent-hook nil
775 "Hook run after sending messages."
776 :group 'message-various
777 :type 'hook)
778 413
779 ;;; Internal variables. 414 ;;; Internal variables.
780 415
781 (defvar message-buffer-list nil) 416 (defvar message-buffer-list nil)
782 (defvar message-this-is-news nil)
783 (defvar message-this-is-mail nil)
784
785 ;; Byte-compiler warning
786 (defvar gnus-active-hashtb)
787 (defvar gnus-read-active-file)
788 417
789 ;;; Regexp matching the delimiter of messages in UNIX mail format 418 ;;; Regexp matching the delimiter of messages in UNIX mail format
790 ;;; (UNIX From lines), minus the initial ^. 419 ;;; (UNIX From lines), minus the initial ^.
791 (defvar message-unix-mail-delimiter 420 (defvar message-unix-mail-delimiter
792 (let ((time-zone-regexp 421 (let ((time-zone-regexp
793 (concat "\\([A-Z]?[A-Z]?[A-Z][A-Z]\\( DST\\)?" 422 (concat "\\([A-Z]?[A-Z]?[A-Z][A-Z]\\( DST\\)?"
794 "\\|[-+]?[0-9][0-9][0-9][0-9]" 423 "\\|[-+]?[0-9][0-9][0-9][0-9]"
795 "\\|" 424 "\\|"
833 "^ *--+ +begin message +--+ *$\\|" 462 "^ *--+ +begin message +--+ *$\\|"
834 "^ *---+ +Original message follows +---+ *$\\|" 463 "^ *---+ +Original message follows +---+ *$\\|"
835 "^|? *---+ +Message text follows: +---+ *|?$") 464 "^|? *---+ +Message text follows: +---+ *|?$")
836 "A regexp that matches the separator before the text of a failed message.") 465 "A regexp that matches the separator before the text of a failed message.")
837 466
838 (defvar message-header-format-alist 467 (defvar message-header-format-alist
839 `((Newsgroups) 468 `((Newsgroups)
840 (To . message-fill-address) 469 (To . message-fill-address)
841 (Cc . message-fill-address) 470 (Cc . message-fill-address)
842 (Subject) 471 (Subject)
843 (In-Reply-To) 472 (In-Reply-To)
844 (Fcc) 473 (Fcc)
845 (Bcc) 474 (Bcc)
847 (Organization) 476 (Organization)
848 (Distribution) 477 (Distribution)
849 (Lines) 478 (Lines)
850 (Expires) 479 (Expires)
851 (Message-ID) 480 (Message-ID)
852 (References) 481 (References . message-fill-header)
853 (X-Mailer) 482 (X-Mailer)
854 (X-Newsreader)) 483 (X-Newsreader))
855 "Alist used for formatting headers.") 484 "Alist used for formatting headers.")
856 485
857 (eval-and-compile 486 (eval-and-compile
858 (autoload 'message-setup-toolbar "messagexmas") 487 (autoload 'message-setup-toolbar "messagexmas")
859 (autoload 'mh-send-letter "mh-comp") 488 (autoload 'mh-send-letter "mh-comp"))
860 (autoload 'gnus-point-at-eol "gnus-util")
861 (autoload 'gnus-point-at-bol "gnus-util")
862 (autoload 'gnus-output-to-mail "gnus-util")
863 (autoload 'gnus-output-to-rmail "gnus-util")
864 (autoload 'mail-abbrev-in-expansion-header-p "mailabbrev"))
865 489
866 490
867 491
868 ;;; 492 ;;;
869 ;;; Utility functions. 493 ;;; Utility functions.
870 ;;; 494 ;;;
871 495
872 (defmacro message-y-or-n-p (question show &rest text) 496 (defun message-point-at-bol ()
873 "Ask QUESTION, displaying the rest of the arguments in a temp. buffer if SHOW" 497 "Return point at the beginning of the line."
874 `(message-talkative-question 'y-or-n-p ,question ,show ,@text)) 498 (let ((p (point)))
499 (beginning-of-line)
500 (prog1
501 (point)
502 (goto-char p))))
503
504 (defun message-point-at-eol ()
505 "Return point at the end of the line."
506 (let ((p (point)))
507 (end-of-line)
508 (prog1
509 (point)
510 (goto-char p))))
875 511
876 ;; Delete the current line (and the next N lines.); 512 ;; Delete the current line (and the next N lines.);
877 (defmacro message-delete-line (&optional n) 513 (defmacro message-delete-line (&optional n)
878 `(delete-region (progn (beginning-of-line) (point)) 514 `(delete-region (progn (beginning-of-line) (point))
879 (progn (forward-line ,(or n 1)) (point)))) 515 (progn (forward-line ,(or n 1)) (point))))
880 516
881 (defun message-tokenize-header (header &optional separator) 517 (defun message-tokenize-header (header &optional separator)
882 "Split HEADER into a list of header elements. 518 "Split HEADER into a list of header elements.
883 \",\" is used as the separator." 519 \",\" is used as the separator."
884 (if (not header) 520 (let ((regexp (format "[%s]+" (or separator ",")))
885 nil 521 (beg 1)
886 (let ((regexp (format "[%s]+" (or separator ","))) 522 (first t)
887 (beg 1) 523 quoted elems)
888 (first t) 524 (save-excursion
889 quoted elems paren) 525 (message-set-work-buffer)
890 (save-excursion 526 (insert header)
891 (message-set-work-buffer)
892 (insert header)
893 (goto-char (point-min))
894 (while (not (eobp))
895 (if first
896 (setq first nil)
897 (forward-char 1))
898 (cond ((and (> (point) beg)
899 (or (eobp)
900 (and (looking-at regexp)
901 (not quoted)
902 (not paren))))
903 (push (buffer-substring beg (point)) elems)
904 (setq beg (match-end 0)))
905 ((= (following-char) ?\")
906 (setq quoted (not quoted)))
907 ((and (= (following-char) ?\()
908 (not quoted))
909 (setq paren t))
910 ((and (= (following-char) ?\))
911 (not quoted))
912 (setq paren nil))))
913 (nreverse elems)))))
914
915 (defun message-mail-file-mbox-p (file)
916 "Say whether FILE looks like a Unix mbox file."
917 (when (and (file-exists-p file)
918 (file-readable-p file)
919 (file-regular-p file))
920 (nnheader-temp-write nil
921 (nnheader-insert-file-contents file)
922 (goto-char (point-min)) 527 (goto-char (point-min))
923 (looking-at message-unix-mail-delimiter)))) 528 (while (not (eobp))
924 529 (if first
925 (defun message-fetch-field (header &optional not-all) 530 (setq first nil)
531 (forward-char 1))
532 (cond ((and (> (point) beg)
533 (or (eobp)
534 (and (looking-at regexp)
535 (not quoted))))
536 (push (buffer-substring beg (point)) elems)
537 (setq beg (match-end 0)))
538 ((= (following-char) ?\")
539 (setq quoted (not quoted)))))
540 (nreverse elems))))
541
542 (defun message-fetch-field (header)
926 "The same as `mail-fetch-field', only remove all newlines." 543 "The same as `mail-fetch-field', only remove all newlines."
927 (let ((value (mail-fetch-field header nil (not not-all)))) 544 (let ((value (mail-fetch-field header)))
928 (when value 545 (when value
929 (nnheader-replace-chars-in-string value ?\n ? )))) 546 (nnheader-replace-chars-in-string value ?\n ? ))))
930 547
931 (defun message-fetch-reply-field (header) 548 (defun message-fetch-reply-field (header)
932 "Fetch FIELD from the message we're replying to." 549 "Fetch FIELD from the message we're replying to."
1011 (point-max))) 628 (point-max)))
1012 (goto-char (point-min))) 629 (goto-char (point-min)))
1013 630
1014 (defun message-news-p () 631 (defun message-news-p ()
1015 "Say whether the current buffer contains a news message." 632 "Say whether the current buffer contains a news message."
1016 (or message-this-is-news 633 (save-excursion
1017 (save-excursion 634 (save-restriction
1018 (save-restriction 635 (message-narrow-to-headers)
1019 (message-narrow-to-headers) 636 (message-fetch-field "newsgroups"))))
1020 (message-fetch-field "newsgroups")))))
1021 637
1022 (defun message-mail-p () 638 (defun message-mail-p ()
1023 "Say whether the current buffer contains a mail message." 639 "Say whether the current buffer contains a mail message."
1024 (or message-this-is-mail 640 (save-excursion
1025 (save-excursion 641 (save-restriction
1026 (save-restriction 642 (message-narrow-to-headers)
1027 (message-narrow-to-headers) 643 (or (message-fetch-field "to")
1028 (or (message-fetch-field "to") 644 (message-fetch-field "cc")
1029 (message-fetch-field "cc") 645 (message-fetch-field "bcc")))))
1030 (message-fetch-field "bcc"))))))
1031 646
1032 (defun message-next-header () 647 (defun message-next-header ()
1033 "Go to the beginning of the next header." 648 "Go to the beginning of the next header."
1034 (beginning-of-line) 649 (beginning-of-line)
1035 (or (eobp) (forward-char 1)) 650 (or (eobp) (forward-char 1))
1036 (not (if (re-search-forward "^[^ \t]" nil t) 651 (not (if (re-search-forward "^[^ \t]" nil t)
1037 (beginning-of-line) 652 (beginning-of-line)
1038 (goto-char (point-max))))) 653 (goto-char (point-max)))))
1039 654
1040 (defun message-sort-headers-1 () 655 (defun message-sort-headers-1 ()
1041 "Sort the buffer as headers using `message-rank' text props." 656 "Sort the buffer as headers using `message-rank' text props."
1042 (goto-char (point-min)) 657 (goto-char (point-min))
1043 (sort-subr 658 (sort-subr
1044 nil 'message-next-header 659 nil 'message-next-header
1045 (lambda () 660 (lambda ()
1046 (message-next-header) 661 (message-next-header)
1047 (unless (bobp) 662 (unless (bobp)
1048 (forward-char -1))) 663 (forward-char -1)))
1049 (lambda () 664 (lambda ()
1050 (or (get-text-property (point) 'message-rank) 665 (or (get-text-property (point) 'message-rank)
1051 10000)))) 666 0))))
1052 667
1053 (defun message-sort-headers () 668 (defun message-sort-headers ()
1054 "Sort the headers of the current message according to `message-header-format-alist'." 669 "Sort the headers of the current message according to `message-header-format-alist'."
1055 (interactive) 670 (interactive)
1056 (save-excursion 671 (save-excursion
1099 (define-key message-mode-map "\C-c\C-b" 'message-goto-body) 714 (define-key message-mode-map "\C-c\C-b" 'message-goto-body)
1100 (define-key message-mode-map "\C-c\C-i" 'message-goto-signature) 715 (define-key message-mode-map "\C-c\C-i" 'message-goto-signature)
1101 716
1102 (define-key message-mode-map "\C-c\C-t" 'message-insert-to) 717 (define-key message-mode-map "\C-c\C-t" 'message-insert-to)
1103 (define-key message-mode-map "\C-c\C-n" 'message-insert-newsgroups) 718 (define-key message-mode-map "\C-c\C-n" 'message-insert-newsgroups)
1104 719
1105 (define-key message-mode-map "\C-c\C-y" 'message-yank-original) 720 (define-key message-mode-map "\C-c\C-y" 'message-yank-original)
1106 (define-key message-mode-map "\C-c\C-q" 'message-fill-yanked-message) 721 (define-key message-mode-map "\C-c\C-q" 'message-fill-yanked-message)
1107 (define-key message-mode-map "\C-c\C-w" 'message-insert-signature) 722 (define-key message-mode-map "\C-c\C-w" 'message-insert-signature)
1108 (define-key message-mode-map "\C-c\C-r" 'message-caesar-buffer-body) 723 (define-key message-mode-map "\C-c\C-r" 'message-caesar-buffer-body)
1109 (define-key message-mode-map "\C-c\C-o" 'message-sort-headers) 724 (define-key message-mode-map "\C-c\C-o" 'message-sort-headers)
1112 (define-key message-mode-map "\C-c\C-c" 'message-send-and-exit) 727 (define-key message-mode-map "\C-c\C-c" 'message-send-and-exit)
1113 (define-key message-mode-map "\C-c\C-s" 'message-send) 728 (define-key message-mode-map "\C-c\C-s" 'message-send)
1114 (define-key message-mode-map "\C-c\C-k" 'message-kill-buffer) 729 (define-key message-mode-map "\C-c\C-k" 'message-kill-buffer)
1115 (define-key message-mode-map "\C-c\C-d" 'message-dont-send) 730 (define-key message-mode-map "\C-c\C-d" 'message-dont-send)
1116 731
1117 (define-key message-mode-map "\C-c\C-e" 'message-elide-region)
1118
1119 (define-key message-mode-map "\t" 'message-tab)) 732 (define-key message-mode-map "\t" 'message-tab))
1120 733
1121 (easy-menu-define 734 (easy-menu-define message-mode-menu message-mode-map
1122 message-mode-menu message-mode-map "Message Menu." 735 "Message Menu."
1123 '("Message" 736 '("Message"
1124 ["Sort Headers" message-sort-headers t] 737 "Go to Field:"
1125 ["Yank Original" message-yank-original t] 738 "----"
1126 ["Fill Yanked Message" message-fill-yanked-message t] 739 ["To" message-goto-to t]
1127 ["Insert Signature" message-insert-signature t] 740 ["Subject" message-goto-subject t]
1128 ["Caesar (rot13) Message" message-caesar-buffer-body t] 741 ["Cc" message-goto-cc t]
1129 ["Caesar (rot13) Region" message-caesar-region (mark t)] 742 ["Reply-to" message-goto-reply-to t]
1130 ["Elide Region" message-elide-region (mark t)] 743 ["Summary" message-goto-summary t]
1131 ["Rename buffer" message-rename-buffer t] 744 ["Keywords" message-goto-keywords t]
1132 ["Spellcheck" ispell-message t] 745 ["Newsgroups" message-goto-newsgroups t]
1133 "----" 746 ["Followup-To" message-goto-followup-to t]
1134 ["Send Message" message-send-and-exit t] 747 ["Distribution" message-goto-distribution t]
1135 ["Abort Message" message-dont-send t])) 748 ["Body" message-goto-body t]
1136 749 ["Signature" message-goto-signature t]
1137 (easy-menu-define 750 "----"
1138 message-mode-field-menu message-mode-map "" 751 "Miscellaneous Commands:"
1139 '("Field" 752 "----"
1140 ["Fetch To" message-insert-to t] 753 ["Sort Headers" message-sort-headers t]
1141 ["Fetch Newsgroups" message-insert-newsgroups t] 754 ["Yank Original" message-yank-original t]
1142 "----" 755 ["Fill Yanked Message" message-fill-yanked-message t]
1143 ["To" message-goto-to t] 756 ["Insert Signature" message-insert-signature t]
1144 ["Subject" message-goto-subject t] 757 ["Caesar (rot13) Message" message-caesar-buffer-body t]
1145 ["Cc" message-goto-cc t] 758 ["Rename buffer" message-rename-buffer t]
1146 ["Reply-To" message-goto-reply-to t] 759 ["Spellcheck" ispell-message t]
1147 ["Summary" message-goto-summary t] 760 "----"
1148 ["Keywords" message-goto-keywords t] 761 ["Send Message" message-send-and-exit t]
1149 ["Newsgroups" message-goto-newsgroups t] 762 ["Abort Message" message-dont-send t]))
1150 ["Followup-To" message-goto-followup-to t]
1151 ["Distribution" message-goto-distribution t]
1152 ["Body" message-goto-body t]
1153 ["Signature" message-goto-signature t]))
1154 763
1155 (defvar facemenu-add-face-function) 764 (defvar facemenu-add-face-function)
1156 (defvar facemenu-remove-face-function) 765 (defvar facemenu-remove-face-function)
1157 766
1158 ;;;###autoload 767 ;;;###autoload
1161 Like Text Mode but with these additional commands: 770 Like Text Mode but with these additional commands:
1162 C-c C-s message-send (send the message) C-c C-c message-send-and-exit 771 C-c C-s message-send (send the message) C-c C-c message-send-and-exit
1163 C-c C-f move to a header field (and create it if there isn't): 772 C-c C-f move to a header field (and create it if there isn't):
1164 C-c C-f C-t move to To C-c C-f C-s move to Subject 773 C-c C-f C-t move to To C-c C-f C-s move to Subject
1165 C-c C-f C-c move to Cc C-c C-f C-b move to Bcc 774 C-c C-f C-c move to Cc C-c C-f C-b move to Bcc
1166 C-c C-f C-w move to Fcc C-c C-f C-r move to Reply-To 775 C-c C-f C-f move to Fcc C-c C-f C-r move to Reply-To
1167 C-c C-f C-u move to Summary C-c C-f C-n move to Newsgroups 776 C-c C-f C-u move to Summary C-c C-f C-n move to Newsgroups
1168 C-c C-f C-k move to Keywords C-c C-f C-d move to Distribution 777 C-c C-f C-k move to Keywords C-c C-f C-d move to Distribution
1169 C-c C-f C-f move to Followup-To 778 C-c C-f C-o move to Followup-To
1170 C-c C-t message-insert-to (add a To header to a news followup) 779 C-c C-t message-insert-to (add a To header to a news followup)
1171 C-c C-n message-insert-newsgroups (add a Newsgroup header to a news reply) 780 C-c C-n message-insert-newsgroups (add a Newsgroup header to a news reply)
1172 C-c C-b message-goto-body (move to beginning of message text). 781 C-c C-b message-goto-body (move to beginning of message text).
1173 C-c C-i message-goto-signature (move to the beginning of the signature). 782 C-c C-i message-goto-signature (move to the beginning of the signature).
1174 C-c C-w message-insert-signature (insert `message-signature-file' file). 783 C-c C-w message-insert-signature (insert `message-signature-file' file).
1175 C-c C-y message-yank-original (insert current message, if any). 784 C-c C-y message-yank-original (insert current message, if any).
1176 C-c C-q message-fill-yanked-message (fill what was yanked). 785 C-c C-q message-fill-yanked-message (fill what was yanked).
1177 C-c C-e message-elide-region (elide the text between point and mark). 786 C-c C-r message-ceasar-buffer-body (rot13 the message body)."
1178 C-c C-r message-caesar-buffer-body (rot13 the message body)."
1179 (interactive) 787 (interactive)
1180 (kill-all-local-variables) 788 (kill-all-local-variables)
1181 (make-local-variable 'message-reply-buffer) 789 (make-local-variable 'message-reply-buffer)
1182 (setq message-reply-buffer nil) 790 (setq message-reply-buffer nil)
1183 (set (make-local-variable 'message-send-actions) nil) 791 (make-local-variable 'message-send-actions)
1184 (set (make-local-variable 'message-exit-actions) nil) 792 (make-local-variable 'message-exit-actions)
1185 (set (make-local-variable 'message-kill-actions) nil) 793 (make-local-variable 'message-kill-actions)
1186 (set (make-local-variable 'message-postpone-actions) nil) 794 (make-local-variable 'message-postpone-actions)
1187 (set-syntax-table message-mode-syntax-table) 795 (set-syntax-table message-mode-syntax-table)
1188 (use-local-map message-mode-map) 796 (use-local-map message-mode-map)
1189 (setq local-abbrev-table message-mode-abbrev-table) 797 (setq local-abbrev-table message-mode-abbrev-table)
1190 (setq major-mode 'message-mode) 798 (setq major-mode 'message-mode)
1191 (setq mode-name "Message") 799 (setq mode-name "Message")
1224 ;;(when (fboundp 'mail-hist-define-keys) 832 ;;(when (fboundp 'mail-hist-define-keys)
1225 ;; (mail-hist-define-keys)) 833 ;; (mail-hist-define-keys))
1226 (when (string-match "XEmacs\\|Lucid" emacs-version) 834 (when (string-match "XEmacs\\|Lucid" emacs-version)
1227 (message-setup-toolbar)) 835 (message-setup-toolbar))
1228 (easy-menu-add message-mode-menu message-mode-map) 836 (easy-menu-add message-mode-menu message-mode-map)
1229 (easy-menu-add message-mode-field-menu message-mode-map)
1230 ;; Allow mail alias things. 837 ;; Allow mail alias things.
1231 (if (fboundp 'mail-abbrevs-setup) 838 (if (fboundp 'mail-abbrevs-setup)
1232 (mail-abbrevs-setup) 839 (mail-abbrevs-setup)
1233 (funcall (intern "mail-aliases-setup"))) 840 (funcall (intern "mail-aliases-setup")))
1234 (run-hooks 'text-mode-hook 'message-mode-hook)) 841 (run-hooks 'text-mode-hook 'message-mode-hook))
1305 912
1306 (defun message-goto-signature () 913 (defun message-goto-signature ()
1307 "Move point to the beginning of the message signature." 914 "Move point to the beginning of the message signature."
1308 (interactive) 915 (interactive)
1309 (goto-char (point-min)) 916 (goto-char (point-min))
1310 (if (re-search-forward message-signature-separator nil t) 917 (or (re-search-forward message-signature-separator nil t)
1311 (forward-line 1) 918 (goto-char (point-max))))
1312 (goto-char (point-max))))
1313 919
1314 920
1315 921
1316 (defun message-insert-to () 922 (defun message-insert-to ()
1317 "Insert a To header that points to the author of the article being replied to." 923 "Insert a To header that points to the author of the article being replied to."
1318 (interactive) 924 (interactive)
1319 (let ((co (message-fetch-field "courtesy-copies-to")))
1320 (when (and co
1321 (equal (downcase co) "never"))
1322 (error "The user has requested not to have copies sent via mail")))
1323 (when (and (message-position-on-field "To") 925 (when (and (message-position-on-field "To")
1324 (mail-fetch-field "to") 926 (mail-fetch-field "to")
1325 (not (string-match "\\` *\\'" (mail-fetch-field "to")))) 927 (not (string-match "\\` *\\'" (mail-fetch-field "to"))))
1326 (insert ", ")) 928 (insert ", "))
1327 (insert (or (message-fetch-reply-field "reply-to") 929 (insert (or (message-fetch-reply-field "reply-to")
1341 ;;; Various commands 943 ;;; Various commands
1342 944
1343 (defun message-insert-signature (&optional force) 945 (defun message-insert-signature (&optional force)
1344 "Insert a signature. See documentation for the `message-signature' variable." 946 "Insert a signature. See documentation for the `message-signature' variable."
1345 (interactive (list 0)) 947 (interactive (list 0))
1346 (let* ((signature 948 (let* ((signature
1347 (cond 949 (cond ((and (null message-signature)
1348 ((and (null message-signature) 950 (eq force 0))
1349 (eq force 0)) 951 (save-excursion
1350 (save-excursion 952 (goto-char (point-max))
1351 (goto-char (point-max)) 953 (not (re-search-backward
1352 (not (re-search-backward 954 message-signature-separator nil t))))
1353 message-signature-separator nil t)))) 955 ((and (null message-signature)
1354 ((and (null message-signature) 956 force)
1355 force) 957 t)
1356 t) 958 ((message-functionp message-signature)
1357 ((message-functionp message-signature) 959 (funcall message-signature))
1358 (funcall message-signature)) 960 ((listp message-signature)
1359 ((listp message-signature) 961 (eval message-signature))
1360 (eval message-signature)) 962 (t message-signature)))
1361 (t message-signature)))
1362 (signature 963 (signature
1363 (cond ((stringp signature) 964 (cond ((stringp signature)
1364 signature) 965 signature)
1365 ((and (eq t signature) 966 ((and (eq t signature)
1366 message-signature-file 967 message-signature-file
1367 (file-exists-p message-signature-file)) 968 (file-exists-p message-signature-file))
1368 signature)))) 969 signature))))
1369 (when signature 970 (when signature
971 ;; Insert the signature.
1370 (goto-char (point-max)) 972 (goto-char (point-max))
1371 ;; Insert the signature.
1372 (unless (bolp) 973 (unless (bolp)
1373 (insert "\n")) 974 (insert "\n"))
1374 (insert "\n-- \n") 975 (insert "\n-- \n")
1375 (if (eq signature t) 976 (if (eq signature t)
1376 (insert-file-contents message-signature-file) 977 (insert-file-contents message-signature-file)
1377 (insert signature)) 978 (insert signature))
1378 (goto-char (point-max)) 979 (goto-char (point-max))
1379 (or (bolp) (insert "\n"))))) 980 (or (bolp) (insert "\n")))))
1380 981
1381 (defun message-elide-region (b e)
1382 "Elide the text between point and mark. An ellipsis (from
1383 message-elide-elipsis) will be inserted where the text was killed."
1384 (interactive "r")
1385 (kill-region b e)
1386 (unless (bolp)
1387 (insert "\n"))
1388 (insert message-elide-elipsis))
1389
1390 (defvar message-caesar-translation-table nil) 982 (defvar message-caesar-translation-table nil)
1391 983
1392 (defun message-caesar-region (b e &optional n) 984 (defun message-caesar-region (b e &optional n)
1393 "Caesar rotation of region by N, default 13, for decrypting netnews." 985 "Caesar rotation of region by N, default 13, for decrypting netnews."
1394 (interactive 986 (interactive
1402 (unless (or (zerop n) ; no action needed for a rot of 0 994 (unless (or (zerop n) ; no action needed for a rot of 0
1403 (= b e)) ; no region to rotate 995 (= b e)) ; no region to rotate
1404 ;; We build the table, if necessary. 996 ;; We build the table, if necessary.
1405 (when (or (not message-caesar-translation-table) 997 (when (or (not message-caesar-translation-table)
1406 (/= (aref message-caesar-translation-table ?a) (+ ?a n))) 998 (/= (aref message-caesar-translation-table ?a) (+ ?a n)))
1407 (setq message-caesar-translation-table 999 (let ((i -1)
1408 (message-make-caesar-translation-table n))) 1000 (table (make-string 256 0)))
1409 ;; Then we translate the region. Do it this way to retain 1001 (while (< (incf i) 256)
1002 (aset table i i))
1003 (setq table
1004 (concat
1005 (substring table 0 ?A)
1006 (substring table (+ ?A n) (+ ?A n (- 26 n)))
1007 (substring table ?A (+ ?A n))
1008 (substring table (+ ?A 26) ?a)
1009 (substring table (+ ?a n) (+ ?a n (- 26 n)))
1010 (substring table ?a (+ ?a n))
1011 (substring table (+ ?a 26) 255)))
1012 (setq message-caesar-translation-table table)))
1013 ;; Then we translate the region. Do it this way to retain
1410 ;; text properties. 1014 ;; text properties.
1411 (while (< b e) 1015 (while (< b e)
1412 (subst-char-in-region 1016 (subst-char-in-region
1413 b (1+ b) (char-after b) 1017 b (1+ b) (char-after b)
1414 (aref message-caesar-translation-table (char-after b))) 1018 (aref message-caesar-translation-table (char-after b)))
1415 (incf b)))) 1019 (incf b))))
1416
1417 (defun message-make-caesar-translation-table (n)
1418 "Create a rot table with offset N."
1419 (let ((i -1)
1420 (table (make-string 256 0)))
1421 (while (< (incf i) 256)
1422 (aset table i i))
1423 (concat
1424 (substring table 0 ?A)
1425 (substring table (+ ?A n) (+ ?A n (- 26 n)))
1426 (substring table ?A (+ ?A n))
1427 (substring table (+ ?A 26) ?a)
1428 (substring table (+ ?a n) (+ ?a n (- 26 n)))
1429 (substring table ?a (+ ?a n))
1430 (substring table (+ ?a 26) 255))))
1431 1020
1432 (defun message-caesar-buffer-body (&optional rotnum) 1021 (defun message-caesar-buffer-body (&optional rotnum)
1433 "Caesar rotates all letters in the current buffer by 13 places. 1022 "Caesar rotates all letters in the current buffer by 13 places.
1434 Used to encode/decode possibly offensive messages (commonly in net.jokes). 1023 Used to encode/decode possibly offensive messages (commonly in net.jokes).
1435 With prefix arg, specifies the number of places to rotate each letter forward. 1024 With prefix arg, specifies the number of places to rotate each letter forward.
1441 (save-restriction 1030 (save-restriction
1442 (when (message-goto-body) 1031 (when (message-goto-body)
1443 (narrow-to-region (point) (point-max))) 1032 (narrow-to-region (point) (point-max)))
1444 (message-caesar-region (point-min) (point-max) rotnum)))) 1033 (message-caesar-region (point-min) (point-max) rotnum))))
1445 1034
1446 (defun message-pipe-buffer-body (program)
1447 "Pipe the message body in the current buffer through PROGRAM."
1448 (save-excursion
1449 (save-restriction
1450 (when (message-goto-body)
1451 (narrow-to-region (point) (point-max)))
1452 (let ((body (buffer-substring (point-min) (point-max))))
1453 (unless (equal 0 (call-process-region
1454 (point-min) (point-max) program t t))
1455 (insert body)
1456 (message "%s failed." program))))))
1457
1458 (defun message-rename-buffer (&optional enter-string) 1035 (defun message-rename-buffer (&optional enter-string)
1459 "Rename the *message* buffer to \"*message* RECIPIENT\". 1036 "Rename the *message* buffer to \"*message* RECIPIENT\".
1460 If the function is run with a prefix, it will ask for a new buffer 1037 If the function is run with a prefix, it will ask for a new buffer
1461 name, rather than giving an automatic name." 1038 name, rather than giving an automatic name."
1462 (interactive "Pbuffer name: ") 1039 (interactive "Pbuffer name: ")
1463 (save-excursion 1040 (save-excursion
1464 (save-restriction 1041 (save-restriction
1465 (goto-char (point-min)) 1042 (goto-char (point-min))
1466 (narrow-to-region (point) 1043 (narrow-to-region (point)
1467 (search-forward mail-header-separator nil 'end)) 1044 (search-forward mail-header-separator nil 'end))
1468 (let* ((mail-to (or 1045 (let* ((mail-to (if (message-news-p) (message-fetch-field "Newsgroups")
1469 (if (message-news-p) (message-fetch-field "Newsgroups") 1046 (message-fetch-field "To")))
1470 (message-fetch-field "To"))
1471 ""))
1472 (mail-trimmed-to 1047 (mail-trimmed-to
1473 (if (string-match "," mail-to) 1048 (if (string-match "," mail-to)
1474 (concat (substring mail-to 0 (match-beginning 0)) ", ...") 1049 (concat (substring mail-to 0 (match-beginning 0)) ", ...")
1475 mail-to)) 1050 mail-to))
1476 (name-default (concat "*message* " mail-trimmed-to)) 1051 (name-default (concat "*message* " mail-trimmed-to))
1477 (name (if enter-string 1052 (name (if enter-string
1478 (read-string "New buffer name: " name-default) 1053 (read-string "New buffer name: " name-default)
1479 name-default)) 1054 name-default)))
1480 (default-directory 1055 (rename-buffer name t)
1481 (file-name-as-directory message-autosave-directory))) 1056 (setq buffer-auto-save-file-name
1482 (rename-buffer name t))))) 1057 (format "%s%s"
1058 (file-name-as-directory message-autosave-directory)
1059 (file-name-nondirectory buffer-auto-save-file-name)))))))
1483 1060
1484 (defun message-fill-yanked-message (&optional justifyp) 1061 (defun message-fill-yanked-message (&optional justifyp)
1485 "Fill the paragraphs of a message yanked into this one. 1062 "Fill the paragraphs of a message yanked into this one.
1486 Numeric argument means justify as well." 1063 Numeric argument means justify as well."
1487 (interactive "P") 1064 (interactive "P")
1500 However, if `message-yank-prefix' is non-nil, insert that prefix on each line." 1077 However, if `message-yank-prefix' is non-nil, insert that prefix on each line."
1501 (let ((start (point))) 1078 (let ((start (point)))
1502 ;; Remove unwanted headers. 1079 ;; Remove unwanted headers.
1503 (when message-ignored-cited-headers 1080 (when message-ignored-cited-headers
1504 (save-restriction 1081 (save-restriction
1505 (narrow-to-region 1082 (narrow-to-region
1506 (goto-char start) 1083 (goto-char start)
1507 (if (search-forward "\n\n" nil t) 1084 (if (search-forward "\n\n" nil t)
1508 (1- (point)) 1085 (1- (point))
1509 (point))) 1086 (point)))
1510 (message-remove-header message-ignored-cited-headers t) 1087 (message-remove-header message-ignored-cited-headers t)))
1511 (goto-char (point-max))))
1512 ;; Delete blank lines at the start of the buffer.
1513 (while (and (point-min)
1514 (eolp)
1515 (not (eobp)))
1516 (message-delete-line))
1517 ;; Delete blank lines at the end of the buffer.
1518 (goto-char (point-max))
1519 (unless (eolp)
1520 (insert "\n"))
1521 (while (and (zerop (forward-line -1))
1522 (looking-at "$"))
1523 (message-delete-line))
1524 ;; Do the indentation. 1088 ;; Do the indentation.
1525 (if (null message-yank-prefix) 1089 (if (null message-yank-prefix)
1526 (indent-rigidly start (mark t) message-indentation-spaces) 1090 (indent-rigidly start (mark t) message-indentation-spaces)
1527 (save-excursion 1091 (save-excursion
1528 (goto-char start) 1092 (goto-char start)
1529 (while (< (point) (mark t)) 1093 (while (< (point) (mark t))
1530 (insert message-yank-prefix) 1094 (insert message-yank-prefix)
1531 (forward-line 1)))) 1095 (forward-line 1)))
1532 (goto-char start))) 1096 (goto-char start))))
1533 1097
1534 (defun message-yank-original (&optional arg) 1098 (defun message-yank-original (&optional arg)
1535 "Insert the message being replied to, if any. 1099 "Insert the message being replied to, if any.
1536 Puts point before the text and mark after. 1100 Puts point before the text and mark after.
1537 Normally indents each nonblank line ARG spaces (default 3). However, 1101 Normally indents each nonblank line ARG spaces (default 3). However,
1552 (unless (bolp) 1116 (unless (bolp)
1553 (insert ?\n)) 1117 (insert ?\n))
1554 (unless modified 1118 (unless modified
1555 (setq message-checksum (cons (message-checksum) (buffer-size))))))) 1119 (setq message-checksum (cons (message-checksum) (buffer-size)))))))
1556 1120
1557 (defun message-cite-original () 1121 (defun message-cite-original ()
1558 "Cite function in the standard Message manner."
1559 (let ((start (point)) 1122 (let ((start (point))
1560 (functions 1123 (functions
1561 (when message-indent-citation-function 1124 (when message-indent-citation-function
1562 (if (listp message-indent-citation-function) 1125 (if (listp message-indent-citation-function)
1563 message-indent-citation-function 1126 message-indent-citation-function
1564 (list message-indent-citation-function))))) 1127 (list message-indent-citation-function)))))
1565 (goto-char start) 1128 (goto-char start)
1579 (let ((case-fold-search t)) 1142 (let ((case-fold-search t))
1580 (save-restriction 1143 (save-restriction
1581 (narrow-to-region 1144 (narrow-to-region
1582 (goto-char (point-min)) 1145 (goto-char (point-min))
1583 (progn 1146 (progn
1584 (re-search-forward 1147 (re-search-forward
1585 (concat "^" (regexp-quote mail-header-separator) "$")) 1148 (concat "^" (regexp-quote mail-header-separator) "$"))
1586 (match-beginning 0))) 1149 (match-beginning 0)))
1587 (goto-char (point-min)) 1150 (goto-char (point-min))
1588 (if (re-search-forward (concat "^" (regexp-quote header) ":") nil t) 1151 (if (re-search-forward (concat "^" (regexp-quote header) ":") nil t)
1589 (progn 1152 (progn
1590 (re-search-forward "^[^ \t]" nil 'move) 1153 (re-search-forward "^[^ \t]" nil 'move)
1591 (beginning-of-line) 1154 (beginning-of-line)
1592 (skip-chars-backward "\n") 1155 (skip-chars-backward "\n")
1593 t) 1156 t)
1594 (while (and afters 1157 (while (and afters
1595 (not (re-search-forward 1158 (not (re-search-forward
1596 (concat "^" (regexp-quote (car afters)) ":") 1159 (concat "^" (regexp-quote (car afters)) ":")
1597 nil t))) 1160 nil t)))
1598 (pop afters)) 1161 (pop afters))
1599 (when afters 1162 (when afters
1600 (re-search-forward "^[^ \t]" nil 'move) 1163 (re-search-forward "^[^ \t]" nil 'move)
1607 "Remove the signature from the text between point and mark. 1170 "Remove the signature from the text between point and mark.
1608 The text will also be indented the normal way." 1171 The text will also be indented the normal way."
1609 (save-excursion 1172 (save-excursion
1610 (let ((start (point)) 1173 (let ((start (point))
1611 mark) 1174 mark)
1612 (if (not (re-search-forward message-signature-separator (mark t) t)) 1175 (if (not (re-search-forward message-signature-separator (mark t) t))
1613 ;; No signature here, so we just indent the cited text. 1176 ;; No signature here, so we just indent the cited text.
1614 (message-indent-citation)
1615 ;; Find the last non-empty line.
1616 (forward-line -1)
1617 (while (looking-at "[ \t]*$")
1618 (forward-line -1))
1619 (forward-line 1)
1620 (setq mark (set-marker (make-marker) (point)))
1621 (goto-char start)
1622 (message-indent-citation) 1177 (message-indent-citation)
1623 ;; Enable undoing the deletion. 1178 ;; Find the last non-empty line.
1624 (undo-boundary) 1179 (forward-line -1)
1625 (delete-region mark (mark t)) 1180 (while (looking-at "[ \t]*$")
1626 (set-marker mark nil))))) 1181 (forward-line -1))
1182 (forward-line 1)
1183 (setq mark (set-marker (make-marker) (point)))
1184 (goto-char start)
1185 (message-indent-citation)
1186 ;; Enable undoing the deletion.
1187 (undo-boundary)
1188 (delete-region mark (mark t))
1189 (set-marker mark nil)))))
1627 1190
1628 1191
1629 1192
1630 ;;; 1193 ;;;
1631 ;;; Sending messages 1194 ;;; Sending messages
1646 (message-do-actions actions)))) 1209 (message-do-actions actions))))
1647 1210
1648 (defun message-dont-send () 1211 (defun message-dont-send ()
1649 "Don't send the message you have been editing." 1212 "Don't send the message you have been editing."
1650 (interactive) 1213 (interactive)
1651 (let ((actions message-postpone-actions)) 1214 (message-bury (current-buffer))
1652 (message-bury (current-buffer)) 1215 (message-do-actions message-postpone-actions))
1653 (message-do-actions actions)))
1654 1216
1655 (defun message-kill-buffer () 1217 (defun message-kill-buffer ()
1656 "Kill the current buffer." 1218 "Kill the current buffer."
1657 (interactive) 1219 (interactive)
1658 (when (or (not (buffer-modified-p)) 1220 (let ((actions message-kill-actions))
1659 (yes-or-no-p "Message modified; kill anyway? ")) 1221 (kill-buffer (current-buffer))
1660 (let ((actions message-kill-actions)) 1222 (message-do-actions actions)))
1661 (kill-buffer (current-buffer))
1662 (message-do-actions actions))))
1663 1223
1664 (defun message-bury (buffer) 1224 (defun message-bury (buffer)
1665 "Bury this mail buffer." 1225 "Bury this mail buffer."
1666 (let ((newbuf (other-buffer buffer))) 1226 (let ((newbuf (other-buffer buffer)))
1667 (bury-buffer buffer) 1227 (bury-buffer buffer)
1733 1293
1734 (defun message-do-actions (actions) 1294 (defun message-do-actions (actions)
1735 "Perform all actions in ACTIONS." 1295 "Perform all actions in ACTIONS."
1736 ;; Now perform actions on successful sending. 1296 ;; Now perform actions on successful sending.
1737 (while actions 1297 (while actions
1738 (ignore-errors 1298 (condition-case nil
1739 (cond 1299 (cond
1740 ;; A simple function. 1300 ;; A simple function.
1741 ((message-functionp (car actions)) 1301 ((message-functionp (car actions))
1742 (funcall (car actions))) 1302 (funcall (car actions)))
1743 ;; Something to be evaled. 1303 ;; Something to be evaled.
1744 (t 1304 (t
1745 (eval (car actions))))) 1305 (eval (car actions))))
1306 (error))
1746 (pop actions))) 1307 (pop actions)))
1747 1308
1748 (defun message-send-mail (&optional arg) 1309 (defun message-send-mail (&optional arg)
1749 (require 'mail-utils) 1310 (require 'mail-utils)
1750 (let ((tembuf (message-generate-new-buffer-clone-locals " message temp")) 1311 (let ((tembuf (generate-new-buffer " message temp"))
1751 (case-fold-search nil) 1312 (case-fold-search nil)
1752 (news (message-news-p)) 1313 (news (message-news-p))
1753 (mailbuf (current-buffer))) 1314 (mailbuf (current-buffer)))
1754 (save-restriction 1315 (save-restriction
1755 (message-narrow-to-headers) 1316 (message-narrow-to-headers)
1762 (unwind-protect 1323 (unwind-protect
1763 (save-excursion 1324 (save-excursion
1764 (set-buffer tembuf) 1325 (set-buffer tembuf)
1765 (erase-buffer) 1326 (erase-buffer)
1766 ;; Avoid copying text props. 1327 ;; Avoid copying text props.
1767 (insert (format 1328 (insert (format
1768 "%s" (save-excursion 1329 "%s" (save-excursion
1769 (set-buffer mailbuf) 1330 (set-buffer mailbuf)
1770 (buffer-string)))) 1331 (buffer-string))))
1771 ;; Remove some headers. 1332 ;; Remove some headers.
1772 (save-restriction 1333 (save-restriction
1801 (re-search-forward 1362 (re-search-forward
1802 (concat "^" (regexp-quote mail-header-separator) "\n")) 1363 (concat "^" (regexp-quote mail-header-separator) "\n"))
1803 (replace-match "\n") 1364 (replace-match "\n")
1804 (backward-char 1) 1365 (backward-char 1)
1805 (setq delimline (point-marker)) 1366 (setq delimline (point-marker))
1806 (run-hooks 'message-send-mail-hook)
1807 ;; Insert an extra newline if we need it to work around 1367 ;; Insert an extra newline if we need it to work around
1808 ;; Sun's bug that swallows newlines. 1368 ;; Sun's bug that swallows newlines.
1809 (goto-char (1+ delimline)) 1369 (goto-char (1+ delimline))
1810 (when (eval message-mailer-swallows-blank-line) 1370 (when (eval message-mailer-swallows-blank-line)
1811 (newline)) 1371 (newline))
1820 sendmail-program 1380 sendmail-program
1821 "/usr/lib/sendmail") 1381 "/usr/lib/sendmail")
1822 nil errbuf nil "-oi") 1382 nil errbuf nil "-oi")
1823 ;; Always specify who from, 1383 ;; Always specify who from,
1824 ;; since some systems have broken sendmails. 1384 ;; since some systems have broken sendmails.
1825 ;; But some systems are more broken with -f, so 1385 (list "-f" (user-login-name))
1826 ;; we'll let users override this.
1827 (if (null message-sendmail-f-is-evil)
1828 (list "-f" (user-login-name)))
1829 ;; These mean "report errors by mail" 1386 ;; These mean "report errors by mail"
1830 ;; and "deliver in background". 1387 ;; and "deliver in background".
1831 (if (null message-interactive) '("-oem" "-odb")) 1388 (if (null message-interactive) '("-oem" "-odb"))
1832 ;; Get the addresses from the message 1389 ;; Get the addresses from the message
1833 ;; unless this is a resend. 1390 ;; unless this is a resend.
1847 (error "Sending...failed to %s" 1404 (error "Sending...failed to %s"
1848 (buffer-substring (point-min) (point-max))))) 1405 (buffer-substring (point-min) (point-max)))))
1849 (when (bufferp errbuf) 1406 (when (bufferp errbuf)
1850 (kill-buffer errbuf))))) 1407 (kill-buffer errbuf)))))
1851 1408
1852 (defun message-send-mail-with-qmail ()
1853 "Pass the prepared message buffer to qmail-inject.
1854 Refer to the documentation for the variable `message-send-mail-function'
1855 to find out how to use this."
1856 ;; replace the header delimiter with a blank line
1857 (goto-char (point-min))
1858 (re-search-forward
1859 (concat "^" (regexp-quote mail-header-separator) "\n"))
1860 (replace-match "\n")
1861 (run-hooks 'message-send-mail-hook)
1862 ;; send the message
1863 (case
1864 (apply
1865 'call-process-region 1 (point-max) message-qmail-inject-program
1866 nil nil nil
1867 ;; qmail-inject's default behaviour is to look for addresses on the
1868 ;; command line; if there're none, it scans the headers.
1869 ;; yes, it does The Right Thing w.r.t. Resent-To and it's kin.
1870 ;;
1871 ;; in general, ALL of qmail-inject's defaults are perfect for simply
1872 ;; reading a formatted (i. e., at least a To: or Resent-To header)
1873 ;; message from stdin.
1874 ;;
1875 ;; qmail also has the advantage of not having been raped by
1876 ;; various vendors, so we don't have to allow for that, either --
1877 ;; compare this with message-send-mail-with-sendmail and weep
1878 ;; for sendmail's lost innocence.
1879 ;;
1880 ;; all this is way cool coz it lets us keep the arguments entirely
1881 ;; free for -inject-arguments -- a big win for the user and for us
1882 ;; since we don't have to play that double-guessing game and the user
1883 ;; gets full control (no gestapo'ish -f's, for instance). --sj
1884 message-qmail-inject-args)
1885 ;; qmail-inject doesn't say anything on it's stdout/stderr,
1886 ;; we have to look at the retval instead
1887 (0 nil)
1888 (1 (error "qmail-inject reported permanent failure."))
1889 (111 (error "qmail-inject reported transient failure."))
1890 ;; should never happen
1891 (t (error "qmail-inject reported unknown failure."))))
1892
1893 (defun message-send-mail-with-mh () 1409 (defun message-send-mail-with-mh ()
1894 "Send the prepared message buffer with mh." 1410 "Send the prepared message buffer with mh."
1895 (let ((mh-previous-window-config nil) 1411 (let ((mh-previous-window-config nil)
1896 (name (make-temp-name 1412 (name (make-temp-name
1897 (concat (file-name-as-directory 1413 (concat (file-name-as-directory message-autosave-directory)
1898 (expand-file-name message-autosave-directory))
1899 "msg.")))) 1414 "msg."))))
1900 (setq buffer-file-name name) 1415 (setq buffer-file-name name)
1901 ;; MH wants to generate these headers itself. 1416 (mh-send-letter)
1902 (when message-mh-deletable-headers 1417 (condition-case ()
1903 (let ((headers message-mh-deletable-headers)) 1418 (delete-file name)
1904 (while headers 1419 (error nil))))
1905 (goto-char (point-min))
1906 (and (re-search-forward
1907 (concat "^" (symbol-name (car headers)) ": *") nil t)
1908 (message-delete-line))
1909 (pop headers))))
1910 (run-hooks 'message-send-mail-hook)
1911 ;; Pass it on to mh.
1912 (mh-send-letter)))
1913 1420
1914 (defun message-send-news (&optional arg) 1421 (defun message-send-news (&optional arg)
1915 (let ((tembuf (message-generate-new-buffer-clone-locals " *message temp*")) 1422 (let ((tembuf (generate-new-buffer " *message temp*"))
1916 (case-fold-search nil) 1423 (case-fold-search nil)
1917 (method (if (message-functionp message-post-method) 1424 (method (if (message-functionp message-post-method)
1918 (funcall message-post-method arg) 1425 (funcall message-post-method arg)
1919 message-post-method)) 1426 message-post-method))
1920 (messbuf (current-buffer)) 1427 (messbuf (current-buffer))
1929 ;; Insert some headers. 1436 ;; Insert some headers.
1930 (message-generate-headers message-required-news-headers) 1437 (message-generate-headers message-required-news-headers)
1931 ;; Let the user do all of the above. 1438 ;; Let the user do all of the above.
1932 (run-hooks 'message-header-hook)) 1439 (run-hooks 'message-header-hook))
1933 (message-cleanup-headers) 1440 (message-cleanup-headers)
1934 (if (not (message-check-news-syntax)) 1441 (when (message-check-news-syntax)
1935 (progn
1936 ;;(message "Posting not performed")
1937 nil)
1938 (unwind-protect 1442 (unwind-protect
1939 (save-excursion 1443 (save-excursion
1940 (set-buffer tembuf) 1444 (set-buffer tembuf)
1941 (buffer-disable-undo (current-buffer)) 1445 (buffer-disable-undo (current-buffer))
1942 (erase-buffer) 1446 (erase-buffer)
1943 ;; Avoid copying text props. 1447 ;; Avoid copying text props.
1944 (insert (format 1448 (insert (format
1945 "%s" (save-excursion 1449 "%s" (save-excursion
1946 (set-buffer messbuf) 1450 (set-buffer messbuf)
1947 (buffer-string)))) 1451 (buffer-string))))
1948 ;; Remove some headers. 1452 ;; Remove some headers.
1949 (save-restriction 1453 (save-restriction
1950 (message-narrow-to-headers) 1454 (message-narrow-to-headers)
1951 ;; Remove some headers. 1455 ;; Remove some headers.
1952 (message-remove-header message-ignored-news-headers t)) 1456 (message-remove-header message-ignored-news-headers t))
1953 (goto-char (point-max)) 1457 (goto-char (point-max))
1954 ;; require one newline at the end. 1458 ;; require one newline at the end.
1955 (or (= (preceding-char) ?\n) 1459 (or (= (preceding-char) ?\n)
1956 (insert ?\n)) 1460 (insert ?\n))
1957 (let ((case-fold-search t)) 1461 (let ((case-fold-search t))
1958 ;; Remove the delimiter. 1462 ;; Remove the delimeter.
1959 (goto-char (point-min)) 1463 (goto-char (point-min))
1960 (re-search-forward 1464 (re-search-forward
1961 (concat "^" (regexp-quote mail-header-separator) "\n")) 1465 (concat "^" (regexp-quote mail-header-separator) "\n"))
1962 (replace-match "\n") 1466 (replace-match "\n")
1963 (backward-char 1)) 1467 (backward-char 1))
1964 (run-hooks 'message-send-news-hook)
1965 (require (car method)) 1468 (require (car method))
1966 (funcall (intern (format "%s-open-server" (car method))) 1469 (funcall (intern (format "%s-open-server" (car method)))
1967 (cadr method) (cddr method)) 1470 (cadr method) (cddr method))
1968 (setq result 1471 (setq result
1969 (funcall (intern (format "%s-request-post" (car method)))))) 1472 (funcall (intern (format "%s-request-post" (car method))))))
1977 1480
1978 ;;; 1481 ;;;
1979 ;;; Header generation & syntax checking. 1482 ;;; Header generation & syntax checking.
1980 ;;; 1483 ;;;
1981 1484
1982 (defmacro message-check (type &rest forms) 1485 (defun message-check-news-syntax ()
1983 "Eval FORMS if TYPE is to be checked." 1486 "Check the syntax of the message."
1984 `(or (message-check-element ,type) 1487 (and
1488 ;; We narrow to the headers and check them first.
1489 (save-excursion
1490 (save-restriction
1491 (message-narrow-to-headers)
1492 (and
1493 ;; Check for commands in Subject.
1494 (or
1495 (message-check-element 'subject-cmsg)
1496 (save-excursion
1497 (if (string-match "^cmsg " (message-fetch-field "subject"))
1498 (y-or-n-p
1499 "The control code \"cmsg \" is in the subject. Really post? ")
1500 t)))
1501 ;; Check for multiple identical headers.
1502 (or (message-check-element 'multiple-headers)
1503 (save-excursion
1504 (let (found)
1505 (while (and (not found)
1506 (re-search-forward "^[^ \t:]+: " nil t))
1507 (save-excursion
1508 (or (re-search-forward
1509 (concat "^" (setq found
1510 (buffer-substring
1511 (match-beginning 0)
1512 (- (match-end 0) 2))))
1513 nil t)
1514 (setq found nil))))
1515 (if found
1516 (y-or-n-p
1517 (format "Multiple %s headers. Really post? " found))
1518 t))))
1519 ;; Check for Version and Sendsys.
1520 (or (message-check-element 'sendsys)
1521 (save-excursion
1522 (if (re-search-forward "^Sendsys:\\|^Version:" nil t)
1523 (y-or-n-p
1524 (format "The article contains a %s command. Really post? "
1525 (buffer-substring (match-beginning 0)
1526 (1- (match-end 0)))))
1527 t)))
1528 ;; See whether we can shorten Followup-To.
1529 (or (message-check-element 'shorten-followup-to)
1530 (let ((newsgroups (message-fetch-field "newsgroups"))
1531 (followup-to (message-fetch-field "followup-to"))
1532 to)
1533 (when (and newsgroups (string-match "," newsgroups)
1534 (not followup-to)
1535 (not
1536 (zerop
1537 (length
1538 (setq to (completing-read
1539 "Followups to: (default all groups) "
1540 (mapcar (lambda (g) (list g))
1541 (cons "poster"
1542 (message-tokenize-header
1543 newsgroups)))))))))
1544 (goto-char (point-min))
1545 (insert "Followup-To: " to "\n"))
1546 t))
1547 ;; Check "Shoot me".
1548 (or (message-check-element 'shoot)
1549 (save-excursion
1550 (if (re-search-forward
1551 "Message-ID.*.i-have-a-misconfigured-system-so-shoot-me"
1552 nil t)
1553 (y-or-n-p
1554 "You appear to have a misconfigured system. Really post? ")
1555 t)))
1556 ;; Check for Approved.
1557 (or (message-check-element 'approved)
1558 (save-excursion
1559 (if (re-search-forward "^Approved:" nil t)
1560 (y-or-n-p
1561 "The article contains an Approved header. Really post? ")
1562 t)))
1563 ;; Check the Message-Id header.
1564 (or (message-check-element 'message-id)
1565 (save-excursion
1566 (let* ((case-fold-search t)
1567 (message-id (message-fetch-field "message-id")))
1568 (or (not message-id)
1569 (and (string-match "@" message-id)
1570 (string-match "@[^\\.]*\\." message-id))
1571 (y-or-n-p
1572 (format
1573 "The Message-ID looks strange: \"%s\". Really post? "
1574 message-id))))))
1575 ;; Check the Subject header.
1576 (or
1577 (message-check-element 'subject)
1578 (save-excursion
1579 (let* ((case-fold-search t)
1580 (subject (message-fetch-field "subject")))
1581 (or
1582 (and subject
1583 (not (string-match "\\`[ \t]*\\'" subject)))
1584 (progn
1585 (message
1586 "The subject field is empty or missing. Posting is denied.")
1587 nil)))))
1588 ;; Check the Newsgroups & Followup-To headers.
1589 (or
1590 (message-check-element 'existing-newsgroups)
1591 (let* ((case-fold-search t)
1592 (newsgroups (message-fetch-field "newsgroups"))
1593 (followup-to (message-fetch-field "followup-to"))
1594 (groups (message-tokenize-header
1595 (if followup-to
1596 (concat newsgroups "," followup-to)
1597 newsgroups)))
1598 (hashtb (and (boundp 'gnus-active-hashtb)
1599 gnus-active-hashtb))
1600 errors)
1601 (if (not hashtb)
1602 t
1603 (while groups
1604 (when (and (not (boundp (intern (car groups) hashtb)))
1605 (not (equal (car groups) "poster")))
1606 (push (car groups) errors))
1607 (pop groups))
1608 (if (not errors)
1609 t
1610 (y-or-n-p
1611 (format
1612 "Really post to %s unknown group%s: %s "
1613 (if (= (length errors) 1) "this" "these")
1614 (if (= (length errors) 1) "" "s")
1615 (mapconcat 'identity errors ", ")))))))
1616 ;; Check the Newsgroups & Followup-To headers for syntax errors.
1617 (or
1618 (message-check-element 'valid-newsgroups)
1619 (let ((case-fold-search t)
1620 (headers '("Newsgroups" "Followup-To"))
1621 header error)
1622 (while (and headers (not error))
1623 (when (setq header (mail-fetch-field (car headers)))
1624 (if (or
1625 (not
1626 (string-match
1627 "\\`\\([-+_&.a-zA-Z0-9]+\\)?\\(,[-.a-zA-Z0-9]+\\)*\\'"
1628 header))
1629 (memq
1630 nil (mapcar
1631 (lambda (g)
1632 (not (string-match "\\.\\'\\|\\.\\." g)))
1633 (message-tokenize-header header ","))))
1634 (setq error t)))
1635 (unless error
1636 (pop headers)))
1637 (if (not error)
1638 t
1639 (y-or-n-p
1640 (format "The %s header looks odd: \"%s\". Really post? "
1641 (car headers) header)))))
1642 ;; Check the From header.
1643 (or
1644 (save-excursion
1645 (let* ((case-fold-search t)
1646 (from (message-fetch-field "from")))
1647 (cond
1648 ((not from)
1649 (message "There is no From line. Posting is denied.")
1650 nil)
1651 ((not (string-match "@[^\\.]*\\." from))
1652 (message
1653 "Denied posting -- the From looks strange: \"%s\"." from)
1654 nil)
1655 ((string-match "@[^@]*@" from)
1656 (message
1657 "Denied posting -- two \"@\"'s in the From header: %s." from)
1658 nil)
1659 ((string-match "(.*).*(.*)" from)
1660 (message
1661 "Denied posting -- the From header looks strange: \"%s\"."
1662 from)
1663 nil)
1664 (t t))))))))
1665 ;; Check for long lines.
1666 (or (message-check-element 'long-lines)
1985 (save-excursion 1667 (save-excursion
1986 ,@forms))) 1668 (goto-char (point-min))
1987 1669 (re-search-forward
1988 (put 'message-check 'lisp-indent-function 1) 1670 (concat "^" (regexp-quote mail-header-separator) "$"))
1989 (put 'message-check 'edebug-form-spec '(form body)) 1671 (while (and
1672 (progn
1673 (end-of-line)
1674 (< (current-column) 80))
1675 (zerop (forward-line 1))))
1676 (or (bolp)
1677 (eobp)
1678 (y-or-n-p
1679 "You have lines longer than 79 characters. Really post? "))))
1680 ;; Check whether the article is empty.
1681 (or (message-check-element 'empty)
1682 (save-excursion
1683 (goto-char (point-min))
1684 (re-search-forward
1685 (concat "^" (regexp-quote mail-header-separator) "$"))
1686 (forward-line 1)
1687 (let ((b (point)))
1688 (goto-char (point-max))
1689 (re-search-backward message-signature-separator nil t)
1690 (beginning-of-line)
1691 (or (re-search-backward "[^ \n\t]" b t)
1692 (y-or-n-p "Empty article. Really post? ")))))
1693 ;; Check for control characters.
1694 (or (message-check-element 'control-chars)
1695 (save-excursion
1696 (if (re-search-forward "[\000-\007\013\015-\037\200-\237]" nil t)
1697 (y-or-n-p
1698 "The article contains control characters. Really post? ")
1699 t)))
1700 ;; Check excessive size.
1701 (or (message-check-element 'size)
1702 (if (> (buffer-size) 60000)
1703 (y-or-n-p
1704 (format "The article is %d octets long. Really post? "
1705 (buffer-size)))
1706 t))
1707 ;; Check whether any new text has been added.
1708 (or (message-check-element 'new-text)
1709 (not message-checksum)
1710 (not (and (eq (message-checksum) (car message-checksum))
1711 (eq (buffer-size) (cdr message-checksum))))
1712 (y-or-n-p
1713 "It looks like no new text has been added. Really post? "))
1714 ;; Check the length of the signature.
1715 (or
1716 (message-check-element 'signature)
1717 (progn
1718 (goto-char (point-max))
1719 (if (or (not (re-search-backward message-signature-separator nil t))
1720 (search-forward message-forward-end-separator nil t))
1721 t
1722 (if (> (count-lines (point) (point-max)) 5)
1723 (y-or-n-p
1724 (format
1725 "Your .sig is %d lines; it should be max 4. Really post? "
1726 (count-lines (point) (point-max))))
1727 t))))))
1990 1728
1991 (defun message-check-element (type) 1729 (defun message-check-element (type)
1992 "Returns non-nil if this type is not to be checked." 1730 "Returns non-nil if this type is not to be checked."
1993 (if (eq message-syntax-checks 'dont-check-for-anything-just-trust-me) 1731 (if (eq message-syntax-checks 'dont-check-for-anything-just-trust-me)
1994 t 1732 t
1995 (let ((able (assq type message-syntax-checks))) 1733 (let ((able (assq type message-syntax-checks)))
1996 (and (consp able) 1734 (and (consp able)
1997 (eq (cdr able) 'disabled))))) 1735 (eq (cdr able) 'disabled)))))
1998
1999 (defun message-check-news-syntax ()
2000 "Check the syntax of the message."
2001 (save-excursion
2002 (save-restriction
2003 (widen)
2004 (and
2005 ;; We narrow to the headers and check them first.
2006 (save-excursion
2007 (save-restriction
2008 (message-narrow-to-headers)
2009 (message-check-news-header-syntax)))
2010 ;; Check the body.
2011 (message-check-news-body-syntax)))))
2012
2013 (defun message-check-news-header-syntax ()
2014 (and
2015 ;; Check for commands in Subject.
2016 (message-check 'subject-cmsg
2017 (if (string-match "^cmsg " (message-fetch-field "subject"))
2018 (y-or-n-p
2019 "The control code \"cmsg\" is in the subject. Really post? ")
2020 t))
2021 ;; Check for multiple identical headers.
2022 (message-check 'multiple-headers
2023 (let (found)
2024 (while (and (not found)
2025 (re-search-forward "^[^ \t:]+: " nil t))
2026 (save-excursion
2027 (or (re-search-forward
2028 (concat "^"
2029 (regexp-quote
2030 (setq found
2031 (buffer-substring
2032 (match-beginning 0) (- (match-end 0) 2))))
2033 ":")
2034 nil t)
2035 (setq found nil))))
2036 (if found
2037 (y-or-n-p (format "Multiple %s headers. Really post? " found))
2038 t)))
2039 ;; Check for Version and Sendsys.
2040 (message-check 'sendsys
2041 (if (re-search-forward "^Sendsys:\\|^Version:" nil t)
2042 (y-or-n-p
2043 (format "The article contains a %s command. Really post? "
2044 (buffer-substring (match-beginning 0)
2045 (1- (match-end 0)))))
2046 t))
2047 ;; See whether we can shorten Followup-To.
2048 (message-check 'shorten-followup-to
2049 (let ((newsgroups (message-fetch-field "newsgroups"))
2050 (followup-to (message-fetch-field "followup-to"))
2051 to)
2052 (when (and newsgroups
2053 (string-match "," newsgroups)
2054 (not followup-to)
2055 (not
2056 (zerop
2057 (length
2058 (setq to (completing-read
2059 "Followups to: (default all groups) "
2060 (mapcar (lambda (g) (list g))
2061 (cons "poster"
2062 (message-tokenize-header
2063 newsgroups)))))))))
2064 (goto-char (point-min))
2065 (insert "Followup-To: " to "\n"))
2066 t))
2067 ;; Check "Shoot me".
2068 (message-check 'shoot
2069 (if (re-search-forward
2070 "Message-ID.*.i-did-not-set--mail-host-address--so-shoot-me" nil t)
2071 (y-or-n-p "You appear to have a misconfigured system. Really post? ")
2072 t))
2073 ;; Check for Approved.
2074 (message-check 'approved
2075 (if (re-search-forward "^Approved:" nil t)
2076 (y-or-n-p "The article contains an Approved header. Really post? ")
2077 t))
2078 ;; Check the Message-ID header.
2079 (message-check 'message-id
2080 (let* ((case-fold-search t)
2081 (message-id (message-fetch-field "message-id" t)))
2082 (or (not message-id)
2083 (and (string-match "@" message-id)
2084 (string-match "@[^\\.]*\\." message-id))
2085 (y-or-n-p
2086 (format "The Message-ID looks strange: \"%s\". Really post? "
2087 message-id)))))
2088 ;; Check the Subject header.
2089 (message-check 'subject
2090 (let* ((case-fold-search t)
2091 (subject (message-fetch-field "subject")))
2092 (or
2093 (and subject
2094 (not (string-match "\\`[ \t]*\\'" subject)))
2095 (ignore
2096 (message
2097 "The subject field is empty or missing. Posting is denied.")))))
2098 ;; Check the Newsgroups & Followup-To headers.
2099 (message-check 'existing-newsgroups
2100 (let* ((case-fold-search t)
2101 (newsgroups (message-fetch-field "newsgroups"))
2102 (followup-to (message-fetch-field "followup-to"))
2103 (groups (message-tokenize-header
2104 (if followup-to
2105 (concat newsgroups "," followup-to)
2106 newsgroups)))
2107 (hashtb (and (boundp 'gnus-active-hashtb)
2108 gnus-active-hashtb))
2109 errors)
2110 (if (or (not hashtb)
2111 (not (boundp 'gnus-read-active-file))
2112 (not gnus-read-active-file)
2113 (eq gnus-read-active-file 'some))
2114 t
2115 (while groups
2116 (when (and (not (boundp (intern (car groups) hashtb)))
2117 (not (equal (car groups) "poster")))
2118 (push (car groups) errors))
2119 (pop groups))
2120 (if (not errors)
2121 t
2122 (y-or-n-p
2123 (format
2124 "Really post to %s unknown group%s: %s "
2125 (if (= (length errors) 1) "this" "these")
2126 (if (= (length errors) 1) "" "s")
2127 (mapconcat 'identity errors ", ")))))))
2128 ;; Check the Newsgroups & Followup-To headers for syntax errors.
2129 (message-check 'valid-newsgroups
2130 (let ((case-fold-search t)
2131 (headers '("Newsgroups" "Followup-To"))
2132 header error)
2133 (while (and headers (not error))
2134 (when (setq header (mail-fetch-field (car headers)))
2135 (if (or
2136 (not
2137 (string-match
2138 "\\`\\([-+_&.a-zA-Z0-9]+\\)?\\(,[-+_&.a-zA-Z0-9]+\\)*\\'"
2139 header))
2140 (memq
2141 nil (mapcar
2142 (lambda (g)
2143 (not (string-match "\\.\\'\\|\\.\\." g)))
2144 (message-tokenize-header header ","))))
2145 (setq error t)))
2146 (unless error
2147 (pop headers)))
2148 (if (not error)
2149 t
2150 (y-or-n-p
2151 (format "The %s header looks odd: \"%s\". Really post? "
2152 (car headers) header)))))
2153 ;; Check the From header.
2154 (message-check 'from
2155 (let* ((case-fold-search t)
2156 (from (message-fetch-field "from"))
2157 (ad (nth 1 (mail-extract-address-components from))))
2158 (cond
2159 ((not from)
2160 (message "There is no From line. Posting is denied.")
2161 nil)
2162 ((or (not (string-match "@[^\\.]*\\." ad)) ;larsi@ifi
2163 (string-match "\\.\\." ad) ;larsi@ifi..uio
2164 (string-match "@\\." ad) ;larsi@.ifi.uio
2165 (string-match "\\.$" ad) ;larsi@ifi.uio.
2166 (not (string-match "^[^@]+@[^@]+$" ad)) ;larsi.ifi.uio
2167 (string-match "(.*).*(.*)" from)) ;(lars) (lars)
2168 (message
2169 "Denied posting -- the From looks strange: \"%s\"." from)
2170 nil)
2171 (t t))))))
2172
2173 (defun message-check-news-body-syntax ()
2174 (and
2175 ;; Check for long lines.
2176 (message-check 'long-lines
2177 (goto-char (point-min))
2178 (re-search-forward
2179 (concat "^" (regexp-quote mail-header-separator) "$"))
2180 (while (and
2181 (progn
2182 (end-of-line)
2183 (< (current-column) 80))
2184 (zerop (forward-line 1))))
2185 (or (bolp)
2186 (eobp)
2187 (y-or-n-p
2188 "You have lines longer than 79 characters. Really post? ")))
2189 ;; Check whether the article is empty.
2190 (message-check 'empty
2191 (goto-char (point-min))
2192 (re-search-forward
2193 (concat "^" (regexp-quote mail-header-separator) "$"))
2194 (forward-line 1)
2195 (let ((b (point)))
2196 (goto-char (point-max))
2197 (re-search-backward message-signature-separator nil t)
2198 (beginning-of-line)
2199 (or (re-search-backward "[^ \n\t]" b t)
2200 (y-or-n-p "Empty article. Really post? "))))
2201 ;; Check for control characters.
2202 (message-check 'control-chars
2203 (if (re-search-forward "[\000-\007\013\015-\037\200-\237]" nil t)
2204 (y-or-n-p
2205 "The article contains control characters. Really post? ")
2206 t))
2207 ;; Check excessive size.
2208 (message-check 'size
2209 (if (> (buffer-size) 60000)
2210 (y-or-n-p
2211 (format "The article is %d octets long. Really post? "
2212 (buffer-size)))
2213 t))
2214 ;; Check whether any new text has been added.
2215 (message-check 'new-text
2216 (or
2217 (not message-checksum)
2218 (not (and (eq (message-checksum) (car message-checksum))
2219 (eq (buffer-size) (cdr message-checksum))))
2220 (y-or-n-p
2221 "It looks like no new text has been added. Really post? ")))
2222 ;; Check the length of the signature.
2223 (message-check 'signature
2224 (goto-char (point-max))
2225 (if (or (not (re-search-backward message-signature-separator nil t))
2226 (search-forward message-forward-end-separator nil t))
2227 t
2228 (if (> (count-lines (point) (point-max)) 5)
2229 (y-or-n-p
2230 (format
2231 "Your .sig is %d lines; it should be max 4. Really post? "
2232 (1- (count-lines (point) (point-max)))))
2233 t)))))
2234 1736
2235 (defun message-checksum () 1737 (defun message-checksum ()
2236 "Return a \"checksum\" for the current buffer." 1738 "Return a \"checksum\" for the current buffer."
2237 (let ((sum 0)) 1739 (let ((sum 0))
2238 (save-excursion 1740 (save-excursion
2280 (funcall message-fcc-handler-function file) 1782 (funcall message-fcc-handler-function file)
2281 (if (and (file-readable-p file) (mail-file-babyl-p file)) 1783 (if (and (file-readable-p file) (mail-file-babyl-p file))
2282 (rmail-output file 1 nil t) 1784 (rmail-output file 1 nil t)
2283 (let ((mail-use-rfc822 t)) 1785 (let ((mail-use-rfc822 t))
2284 (rmail-output file 1 t t)))))) 1786 (rmail-output file 1 t t))))))
2285
2286 (kill-buffer (current-buffer))))) 1787 (kill-buffer (current-buffer)))))
2287
2288 (defun message-output (filename)
2289 "Append this article to Unix/babyl mail file.."
2290 (if (and (file-readable-p filename)
2291 (mail-file-babyl-p filename))
2292 (gnus-output-to-rmail filename t)
2293 (gnus-output-to-mail filename t)))
2294 1788
2295 (defun message-cleanup-headers () 1789 (defun message-cleanup-headers ()
2296 "Do various automatic cleanups of the headers." 1790 "Do various automatic cleanups of the headers."
2297 ;; Remove empty lines in the header. 1791 ;; Remove empty lines in the header.
2298 (save-restriction 1792 (save-restriction
2324 (replace-match "" t t))))) 1818 (replace-match "" t t)))))
2325 1819
2326 (defun message-make-date () 1820 (defun message-make-date ()
2327 "Make a valid data header." 1821 "Make a valid data header."
2328 (let ((now (current-time))) 1822 (let ((now (current-time)))
2329 (timezone-make-date-arpa-standard 1823 (timezone-make-date-arpa-standard
2330 (current-time-string now) (current-time-zone now)))) 1824 (current-time-string now) (current-time-zone now))))
2331 1825
2332 (defun message-make-message-id () 1826 (defun message-make-message-id ()
2333 "Make a unique Message-ID." 1827 "Make a unique Message-ID."
2334 (concat "<" (message-unique-id) 1828 (concat "<" (message-unique-id)
2335 (let ((psubject (save-excursion (message-fetch-field "subject")))) 1829 (let ((psubject (save-excursion (message-fetch-field "subject"))))
2336 (if (and message-reply-headers 1830 (if (and message-reply-headers
2337 (mail-header-references message-reply-headers) 1831 (mail-header-references message-reply-headers)
2338 (mail-header-subject message-reply-headers) 1832 (mail-header-subject message-reply-headers)
2339 psubject 1833 psubject
2340 (mail-header-subject message-reply-headers) 1834 (mail-header-subject message-reply-headers)
2341 (not (string= 1835 (not (string=
2342 (message-strip-subject-re 1836 (message-strip-subject-re
2343 (mail-header-subject message-reply-headers)) 1837 (mail-header-subject message-reply-headers))
2344 (message-strip-subject-re psubject)))) 1838 (message-strip-subject-re psubject))))
2345 "_-_" "")) 1839 "_-_" ""))
2346 "@" (message-make-fqdn) ">")) 1840 "@" (message-make-fqdn) ">"))
2365 (let ((user (downcase (user-login-name)))) 1859 (let ((user (downcase (user-login-name))))
2366 (while (string-match "[^a-z0-9_]" user) 1860 (while (string-match "[^a-z0-9_]" user)
2367 (aset user (match-beginning 0) ?_)) 1861 (aset user (match-beginning 0) ?_))
2368 user) 1862 user)
2369 (message-number-base36 (user-uid) -1)) 1863 (message-number-base36 (user-uid) -1))
2370 (message-number-base36 (+ (car tm) 1864 (message-number-base36 (+ (car tm)
2371 (lsh (% message-unique-id-char 25) 16)) 4) 1865 (lsh (% message-unique-id-char 25) 16)) 4)
2372 (message-number-base36 (+ (nth 1 tm) 1866 (message-number-base36 (+ (nth 1 tm)
2373 (lsh (/ message-unique-id-char 25) 16)) 4) 1867 (lsh (/ message-unique-id-char 25) 16)) 4)
2374 ;; Append the newsreader name, because while the generated 1868 ;; Append the newsreader name, because while the generated
2375 ;; ID is unique to this newsreader, other newsreaders might 1869 ;; ID is unique to this newsreader, other newsreaders might
2376 ;; otherwise generate the same ID via another algorithm. 1870 ;; otherwise generate the same ID via another algorithm.
2377 ".fsf"))) 1871 ".fsf")))
2378 1872
2379 (defun message-number-base36 (num len) 1873 (defun message-number-base36 (num len)
2380 (if (if (< len 0) 1874 (if (if (< len 0) (<= num 0) (= len 0))
2381 (<= num 0)
2382 (= len 0))
2383 "" 1875 ""
2384 (concat (message-number-base36 (/ num 36) (1- len)) 1876 (concat (message-number-base36 (/ num 36) (1- len))
2385 (char-to-string (aref "zyxwvutsrqponmlkjihgfedcba9876543210" 1877 (char-to-string (aref "zyxwvutsrqponmlkjihgfedcba9876543210"
2386 (% num 36)))))) 1878 (% num 36))))))
2387 1879
2388 (defun message-make-organization () 1880 (defun message-make-organization ()
2389 "Make an Organization header." 1881 "Make an Organization header."
2390 (let* ((organization 1882 (let* ((organization
2391 (or (getenv "ORGANIZATION") 1883 (or (getenv "ORGANIZATION")
2392 (when message-user-organization 1884 (when message-user-organization
2393 (if (message-functionp message-user-organization) 1885 (if (message-functionp message-user-organization)
2394 (funcall message-user-organization) 1886 (funcall message-user-organization)
2395 message-user-organization))))) 1887 message-user-organization)))))
2411 "Count the number of lines and return numeric string." 1903 "Count the number of lines and return numeric string."
2412 (save-excursion 1904 (save-excursion
2413 (save-restriction 1905 (save-restriction
2414 (widen) 1906 (widen)
2415 (goto-char (point-min)) 1907 (goto-char (point-min))
2416 (re-search-forward 1908 (re-search-forward
2417 (concat "^" (regexp-quote mail-header-separator) "$")) 1909 (concat "^" (regexp-quote mail-header-separator) "$"))
2418 (forward-line 1) 1910 (forward-line 1)
2419 (int-to-string (count-lines (point) (point-max)))))) 1911 (int-to-string (count-lines (point) (point-max))))))
2420 1912
2421 (defun message-make-in-reply-to () 1913 (defun message-make-in-reply-to ()
2422 "Return the In-Reply-To header for this message." 1914 "Return the In-Reply-To header for this message."
2423 (when message-reply-headers 1915 (when message-reply-headers
2424 (let ((from (mail-header-from message-reply-headers)) 1916 (let ((from (mail-header-from message-reply-headers))
2425 (date (mail-header-date message-reply-headers))) 1917 (date (mail-header-date message-reply-headers)))
2426 (when from 1918 (when from
2427 (let ((stop-pos 1919 (let ((stop-pos
2428 (string-match " *at \\| *@ \\| *(\\| *<" from))) 1920 (string-match " *at \\| *@ \\| *(\\| *<" from)))
2429 (concat (if stop-pos (substring from 0 stop-pos) from) 1921 (concat (if stop-pos (substring from 0 stop-pos) from)
2430 "'s message of " 1922 "'s message of "
2431 (if (or (not date) (string= date "")) 1923 (if (or (not date) (string= date ""))
2432 "(unknown date)" date))))))) 1924 "(unknown date)" date)))))))
2433 1925
2434 (defun message-make-distribution () 1926 (defun message-make-distribution ()
2435 "Make a Distribution header." 1927 "Make a Distribution header."
2444 (future (* 1.0 message-expires 60 60 24))) 1936 (future (* 1.0 message-expires 60 60 24)))
2445 ;; Add the future to current. 1937 ;; Add the future to current.
2446 (setcar current (+ (car current) (round (/ future (expt 2 16))))) 1938 (setcar current (+ (car current) (round (/ future (expt 2 16)))))
2447 (setcar (cdr current) (+ (nth 1 current) (% (round future) (expt 2 16)))) 1939 (setcar (cdr current) (+ (nth 1 current) (% (round future) (expt 2 16))))
2448 ;; Return the date in the future in UT. 1940 ;; Return the date in the future in UT.
2449 (timezone-make-date-arpa-standard 1941 (timezone-make-date-arpa-standard
2450 (current-time-string current) (current-time-zone current) '(0 "UT")))) 1942 (current-time-string current) (current-time-zone current) '(0 "UT"))))
2451 1943
2452 (defun message-make-path () 1944 (defun message-make-path ()
2453 "Return uucp path." 1945 "Return uucp path."
2454 (let ((login-name (user-login-name))) 1946 (let ((login-name (user-login-name)))
2459 (concat message-user-path "!" login-name)) 1951 (concat message-user-path "!" login-name))
2460 (t login-name)))) 1952 (t login-name))))
2461 1953
2462 (defun message-make-from () 1954 (defun message-make-from ()
2463 "Make a From header." 1955 "Make a From header."
2464 (let* ((style message-from-style) 1956 (let* ((login (message-make-address))
2465 (login (message-make-address)) 1957 (fullname
2466 (fullname
2467 (or (and (boundp 'user-full-name) 1958 (or (and (boundp 'user-full-name)
2468 user-full-name) 1959 user-full-name)
2469 (user-full-name)))) 1960 (user-full-name))))
2470 (when (string= fullname "&") 1961 (when (string= fullname "&")
2471 (setq fullname (user-login-name))) 1962 (setq fullname (user-login-name)))
2472 (save-excursion 1963 (save-excursion
2473 (message-set-work-buffer) 1964 (message-set-work-buffer)
2474 (cond 1965 (cond
2475 ((or (null style) 1966 ((or (null message-from-style)
2476 (equal fullname "")) 1967 (equal fullname ""))
2477 (insert login)) 1968 (insert login))
2478 ((or (eq style 'angles) 1969 ((or (eq message-from-style 'angles)
2479 (and (not (eq style 'parens)) 1970 (and (not (eq message-from-style 'parens))
2480 ;; Use angles if no quoting is needed, or if parens would 1971 ;; Use angles if no quoting is needed, or if parens would
2481 ;; need quoting too. 1972 ;; need quoting too.
2482 (or (not (string-match "[^- !#-'*+/-9=?A-Z^-~]" fullname)) 1973 (or (not (string-match "[^- !#-'*+/-9=?A-Z^-~]" fullname))
2483 (let ((tmp (concat fullname nil))) 1974 (let ((tmp (concat fullname nil)))
2484 (while (string-match "([^()]*)" tmp) 1975 (while (string-match "([^()]*)" tmp)
2508 (while (re-search-forward "[()\\]" nil 1) 1999 (while (re-search-forward "[()\\]" nil 1)
2509 (replace-match "\\\\\\&" t)) 2000 (replace-match "\\\\\\&" t))
2510 ;; ... then undo escaping of matching parentheses, 2001 ;; ... then undo escaping of matching parentheses,
2511 ;; including matching nested parentheses. 2002 ;; including matching nested parentheses.
2512 (goto-char fullname-start) 2003 (goto-char fullname-start)
2513 (while (re-search-forward 2004 (while (re-search-forward
2514 "\\(\\=\\|[^\\]\\(\\\\\\\\\\)*\\)\\\\(\\(\\([^\\]\\|\\\\\\\\\\)*\\)\\\\)" 2005 "\\(\\=\\|[^\\]\\(\\\\\\\\\\)*\\)\\\\(\\(\\([^\\]\\|\\\\\\\\\\)*\\)\\\\)"
2515 nil 1) 2006 nil 1)
2516 (replace-match "\\1(\\3)" t) 2007 (replace-match "\\1(\\3)" t)
2517 (goto-char fullname-start))) 2008 (goto-char fullname-start)))
2518 (insert ")"))) 2009 (insert ")")))
2519 (buffer-string)))) 2010 (buffer-string))))
2520 2011
2521 (defun message-make-sender () 2012 (defun message-make-sender ()
2522 "Return the \"real\" user address. 2013 "Return the \"real\" user address.
2523 This function tries to ignore all user modifications, and 2014 This function tries to ignore all user modifications, and
2524 give as trustworthy answer as possible." 2015 give as trustworthy answer as possible."
2525 (concat (user-login-name) "@" (system-name))) 2016 (concat (user-login-name) "@" (system-name)))
2526 2017
2527 (defun message-make-address () 2018 (defun message-make-address ()
2528 "Make the address of the user." 2019 "Make the address of the user."
2530 (concat (user-login-name) "@" (message-make-domain)))) 2021 (concat (user-login-name) "@" (message-make-domain))))
2531 2022
2532 (defun message-user-mail-address () 2023 (defun message-user-mail-address ()
2533 "Return the pertinent part of `user-mail-address'." 2024 "Return the pertinent part of `user-mail-address'."
2534 (when user-mail-address 2025 (when user-mail-address
2535 (if (string-match " " user-mail-address) 2026 (nth 1 (mail-extract-address-components user-mail-address))))
2536 (nth 1 (mail-extract-address-components user-mail-address))
2537 user-mail-address)))
2538 2027
2539 (defun message-make-fqdn () 2028 (defun message-make-fqdn ()
2540 "Return user's fully qualified domain name." 2029 "Return user's fully qualified domain name."
2541 (let ((system-name (system-name)) 2030 (let ((system-name (system-name))
2542 (user-mail (message-user-mail-address))) 2031 (user-mail (message-user-mail-address)))
2543 (cond 2032 (cond
2544 ((string-match "[^.]\\.[^.]" system-name) 2033 ((string-match "[^.]\\.[^.]" system-name)
2545 ;; `system-name' returned the right result. 2034 ;; `system-name' returned the right result.
2546 system-name) 2035 system-name)
2547 ;; Try `mail-host-address'. 2036 ;; Try `mail-host-address'.
2548 ((and (boundp 'mail-host-address) 2037 ((and (boundp 'mail-host-address)
2553 ((and (string-match "\\." user-mail) 2042 ((and (string-match "\\." user-mail)
2554 (string-match "@\\(.*\\)\\'" user-mail)) 2043 (string-match "@\\(.*\\)\\'" user-mail))
2555 (match-string 1 user-mail)) 2044 (match-string 1 user-mail))
2556 ;; Default to this bogus thing. 2045 ;; Default to this bogus thing.
2557 (t 2046 (t
2558 (concat system-name ".i-did-not-set--mail-host-address--so-shoot-me"))))) 2047 (concat system-name ".i-have-a-misconfigured-system-so-shoot-me")))))
2559 2048
2560 (defun message-make-host-name () 2049 (defun message-make-host-name ()
2561 "Return the name of the host." 2050 "Return the name of the host."
2562 (let ((fqdn (message-make-fqdn))) 2051 (let ((fqdn (message-make-fqdn)))
2563 (string-match "^[^.]+\\." fqdn) 2052 (string-match "^[^.]+\\." fqdn)
2592 header value elem) 2081 header value elem)
2593 ;; First we remove any old generated headers. 2082 ;; First we remove any old generated headers.
2594 (let ((headers message-deletable-headers)) 2083 (let ((headers message-deletable-headers))
2595 (while headers 2084 (while headers
2596 (goto-char (point-min)) 2085 (goto-char (point-min))
2597 (and (re-search-forward 2086 (and (re-search-forward
2598 (concat "^" (symbol-name (car headers)) ": *") nil t) 2087 (concat "^" (symbol-name (car headers)) ": *") nil t)
2599 (get-text-property (1+ (match-beginning 0)) 'message-deletable) 2088 (get-text-property (1+ (match-beginning 0)) 'message-deletable)
2600 (message-delete-line)) 2089 (message-delete-line))
2601 (pop headers))) 2090 (pop headers)))
2602 ;; Go through all the required headers and see if they are in the 2091 ;; Go through all the required headers and see if they are in the
2603 ;; articles already. If they are not, or are empty, they are 2092 ;; articles already. If they are not, or are empty, they are
2604 ;; inserted automatically - except for Subject, Newsgroups and 2093 ;; inserted automatically - except for Subject, Newsgroups and
2605 ;; Distribution. 2094 ;; Distribution.
2606 (while headers 2095 (while headers
2607 (goto-char (point-min)) 2096 (goto-char (point-min))
2608 (setq elem (pop headers)) 2097 (setq elem (pop headers))
2609 (if (consp elem) 2098 (if (consp elem)
2610 (if (eq (car elem) 'optional) 2099 (if (eq (car elem) 'optional)
2611 (setq header (cdr elem)) 2100 (setq header (cdr elem))
2612 (setq header (car elem))) 2101 (setq header (car elem)))
2613 (setq header elem)) 2102 (setq header elem))
2614 (when (or (not (re-search-forward 2103 (when (or (not (re-search-forward
2615 (concat "^" (downcase (symbol-name header)) ":") 2104 (concat "^" (downcase (symbol-name header)) ":")
2616 nil t)) 2105 nil t))
2617 (progn 2106 (progn
2618 ;; The header was found. We insert a space after the 2107 ;; The header was found. We insert a space after the
2619 ;; colon, if there is none. 2108 ;; colon, if there is none.
2620 (if (/= (following-char) ? ) (insert " ") (forward-char 1)) 2109 (if (/= (following-char) ? ) (insert " ") (forward-char 1))
2621 ;; Find out whether the header is empty... 2110 ;; Find out whether the header is empty...
2622 (looking-at "[ \t]*$"))) 2111 (looking-at "[ \t]*$")))
2623 ;; So we find out what value we should insert. 2112 ;; So we find out what value we should insert.
2624 (setq value 2113 (setq value
2625 (cond 2114 (cond
2626 ((and (consp elem) (eq (car elem) 'optional)) 2115 ((and (consp elem) (eq (car elem) 'optional))
2627 ;; This is an optional header. If the cdr of this 2116 ;; This is an optional header. If the cdr of this
2628 ;; is something that is nil, then we do not insert 2117 ;; is something that is nil, then we do not insert
2629 ;; this header. 2118 ;; this header.
2630 (setq header (cdr elem)) 2119 (setq header (cdr elem))
2645 ;; We couldn't generate a value for this header, 2134 ;; We couldn't generate a value for this header,
2646 ;; so we just ask the user. 2135 ;; so we just ask the user.
2647 (read-from-minibuffer 2136 (read-from-minibuffer
2648 (format "Empty header for %s; enter value: " header))))) 2137 (format "Empty header for %s; enter value: " header)))))
2649 ;; Finally insert the header. 2138 ;; Finally insert the header.
2650 (when (and value 2139 (when (and value
2651 (not (equal value ""))) 2140 (not (equal value "")))
2652 (save-excursion 2141 (save-excursion
2653 (if (bolp) 2142 (if (bolp)
2654 (progn 2143 (progn
2655 ;; This header didn't exist, so we insert it. 2144 ;; This header didn't exist, so we insert it.
2656 (goto-char (point-max)) 2145 (goto-char (point-max))
2657 (insert (symbol-name header) ": " value "\n") 2146 (insert (symbol-name header) ": " value "\n")
2658 (forward-line -1)) 2147 (forward-line -1))
2659 ;; The value of this header was empty, so we clear 2148 ;; The value of this header was empty, so we clear
2660 ;; totally and insert the new value. 2149 ;; totally and insert the new value.
2661 (delete-region (point) (gnus-point-at-eol)) 2150 (delete-region (point) (message-point-at-eol))
2662 (insert value)) 2151 (insert value))
2663 ;; Add the deletable property to the headers that require it. 2152 ;; Add the deletable property to the headers that require it.
2664 (and (memq header message-deletable-headers) 2153 (and (memq header message-deletable-headers)
2665 (progn (beginning-of-line) (looking-at "[^:]+: ")) 2154 (progn (beginning-of-line) (looking-at "[^:]+: "))
2666 (add-text-properties 2155 (add-text-properties
2667 (point) (match-end 0) 2156 (point) (match-end 0)
2668 '(message-deletable t face italic) (current-buffer))))))) 2157 '(message-deletable t face italic) (current-buffer)))))))
2669 ;; Insert new Sender if the From is strange. 2158 ;; Insert new Sender if the From is strange.
2670 (let ((from (message-fetch-field "from")) 2159 (let ((from (message-fetch-field "from"))
2671 (sender (message-fetch-field "sender")) 2160 (sender (message-fetch-field "sender"))
2672 (secure-sender (message-make-sender))) 2161 (secure-sender (message-make-sender)))
2673 (when (and from 2162 (when (and from
2674 (not (message-check-element 'sender)) 2163 (not (message-check-element 'sender))
2675 (not (string= 2164 (not (string=
2676 (downcase 2165 (downcase
2677 (cadr (mail-extract-address-components from))) 2166 (cadr (mail-extract-address-components from)))
2678 (downcase secure-sender))) 2167 (downcase secure-sender)))
2679 (or (null sender) 2168 (or (null sender)
2680 (not 2169 (not
2681 (string= 2170 (string=
2682 (downcase 2171 (downcase
2683 (cadr (mail-extract-address-components sender))) 2172 (cadr (mail-extract-address-components sender)))
2684 (downcase secure-sender))))) 2173 (downcase secure-sender)))))
2685 (goto-char (point-min)) 2174 (goto-char (point-min))
2686 ;; Rename any old Sender headers to Original-Sender. 2175 ;; Rename any old Sender headers to Original-Sender.
2687 (when (re-search-forward "^\\(Original-\\)*Sender:" nil t) 2176 (when (re-search-forward "^Sender:" nil t)
2688 (beginning-of-line) 2177 (beginning-of-line)
2689 (insert "Original-") 2178 (insert "Original-")
2690 (beginning-of-line)) 2179 (beginning-of-line))
2691 (insert "Sender: " secure-sender "\n")))))) 2180 (insert "Sender: " secure-sender "\n"))))))
2692 2181
2693 (defun message-insert-courtesy-copy () 2182 (defun message-insert-courtesy-copy ()
2694 "Insert a courtesy message in mail copies of combined messages." 2183 "Insert a courtesy message in mail copies of combined messages."
2695 (let (newsgroups) 2184 (save-excursion
2696 (save-excursion 2185 (save-restriction
2697 (save-restriction 2186 (message-narrow-to-headers)
2698 (message-narrow-to-headers) 2187 (let ((newsgroups (message-fetch-field "newsgroups")))
2699 (when (setq newsgroups (message-fetch-field "newsgroups")) 2188 (when newsgroups
2700 (goto-char (point-max)) 2189 (goto-char (point-max))
2701 (insert "Posted-To: " newsgroups "\n"))) 2190 (insert "Posted-To: " newsgroups "\n"))))
2702 (forward-line 1) 2191 (forward-line 1)
2703 (when message-courtesy-message 2192 (insert message-courtesy-message)))
2704 (cond 2193
2705 ((string-match "%s" message-courtesy-message)
2706 (insert (format message-courtesy-message newsgroups)))
2707 (t
2708 (insert message-courtesy-message)))))))
2709
2710 ;;; 2194 ;;;
2711 ;;; Setting up a message buffer 2195 ;;; Setting up a message buffer
2712 ;;; 2196 ;;;
2713 2197
2714 (defun message-fill-address (header value) 2198 (defun message-fill-address (header value)
2763 (goto-char (point-max))))) 2247 (goto-char (point-max)))))
2764 2248
2765 (defun message-position-point () 2249 (defun message-position-point ()
2766 "Move point to where the user probably wants to find it." 2250 "Move point to where the user probably wants to find it."
2767 (message-narrow-to-headers) 2251 (message-narrow-to-headers)
2768 (cond 2252 (cond
2769 ((re-search-forward "^[^:]+:[ \t]*$" nil t) 2253 ((re-search-forward "^[^:]+:[ \t]*$" nil t)
2770 (search-backward ":" ) 2254 (search-backward ":" )
2771 (widen) 2255 (widen)
2772 (forward-char 1) 2256 (forward-char 1)
2773 (if (= (following-char) ? ) 2257 (if (= (following-char) ? )
2782 (sit-for 0))) 2266 (sit-for 0)))
2783 2267
2784 (defun message-buffer-name (type &optional to group) 2268 (defun message-buffer-name (type &optional to group)
2785 "Return a new (unique) buffer name based on TYPE and TO." 2269 "Return a new (unique) buffer name based on TYPE and TO."
2786 (cond 2270 (cond
2787 ;; Check whether `message-generate-new-buffers' is a function, 2271 ;; Check whether `message-generate-new-buffers' is a function,
2788 ;; and if so, call it. 2272 ;; and if so, call it.
2789 ((message-functionp message-generate-new-buffers) 2273 ((message-functionp message-generate-new-buffers)
2790 (funcall message-generate-new-buffers type to group)) 2274 (funcall message-generate-new-buffers type to group))
2791 ;; Generate a new buffer name The Message Way. 2275 ;; Generate a new buffer name The Message Way.
2792 (message-generate-new-buffers 2276 (message-generate-new-buffers
2822 "Kill old message buffers." 2306 "Kill old message buffers."
2823 ;; We might have sent this buffer already. Delete it from the 2307 ;; We might have sent this buffer already. Delete it from the
2824 ;; list of buffers. 2308 ;; list of buffers.
2825 (setq message-buffer-list (delq (current-buffer) message-buffer-list)) 2309 (setq message-buffer-list (delq (current-buffer) message-buffer-list))
2826 (while (and message-max-buffers 2310 (while (and message-max-buffers
2827 message-buffer-list
2828 (>= (length message-buffer-list) message-max-buffers)) 2311 (>= (length message-buffer-list) message-max-buffers))
2829 ;; Kill the oldest buffer -- unless it has been changed. 2312 ;; Kill the oldest buffer -- unless it has been changed.
2830 (let ((buffer (pop message-buffer-list))) 2313 (let ((buffer (pop message-buffer-list)))
2831 (when (and (buffer-name buffer) 2314 (when (and (buffer-name buffer)
2832 (not (buffer-modified-p buffer))) 2315 (not (buffer-modified-p buffer)))
2833 (kill-buffer buffer)))) 2316 (kill-buffer buffer))))
2834 ;; Rename the buffer. 2317 ;; Rename the buffer.
2835 (if message-send-rename-function 2318 (if message-send-rename-function
2836 (funcall message-send-rename-function) 2319 (funcall message-send-rename-function)
2837 (when (string-match "\\`\\*" (buffer-name)) 2320 (when (string-match "\\`\\*" (buffer-name))
2838 (rename-buffer 2321 (rename-buffer
2839 (concat "*sent " (substring (buffer-name) (match-end 0))) t))) 2322 (concat "*sent " (substring (buffer-name) (match-end 0))) t)))
2840 ;; Push the current buffer onto the list. 2323 ;; Push the current buffer onto the list.
2841 (when message-max-buffers 2324 (when message-max-buffers
2842 (setq message-buffer-list 2325 (setq message-buffer-list
2843 (nconc message-buffer-list (list (current-buffer)))))) 2326 (nconc message-buffer-list (list (current-buffer))))))
2844 2327
2845 (defvar mc-modes-alist) 2328 (defvar mc-modes-alist)
2846 (defun message-setup (headers &optional replybuffer actions) 2329 (defun message-setup (headers &optional replybuffer actions)
2847 (when (and (boundp 'mc-modes-alist) 2330 (when (and (boundp 'mc-modes-alist)
2852 (when actions 2335 (when actions
2853 (setq message-send-actions actions)) 2336 (setq message-send-actions actions))
2854 (setq message-reply-buffer replybuffer) 2337 (setq message-reply-buffer replybuffer)
2855 (goto-char (point-min)) 2338 (goto-char (point-min))
2856 ;; Insert all the headers. 2339 ;; Insert all the headers.
2857 (mail-header-format 2340 (mail-header-format
2858 (let ((h headers) 2341 (let ((h headers)
2859 (alist message-header-format-alist)) 2342 (alist message-header-format-alist))
2860 (while h 2343 (while h
2861 (unless (assq (caar h) message-header-format-alist) 2344 (unless (assq (caar h) message-header-format-alist)
2862 (push (list (caar h)) alist)) 2345 (push (list (caar h)) alist))
2904 "Associate the message buffer with a file in the drafts directory." 2387 "Associate the message buffer with a file in the drafts directory."
2905 (when message-autosave-directory 2388 (when message-autosave-directory
2906 (unless (file-exists-p message-autosave-directory) 2389 (unless (file-exists-p message-autosave-directory)
2907 (make-directory message-autosave-directory t)) 2390 (make-directory message-autosave-directory t))
2908 (let ((name (make-temp-name 2391 (let ((name (make-temp-name
2909 (expand-file-name 2392 (concat (file-name-as-directory message-autosave-directory)
2910 (concat (file-name-as-directory message-autosave-directory) 2393 "msg."))))
2911 "msg.")))))
2912 (setq buffer-auto-save-file-name 2394 (setq buffer-auto-save-file-name
2913 (save-excursion 2395 (save-excursion
2914 (prog1 2396 (prog1
2915 (progn 2397 (progn
2916 (set-buffer (get-buffer-create " *draft tmp*")) 2398 (set-buffer (get-buffer-create " *draft tmp*"))
2924 ;;; 2406 ;;;
2925 ;;; Commands for interfacing with message 2407 ;;; Commands for interfacing with message
2926 ;;; 2408 ;;;
2927 2409
2928 ;;;###autoload 2410 ;;;###autoload
2929 (defun message-mail (&optional to subject 2411 (defun message-mail (&optional to subject)
2930 other-headers continue switch-function
2931 yank-action send-actions)
2932 "Start editing a mail message to be sent." 2412 "Start editing a mail message to be sent."
2933 (interactive) 2413 (interactive)
2934 (let ((message-this-is-mail t)) 2414 (message-pop-to-buffer (message-buffer-name "mail" to))
2935 (message-pop-to-buffer (message-buffer-name "mail" to)) 2415 (message-setup `((To . ,(or to "")) (Subject . ,(or subject "")))))
2936 (message-setup
2937 (nconc
2938 `((To . ,(or to "")) (Subject . ,(or subject "")))
2939 (when other-headers other-headers)))))
2940 2416
2941 ;;;###autoload 2417 ;;;###autoload
2942 (defun message-news (&optional newsgroups subject) 2418 (defun message-news (&optional newsgroups subject)
2943 "Start editing a news article to be sent." 2419 "Start editing a news article to be sent."
2944 (interactive) 2420 (interactive)
2945 (let ((message-this-is-news t)) 2421 (message-pop-to-buffer (message-buffer-name "news" nil newsgroups))
2946 (message-pop-to-buffer (message-buffer-name "news" nil newsgroups)) 2422 (message-setup `((Newsgroups . ,(or newsgroups ""))
2947 (message-setup `((Newsgroups . ,(or newsgroups "")) 2423 (Subject . ,(or subject "")))))
2948 (Subject . ,(or subject ""))))))
2949 2424
2950 ;;;###autoload 2425 ;;;###autoload
2951 (defun message-reply (&optional to-address wide ignore-reply-to) 2426 (defun message-reply (&optional to-address wide ignore-reply-to)
2952 "Start editing a reply to the article in the current buffer." 2427 "Start editing a reply to the article in the current buffer."
2953 (interactive) 2428 (interactive)
2954 (let ((cur (current-buffer)) 2429 (let ((cur (current-buffer))
2955 from subject date reply-to to cc 2430 from subject date reply-to to cc
2956 references message-id follow-to 2431 references message-id follow-to
2957 (inhibit-point-motion-hooks t) 2432 (inhibit-point-motion-hooks t)
2958 mct never-mct gnus-warning) 2433 mct never-mct gnus-warning)
2959 (save-restriction 2434 (save-restriction
2960 (message-narrow-to-head) 2435 (narrow-to-region
2436 (goto-char (point-min))
2437 (if (search-forward "\n\n" nil t)
2438 (1- (point))
2439 (point-max)))
2961 ;; Allow customizations to have their say. 2440 ;; Allow customizations to have their say.
2962 (if (not wide) 2441 (if (not wide)
2963 ;; This is a regular reply. 2442 ;; This is a regular reply.
2964 (if (message-functionp message-reply-to-function) 2443 (if (message-functionp message-reply-to-function)
2965 (setq follow-to (funcall message-reply-to-function))) 2444 (setq follow-to (funcall message-reply-to-function)))
2968 (save-excursion 2447 (save-excursion
2969 (setq follow-to 2448 (setq follow-to
2970 (funcall message-wide-reply-to-function))))) 2449 (funcall message-wide-reply-to-function)))))
2971 ;; Find all relevant headers we need. 2450 ;; Find all relevant headers we need.
2972 (setq from (message-fetch-field "from") 2451 (setq from (message-fetch-field "from")
2973 date (message-fetch-field "date") 2452 date (message-fetch-field "date")
2974 subject (or (message-fetch-field "subject") "none") 2453 subject (or (message-fetch-field "subject") "none")
2975 to (message-fetch-field "to") 2454 to (message-fetch-field "to")
2976 cc (message-fetch-field "cc") 2455 cc (message-fetch-field "cc")
2977 mct (message-fetch-field "mail-copies-to") 2456 mct (message-fetch-field "mail-copies-to")
2978 reply-to (unless ignore-reply-to (message-fetch-field "reply-to")) 2457 reply-to (unless ignore-reply-to (message-fetch-field "reply-to"))
2979 references (message-fetch-field "references") 2458 references (message-fetch-field "references")
2980 message-id (message-fetch-field "message-id" t)) 2459 message-id (message-fetch-field "message-id"))
2981 ;; Remove any (buggy) Re:'s that are present and make a 2460 ;; Remove any (buggy) Re:'s that are present and make a
2982 ;; proper one. 2461 ;; proper one.
2983 (when (string-match "^[ \t]*[Rr][Ee]:[ \t]*" subject) 2462 (when (string-match "^[ \t]*[Rr][Ee]:[ \t]*" subject)
2984 (setq subject (substring subject (match-end 0)))) 2463 (setq subject (substring subject (match-end 0))))
2985 (setq subject (concat "Re: " subject)) 2464 (setq subject (concat "Re: " subject))
2986 2465
2987 (when (and (setq gnus-warning (message-fetch-field "gnus-warning")) 2466 (when (and (setq gnus-warning (message-fetch-field "gnus-warning"))
2988 (string-match "<[^>]+>" gnus-warning)) 2467 (string-match "<[^>]+>" gnus-warning))
2989 (setq message-id (match-string 0 gnus-warning))) 2468 (setq message-id (match-string 0 gnus-warning)))
2990 2469
2991 ;; Handle special values of Mail-Copies-To. 2470 ;; Handle special values of Mail-Copies-To.
2992 (when mct 2471 (when mct
2993 (cond ((equal (downcase mct) "never") 2472 (cond ((equal (downcase mct) "never")
2994 (setq never-mct t) 2473 (setq never-mct t)
2995 (setq mct nil)) 2474 (setq mct nil))
3006 (unless never-mct 2485 (unless never-mct
3007 (insert (or reply-to from ""))) 2486 (insert (or reply-to from "")))
3008 (insert (if (bolp) "" ", ") (or to "")) 2487 (insert (if (bolp) "" ", ") (or to ""))
3009 (insert (if mct (concat (if (bolp) "" ", ") mct) "")) 2488 (insert (if mct (concat (if (bolp) "" ", ") mct) ""))
3010 (insert (if cc (concat (if (bolp) "" ", ") cc) "")) 2489 (insert (if cc (concat (if (bolp) "" ", ") cc) ""))
3011 (goto-char (point-min)) 2490 ;; Remove addresses that match `rmail-dont-reply-to-names'.
3012 (while (re-search-forward "[ \t]+" nil t)
3013 (replace-match " " t t))
3014 ;; Remove addresses that match `rmail-dont-reply-to-names'.
3015 (insert (prog1 (rmail-dont-reply-to (buffer-string)) 2491 (insert (prog1 (rmail-dont-reply-to (buffer-string))
3016 (erase-buffer))) 2492 (erase-buffer)))
3017 (goto-char (point-min)) 2493 (goto-char (point-min))
3018 ;; Perhaps Mail-Copies-To: never removed the only address?
3019 (when (eobp)
3020 (insert (or reply-to from "")))
3021 (setq ccalist 2494 (setq ccalist
3022 (mapcar 2495 (mapcar
3023 (lambda (addr) 2496 (lambda (addr)
3024 (cons (mail-strip-quoted-names addr) addr)) 2497 (cons (mail-strip-quoted-names addr) addr))
3025 (message-tokenize-header (buffer-string)))) 2498 (message-tokenize-header (buffer-string))))
3026 (let ((s ccalist)) 2499 (let ((s ccalist))
3027 (while s 2500 (while s
3028 (setq ccalist (delq (assoc (car (pop s)) s) ccalist))))) 2501 (setq ccalist (delq (assoc (car (pop s)) s) ccalist)))))
3029 (setq follow-to (list (cons 'To (cdr (pop ccalist))))) 2502 (setq follow-to (list (cons 'To (cdr (pop ccalist)))))
3030 (when ccalist 2503 (when ccalist
3031 (let ((ccs (cons 'Cc (mapconcat 2504 (push (cons 'Cc
3032 (lambda (addr) (cdr addr)) ccalist ", ")))) 2505 (mapconcat (lambda (addr) (cdr addr)) ccalist ", "))
3033 (when (string-match "^ +" (cdr ccs)) 2506 follow-to)))))
3034 (setcdr ccs (substring (cdr ccs) (match-end 0))))
3035 (push ccs follow-to))))))
3036 (widen)) 2507 (widen))
3037 2508
3038 (message-pop-to-buffer (message-buffer-name 2509 (message-pop-to-buffer (message-buffer-name
3039 (if wide "wide reply" "reply") from 2510 (if wide "wide reply" "reply") from
3040 (if wide to-address nil))) 2511 (if wide to-address nil)))
3042 (setq message-reply-headers 2513 (setq message-reply-headers
3043 (vector 0 subject from date message-id references 0 0 "")) 2514 (vector 0 subject from date message-id references 0 0 ""))
3044 2515
3045 (message-setup 2516 (message-setup
3046 `((Subject . ,subject) 2517 `((Subject . ,subject)
3047 ,@follow-to 2518 ,@follow-to
3048 ,@(if (or references message-id) 2519 ,@(if (or references message-id)
3049 `((References . ,(concat (or references "") (and references " ") 2520 `((References . ,(concat (or references "") (and references " ")
3050 (or message-id "")))) 2521 (or message-id ""))))
3051 nil)) 2522 nil))
3052 cur))) 2523 cur)))
3053 2524
3054 ;;;###autoload 2525 ;;;###autoload
3055 (defun message-wide-reply (&optional to-address) 2526 (defun message-wide-reply (&optional to-address)
3056 "Make a \"wide\" reply to the message in the current buffer."
3057 (interactive) 2527 (interactive)
3058 (message-reply to-address t)) 2528 (message-reply to-address t))
3059 2529
3060 ;;;###autoload 2530 ;;;###autoload
3061 (defun message-followup (&optional to-newsgroups) 2531 (defun message-followup ()
3062 "Follow up to the message in the current buffer.
3063 If TO-NEWSGROUPS, use that as the new Newsgroups line."
3064 (interactive) 2532 (interactive)
3065 (let ((cur (current-buffer)) 2533 (let ((cur (current-buffer))
3066 from subject date reply-to mct 2534 from subject date reply-to mct
3067 references message-id follow-to 2535 references message-id follow-to
3068 (inhibit-point-motion-hooks t) 2536 (inhibit-point-motion-hooks t)
3069 (message-this-is-news t) 2537 followup-to distribution newsgroups gnus-warning)
3070 followup-to distribution newsgroups gnus-warning posted-to)
3071 (save-restriction 2538 (save-restriction
3072 (narrow-to-region 2539 (narrow-to-region
3073 (goto-char (point-min)) 2540 (goto-char (point-min))
3074 (if (search-forward "\n\n" nil t) 2541 (if (search-forward "\n\n" nil t)
3075 (1- (point)) 2542 (1- (point))
3076 (point-max))) 2543 (point-max)))
3077 (when (message-functionp message-followup-to-function) 2544 (when (message-functionp message-followup-to-function)
3078 (setq follow-to 2545 (setq follow-to
3079 (funcall message-followup-to-function))) 2546 (funcall message-followup-to-function)))
3080 (setq from (message-fetch-field "from") 2547 (setq from (message-fetch-field "from")
3081 date (message-fetch-field "date") 2548 date (message-fetch-field "date")
3082 subject (or (message-fetch-field "subject") "none") 2549 subject (or (message-fetch-field "subject") "none")
3083 references (message-fetch-field "references") 2550 references (message-fetch-field "references")
3084 message-id (message-fetch-field "message-id" t) 2551 message-id (message-fetch-field "message-id")
3085 followup-to (message-fetch-field "followup-to") 2552 followup-to (message-fetch-field "followup-to")
3086 newsgroups (message-fetch-field "newsgroups") 2553 newsgroups (message-fetch-field "newsgroups")
3087 posted-to (message-fetch-field "posted-to")
3088 reply-to (message-fetch-field "reply-to") 2554 reply-to (message-fetch-field "reply-to")
3089 distribution (message-fetch-field "distribution") 2555 distribution (message-fetch-field "distribution")
3090 mct (message-fetch-field "mail-copies-to")) 2556 mct (message-fetch-field "mail-copies-to"))
3091 (when (and (setq gnus-warning (message-fetch-field "gnus-warning")) 2557 (when (and (setq gnus-warning (message-fetch-field "gnus-warning"))
3092 (string-match "<[^>]+>" gnus-warning)) 2558 (string-match "<[^>]+>" gnus-warning))
3093 (setq message-id (match-string 0 gnus-warning))) 2559 (setq message-id (match-string 0 gnus-warning)))
3094 ;; Remove bogus distribution. 2560 ;; Remove bogus distribution.
3095 (when (and (stringp distribution) 2561 (and (stringp distribution)
3096 (let ((case-fold-search t)) 2562 (string-match "world" distribution)
3097 (string-match "world" distribution))) 2563 (setq distribution nil))
3098 (setq distribution nil))
3099 ;; Remove any (buggy) Re:'s that are present and make a 2564 ;; Remove any (buggy) Re:'s that are present and make a
3100 ;; proper one. 2565 ;; proper one.
3101 (when (string-match "^[ \t]*[Rr][Ee]:[ \t]*" subject) 2566 (when (string-match "^[ \t]*[Rr][Ee]:[ \t]*" subject)
3102 (setq subject (substring subject (match-end 0)))) 2567 (setq subject (substring subject (match-end 0))))
3103 (setq subject (concat "Re: " subject)) 2568 (setq subject (concat "Re: " subject))
3105 2570
3106 (message-pop-to-buffer (message-buffer-name "followup" from newsgroups)) 2571 (message-pop-to-buffer (message-buffer-name "followup" from newsgroups))
3107 2572
3108 (message-setup 2573 (message-setup
3109 `((Subject . ,subject) 2574 `((Subject . ,subject)
3110 ,@(cond 2575 ,@(cond
3111 (to-newsgroups
3112 (list (cons 'Newsgroups to-newsgroups)))
3113 (follow-to follow-to) 2576 (follow-to follow-to)
3114 ((and followup-to message-use-followup-to) 2577 ((and followup-to message-use-followup-to)
3115 (list 2578 (list
3116 (cond 2579 (cond
3117 ((equal (downcase followup-to) "poster") 2580 ((equal (downcase followup-to) "poster")
3118 (if (or (eq message-use-followup-to 'use) 2581 (if (or (eq message-use-followup-to 'use)
3119 (message-y-or-n-p "Obey Followup-To: poster? " t "\ 2582 (message-y-or-n-p "Obey Followup-To: poster? " t "\
3120 You should normally obey the Followup-To: header. 2583 You should normally obey the Followup-To: header.
3121 2584
3122 `Followup-To: poster' sends your response via e-mail instead of news. 2585 `Followup-To: poster' sends your response via e-mail instead of news.
3123 2586
3124 A typical situation where `Followup-To: poster' is used is when the poster 2587 A typical situation where `Followup-To: poster' is used is when the poster
3125 does not read the newsgroup, so he wouldn't see any replies sent to it.")) 2588 does not read the newsgroup, so he wouldn't see any replies sent to it."))
3126 (progn 2589 (cons 'To (or reply-to from ""))
3127 (setq message-this-is-news nil)
3128 (cons 'To (or reply-to from "")))
3129 (cons 'Newsgroups newsgroups))) 2590 (cons 'Newsgroups newsgroups)))
3130 (t 2591 (t
3131 (if (or (equal followup-to newsgroups) 2592 (if (or (equal followup-to newsgroups)
3132 (not (eq message-use-followup-to 'ask)) 2593 (not (eq message-use-followup-to 'ask))
3133 (message-y-or-n-p 2594 (message-y-or-n-p
3142 If a message is posted to several newsgroups, Followup-To is often 2603 If a message is posted to several newsgroups, Followup-To is often
3143 used to direct the following discussion to one newsgroup only, 2604 used to direct the following discussion to one newsgroup only,
3144 because discussions that are spread over several newsgroup tend to 2605 because discussions that are spread over several newsgroup tend to
3145 be fragmented and very difficult to follow. 2606 be fragmented and very difficult to follow.
3146 2607
3147 Also, some source/announcement newsgroups are not indented for discussion; 2608 Also, some source/announcment newsgroups are not indented for discussion;
3148 responses here are directed to other newsgroups.")) 2609 responses here are directed to other newsgroups."))
3149 (cons 'Newsgroups followup-to) 2610 (cons 'Newsgroups followup-to)
3150 (cons 'Newsgroups newsgroups)))))) 2611 (cons 'Newsgroups newsgroups))))))
3151 (posted-to
3152 `((Newsgroups . ,posted-to)))
3153 (t 2612 (t
3154 `((Newsgroups . ,newsgroups)))) 2613 `((Newsgroups . ,newsgroups))))
3155 ,@(and distribution (list (cons 'Distribution distribution))) 2614 ,@(and distribution (list (cons 'Distribution distribution)))
3156 ,@(if (or references message-id) 2615 (References . ,(concat (or references "") (and references " ")
3157 `((References . ,(concat (or references "") (and references " ") 2616 (or message-id "")))
3158 (or message-id "")))))
3159 ,@(when (and mct 2617 ,@(when (and mct
3160 (not (equal (downcase mct) "never"))) 2618 (not (equal (downcase mct) "never")))
3161 (list (cons 'Cc (if (equal (downcase mct) "always") 2619 (list (cons 'Cc (if (equal (downcase mct) "always")
3162 (or reply-to from "") 2620 (or reply-to from "")
3163 mct))))) 2621 mct)))))
3180 ;; Get header info. from original article. 2638 ;; Get header info. from original article.
3181 (save-restriction 2639 (save-restriction
3182 (message-narrow-to-head) 2640 (message-narrow-to-head)
3183 (setq from (message-fetch-field "from") 2641 (setq from (message-fetch-field "from")
3184 newsgroups (message-fetch-field "newsgroups") 2642 newsgroups (message-fetch-field "newsgroups")
3185 message-id (message-fetch-field "message-id" t) 2643 message-id (message-fetch-field "message-id")
3186 distribution (message-fetch-field "distribution"))) 2644 distribution (message-fetch-field "distribution")))
3187 ;; Make sure that this article was written by the user. 2645 ;; Make sure that this article was written by the user.
3188 (unless (string-equal 2646 (unless (string-equal
3189 (downcase (cadr (mail-extract-address-components from))) 2647 (downcase (cadr (mail-extract-address-components from)))
3190 (downcase (message-make-address))) 2648 (downcase (message-make-address)))
3199 "Control: cancel " message-id "\n" 2657 "Control: cancel " message-id "\n"
3200 (if distribution 2658 (if distribution
3201 (concat "Distribution: " distribution "\n") 2659 (concat "Distribution: " distribution "\n")
3202 "") 2660 "")
3203 mail-header-separator "\n" 2661 mail-header-separator "\n"
3204 message-cancel-message) 2662 "This is a cancel message from " from ".\n")
3205 (message "Canceling your article...") 2663 (message "Canceling your article...")
3206 (let ((message-syntax-checks 'dont-check-for-anything-just-trust-me)) 2664 (let ((message-syntax-checks 'dont-check-for-anything-just-trust-me))
3207 (funcall message-send-news-function)) 2665 (funcall message-send-news-function))
3208 (message "Canceling your article...done") 2666 (message "Canceling your article...done")
3209 (kill-buffer buf))))) 2667 (kill-buffer buf)))))
3213 "Start composing a message to supersede the current message. 2671 "Start composing a message to supersede the current message.
3214 This is done simply by taking the old article and adding a Supersedes 2672 This is done simply by taking the old article and adding a Supersedes
3215 header line with the old Message-ID." 2673 header line with the old Message-ID."
3216 (interactive) 2674 (interactive)
3217 (let ((cur (current-buffer))) 2675 (let ((cur (current-buffer)))
3218 ;; Check whether the user owns the article that is to be superseded. 2676 ;; Check whether the user owns the article that is to be superseded.
3219 (unless (string-equal 2677 (unless (string-equal
3220 (downcase (cadr (mail-extract-address-components 2678 (downcase (cadr (mail-extract-address-components
3221 (message-fetch-field "from")))) 2679 (message-fetch-field "from"))))
3222 (downcase (message-make-address))) 2680 (downcase (message-make-address)))
3223 (error "This article is not yours")) 2681 (error "This article is not yours"))
3257 2715
3258 ;;; Forwarding messages. 2716 ;;; Forwarding messages.
3259 2717
3260 (defun message-make-forward-subject () 2718 (defun message-make-forward-subject ()
3261 "Return a Subject header suitable for the message in the current buffer." 2719 "Return a Subject header suitable for the message in the current buffer."
3262 (save-excursion 2720 (concat "[" (or (message-fetch-field (if (message-news-p) "newsgroups" "from"))
3263 (save-restriction 2721 "(nowhere)")
3264 (current-buffer) 2722 "] " (or (message-fetch-field "Subject") "")))
3265 (message-narrow-to-head)
3266 (concat "[" (or (message-fetch-field
3267 (if (message-news-p) "newsgroups" "from"))
3268 "(nowhere)")
3269 "] " (or (message-fetch-field "Subject") "")))))
3270 2723
3271 ;;;###autoload 2724 ;;;###autoload
3272 (defun message-forward (&optional news) 2725 (defun message-forward (&optional news)
3273 "Forward the current message via mail. 2726 "Forward the current message via mail.
3274 Optional NEWS will use news to forward instead of mail." 2727 Optional NEWS will use news to forward instead of mail."
3275 (interactive "P") 2728 (interactive "P")
3276 (let ((cur (current-buffer)) 2729 (let ((cur (current-buffer))
3277 (subject (message-make-forward-subject)) 2730 (subject (message-make-forward-subject)))
3278 art-beg)
3279 (if news (message-news nil subject) (message-mail nil subject)) 2731 (if news (message-news nil subject) (message-mail nil subject))
3280 ;; Put point where we want it before inserting the forwarded 2732 ;; Put point where we want it before inserting the forwarded
3281 ;; message. 2733 ;; message.
3282 (if message-signature-before-forwarded-message 2734 (if message-signature-before-forwarded-message
3283 (goto-char (point-max)) 2735 (goto-char (point-max))
3284 (message-goto-body)) 2736 (message-goto-body))
3285 ;; Make sure we're at the start of the line. 2737 ;; Make sure we're at the start of the line.
3286 (unless (eolp) 2738 (unless (eolp)
3287 (insert "\n")) 2739 (insert "\n"))
3288 ;; Narrow to the area we are to insert. 2740 ;; Narrow to the area we are to insert.
3289 (narrow-to-region (point) (point)) 2741 (narrow-to-region (point) (point))
3290 ;; Insert the separators and the forwarded buffer. 2742 ;; Insert the separators and the forwarded buffer.
3291 (insert message-forward-start-separator) 2743 (insert message-forward-start-separator)
3292 (setq art-beg (point))
3293 (insert-buffer-substring cur) 2744 (insert-buffer-substring cur)
3294 (goto-char (point-max)) 2745 (goto-char (point-max))
3295 (insert message-forward-end-separator) 2746 (insert message-forward-end-separator)
3296 (set-text-properties (point-min) (point-max) nil) 2747 (set-text-properties (point-min) (point-max) nil)
3297 ;; Remove all unwanted headers. 2748 ;; Remove all unwanted headers.
3298 (goto-char art-beg) 2749 (goto-char (point-min))
2750 (forward-line 1)
3299 (narrow-to-region (point) (if (search-forward "\n\n" nil t) 2751 (narrow-to-region (point) (if (search-forward "\n\n" nil t)
3300 (1- (point)) 2752 (1- (point))
3301 (point))) 2753 (point)))
3302 (goto-char (point-min)) 2754 (goto-char (point-min))
3303 (message-remove-header message-included-forward-headers t nil t) 2755 (message-remove-header message-included-forward-headers t nil t)
3306 2758
3307 ;;;###autoload 2759 ;;;###autoload
3308 (defun message-resend (address) 2760 (defun message-resend (address)
3309 "Resend the current article to ADDRESS." 2761 "Resend the current article to ADDRESS."
3310 (interactive "sResend message to: ") 2762 (interactive "sResend message to: ")
3311 (message "Resending message to %s..." address)
3312 (save-excursion 2763 (save-excursion
3313 (let ((cur (current-buffer)) 2764 (let ((cur (current-buffer))
3314 beg) 2765 beg)
3315 ;; We first set up a normal mail buffer. 2766 ;; We first set up a normal mail buffer.
3316 (set-buffer (get-buffer-create " *message resend*")) 2767 (set-buffer (get-buffer-create " *message resend*"))
3340 (insert mail-header-separator) 2791 (insert mail-header-separator)
3341 ;; Rename all old ("Also-")Resent headers. 2792 ;; Rename all old ("Also-")Resent headers.
3342 (while (re-search-backward "^\\(Also-\\)?Resent-" beg t) 2793 (while (re-search-backward "^\\(Also-\\)?Resent-" beg t)
3343 (beginning-of-line) 2794 (beginning-of-line)
3344 (insert "Also-")) 2795 (insert "Also-"))
3345 ;; Quote any "From " lines at the beginning.
3346 (goto-char beg)
3347 (when (looking-at "From ")
3348 (replace-match "X-From-Line: "))
3349 ;; Send it. 2796 ;; Send it.
3350 (message-send-mail) 2797 (message-send-mail)
3351 (kill-buffer (current-buffer))) 2798 (kill-buffer (current-buffer)))))
3352 (message "Resending message to %s...done" address)))
3353 2799
3354 ;;;###autoload 2800 ;;;###autoload
3355 (defun message-bounce () 2801 (defun message-bounce ()
3356 "Re-mail the current message. 2802 "Re-mail the current message.
3357 This only makes sense if the current message is a bounce message than 2803 This only makes sense if the current message is a bounce message than
3379 (and (re-search-forward message-unsent-separator nil t) 2825 (and (re-search-forward message-unsent-separator nil t)
3380 (forward-line 1)) 2826 (forward-line 1))
3381 (and (search-forward "\n\n" nil t) 2827 (and (search-forward "\n\n" nil t)
3382 (re-search-forward "^Return-Path:.*\n" nil t))) 2828 (re-search-forward "^Return-Path:.*\n" nil t)))
3383 ;; We remove everything before the bounced mail. 2829 ;; We remove everything before the bounced mail.
3384 (delete-region 2830 (delete-region
3385 (point-min) 2831 (point-min)
3386 (if (re-search-forward "^[^ \n\t]+:" nil t) 2832 (if (re-search-forward "^[^ \n\t]+:" nil t)
3387 (match-beginning 0) 2833 (match-beginning 0)
3388 (point))) 2834 (point)))
3389 (save-restriction 2835 (save-restriction
3429 (special-display-buffer-names nil) 2875 (special-display-buffer-names nil)
3430 (special-display-regexps nil) 2876 (special-display-regexps nil)
3431 (same-window-buffer-names nil) 2877 (same-window-buffer-names nil)
3432 (same-window-regexps nil)) 2878 (same-window-regexps nil))
3433 (message-pop-to-buffer (message-buffer-name "news" nil newsgroups))) 2879 (message-pop-to-buffer (message-buffer-name "news" nil newsgroups)))
3434 (message-setup `((Newsgroups . ,(or newsgroups "")) 2880 (message-setup `((Newsgroups . ,(or newsgroups ""))
3435 (Subject . ,(or subject ""))))) 2881 (Subject . ,(or subject "")))))
3436 2882
3437 ;;;###autoload 2883 ;;;###autoload
3438 (defun message-news-other-frame (&optional newsgroups subject) 2884 (defun message-news-other-frame (&optional newsgroups subject)
3439 "Start editing a news article to be sent." 2885 "Start editing a news article to be sent."
3442 (special-display-buffer-names nil) 2888 (special-display-buffer-names nil)
3443 (special-display-regexps nil) 2889 (special-display-regexps nil)
3444 (same-window-buffer-names nil) 2890 (same-window-buffer-names nil)
3445 (same-window-regexps nil)) 2891 (same-window-regexps nil))
3446 (message-pop-to-buffer (message-buffer-name "news" nil newsgroups))) 2892 (message-pop-to-buffer (message-buffer-name "news" nil newsgroups)))
3447 (message-setup `((Newsgroups . ,(or newsgroups "")) 2893 (message-setup `((Newsgroups . ,(or newsgroups ""))
3448 (Subject . ,(or subject ""))))) 2894 (Subject . ,(or subject "")))))
3449 2895
3450 ;;; underline.el 2896 ;;; underline.el
3451 2897
3452 ;; This code should be moved to underline.el (from which it is stolen). 2898 ;; This code should be moved to underline.el (from which it is stolen).
3453 2899
3454 ;;;###autoload 2900 ;;;###autoload
3455 (defun bold-region (start end) 2901 (defun bold-region (start end)
3456 "Bold all nonblank characters in the region. 2902 "Bold all nonblank characters in the region.
3457 Works by overstriking characters. 2903 Works by overstriking characters.
3458 Called from program, takes two arguments START and END 2904 Called from program, takes two arguments START and END
3459 which specify the range to operate on." 2905 which specify the range to operate on."
3460 (interactive "r") 2906 (interactive "r")
3461 (save-excursion 2907 (save-excursion
3462 (let ((end1 (make-marker))) 2908 (let ((end1 (make-marker)))
3463 (move-marker end1 (max start end)) 2909 (move-marker end1 (max start end))
3464 (goto-char (min start end)) 2910 (goto-char (min start end))
3465 (while (< (point) end1) 2911 (while (< (point) end1)
3466 (or (looking-at "[_\^@- ]") 2912 (or (looking-at "[_\^@- ]")
3467 (insert (following-char) "\b")) 2913 (insert (following-char) "\b"))
3468 (forward-char 1))))) 2914 (forward-char 1)))))
3469 2915
3470 ;;;###autoload 2916 ;;;###autoload
3471 (defun unbold-region (start end) 2917 (defun unbold-region (start end)
3472 "Remove all boldness (overstruck characters) in the region. 2918 "Remove all boldness (overstruck characters) in the region.
3473 Called from program, takes two arguments START and END 2919 Called from program, takes two arguments START and END
3474 which specify the range to operate on." 2920 which specify the range to operate on."
3475 (interactive "r") 2921 (interactive "r")
3476 (save-excursion 2922 (save-excursion
3477 (let ((end1 (make-marker))) 2923 (let ((end1 (make-marker)))
3478 (move-marker end1 (max start end)) 2924 (move-marker end1 (max start end))
3479 (goto-char (min start end)) 2925 (goto-char (min start end))
3480 (while (re-search-forward "\b" end1 t) 2926 (while (re-search-forward "\b" end1 t)
3481 (if (eq (following-char) (char-after (- (point) 2))) 2927 (if (eq (following-char) (char-after (- (point) 2)))
3482 (delete-char -2)))))) 2928 (delete-char -2))))))
3483 2929
3484 (defalias 'message-exchange-point-and-mark 'exchange-point-and-mark) 2930 (defalias 'message-exchange-point-and-mark 'exchange-point-and-mark)
3485 2931
3486 ;; Support for toolbar 2932 ;; Support for toolbar
3487 (when (string-match "XEmacs\\|Lucid" emacs-version) 2933 (when (string-match "XEmacs\\|Lucid" emacs-version)
3488 (require 'messagexmas)) 2934 (require 'messagexmas))
3489 2935
3490 ;;; Group name completion. 2936 ;;; Group name completion.
3491 2937
3492 (defvar message-newgroups-header-regexp 2938 (defvar message-newgroups-header-regexp
3493 "^\\(Newsgroups\\|Followup-To\\|Posted-To\\|Gcc\\):" 2939 "^\\(Newsgroups\\|Followup-To\\|Posted-To\\):"
3494 "Regexp that match headers that lists groups.") 2940 "Regexp that match headers that lists groups.")
3495 2941
3496 (defun message-tab () 2942 (defun message-tab ()
3497 "Expand group names in Newsgroups and Followup-To headers. 2943 "Expand group names in Newsgroups and Followup-To headers.
3498 Do a `tab-to-tab-stop' if not in those headers." 2944 Do a `tab-to-tab-stop' if not in those headers."
3502 (message-expand-group) 2948 (message-expand-group)
3503 (tab-to-tab-stop))) 2949 (tab-to-tab-stop)))
3504 2950
3505 (defvar gnus-active-hashtb) 2951 (defvar gnus-active-hashtb)
3506 (defun message-expand-group () 2952 (defun message-expand-group ()
3507 (let* ((b (save-excursion 2953 (let* ((b (save-excursion (skip-chars-backward "^, :\t\n") (point)))
3508 (save-restriction
3509 (narrow-to-region
3510 (save-excursion
3511 (beginning-of-line)
3512 (skip-chars-forward "^:")
3513 (1+ (point)))
3514 (point))
3515 (skip-chars-backward "^, \t\n") (point))))
3516 (completion-ignore-case t) 2954 (completion-ignore-case t)
3517 (string (buffer-substring b (point))) 2955 (string (buffer-substring b (point)))
3518 (hashtb (and (boundp 'gnus-active-hashtb) gnus-active-hashtb)) 2956 (hashtb (and (boundp 'gnus-active-hashtb) gnus-active-hashtb))
3519 (completions (all-completions string hashtb)) 2957 (completions (all-completions string hashtb))
3520 (cur (current-buffer)) 2958 (cur (current-buffer))
3521 comp) 2959 comp)
3522 (delete-region b (point)) 2960 (delete-region b (point))
3523 (cond 2961 (cond
3524 ((= (length completions) 1) 2962 ((= (length completions) 1)
3525 (if (string= (car completions) string) 2963 (if (string= (car completions) string)
3526 (progn 2964 (progn
3527 (insert string) 2965 (insert string)
3528 (message "Only matching group")) 2966 (message "Only matching group"))
3543 (goto-char (point-min)) 2981 (goto-char (point-min))
3544 (pop-to-buffer cur))))))) 2982 (pop-to-buffer cur)))))))
3545 2983
3546 ;;; Help stuff. 2984 ;;; Help stuff.
3547 2985
2986 (defmacro message-y-or-n-p (question show &rest text)
2987 "Ask QUESTION, displaying the rest of the arguments in a temp. buffer if SHOW"
2988 `(message-talkative-question 'y-or-n-p ,question ,show ,@text))
2989
3548 (defun message-talkative-question (ask question show &rest text) 2990 (defun message-talkative-question (ask question show &rest text)
3549 "Call FUNCTION with argument QUESTION, displaying the rest of the arguments in a temporary buffer if SHOW. 2991 "Call FUNCTION with argument QUESTION, displaying the rest of the arguments in a temporary buffer if SHOW.
3550 The following arguments may contain lists of values." 2992 The following arguments may contain lists of values."
3551 (if (and show 2993 (if (and show
3552 (setq text (message-flatten-list text))) 2994 (setq text (message-flatten-list text)))
3553 (save-window-excursion 2995 (save-window-excursion
3554 (save-excursion 2996 (save-excursion
3557 (mapcar 'princ text) 2999 (mapcar 'princ text)
3558 (goto-char (point-min)))) 3000 (goto-char (point-min))))
3559 (funcall ask question)) 3001 (funcall ask question))
3560 (funcall ask question))) 3002 (funcall ask question)))
3561 3003
3562 (defun message-flatten-list (list) 3004 (defun message-flatten-list (&rest list)
3563 "Return a new, flat list that contains all elements of LIST. 3005 (message-flatten-list-1 list))
3564 3006
3565 \(message-flatten-list '(1 (2 3 (4 5 (6))) 7)) 3007 (defun message-flatten-list-1 (list)
3566 => (1 2 3 4 5 6 7)" 3008 (cond ((consp list)
3567 (cond ((consp list) 3009 (apply 'append (mapcar 'message-flatten-list-1 list)))
3568 (apply 'append (mapcar 'message-flatten-list list)))
3569 (list 3010 (list
3570 (list list)))) 3011 (list list))))
3571 3012
3572 (defun message-generate-new-buffer-clone-locals (name &optional varstr)
3573 "Create and return a buffer with a name based on NAME using generate-new-buffer.
3574 Then clone the local variables and values from the old buffer to the
3575 new one, cloning only the locals having a substring matching the
3576 regexp varstr."
3577 (let ((oldlocals (buffer-local-variables)))
3578 (save-excursion
3579 (set-buffer (generate-new-buffer name))
3580 (mapcar (lambda (dude)
3581 (when (and (car dude)
3582 (or (not varstr)
3583 (string-match varstr (symbol-name (car dude)))))
3584 (ignore-errors
3585 (set (make-local-variable (car dude))
3586 (cdr dude)))))
3587 oldlocals)
3588 (current-buffer))))
3589
3590 (run-hooks 'message-load-hook) 3013 (run-hooks 'message-load-hook)
3591 3014
3592 (provide 'message) 3015 (provide 'message)
3593 3016
3594 ;;; message.el ends here 3017 ;;; message.el ends here