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