bdc0195e15ca76ba53d25f3be331658c7951f78f
[gnus] / lisp / gnus-msg.el
1 ;;; gnus-msg.el --- mail and post interface for Gnus
2
3 ;; Copyright (C) 1995-2012  Free Software Foundation, Inc.
4
5 ;; Author: Masanobu UMEDA <umerin@flab.flab.fujitsu.junet>
6 ;;      Lars Magne Ingebrigtsen <larsi@gnus.org>
7 ;; Keywords: news
8
9 ;; This file is part of GNU Emacs.
10
11 ;; GNU Emacs is free software: you can redistribute it and/or modify
12 ;; it under the terms of the GNU General Public License as published by
13 ;; the Free Software Foundation, either version 3 of the License, or
14 ;; (at your option) any later version.
15
16 ;; GNU Emacs is distributed in the hope that it will be useful,
17 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 ;; GNU General Public License for more details.
20
21 ;; You should have received a copy of the GNU General Public License
22 ;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
23
24 ;;; Commentary:
25
26 ;;; Code:
27
28 (eval-when-compile (require 'cl))
29
30 (require 'gnus)
31 (require 'gnus-ems)
32 (require 'message)
33 (require 'gnus-art)
34 (require 'gnus-util)
35
36 (defcustom gnus-post-method 'current
37   "*Preferred method for posting USENET news.
38
39 If this variable is `current' (which is the default), Gnus will use
40 the \"current\" select method when posting.  If it is `native', Gnus
41 will use the native select method when posting.
42
43 This method will not be used in mail groups and the like, only in
44 \"real\" newsgroups.
45
46 If not `native' nor `current', the value must be a valid method as discussed
47 in the documentation of `gnus-select-method'.  It can also be a list of
48 methods.  If that is the case, the user will be queried for what select
49 method to use when posting."
50   :group 'gnus-group-foreign
51   :link '(custom-manual "(gnus)Posting Server")
52   :type `(choice (const native)
53                  (const current)
54                  (sexp :tag "Methods" ,gnus-select-method)))
55
56 (defcustom gnus-outgoing-message-group nil
57   "All outgoing messages will be put in this group.
58 If you want to store all your outgoing mail and articles in the group
59 \"nnml:archive\", you set this variable to that value.  This variable
60 can also be a list of group names.
61
62 If you want to have greater control over what group to put each
63 message in, you can set this variable to a function that checks the
64 current newsgroup name and then returns a suitable group name (or list
65 of names)."
66   :group 'gnus-message
67   :type '(choice (const nil)
68                  (function)
69                  (string :tag "Group")
70                  (repeat :tag "List of groups" (string :tag "Group"))))
71
72 (make-obsolete-variable 'gnus-outgoing-message-group 'gnus-message-archive-group "24.1")
73
74 (defcustom gnus-mailing-list-groups nil
75   "*If non-nil a regexp matching groups that are really mailing lists.
76 This is useful when you're reading a mailing list that has been
77 gatewayed to a newsgroup, and you want to followup to an article in
78 the group."
79   :group 'gnus-message
80   :type '(choice (regexp)
81                  (const nil)))
82
83 (defcustom gnus-add-to-list nil
84   "*If non-nil, add a `to-list' parameter automatically."
85   :group 'gnus-message
86   :type 'boolean)
87
88 (defcustom gnus-crosspost-complaint
89   "Hi,
90
91 You posted the article below with the following Newsgroups header:
92
93 Newsgroups: %s
94
95 The %s group, at least, was an inappropriate recipient
96 of this message.  Please trim your Newsgroups header to exclude this
97 group before posting in the future.
98
99 Thank you.
100
101 "
102   "Format string to be inserted when complaining about crossposts.
103 The first %s will be replaced by the Newsgroups header;
104 the second with the current group name."
105   :group 'gnus-message
106   :type 'string)
107
108 (defcustom gnus-message-setup-hook nil
109   "Hook run after setting up a message buffer."
110   :group 'gnus-message
111   :options '(message-remove-blank-cited-lines)
112   :type 'hook)
113
114 (defcustom gnus-bug-create-help-buffer t
115   "*Should we create the *Gnus Help Bug* buffer?"
116   :group 'gnus-message
117   :type 'boolean)
118
119 (defcustom gnus-posting-styles nil
120   "*Alist of styles to use when posting.
121 See Info node `(gnus)Posting Styles'."
122   :group 'gnus-message
123   :link '(custom-manual "(gnus)Posting Styles")
124   :type '(repeat (cons (choice (regexp)
125                                (variable)
126                                (list (const header)
127                                      (string :tag "Header")
128                                      (regexp :tag "Regexp"))
129                                (function)
130                                (sexp))
131                        (repeat (list
132                                 (choice (const signature)
133                                         (const signature-file)
134                                         (const organization)
135                                         (const address)
136                                         (const x-face-file)
137                                         (const name)
138                                         (const body)
139                                         (symbol)
140                                         (string :tag "Header"))
141                                 (choice (string)
142                                         (function)
143                                         (variable)
144                                         (sexp)))))))
145
146 (defcustom gnus-gcc-mark-as-read nil
147   "If non-nil, automatically mark Gcc articles as read."
148   :version "22.1"
149   :group 'gnus-message
150   :type 'boolean)
151
152 (make-obsolete-variable 'gnus-inews-mark-gcc-as-read
153                         'gnus-gcc-mark-as-read "Emacs 22.1")
154
155 (defcustom gnus-gcc-externalize-attachments nil
156   "Should local-file attachments be included as external parts in Gcc copies?
157 If it is `all', attach files as external parts;
158 if a regexp and matches the Gcc group name, attach files as external parts;
159 if nil, attach files as normal parts."
160   :version "22.1"
161   :group 'gnus-message
162   :type '(choice (const nil :tag "None")
163                  (const all :tag "Any")
164                  (string :tag "Regexp")))
165
166 (defcustom gnus-gcc-self-resent-messages 'no-gcc-self
167   "Like `gcc-self' group parameter, only for unmodified resent messages.
168 Applied to messages sent by `gnus-summary-resend-message'.  Non-nil
169 value of this variable takes precedence over any existing Gcc header.
170
171 If this is `none', no Gcc copy will be made.  If this is t, messages
172 resent will be Gcc'd to the current group.  If this is a string, it
173 specifies a group to which resent messages will be Gcc'd.  If this is
174 nil, Gcc will be done according to existing Gcc header(s), if any.
175 If this is `no-gcc-self', resent messages will be Gcc'd to groups that
176 existing Gcc header specifies, except for the current group."
177   :version "24.2"
178   :group 'gnus-message
179   :type '(choice (const none) (const t) string (const nil)
180                  (const no-gcc-self)))
181
182 (gnus-define-group-parameter
183  posting-charset-alist
184  :type list
185  :function-document
186  "Return the permitted unencoded charsets for posting of GROUP."
187  :variable gnus-group-posting-charset-alist
188  :variable-default
189   '(("^\\(no\\|fr\\)\\.[^,]*\\(,[ \t\n]*\\(no\\|fr\\)\\.[^,]*\\)*$" iso-8859-1 (iso-8859-1))
190     ("^\\(fido7\\|relcom\\)\\.[^,]*\\(,[ \t\n]*\\(fido7\\|relcom\\)\\.[^,]*\\)*$" koi8-r (koi8-r))
191     (message-this-is-mail nil nil)
192     (message-this-is-news nil t))
193  :variable-document
194   "Alist of regexps and permitted unencoded charsets for posting.
195 Each element of the alist has the form (TEST HEADER BODY-LIST), where
196 TEST is either a regular expression matching the newsgroup header or a
197 variable to query,
198 HEADER is the charset which may be left unencoded in the header (nil
199 means encode all charsets),
200 BODY-LIST is a list of charsets which may be encoded using 8bit
201 content-transfer encoding in the body, or one of the special values
202 nil (always encode using quoted-printable) or t (always use 8bit).
203
204 Note that any value other than nil for HEADER infringes some RFCs, so
205 use this option with care."
206  :variable-group gnus-charset
207  :variable-type
208  '(repeat (list :tag "Permitted unencoded charsets"
209                 (choice :tag "Where"
210                         (regexp :tag "Group")
211                         (const :tag "Mail message" :value message-this-is-mail)
212                         (const :tag "News article" :value message-this-is-news))
213                 (choice :tag "Header"
214                         (const :tag "None" nil)
215                         (symbol :tag "Charset"))
216                 (choice :tag "Body"
217                         (const :tag "Any" :value t)
218                         (const :tag "None" :value nil)
219                         (repeat :tag "Charsets"
220                                 (symbol :tag "Charset")))))
221  :parameter-type '(choice :tag "Permitted unencoded charsets"
222                           :value nil
223                           (repeat (symbol)))
224  :parameter-document       "\
225 List of charsets that are permitted to be unencoded.")
226
227 (defcustom gnus-debug-files
228   '("gnus.el" "gnus-sum.el" "gnus-group.el"
229     "gnus-art.el" "gnus-start.el" "gnus-async.el"
230     "gnus-msg.el" "gnus-score.el" "gnus-win.el" "gnus-topic.el"
231     "gnus-agent.el" "gnus-cache.el" "gnus-srvr.el"
232     "mm-util.el" "mm-decode.el" "nnmail.el" "message.el")
233   "Files whose variables will be reported in `gnus-bug'."
234   :version "22.1"
235   :group 'gnus-message
236   :type '(repeat (string :tag "File")))
237
238 (defcustom gnus-debug-exclude-variables
239   '(mm-mime-mule-charset-alist
240     nnmail-split-fancy message-minibuffer-local-map)
241   "Variables that should not be reported in `gnus-bug'."
242   :version "22.1"
243   :group 'gnus-message
244   :type '(repeat (symbol :tag "Variable")))
245
246 (defcustom gnus-discouraged-post-methods
247   '(nndraft nnml nnimap nnmaildir nnmh nnfolder nndir)
248   "A list of back ends that are not used in \"real\" newsgroups.
249 This variable is used only when `gnus-post-method' is `current'."
250   :version "22.1"
251   :group 'gnus-group-foreign
252   :type '(repeat (symbol :tag "Back end")))
253
254 (defcustom gnus-message-replysign
255   nil
256   "Automatically sign replies to signed messages.
257 See also the `mml-default-sign-method' variable."
258   :group 'gnus-message
259   :type 'boolean)
260
261 (defcustom gnus-message-replyencrypt t
262   "Automatically encrypt replies to encrypted messages.
263 See also the `mml-default-encrypt-method' variable."
264   :version "24.1"
265   :group 'gnus-message
266   :type 'boolean)
267
268 (defcustom gnus-message-replysignencrypted
269   t
270   "Setting this causes automatically encrypted messages to also be signed."
271   :group 'gnus-message
272   :type 'boolean)
273
274 (defcustom gnus-confirm-mail-reply-to-news (and gnus-novice-user
275                                                 (not gnus-expert-user))
276   "If non-nil, Gnus requests confirmation when replying to news.
277 This is done because new users often reply by mistake when reading
278 news.
279 This can also be a function receiving the group name as the only
280 parameter, which should return non-nil if a confirmation is needed; or
281 a regexp, in which case a confirmation is asked for if the group name
282 matches the regexp."
283   :version "23.1" ;; No Gnus (default changed)
284   :group 'gnus-message
285   :type '(choice (const :tag "No" nil)
286                  (const :tag "Yes" t)
287                  (regexp :tag "If group matches regexp")
288                  (function :tag "If function evaluates to non-nil")))
289
290 (defcustom gnus-confirm-treat-mail-like-news
291   nil
292   "If non-nil, Gnus will treat mail like news with regard to confirmation
293 when replying by mail.  See the `gnus-confirm-mail-reply-to-news' variable
294 for fine-tuning this.
295 If nil, Gnus will never ask for confirmation if replying to mail."
296   :version "22.1"
297   :group 'gnus-message
298   :type 'boolean)
299
300 (defcustom gnus-summary-resend-default-address t
301   "If non-nil, Gnus tries to suggest a default address to resend to.
302 If nil, the address field will always be empty after invoking
303 `gnus-summary-resend-message'."
304   :version "22.1"
305   :group 'gnus-message
306   :type 'boolean)
307
308 (defcustom gnus-message-highlight-citation
309   t ;; gnus-treat-highlight-citation ;; gnus-cite dependency
310   "Enable highlighting of different citation levels in message-mode."
311   :version "23.1" ;; No Gnus
312   :group 'gnus-cite
313   :group 'gnus-message
314   :type 'boolean)
315
316 (defcustom gnus-gcc-pre-body-encode-hook nil
317   "A hook called before encoding the body of the Gcc copy of a message.
318 The current buffer (when the hook is run) contains the message
319 including the message header.  Changes made to the message will
320 only affect the Gcc copy, but not the original message."
321   :group 'gnus-message
322   :type 'hook)
323
324 (defcustom gnus-gcc-post-body-encode-hook nil
325     "A hook called after encoding the body of the Gcc copy of a message.
326 The current buffer (when the hook is run) contains the message
327 including the message header.  Changes made to the message will
328 only affect the Gcc copy, but not the original message."
329   :group 'gnus-message
330   :type 'hook)
331
332 (autoload 'gnus-message-citation-mode "gnus-cite" nil t)
333
334 ;;; Internal variables.
335
336 (defvar gnus-inhibit-posting-styles nil
337   "Inhibit the use of posting styles.")
338
339 (defvar gnus-article-yanked-articles nil)
340 (defvar gnus-message-buffer "*Mail Gnus*")
341 (defvar gnus-article-copy nil)
342 (defvar gnus-check-before-posting nil)
343 (defvar gnus-last-posting-server nil)
344 (defvar gnus-message-group-art nil)
345
346 (defvar gnus-msg-force-broken-reply-to nil)
347
348 (defconst gnus-bug-message
349   "Sending a bug report to the Gnus Towers.
350 ========================================
351
352 The buffer below is a mail buffer.  When you press `C-c C-c', it will
353 be sent to the Gnus Bug Exterminators.
354
355 The thing near the bottom of the buffer is how the environment
356 settings will be included in the mail.  Please do not delete that.
357 They will tell the Bug People what your environment is, so that it
358 will be easier to locate the bugs.
359
360 If you have found a bug that makes Emacs go \"beep\", set
361 debug-on-error to t (`M-x set-variable RET debug-on-error RET t RET')
362 and include the backtrace in your bug report.
363
364 Please describe the bug in annoying, painstaking detail.
365
366 Thank you for your help in stamping out bugs.
367 ")
368
369 (autoload 'gnus-uu-post-news "gnus-uu" nil t)
370
371 \f
372 ;;;
373 ;;; Gnus Posting Functions
374 ;;;
375
376 (gnus-define-keys (gnus-summary-send-map "S" gnus-summary-mode-map)
377   "p" gnus-summary-post-news
378   "i" gnus-summary-news-other-window
379   "f" gnus-summary-followup
380   "F" gnus-summary-followup-with-original
381   "c" gnus-summary-cancel-article
382   "s" gnus-summary-supersede-article
383   "r" gnus-summary-reply
384   "y" gnus-summary-yank-message
385   "R" gnus-summary-reply-with-original
386   "L" gnus-summary-reply-to-list-with-original
387   "w" gnus-summary-wide-reply
388   "W" gnus-summary-wide-reply-with-original
389   "v" gnus-summary-very-wide-reply
390   "V" gnus-summary-very-wide-reply-with-original
391   "n" gnus-summary-followup-to-mail
392   "N" gnus-summary-followup-to-mail-with-original
393   "m" gnus-summary-mail-other-window
394   "u" gnus-uu-post-news
395   "\M-c" gnus-summary-mail-crosspost-complaint
396   "Br" gnus-summary-reply-broken-reply-to
397   "BR" gnus-summary-reply-broken-reply-to-with-original
398   "om" gnus-summary-mail-forward
399   "op" gnus-summary-post-forward
400   "Om" gnus-uu-digest-mail-forward
401   "Op" gnus-uu-digest-post-forward)
402
403 (gnus-define-keys (gnus-send-bounce-map "D" gnus-summary-send-map)
404   "b" gnus-summary-resend-bounced-mail
405   ;; "c" gnus-summary-send-draft
406   "r" gnus-summary-resend-message
407   "e" gnus-summary-resend-message-edit)
408
409 ;;; Internal functions.
410
411 (defun gnus-inews-make-draft (articles)
412   `(lambda ()
413      (gnus-inews-make-draft-meta-information
414       ,(gnus-group-decoded-name gnus-newsgroup-name) ',articles)))
415
416 (defvar gnus-article-reply nil)
417 (defmacro gnus-setup-message (config &rest forms)
418   (let ((winconf (make-symbol "gnus-setup-message-winconf"))
419         (winconf-name (make-symbol "gnus-setup-message-winconf-name"))
420         (buffer (make-symbol "gnus-setup-message-buffer"))
421         (article (make-symbol "gnus-setup-message-article"))
422         (yanked (make-symbol "gnus-setup-yanked-articles"))
423         (group (make-symbol "gnus-setup-message-group")))
424     `(let ((,winconf (current-window-configuration))
425            (,winconf-name gnus-current-window-configuration)
426            (,buffer (buffer-name (current-buffer)))
427            (,article gnus-article-reply)
428            (,yanked gnus-article-yanked-articles)
429            (,group gnus-newsgroup-name)
430            (message-header-setup-hook
431             (copy-sequence message-header-setup-hook))
432            (mbl mml-buffer-list)
433            (message-mode-hook (copy-sequence message-mode-hook)))
434        (setq mml-buffer-list nil)
435        (add-hook 'message-header-setup-hook 'gnus-inews-insert-gcc)
436        ;; message-newsreader and message-mailer were formerly set in
437        ;; gnus-inews-add-send-actions, but this is too late when
438        ;; message-generate-headers-first is used. --ansel
439        (add-hook 'message-mode-hook
440                  (lambda nil
441                    (setq message-newsreader
442                          (setq message-mailer (gnus-extended-version)))))
443        ;; #### FIXME: for a reason that I did not manage to identify yet,
444        ;; the variable `gnus-newsgroup-name' does not honor a dynamically
445        ;; scoped or setq'ed value from a caller like `C-u gnus-summary-mail'.
446        ;; After evaluation of @forms below, it gets the value we actually want
447        ;; to override, and the posting styles are used. For that reason, I've
448        ;; added an optional argument to `gnus-configure-posting-styles' to
449        ;; make sure that the correct value for the group name is used. -- drv
450        (add-hook 'message-mode-hook
451                  (if (memq ,config '(reply-yank reply))
452                      (lambda ()
453                        (gnus-configure-posting-styles ,group))
454                    (lambda ()
455                      ;; There may be an old " *gnus article copy*" buffer.
456                      (let (gnus-article-copy)
457                        (gnus-configure-posting-styles ,group)))))
458        (gnus-alist-pull ',(intern gnus-draft-meta-information-header)
459                   message-required-headers)
460        (when (and ,group
461                   (not (string= ,group "")))
462          (push (cons
463                 (intern gnus-draft-meta-information-header)
464                 (gnus-inews-make-draft (or ,yanked ,article)))
465                message-required-headers))
466        (unwind-protect
467            (progn
468              ,@forms)
469          (gnus-inews-add-send-actions ,winconf ,buffer ,article ,config
470                                       ,yanked ,winconf-name)
471          (setq gnus-message-buffer (current-buffer))
472          (set (make-local-variable 'gnus-message-group-art)
473               (cons ,group ,article))
474          (set (make-local-variable 'gnus-newsgroup-name) ,group)
475          ;; Enable highlighting of different citation levels
476          (when gnus-message-highlight-citation
477            (gnus-message-citation-mode 1))
478          (gnus-run-hooks 'gnus-message-setup-hook)
479          (if (eq major-mode 'message-mode)
480              (let ((mbl1 mml-buffer-list))
481                (setq mml-buffer-list mbl)  ;; Global value
482                (set (make-local-variable 'mml-buffer-list) mbl1);; Local value
483                (gnus-make-local-hook 'kill-buffer-hook)
484                (gnus-make-local-hook 'change-major-mode-hook)
485                (add-hook 'change-major-mode-hook 'mml-destroy-buffers nil t)
486                (add-hook 'kill-buffer-hook 'mml-destroy-buffers t t))
487            (mml-destroy-buffers)
488            (setq mml-buffer-list mbl)))
489        (message-hide-headers)
490        (gnus-add-buffer)
491        (gnus-configure-windows ,config t)
492        (run-hooks 'post-command-hook)
493        (set-buffer-modified-p nil))))
494
495 (defun gnus-inews-make-draft-meta-information (group articles)
496   (when (numberp articles)
497     (setq articles (list articles)))
498   (concat "(\"" group "\""
499           (if articles
500               (concat " "
501                       (mapconcat
502                        (lambda (elem)
503                          (number-to-string
504                           (if (consp elem)
505                               (car elem)
506                             elem)))
507                        articles " "))
508             "")
509           ")"))
510
511 ;;;###autoload
512 (defun gnus-msg-mail (&optional to subject other-headers continue
513                                 switch-action yank-action send-actions
514                                 return-action)
515   "Start editing a mail message to be sent.
516 Like `message-mail', but with Gnus paraphernalia, particularly the
517 Gcc: header for archiving purposes.
518 If Gnus isn't running, a plain `message-mail' setup is used
519 instead."
520   (interactive)
521   (if (not (gnus-alive-p))
522       (message-mail to subject other-headers continue
523                     nil yank-action send-actions return-action)
524     (let ((buf (current-buffer))
525           (gnus-newsgroup-name (or gnus-newsgroup-name ""))
526           mail-buf)
527       (gnus-setup-message 'message
528         (message-mail to subject other-headers continue
529                       nil yank-action send-actions return-action))
530       (when switch-action
531         (setq mail-buf (current-buffer))
532         (switch-to-buffer buf)
533         (apply switch-action mail-buf nil))
534       ;; COMPOSEFUNC should return t if succeed.  Undocumented ???
535       t)))
536
537 ;;;###autoload
538 (defun gnus-button-mailto (address)
539   "Mail to ADDRESS."
540   (set-buffer (gnus-copy-article-buffer))
541   (gnus-setup-message 'message
542     (message-reply address)))
543
544 ;;;###autoload
545 (defun gnus-button-reply (&optional to-address wide)
546   "Like `message-reply'."
547   (interactive)
548   (gnus-setup-message 'message
549     (message-reply to-address wide)))
550
551 ;;;###autoload
552 (define-mail-user-agent 'gnus-user-agent
553   'gnus-msg-mail 'message-send-and-exit
554   'message-kill-buffer 'message-send-hook)
555
556 (defun gnus-setup-posting-charset (group)
557   (let ((alist gnus-group-posting-charset-alist)
558         (group (or group ""))
559         elem)
560     (when group
561       (catch 'found
562         (while (setq elem (pop alist))
563           (when (or (and (stringp (car elem))
564                          (string-match (car elem) group))
565                     (and (functionp (car elem))
566                          (funcall (car elem) group))
567                     (and (symbolp (car elem))
568                          (symbol-value (car elem))))
569             (throw 'found (cons (cadr elem) (caddr elem)))))))))
570
571 (defun gnus-inews-add-send-actions (winconf buffer article
572                                             &optional config yanked
573                                             winconf-name)
574   (gnus-make-local-hook 'message-sent-hook)
575   (add-hook 'message-sent-hook (if gnus-agent 'gnus-agent-possibly-do-gcc
576                                  'gnus-inews-do-gcc) nil t)
577   (when gnus-agent
578     (gnus-make-local-hook 'message-header-hook)
579     (add-hook 'message-header-hook 'gnus-agent-possibly-save-gcc nil t))
580   (setq message-post-method
581         `(lambda (&optional arg)
582            (gnus-post-method arg ,gnus-newsgroup-name)))
583   (message-add-action
584    `(progn
585       (setq gnus-current-window-configuration ',winconf-name)
586       (when (gnus-buffer-exists-p ,buffer)
587         (set-window-configuration ,winconf)))
588    'exit 'postpone 'kill)
589   (let ((to-be-marked (cond
590                        (yanked
591                         (mapcar
592                          (lambda (x) (if (listp x) (car x) x)) yanked))
593                        (article (if (listp article) article (list article)))
594                        (t nil))))
595     (message-add-action
596      `(when (gnus-buffer-exists-p ,buffer)
597         (with-current-buffer ,buffer
598           ,(when to-be-marked
599              (if (eq config 'forward)
600                  `(gnus-summary-mark-article-as-forwarded ',to-be-marked)
601                `(gnus-summary-mark-article-as-replied ',to-be-marked)))))
602      'send)))
603
604 (put 'gnus-setup-message 'lisp-indent-function 1)
605 (put 'gnus-setup-message 'edebug-form-spec '(form body))
606
607 ;;; Post news commands of Gnus group mode and summary mode
608
609 (defun gnus-group-mail (&optional arg)
610   "Start composing a mail.
611 If ARG, use the group under the point to find a posting style.
612 If ARG is 1, prompt for a group name to find the posting style."
613   (interactive "P")
614   ;; We can't `let' gnus-newsgroup-name here, since that leads
615   ;; to local variables leaking.
616   (let ((group gnus-newsgroup-name)
617         ;; make sure last viewed article doesn't affect posting styles:
618         (gnus-article-copy)
619         (buffer (current-buffer)))
620     (unwind-protect
621         (progn
622           (setq gnus-newsgroup-name
623                 (if arg
624                     (if (= 1 (prefix-numeric-value arg))
625                         (gnus-group-completing-read
626                          "Use posting style of group"
627                          nil (gnus-read-active-file-p))
628                       (gnus-group-group-name))
629                   ""))
630           ;; #### see comment in gnus-setup-message -- drv
631           (gnus-setup-message 'message (message-mail)))
632       (with-current-buffer buffer
633         (setq gnus-newsgroup-name group)))))
634
635 (defun gnus-group-news (&optional arg)
636   "Start composing a news.
637 If ARG, post to group under point.
638 If ARG is 1, prompt for group name to post to.
639
640 This function prepares a news even when using mail groups.  This is useful
641 for posting messages to mail groups without actually sending them over the
642 network.  The corresponding back end must have a 'request-post method."
643   (interactive "P")
644   ;; We can't `let' gnus-newsgroup-name here, since that leads
645   ;; to local variables leaking.
646   (let ((group gnus-newsgroup-name)
647         ;; make sure last viewed article doesn't affect posting styles:
648         (gnus-article-copy)
649         (buffer (current-buffer)))
650     (unwind-protect
651         (progn
652           (setq gnus-newsgroup-name
653                 (if arg
654                     (if (= 1 (prefix-numeric-value arg))
655                         (gnus-group-completing-read "Use group"
656                                                     nil
657                                                     (gnus-read-active-file-p))
658                       (gnus-group-group-name))
659                   ""))
660           ;; #### see comment in gnus-setup-message -- drv
661           (gnus-setup-message 'message
662             (message-news (gnus-group-real-name gnus-newsgroup-name))))
663       (with-current-buffer buffer
664         (setq gnus-newsgroup-name group)))))
665
666 (defun gnus-group-post-news (&optional arg)
667   "Start composing a message (a news by default).
668 If ARG, post to group under point.  If ARG is 1, prompt for group name.
669 Depending on the selected group, the message might be either a mail or
670 a news."
671   (interactive "P")
672   ;; Bind this variable here to make message mode hooks work ok.
673   (let ((gnus-newsgroup-name
674          (if arg
675              (if (= 1 (prefix-numeric-value arg))
676                  (gnus-group-completing-read "Newsgroup" nil
677                                              (gnus-read-active-file-p))
678                (or (gnus-group-group-name) ""))
679            ""))
680         ;; make sure last viewed article doesn't affect posting styles:
681         (gnus-article-copy))
682     (gnus-post-news 'post gnus-newsgroup-name nil nil nil nil
683                     (string= gnus-newsgroup-name ""))))
684
685 (defun gnus-summary-mail-other-window (&optional arg)
686   "Start composing a mail in another window.
687 Use the posting of the current group by default.
688 If ARG, don't do that.  If ARG is 1, prompt for group name to find the
689 posting style."
690   (interactive "P")
691   ;; We can't `let' gnus-newsgroup-name here, since that leads
692   ;; to local variables leaking.
693   (let ((group gnus-newsgroup-name)
694         ;; make sure last viewed article doesn't affect posting styles:
695         (gnus-article-copy)
696         (buffer (current-buffer)))
697     (unwind-protect
698         (progn
699           (setq gnus-newsgroup-name
700                 (if arg
701                     (if (= 1 (prefix-numeric-value arg))
702                         (gnus-group-completing-read "Use group"
703                                                     nil
704                                                     (gnus-read-active-file-p))
705                       "")
706                   gnus-newsgroup-name))
707           ;; #### see comment in gnus-setup-message -- drv
708           (gnus-setup-message 'message (message-mail)))
709       (with-current-buffer buffer
710         (setq gnus-newsgroup-name group)))))
711
712 (defun gnus-summary-news-other-window (&optional arg)
713   "Start composing a news in another window.
714 Post to the current group by default.
715 If ARG, don't do that.  If ARG is 1, prompt for group name to post to.
716
717 This function prepares a news even when using mail groups.  This is useful
718 for posting messages to mail groups without actually sending them over the
719 network.  The corresponding back end must have a 'request-post method."
720   (interactive "P")
721   ;; We can't `let' gnus-newsgroup-name here, since that leads
722   ;; to local variables leaking.
723   (let ((group gnus-newsgroup-name)
724         ;; make sure last viewed article doesn't affect posting styles:
725         (gnus-article-copy)
726         (buffer (current-buffer)))
727     (unwind-protect
728         (progn
729           (setq gnus-newsgroup-name
730                 (if arg
731                     (if (= 1 (prefix-numeric-value arg))
732                         (gnus-group-completing-read "Use group"
733                                                     nil
734                                                     (gnus-read-active-file-p))
735                       "")
736                   gnus-newsgroup-name))
737           ;; #### see comment in gnus-setup-message -- drv
738           (gnus-setup-message 'message
739             (progn
740               (message-news (gnus-group-real-name gnus-newsgroup-name))
741               (set (make-local-variable 'gnus-discouraged-post-methods)
742                    (remove
743                     (car (gnus-find-method-for-group gnus-newsgroup-name))
744                     gnus-discouraged-post-methods)))))
745       (with-current-buffer buffer
746         (setq gnus-newsgroup-name group)))))
747
748 (defun gnus-summary-post-news (&optional arg)
749   "Start composing a message.  Post to the current group by default.
750 If ARG, don't do that.  If ARG is 1, prompt for a group name to post to.
751 Depending on the selected group, the message might be either a mail or
752 a news."
753   (interactive "P")
754   ;; Bind this variable here to make message mode hooks work ok.
755   (let ((gnus-newsgroup-name
756          (if arg
757              (if (= 1 (prefix-numeric-value arg))
758                  (gnus-group-completing-read "Newsgroup" nil
759                                              (gnus-read-active-file-p))
760                "")
761            gnus-newsgroup-name))
762         ;; make sure last viewed article doesn't affect posting styles:
763         (gnus-article-copy))
764     (gnus-post-news 'post gnus-newsgroup-name)))
765
766
767 (defun gnus-summary-followup (yank &optional force-news)
768   "Compose a followup to an article.
769 If prefix argument YANK is non-nil, the original article is yanked
770 automatically.
771 YANK is a list of elements, where the car of each element is the
772 article number, and the cdr is the string to be yanked."
773   (interactive
774    (list (and current-prefix-arg
775               (gnus-summary-work-articles 1))))
776   (when yank
777     (gnus-summary-goto-subject
778      (if (listp (car yank))
779          (caar yank)
780        (car yank))))
781   (save-window-excursion
782     (gnus-summary-select-article))
783   (let ((headers (gnus-summary-article-header (gnus-summary-article-number)))
784         (gnus-newsgroup-name gnus-newsgroup-name))
785     ;; Send a followup.
786     (gnus-post-news nil gnus-newsgroup-name
787                     headers gnus-article-buffer
788                     yank nil force-news)
789     (gnus-summary-handle-replysign)))
790
791 (defun gnus-summary-followup-with-original (n &optional force-news)
792   "Compose a followup to an article and include the original article.
793 The text in the region will be yanked.  If the region isn't
794 active, the entire article will be yanked."
795   (interactive "P")
796   (gnus-summary-followup (gnus-summary-work-articles n) force-news))
797
798 (defun gnus-summary-followup-to-mail (&optional arg)
799   "Followup to the current mail message via news."
800   (interactive
801    (list (and current-prefix-arg
802               (gnus-summary-work-articles 1))))
803   (gnus-summary-followup arg t))
804
805 (defun gnus-summary-followup-to-mail-with-original (&optional arg)
806   "Followup to the current mail message via news."
807   (interactive "P")
808   (gnus-summary-followup (gnus-summary-work-articles arg) t))
809
810 (defun gnus-inews-yank-articles (articles)
811   (let (beg article yank-string)
812     (message-goto-body)
813     (while (setq article (pop articles))
814       (when (listp article)
815         (setq yank-string (nth 1 article)
816               article (nth 0 article)))
817       (save-window-excursion
818         (set-buffer gnus-summary-buffer)
819         (gnus-summary-select-article nil nil nil article)
820         (gnus-summary-remove-process-mark article))
821       (gnus-copy-article-buffer nil yank-string)
822       (let ((message-reply-buffer gnus-article-copy)
823             (message-reply-headers
824              ;; The headers are decoded.
825              (with-current-buffer gnus-article-copy
826                (save-restriction
827                  (nnheader-narrow-to-headers)
828                  (nnheader-parse-naked-head)))))
829         (message-yank-original)
830         (message-exchange-point-and-mark)
831         (setq beg (or beg (mark t))))
832       (when articles
833         (insert "\n")))
834     (push-mark)
835     (goto-char beg)))
836
837 (defun gnus-summary-cancel-article (&optional n symp)
838   "Cancel an article you posted.
839 Uses the process-prefix convention.  If given the symbolic
840 prefix `a', cancel using the standard posting method; if not
841 post using the current select method."
842   (interactive (gnus-interactive "P\ny"))
843   (let ((message-post-method
844          `(lambda (arg)
845             (gnus-post-method (eq ',symp 'a) ,gnus-newsgroup-name)))
846         (user-mail-address user-mail-address))
847     (dolist (article (gnus-summary-work-articles n))
848       (when (gnus-summary-select-article t nil nil article)
849         ;; Pretend that we're doing a followup so that we can see what
850         ;; the From header would have ended up being.
851         (save-window-excursion
852           (save-excursion
853             (gnus-summary-followup nil)
854             (let ((from (message-fetch-field "from")))
855               (when from
856                 (setq user-mail-address
857                       (car (mail-header-parse-address from)))))
858             (kill-buffer (current-buffer))))
859         ;; Now cancel the article using the From header we got.
860         (when (gnus-eval-in-buffer-window gnus-original-article-buffer
861                 (message-cancel-news))
862           (gnus-summary-mark-as-read article gnus-canceled-mark)
863           (gnus-cache-remove-article 1))
864         (gnus-article-hide-headers-if-wanted))
865       (gnus-summary-remove-process-mark article))))
866
867 (defun gnus-summary-supersede-article ()
868   "Compose an article that will supersede a previous article.
869 This is done simply by taking the old article and adding a Supersedes
870 header line with the old Message-ID."
871   (interactive)
872   (let ((article (gnus-summary-article-number))
873         (mail-parse-charset gnus-newsgroup-charset))
874     (gnus-setup-message 'reply-yank
875       (gnus-summary-select-article t)
876       (set-buffer gnus-original-article-buffer)
877       (message-supersede)
878       (push
879        `((lambda ()
880            (when (gnus-buffer-exists-p ,gnus-summary-buffer)
881              (with-current-buffer ,gnus-summary-buffer
882                (gnus-cache-possibly-remove-article ,article nil nil nil t)
883                (gnus-summary-mark-as-read ,article gnus-canceled-mark)))))
884        message-send-actions)
885       ;; Add Gcc header.
886       (gnus-inews-insert-gcc))))
887
888 \f
889
890 (defun gnus-copy-article-buffer (&optional article-buffer yank-string)
891   ;; make a copy of the article buffer with all text properties removed
892   ;; this copy is in the buffer gnus-article-copy.
893   ;; if ARTICLE-BUFFER is nil, gnus-article-buffer is used
894   ;; this buffer should be passed to all mail/news reply/post routines.
895   (setq gnus-article-copy (gnus-get-buffer-create " *gnus article copy*"))
896   (with-current-buffer gnus-article-copy
897     (mm-enable-multibyte))
898   (let ((article-buffer (or article-buffer gnus-article-buffer))
899         end beg)
900     (if (not (and (get-buffer article-buffer)
901                   (gnus-buffer-exists-p article-buffer)))
902         (error "Can't find any article buffer")
903       (with-current-buffer article-buffer
904         (let ((gnus-newsgroup-charset (or gnus-article-charset
905                                           gnus-newsgroup-charset))
906               (gnus-newsgroup-ignored-charsets
907                (or gnus-article-ignored-charsets
908                    gnus-newsgroup-ignored-charsets)))
909           (save-restriction
910             ;; Copy over the (displayed) article buffer, delete
911             ;; hidden text and remove text properties.
912             (widen)
913             (copy-to-buffer gnus-article-copy (point-min) (point-max))
914             (set-buffer gnus-article-copy)
915             (when yank-string
916               (message-goto-body)
917               (delete-region (point) (point-max))
918               (insert yank-string))
919             (gnus-article-delete-text-of-type 'annotation)
920             (gnus-article-delete-text-of-type 'multipart)
921             (gnus-remove-text-with-property 'gnus-prev)
922             (gnus-remove-text-with-property 'gnus-next)
923             (gnus-remove-text-with-property 'gnus-decoration)
924             (insert
925              (prog1
926                  (buffer-substring-no-properties (point-min) (point-max))
927                (erase-buffer)))
928             ;; Find the original headers.
929             (set-buffer gnus-original-article-buffer)
930             (goto-char (point-min))
931             (while (looking-at message-unix-mail-delimiter)
932               (forward-line 1))
933             (let ((mail-header-separator ""))
934               (setq beg (point)
935                     end (or (message-goto-body)
936                             ;; There may be just a header.
937                             (point-max))))
938             ;; Delete the headers from the displayed articles.
939             (set-buffer gnus-article-copy)
940             (let ((mail-header-separator ""))
941               (delete-region (goto-char (point-min))
942                              (or (message-goto-body) (point-max))))
943             ;; Insert the original article headers.
944             (insert-buffer-substring gnus-original-article-buffer beg end)
945             ;; Decode charsets.
946             (let ((gnus-article-decode-hook
947                    (delq 'article-decode-charset
948                          (copy-sequence gnus-article-decode-hook)))
949                   (rfc2047-quote-decoded-words-containing-tspecials t))
950               (run-hooks 'gnus-article-decode-hook)))))
951       gnus-article-copy)))
952
953 (defun gnus-post-news (post &optional group header article-buffer yank subject
954                             force-news)
955   (when article-buffer
956     (gnus-copy-article-buffer))
957   (let ((gnus-article-reply (and article-buffer (gnus-summary-article-number)))
958         (gnus-article-yanked-articles yank)
959         (add-to-list gnus-add-to-list))
960     (gnus-setup-message (cond (yank 'reply-yank)
961                               (article-buffer 'reply)
962                               (t 'message))
963       (let* ((group (or group gnus-newsgroup-name))
964              (charset (gnus-group-name-charset nil group))
965              (pgroup group)
966              to-address to-group mailing-list to-list
967              newsgroup-p)
968         (when group
969           (setq to-address (gnus-parameter-to-address group)
970                 to-group (gnus-group-find-parameter group 'to-group)
971                 to-list (gnus-parameter-to-list group)
972                 newsgroup-p (gnus-group-find-parameter group 'newsgroup)
973                 mailing-list (when gnus-mailing-list-groups
974                                (string-match gnus-mailing-list-groups group))
975                 group (gnus-group-name-decode (gnus-group-real-name group)
976                                               charset)))
977         (if (or (and to-group
978                      (gnus-news-group-p to-group))
979                 newsgroup-p
980                 force-news
981                 (and (gnus-news-group-p
982                       (or pgroup gnus-newsgroup-name)
983                       (or header gnus-current-article))
984                      (not mailing-list)
985                      (not to-list)
986                      (not to-address)))
987             ;; This is news.
988             (if post
989                 (message-news
990                  (or to-group
991                      (and (not (gnus-virtual-group-p pgroup)) group)))
992               (set-buffer gnus-article-copy)
993               (gnus-msg-treat-broken-reply-to)
994               (message-followup (if (or newsgroup-p force-news)
995                                     (if (save-restriction
996                                           (article-narrow-to-head)
997                                           (message-fetch-field "newsgroups"))
998                                         nil
999                                       "")
1000                                   to-group)))
1001           ;; The is mail.
1002           (if post
1003               (progn
1004                 (message-mail (or to-address to-list))
1005                 ;; Arrange for mail groups that have no `to-address' to
1006                 ;; get that when the user sends off the mail.
1007                 (when (and (not to-list)
1008                            (not to-address)
1009                            add-to-list)
1010                   (push (list 'gnus-inews-add-to-address pgroup)
1011                         message-send-actions)))
1012             (set-buffer gnus-article-copy)
1013             (gnus-msg-treat-broken-reply-to)
1014             (message-wide-reply to-address)))
1015         (when yank
1016           (gnus-inews-yank-articles yank))))))
1017
1018 (defun gnus-msg-treat-broken-reply-to (&optional force)
1019   "Remove the Reply-to header if broken-reply-to."
1020   (when (or force
1021             (gnus-group-find-parameter
1022              gnus-newsgroup-name 'broken-reply-to))
1023     (save-restriction
1024       (message-narrow-to-head)
1025       (message-remove-header "reply-to"))))
1026
1027 (defun gnus-post-method (arg group &optional silent)
1028   "Return the posting method based on GROUP and ARG.
1029 If SILENT, don't prompt the user."
1030   (let ((gnus-post-method (or (gnus-parameter-post-method group)
1031                               gnus-post-method))
1032         (group-method (gnus-find-method-for-group group)))
1033     (cond
1034      ;; If the group-method is nil (which shouldn't happen) we use
1035      ;; the default method.
1036      ((null group-method)
1037       (or (and (listp gnus-post-method) ;If not current/native/nil
1038                (not (listp (car gnus-post-method))) ; and not a list of methods
1039                gnus-post-method)        ;then use it.
1040           gnus-select-method
1041           message-post-method))
1042      ;; We want the inverse of the default
1043      ((and arg (not (eq arg 0)))
1044       (if (eq gnus-post-method 'current)
1045           gnus-select-method
1046         group-method))
1047      ;; We query the user for a post method.
1048      ((or arg
1049           (and (listp gnus-post-method)
1050                (listp (car gnus-post-method))))
1051       (let* ((methods
1052               ;; Collect all methods we know about.
1053               (append
1054                (when (listp gnus-post-method)
1055                  (if (listp (car gnus-post-method))
1056                      gnus-post-method
1057                    (list gnus-post-method)))
1058                gnus-secondary-select-methods
1059                (mapcar 'cdr gnus-server-alist)
1060                (mapcar 'car gnus-opened-servers)
1061                (list gnus-select-method)
1062                (list group-method)))
1063              method-alist post-methods method)
1064         ;; Weed out all mail methods.
1065         (while methods
1066           (setq method (gnus-server-get-method "" (pop methods)))
1067           (when (and (or (gnus-method-option-p method 'post)
1068                          (gnus-method-option-p method 'post-mail))
1069                      (not (member method post-methods)))
1070             (push method post-methods)))
1071         ;; Create a name-method alist.
1072         (setq method-alist
1073               (mapcar
1074                (lambda (m)
1075                  (if (equal (cadr m) "")
1076                      (list (symbol-name (car m)) m)
1077                    (list (concat (cadr m) " (" (symbol-name (car m)) ")") m)))
1078                post-methods))
1079         ;; Query the user.
1080         (cadr
1081          (assoc
1082           (setq gnus-last-posting-server
1083                 (if (and silent
1084                          gnus-last-posting-server)
1085                     ;; Just use the last value.
1086                     gnus-last-posting-server
1087                   (gnus-completing-read
1088                    "Posting method" (mapcar 'car method-alist) t
1089                    (cons (or gnus-last-posting-server "") 0))))
1090           method-alist))))
1091      ;; Override normal method.
1092      ((and (eq gnus-post-method 'current)
1093            (not (memq (car group-method) gnus-discouraged-post-methods))
1094            (gnus-get-function group-method 'request-post t))
1095       (assert (not arg))
1096       group-method)
1097      ;; Use gnus-post-method.
1098      ((listp gnus-post-method)          ;A method...
1099       (assert (not (listp (car gnus-post-method)))) ;... not a list of methods.
1100       gnus-post-method)
1101      ;; Use the normal select method (nil or native).
1102      (t gnus-select-method))))
1103
1104 \f
1105
1106 (defun gnus-extended-version ()
1107   "Stringified Gnus version and Emacs version.
1108 See the variable `gnus-user-agent'."
1109   (interactive)
1110   (if (stringp gnus-user-agent)
1111       gnus-user-agent
1112     ;; `gnus-user-agent' is a list:
1113     (let* ((float-output-format nil)
1114            (gnus-v
1115             (when (memq 'gnus gnus-user-agent)
1116               (concat "Gnus/"
1117                       (prin1-to-string (gnus-continuum-version gnus-version) t)
1118                       " (" gnus-version ")")))
1119            (emacs-v (gnus-emacs-version)))
1120       (concat gnus-v (when (and gnus-v emacs-v) " ")
1121               emacs-v))))
1122
1123 \f
1124 ;;;
1125 ;;; Gnus Mail Functions
1126 ;;;
1127
1128 ;;; Mail reply commands of Gnus summary mode
1129
1130 (defun gnus-summary-reply (&optional yank wide very-wide)
1131   "Start composing a mail reply to the current message.
1132 If prefix argument YANK is non-nil, the original article is yanked
1133 automatically.
1134 If WIDE, make a wide reply.
1135 If VERY-WIDE, make a very wide reply."
1136   (interactive
1137    (list (and current-prefix-arg
1138               (gnus-summary-work-articles 1))))
1139   ;; Allow user to require confirmation before replying by mail to the
1140   ;; author of a news article (or mail message).
1141   (when (or (not (or (gnus-news-group-p gnus-newsgroup-name)
1142                      gnus-confirm-treat-mail-like-news))
1143             (not (cond ((stringp gnus-confirm-mail-reply-to-news)
1144                         (string-match gnus-confirm-mail-reply-to-news
1145                                       gnus-newsgroup-name))
1146                        ((functionp gnus-confirm-mail-reply-to-news)
1147                         (funcall gnus-confirm-mail-reply-to-news
1148                                  gnus-newsgroup-name))
1149                        (t gnus-confirm-mail-reply-to-news)))
1150             (if (or wide very-wide)
1151                 t ;; Ignore gnus-confirm-mail-reply-to-news for wide and very
1152                   ;; wide replies.
1153               (y-or-n-p "Really reply by mail to article author? ")))
1154     (let* ((article
1155             (if (listp (car yank))
1156                 (caar yank)
1157               (car yank)))
1158            (gnus-article-reply (or article (gnus-summary-article-number)))
1159            (gnus-article-yanked-articles yank)
1160            (headers ""))
1161       ;; Stripping headers should be specified with mail-yank-ignored-headers.
1162       (when yank
1163         (gnus-summary-goto-subject article))
1164       (gnus-setup-message (if yank 'reply-yank 'reply)
1165         (if (not very-wide)
1166             (gnus-summary-select-article)
1167           (dolist (article very-wide)
1168             (gnus-summary-select-article nil nil nil article)
1169             (with-current-buffer (gnus-copy-article-buffer)
1170               (gnus-msg-treat-broken-reply-to)
1171               (save-restriction
1172                 (message-narrow-to-head)
1173                 (setq headers (concat headers (buffer-string)))))))
1174         (set-buffer (gnus-copy-article-buffer))
1175         (gnus-msg-treat-broken-reply-to gnus-msg-force-broken-reply-to)
1176         (save-restriction
1177           (message-narrow-to-head)
1178           (when very-wide
1179             (erase-buffer)
1180             (insert headers))
1181           (goto-char (point-max)))
1182         (mml-quote-region (point) (point-max))
1183         (message-reply nil wide)
1184         (when yank
1185           (gnus-inews-yank-articles yank))
1186         (gnus-summary-handle-replysign)))))
1187
1188 (defun gnus-summary-handle-replysign ()
1189   "Check the various replysign variables and take action accordingly."
1190   (when (or gnus-message-replysign gnus-message-replyencrypt)
1191     (let (signed encrypted)
1192       (with-current-buffer gnus-article-buffer
1193         (setq signed (memq 'signed gnus-article-wash-types))
1194         (setq encrypted (memq 'encrypted gnus-article-wash-types)))
1195       (cond ((and gnus-message-replyencrypt encrypted)
1196              (mml-secure-message mml-default-encrypt-method
1197                                  (if gnus-message-replysignencrypted
1198                                      'signencrypt
1199                                    'encrypt)))
1200             ((and gnus-message-replysign signed)
1201              (mml-secure-message mml-default-sign-method 'sign))))))
1202
1203 (defun gnus-summary-reply-with-original (n &optional wide)
1204   "Start composing a reply mail to the current message.
1205 The original article will be yanked."
1206   (interactive "P")
1207   (gnus-summary-reply (gnus-summary-work-articles n) wide))
1208
1209 (defun gnus-summary-reply-to-list-with-original (n &optional wide)
1210   "Start composing a reply mail to the current message.
1211 The reply goes only to the mailing list.
1212 The original article will be yanked."
1213   (interactive "P")
1214   (let ((message-reply-to-function
1215          (lambda nil
1216            `((To . ,(gnus-mailing-list-followup-to))))))
1217     (gnus-summary-reply (gnus-summary-work-articles n) wide)))
1218
1219 (defun gnus-summary-reply-broken-reply-to (&optional yank wide very-wide)
1220   "Like `gnus-summary-reply' except removing reply-to field.
1221 If prefix argument YANK is non-nil, the original article is yanked
1222 automatically.
1223 If WIDE, make a wide reply.
1224 If VERY-WIDE, make a very wide reply."
1225   (interactive
1226    (list (and current-prefix-arg
1227               (gnus-summary-work-articles 1))))
1228   (let ((gnus-msg-force-broken-reply-to t))
1229     (gnus-summary-reply yank wide very-wide)))
1230
1231 (defun gnus-summary-reply-broken-reply-to-with-original (n &optional wide)
1232   "Like `gnus-summary-reply-with-original' except removing reply-to field.
1233 The original article will be yanked."
1234   (interactive "P")
1235   (gnus-summary-reply-broken-reply-to (gnus-summary-work-articles n) wide))
1236
1237 (defun gnus-summary-wide-reply (&optional yank)
1238   "Start composing a wide reply mail to the current message.
1239 If prefix argument YANK is non-nil, the original article is yanked
1240 automatically."
1241   (interactive
1242    (list (and current-prefix-arg
1243               (gnus-summary-work-articles 1))))
1244   (gnus-summary-reply yank t))
1245
1246 (defun gnus-summary-wide-reply-with-original (n)
1247   "Start composing a wide reply mail to the current message.
1248 The original article will be yanked.
1249 Uses the process/prefix convention."
1250   (interactive "P")
1251   (gnus-summary-reply-with-original n t))
1252
1253 (defun gnus-summary-very-wide-reply (&optional yank)
1254   "Start composing a very wide reply mail to the current message.
1255 If prefix argument YANK is non-nil, the original article is yanked
1256 automatically."
1257   (interactive
1258    (list (and current-prefix-arg
1259               (gnus-summary-work-articles 1))))
1260   (gnus-summary-reply yank t (gnus-summary-work-articles yank)))
1261
1262 (defun gnus-summary-very-wide-reply-with-original (n)
1263   "Start composing a very wide reply mail to the current message.
1264 The original article will be yanked."
1265   (interactive "P")
1266   (gnus-summary-reply
1267    (gnus-summary-work-articles n) t (gnus-summary-work-articles n)))
1268
1269 (defun gnus-summary-mail-forward (&optional arg post)
1270   "Forward the current message(s) to another user.
1271 If process marks exist, forward all marked messages;
1272 if ARG is nil, see `message-forward-as-mime' and `message-forward-show-mml';
1273 if ARG is 1, decode the message and forward directly inline;
1274 if ARG is 2, forward message as an rfc822 MIME section;
1275 if ARG is 3, decode message and forward as an rfc822 MIME section;
1276 if ARG is 4, forward message directly inline;
1277 otherwise, use flipped `message-forward-as-mime'.
1278 If POST, post instead of mail.
1279 For the \"inline\" alternatives, also see the variable
1280 `message-forward-ignored-headers'."
1281   (interactive "P")
1282   (if (cdr (gnus-summary-work-articles nil))
1283       ;; Process marks are given.
1284       (gnus-uu-digest-mail-forward nil post)
1285     ;; No process marks.
1286     (let ((message-forward-as-mime message-forward-as-mime)
1287           (message-forward-show-mml message-forward-show-mml))
1288       (cond
1289        ((null arg))
1290        ((eq arg 1)
1291         (setq message-forward-as-mime nil
1292               message-forward-show-mml t))
1293        ((eq arg 2)
1294         (setq message-forward-as-mime t
1295               message-forward-show-mml nil))
1296        ((eq arg 3)
1297         (setq message-forward-as-mime t
1298               message-forward-show-mml t))
1299        ((eq arg 4)
1300         (setq message-forward-as-mime nil
1301               message-forward-show-mml nil))
1302        (t
1303         (setq message-forward-as-mime (not message-forward-as-mime))))
1304       (let* ((gnus-article-reply (gnus-summary-article-number))
1305              (gnus-article-yanked-articles (list gnus-article-reply)))
1306         (gnus-setup-message 'forward
1307           (gnus-summary-select-article)
1308           (let ((mail-parse-charset
1309                  (or (and (gnus-buffer-live-p gnus-article-buffer)
1310                           (with-current-buffer gnus-article-buffer
1311                             gnus-article-charset))
1312                      gnus-newsgroup-charset))
1313                 (mail-parse-ignored-charsets
1314                  gnus-newsgroup-ignored-charsets))
1315             (set-buffer gnus-original-article-buffer)
1316             (message-forward post)))))))
1317
1318 (defun gnus-summary-resend-message-insert-gcc ()
1319   "Insert Gcc header according to `gnus-gcc-self-resent-messages'."
1320   (gnus-inews-insert-gcc)
1321   (let ((gcc (mapcar
1322               (lambda (group)
1323                 (mm-encode-coding-string
1324                  group
1325                  (gnus-group-name-charset (gnus-inews-group-method group)
1326                                           group)))
1327               (message-unquote-tokens
1328                (message-tokenize-header (mail-fetch-field "gcc" nil t)
1329                                         " ,"))))
1330         (self (with-current-buffer gnus-summary-buffer
1331                 gnus-gcc-self-resent-messages)))
1332     (message-remove-header "gcc")
1333     (when gcc
1334       (goto-char (point-max))
1335       (cond ((eq self 'none))
1336             ((eq self t)
1337              (insert "Gcc: \"" gnus-newsgroup-name "\"\n"))
1338             ((stringp self)
1339              (insert "Gcc: "
1340                      (mm-encode-coding-string
1341                       (if (string-match " " self)
1342                           (concat "\"" self "\"")
1343                         self)
1344                       (gnus-group-name-charset (gnus-inews-group-method self)
1345                                                self))
1346                      "\n"))
1347             ((null self)
1348              (insert "Gcc: " (mapconcat 'identity gcc ", ") "\n"))
1349             ((eq self 'no-gcc-self)
1350              (when (setq gcc (delete
1351                               gnus-newsgroup-name
1352                               (delete (concat "\"" gnus-newsgroup-name "\"")
1353                                       gcc)))
1354                (insert "Gcc: " (mapconcat 'identity gcc ", ") "\n")))))))
1355
1356 (defun gnus-summary-resend-message (address n)
1357   "Resend the current article to ADDRESS."
1358   (interactive
1359    (list (message-read-from-minibuffer
1360           "Resend message(s) to: "
1361           (when (and gnus-summary-resend-default-address
1362                      (gnus-buffer-live-p gnus-original-article-buffer))
1363             ;; If some other article is currently selected, the
1364             ;; initial-contents is wrong. Whatever, it is just the
1365             ;; initial-contents.
1366             (with-current-buffer gnus-original-article-buffer
1367               (nnmail-fetch-field "to"))))
1368          current-prefix-arg))
1369   (let ((message-header-setup-hook (copy-sequence message-header-setup-hook))
1370         (message-sent-hook (copy-sequence message-sent-hook)))
1371     ;; `gnus-summary-resend-message-insert-gcc' must run last.
1372     (add-hook 'message-header-setup-hook
1373               'gnus-summary-resend-message-insert-gcc t)
1374     (add-hook 'message-sent-hook
1375               `(lambda ()
1376                  (let ((rfc2047-encode-encoded-words nil))
1377                    ,(if gnus-agent
1378                         '(gnus-agent-possibly-do-gcc)
1379                       '(gnus-inews-do-gcc)))))
1380     (dolist (article (gnus-summary-work-articles n))
1381       (gnus-summary-select-article nil nil nil article)
1382       (with-current-buffer gnus-original-article-buffer
1383         (let ((gnus-gcc-externalize-attachments nil)
1384               (message-inhibit-body-encoding t))
1385           (message-resend address)))
1386       (gnus-summary-mark-article-as-forwarded article))))
1387
1388 ;; From: Matthieu Moy <Matthieu.Moy@imag.fr>
1389 (defun gnus-summary-resend-message-edit ()
1390   "Resend an article that has already been sent.
1391 A new buffer will be created to allow the user to modify body and
1392 contents of the message, and then, everything will happen as when
1393 composing a new message."
1394   (interactive)
1395   (let ((mail-parse-charset gnus-newsgroup-charset))
1396     (gnus-setup-message 'reply-yank
1397       (gnus-summary-select-article t)
1398       (set-buffer gnus-original-article-buffer)
1399       (let ((cur (current-buffer))
1400             (to (message-fetch-field "to")))
1401         ;; Get a normal message buffer.
1402         (message-pop-to-buffer (message-buffer-name "Resend" to))
1403         (insert-buffer-substring cur)
1404         (mime-to-mml)
1405         (message-narrow-to-head-1)
1406         ;; Gnus will generate a new one when sending.
1407         (message-remove-header "Message-ID")
1408         ;; Remove unwanted headers.
1409         (message-remove-header message-ignored-resent-headers t)
1410         (goto-char (point-max))
1411         (insert mail-header-separator)
1412         ;; Add Gcc header.
1413         (gnus-inews-insert-gcc)
1414         (goto-char (point-min))
1415         (when (re-search-forward "^To:\\|^Newsgroups:" nil 'move)
1416           (forward-char 1))
1417         (widen)))))
1418
1419 (defun gnus-summary-post-forward (&optional arg)
1420   "Forward the current article to a newsgroup.
1421 See `gnus-summary-mail-forward' for ARG."
1422   (interactive "P")
1423   (gnus-summary-mail-forward arg t))
1424
1425 (defun gnus-summary-mail-crosspost-complaint (n)
1426   "Send a complaint about crossposting to the current article(s)."
1427   (interactive "P")
1428   (dolist (article (gnus-summary-work-articles n))
1429     (set-buffer gnus-summary-buffer)
1430     (gnus-summary-goto-subject article)
1431     (let ((group (gnus-group-real-name gnus-newsgroup-name))
1432           newsgroups followup-to)
1433       (gnus-summary-select-article)
1434       (set-buffer gnus-original-article-buffer)
1435       (if (and (<= (length (message-tokenize-header
1436                             (setq newsgroups
1437                                   (mail-fetch-field "newsgroups"))
1438                             ", "))
1439                    1)
1440                (or (not (setq followup-to (mail-fetch-field "followup-to")))
1441                    (not (member group (message-tokenize-header
1442                                        followup-to ", ")))))
1443           (if followup-to
1444               (gnus-message 1 "Followup-to restricted")
1445             (gnus-message 1 "Not a crossposted article"))
1446         (set-buffer gnus-summary-buffer)
1447         (gnus-summary-reply-with-original 1)
1448         (set-buffer gnus-message-buffer)
1449         (message-goto-body)
1450         (insert (format gnus-crosspost-complaint newsgroups group))
1451         (message-goto-subject)
1452         (re-search-forward " *$")
1453         (replace-match " (crosspost notification)" t t)
1454         (gnus-deactivate-mark)
1455         (when (gnus-y-or-n-p "Send this complaint? ")
1456           (message-send-and-exit))))))
1457
1458 (defun gnus-mail-parse-comma-list ()
1459   (let (accumulated
1460         beg)
1461     (skip-chars-forward " ")
1462     (while (not (eobp))
1463       (setq beg (point))
1464       (skip-chars-forward "^,")
1465       (while (zerop
1466               (save-excursion
1467                 (save-restriction
1468                   (let ((i 0))
1469                     (narrow-to-region beg (point))
1470                     (goto-char beg)
1471                     (logand (progn
1472                               (while (search-forward "\"" nil t)
1473                                 (incf i))
1474                               (if (zerop i) 2 i))
1475                             2)))))
1476         (skip-chars-forward ",")
1477         (skip-chars-forward "^,"))
1478       (skip-chars-backward " ")
1479       (push (buffer-substring beg (point))
1480             accumulated)
1481       (skip-chars-forward "^,")
1482       (skip-chars-forward ", "))
1483     accumulated))
1484
1485 (defun gnus-inews-add-to-address (group)
1486   (let ((to-address (mail-fetch-field "to")))
1487     (when (and to-address
1488                (gnus-alive-p))
1489       ;; This mail group doesn't have a `to-list', so we add one
1490       ;; here.  Magic!
1491       (when (gnus-y-or-n-p
1492              (format "Do you want to add this as `to-list': %s? " to-address))
1493         (gnus-group-add-parameter group (cons 'to-list to-address))))))
1494
1495 (defun gnus-put-message ()
1496   "Put the current message in some group and return to Gnus."
1497   (interactive)
1498   (let ((reply gnus-article-reply)
1499         (winconf gnus-prev-winconf)
1500         (group gnus-newsgroup-name))
1501     (unless (and group
1502                  (not (gnus-group-read-only-p group)))
1503       (setq group (read-string "Put in group: " nil (gnus-writable-groups))))
1504
1505     (when (gnus-group-entry group)
1506       (error "No such group: %s" group))
1507     (save-excursion
1508       (save-restriction
1509         (widen)
1510         (message-narrow-to-headers)
1511         (let ((gnus-deletable-headers nil))
1512           (message-generate-headers
1513            (if (message-news-p)
1514                message-required-news-headers
1515              message-required-mail-headers)))
1516         (goto-char (point-max))
1517         (if (string-match " " group)
1518             (insert "Gcc: \"" group "\"\n")
1519           (insert "Gcc: " group "\n"))
1520         (widen)))
1521     (gnus-inews-do-gcc)
1522     (when (and (get-buffer gnus-group-buffer)
1523                (gnus-buffer-exists-p (car-safe reply))
1524                (cdr reply))
1525       (set-buffer (car reply))
1526       (gnus-summary-mark-article-as-replied (cdr reply)))
1527     (when winconf
1528       (set-window-configuration winconf))))
1529
1530 (defun gnus-article-mail (yank)
1531   "Send a reply to the address near point.
1532 If YANK is non-nil, include the original article."
1533   (interactive "P")
1534   (let ((address
1535          (buffer-substring
1536           (save-excursion (re-search-backward "[ \t\n]" nil t) (1+ (point)))
1537           (save-excursion (re-search-forward "[ \t\n]" nil t) (1- (point))))))
1538     (when address
1539       (gnus-msg-mail address)
1540       (when yank
1541         (gnus-inews-yank-articles (list (cdr gnus-article-current)))))))
1542
1543 (defvar nntp-server-type)
1544 (defun gnus-bug ()
1545   "Send a bug report to the Gnus maintainers."
1546   (interactive)
1547   (unless (gnus-alive-p)
1548     (error "Gnus has been shut down"))
1549   (gnus-setup-message (if (message-mail-user-agent) 'message 'bug)
1550     (unless (message-mail-user-agent)
1551       (when gnus-bug-create-help-buffer
1552         (switch-to-buffer "*Gnus Help Bug*")
1553         (erase-buffer)
1554         (insert gnus-bug-message)
1555         (goto-char (point-min)))
1556       (message-pop-to-buffer "*Gnus Bug*"))
1557     (let ((message-this-is-mail t))
1558       (message-setup `((To . ,gnus-maintainer)
1559                        (Subject . "")
1560                        (X-Debbugs-Package
1561                         . ,(format "%s" gnus-bug-package))
1562                        (X-Debbugs-Version
1563                         . ,(format "%s" (gnus-continuum-version))))))
1564     (when gnus-bug-create-help-buffer
1565       (push `(gnus-bug-kill-buffer) message-send-actions))
1566     (goto-char (point-min))
1567     (message-goto-body)
1568     (insert "\n\n\n\n\n")
1569     (insert (gnus-version) "\n"
1570             (emacs-version) "\n")
1571     (when (and (boundp 'nntp-server-type)
1572                (stringp nntp-server-type))
1573       (insert nntp-server-type))
1574     (goto-char (point-min))
1575     (search-forward "Subject: " nil t)
1576     (message "")))
1577
1578 (defun gnus-bug-kill-buffer ()
1579   (when (get-buffer "*Gnus Help Bug*")
1580     (kill-buffer "*Gnus Help Bug*")))
1581
1582 (defun gnus-summary-yank-message (buffer n)
1583   "Yank the current article into a composed message."
1584   (interactive
1585    (list (gnus-completing-read "Buffer" (message-buffers) t)
1586          current-prefix-arg))
1587   (gnus-summary-iterate n
1588     (let ((gnus-inhibit-treatment t))
1589       (gnus-summary-select-article))
1590     (with-current-buffer buffer
1591       (message-yank-buffer gnus-article-buffer))))
1592
1593 ;;; Treatment of rejected articles.
1594 ;;; Bounced mail.
1595
1596 (defun gnus-summary-resend-bounced-mail (&optional fetch)
1597   "Re-mail the current message.
1598 This only makes sense if the current message is a bounce message that
1599 contains some mail you have written which has been bounced back to
1600 you.
1601 If FETCH, try to fetch the article that this is a reply to, if indeed
1602 this is a reply."
1603   (interactive "P")
1604   (gnus-summary-select-article t)
1605   (let (summary-buffer parent)
1606     (if fetch
1607         (progn
1608           (setq summary-buffer (current-buffer))
1609           (set-buffer gnus-original-article-buffer)
1610           (article-goto-body)
1611           (when (re-search-forward "^References:\n?" nil t)
1612             (while (memq (char-after) '(?\t ? ))
1613               (forward-line 1))
1614             (skip-chars-backward "\t\n ")
1615             (setq parent
1616                   (gnus-parent-id (buffer-substring (match-end 0) (point))))))
1617       (set-buffer gnus-original-article-buffer))
1618     (gnus-setup-message 'compose-bounce
1619       (message-bounce)
1620       ;; Add Gcc header.
1621       (gnus-inews-insert-gcc)
1622       ;; If there are references, we fetch the article we answered to.
1623       (when parent
1624         (with-current-buffer summary-buffer
1625           (gnus-summary-refer-article parent)
1626           (gnus-summary-show-all-headers))))))
1627
1628 ;;; Gcc handling.
1629
1630 (defun gnus-inews-group-method (group)
1631   (cond
1632    ;; If the group doesn't exist, we assume
1633    ;; it's an archive group...
1634    ((and (null (gnus-get-info group))
1635          (eq (car (gnus-server-to-method gnus-message-archive-method))
1636              (car (gnus-server-to-method (gnus-group-method group)))))
1637     gnus-message-archive-method)
1638    ;; Use the method.
1639    ((gnus-info-method (gnus-get-info group))
1640     (gnus-info-method (gnus-get-info group)))
1641    ;; Find the method.
1642    (t (gnus-server-to-method (gnus-group-method group)))))
1643
1644 ;; Do Gcc handling, which copied the message over to some group.
1645 (defun gnus-inews-do-gcc (&optional gcc)
1646   (interactive)
1647   (save-excursion
1648     (save-restriction
1649       (message-narrow-to-headers)
1650       (let ((gcc (or gcc (mail-fetch-field "gcc" nil t)))
1651             (cur (current-buffer))
1652             groups group method group-art options
1653             mml-externalize-attachments)
1654         (when gcc
1655           (message-remove-header "gcc")
1656           (widen)
1657           (setq groups (message-unquote-tokens
1658                         (message-tokenize-header gcc " ,")))
1659           ;; Copy the article over to some group(s).
1660           (while (setq group (pop groups))
1661             (setq method (gnus-inews-group-method group)
1662                   group (mm-encode-coding-string
1663                          group
1664                          (gnus-group-name-charset method group)))
1665             (unless (gnus-check-server method)
1666               (error "Can't open server %s" (if (stringp method) method
1667                                               (car method))))
1668             (unless (gnus-request-group group t method)
1669               (gnus-request-create-group group method))
1670             (setq mml-externalize-attachments
1671                   (if (stringp gnus-gcc-externalize-attachments)
1672                       (string-match gnus-gcc-externalize-attachments group)
1673                     gnus-gcc-externalize-attachments))
1674             (save-excursion
1675               (nnheader-set-temp-buffer " *acc*")
1676               (setq message-options (with-current-buffer cur message-options))
1677               (insert-buffer-substring cur)
1678               (run-hooks 'gnus-gcc-pre-body-encode-hook)
1679               (message-encode-message-body)
1680               (run-hooks 'gnus-gcc-post-body-encode-hook)
1681               (save-restriction
1682                 (message-narrow-to-headers)
1683                 (let* ((mail-parse-charset message-default-charset)
1684                        (newsgroups-field (save-restriction
1685                                            (message-narrow-to-headers-or-head)
1686                                            (message-fetch-field "Newsgroups")))
1687                        (followup-field (save-restriction
1688                                          (message-narrow-to-headers-or-head)
1689                                          (message-fetch-field "Followup-To")))
1690                        ;; BUG: We really need to get the charset for
1691                        ;; each name in the Newsgroups and Followup-To
1692                        ;; lines to allow crossposting between group
1693                        ;; names with incompatible character sets.
1694                        ;; -- Per Abrahamsen <abraham@dina.kvl.dk> 2001-10-08.
1695                        (group-field-charset
1696                         (gnus-group-name-charset
1697                          method (or newsgroups-field "")))
1698                        (followup-field-charset
1699                         (gnus-group-name-charset
1700                          method (or followup-field "")))
1701                        (rfc2047-header-encoding-alist
1702                         (append
1703                          (when group-field-charset
1704                            (list (cons "Newsgroups" group-field-charset)))
1705                          (when followup-field-charset
1706                            (list (cons "Followup-To" followup-field-charset)))
1707                          rfc2047-header-encoding-alist)))
1708                   (mail-encode-encoded-word-buffer)))
1709               (goto-char (point-min))
1710               (when (re-search-forward
1711                      (concat "^" (regexp-quote mail-header-separator) "$")
1712                      nil t)
1713                 (replace-match "" t t ))
1714               (when (or (not (gnus-check-backend-function
1715                               'request-accept-article group))
1716                         (not (setq group-art
1717                                    (gnus-request-accept-article
1718                                     group method t t))))
1719                 (gnus-message 1 "Couldn't store article in group %s: %s"
1720                               group (gnus-status-message method)))
1721               (when (stringp method)
1722                 (setq method (gnus-server-to-method method)))
1723               (when (and (listp method)
1724                          (gnus-native-method-p method))
1725                 (setq group (gnus-group-short-name group)))
1726               (when (and group-art
1727                          ;; FIXME: Should gcc-mark-as-read work when
1728                          ;; Gnus is not running?
1729                          (gnus-alive-p))
1730                 (if (or gnus-gcc-mark-as-read
1731                         (and (boundp 'gnus-inews-mark-gcc-as-read)
1732                              (symbol-value 'gnus-inews-mark-gcc-as-read)))
1733                     (gnus-group-mark-article-read group (cdr group-art))
1734                   (with-current-buffer gnus-group-buffer
1735                     (let ((gnus-group-marked (list group))
1736                           (gnus-get-new-news-hook nil)
1737                           (inhibit-read-only t))
1738                       (gnus-group-get-new-news-this-group nil t)))))
1739               (setq options message-options)
1740               (with-current-buffer cur (setq message-options options))
1741               (kill-buffer (current-buffer)))))))))
1742
1743 (defun gnus-inews-insert-gcc (&optional group)
1744   "Insert the Gcc to say where the article is to be archived."
1745   (let* ((group (or group gnus-newsgroup-name))
1746          (group (when group (gnus-group-decoded-name group)))
1747          (var (or gnus-outgoing-message-group gnus-message-archive-group))
1748          (gcc-self-val
1749           (and group (gnus-group-find-parameter group 'gcc-self)))
1750          result
1751          (groups
1752           (cond
1753            ((null gnus-message-archive-method)
1754             ;; Ignore.
1755             nil)
1756            ((stringp var)
1757             ;; Just a single group.
1758             (list var))
1759            ((null var)
1760             ;; We don't want this.
1761             nil)
1762            ((and (listp var) (stringp (car var)))
1763             ;; A list of groups.
1764             var)
1765            ((functionp var)
1766             ;; A function.
1767             (funcall var group))
1768            (group
1769             ;; An alist of regexps/functions/forms.
1770             (while (and var
1771                         (not
1772                          (setq result
1773                                (cond
1774                                 ((and group
1775                                       (stringp (caar var)))
1776                                  ;; Regexp.
1777                                  (when (string-match (caar var) group)
1778                                    (cdar var)))
1779                                 ((and group
1780                                       (functionp (car var)))
1781                                  ;; Function.
1782                                  (funcall (car var) group))
1783                                 (t
1784                                  (eval (car var)))))))
1785               (setq var (cdr var)))
1786             result)))
1787          name)
1788     (when (or groups gcc-self-val)
1789       (when (stringp groups)
1790         (setq groups (list groups)))
1791       (save-excursion
1792         (save-restriction
1793           (message-narrow-to-headers)
1794           (goto-char (point-max))
1795           (insert "Gcc: ")
1796           (if gcc-self-val
1797               ;; Use the `gcc-self' param value instead.
1798               (progn
1799                 (insert
1800                  (if (stringp gcc-self-val)
1801                      (if (string-match " " gcc-self-val)
1802                          (concat "\"" gcc-self-val "\"")
1803                        gcc-self-val)
1804                    ;; In nndoc groups, we use the parent group name
1805                    ;; instead of the current group.
1806                    (let ((group (or (gnus-group-find-parameter
1807                                      gnus-newsgroup-name 'parent-group)
1808                                     group)))
1809                      (if (string-match " " group)
1810                          (concat "\"" group "\"")
1811                        group))))
1812                 (if (not (eq gcc-self-val 'none))
1813                     (insert "\n")
1814                   (gnus-delete-line)))
1815             ;; Use the list of groups.
1816             (while (setq name (pop groups))
1817               (let ((str (if (string-match ":" name)
1818                              name
1819                            (gnus-group-prefixed-name
1820                             name gnus-message-archive-method))))
1821                 (insert (if (string-match " " str)
1822                             (concat "\"" str "\"")
1823                           str)))
1824               (when groups
1825                 (insert " ")))
1826             (insert "\n")))))))
1827
1828 (defun gnus-mailing-list-followup-to ()
1829   "Look at the headers in the current buffer and return a Mail-Followup-To address."
1830   (let ((x-been-there (gnus-fetch-original-field "x-beenthere"))
1831         (list-post (gnus-fetch-original-field "list-post")))
1832     (when (and list-post
1833                (string-match "mailto:\\([^>]+\\)" list-post))
1834       (setq list-post (match-string 1 list-post)))
1835     (or list-post
1836         x-been-there)))
1837
1838 ;;; Posting styles.
1839
1840 (defun gnus-configure-posting-styles (&optional group-name)
1841   "Configure posting styles according to `gnus-posting-styles'."
1842   (unless gnus-inhibit-posting-styles
1843     (let ((group (or group-name gnus-newsgroup-name ""))
1844           (styles (if (gnus-buffer-live-p gnus-summary-buffer)
1845                       (with-current-buffer gnus-summary-buffer
1846                         gnus-posting-styles)
1847                     gnus-posting-styles))
1848           style match attribute value v results
1849           filep name address element)
1850       ;; If the group has a posting-style parameter, add it at the end with a
1851       ;; regexp matching everything, to be sure it takes precedence over all
1852       ;; the others.
1853       (when gnus-newsgroup-name
1854         (let ((tmp-style (gnus-group-find-parameter group 'posting-style t)))
1855           (when tmp-style
1856             (setq styles (append styles (list (cons ".*" tmp-style)))))))
1857       ;; Go through all styles and look for matches.
1858       (dolist (style styles)
1859         (setq match (pop style))
1860         (goto-char (point-min))
1861         (when (cond
1862                ((stringp match)
1863                 ;; Regexp string match on the group name.
1864                 (string-match match group))
1865                ((eq match 'header)
1866                 ;; Obsolete format of header match.
1867                 (and (gnus-buffer-live-p gnus-article-copy)
1868                      (with-current-buffer gnus-article-copy
1869                        (save-restriction
1870                          (nnheader-narrow-to-headers)
1871                          (let ((header (message-fetch-field (pop style))))
1872                            (and header
1873                                 (string-match (pop style) header)))))))
1874                ((or (symbolp match)
1875                     (functionp match))
1876                 (cond
1877                  ((functionp match)
1878                   ;; Function to be called.
1879                   (funcall match))
1880                  ((boundp match)
1881                   ;; Variable to be checked.
1882                   (symbol-value match))))
1883                ((listp match)
1884                 (cond
1885                  ((eq (car match) 'header)
1886                   ;; New format of header match.
1887                   (and (gnus-buffer-live-p gnus-article-copy)
1888                        (with-current-buffer gnus-article-copy
1889                          (save-restriction
1890                            (nnheader-narrow-to-headers)
1891                            (let ((header (message-fetch-field (nth 1 match))))
1892                              (and header
1893                                   (string-match (nth 2 match) header)))))))
1894                  (t
1895                   ;; This is a form to be evalled.
1896                   (eval match)))))
1897           ;; We have a match, so we set the variables.
1898           (dolist (attribute style)
1899             (setq element (pop attribute)
1900                   filep nil)
1901             (setq value
1902                   (cond
1903                    ((eq (car attribute) :file)
1904                     (setq filep t)
1905                     (cadr attribute))
1906                    ((eq (car attribute) :value)
1907                     (cadr attribute))
1908                    (t
1909                     (car attribute))))
1910             ;; We get the value.
1911             (setq v
1912                   (cond
1913                    ((stringp value)
1914                     (if (and (stringp match)
1915                              (gnus-string-match-p "\\\\[&[:digit:]]" value)
1916                              (match-beginning 1))
1917                         (gnus-match-substitute-replacement value nil nil group)
1918                       value))
1919                    ((or (symbolp value)
1920                         (functionp value))
1921                     (cond ((functionp value)
1922                            (funcall value))
1923                           ((boundp value)
1924                            (symbol-value value))))
1925                    ((listp value)
1926                     (eval value))))
1927             ;; Translate obsolescent value.
1928             (cond
1929              ((eq element 'signature-file)
1930               (setq element 'signature
1931                     filep t))
1932              ((eq element 'x-face-file)
1933               (setq element 'x-face
1934                     filep t)))
1935             ;; Post-processing for the signature posting-style:
1936             (and (eq element 'signature) filep
1937                  message-signature-directory
1938                  ;; don't actually use the signature directory
1939                  ;; if message-signature-file contains a path.
1940                  (not (file-name-directory v))
1941                  (setq v (nnheader-concat message-signature-directory v)))
1942             ;; Get the contents of file elems.
1943             (when (and filep v)
1944               (setq v (with-temp-buffer
1945                         (insert-file-contents v)
1946                         (buffer-substring
1947                          (point-min)
1948                          (progn
1949                            (goto-char (point-max))
1950                            (if (zerop (skip-chars-backward "\n"))
1951                                (point)
1952                              (1+ (point))))))))
1953             (setq results (delq (assoc element results) results))
1954             (push (cons element v) results))))
1955       ;; Now we have all the styles, so we insert them.
1956       (setq name (assq 'name results)
1957             address (assq 'address results))
1958       (setq results (delq name (delq address results)))
1959       (gnus-make-local-hook 'message-setup-hook)
1960       (setq results (sort results (lambda (x y)
1961                                     (string-lessp (car x) (car y)))))
1962       (dolist (result results)
1963         (add-hook 'message-setup-hook
1964                   (cond
1965                    ((eq 'eval (car result))
1966                     'ignore)
1967                    ((eq 'body (car result))
1968                     `(lambda ()
1969                        (save-excursion
1970                          (message-goto-body)
1971                          (insert ,(cdr result)))))
1972                    ((eq 'signature (car result))
1973                     (set (make-local-variable 'message-signature) nil)
1974                     (set (make-local-variable 'message-signature-file) nil)
1975                     (if (not (cdr result))
1976                         'ignore
1977                       `(lambda ()
1978                          (save-excursion
1979                            (let ((message-signature ,(cdr result)))
1980                              (when message-signature
1981                                (message-insert-signature)))))))
1982                    (t
1983                     (let ((header
1984                            (if (symbolp (car result))
1985                                (capitalize (symbol-name (car result)))
1986                              (car result))))
1987                       `(lambda ()
1988                          (save-excursion
1989                            (message-remove-header ,header)
1990                            (let ((value ,(cdr result)))
1991                              (when value
1992                                (message-goto-eoh)
1993                                (insert ,header ": " value)
1994                                (unless (bolp)
1995                                  (insert "\n")))))))))
1996                   nil 'local))
1997       (when (or name address)
1998         (add-hook 'message-setup-hook
1999                   `(lambda ()
2000                      (set (make-local-variable 'user-mail-address)
2001                           ,(or (cdr address) user-mail-address))
2002                      (let ((user-full-name ,(or (cdr name) (user-full-name)))
2003                            (user-mail-address
2004                             ,(or (cdr address) user-mail-address)))
2005                        (save-excursion
2006                          (message-remove-header "From")
2007                          (message-goto-eoh)
2008                          (insert "From: " (message-make-from) "\n"))))
2009                   nil 'local)))))
2010
2011 ;;; Allow redefinition of functions.
2012
2013 (gnus-ems-redefine)
2014
2015 (provide 'gnus-msg)
2016
2017 ;;; gnus-msg.el ends here