1 ;;; gnus-art.el --- article mode commands for Gnus
3 ;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
4 ;; 2005, 2006, 2007 Free Software Foundation, Inc.
6 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
9 ;; This file is part of GNU Emacs.
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 2, or (at your option)
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.
21 ;; You should have received a copy of the GNU General Public License
22 ;; along with GNU Emacs; see the file COPYING. If not, write to the
23 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24 ;; Boston, MA 02110-1301, USA.
33 (defvar w3m-minor-mode-map))
36 ;; Avoid the "Recursive load suspected" error in Emacs 21.1.
38 (let ((recursive-load-depth-limit 100))
51 (autoload 'gnus-msg-mail "gnus-msg" nil t)
52 (autoload 'gnus-button-mailto "gnus-msg")
53 (autoload 'gnus-button-reply "gnus-msg" nil t)
54 (autoload 'parse-time-string "parse-time" nil nil)
55 (autoload 'ansi-color-apply-on-region "ansi-color")
56 (autoload 'mm-url-insert-file-contents-external "mm-url")
57 (autoload 'mm-extern-cache-contents "mm-extern")
59 (defgroup gnus-article nil
61 :link '(custom-manual "(gnus)Article Buffer")
64 (defgroup gnus-article-treat nil
65 "Treating article parts."
66 :link '(custom-manual "(gnus)Article Hiding")
69 (defgroup gnus-article-hiding nil
70 "Hiding article parts."
71 :link '(custom-manual "(gnus)Article Hiding")
74 (defgroup gnus-article-highlight nil
75 "Article highlighting."
76 :link '(custom-manual "(gnus)Article Highlighting")
80 (defgroup gnus-article-signature nil
82 :link '(custom-manual "(gnus)Article Signature")
85 (defgroup gnus-article-headers nil
87 :link '(custom-manual "(gnus)Hiding Headers")
90 (defgroup gnus-article-washing nil
91 "Special commands on articles."
92 :link '(custom-manual "(gnus)Article Washing")
95 (defgroup gnus-article-emphasis nil
96 "Fontisizing articles."
97 :link '(custom-manual "(gnus)Article Fontisizing")
100 (defgroup gnus-article-saving nil
102 :link '(custom-manual "(gnus)Saving Articles")
103 :group 'gnus-article)
105 (defgroup gnus-article-mime nil
106 "Worshiping the MIME wonder."
107 :link '(custom-manual "(gnus)Using MIME")
108 :group 'gnus-article)
110 (defgroup gnus-article-buttons nil
111 "Pushable buttons in the article buffer."
112 :link '(custom-manual "(gnus)Article Buttons")
113 :group 'gnus-article)
115 (defgroup gnus-article-various nil
116 "Other article options."
117 :link '(custom-manual "(gnus)Misc Article")
118 :group 'gnus-article)
120 (defcustom gnus-ignored-headers
123 (concat "^" header ":"))
124 '("Path" "Expires" "Date-Received" "References" "Xref" "Lines"
125 "Relay-Version" "Message-ID" "Approved" "Sender" "Received"
126 "X-UIDL" "MIME-Version" "Return-Path" "In-Reply-To"
127 "Content-Type" "Content-Transfer-Encoding" "X-WebTV-Signature"
128 "X-MimeOLE" "X-MSMail-Priority" "X-Priority" "X-Loop"
129 "X-Authentication-Warning" "X-MIME-Autoconverted" "X-Face"
130 "X-Attribution" "X-Originating-IP" "Delivered-To"
131 "NNTP-[-A-Za-z]+" "Distribution" "X-no-archive" "X-Trace"
132 "X-Complaints-To" "X-NNTP-Posting-Host" "X-Orig.*"
133 "Abuse-Reports-To" "Cache-Post-Path" "X-Article-Creation-Date"
134 "X-Poster" "X-Mail2News-Path" "X-Server-Date" "X-Cache"
135 "Originator" "X-Problems-To" "X-Auth-User" "X-Post-Time"
136 "X-Admin" "X-UID" "Resent-[-A-Za-z]+" "X-Mailing-List"
137 "Precedence" "Original-[-A-Za-z]+" "X-filename" "X-Orcpt"
138 "Old-Received" "X-Pgp" "X-Auth" "X-From-Line"
139 "X-Gnus-Article-Number" "X-Majordomo" "X-Url" "X-Sender"
140 "MBOX-Line" "Priority" "X400-[-A-Za-z]+"
141 "Status" "X-Gnus-Mail-Source" "Cancel-Lock"
142 "X-FTN" "X-EXP32-SerialNo" "Encoding" "Importance"
143 "Autoforwarded" "Original-Encoded-Information-Types" "X-Ya-Pop3"
144 "X-Face-Version" "X-Vms-To" "X-ML-NAME" "X-ML-COUNT"
145 "Mailing-List" "X-finfo" "X-md5sum" "X-md5sum-Origin"
146 "X-Sun-Charset" "X-Accept-Language" "X-Envelope-Sender"
147 "List-[A-Za-z]+" "X-Listprocessor-Version"
148 "X-Received" "X-Distribute" "X-Sequence" "X-Juno-Line-Breaks"
149 "X-Notes-Item" "X-MS-TNEF-Correlator" "x-uunet-gateway"
150 "X-Received" "Content-length" "X-precedence"
151 "X-Authenticated-User" "X-Comment" "X-Report" "X-Abuse-Info"
152 "X-HTTP-Proxy" "X-Mydeja-Info" "X-Copyright" "X-No-Markup"
153 "X-Abuse-Info" "X-From_" "X-Accept-Language" "Errors-To"
154 "X-BeenThere" "X-Mailman-Version" "List-Help" "List-Post"
155 "List-Subscribe" "List-Id" "List-Unsubscribe" "List-Archive"
156 "X-Content-length" "X-Posting-Agent" "Original-Received"
157 "X-Request-PGP" "X-Fingerprint" "X-WRIEnvto" "X-WRIEnvfrom"
158 "X-Virus-Scanned" "X-Delivery-Agent" "Posted-Date" "X-Gateway"
159 "X-Local-Origin" "X-Local-Destination" "X-UserInfo1"
160 "X-Received-Date" "X-Hashcash" "Face" "X-DMCA-Notifications"
161 "X-Abuse-and-DMCA-Info" "X-Postfilter" "X-Gpg-.*" "X-Disclaimer"
162 "Envelope-To" "X-Spam-Score" "System-Type" "X-Injected-Via-Gmane"
163 "X-Gmane-NNTP-Posting-Host" "Jabber-ID" "Archived-At"
164 "Envelope-Sender" "Envelope-Recipients"))
165 "*All headers that start with this regexp will be hidden.
166 This variable can also be a list of regexps of headers to be ignored.
167 If `gnus-visible-headers' is non-nil, this variable will be ignored."
168 :type '(choice :custom-show nil
171 :group 'gnus-article-hiding)
173 (defcustom gnus-visible-headers
174 "^From:\\|^Newsgroups:\\|^Subject:\\|^Date:\\|^Followup-To:\\|^Reply-To:\\|^Organization:\\|^Summary:\\|^Keywords:\\|^To:\\|^[BGF]?Cc:\\|^Posted-To:\\|^Mail-Copies-To:\\|^Mail-Followup-To:\\|^Apparently-To:\\|^Gnus-Warning:\\|^Resent-From:\\|^X-Sent:"
175 "*All headers that do not match this regexp will be hidden.
176 This variable can also be a list of regexp of headers to remain visible.
177 If this variable is non-nil, `gnus-ignored-headers' will be ignored."
178 :type '(repeat :value-to-internal (lambda (widget value)
179 (custom-split-regexp-maybe value))
180 :match (lambda (widget value)
182 (widget-editable-list-match widget value)))
184 :group 'gnus-article-hiding)
186 (defcustom gnus-sorted-header-list
187 '("^From:" "^Subject:" "^Summary:" "^Keywords:" "^Newsgroups:"
188 "^Followup-To:" "^To:" "^Cc:" "^Date:" "^Organization:")
189 "*This variable is a list of regular expressions.
190 If it is non-nil, headers that match the regular expressions will
191 be placed first in the article buffer in the sequence specified by
193 :type '(repeat regexp)
194 :group 'gnus-article-hiding)
196 (defcustom gnus-boring-article-headers '(empty followup-to reply-to)
197 "Headers that are only to be displayed if they have interesting data.
198 Possible values in this list are:
200 'empty Headers with no content.
201 'newsgroups Newsgroup identical to Gnus group.
202 'to-address To identical to To-address.
203 'to-list To identical to To-list.
204 'cc-list CC identical to To-list.
205 'followup-to Followup-to identical to Newsgroups.
206 'reply-to Reply-to identical to From.
207 'date Date less than four days old.
208 'long-to To and/or Cc longer than 1024 characters.
209 'many-to Multiple To and/or Cc."
210 :type '(set (const :tag "Headers with no content." empty)
211 (const :tag "Newsgroups identical to Gnus group." newsgroups)
212 (const :tag "To identical to To-address." to-address)
213 (const :tag "To identical to To-list." to-list)
214 (const :tag "CC identical to To-list." cc-list)
215 (const :tag "Followup-to identical to Newsgroups." followup-to)
216 (const :tag "Reply-to identical to From." reply-to)
217 (const :tag "Date less than four days old." date)
218 (const :tag "To and/or Cc longer than 1024 characters." long-to)
219 (const :tag "Multiple To and/or Cc headers." many-to))
220 :group 'gnus-article-hiding)
222 (defcustom gnus-article-skip-boring nil
223 "Skip over text that is not worth reading.
224 By default, if you set this t, then Gnus will display citations and
225 signatures, but will never scroll down to show you a page consisting
226 only of boring text. Boring text is controlled by
227 `gnus-article-boring-faces'."
230 :group 'gnus-article-hiding)
232 (defcustom gnus-signature-separator '("^-- $" "^-- *$")
233 "Regexp matching signature separator.
234 This can also be a list of regexps. In that case, it will be checked
235 from head to tail looking for a separator. Searches will be done from
236 the end of the buffer."
237 :type '(choice :format "%{%t%}: %[Value Menu%]\n%v"
239 (repeat :tag "List of regexp" regexp))
240 :group 'gnus-article-signature)
242 (defcustom gnus-signature-limit nil
243 "Provide a limit to what is considered a signature.
244 If it is a number, no signature may not be longer (in characters) than
245 that number. If it is a floating point number, no signature may be
246 longer (in lines) than that number. If it is a function, the function
247 will be called without any parameters, and if it returns nil, there is
248 no signature in the buffer. If it is a string, it will be used as a
249 regexp. If it matches, the text in question is not a signature.
251 This can also be a list of the above values."
252 :type '(choice (const nil)
256 (regexp :value ".*"))
257 :group 'gnus-article-signature)
259 (defcustom gnus-hidden-properties '(invisible t intangible t)
260 "Property list to use for hiding text."
262 :group 'gnus-article-hiding)
264 ;; Fixme: This isn't the right thing for mixed graphical and non-graphical
265 ;; frames in a session.
266 (defcustom gnus-article-x-face-command
267 (if (featurep 'xemacs)
268 (if (or (gnus-image-type-available-p 'xface)
269 (gnus-image-type-available-p 'pbm))
270 'gnus-display-x-face-in-from
271 "{ echo '/* Width=48, Height=48 */'; uncompface; } | icontopbm | ee -")
272 (if (gnus-image-type-available-p 'pbm)
273 'gnus-display-x-face-in-from
274 "{ echo '/* Width=48, Height=48 */'; uncompface; } | icontopbm | \
276 "*String or function to be executed to display an X-Face header.
277 If it is a string, the command will be executed in a sub-shell
278 asynchronously. The compressed face will be piped to this command."
279 :type `(choice string
280 (function-item gnus-display-x-face-in-from)
284 :group 'gnus-article-washing)
286 (defcustom gnus-article-x-face-too-ugly nil
287 "Regexp matching posters whose face shouldn't be shown automatically."
288 :type '(choice regexp (const nil))
289 :group 'gnus-article-washing)
291 (defcustom gnus-article-banner-alist nil
292 "Banner alist for stripping.
294 ((egroups . \"^[ \\t\\n]*-------------------+\\\\( \\\\(e\\\\|Yahoo! \\\\)Groups Sponsor -+\\\\)?....\\n\\\\(.+\\n\\\\)+\"))"
296 :type '(repeat (cons symbol regexp))
297 :group 'gnus-article-washing)
299 (gnus-define-group-parameter
302 "Alist of regexps (to match group names) and banner."
303 :variable-group gnus-article-washing
305 '(choice :tag "Banner"
307 (const :tag "Remove signature" signature)
308 (symbol :tag "Item in `gnus-article-banner-alist'" none)
310 (const :tag "None" nil))
312 "If non-nil, specify how to remove `banners' from articles.
314 Symbol `signature' means to remove signatures delimited by
315 `gnus-signature-separator'. Any other symbol is used to look up a
316 regular expression to match the banner in `gnus-article-banner-alist'.
317 A string is used as a regular expression to match the banner
320 (defcustom gnus-article-address-banner-alist nil
321 "Alist of mail addresses and banners.
322 Each element has the form (ADDRESS . BANNER), where ADDRESS is a regexp
323 to match a mail address in the From: header, BANNER is one of a symbol
324 `signature', an item in `gnus-article-banner-alist', a regexp and nil.
325 If ADDRESS matches author's mail address, it will remove things like
326 advertisements. For example:
328 \((\"@yoo-hoo\\\\.co\\\\.jp\\\\'\" . \"\\n_+\\nDo You Yoo-hoo!\\\\?\\n.*\\n.*\\n\"))
332 (regexp :tag "Address")
333 (choice :tag "Banner" :value nil
334 (const :tag "Remove signature" signature)
335 (symbol :tag "Item in `gnus-article-banner-alist'" none)
337 (const :tag "None" nil))))
339 :group 'gnus-article-washing)
341 (defmacro gnus-emphasis-custom-with-format (&rest body)
343 \\(\\s-\\|^\\|\\=\\|[-\"]\\|\\s(\\)\\(%s\\(\\w+\\(\\s-+\\w+\\)*[.,]?\\)%s\\)\
344 \\(\\([-,.;:!?\"]\\|\\s)\\)+\\s-\\|[?!.]\\s-\\|\\s)\\|\\s-\\)"))
347 (defun gnus-emphasis-custom-value-to-external (value)
348 (gnus-emphasis-custom-with-format
349 (if (consp (car value))
350 (list (format format (car (car value)) (cdr (car value)))
352 (if (nth 1 value) 2 3)
356 (defun gnus-emphasis-custom-value-to-internal (value)
357 (gnus-emphasis-custom-with-format
358 (let ((regexp (concat "\\`"
359 (format (regexp-quote format)
360 "\\([^()]+\\)" "\\([^()]+\\)")
363 (if (string-match regexp (setq pattern (car value)))
364 (list (cons (match-string 1 pattern) (match-string 2 pattern))
369 (defcustom gnus-emphasis-alist
371 '(("\\*" "\\*" bold nil 2)
374 ("_/" "/_" underline-italic)
375 ("_\\*" "\\*_" underline-bold)
376 ("\\*/" "/\\*" bold-italic)
377 ("_\\*/" "/\\*_" underline-bold-italic))))
379 (gnus-emphasis-custom-with-format
380 (mapcar (lambda (spec)
381 (list (format format (car spec) (cadr spec))
384 (intern (format "gnus-emphasis-%s" (nth 2 spec)))))
386 '(;; I've never seen anyone use this strikethru convention whereas I've
387 ;; several times seen it triggered by normal text. --Stef
388 ;; Miles suggests that this form is sometimes used but for italics,
389 ;; so maybe we should map it to `italic'.
390 ;; ("\\(\\s-\\|^\\)\\(-\\(\\(\\w\\|-[^-]\\)+\\)-\\)\\(\\s-\\|[?!.,;]\\)"
391 ;; 2 3 gnus-emphasis-strikethru)
392 ("\\(\\s-\\|^\\)\\(_\\(\\(\\w\\|_[^_]\\)+\\)_\\)\\(\\s-\\|[?!.,;]\\)"
393 2 3 gnus-emphasis-underline))))
394 "*Alist that says how to fontify certain phrases.
395 Each item looks like this:
397 (\"_\\\\(\\\\w+\\\\)_\" 0 1 'underline)
399 The first element is a regular expression to be matched. The second
400 is a number that says what regular expression grouping used to find
401 the entire emphasized word. The third is a number that says what
402 regexp grouping should be displayed and highlighted. The fourth
403 is the face used for highlighting."
407 :format "%[Customizing Style%]\n%v"