;;; gnus-art.el --- article mode commands for Gnus
-;; Copyright (C) 1996,97 Free Software Foundation, Inc.
+;; Copyright (C) 1996,97,98 Free Software Foundation, Inc.
-;; Author: Lars Magne Ingebrigtsen <larsi@ifi.uio.no>
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
;; Keywords: news
;; This file is part of GNU Emacs.
;;; Code:
+(eval-when-compile (require 'cl))
+
(require 'custom)
(require 'gnus)
(require 'gnus-sum)
'("^Path:" "^Posting-Version:" "^Article-I.D.:" "^Expires:"
"^Date-Received:" "^References:" "^Control:" "^Xref:" "^Lines:"
"^Posted:" "^Relay-Version:" "^Message-ID:" "^Nf-ID:" "^Nf-From:"
- "^Approved:" "^Sender:" "^Received:" "^Mail-from:")
- "All headers that match this regexp will be hidden.
+ "^Approved:" "^Sender:" "^Received:" "^Mail-from:")
+ "*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."
:type '(choice :custom-show nil
(repeat regexp))
:group 'gnus-article-hiding)
-(defcustom gnus-visible-headers
- "^From:\\|^Newsgroups:\\|^Subject:\\|^Date:\\|^Followup-To:\\|^Reply-To:\\|^Organization:\\|^Summary:\\|^Keywords:\\|^To:\\|^Cc:\\|^Posted-To:\\|^Mail-Copies-To:\\|^Apparently-To:\\|^Gnus-Warning:\\|^Resent-From"
- "All headers that do not match this regexp will be hidden.
+(defcustom gnus-visible-headers
+ "From:\\|^Newsgroups:\\|^Subject:\\|^Date:\\|^Followup-To:\\|^Reply-To:\\|^Organization:\\|^Summary:\\|^Keywords:\\|^To:\\|^Cc:\\|^Posted-To:\\|^Mail-Copies-To:\\|^Apparently-To:\\|^Gnus-Warning:\\|^Resent-From:\\|X-Sent:"
+ "*All headers that do not match this regexp will be hidden.
This variable can also be a list of regexp of headers to remain visible.
If this variable is non-nil, `gnus-ignored-headers' will be ignored."
:type '(repeat :value-to-internal (lambda (widget value)
:group 'gnus-article-hiding)
(defcustom gnus-sorted-header-list
- '("^From:" "^Subject:" "^Summary:" "^Keywords:" "^Newsgroups:" "^To:"
- "^Cc:" "^Date:" "^Organization:")
- "This variable is a list of regular expressions.
+ '("^From:" "^Subject:" "^Summary:" "^Keywords:" "^Newsgroups:"
+ "^Followup-To:" "^To:" "^Cc:" "^Date:" "^Organization:")
+ "*This variable is a list of regular expressions.
If it is non-nil, headers that match the regular expressions will
be placed first in the article buffer in the sequence specified by
this list."
(defcustom gnus-boring-article-headers '(empty followup-to reply-to)
"Headers that are only to be displayed if they have interesting data.
Possible values in this list are `empty', `newsgroups', `followup-to',
-`reply-to', and `date'."
+`reply-to', `date', `long-to', and `many-to'."
:type '(set (const :tag "Headers with no content." empty)
(const :tag "Newsgroups with only one group." newsgroups)
(const :tag "Followup-to identical to newsgroups." followup-to)
(const :tag "Reply-to identical to from." reply-to)
- (const :tag "Date less than four days old." date))
+ (const :tag "Date less than four days old." date)
+ (const :tag "Very long To header." long-to)
+ (const :tag "Multiple To headers." many-to))
:group 'gnus-article-hiding)
(defcustom gnus-signature-separator '("^-- $" "^-- *$")
will be called without any parameters, and if it returns nil, there is
no signature in the buffer. If it is a string, it will be used as a
regexp. If it matches, the text in question is not a signature."
- :type '(choice integer number function regexp)
+ :type '(choice (integer :value 200)
+ (number :value 4.0)
+ (function :value fun)
+ (regexp :value ".*"))
:group 'gnus-article-signature)
(defcustom gnus-hidden-properties '(invisible t intangible t)
"Property list to use for hiding text."
- :type 'sexp
+ :type 'sexp
:group 'gnus-article-hiding)
(defcustom gnus-article-x-face-command
"{ echo '/* Width=48, Height=48 */'; uncompface; } | icontopbm | xv -quit -"
- "String or function to be executed to display an X-Face header.
+ "*String or function to be executed to display an X-Face header.
If it is a string, the command will be executed in a sub-shell
asynchronously. The compressed face will be piped to this command."
:type 'string ;Leave function case to Lisp.
(defcustom gnus-article-x-face-too-ugly nil
"Regexp matching posters whose face shouldn't be shown automatically."
- :type 'regexp
+ :type '(choice regexp (const nil))
:group 'gnus-article-washing)
(defcustom gnus-emphasis-alist
(let ((format
- "\\(\\s-\\|^\\|[-\"\(]\\)\\(%s\\(\\w+\\(\\s-+\\w+\\)*[.,]?\\)%s\\)\\(\\s-\\|[-?!.,;:\"\)]\\)")
+ "\\(\\s-\\|^\\|[-\"]\\|\\s(\\|\\s)\\)\\(%s\\(\\w+\\(\\s-+\\w+\\)*[.,]?\\)%s\\)\\(\\s-\\|[-?!.,;:\"]\\|\\s(\\|\\s)\\)")
(types
'(("_" "_" underline)
("/" "/" italic)
(lambda (spec)
(list
(format format (car spec) (cadr spec))
- 2 3 (intern (format "gnus-emphasis-%s" (caddr spec)))))
+ 2 3 (intern (format "gnus-emphasis-%s" (nth 2 spec)))))
types)))
- "Alist that says how to fontify certain phrases.
+ "*Alist that says how to fontify certain phrases.
Each item looks like this:
(\"_\\\\(\\\\w+\\\\)_\" 0 1 'underline)
"Face used for displaying bold italic emphasized text (/*word*/)."
:group 'gnus-article-emphasis)
-(defface gnus-emphasis-underline-bold-italic
+(defface gnus-emphasis-underline-bold-italic
'((t (:bold t :italic t :underline t)))
"Face used for displaying underlined bold italic emphasized text.
Esample: (_/*word*/_)."
(defcustom gnus-article-time-format "%a, %b %d %Y %T %Z"
"Format for display of Date headers in article bodies.
-See `format-time-zone' for the possible values."
- :type 'string
+See `format-time-string' for the possible values.
+
+The variable can also be function, which should return a complete Date
+header. The function is called with one argument, the time, which can
+be fed to `format-time-string'."
+ :type '(choice string symbol)
:link '(custom-manual "(gnus)Article Date")
:group 'gnus-article-washing)
(autoload 'timezone-make-date-arpa-standard "timezone")
(autoload 'mail-extract-address-components "mail-extr"))
-(defcustom gnus-article-save-directory gnus-directory
- "*Name of the directory articles will be saved in (default \"~/News\")."
- :group 'gnus-article-saving
- :type 'directory)
-
(defcustom gnus-save-all-headers t
"*If non-nil, don't remove any headers before saving."
:group 'gnus-article-saving
:group 'gnus-article-saving
:type '(choice (item always)
(item :tag "never" nil)
- (sexp :tag "once" :format "%t")))
+ (sexp :tag "once" :format "%t\n" :value t)))
(defcustom gnus-saved-headers gnus-visible-headers
"Headers to keep if `gnus-save-all-headers' is nil.
If that variable is nil, however, all headers that match this regexp
will be kept while the rest will be deleted before saving."
:group 'gnus-article-saving
- :type '(repeat string))
+ :type 'regexp)
(defcustom gnus-default-article-saver 'gnus-summary-save-in-rmail
"A function to save articles in your favourite format.
:type 'function)
(defcustom gnus-split-methods
- '((gnus-article-archive-name))
- "Variable used to suggest where articles are to be saved.
+ '((gnus-article-archive-name)
+ (gnus-article-nndoc-name))
+ "*Variable used to suggest where articles are to be saved.
For instance, if you would like to save articles related to Gnus in
the file \"gnus-stuff\", and articles related to VM in \"vm-stuff\",
you could set this variable to something like:
a possible file name; and if it returns a non-nil list, that list will
be used as possible file names."
:group 'gnus-article-saving
- :type '(repeat (choice (list function)
- (cons regexp (repeat string))
- sexp)))
+ :type '(repeat (choice (list :value (fun) function)
+ (cons :value ("" "") regexp (repeat string))
+ (sexp :value nil))))
(defcustom gnus-strict-mime t
"*If nil, MIME-decode even if there is no Mime-Version header."
:type 'hook
:group 'gnus-article-various)
+(defcustom gnus-article-hide-pgp-hook nil
+ "*A hook called after successfully hiding a PGP signature."
+ :type 'hook
+ :group 'gnus-article-various)
+
(defcustom gnus-article-button-face 'bold
"Face used for highlighting buttons in the article buffer.
:type 'face
:group 'gnus-article-buttons)
-(defcustom gnus-signature-face 'italic
- "Face used for highlighting a signature in the article buffer."
+(defcustom gnus-signature-face 'gnus-signature-face
+ "Face used for highlighting a signature in the article buffer.
+Obsolete; use the face `gnus-signature-face' for customizations instead."
:type 'face
:group 'gnus-article-highlight
:group 'gnus-article-signature)
-(defface gnus-header-from-face
+(defface gnus-signature-face
+ '((((type x))
+ (:italic t)))
+ "Face used for highlighting a signature in the article buffer."
+ :group 'gnus-article-highlight
+ :group 'gnus-article-signature)
+
+(defface gnus-header-from-face
'((((class color)
(background dark))
- (:foreground "light blue" :bold t :italic t))
+ (:foreground "spring green"))
(((class color)
(background light))
- (:foreground "MidnightBlue" :bold t :italic t))
- (t
- (:bold t :italic t)))
+ (:foreground "red3"))
+ (t
+ (:italic t)))
"Face used for displaying from headers."
:group 'gnus-article-headers
:group 'gnus-article-highlight)
-(defface gnus-header-subject-face
+(defface gnus-header-subject-face
'((((class color)
(background dark))
- (:foreground "pink" :bold t :italic t))
+ (:foreground "SeaGreen3"))
(((class color)
(background light))
- (:foreground "firebrick" :bold t :italic t))
- (t
+ (:foreground "red4"))
+ (t
(:bold t :italic t)))
"Face used for displaying subject headers."
:group 'gnus-article-headers
:group 'gnus-article-highlight)
-(defface gnus-header-newsgroups-face
+(defface gnus-header-newsgroups-face
'((((class color)
(background dark))
- (:foreground "yellow" :bold t :italic t))
+ (:foreground "yellow" :italic t))
(((class color)
(background light))
- (:foreground "indianred" :bold t :italic t))
- (t
- (:bold t :italic t)))
+ (:foreground "MidnightBlue" :italic t))
+ (t
+ (:italic t)))
"Face used for displaying newsgroups headers."
:group 'gnus-article-headers
:group 'gnus-article-highlight)
-(defface gnus-header-name-face
+(defface gnus-header-name-face
'((((class color)
(background dark))
- (:foreground "cyan" :bold t))
+ (:foreground "SeaGreen"))
(((class color)
(background light))
- (:foreground "DarkGreen" :bold t))
- (t
+ (:foreground "maroon"))
+ (t
(:bold t)))
"Face used for displaying header names."
:group 'gnus-article-headers
(:foreground "forest green" :italic t))
(((class color)
(background light))
- (:foreground "DarkGreen" :italic t))
- (t
+ (:foreground "indianred4" :italic t))
+ (t
(:italic t))) "Face used for displaying header content."
:group 'gnus-article-headers
:group 'gnus-article-highlight)
("Subject" nil gnus-header-subject-face)
("Newsgroups:.*," nil gnus-header-newsgroups-face)
("" gnus-header-name-face gnus-header-content-face))
- "Controls highlighting of article header.
+ "*Controls highlighting of article header.
-An alist of the form (HEADER NAME CONTENT).
+An alist of the form (HEADER NAME CONTENT).
HEADER is a regular expression which should match the name of an
header header and NAME and CONTENT are either face names or nil.
;;; Internal variables
+(defvar article-lapsed-timer nil)
+(defvar gnus-article-current-summary nil)
+
(defvar gnus-article-mode-syntax-table
(let ((table (copy-syntax-table text-mode-syntax-table)))
- ;;(modify-syntax-entry ?_ "w" table)
+ (modify-syntax-entry ?- "w" table)
+ (modify-syntax-entry ?> ")" table)
+ (modify-syntax-entry ?< "(" table)
table)
"Syntax table used in article mode buffers.
Initialized from `text-mode-syntax-table.")
(defvar gnus-save-article-buffer nil)
(defvar gnus-article-mode-line-format-alist
- (nconc '((?w (gnus-article-wash-status) ?s))
- gnus-summary-mode-line-format-alist))
+ (nconc '((?w (gnus-article-wash-status) ?s))
+ gnus-summary-mode-line-format-alist))
(defvar gnus-number-of-articles-to-be-saved nil)
(defvar gnus-inhibit-hiding nil)
-(defvar gnus-newsgroup-name)
(defsubst gnus-article-hide-text (b e props)
"Set text PROPS on the B to E region, extending `intangible' 1 past B."
(add-text-properties b e props)
(when (memq 'intangible props)
- (put-text-property
+ (put-text-property
(max (1- b) (point-min))
b 'intangible (cddr (memq 'intangible props)))))
(save-excursion
(let ((b (point-min)))
(while (setq b (text-property-any b (point-max) 'article-type type))
- (delete-region b (incf b))))))
+ (delete-region
+ b (or (text-property-not-all b (point-max) 'article-type type)
+ (point-max)))))))
(defun gnus-article-delete-invisible-text ()
"Delete all invisible text in the current buffer."
(save-excursion
(let ((b (point-min)))
(while (setq b (text-property-any b (point-max) 'invisible t))
- (delete-region b (incf b))))))
+ (delete-region
+ b (or (text-property-not-all b (point-max) 'invisible t)
+ (point-max)))))))
(defun gnus-article-text-type-exists-p (type)
"Say whether any text of type TYPE exists in the buffer."
If given a negative prefix, always show; if given a positive prefix,
always hide."
(interactive (gnus-article-hidden-arg))
+ (current-buffer)
(if (gnus-article-check-hidden-text 'headers arg)
;; Show boring headers as well.
(gnus-article-show-hidden-text 'boring-headers)
(save-excursion
(save-restriction
(let ((buffer-read-only nil)
+ (case-fold-search t)
(props (nconc (list 'article-type 'headers)
gnus-hidden-properties))
(max (1+ (length gnus-sorted-header-list)))
(while (re-search-forward "^[^ \t]*:" nil t)
(beginning-of-line)
;; Mark the rank of the header.
- (put-text-property
+ (put-text-property
(point) (1+ (point)) 'message-rank
(if (or (and visible (looking-at visible))
(and ignored
(not (looking-at ignored))))
- (gnus-article-header-rank)
+ (gnus-article-header-rank)
(+ 2 max)))
(forward-line 1))
(message-sort-headers-1)
- (when (setq beg (text-property-any
+ (when (setq beg (text-property-any
(point-min) (point-max) 'message-rank (+ 2 max)))
;; We make the unwanted headers invisible.
(if delete
(forward-line -1)
(gnus-article-hide-text-type
(progn (beginning-of-line) (point))
- (progn
+ (progn
(end-of-line)
(if (re-search-forward "^[^ \t]" nil t)
(match-beginning 0)
(when (and
from reply-to
(ignore-errors
- (equal
+ (equal
(nth 1 (mail-extract-address-components from))
(nth 1 (mail-extract-address-components reply-to)))))
(gnus-article-hide-header "reply-to"))))
(when (and date
(< (gnus-days-between (current-time-string) date)
4))
- (gnus-article-hide-header "date")))))))))))
+ (gnus-article-hide-header "date"))))
+ ((eq elem 'long-to)
+ (let ((to (message-fetch-field "to")))
+ (when (> (length to) 1024)
+ (gnus-article-hide-header "to"))))
+ ((eq elem 'many-to)
+ (let ((to-count 0))
+ (goto-char (point-min))
+ (while (re-search-forward "^to:" nil t)
+ (setq to-count (1+ to-count)))
+ (when (> to-count 1)
+ (while (> to-count 0)
+ (goto-char (point-min))
+ (save-restriction
+ (re-search-forward "^to:" nil nil to-count)
+ (forward-line -1)
+ (narrow-to-region (point) (point-max))
+ (gnus-article-hide-header "to"))
+ (setq to-count (1- to-count)))))))))))))
(defun gnus-article-hide-header (header)
(save-excursion
(when (re-search-forward (concat "^" header ":") nil t)
(gnus-article-hide-text-type
(progn (beginning-of-line) (point))
- (progn
+ (progn
(end-of-line)
(if (re-search-forward "^[^ \t]" nil t)
(match-beginning 0)
(point-max)))
'boring-headers))))
-;; Written by Per Abrahamsen <amanda@iesd.auc.dk>.
+(defun article-treat-dumbquotes ()
+ "Translate M******** sm*rtq**t*s into proper text."
+ (interactive)
+ (article-translate-characters "\221\222\223\223" "`'\"\""))
+
+(defun article-translate-characters (from to)
+ "Translate all characters in the body of the article according to FROM and TO.
+FROM is a string of characters to translate from; to is a string of
+characters to translate to."
+ (save-excursion
+ (goto-char (point-min))
+ (when (search-forward "\n\n" nil t)
+ (let ((buffer-read-only nil)
+ (x (make-string 225 ?x))
+ (i -1))
+ (while (< (incf i) (length x))
+ (aset x i i))
+ (setq i 0)
+ (while (< i (length from))
+ (aset x (aref from i) (aref to i))
+ (incf i))
+ (translate-region (point) (point-max) x)))))
+
(defun article-treat-overstrike ()
"Translate overstrikes into bold text."
(interactive)
(save-excursion
- (let ((buffer-read-only nil))
- (while (search-forward "\b" nil t)
- (let ((next (following-char))
- (previous (char-after (- (point) 2))))
- ;; We do the boldification/underlining by hiding the
- ;; overstrikes and putting the proper text property
- ;; on the letters.
- (cond
- ((eq next previous)
- (gnus-article-hide-text-type (- (point) 2) (point) 'overstrike)
- (put-text-property (point) (1+ (point)) 'face 'bold))
- ((eq next ?_)
- (gnus-article-hide-text-type (1- (point)) (1+ (point)) 'overstrike)
- (put-text-property
- (- (point) 2) (1- (point)) 'face 'underline))
- ((eq previous ?_)
- (gnus-article-hide-text-type (- (point) 2) (point) 'overstrike)
- (put-text-property
- (point) (1+ (point)) 'face 'underline))))))))
+ (goto-char (point-min))
+ (when (search-forward "\n\n" nil t)
+ (let ((buffer-read-only nil))
+ (while (search-forward "\b" nil t)
+ (let ((next (following-char))
+ (previous (char-after (- (point) 2))))
+ ;; We do the boldification/underlining by hiding the
+ ;; overstrikes and putting the proper text property
+ ;; on the letters.
+ (cond
+ ((eq next previous)
+ (gnus-article-hide-text-type (- (point) 2) (point) 'overstrike)
+ (put-text-property (point) (1+ (point)) 'face 'bold))
+ ((eq next ?_)
+ (gnus-article-hide-text-type
+ (1- (point)) (1+ (point)) 'overstrike)
+ (put-text-property
+ (- (point) 2) (1- (point)) 'face 'underline))
+ ((eq previous ?_)
+ (gnus-article-hide-text-type (- (point) 2) (point) 'overstrike)
+ (put-text-property
+ (point) (1+ (point)) 'face 'underline)))))))))
(defun article-fill ()
"Format too long lines."
(when (process-status "article-x-face")
(delete-process "article-x-face"))
(let ((inhibit-point-motion-hooks t)
- (case-fold-search nil)
+ (case-fold-search t)
from)
(save-restriction
(nnheader-narrow-to-headers)
(setq from (message-fetch-field "from"))
(goto-char (point-min))
+ ;; This used to try to do multiple faces (`while' instead of
+ ;; `when' below), but (a) sending multiple EOFs to xv doesn't
+ ;; work (b) it can crash some versions of Emacs (c) are
+ ;; multiple faces really something to encourage?
(when (and gnus-article-x-face-command
(or force
;; Check whether this face is censored.
;; Has to be present.
(re-search-forward "^X-Face: " nil t))
;; We now have the area of the buffer where the X-Face is stored.
- (let ((beg (point))
- (end (1- (re-search-forward "^\\($\\|[^ \t]\\)" nil t))))
- ;; We display the face.
- (if (symbolp gnus-article-x-face-command)
- ;; The command is a lisp function, so we call it.
- (if (gnus-functionp gnus-article-x-face-command)
- (funcall gnus-article-x-face-command beg end)
- (error "%s is not a function" gnus-article-x-face-command))
- ;; The command is a string, so we interpret the command
- ;; as a, well, command, and fork it off.
- (let ((process-connection-type nil))
- (process-kill-without-query
- (start-process
- "article-x-face" nil shell-file-name shell-command-switch
- gnus-article-x-face-command))
- (process-send-region "article-x-face" beg end)
- (process-send-eof "article-x-face")))))))))
+ (save-excursion
+ (let ((beg (point))
+ (end (1- (re-search-forward "^\\($\\|[^ \t]\\)" nil t))))
+ ;; We display the face.
+ (if (symbolp gnus-article-x-face-command)
+ ;; The command is a lisp function, so we call it.
+ (if (gnus-functionp gnus-article-x-face-command)
+ (funcall gnus-article-x-face-command beg end)
+ (error "%s is not a function" gnus-article-x-face-command))
+ ;; The command is a string, so we interpret the command
+ ;; as a, well, command, and fork it off.
+ (let ((process-connection-type nil))
+ (process-kill-without-query
+ (start-process
+ "article-x-face" nil shell-file-name shell-command-switch
+ gnus-article-x-face-command))
+ (process-send-region "article-x-face" beg end)
+ (process-send-eof "article-x-face"))))))))))
+
+(defun gnus-hack-decode-rfc1522 ()
+ "Emergency hack function for avoiding problems when decoding."
+ (let ((buffer-read-only nil))
+ (goto-char (point-min))
+ ;; Remove encoded TABs.
+ (while (search-forward "=09" nil t)
+ (replace-match " " t t))
+ ;; Remove encoded newlines.
+ (goto-char (point-min))
+ (while (search-forward "=10" nil t)
+ (replace-match " " t t))))
(defalias 'gnus-decode-rfc1522 'article-decode-rfc1522)
(defalias 'gnus-article-decode-rfc1522 'article-decode-rfc1522)
(goto-char (point-min))
(or (search-forward "\n\n" nil t) (point-max)))
(goto-char (point-min))
- (while (re-search-forward
+ (while (re-search-forward
"=\\?iso-8859-1\\?q\\?\\([^?\t\n]*\\)\\?=" nil t)
(setq string (match-string 1))
(save-restriction
(narrow-to-region (match-beginning 0) (match-end 0))
(delete-region (point-min) (point-max))
(insert string)
- (article-mime-decode-quoted-printable
+ (article-mime-decode-quoted-printable
(goto-char (point-min)) (point-max))
(subst-char-in-region (point-min) (point-max) ?_ ? )
(goto-char (point-max)))
(defun article-mime-decode-quoted-printable-buffer ()
"Decode Quoted-Printable in the current buffer."
(article-mime-decode-quoted-printable (point-min) (point-max)))
-
+
(defun article-mime-decode-quoted-printable (from to)
"Decode Quoted-Printable in the region between FROM and TO."
(interactive "r")
(goto-char (point-min))
;; Hide the "header".
(when (search-forward "\n-----BEGIN PGP SIGNED MESSAGE-----\n" nil t)
- (gnus-article-hide-text-type (1+ (match-beginning 0))
- (match-end 0) 'pgp))
- (setq beg (point))
- ;; Hide the actual signature.
- (and (search-forward "\n-----BEGIN PGP SIGNATURE-----\n" nil t)
- (setq end (1+ (match-beginning 0)))
- (gnus-article-hide-text-type
- end
- (if (search-forward "\n-----END PGP SIGNATURE-----\n" nil t)
- (match-end 0)
- ;; Perhaps we shouldn't hide to the end of the buffer
- ;; if there is no end to the signature?
- (point-max))
- 'pgp))
- ;; Hide "- " PGP quotation markers.
- (when (and beg end)
- (narrow-to-region beg end)
- (goto-char (point-min))
- (while (re-search-forward "^- " nil t)
- (gnus-article-hide-text-type
- (match-beginning 0) (match-end 0) 'pgp))
- (widen))))))
+ (delete-region (1+ (match-beginning 0)) (match-end 0))
+ (setq beg (point))
+ ;; Hide the actual signature.
+ (and (search-forward "\n-----BEGIN PGP SIGNATURE-----\n" nil t)
+ (setq end (1+ (match-beginning 0)))
+ (delete-region
+ end
+ (if (search-forward "\n-----END PGP SIGNATURE-----\n" nil t)
+ (match-end 0)
+ ;; Perhaps we shouldn't hide to the end of the buffer
+ ;; if there is no end to the signature?
+ (point-max))))
+ ;; Hide "- " PGP quotation markers.
+ (when (and beg end)
+ (narrow-to-region beg end)
+ (goto-char (point-min))
+ (while (re-search-forward "^- " nil t)
+ (delete-region
+ (match-beginning 0) (match-end 0)))
+ (widen))
+ (gnus-run-hooks 'gnus-article-hide-pgp-hook))))))
(defun article-hide-pem (&optional arg)
"Toggle hiding of any PEM headers and signatures in the current article.
(save-restriction
(let ((buffer-read-only nil))
(when (gnus-article-narrow-to-signature)
- (gnus-article-hide-text-type
+ (gnus-article-hide-text-type
(point-min) (point-max) 'signature)))))))
(defun article-strip-leading-blank-lines ()
(while (re-search-forward "\n\n\n+" nil t)
(replace-match "\n\n" t t)))))
+(defun article-strip-leading-space ()
+ "Remove all white space from the beginning of the lines in the article."
+ (interactive)
+ (save-excursion
+ (let ((inhibit-point-motion-hooks t)
+ buffer-read-only)
+ (goto-char (point-min))
+ (search-forward "\n\n" nil t)
+ (while (re-search-forward "^[ \t]+" nil t)
+ (replace-match "" t t)))))
+
(defun article-strip-blank-lines ()
"Strip leading, trailing and multiple blank lines."
(interactive)
(article-remove-trailing-blank-lines)
(article-strip-multiple-blank-lines))
+(defun article-strip-all-blank-lines ()
+ "Strip all blank lines."
+ (interactive)
+ (save-excursion
+ (let ((inhibit-point-motion-hooks t)
+ buffer-read-only)
+ (goto-char (point-min))
+ (search-forward "\n\n" nil t)
+ (while (re-search-forward "^[ \t]*\n" nil t)
+ (replace-match "" t t)))))
+
(defvar mime::preview/content-list)
(defvar mime::preview-content-info/point-min)
(defun gnus-article-narrow-to-signature ()
"Narrow to the signature; return t if a signature is found, else nil."
(widen)
- (when (and (boundp 'mime::preview/content-list)
- mime::preview/content-list)
- ;; We have a MIMEish article, so we use the MIME data to narrow.
- (let ((pcinfo (car (last mime::preview/content-list))))
- (ignore-errors
- (narrow-to-region
- (funcall (intern "mime::preview-content-info/point-min") pcinfo)
- (point-max)))))
-
- (when (gnus-article-search-signature)
- (forward-line 1)
- ;; Check whether we have some limits to what we consider
- ;; to be a signature.
- (let ((limits (if (listp gnus-signature-limit) gnus-signature-limit
- (list gnus-signature-limit)))
- limit limited)
- (while (setq limit (pop limits))
- (if (or (and (integerp limit)
- (< (- (point-max) (point)) limit))
- (and (floatp limit)
- (< (count-lines (point) (point-max)) limit))
- (and (gnus-functionp limit)
- (funcall limit))
- (and (stringp limit)
- (not (re-search-forward limit nil t))))
- () ; This limit did not succeed.
- (setq limited t
- limits nil)))
- (unless limited
- (narrow-to-region (point) (point-max))
- t))))
+ (let ((inhibit-point-motion-hooks t))
+ (when (and (boundp 'mime::preview/content-list)
+ mime::preview/content-list)
+ ;; We have a MIMEish article, so we use the MIME data to narrow.
+ (let ((pcinfo (car (last mime::preview/content-list))))
+ (ignore-errors
+ (narrow-to-region
+ (funcall (intern "mime::preview-content-info/point-min") pcinfo)
+ (point-max)))))
+
+ (when (gnus-article-search-signature)
+ (forward-line 1)
+ ;; Check whether we have some limits to what we consider
+ ;; to be a signature.
+ (let ((limits (if (listp gnus-signature-limit) gnus-signature-limit
+ (list gnus-signature-limit)))
+ limit limited)
+ (while (setq limit (pop limits))
+ (if (or (and (integerp limit)
+ (< (- (point-max) (point)) limit))
+ (and (floatp limit)
+ (< (count-lines (point) (point-max)) limit))
+ (and (gnus-functionp limit)
+ (funcall limit))
+ (and (stringp limit)
+ (not (re-search-forward limit nil t))))
+ () ; This limit did not succeed.
+ (setq limited t
+ limits nil)))
+ (unless limited
+ (narrow-to-region (point) (point-max))
+ t)))))
(defun gnus-article-search-signature ()
"Search the current buffer for the signature separator.
nil)))
(eval-and-compile
- (autoload 'w3-parse-buffer "w3-parse"))
+ (autoload 'w3-display "w3-parse")
+ (autoload 'w3-do-setup "w3" "" t)
+ (autoload 'w3-region "w3-display" "" t))
(defun gnus-article-treat-html ()
"Render HTML."
(let ((cbuf (current-buffer)))
(set-buffer gnus-article-buffer)
(let (buf buffer-read-only b e)
+ (w3-do-setup)
(goto-char (point-min))
(narrow-to-region
(if (search-forward "\n\n" nil t)
(setq e (point-max)))
(nnheader-temp-write nil
(insert-buffer-substring gnus-article-buffer b e)
+ (require 'url)
(save-window-excursion
- (setq buf (car (w3-parse-buffer (current-buffer))))))
+ (w3-region (point-min) (point-max))
+ (setq buf (buffer-substring-no-properties (point-min) (point-max)))))
(when buf
(delete-region (point-min) (point-max))
- (insert-buffer-substring buf)
- (kill-buffer buf))
+ (insert buf))
(widen)
(goto-char (point-min))
(set-window-start (get-buffer-window (current-buffer)) (point-min))
(defun gnus-article-hidden-text-p (type)
"Say whether the current buffer contains hidden text of type TYPE."
- (let ((pos (text-property-any (point-min) (point-max) 'article-type type)))
- (when pos
- (if (get-text-property pos 'invisible)
- 'hidden
- 'shown))))
+ (let ((start (point-min))
+ (pos (text-property-any (point-min) (point-max) 'article-type type)))
+ (while (and pos
+ (not (get-text-property pos 'invisible)))
+ (setq pos
+ (text-property-any (1+ pos) (point-max) 'article-type type)))
+ (if pos
+ 'hidden
+ 'shown)))
(defun gnus-article-show-hidden-text (type &optional hide)
"Show all hidden text of type TYPE.
If TYPE is `local', convert to local time; if it is `lapsed', output
how much time has lapsed since DATE."
(interactive (list 'ut t))
- (let* ((header (or header
+ (let* ((header (or header
(mail-header-date gnus-current-headers)
(message-fetch-field "date")
""))
header))
(date-regexp "^Date:[ \t]\\|^X-Sent:[ \t]")
(inhibit-point-motion-hooks t)
- bface eface)
+ bface eface newline)
(when (and date (not (string= date "")))
(save-excursion
(save-restriction
(setq bface (get-text-property (gnus-point-at-bol) 'face)
eface (get-text-property (1- (gnus-point-at-eol))
'face))
- (message-remove-header date-regexp t)
+ (delete-region (progn (beginning-of-line) (point))
+ (progn (end-of-line) (point)))
(beginning-of-line))
- (goto-char (point-max)))
+ (goto-char (point-max))
+ (setq newline t))
(insert (article-make-date-line date type))
;; Do highlighting.
- (forward-line -1)
+ (beginning-of-line)
(when (looking-at "\\([^:]+\\): *\\(.*\\)$")
- (put-text-property (match-beginning 1) (match-end 1)
+ (put-text-property (match-beginning 1) (1+ (match-end 1))
'face bface)
(put-text-property (match-beginning 2) (match-end 2)
- 'face eface))))))))
+ 'face eface))
+ (when newline
+ (end-of-line)
+ (insert "\n"))))))))
(defun article-make-date-line (date type)
"Return a DATE line of TYPE."
((eq type 'local)
(concat "Date: " (condition-case ()
(timezone-make-date-arpa-standard date)
- (error date))
- "\n"))
+ (error date))))
;; Convert to Universal Time.
((eq type 'ut)
(concat "Date: "
(condition-case ()
(timezone-make-date-arpa-standard date nil "UT")
- (error date))
- "\n"))
+ (error date))))
;; Get the original date from the article.
((eq type 'original)
- (concat "Date: " date "\n"))
+ (concat "Date: " date))
;; Let the user define the format.
((eq type 'user)
+ (if (gnus-functionp gnus-article-time-format)
+ (funcall
+ gnus-article-time-format
+ (ignore-errors
+ (gnus-encode-date
+ (timezone-make-date-arpa-standard
+ date nil "UT"))))
+ (concat
+ "Date: "
+ (format-time-string gnus-article-time-format
+ (ignore-errors
+ (gnus-encode-date
+ (timezone-make-date-arpa-standard
+ date nil "UT")))))))
+ ;; ISO 8601.
+ ((eq type 'iso8601)
(concat
"Date: "
- (format-time-string gnus-article-time-format
+ (format-time-string "%Y%M%DT%h%m%s"
(ignore-errors
(gnus-encode-date
(timezone-make-date-arpa-standard
- date nil "UT"))))
- "\n"))
+ date nil "UT"))))))
;; Do an X-Sent lapsed format.
((eq type 'lapsed)
;; If the date is seriously mangled, the timezone functions are
num prev)
(cond
((null real-time)
- "X-Sent: Unknown\n")
+ "X-Sent: Unknown")
((zerop sec)
- "X-Sent: Now\n")
+ "X-Sent: Now")
(t
(concat
"X-Sent: "
(prog1
(concat (if prev ", " "") (int-to-string
(floor num))
- " " (symbol-name (car unit))
+ " " (symbol-name (car unit))
(if (> num 1) "s" ""))
(setq prev t))))
article-time-units "")
;; If dates are odd, then it might appear like the
;; article was sent in the future.
(if (> real-sec 0)
- " ago\n"
- " in the future\n"))))))
+ " ago"
+ " in the future"))))))
(t
(error "Unknown conversion type: %s" type))))
(interactive (list t))
(article-date-ut 'lapsed highlight))
+(defun article-update-date-lapsed ()
+ "Function to be run from a timer to update the lapsed time line."
+ (let (deactivate-mark)
+ (save-excursion
+ (ignore-errors
+ (when (gnus-buffer-live-p gnus-article-buffer)
+ (set-buffer gnus-article-buffer)
+ (goto-char (point-min))
+ (when (re-search-forward "^X-Sent:" nil t)
+ (article-date-lapsed t)))))))
+
+(defun gnus-start-date-timer (&optional n)
+ "Start a timer to update the X-Sent header in the article buffers.
+The numerical prefix says how frequently (in seconds) the function
+is to run."
+ (interactive "p")
+ (unless n
+ (setq n 1))
+ (gnus-stop-date-timer)
+ (setq article-lapsed-timer
+ (nnheader-run-at-time 1 n 'article-update-date-lapsed)))
+
+(defun gnus-stop-date-timer ()
+ "Stop the X-Sent timer."
+ (interactive)
+ (when article-lapsed-timer
+ (nnheader-cancel-timer article-lapsed-timer)
+ (setq article-lapsed-timer nil)))
+
(defun article-date-user (&optional highlight)
"Convert the current article date to the user-defined format.
This format is defined by the `gnus-article-time-format' variable."
(interactive (list t))
(article-date-ut 'user highlight))
+(defun article-date-iso8601 (&optional highlight)
+ "Convert the current article date to ISO8601."
+ (interactive (list t))
+ (article-date-ut 'iso8601 highlight))
+
(defun article-show-all ()
"Show all hidden text in the article buffer."
(interactive)
(let ((gnus-visible-headers
(or gnus-saved-headers gnus-visible-headers))
(gnus-article-buffer save-buffer))
- (gnus-article-hide-headers 1 t)))
+ (save-excursion
+ (set-buffer save-buffer)
+ (article-hide-headers 1 t))))
(save-window-excursion
(if (not gnus-default-article-saver)
- (error "No default saver is defined.")
+ (error "No default saver is defined")
;; !!! Magic! The saving functions all save
;; `gnus-original-article-buffer' (or so they think), but we
;; bind that variable to our save-buffer.
(gnus-number-of-articles-to-be-saved
(when (eq gnus-prompt-before-saving t)
num))) ; Magic
- (set-buffer gnus-summary-buffer)
- (funcall gnus-default-article-saver filename)))))
+ (set-buffer gnus-article-current-summary)
+ (funcall gnus-default-article-saver filename)))))
-(defun gnus-read-save-file-name (prompt default-name &optional filename)
- (cond
- ((eq filename 'default)
- default-name)
- (filename filename)
- (t
- (let* ((split-name (gnus-get-split-value gnus-split-methods))
- (prompt
- (format prompt (if (and gnus-number-of-articles-to-be-saved
- (> gnus-number-of-articles-to-be-saved 1))
- (format "these %d articles"
- gnus-number-of-articles-to-be-saved)
- "this article")))
- (file
- ;; Let the split methods have their say.
- (cond
- ;; No split name was found.
- ((null split-name)
- (read-file-name
- (concat prompt " (default "
- (file-name-nondirectory default-name) ") ")
- (file-name-directory default-name)
- default-name))
- ;; A single split name was found
- ((= 1 (length split-name))
- (let* ((name (car split-name))
- (dir (cond ((file-directory-p name)
- (file-name-as-directory name))
- ((file-exists-p name) name)
- (t gnus-article-save-directory))))
- (read-file-name
- (concat prompt " (default " name ") ")
- dir name)))
- ;; A list of splits was found.
- (t
- (setq split-name (nreverse split-name))
- (let (result)
- (let ((file-name-history (nconc split-name file-name-history)))
- (setq result
- (expand-file-name
- (read-file-name
- (concat prompt " (`M-p' for defaults) ")
- gnus-article-save-directory
- (car split-name))
- gnus-article-save-directory)))
- (car (push result file-name-history)))))))
- ;; Create the directory.
- (gnus-make-directory (file-name-directory file))
- ;; If we have read a directory, we append the default file name.
- (when (file-directory-p file)
- (setq file (concat (file-name-as-directory file)
- (file-name-nondirectory default-name))))
- ;; Possibly translate some characters.
- (nnheader-translate-file-chars file)))))
+(defun gnus-read-save-file-name (prompt &optional filename
+ function group headers variable)
+ (let ((default-name
+ (funcall function group headers (symbol-value variable)))
+ result)
+ (setq
+ result
+ (cond
+ ((eq filename 'default)
+ default-name)
+ ((eq filename t)
+ default-name)
+ (filename filename)
+ (t
+ (let* ((split-name (gnus-get-split-value gnus-split-methods))
+ (prompt
+ (format prompt
+ (if (and gnus-number-of-articles-to-be-saved
+ (> gnus-number-of-articles-to-be-saved 1))
+ (format "these %d articles"
+ gnus-number-of-articles-to-be-saved)
+ "this article")))
+ (file
+ ;; Let the split methods have their say.
+ (cond
+ ;; No split name was found.
+ ((null split-name)
+ (read-file-name
+ (concat prompt " (default "
+ (file-name-nondirectory default-name) ") ")
+ (file-name-directory default-name)
+ default-name))
+ ;; A single group name is returned.
+ ((stringp split-name)
+ (setq default-name
+ (funcall function split-name headers
+ (symbol-value variable)))
+ (read-file-name
+ (concat prompt " (default "
+ (file-name-nondirectory default-name) ") ")
+ (file-name-directory default-name)
+ default-name))
+ ;; A single split name was found
+ ((= 1 (length split-name))
+ (let* ((name (expand-file-name
+ (car split-name) gnus-article-save-directory))
+ (dir (cond ((file-directory-p name)
+ (file-name-as-directory name))
+ ((file-exists-p name) name)
+ (t gnus-article-save-directory))))
+ (read-file-name
+ (concat prompt " (default " name ") ")
+ dir name)))
+ ;; A list of splits was found.
+ (t
+ (setq split-name (nreverse split-name))
+ (let (result)
+ (let ((file-name-history
+ (nconc split-name file-name-history)))
+ (setq result
+ (expand-file-name
+ (read-file-name
+ (concat prompt " (`M-p' for defaults) ")
+ gnus-article-save-directory
+ (car split-name))
+ gnus-article-save-directory)))
+ (car (push result file-name-history)))))))
+ ;; Create the directory.
+ (gnus-make-directory (file-name-directory file))
+ ;; If we have read a directory, we append the default file name.
+ (when (file-directory-p file)
+ (setq file (concat (file-name-as-directory file)
+ (file-name-nondirectory default-name))))
+ ;; Possibly translate some characters.
+ (nnheader-translate-file-chars file)))))
+ (gnus-make-directory (file-name-directory result))
+ (set variable result)))
(defun gnus-article-archive-name (group)
"Return the first instance of an \"Archive-name\" in the current buffer."
(nnheader-concat gnus-article-save-directory
(match-string 1)))))
+(defun gnus-article-nndoc-name (group)
+ "If GROUP is an nndoc group, return the name of the parent group."
+ (when (eq (car (gnus-find-method-for-group group)) 'nndoc)
+ (gnus-group-get-parameter group 'save-article-group)))
+
(defun gnus-summary-save-in-rmail (&optional filename)
"Append this article to Rmail file.
Optional argument FILENAME specifies file name.
Directory to save to is default to `gnus-article-save-directory'."
- (interactive)
- (gnus-set-global-variables)
- (let ((default-name
- (funcall gnus-rmail-save-name gnus-newsgroup-name
- gnus-current-headers gnus-newsgroup-last-rmail)))
- (setq filename (gnus-read-save-file-name
- "Save %s in rmail file:" default-name filename))
- (gnus-make-directory (file-name-directory filename))
- (gnus-eval-in-buffer-window gnus-save-article-buffer
- (save-excursion
- (save-restriction
- (widen)
- (gnus-output-to-rmail filename))))
- ;; Remember the directory name to save articles
- (setq gnus-newsgroup-last-rmail filename)))
+ (setq filename (gnus-read-save-file-name
+ "Save %s in rmail file:" filename
+ gnus-rmail-save-name gnus-newsgroup-name
+ gnus-current-headers 'gnus-newsgroup-last-rmail))
+ (gnus-eval-in-buffer-window gnus-save-article-buffer
+ (save-excursion
+ (save-restriction
+ (widen)
+ (gnus-output-to-rmail filename))))
+ filename)
(defun gnus-summary-save-in-mail (&optional filename)
"Append this article to Unix mail file.
Optional argument FILENAME specifies file name.
Directory to save to is default to `gnus-article-save-directory'."
- (interactive)
- (gnus-set-global-variables)
- (let ((default-name
- (funcall gnus-mail-save-name gnus-newsgroup-name
- gnus-current-headers gnus-newsgroup-last-mail)))
- (setq filename (gnus-read-save-file-name
- "Save %s in Unix mail file:" default-name filename))
- (setq filename
- (expand-file-name filename
- (and default-name
- (file-name-directory default-name))))
- (gnus-make-directory (file-name-directory filename))
- (gnus-eval-in-buffer-window gnus-save-article-buffer
- (save-excursion
- (save-restriction
- (widen)
- (if (and (file-readable-p filename)
- (mail-file-babyl-p filename))
- (gnus-output-to-rmail filename t)
- (gnus-output-to-mail filename)))))
- ;; Remember the directory name to save articles.
- (setq gnus-newsgroup-last-mail filename)))
+ (setq filename (gnus-read-save-file-name
+ "Save %s in Unix mail file:" filename
+ gnus-mail-save-name gnus-newsgroup-name
+ gnus-current-headers 'gnus-newsgroup-last-mail))
+ (gnus-eval-in-buffer-window gnus-save-article-buffer
+ (save-excursion
+ (save-restriction
+ (widen)
+ (if (and (file-readable-p filename)
+ (mail-file-babyl-p filename))
+ (gnus-output-to-rmail filename t)
+ (gnus-output-to-mail filename)))))
+ filename)
(defun gnus-summary-save-in-file (&optional filename overwrite)
"Append this article to file.
Optional argument FILENAME specifies file name.
Directory to save to is default to `gnus-article-save-directory'."
- (interactive)
- (gnus-set-global-variables)
- (let ((default-name
- (funcall gnus-file-save-name gnus-newsgroup-name
- gnus-current-headers gnus-newsgroup-last-file)))
- (setq filename (gnus-read-save-file-name
- "Save %s in file:" default-name filename))
- (gnus-make-directory (file-name-directory filename))
- (gnus-eval-in-buffer-window gnus-save-article-buffer
- (save-excursion
- (save-restriction
- (widen)
- (when (and overwrite
- (file-exists-p filename))
- (delete-file filename))
- (gnus-output-to-file filename))))
- ;; Remember the directory name to save articles.
- (setq gnus-newsgroup-last-file filename)))
+ (setq filename (gnus-read-save-file-name
+ "Save %s in file:" filename
+ gnus-file-save-name gnus-newsgroup-name
+ gnus-current-headers 'gnus-newsgroup-last-file))
+ (gnus-eval-in-buffer-window gnus-save-article-buffer
+ (save-excursion
+ (save-restriction
+ (widen)
+ (when (and overwrite
+ (file-exists-p filename))
+ (delete-file filename))
+ (gnus-output-to-file filename))))
+ filename)
(defun gnus-summary-write-to-file (&optional filename)
"Write this article to a file.
Optional argument FILENAME specifies file name.
The directory to save in defaults to `gnus-article-save-directory'."
- (interactive)
(gnus-summary-save-in-file nil t))
(defun gnus-summary-save-body-in-file (&optional filename)
"Append this article body to a file.
Optional argument FILENAME specifies file name.
The directory to save in defaults to `gnus-article-save-directory'."
- (interactive)
- (gnus-set-global-variables)
- (let ((default-name
- (funcall gnus-file-save-name gnus-newsgroup-name
- gnus-current-headers gnus-newsgroup-last-file)))
- (setq filename (gnus-read-save-file-name
- "Save %s body in file:" default-name filename))
- (gnus-make-directory (file-name-directory filename))
- (gnus-eval-in-buffer-window gnus-save-article-buffer
- (save-excursion
- (save-restriction
- (widen)
- (goto-char (point-min))
- (when (search-forward "\n\n" nil t)
- (narrow-to-region (point) (point-max)))
- (gnus-output-to-file filename))))
- ;; Remember the directory name to save articles.
- (setq gnus-newsgroup-last-file filename)))
+ (setq filename (gnus-read-save-file-name
+ "Save %s body in file:" filename
+ gnus-file-save-name gnus-newsgroup-name
+ gnus-current-headers 'gnus-newsgroup-last-file))
+ (gnus-eval-in-buffer-window gnus-save-article-buffer
+ (save-excursion
+ (save-restriction
+ (widen)
+ (goto-char (point-min))
+ (when (search-forward "\n\n" nil t)
+ (narrow-to-region (point) (point-max)))
+ (gnus-output-to-file filename))))
+ filename)
(defun gnus-summary-save-in-pipe (&optional command)
"Pipe this article to subprocess."
- (interactive)
- (gnus-set-global-variables)
(setq command
(cond ((eq command 'default)
gnus-last-shell-command)
(command command)
- (t (read-string
+ (t (read-string
(format
"Shell command on %s: "
(if (and gnus-number-of-articles-to-be-saved
gfunc (cdr func))
(setq afunc func
gfunc (intern (format "gnus-%s" func))))
- (fset gfunc
+ (fset gfunc
(if (not (fboundp afunc))
nil
`(lambda (&optional interactive &rest args)
article-remove-trailing-blank-lines
article-strip-leading-blank-lines
article-strip-multiple-blank-lines
+ article-strip-leading-space
article-strip-blank-lines
+ article-strip-all-blank-lines
article-date-local
+ article-date-iso8601
article-date-original
article-date-ut
article-date-user
article-date-lapsed
article-emphasize
+ article-treat-dumbquotes
(article-show-all . gnus-article-show-all-headers))))
\f
;;;
(put 'gnus-article-mode 'mode-class 'special)
-(when t
- (gnus-define-keys gnus-article-mode-map
- " " gnus-article-goto-next-page
- "\177" gnus-article-goto-prev-page
- [delete] gnus-article-goto-prev-page
- "\C-c^" gnus-article-refer-article
- "h" gnus-article-show-summary
- "s" gnus-article-show-summary
- "\C-c\C-m" gnus-article-mail
- "?" gnus-article-describe-briefly
- gnus-mouse-2 gnus-article-push-button
- "\r" gnus-article-press-button
- "\t" gnus-article-next-button
- "\M-\t" gnus-article-prev-button
- "e" gnus-article-edit
- "<" beginning-of-buffer
- ">" end-of-buffer
- "\C-c\C-i" gnus-info-find-node
- "\C-c\C-b" gnus-bug
-
- "\C-d" gnus-article-read-summary-keys
- "\M-*" gnus-article-read-summary-keys
- "\M-#" gnus-article-read-summary-keys
- "\M-^" gnus-article-read-summary-keys
- "\M-g" gnus-article-read-summary-keys)
-
- (substitute-key-definition
- 'undefined 'gnus-article-read-summary-keys gnus-article-mode-map))
+(gnus-define-keys gnus-article-mode-map
+ " " gnus-article-goto-next-page
+ "\177" gnus-article-goto-prev-page
+ [delete] gnus-article-goto-prev-page
+ "\C-c^" gnus-article-refer-article
+ "h" gnus-article-show-summary
+ "s" gnus-article-show-summary
+ "\C-c\C-m" gnus-article-mail
+ "?" gnus-article-describe-briefly
+ gnus-mouse-2 gnus-article-push-button
+ "\r" gnus-article-press-button
+ "\t" gnus-article-next-button
+ "\M-\t" gnus-article-prev-button
+ "e" gnus-article-edit
+ "<" beginning-of-buffer
+ ">" end-of-buffer
+ "\C-c\C-i" gnus-info-find-node
+ "\C-c\C-b" gnus-bug
+
+ "\C-d" gnus-article-read-summary-keys
+ "\M-*" gnus-article-read-summary-keys
+ "\M-#" gnus-article-read-summary-keys
+ "\M-^" gnus-article-read-summary-keys
+ "\M-g" gnus-article-read-summary-keys)
+
+(substitute-key-definition
+ 'undefined 'gnus-article-read-summary-keys gnus-article-mode-map)
(defun gnus-article-make-menu-bar ()
(gnus-turn-off-edit-menu 'article)
["Scroll backwards" gnus-article-goto-prev-page t]
["Show summary" gnus-article-show-summary t]
["Fetch Message-ID at point" gnus-article-refer-article t]
- ["Mail to address at point" gnus-article-mail t]))
+ ["Mail to address at point" gnus-article-mail t]
+ ["Send a bug report" gnus-bug t]))
(easy-menu-define
gnus-article-treatment-menu gnus-article-mode-map ""
["Remove carriage return" gnus-article-remove-cr t]
["Remove quoted-unreadable" gnus-article-de-quoted-unreadable t]))
- (when nil
- (when (boundp 'gnus-summary-article-menu)
- (define-key gnus-article-mode-map [menu-bar commands]
- (cons "Commands" gnus-summary-article-menu))))
+ ;; Note "Commands" menu is defined in gnus-sum.el for consistency
(when (boundp 'gnus-summary-post-menu)
(define-key gnus-article-mode-map [menu-bar post]
(cons "Post" gnus-summary-post-menu)))
- (run-hooks 'gnus-article-menu-hook)))
+ (gnus-run-hooks 'gnus-article-menu-hook)))
(defun gnus-article-mode ()
"Major mode for displaying an article.
(interactive)
(when (gnus-visual-p 'article-menu 'menu)
(gnus-article-make-menu-bar))
- (kill-all-local-variables)
(gnus-simplify-mode-line)
(setq mode-name "Article")
(setq major-mode 'gnus-article-mode)
(use-local-map gnus-article-mode-map)
(gnus-update-format-specifications nil 'article-mode)
(set (make-local-variable 'page-delimiter) gnus-page-delimiter)
- (set (make-local-variable 'gnus-button-marker-list) nil)
+ (make-local-variable 'gnus-page-broken)
+ (make-local-variable 'gnus-button-marker-list)
+ (make-local-variable 'gnus-article-current-summary)
(gnus-set-default-directory)
(buffer-disable-undo (current-buffer))
(setq buffer-read-only t)
(set-syntax-table gnus-article-mode-syntax-table)
- (run-hooks 'gnus-article-mode-hook))
+ (gnus-run-hooks 'gnus-article-mode-hook))
(defun gnus-article-setup-buffer ()
"Initialize the article buffer."
(unless (eq major-mode 'gnus-summary-mode)
(set-buffer gnus-summary-buffer))
(setq gnus-summary-buffer (current-buffer))
- ;; Make sure the connection to the server is alive.
- (unless (gnus-server-opened
- (gnus-find-method-for-group gnus-newsgroup-name))
- (gnus-check-server (gnus-find-method-for-group gnus-newsgroup-name))
- (gnus-request-group gnus-newsgroup-name t))
(let* ((gnus-article (if header (mail-header-number header) article))
(summary-buffer (current-buffer))
(internal-hook gnus-article-internal-prepare-hook)
(cons gnus-newsgroup-name article))
(set-buffer gnus-summary-buffer)
(setq gnus-current-article article)
- (gnus-summary-mark-article article gnus-canceled-mark))
- (unless (memq article gnus-newsgroup-sparse)
- (gnus-error
- 1 "No such article (may have expired or been canceled)")))
+ (if (eq (gnus-article-mark article) gnus-undownloaded-mark)
+ (progn
+ (gnus-summary-set-agent-mark article)
+ (message "Message marked for downloading"))
+ (gnus-summary-mark-article article gnus-canceled-mark)
+ (unless (memq article gnus-newsgroup-sparse)
+ (gnus-error 1
+ "No such article (may have expired or been canceled)")))))
(if (or (eq result 'pseudo) (eq result 'nneething))
(progn
(save-excursion
(set-buffer summary-buffer)
+ (push article gnus-newsgroup-history)
(setq gnus-last-article gnus-current-article
- gnus-newsgroup-history (cons gnus-current-article
- gnus-newsgroup-history)
gnus-current-article 0
gnus-current-headers nil
gnus-article-current nil)
;; `gnus-current-article' must be an article number.
(save-excursion
(set-buffer summary-buffer)
+ (push article gnus-newsgroup-history)
(setq gnus-last-article gnus-current-article
- gnus-newsgroup-history (cons gnus-current-article
- gnus-newsgroup-history)
gnus-current-article article
gnus-current-headers
(gnus-summary-article-header gnus-current-article)
(cons gnus-newsgroup-name gnus-current-article))
(unless (vectorp gnus-current-headers)
(setq gnus-current-headers nil))
- (gnus-summary-show-thread)
- (run-hooks 'gnus-mark-article-hook)
+ (gnus-summary-goto-subject gnus-current-article)
+ (when (gnus-summary-show-thread)
+ ;; If the summary buffer really was folded, the
+ ;; previous goto may not actually have gone to
+ ;; the right article, but the thread root instead.
+ ;; So we go again.
+ (gnus-summary-goto-subject gnus-current-article))
+ (gnus-run-hooks 'gnus-mark-article-hook)
(gnus-set-mode-line 'summary)
(when (gnus-visual-p 'article-highlight 'highlight)
- (run-hooks 'gnus-visual-mark-article-hook))
+ (gnus-run-hooks 'gnus-visual-mark-article-hook))
;; Set the global newsgroup variables here.
;; Suggested by Jim Sisolak
;; <sisolak@trans4.neep.wisc.edu>.
(gnus-set-global-variables)
(setq gnus-have-all-headers
- (or all-headers gnus-show-all-headers))
- (and gnus-use-cache
- (vectorp (gnus-summary-article-header article))
- (gnus-cache-possibly-enter-article
- group article
- (gnus-summary-article-header article)
- (memq article gnus-newsgroup-marked)
- (memq article gnus-newsgroup-dormant)
- (memq article gnus-newsgroup-unreads)))))
+ (or all-headers gnus-show-all-headers))))
(when (or (numberp article)
(stringp article))
;; Hooks for getting information from the article.
;; This hook must be called before being narrowed.
(let (buffer-read-only)
- (run-hooks 'internal-hook)
- (run-hooks 'gnus-article-prepare-hook)
+ (gnus-run-hooks 'internal-hook)
+ (gnus-run-hooks 'gnus-article-prepare-hook)
;; Decode MIME message.
(when gnus-show-mime
(if (or (not gnus-strict-mime)
(gnus-fetch-field "Mime-Version"))
- (funcall gnus-show-mime-method)
+ (let ((coding-system-for-write 'binary)
+ (coding-system-for-read 'binary))
+ (funcall gnus-show-mime-method))
(funcall gnus-decode-encoded-word-method)))
;; Perform the article display hooks.
- (run-hooks 'gnus-article-display-hook))
+ (gnus-run-hooks 'gnus-article-display-hook))
;; Do page break.
(goto-char (point-min))
- (when gnus-break-pages
- (gnus-narrow-to-page)))
+ (setq gnus-page-broken
+ (when gnus-break-pages
+ (gnus-narrow-to-page)
+ t)))
(gnus-set-mode-line 'article)
(gnus-configure-windows 'article)
(goto-char (point-min))
+ (search-forward "\n\n" nil t)
+ (set-window-point (get-buffer-window (current-buffer)) (point))
t))))))
(defun gnus-article-wash-status ()
(if mime ?m ? )
(if emphasis ?e ? )))))
-(defun gnus-article-hide-headers-if-wanted ()
+(fset 'gnus-article-hide-headers-if-wanted 'gnus-article-maybe-hide-headers)
+
+(defun gnus-article-maybe-hide-headers ()
"Hide unwanted headers if `gnus-have-all-headers' is nil.
Provided for backwards compatibility."
(or (save-excursion (set-buffer gnus-summary-buffer) gnus-have-all-headers)
;; save it to file.
(goto-char (point-max))
(insert "\n")
- (append-to-file (point-min) (point-max) file-name))))
+ (append-to-file (point-min) (point-max) file-name)
+ t)))
(defun gnus-narrow-to-page (&optional arg)
"Narrow the article buffer to a page.
"Show the next page of the article."
(interactive)
(when (gnus-article-next-page)
+ (goto-char (point-min))
(gnus-article-read-summary-keys nil (gnus-character-to-event ?n))))
(defun gnus-article-goto-prev-page ()
(and (pos-visible-in-window-p) ;Not continuation line.
(eobp)))
;; Nothing in this page.
- (if (or (not gnus-break-pages)
+ (if (or (not gnus-page-broken)
(save-excursion
(save-restriction
(widen) (forward-line 1) (eobp)))) ;Real end-of-buffer?
Argument LINES specifies lines to be scrolled down."
(interactive "p")
(move-to-window-line 0)
- (if (and gnus-break-pages
+ (if (and gnus-page-broken
(bobp)
(not (save-restriction (widen) (bobp)))) ;Real beginning-of-buffer?
(progn
(recenter -1))
(let ((scroll-in-place nil))
(prog1
- (ignore-errors
- (scroll-down lines))
+ (condition-case ()
+ (scroll-down lines)
+ (beginning-of-buffer
+ (goto-char (point-min))))
(move-to-window-line 0)))))
(defun gnus-article-refer-article ()
(defun gnus-article-show-summary ()
"Reconfigure windows to show summary buffer."
(interactive)
- (gnus-configure-windows 'article)
- (gnus-summary-goto-subject gnus-current-article))
+ (if (not (gnus-buffer-live-p gnus-summary-buffer))
+ (error "There is no summary buffer for this article buffer")
+ (gnus-article-set-globals)
+ (gnus-configure-windows 'article)
+ (gnus-summary-goto-subject gnus-current-article)
+ (gnus-summary-position-point)))
(defun gnus-article-describe-briefly ()
"Describe article mode commands briefly."
(let ((obuf (current-buffer))
(owin (current-window-configuration))
func)
- (switch-to-buffer gnus-summary-buffer 'norecord)
+ (switch-to-buffer gnus-article-current-summary 'norecord)
(setq func (lookup-key (current-local-map) (this-command-keys)))
(call-interactively func)
(set-buffer obuf)
"Execute the last keystroke in the summary buffer."
(interactive)
(let (func)
- (pop-to-buffer gnus-summary-buffer 'norecord)
+ (pop-to-buffer gnus-article-current-summary 'norecord)
(setq func (lookup-key (current-local-map) (this-command-keys)))
(call-interactively func)))
"Read a summary buffer key sequence and execute it from the article buffer."
(interactive "P")
(let ((nosaves
- '("q" "Q" "c" "r" "R" "\C-c\C-f" "m" "a" "f" "F"
- "Zc" "ZC" "ZE" "ZQ" "ZZ" "Zn" "ZR" "ZG" "ZN" "ZP"
- "=" "^" "\M-^" "|"))
- (nosave-but-article
- '("A\r"))
- (nosave-in-article
- '("\C-d"))
- keys)
+ '("q" "Q" "c" "r" "R" "\C-c\C-f" "m" "a" "f" "F"
+ "Zc" "ZC" "ZE" "ZQ" "ZZ" "Zn" "ZR" "ZG" "ZN" "ZP"
+ "=" "^" "\M-^" "|"))
+ (nosave-but-article
+ '("A\r"))
+ (nosave-in-article
+ '("\C-d"))
+ (up-to-top
+ '("n" "Gn" "p" "Gp"))
+ keys new-sum-point)
(save-excursion
- (set-buffer gnus-summary-buffer)
+ (set-buffer gnus-article-current-summary)
(let (gnus-pick-mode)
- (push (or key last-command-event) unread-command-events)
- (setq keys (read-key-sequence nil))))
+ (push (or key last-command-event) unread-command-events)
+ (setq keys (read-key-sequence nil))))
(message "")
(if (or (member keys nosaves)
- (member keys nosave-but-article)
- (member keys nosave-in-article))
- (let (func)
- (save-window-excursion
- (pop-to-buffer gnus-summary-buffer 'norecord)
- ;; We disable the pick minor mode commands.
- (let (gnus-pick-mode)
- (setq func (lookup-key (current-local-map) keys))))
- (if (not func)
- (ding)
- (unless (member keys nosave-in-article)
- (set-buffer gnus-summary-buffer))
- (call-interactively func))
- (when (member keys nosave-but-article)
- (pop-to-buffer gnus-article-buffer 'norecord)))
+ (member keys nosave-but-article)
+ (member keys nosave-in-article))
+ (let (func)
+ (save-window-excursion
+ (pop-to-buffer gnus-article-current-summary 'norecord)
+ ;; We disable the pick minor mode commands.
+ (let (gnus-pick-mode)
+ (setq func (lookup-key (current-local-map) keys))))
+ (if (not func)
+ (ding)
+ (unless (member keys nosave-in-article)
+ (set-buffer gnus-article-current-summary))
+ (call-interactively func)
+ (setq new-sum-point (point)))
+ (when (member keys nosave-but-article)
+ (pop-to-buffer gnus-article-buffer 'norecord)))
;; These commands should restore window configuration.
(let ((obuf (current-buffer))
- (owin (current-window-configuration))
- (opoint (point))
- func in-buffer)
- (if not-restore-window
- (pop-to-buffer gnus-summary-buffer 'norecord)
- (switch-to-buffer gnus-summary-buffer 'norecord))
- (setq in-buffer (current-buffer))
- ;; We disable the pick minor mode commands.
- (if (setq func (let (gnus-pick-mode)
- (lookup-key (current-local-map) keys)))
- (call-interactively func)
- (ding))
- (when (eq in-buffer (current-buffer))
- (set-buffer obuf)
- (unless not-restore-window
- (set-window-configuration owin))
- (set-window-point (get-buffer-window (current-buffer)) opoint))))))
+ (owin (current-window-configuration))
+ (opoint (point))
+ (summary gnus-article-current-summary)
+ func in-buffer selected)
+ (if not-restore-window
+ (pop-to-buffer summary 'norecord)
+ (switch-to-buffer summary 'norecord))
+ (setq in-buffer (current-buffer))
+ ;; We disable the pick minor mode commands.
+ (if (setq func (let (gnus-pick-mode)
+ (lookup-key (current-local-map) keys)))
+ (progn
+ (call-interactively func)
+ (setq new-sum-point (point)))
+ (ding))
+ (when (eq in-buffer (current-buffer))
+ (setq selected (gnus-summary-select-article))
+ (set-buffer obuf)
+ (unless not-restore-window
+ (set-window-configuration owin))
+ (unless (or (not (eq selected 'old)) (member keys up-to-top))
+ (set-window-point (get-buffer-window (current-buffer))
+ opoint))
+ (let ((win (get-buffer-window gnus-article-current-summary)))
+ (when win
+ (set-window-point win new-sum-point))))))))
(defun gnus-article-hide (&optional arg force)
"Hide all the gruft in the current article.
This means that PGP stuff, signatures, cited text and (some)
headers will be hidden.
If given a prefix, show the hidden text instead."
- (interactive (list current-prefix-arg 'force))
+ (interactive (append (gnus-article-hidden-arg) (list 'force)))
(gnus-article-hide-headers arg)
(gnus-article-hide-pgp arg)
(gnus-article-hide-citation-maybe arg force)
(gnus-article-hide-signature arg))
(defun gnus-article-maybe-highlight ()
- "Do some article highlighting if `article-visual' is non-nil."
+ "Do some article highlighting if article highlighting is requested."
(when (gnus-visual-p 'article-highlight 'highlight)
(gnus-article-highlight-some)))
+(defun gnus-check-group-server ()
+ ;; Make sure the connection to the server is alive.
+ (unless (gnus-server-opened
+ (gnus-find-method-for-group gnus-newsgroup-name))
+ (gnus-check-server (gnus-find-method-for-group gnus-newsgroup-name))
+ (gnus-request-group gnus-newsgroup-name t)))
+
(defun gnus-request-article-this-buffer (article group)
"Get an article and insert it into this buffer."
- (let (do-update-line)
+ (let (do-update-line sparse-header)
(prog1
(save-excursion
(erase-buffer)
(gnus-kill-all-overlays)
(setq group (or group gnus-newsgroup-name))
- ;; Open server if it has closed.
- (gnus-check-server (gnus-find-method-for-group group))
-
;; Using `gnus-request-article' directly will insert the article into
;; `nntp-server-buffer' - so we'll save some time by not having to
;; copy it from the server buffer into the article buffer.
(when (and (numberp article)
gnus-summary-buffer
(get-buffer gnus-summary-buffer)
- (buffer-name (get-buffer gnus-summary-buffer)))
+ (gnus-buffer-exists-p gnus-summary-buffer))
(save-excursion
(set-buffer gnus-summary-buffer)
(let ((header (gnus-summary-article-header article)))
(when (< article 0)
- (cond
+ (cond
((memq article gnus-newsgroup-sparse)
;; This is a sparse gap article.
(setq do-update-line article)
(setq article (mail-header-id header))
(let ((gnus-override-method gnus-refer-article-method))
- (gnus-read-header article))
+ (setq sparse-header (gnus-read-header article)))
(setq gnus-newsgroup-sparse
(delq article gnus-newsgroup-sparse)))
((vectorp header)
;; It is an extracted pseudo-article.
(setq article 'pseudo)
(gnus-request-pseudo-article header))))
-
- (let ((method (gnus-find-method-for-group
+
+ (let ((method (gnus-find-method-for-group
gnus-newsgroup-name)))
- (if (not (eq (car method) 'nneething))
- ()
+ (when (and (eq (car method) 'nneething)
+ (vectorp header))
(let ((dir (concat (file-name-as-directory (nth 1 method))
(mail-header-subject header))))
(when (file-directory-p dir)
((and (numberp article)
gnus-summary-buffer
(get-buffer gnus-summary-buffer)
- (buffer-name (get-buffer gnus-summary-buffer))
+ (gnus-buffer-exists-p gnus-summary-buffer)
(eq (cdr (save-excursion
(set-buffer gnus-summary-buffer)
(assq article gnus-newsgroup-reads)))
;; Check asynchronous pre-fetch.
((gnus-async-request-fetched-article group article (current-buffer))
(gnus-async-prefetch-next group article gnus-summary-buffer)
+ (when (and (numberp article) gnus-keep-backlog)
+ (gnus-backlog-enter-article group article (current-buffer)))
'article)
;; Check the cache.
((and gnus-use-cache
(buffer-read-only nil))
(erase-buffer)
(gnus-kill-all-overlays)
+ (gnus-check-group-server)
(when (gnus-request-article article group (current-buffer))
(when (numberp article)
(gnus-async-prefetch-next group article gnus-summary-buffer)
(when gnus-keep-backlog
- (gnus-backlog-enter-article
+ (gnus-backlog-enter-article
group article (current-buffer))))
'article)))
;; It was a pseudo.
(t article)))
+ ;; Associate this article with the current summary buffer.
+ (setq gnus-article-current-summary gnus-summary-buffer)
+
;; Take the article from the original article buffer
;; and place it in the buffer it's supposed to be in.
(when (and (get-buffer gnus-article-buffer)
- ;;(numberp article)
(equal (buffer-name (current-buffer))
(buffer-name (get-buffer gnus-article-buffer))))
(save-excursion
(if (get-buffer gnus-original-article-buffer)
- (set-buffer (get-buffer gnus-original-article-buffer))
+ (set-buffer gnus-original-article-buffer)
(set-buffer (get-buffer-create gnus-original-article-buffer))
(buffer-disable-undo (current-buffer))
(setq major-mode 'gnus-original-article-mode)
(erase-buffer)
(insert-buffer-substring gnus-article-buffer))
(setq gnus-original-article (cons group article))))
-
+
;; Update sparse articles.
(when (and do-update-line
(or (numberp article)
(stringp article)))
(let ((buf (current-buffer)))
(set-buffer gnus-summary-buffer)
- (gnus-summary-update-article do-update-line)
+ (gnus-summary-update-article do-update-line sparse-header)
(gnus-summary-goto-subject do-update-line nil t)
(set-window-point (get-buffer-window (current-buffer) t)
(point))
(defvar gnus-article-edit-mode-map nil)
-(unless gnus-article-edit-mode-map
+(unless gnus-article-edit-mode-map
(setq gnus-article-edit-mode-map (copy-keymap text-mode-map))
(gnus-define-keys gnus-article-edit-mode-map
\\{gnus-article-edit-mode-map}"
(interactive)
- (kill-all-local-variables)
(setq major-mode 'gnus-article-edit-mode)
(setq mode-name "Article Edit")
(use-local-map gnus-article-edit-mode-map)
(setq buffer-read-only nil)
(buffer-enable-undo)
(widen)
- (run-hooks 'text-mode 'gnus-article-edit-mode-hook))
+ (gnus-run-hooks 'text-mode-hook 'gnus-article-edit-mode-hook))
(defun gnus-article-edit (&optional force)
"Edit the current article.
(interactive "P")
(when (and (not force)
(gnus-group-read-only-p))
- (error "The current newsgroup does not support article editing."))
+ (error "The current newsgroup does not support article editing"))
+ (gnus-article-date-original)
(gnus-article-edit-article
- `(lambda ()
+ `(lambda (no-highlight)
(gnus-summary-edit-article-done
,(or (mail-header-references gnus-current-headers) "")
- ,(gnus-group-read-only-p) ,gnus-summary-buffer))))
+ ,(gnus-group-read-only-p) ,gnus-summary-buffer no-highlight))))
(defun gnus-article-edit-article (exit-func)
"Start editing the contents of the current article buffer."
(let ((winconf (current-window-configuration)))
(set-buffer gnus-article-buffer)
(gnus-article-edit-mode)
- (set-text-properties (point-min) (point-max) nil)
+ (gnus-article-delete-text-of-type 'annotation)
+ (gnus-set-text-properties (point-min) (point-max) nil)
(gnus-configure-windows 'edit-article)
(setq gnus-article-edit-done-function exit-func)
(setq gnus-prev-winconf winconf)
(gnus-message 6 "C-c C-c to end edits")))
-(defun gnus-article-edit-done ()
+(defun gnus-article-edit-done (&optional arg)
"Update the article edits and exit."
- (interactive)
+ (interactive "P")
+ (save-excursion
+ (save-restriction
+ (widen)
+ (goto-char (point-min))
+ (when (search-forward "\n\n" nil 1)
+ (let ((lines (count-lines (point) (point-max)))
+ (length (- (point-max) (point)))
+ (case-fold-search t)
+ (body (copy-marker (point))))
+ (goto-char (point-min))
+ (when (re-search-forward "^content-length:[ \t]\\([0-9]+\\)" body t)
+ (delete-region (match-beginning 1) (match-end 1))
+ (insert (number-to-string length)))
+ (goto-char (point-min))
+ (when (re-search-forward
+ "^x-content-length:[ \t]\\([0-9]+\\)" body t)
+ (delete-region (match-beginning 1) (match-end 1))
+ (insert (number-to-string length)))
+ (goto-char (point-min))
+ (when (re-search-forward "^lines:[ \t]\\([0-9]+\\)" body t)
+ (delete-region (match-beginning 1) (match-end 1))
+ (insert (number-to-string lines)))))))
(let ((func gnus-article-edit-done-function)
(buf (current-buffer))
(start (window-start)))
(save-excursion
(set-buffer buf)
(let ((buffer-read-only nil))
- (funcall func)))
+ (funcall func arg)))
(set-buffer buf)
(set-window-start (get-buffer-window buf) start)
(set-window-point (get-buffer-window buf) (point))))
(gnus-article-mode)
;; The cache and backlog have to be flushed somewhat.
(when gnus-use-cache
- (gnus-cache-update-article
+ (gnus-cache-update-article
(car gnus-article-current) (cdr gnus-article-current)))
(when gnus-keep-backlog
- (gnus-backlog-remove-article
+ (gnus-backlog-remove-article
(car gnus-article-current) (cdr gnus-article-current)))
;; Flush original article as well.
(save-excursion
(set-window-start (get-buffer-window (current-buffer)) window-start)
(goto-char p)
(set-buffer buf)))))
-
+
(defun gnus-article-edit-full-stops ()
"Interactively repair spacing at end of sentences."
(interactive)
(let ((case-fold-search nil))
(query-replace-regexp "\\([.!?][])}]* \\)\\([[({A-Z]\\)" "\\1 \\2"))))
-;;;
+;;;
;;; Article highlights
;;;
:group 'gnus-article-buttons
:type 'regexp)
-(defcustom gnus-button-alist
- `(("<\\(url: ?\\)?news:\\([^>\n\t ]*@[^>\n\t ]*\\)>" 0 t
+(defcustom gnus-button-alist
+ `(("<\\(url:[>\n\t ]*?\\)?news:[>\n\t ]*\\([^>\n\t ]*@[^>\n\t ]*\\)>" 0 t
gnus-button-message-id 2)
- ("\\bnews:\\([^>\n\t ]*@[^>\n\t ]*+\\)" 0 t gnus-button-message-id 1)
- ("\\(\\b<\\(url: ?\\)?news:\\(//\\)?\\([^>\n\t ]*\\)>\\)" 1 t
+ ("\\bnews:\\([^>\n\t ]*@[^>\n\t ]*\\)" 0 t gnus-button-message-id 1)
+ ("\\(\\b<\\(url:[>\n\t ]*\\)?news:[>\n\t ]*\\(//\\)?\\([^>\n\t ]*\\)>\\)"
+ 1 t
gnus-button-fetch-group 4)
- ("\\bnews:\\(//\\)?\\([^>\n\t ]+\\)" 0 t gnus-button-fetch-group 2)
- ("\\bin\\( +article\\)? +\\(<\\([^\n @<>]+@[^\n @<>]+\\)>\\)" 2
+ ("\\bnews:\\(//\\)?\\([^'\">\n\t ]+\\)" 0 t gnus-button-fetch-group 2)
+ ("\\bin\\( +article\\| +message\\)? +\\(<\\([^\n @<>]+@[^\n @<>]+\\)>\\)" 2
t gnus-button-message-id 3)
- ("\\(<URL: *\\)mailto: *\\([^> \n\t]+\\)>" 0 t gnus-url-mailto 1)
- ("\\bmailto:\\([^ \n\t]+\\)" 0 t gnus-url-mailto 2)
+ ("\\(<URL: *\\)mailto: *\\([^> \n\t]+\\)>" 0 t gnus-url-mailto 2)
+ ("mailto:\\([a-zA-Z.-@_+0-9%]+\\)" 0 t gnus-url-mailto 1)
+ ("\\bmailto:\\([^ \n\t]+\\)" 0 t gnus-url-mailto 1)
;; This is how URLs _should_ be embedded in text...
("<URL: *\\([^>]*\\)>" 0 t gnus-button-embedded-url 1)
;; Raw URLs.
(,gnus-button-url-regexp 0 t gnus-button-url 0))
- "Alist of regexps matching buttons in article bodies.
+ "*Alist of regexps matching buttons in article bodies.
Each entry has the form (REGEXP BUTTON FORM CALLBACK PAR...), where
REGEXP: is the string matching text around the button,
BUTTON: is the number of the regexp grouping actually matching the button,
FORM: is a lisp expression which must eval to true for the button to
-be added,
+be added,
CALLBACK: is the function to call when the user push this button, and each
PAR: is a number of a regexp grouping whose text will be passed to CALLBACK.
CALLBACK can also be a variable, in that case the value of that
variable it the real callback function."
:group 'gnus-article-buttons
- :type '(repeat (list regexp
+ :type '(repeat (list regexp
(integer :tag "Button")
(sexp :tag "Form")
(function :tag "Callback")
:inline t
(integer :tag "Regexp group")))))
-(defcustom gnus-header-button-alist
+(defcustom gnus-header-button-alist
`(("^\\(References\\|Message-I[Dd]\\):" "<[^>]+>"
0 t gnus-button-message-id 0)
("^\\(From\\|Reply-To\\):" ": *\\(.+\\)$" 1 t gnus-button-reply 1)
- ("^\\(Cc\\|To\\):" "[^ \t\n<>,()\"]+@[^ \t\n<>,()\"]+"
+ ("^\\(Cc\\|To\\):" "[^ \t\n<>,()\"]+@[^ \t\n<>,()\"]+"
0 t gnus-button-mailto 0)
("^X-[Uu][Rr][Ll]:" ,gnus-button-url-regexp 0 t gnus-button-url 0)
+ ("^Subject:" ,gnus-button-url-regexp 0 t gnus-button-url 0)
("^[^:]+:" ,gnus-button-url-regexp 0 t gnus-button-url 0)
("^[^:]+:" "\\(<\\(url: \\)?news:\\([^>\n ]*\\)>\\)" 1 t
gnus-button-message-id 3))
- "Alist of headers and regexps to match buttons in article heads.
+ "*Alist of headers and regexps to match buttons in article heads.
This alist is very similar to `gnus-button-alist', except that each
alist has an additional HEADER element first in each entry:
:group 'gnus-article-buttons
:group 'gnus-article-headers
:type '(repeat (list (regexp :tag "Header")
- regexp
+ regexp
(integer :tag "Button")
(sexp :tag "Form")
(function :tag "Callback")
(defun gnus-article-highlight (&optional force)
"Highlight current article.
This function calls `gnus-article-highlight-headers',
-`gnus-article-highlight-citation',
+`gnus-article-highlight-citation',
`gnus-article-highlight-signature', and `gnus-article-add-buttons' to
do the highlighting. See the documentation for those functions."
(interactive (list 'force))
(case-fold-search t)
(inhibit-point-motion-hooks t)
entry regexp header-face field-face from hpoints fpoints)
- (goto-char (point-min))
- (when (search-forward "\n\n" nil t)
- (narrow-to-region (1- (point)) (point-min))
- (while (setq entry (pop alist))
- (goto-char (point-min))
- (setq regexp (concat "^\\("
- (if (string-equal "" (nth 0 entry))
- "[^\t ]"
- (nth 0 entry))
- "\\)")
- header-face (nth 1 entry)
- field-face (nth 2 entry))
- (while (and (re-search-forward regexp nil t)
- (not (eobp)))
- (beginning-of-line)
- (setq from (point))
- (unless (search-forward ":" nil t)
- (forward-char 1))
- (when (and header-face
- (not (memq (point) hpoints)))
- (push (point) hpoints)
- (gnus-put-text-property from (point) 'face header-face))
- (when (and field-face
- (not (memq (setq from (point)) fpoints)))
- (push from fpoints)
- (if (re-search-forward "^[^ \t]" nil t)
- (forward-char -2)
- (goto-char (point-max)))
- (gnus-put-text-property from (point) 'face field-face)))))))))
+ (message-narrow-to-head)
+ (while (setq entry (pop alist))
+ (goto-char (point-min))
+ (setq regexp (concat "^\\("
+ (if (string-equal "" (nth 0 entry))
+ "[^\t ]"
+ (nth 0 entry))
+ "\\)")
+ header-face (nth 1 entry)
+ field-face (nth 2 entry))
+ (while (and (re-search-forward regexp nil t)
+ (not (eobp)))
+ (beginning-of-line)
+ (setq from (point))
+ (unless (search-forward ":" nil t)
+ (forward-char 1))
+ (when (and header-face
+ (not (memq (point) hpoints)))
+ (push (point) hpoints)
+ (gnus-put-text-property from (point) 'face header-face))
+ (when (and field-face
+ (not (memq (setq from (point)) fpoints)))
+ (push from fpoints)
+ (if (re-search-forward "^[^ \t]" nil t)
+ (forward-char -2)
+ (goto-char (point-max)))
+ (gnus-put-text-property from (point) 'face field-face))))))))
(defun gnus-article-highlight-signature ()
"Highlight the signature in an article.
It does this by highlighting everything after
-`gnus-signature-separator' using `gnus-signature-face'."
+`gnus-signature-separator' using `gnus-signature-face'."
(interactive)
(save-excursion
(set-buffer gnus-article-buffer)
(interactive (list 'force))
(save-excursion
(set-buffer gnus-article-buffer)
- ;; Remove all old markers.
- (let (marker entry)
- (while (setq marker (pop gnus-button-marker-list))
- (goto-char marker)
- (when (setq entry (gnus-button-entry))
- (put-text-property (match-beginning (nth 1 entry))
- (match-end (nth 1 entry))
- 'gnus-callback nil))
- (set-marker marker nil)))
(let ((buffer-read-only nil)
(inhibit-point-motion-hooks t)
(case-fold-search t)
(alist gnus-button-alist)
beg entry regexp)
- (goto-char (point-min))
+ ;; Remove all old markers.
+ (let (marker entry)
+ (while (setq marker (pop gnus-button-marker-list))
+ (goto-char marker)
+ (when (setq entry (gnus-button-entry))
+ (put-text-property (match-beginning (nth 1 entry))
+ (match-end (nth 1 entry))
+ 'gnus-callback nil))
+ (set-marker marker nil)))
;; We skip the headers.
+ (goto-char (point-min))
(unless (search-forward "\n\n" nil t)
(goto-char (point-max)))
(setq beg (point))
(let* ((start (and entry (match-beginning (nth 1 entry))))
(end (and entry (match-end (nth 1 entry))))
(from (match-beginning 0)))
- (when (and (or (eq t (nth 1 entry))
- (eval (nth 1 entry)))
+ (when (and (or (eq t (nth 2 entry))
+ (eval (nth 2 entry)))
(not (gnus-button-in-region-p
start end 'gnus-callback)))
;; That optional form returned non-nil, so we add the
;; button.
- (gnus-article-add-button
- start end 'gnus-button-push
+ (gnus-article-add-button
+ start end 'gnus-button-push
(car (push (set-marker (make-marker) from)
gnus-button-marker-list))))))))))
(form (nth 2 entry)))
(goto-char (match-end 0))
(when (eval form)
- (gnus-article-add-button
+ (gnus-article-add-button
start end (nth 3 entry)
(buffer-substring (match-beginning (nth 4 entry))
(match-end (nth 4 entry)))))))
(when gnus-article-button-face
(gnus-overlay-put (gnus-make-overlay from to)
'face gnus-article-button-face))
- (gnus-add-text-properties
+ (gnus-add-text-properties
from to
(nconc (and gnus-article-mouse-face
(list gnus-mouse-face-prop gnus-article-mouse-face))
;;; Internal functions:
+(defun gnus-article-set-globals ()
+ (save-excursion
+ (set-buffer gnus-summary-buffer)
+ (gnus-set-global-variables)))
+
(defun gnus-signature-toggle (end)
(save-excursion
(set-buffer gnus-article-buffer)
(match-string 3 address)
"nntp")))))))
-(defun gnus-split-string (string pattern)
- "Return a list of substrings of STRING which are separated by PATTERN."
- (let (parts (start 0))
- (while (string-match pattern string start)
- (setq parts (cons (substring string start (match-beginning 0)) parts)
- start (match-end 0)))
- (nreverse (cons (substring string start) parts))))
-
(defun gnus-url-parse-query-string (query &optional downcase)
(let (retval pairs cur key val)
(setq pairs (gnus-split-string query "&"))
(setcdr cur (cons val (cdr cur)))
(setq retval (cons (list key val) retval)))))
retval))
-
+
(defun gnus-url-unhex (x)
(if (> x ?9)
(if (>= x ?a)
(+ 10 (- x ?a))
(+ 10 (- x ?A)))
(- x ?0)))
-
+
(defun gnus-url-unhex-string (str &optional allow-newlines)
"Remove %XXX embedded spaces, etc in a url.
If optional second argument ALLOW-NEWLINES is non-nil, then allow the
(ch1 (gnus-url-unhex (elt str (+ start 1))))
(code (+ (* 16 ch1)
(gnus-url-unhex (elt str (+ start 2))))))
- (setq tmp (concat
+ (setq tmp (concat
tmp (substring str 0 start)
(cond
(allow-newlines
str (substring str (match-end 0)))))
(setq tmp (concat tmp str))
tmp))
-
+
(defun gnus-url-mailto (url)
;; Send mail to someone
(when (string-match "mailto:/*\\(.*\\)" url)
(defun gnus-button-url (address)
"Browse ADDRESS."
- (funcall browse-url-browser-function address))
+ ;; In Emacs 20, `browse-url-browser-function' may be an alist.
+ (if (listp browse-url-browser-function)
+ (browse-url address)
+ (funcall browse-url-browser-function address)))
(defun gnus-button-embedded-url (address)
"Browse ADDRESS."
- (funcall browse-url-browser-function (gnus-strip-whitespace address)))
+ ;; In Emacs 20, `browse-url-browser-function' may be an alist.
+ (if (listp browse-url-browser-function)
+ (browse-url (gnus-strip-whitespace address))
+ (funcall browse-url-browser-function (gnus-strip-whitespace address))))
;;; Next/prev buttons in the article buffer.
(defun gnus-insert-prev-page-button ()
(let ((buffer-read-only nil))
- (gnus-eval-format
+ (gnus-eval-format
gnus-prev-page-line-format nil
`(gnus-prev t local-map ,gnus-prev-page-map
- gnus-callback gnus-article-button-prev-page))))
+ gnus-callback gnus-article-button-prev-page
+ gnus-type annotation))))
(defvar gnus-next-page-map nil)
(unless gnus-next-page-map
(defun gnus-insert-next-page-button ()
(let ((buffer-read-only nil))
(gnus-eval-format gnus-next-page-line-format nil
- `(gnus-next t local-map ,gnus-next-page-map
- gnus-callback
- gnus-article-button-next-page))))
+ `(gnus-next
+ t local-map ,gnus-next-page-map
+ gnus-callback gnus-article-button-next-page
+ gnus-type annotation))))
(defun gnus-article-button-next-page (arg)
"Go to the next page."
(let ((win (selected-window)))
(select-window (get-buffer-window gnus-article-buffer t))
(gnus-article-prev-page)
- (select-window win)))
+ (select-window win)))
(gnus-ems-redefine)