(autoload 'gnus-button-reply "gnus-msg" nil t)
(autoload 'parse-time-string "parse-time" nil nil)
(autoload 'ansi-color-apply-on-region "ansi-color")
+(autoload 'mm-url-insert-file-contents-external "mm-url")
+(autoload 'mm-extern-cache-contents "mm-extern")
(defgroup gnus-article nil
"Article display."
"X-Virus-Scanned" "X-Delivery-Agent" "Posted-Date" "X-Gateway"
"X-Local-Origin" "X-Local-Destination" "X-UserInfo1"
"X-Received-Date" "X-Hashcash" "Face" "X-DMCA-Notifications"
- "X-Abuse-and-DMCA-Info" "X-Postfilter" "X-Gpg-.*" "X-Disclaimer"))
+ "X-Abuse-and-DMCA-Info" "X-Postfilter" "X-Gpg-.*" "X-Disclaimer"
+ "Envelope-To" "X-Spam-Score" "System-Type" "X-Injected-Via-Gmane"
+ "X-Gmane-NNTP-Posting-Host" "Jabber-ID" "Archived-At"
+ "Envelope-Sender" "Envelope-Recipients"))
"*All headers that start with this regexp will be hidden.
This variable can also be a list of regexps of headers to be ignored.
If `gnus-visible-headers' is non-nil, this variable will be ignored."
(make-obsolete-variable 'gnus-article-hide-pgp-hook
"This variable is obsolete in Gnus 5.10.")
-(defcustom gnus-article-button-face 'bold
+(defface gnus-button
+ '((t (:weight bold)))
+ "Face used for highlighting a button in the article buffer."
+ :group 'gnus-article-buttons)
+
+(defcustom gnus-article-button-face 'gnus-button
"Face used for highlighting buttons in the article buffer.
An article button is a piece of text that you can activate by pressing
(item :tag "skip" nil)
(face :value default)))))
+(defcustom gnus-face-properties-alist (if (featurep 'xemacs)
+ '((xface . (:face gnus-x-face)))
+ '((pbm . (:face gnus-x-face))
+ (png . nil)))
+ "Alist of image types and properties applied to Face and X-Face images.
+Here are examples:
+
+;; Specify the altitude of Face images in the From header.
+\(setq gnus-face-properties-alist
+ '((pbm . (:face gnus-x-face :ascent 80))
+ (png . (:ascent 80))))
+
+;; Show Face images as pressed buttons.
+\(setq gnus-face-properties-alist
+ '((pbm . (:face gnus-x-face :relief -2))
+ (png . (:relief -2))))
+
+See the manual for the valid properties for various image types.
+Currently, `pbm' is used for X-Face images and `png' is used for Face
+images in Emacs. Only the `:face' property is effective on the `xface'
+image type in XEmacs if it is built with the libcompface library."
+ :version "23.0" ;; No Gnus
+ :group 'gnus-article-headers
+ :type '(repeat (cons :format "%v" (symbol :tag "Image type") plist)))
+
(defcustom gnus-article-decode-hook
'(article-decode-charset article-decode-encoded-words
article-decode-group-name article-decode-idna-rhs)
:group 'gnus-article-mime
:type '(repeat regexp))
-(defcustom gnus-buttonized-mime-types nil
+(defcustom gnus-buttonized-mime-types (unless (eq mm-verify-option 'never)
+ '("multipart/signed"))
"List of MIME types that should be given buttons when rendered inline.
If set, this variable overrides `gnus-unbuttonized-mime-types'.
To see e.g. security buttons you could set this to
'(choice (const :tag "Off" nil)
(const :tag "Header" head)))
-(defvar gnus-article-treat-types '("text/plain")
+(defvar gnus-article-treat-types '("text/plain" "text/x-verbatim"
+ "text/x-patch")
"Parts to treat.")
(defvar gnus-inhibit-treatment nil
(gnus-treat-overstrike gnus-article-treat-overstrike)
(gnus-treat-ansi-sequences gnus-article-treat-ansi-sequences)
(gnus-treat-unfold-headers gnus-article-treat-unfold-headers)
- (gnus-treat-fold-headers gnus-article-treat-fold-headers)
(gnus-treat-fold-newsgroups gnus-article-treat-fold-newsgroups)
+ (gnus-treat-fold-headers gnus-article-treat-fold-headers)
(gnus-treat-buttonize-head gnus-article-add-buttons-to-head)
(gnus-treat-display-smileys gnus-treat-smiley)
(gnus-treat-capitalize-sentences gnus-article-capitalize-sentences)
"-I" (symbol-name charset) "-O" (symbol-name charset))))
(mm-inline-wash-with-stdin nil "w3m" "-dump" "-T" "text/html")))
+(defvar gnus-article-browse-html-temp-list nil
+ "List of temporary files created by `gnus-article-browse-html-parts'.
+Internal variable.")
+
+(defcustom gnus-article-browse-delete-temp 'ask
+ "What to do with temporary files from `gnus-article-browse-html-parts'.
+If nil, don't delete temporary files. If it is t, delete them on
+exit from the summary buffer. If it is the symbol `file', query
+on each file, if it is `ask' ask once when exiting from the
+summary buffer."
+ :group 'gnus-article
+ :version "23.0" ;; No Gnus
+ :type '(choice (const :tag "Don't delete" nil)
+ (const :tag "Don't ask" t)
+ (const :tag "Ask" ask)
+ (const :tag "Ask for each file" file)))
+
+;; Cf. mm-postponed-undisplay-list / mm-destroy-postponed-undisplay-list.
+
+(defun gnus-article-browse-delete-temp-files (&optional how)
+ "Delete temp-files created by `gnus-article-browse-html-parts'."
+ (when (and gnus-article-browse-html-temp-list
+ (or how
+ (setq how gnus-article-browse-delete-temp)))
+ (when (and (eq how 'ask)
+ (y-or-n-p (format
+ "Delete all %s temporary HTML file(s)? "
+ (length gnus-article-browse-html-temp-list)))
+ (setq how t)))
+ (dolist (file gnus-article-browse-html-temp-list)
+ (when (and (file-exists-p file)
+ (or (eq how t)
+ ;; `how' is neither `nil', `ask' nor `t' (i.e. `file'):
+ (gnus-y-or-n-p
+ (format "Delete temporary HTML file `%s'? " file))))
+ (delete-file file)))
+ ;; Also remove file from the list when not deleted or if file doesn't
+ ;; exist anymore.
+ (setq gnus-article-browse-html-temp-list nil))
+ gnus-article-browse-html-temp-list)
+
(defun gnus-article-browse-html-parts (list)
"View all \"text/html\" parts from LIST.
Recurse into multiparts."
(when (listp handle)
(cond ((and (bufferp (car handle))
(string-match "text/html" (car (mm-handle-type handle))))
- (let ((tmp-file
- (concat (mm-make-temp-file
- ;; Do we need to care for 8.3 filenames?
- (format "mm-") nil) ".html")))
+ (let ((tmp-file (mm-make-temp-file
+ ;; Do we need to care for 8.3 filenames?
+ "mm-" nil ".html")))
(mm-save-part-to-file handle tmp-file)
+ (add-to-list 'gnus-article-browse-html-temp-list tmp-file)
+ (add-hook 'gnus-summary-prepare-exit-hook
+ 'gnus-article-browse-delete-temp-files)
+ (add-hook 'gnus-exit-gnus-hook
+ (lambda ()
+ (gnus-article-browse-delete-temp-files t)))
(browse-url tmp-file)
(setq showed t)))
;; If multipart, recurse
(gnus-article-browse-html-parts handle))))))))
showed))
-;; TODO: Key binding; Remove temp files.
+;; TODO: Key binding
(defun gnus-article-browse-html-article ()
"View \"text/html\" parts of the current article with a WWW browser."
(interactive)
(article-really-strip-banner
(gnus-parameter-banner gnus-newsgroup-name)))
(when gnus-article-address-banner-alist
- ;; It is necessary to encode from fields before checking,
- ;; because `mail-header-parse-addresses' does not work
- ;; (reliably) on decoded headers. And more, it is
- ;; impossible to use `gnus-fetch-original-field' here,
- ;; because `article-strip-banner' may be called in draft
- ;; buffers to preview them.
+ ;; Note that the From header is decoded here, so it is
+ ;; required that the *-extract-address-components function
+ ;; supports non-ASCII text.
(let ((from (save-restriction
(widen)
(article-narrow-to-head)
(mail-fetch-field "from"))))
(when (and from
(setq from
- (caar (mail-header-parse-addresses
- (mail-encode-encoded-word-string from)))))
+ (cadr (funcall gnus-extract-address-components
+ from))))
(catch 'found
(dolist (pair gnus-article-address-banner-alist)
(when (string-match (car pair) from)
(make-local-variable 'gnus-article-ignored-charsets)
;; Prevent recent Emacsen from displaying non-break space as "\ ".
(set (make-local-variable 'nobreak-char-display) nil)
+ (setq cursor-in-non-selected-windows nil)
(gnus-set-default-directory)
(buffer-disable-undo)
(setq buffer-read-only t
(insert "Content-Type: " (mm-handle-media-type data))
(mml-insert-parameter-string (cdr (mm-handle-type data))
'(charset))
+ ;; Add a filename for the sake of saving the part again.
+ (mml-insert-parameter
+ (mail-header-encode-parameter "name" (file-name-nondirectory file)))
(insert "\n")
(insert "Content-ID: " (message-make-message-id) "\n")
(insert "Content-Transfer-Encoding: binary\n")
(gnus-article-check-buffer)
(let ((handle (get-text-property (point) 'gnus-data)))
(when handle
+ (when (equal (mm-handle-media-type handle) "message/external-body")
+ (unless (mm-handle-cache handle)
+ (mm-extern-cache-contents handle))
+ (setq handle (mm-handle-cache handle)))
(setq handle
(mm-make-handle (mm-handle-buffer handle)
(cons mime-type (cdr (mm-handle-type handle)))
(unless handle
(setq handle (get-text-property (point) 'gnus-data)))
(when handle
- (let ((filename (or (mail-content-type-get (mm-handle-disposition handle)
+ (let ((filename (or (mail-content-type-get (mm-handle-type handle)
'name)
(mail-content-type-get (mm-handle-disposition handle)
'filename)))
(mm-insert-part handle)
(setq contents
(or (mm-decompress-buffer
- (or (mail-content-type-get (mm-handle-disposition handle)
+ (or (mail-content-type-get (mm-handle-type handle)
'name)
(mail-content-type-get (mm-handle-disposition handle)
'filename))
specified charset."
(interactive (list nil current-prefix-arg))
(gnus-article-check-buffer)
- (let* ((handle (or handle (get-text-property (point) 'gnus-data)))
- contents charset
- (b (point))
- (inhibit-read-only t))
+ (let ((handle (or handle (get-text-property (point) 'gnus-data)))
+ (fun (get-text-property (point) 'gnus-callback))
+ (gnus-newsgroup-ignored-charsets 'gnus-all)
+ gnus-newsgroup-charset type charset)
(when handle
(if (mm-handle-undisplayer handle)
(mm-remove-part handle))
- (let ((gnus-newsgroup-charset
- (or (cdr (assq arg
- gnus-summary-show-article-charset-alist))
- (mm-read-coding-system "Charset: ")))
- (gnus-newsgroup-ignored-charsets 'gnus-all))
- (gnus-article-press-button)))))
+ (when fun
+ (setq gnus-newsgroup-charset
+ (or (cdr (assq arg gnus-summary-show-article-charset-alist))
+ (mm-read-coding-system "Charset: ")))
+ ;; Strip the charset parameter from `handle'.
+ (setq type (mm-handle-type
+ (if (equal (mm-handle-media-type handle)
+ "message/external-body")
+ (progn
+ (unless (mm-handle-cache handle)
+ (mm-extern-cache-contents handle))
+ (mm-handle-cache handle))
+ handle))
+ charset (assq 'charset (cdr type)))
+ (delq charset type)
+ (funcall fun handle)))))
(defun gnus-mime-view-part-externally (&optional handle)
"View the MIME part under point with an external viewer."
(interactive "p")
(gnus-article-part-wrapper n 'gnus-mime-delete-part t))
+(defun gnus-article-view-part-as-type (n)
+ "Choose a MIME media type, and view part N as such.
+N is the numerical prefix."
+ (interactive "p")
+ (gnus-article-part-wrapper n 'gnus-mime-view-part-as-type t))
+
(defun gnus-article-mime-match-handle-first (condition)
(if condition
(let (n)
(let ((id (1+ (length gnus-article-mime-handle-alist)))
beg)
(push (cons id handle) gnus-article-mime-handle-alist)
+ (when (and display
+ (equal (mm-handle-media-supertype handle) "message"))
+ (insert-char
+ ?\n
+ (cond ((not (bolp)) 2)
+ ((or (bobp) (eq (char-before (1- (point))) ?\n)) 0)
+ (t 1))))
(when (or (not display)
(not (gnus-unbuttonized-mime-type-p type)))
(gnus-insert-mime-button
(boundp 'gnus-article-boring-faces)
(symbol-value 'gnus-article-boring-faces))
(save-excursion
- (catch 'only-boring
- (while (re-search-forward "\\b\\w\\w" nil t)
- (forward-char -1)
- (when (not (gnus-intersection
- (gnus-faces-at (point))
- (symbol-value 'gnus-article-boring-faces)))
- (throw 'only-boring nil)))
- (throw 'only-boring t)))))
+ (let ((inhibit-point-motion-hooks t))
+ (catch 'only-boring
+ (while (re-search-forward "\\b\\w\\w" nil t)
+ (forward-char -1)
+ (when (not (gnus-intersection
+ (gnus-faces-at (point))
+ (symbol-value 'gnus-article-boring-faces)))
+ (throw 'only-boring nil)))
+ (throw 'only-boring t))))))
(defun gnus-article-refer-article ()
"Read article specified by message-id around point."
;; Regexp suggested by Felix Wiemann in <87oeuomcz9.fsf@news2.ososo.de>
(defcustom gnus-button-valid-localpart-regexp
- "[a-z0-9$%(*-=?[_][^<>\")!;:,{}\n\t ]*"
+ "[a-z0-9$%(*-=?[_][^<>\")!;:,{}\n\t @]*"
"Regular expression that matches a localpart of mail addresses or MIDs."
:version "22.1"
:group 'gnus-article-buttons
;; SoWWWAnchor(3iv), XSelectInput(3X11), X(1), X(7)
("\\b\\(\\(?:[a-z][-+_.:a-z0-9]+([1-9][X1a-z]*)\\)\\|\\b\\(?:X([1-9])\\)\\)\\W"
0 (>= gnus-button-man-level 5) gnus-button-handle-man 1)
+ ;; Recognizing patches to .el files. This is somewhat obscure,
+ ;; but considering the percentage of Gnus users who hack Emacs
+ ;; Lisp files...
+ ("^--- \\([^ .]+\\.el\\).*\n.*\n@@ -?\\([0-9]+\\)" 1
+ (>= gnus-button-message-level 4) gnus-button-patch 1 2)
+ ("^\\*\\*\\* \\([^ .]+\\.el\\).*\n.*\n\\*+\n\\*\\*\\* \\([0-9]+\\)" 1
+ (>= gnus-button-message-level 4) gnus-button-patch 1 2)
;; MID or mail: To avoid too many false positives we don't try to catch
;; all kind of allowed MIDs or mail addresses. Domain part must contain
;; at least one dot. TLD must contain two or three chars or be a know TLD
(group
(gnus-button-fetch-group url)))))
+(defun gnus-button-patch (library line)
+ "Visit an Emacs Lisp library LIBRARY on line LINE."
+ (interactive)
+ (let ((file (locate-library (file-name-nondirectory library))))
+ (unless file
+ (error "Couldn't find library %s" library))
+ (find-file file)
+ (goto-line (string-to-number line))))
+
(defun gnus-button-handle-man (url)
"Fetch a man page."
(gnus-message 9 "`%s' `%s'" gnus-button-man-handler url)