;; GNU Emacs is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 2, or (at your option)
+;; the Free Software Foundation; either version 3, or (at your option)
;; any later version.
;; GNU Emacs is distributed in the hope that it will be useful,
If the match is a string, it is used as a regexp match on the
article. If the match is a symbol, that symbol will be funcalled
-from the buffer of the article to be saved with the newsgroup as
-the parameter. If it is a list, it will be evaled in the same
-buffer.
+from the buffer of the article to be saved with the newsgroup as the
+parameter. If it is a list, it will be evaled in the same buffer.
-If this form or function returns a string, this string will be
-used as a possible file name; and if it returns a non-nil list,
-that list will be used as possible file names."
+If this form or function returns a string, this string will be used as 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 :value (fun) function)
(cons :value ("" "") regexp (repeat string))
(defface gnus-header-from
'((((class color)
(background dark))
- (:foreground "spring green"))
+ (:foreground "PaleGreen1"))
(((class color)
(background light))
(:foreground "red3"))
(defface gnus-header-subject
'((((class color)
(background dark))
- (:foreground "SeaGreen3"))
+ (:foreground "SeaGreen1"))
(((class color)
(background light))
(:foreground "red4"))
(defface gnus-header-name
'((((class color)
(background dark))
- (:foreground "SeaGreen"))
+ (:foreground "SpringGreen2"))
(((class color)
(background light))
(:foreground "maroon"))
(defface gnus-header-content
'((((class color)
(background dark))
- (:foreground "forest green" :italic t))
+ (:foreground "SpringGreen1" :italic t))
(((class color)
(background light))
(:foreground "indianred4" :italic t))
:type gnus-article-treat-head-custom)
(put 'gnus-treat-buttonize-head 'highlight t)
-(defcustom gnus-treat-emphasize
- (and (or window-system
- (featurep 'xemacs))
- 50000)
+(defcustom gnus-treat-emphasize 50000
"Emphasize text.
Valid values are nil, t, `head', `first', `last', an integer or a
predicate. See Info node `(gnus)Customizing Articles'."
(executable-find "icontopbm")))
'head)
"Display X-Face headers.
-Valid values are nil, t, `head', `first', `last', an integer or a
-predicate. See Info node `(gnus)Customizing Articles' and Info
-node `(gnus)X-Face' for details."
+Valid values are nil and `head'.
+See Info node `(gnus)Customizing Articles' and Info node
+`(gnus)X-Face' for details."
:group 'gnus-article-treat
:version "21.1"
:link '(custom-manual "(gnus)Customizing Articles")
(put 'gnus-treat-newsgroups-picon 'highlight t)
(defcustom gnus-treat-body-boundary
- (if (and (eq window-system 'x)
- (or gnus-treat-newsgroups-picon
- gnus-treat-mail-picon
- gnus-treat-from-picon))
- 'head nil)
+ (if (or gnus-treat-newsgroups-picon
+ gnus-treat-mail-picon
+ gnus-treat-from-picon)
+ ;; If there's much decoration, the user might prefer a boundery.
+ 'head
+ nil)
"Draw a boundary at the end of the headers.
Valid values are nil and `head'.
See Info node `(gnus)Customizing Articles' for details."
(eval-when-compile
(defvar gnus-face-properties-alist))
-(defun article-display-face ()
+(defun article-display-face (&optional force)
"Display any Face headers in the header."
- (interactive)
+ (interactive (list 'force))
(let ((wash-face-p buffer-read-only))
(gnus-with-article-headers
;; When displaying parts, this function can be called several times on
;; read-only.
(if (and wash-face-p (memq 'face gnus-article-wash-types))
(gnus-delete-images 'face)
- (let (face faces from)
+ (let ((from (message-fetch-field "from"))
+ face faces)
(save-current-buffer
(when (and wash-face-p
(gnus-buffer-live-p gnus-original-article-buffer)
(set-buffer gnus-original-article-buffer))
(save-restriction
(mail-narrow-to-head)
- (while (gnus-article-goto-header "Face")
- (push (mail-header-field-value) faces))))
+ (when (or force
+ ;; Check whether this face is censored.
+ (not (and gnus-article-x-face-too-ugly
+ (or from
+ (setq from (message-fetch-field "from")))
+ (string-match gnus-article-x-face-too-ugly
+ from))))
+ (while (gnus-article-goto-header "Face")
+ (push (mail-header-field-value) faces)))))
(when faces
(goto-char (point-min))
- (let ((from (gnus-article-goto-header "from"))
- png image)
- (unless from
+ (let (png image)
+ (unless (setq from (gnus-article-goto-header "from"))
(insert "From:")
(setq from (point))
- (insert "[no `from' set]\n"))
+ (insert " [no `from' set]\n"))
(while faces
(when (setq png (gnus-convert-face-to-png (pop faces)))
(setq image
;; instead.
(gnus-delete-images 'xface)
;; Display X-Faces.
- (let (x-faces from face)
+ (let ((from (message-fetch-field "from"))
+ x-faces face)
(save-current-buffer
(when (and wash-face-p
(gnus-buffer-live-p gnus-original-article-buffer)
(set-buffer gnus-original-article-buffer))
(save-restriction
(mail-narrow-to-head)
- (while (gnus-article-goto-header "X-Face")
- (push (mail-header-field-value) x-faces))
- (setq from (message-fetch-field "from"))))
- ;; Sending multiple EOFs to xv doesn't work, so we only do a
- ;; single external face.
- (when (stringp gnus-article-x-face-command)
- (setq x-faces (list (car x-faces))))
- (when (and x-faces
- gnus-article-x-face-command
- (or force
- ;; Check whether this face is censored.
- (not gnus-article-x-face-too-ugly)
- (and from
- (not (string-match gnus-article-x-face-too-ugly
- from)))))
- (while (setq face (pop x-faces))
- ;; We display the face.
- (cond ((stringp 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))
- (gnus-set-process-query-on-exit-flag
- (start-process
- "article-x-face" nil shell-file-name
- shell-command-switch gnus-article-x-face-command)
- nil)
- (with-temp-buffer
- (insert face)
- (process-send-region "article-x-face"
- (point-min) (point-max)))
- (process-send-eof "article-x-face")))
- ((functionp gnus-article-x-face-command)
- ;; The command is a lisp function, so we call it.
- (funcall gnus-article-x-face-command face))
- (t
- (error "%s is not a function"
- gnus-article-x-face-command))))))))))
+ (and gnus-article-x-face-command
+ (or force
+ ;; Check whether this face is censored.
+ (not (and gnus-article-x-face-too-ugly
+ (or from
+ (setq from (message-fetch-field "from")))
+ (string-match gnus-article-x-face-too-ugly
+ from))))
+ (while (gnus-article-goto-header "X-Face")
+ (push (mail-header-field-value) x-faces)))))
+ (when x-faces
+ ;; We display the face.
+ (cond ((functionp gnus-article-x-face-command)
+ ;; The command is a lisp function, so we call it.
+ (mapc gnus-article-x-face-command x-faces))
+ ((stringp 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))
+ (gnus-set-process-query-on-exit-flag
+ (start-process
+ "article-x-face" nil shell-file-name
+ shell-command-switch gnus-article-x-face-command)
+ nil)
+ ;; Sending multiple EOFs to xv doesn't work,
+ ;; so we only do a single external face.
+ (with-temp-buffer
+ (insert (car x-faces))
+ (process-send-region "article-x-face"
+ (point-min) (point-max)))
+ (process-send-eof "article-x-face")))
+ (t
+ (error "`%s' set to `%s' is not a function"
+ gnus-article-x-face-command
+ 'gnus-article-x-face-command)))))))))
(defun article-decode-mime-words ()
"Decode all MIME-encoded words in the article."
(goto-char (setq end start)))))
(defun article-decode-group-name ()
- "Decode group names in `Newsgroups:'."
+ "Decode group names in Newsgroups, Followup-To and Xref headers."
(let ((inhibit-point-motion-hooks t)
(inhibit-read-only t)
- (method (gnus-find-method-for-group gnus-newsgroup-name)))
+ (method (gnus-find-method-for-group gnus-newsgroup-name))
+ regexp)
(when (and (or gnus-group-name-charset-method-alist
gnus-group-name-charset-group-alist)
(gnus-buffer-live-p gnus-original-article-buffer))
(save-restriction
(article-narrow-to-head)
- (with-current-buffer gnus-original-article-buffer
- (goto-char (point-min)))
- (while (re-search-forward
- "^Newsgroups:\\(\\(.\\|\n[\t ]\\)*\\)\n[^\t ]" nil t)
- (replace-match (save-match-data
- (gnus-decode-newsgroups
- ;; XXX how to use data in article buffer?
- (with-current-buffer gnus-original-article-buffer
- (re-search-forward
- "^Newsgroups:\\(\\(.\\|\n[\t ]\\)*\\)\n[^\t ]"
- nil t)
- (match-string 1))
- gnus-newsgroup-name method))
- t t nil 1))
- (goto-char (point-min))
- (with-current-buffer gnus-original-article-buffer
- (goto-char (point-min)))
- (while (re-search-forward
- "^Followup-To:\\(\\(.\\|\n[\t ]\\)*\\)\n[^\t ]" nil t)
- (replace-match (save-match-data
- (gnus-decode-newsgroups
- ;; XXX how to use data in article buffer?
- (with-current-buffer gnus-original-article-buffer
- (re-search-forward
- "^Followup-To:\\(\\(.\\|\n[\t ]\\)*\\)\n[^\t ]"
- nil t)
- (match-string 1))
- gnus-newsgroup-name method))
- t t nil 1))))))
+ (dolist (header '("Newsgroups" "Followup-To" "Xref"))
+ (with-current-buffer gnus-original-article-buffer
+ (goto-char (point-min)))
+ (setq regexp (concat "^" header
+ ":\\([^\n]*\\(?:\n[\t ]+[^\n]+\\)*\\)\n"))
+ (while (re-search-forward regexp nil t)
+ (replace-match (save-match-data
+ (gnus-decode-newsgroups
+ ;; XXX how to use data in article buffer?
+ (with-current-buffer gnus-original-article-buffer
+ (re-search-forward regexp nil t)
+ (match-string 1))
+ gnus-newsgroup-name method))
+ t t nil 1))
+ (goto-char (point-min)))))))
(autoload 'idna-to-unicode "idna")
(string-match "text/html" (car (mm-handle-type handle))))
(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)
+ "mm-" nil ".html"))
+ (charset (mail-content-type-get (mm-handle-type handle)
+ 'charset)))
+ (if charset
+ ;; Add a meta html tag to specify charset.
+ (mm-with-unibyte-buffer
+ (insert (with-current-buffer (mm-handle-buffer handle)
+ (if (eq charset 'gnus-decoded)
+ (mm-encode-coding-string
+ (buffer-string)
+ (setq charset 'utf-8))
+ (buffer-string))))
+ (setq charset (format "\
+<meta http-equiv=\"Content-Type\" content=\"text/html; charset=%s\">"
+ charset))
+ (goto-char (point-min))
+ (let ((case-fold-search t))
+ (cond (;; Don't modify existing meta tag.
+ (re-search-forward "\
+<meta[\t\n\r ]+http-equiv=\"content-type\"[^>]+>"
+ nil t))
+ ((re-search-forward "<head>[\t\n\r ]*" nil t)
+ (insert charset "\n"))
+ (t
+ (re-search-forward "\
+<html\\(?:[\t\n\r ]+[^>]+\\|[\t\n\r ]*\\)>[\t\n\r ]*"
+ nil t)
+ (insert "<head>\n" charset "\n</head>\n"))))
+ (mm-write-region (point-min) (point-max)
+ tmp-file nil nil nil 'binary t))
+ (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)
whether you have read the message. As
`gnus-article-browse-html-article' passes the unmodified HTML
content to the browser without eliminating these \"web bugs\" you
-should only use it for mails from trusted senders."
+should only use it for mails from trusted senders.
+
+If you alwasy want to display HTML part in the browser, set
+`mm-text-html-renderer' to nil."
;; Cf. `mm-w3m-safe-url-regexp'
(interactive)
(save-window-excursion
(canlock-verify gnus-original-article-buffer)))
(eval-and-compile
- (mapcar
+ (mapc
(lambda (func)
(let (afunc gfunc)
(if (consp func)
article-emphasize
article-treat-dumbquotes
article-normalize-headers
-;; (article-show-all . gnus-article-show-all-headers)
+ ;;(article-show-all . gnus-article-show-all-headers)
)))
\f
;;;
(make-local-variable 'gnus-article-image-alist)
(make-local-variable 'gnus-article-charset)
(make-local-variable 'gnus-article-ignored-charsets)
- ;; Prevent recent Emacsen from displaying non-break space as "\ ".
+ ;; Prevent Emacs 22 from displaying non-break space with `nobreak-space'
+ ;; face.
(set (make-local-variable 'nobreak-char-display) nil)
(setq cursor-in-non-selected-windows nil)
(setq truncate-lines gnus-article-truncate-lines)
;; Set article window start at LINE, where LINE is the number of lines
;; from the head of the article.
(defun gnus-article-set-window-start (&optional line)
- (set-window-start
- (gnus-get-buffer-window gnus-article-buffer t)
- (save-excursion
- (set-buffer gnus-article-buffer)
- (goto-char (point-min))
- (if (not line)
- (point-min)
- (gnus-message 6 "Moved to bookmark")
- (search-forward "\n\n" nil t)
- (forward-line line)
- (point)))))
+ (let ((article-window (gnus-get-buffer-window gnus-article-buffer t)))
+ (when article-window
+ (set-window-start
+ article-window
+ (save-excursion
+ (set-buffer gnus-article-buffer)
+ (goto-char (point-min))
+ (if (not line)
+ (point-min)
+ (gnus-message 6 "Moved to bookmark")
+ (search-forward "\n\n" nil t)
+ (forward-line line)
+ (point)))))))
(defun gnus-article-prepare (article &optional all-headers header)
"Prepare ARTICLE in article mode buffer.
(funcall gnus-display-mime-function))
(gnus-run-hooks 'gnus-article-prepare-hook)))
+;;;
+;;; Gnus Sticky Article Mode
+;;;
+
+(define-derived-mode gnus-sticky-article-mode gnus-article-mode "StickyArticle"
+ "Mode for sticky articles."
+ ;; Release bindings that won't work.
+ (substitute-key-definition 'gnus-article-read-summary-keys 'undefined
+ gnus-sticky-article-mode-map)
+ (substitute-key-definition 'gnus-article-refer-article 'undefined
+ gnus-sticky-article-mode-map)
+ (dolist (k '("e" "h" "s" "F" "R"))
+ (define-key gnus-sticky-article-mode-map k nil))
+ (define-key gnus-sticky-article-mode-map "k" 'gnus-kill-sticky-article-buffer)
+ (define-key gnus-sticky-article-mode-map "q" 'bury-buffer)
+ (define-key gnus-sticky-article-mode-map "\C-hc" 'describe-key-briefly)
+ (define-key gnus-sticky-article-mode-map "\C-hk" 'describe-key))
+
+(defun gnus-sticky-article (arg)
+ "Make the current article sticky.
+If a prefix ARG is given, ask for a name for this sticky article buffer."
+ (interactive "P")
+ (gnus-summary-show-thread)
+ (gnus-summary-select-article nil nil 'pseudo)
+ (let (new-art-buf-name)
+ (gnus-eval-in-buffer-window gnus-article-buffer
+ (setq new-art-buf-name
+ (concat
+ "*Sticky Article: "
+ (if arg
+ (read-from-minibuffer "Sticky article buffer name: ")
+ (gnus-with-article-headers
+ (gnus-article-goto-header "subject")
+ (setq new-art-buf-name
+ (buffer-substring-no-properties
+ (line-beginning-position) (line-end-position)))
+ (goto-char (point-min))
+ (gnus-article-goto-header "from")
+ (setq new-art-buf-name
+ (concat
+ new-art-buf-name ", "
+ (buffer-substring-no-properties
+ (line-beginning-position) (line-end-position))))
+ (goto-char (point-min))
+ (gnus-article-goto-header "date")
+ (setq new-art-buf-name
+ (concat
+ new-art-buf-name ", "
+ (buffer-substring-no-properties
+ (line-beginning-position) (line-end-position))))))
+ "*"))
+ (if (and (gnus-buffer-live-p new-art-buf-name)
+ (with-current-buffer new-art-buf-name
+ (eq major-mode 'gnus-sticky-article-mode)))
+ (switch-to-buffer new-art-buf-name)
+ (setq new-art-buf-name (rename-buffer new-art-buf-name t)))
+ (gnus-sticky-article-mode))
+ (setq gnus-article-buffer new-art-buf-name))
+ (gnus-summary-recenter)
+ (gnus-summary-position-point))
+
+(defun gnus-kill-sticky-article-buffer (&optional buffer)
+ "Kill the given sticky article BUFFER.
+If none is given, assume the current buffer and kill it if it has
+`gnus-sticky-article-mode'."
+ (interactive)
+ (unless buffer
+ (setq buffer (current-buffer)))
+ (with-current-buffer buffer
+ (when (eq major-mode 'gnus-sticky-article-mode)
+ (gnus-kill-buffer buffer))))
+
+(defun gnus-kill-sticky-article-buffers (arg)
+ "Kill all sticky article buffers.
+If a prefix ARG is given, ask for confirmation."
+ (interactive "P")
+ (dolist (buf (gnus-buffers))
+ (with-current-buffer buf
+ (when (eq major-mode 'gnus-sticky-article-mode)
+ (if (not arg)
+ (gnus-kill-buffer buf)
+ (when (yes-or-no-p (concat "Kill buffer " (buffer-name buf) "? "))
+ (gnus-kill-buffer buf)))))))
+
;;;
;;; Gnus MIME viewing functions
;;;
(gnus-summary-show-article)
(when (and current-id (integerp gnus-auto-select-part))
(gnus-article-jump-to-part
- (+ current-id gnus-auto-select-part)))))
+ (if (text-property-any (point-min) (point-max)
+ 'gnus-part (+ current-id gnus-auto-select-part))
+ (+ current-id gnus-auto-select-part)
+ (with-current-buffer gnus-article-buffer
+ (length gnus-article-mime-handle-alist)))))))
(defun gnus-mime-replace-part (file)
"Replace MIME part under point with an external body."
;; Content-Disposition: attachment; filename=...
(cdr (assq 'filename (cdr (mm-handle-disposition handle))))))
(def-type (and name (mm-default-file-encoding name))))
- (and def-type (cons def-type 0))))
+ (or (and def-type (cons def-type 0))
+ (and handle
+ (equal (mm-handle-media-supertype handle) "text")
+ '("text/plain" . 0))
+ '("application/octet-stream" . 0))))
(defun gnus-mime-view-part-as-type (&optional mime-type pred)
"Choose a MIME media type, and view the part as such.
(mm-handle-id handle)))
(setq gnus-article-mime-handles
(mm-merge-handles gnus-article-mime-handles handle))
+ (when (mm-handle-displayed-p handle)
+ (mm-remove-part handle))
(gnus-mm-display-part handle))))
(defun gnus-mime-copy-part (&optional handle arg)
(mm-string-to-multibyte contents)))
(goto-char b)))))
+(defun gnus-mime-strip-charset-parameters (handle)
+ "Strip charset parameters from HANDLE."
+ (if (stringp (car handle))
+ (mapc #'gnus-mime-strip-charset-parameters (cdr handle))
+ (let* ((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))))
+ (when charset
+ (delq charset type)))))
+
(defun gnus-mime-view-part-as-charset (&optional handle arg)
"Insert the MIME part under point into the current buffer using the
specified charset."
(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)
+ gnus-newsgroup-charset form preferred parts)
(when handle
- (if (mm-handle-undisplayer handle)
- (mm-remove-part handle))
- (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)
+ (when (prog1
+ (and fun
+ (setq gnus-newsgroup-charset
+ (or (cdr (assq
+ arg
+ gnus-summary-show-article-charset-alist))
+ (mm-read-coding-system "Charset: "))))
+ (if (mm-handle-undisplayer handle)
+ (mm-remove-part handle)))
+ (gnus-mime-strip-charset-parameters handle)
+ (when (and (consp (setq form (cdr-safe fun)))
+ (setq form (ignore-errors
+ (assq 'gnus-mime-display-alternative form)))
+ (setq preferred (caddr form))
+ (progn
+ (when (eq (car preferred) 'quote)
+ (setq preferred (cadr preferred)))
+ (not (equal preferred
+ (get-text-property (point) 'gnus-data))))
+ (setq parts (get-text-property (point) 'gnus-part))
+ (setq parts (cdr (assq parts
+ gnus-article-mime-handle-alist)))
+ (equal (mm-handle-media-type parts) "multipart/alternative")
+ (setq parts (reverse (cdr parts))))
+ (setcar (cddr form)
+ (list 'quote (or (cadr (member preferred parts))
+ (car parts)))))
(funcall fun handle)))))
(defun gnus-mime-view-part-externally (&optional handle)
(mm-enable-external t))
(if (not (stringp method))
(gnus-mime-view-part-as-type
- nil (lambda (type) (stringp (mailcap-mime-info type))))
+ nil (lambda (types) (stringp (mailcap-mime-info (car types)))))
(when handle
(if (mm-handle-undisplayer handle)
(mm-remove-part handle)
(inhibit-read-only t))
(if (not (mm-inlinable-p handle))
(gnus-mime-view-part-as-type
- nil (lambda (type) (mm-inlinable-p handle type)))
+ nil (lambda (types) (mm-inlinable-p handle (car types))))
(when handle
(if (mm-handle-undisplayer handle)
(mm-remove-part handle)
(unless (with-current-buffer gnus-summary-buffer
(eq gnus-current-article (gnus-summary-article-number)))
(error "You should select the right article first"))
+ (if n
+ (setq n (prefix-numeric-value n))
+ (let ((pt (point)))
+ (setq n (or (get-text-property pt 'gnus-part)
+ (and (not (bobp))
+ (get-text-property (1- pt) 'gnus-part))
+ (get-text-property (prog2
+ (forward-line 1)
+ (point)
+ (goto-char pt))
+ 'gnus-part)
+ (get-text-property
+ (or (and (setq pt (previous-single-property-change
+ pt 'gnus-part))
+ (1- pt))
+ (next-single-property-change (point) 'gnus-part)
+ (point))
+ 'gnus-part)
+ 1))))
;; Check whether the specified part exists.
(when (> n (length gnus-article-mime-handle-alist))
(error "No such part")))
(defun gnus-article-pipe-part (n)
"Pipe MIME part N, which is the numerical prefix."
- (interactive "p")
+ (interactive "P")
(gnus-article-part-wrapper n 'mm-pipe-part))
(defun gnus-article-save-part (n)
"Save MIME part N, which is the numerical prefix."
- (interactive "p")
+ (interactive "P")
(gnus-article-part-wrapper n 'mm-save-part))
(defun gnus-article-interactively-view-part (n)
"View MIME part N interactively, which is the numerical prefix."
- (interactive "p")
+ (interactive "P")
(gnus-article-part-wrapper n 'mm-interactively-view-part))
(defun gnus-article-copy-part (n)
"Copy MIME part N, which is the numerical prefix."
- (interactive "p")
+ (interactive "P")
(gnus-article-part-wrapper n 'gnus-mime-copy-part))
(defun gnus-article-view-part-as-charset (n)
"View MIME part N using a specified charset.
N is the numerical prefix."
- (interactive "p")
+ (interactive "P")
(gnus-article-part-wrapper n 'gnus-mime-view-part-as-charset))
(defun gnus-article-view-part-externally (n)
"View MIME part N externally, which is the numerical prefix."
- (interactive "p")
+ (interactive "P")
(gnus-article-part-wrapper n 'gnus-mime-view-part-externally))
(defun gnus-article-inline-part (n)
"Inline MIME part N, which is the numerical prefix."
- (interactive "p")
+ (interactive "P")
(gnus-article-part-wrapper n 'gnus-mime-inline-part))
(defun gnus-article-save-part-and-strip (n)
"Save MIME part N and replace it with an external body.
N is the numerical prefix."
- (interactive "p")
+ (interactive "P")
(gnus-article-part-wrapper n 'gnus-mime-save-part-and-strip t))
(defun gnus-article-replace-part (n)
"Replace MIME part N with an external body.
N is the numerical prefix."
- (interactive "p")
+ (interactive "P")
(gnus-article-part-wrapper n 'gnus-mime-replace-part t t))
(defun gnus-article-delete-part (n)
"Delete MIME part N and add some information about the removed part.
N is the numerical prefix."
- (interactive "p")
+ (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")
+ (interactive "P")
(gnus-article-part-wrapper n 'gnus-mime-view-part-as-type t))
(defun gnus-article-mime-match-handle-first (condition)
(1- (point))
(point)))
(when gnus-article-button-face
- (gnus-overlay-put (gnus-make-overlay b e)
- 'face gnus-article-button-face))
+ (gnus-overlay-put (gnus-make-overlay b e nil t)
+ 'face gnus-article-button-face))
(widget-convert-button
'link b e
:mime-handle handle
(gnus-article-insert-newline)
(mm-insert-inline
handle
- (let ((charset (mail-content-type-get (mm-handle-type handle)
- 'charset)))
+ (let ((charset (or (mail-content-type-get (mm-handle-type handle)
+ 'charset)
+ (and (equal type "text/calendar") 'utf-8))))
(cond ((not charset)
(mm-string-as-multibyte (mm-get-part handle)))
((eq charset 'gnus-decoded)
(save-excursion
(save-restriction
(narrow-to-region beg (point))
- (gnus-treat-article
- nil id
- (gnus-article-mime-total-parts)
- (mm-handle-media-type handle)))))))))
+ (if (eq handle gnus-article-mime-handles)
+ ;; The format=flowed case.
+ (gnus-treat-article nil 1 1 (mm-handle-media-type handle))
+ ;; Don't count signature parts that are never displayed.
+ ;; The part number should be re-calculated supposing this
+ ;; might be a message/rfc822 part.
+ (let (handles)
+ (dolist (part gnus-article-mime-handles)
+ (unless (or (stringp part)
+ (equal (car (mm-handle-type part))
+ "application/pgp-signature"))
+ (push part handles)))
+ (gnus-treat-article
+ nil (length (memq handle handles)) (length handles)
+ (mm-handle-media-type handle)))))))))))
(defun gnus-unbuttonized-mime-type-p (type)
"Say whether TYPE is to be unbuttonized."
Argument LINES specifies lines to be scrolled up."
(interactive "p")
(move-to-window-line -1)
- (if (save-excursion
- (end-of-line)
- (and (pos-visible-in-window-p) ;Not continuation line.
- (>= (1+ (point)) (point-max)))) ;Allow for trailing newline.
+ (if (and (not (and gnus-article-over-scroll
+ (> (count-lines (window-start) (point-max))
+ (+ (or lines (1- (window-height)))
+ (or (and (boundp 'scroll-margin)
+ (symbol-value 'scroll-margin))
+ 0)))))
+ (save-excursion
+ (end-of-line)
+ (and (pos-visible-in-window-p) ;Not continuation line.
+ (>= (1+ (point)) (point-max))))) ;Allow for trailing newline.
;; Nothing in this page.
(if (or (not gnus-page-broken)
(save-excursion
(progn
(gnus-narrow-to-page -1) ;Go to previous page.
(goto-char (point-max))
- (recenter -1))
+ (recenter (if gnus-article-over-scroll
+ (if lines
+ (max (+ lines (or (and (boundp 'scroll-margin)
+ (symbol-value 'scroll-margin))
+ 0))
+ 3)
+ (- (window-height) 2))
+ -1)))
(prog1
(condition-case ()
(let ((scroll-in-place nil))
"Execute the last keystroke in the summary buffer."
(interactive)
(let (func)
- (pop-to-buffer gnus-article-current-summary 'norecord)
+ (pop-to-buffer gnus-article-current-summary)
(setq func (lookup-key (current-local-map) (this-command-keys)))
(call-interactively func)))
(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-article-current-summary 'norecord)
- ;; We disable the pick minor mode commands.
- (let (gnus-pick-mode)
- (setq func (lookup-key (current-local-map) keys))))
- (if (or (not func)
- (numberp 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)))
+ (cond
+ ((eq (aref keys (1- (length keys))) ?\C-h)
+ (with-current-buffer gnus-article-current-summary
+ (describe-bindings (substring keys 0 -1))))
+ ((or (member keys nosaves)
+ (member keys nosave-but-article)
+ (member keys nosave-in-article))
+ (let (func)
+ (save-window-excursion
+ (pop-to-buffer gnus-article-current-summary)
+ ;; We disable the pick minor mode commands.
+ (let (gnus-pick-mode)
+ (setq func (lookup-key (current-local-map) keys))))
+ (if (or (not func)
+ (numberp 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))))
+ (t
;; These commands should restore window configuration.
(let ((obuf (current-buffer))
(owin (current-window-configuration))
- (opoint (point))
- win func in-buffer selected new-sum-start new-sum-hscroll)
+ win func in-buffer selected new-sum-start new-sum-hscroll err)
(cond (not-restore-window
- (pop-to-buffer gnus-article-current-summary 'norecord))
+ (pop-to-buffer gnus-article-current-summary)
+ (setq win (selected-window)))
((setq win (get-buffer-window gnus-article-current-summary))
(select-window win))
(t
- (switch-to-buffer gnus-article-current-summary 'norecord)))
+ (let ((summary-buffer gnus-article-current-summary))
+ (gnus-configure-windows 'article)
+ (unless (setq win (get-buffer-window summary-buffer 'visible))
+ (let ((gnus-buffer-configuration
+ '(article ((vertical 1.0
+ (summary 0.25 point)
+ (article 1.0))))))
+ (gnus-configure-windows 'article))
+ (setq win (get-buffer-window summary-buffer 'visible)))
+ (gnus-select-frame-set-input-focus (window-frame win))
+ (select-window win))))
(setq in-buffer (current-buffer))
;; We disable the pick minor mode commands.
(if (and (setq func (let (gnus-pick-mode)
(lookup-key (current-local-map) keys)))
- (functionp func))
+ (functionp func)
+ (condition-case code
+ (progn
+ (call-interactively func)
+ t)
+ (error
+ (setq err code)
+ nil)))
(progn
- (call-interactively func)
(when (eq win (selected-window))
(setq new-sum-point (point)
new-sum-start (window-start win)
new-sum-hscroll (window-hscroll win)))
- (when (eq in-buffer (current-buffer))
+ (when (or (eq in-buffer (current-buffer))
+ (when (eq obuf (current-buffer))
+ (set-buffer in-buffer)
+ t))
(setq selected (gnus-summary-select-article))
(set-buffer obuf)
(unless not-restore-window
(set-window-configuration owin))
- (when (eq selected 'old)
- (article-goto-body)
+ (when (and (eq selected 'old)
+ new-sum-point)
(set-window-start (get-buffer-window (current-buffer))
1)
(set-window-point (get-buffer-window (current-buffer))
- (point)))
+ (if (article-goto-body)
+ (1- (point))
+ (point))))
(when (and (not not-restore-window)
- new-sum-point)
+ new-sum-point
+ (with-current-buffer (window-buffer win)
+ (eq major-mode 'gnus-summary-mode)))
(set-window-point win new-sum-point)
(set-window-start win new-sum-start)
(set-window-hscroll win new-sum-hscroll))))
(set-window-configuration owin)
- (ding))))))
+ (if err
+ (signal (car err) (cdr err))
+ (ding))))))))
(defun gnus-article-describe-key (key)
"Display documentation of the function invoked by KEY. KEY is a string."
(-20.0 . "\\.fsf@") ;; Gnus
(-20.0 . "^slrn")
(-20.0 . "^Pine")
+ (-20.0 . "^alpine\\.")
(-20.0 . "_-_") ;; Subject change in thread
;;
(-20.0 . "\\.ln@") ;; leafnode
;; here to determine where it ends.
1 (>= gnus-button-emacs-level 1) gnus-button-handle-describe-key 3)
;; This is how URLs _should_ be embedded in text (RFC 1738, RFC 2396)...
- ("<URL: *\\([^<>]*\\)>"
- 1 (>= gnus-button-browse-level 0) gnus-button-embedded-url 1)
- ;; RFC 2396 (2.4.3., delims) ...
- ("\"URL: *\\([^\"]*\\)\""
+ ("<URL: *\\([^\n<>]*\\)>"
1 (>= gnus-button-browse-level 0) gnus-button-embedded-url 1)
;; RFC 2396 (2.4.3., delims) ...
- ("\"URL: *\\([^\"]*\\)\""
+ ("\"URL: *\\([^\n\"]*\\)\""
1 (>= gnus-button-browse-level 0) gnus-button-embedded-url 1)
;; Raw URLs.
(gnus-button-url-regexp
(repeat :tag "Par"
:inline t
(integer :tag "Regexp group")))))
+(put 'gnus-button-alist 'risky-local-variable t)
(defcustom gnus-header-button-alist
'(("^\\(References\\|Message-I[Dd]\\|^In-Reply-To\\):" "<[^<>]+>"
(repeat :tag "Par"
:inline t
(integer :tag "Regexp group")))))
+(put 'gnus-header-button-alist 'risky-local-variable t)
;;; Commands:
(save-restriction
(when (and gnus-signature-face
(gnus-article-narrow-to-signature))
- (gnus-overlay-put (gnus-make-overlay (point-min) (point-max))
+ (gnus-overlay-put (gnus-make-overlay (point-min) (point-max) nil t)
'face gnus-signature-face)
(widen)
(gnus-article-search-signature)
(setq regexp (eval (car entry)))
(goto-char beg)
(while (re-search-forward regexp nil t)
- (let* ((start (and entry (match-beginning (nth 1 entry))))
- (end (and entry (match-end (nth 1 entry))))
- (from (match-beginning 0)))
+ (let ((start (match-beginning (nth 1 entry)))
+ (end (match-end (nth 1 entry)))
+ (from (match-beginning 0)))
(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
- (car (push (set-marker (make-marker) from)
- gnus-button-marker-list))))))))))
+ (setq from (set-marker (make-marker) from))
+ (push from gnus-button-marker-list)
+ (unless (and (eq (car entry) 'gnus-button-url-regexp)
+ (gnus-article-extend-url-button from start end))
+ (gnus-article-add-button start end
+ 'gnus-button-push from)))))))))
+
+(defun gnus-article-extend-url-button (beg start end)
+ "Extend url button if url is folded into two or more lines.
+Return non-nil if button is extended. BEG is a marker that points to
+the beginning position of a text containing url. START and END are
+the endpoints of a url button before it is extended. The concatenated
+url is put as the `gnus-button-url' overlay property on the button."
+ (let ((opoint (point))
+ (points (list start end))
+ url delim regexp)
+ (prog1
+ (when (and (progn
+ (goto-char end)
+ (not (looking-at "[\t ]*[\">]")))
+ (progn
+ (goto-char start)
+ (string-match
+ "\\(?:\"\\|\\(<\\)\\)[\t ]*\\(?:url[\t ]*:[\t ]*\\)?\\'"
+ (buffer-substring (point-at-bol) start)))
+ (progn
+ (setq url (list (buffer-substring start end))
+ delim (if (match-beginning 1) ">" "\""))
+ (beginning-of-line)
+ (setq regexp (concat
+ (when (and (looking-at
+ message-cite-prefix-regexp)
+ (< (match-end 0) start))
+ (regexp-quote (match-string 0)))
+ "\
+\[\t ]*\\(?:\\([^\t\n \">]+\\)[\t ]*$\\|\\([^\t\n \">]*\\)[\t ]*"
+ delim "\\)"))
+ (while (progn
+ (forward-line 1)
+ (and (looking-at regexp)
+ (prog1
+ (match-beginning 1)
+ (push (or (match-string 2)
+ (match-string 1))
+ url)
+ (push (setq end (or (match-end 2)
+ (match-end 1)))
+ points)
+ (push (or (match-beginning 2)
+ (match-beginning 1))
+ points)))))
+ (match-beginning 2)))
+ (let (gnus-article-mouse-face widget-mouse-face)
+ (while points
+ (gnus-article-add-button (pop points) (pop points)
+ 'gnus-button-push beg)))
+ (let ((overlay (gnus-make-overlay start end)))
+ (gnus-overlay-put overlay 'evaporate t)
+ (gnus-overlay-put overlay 'gnus-button-url
+ (list (mapconcat 'identity (nreverse url) "")))
+ (when gnus-article-mouse-face
+ (gnus-overlay-put overlay 'mouse-face gnus-article-mouse-face)))
+ t)
+ (goto-char opoint))))
;; Add buttons to the head of an article.
(defun gnus-article-add-buttons-to-head ()
(defun gnus-article-add-button (from to fun &optional data)
"Create a button between FROM and TO with callback FUN and data DATA."
(when gnus-article-button-face
- (gnus-overlay-put (gnus-make-overlay from to)
+ (gnus-overlay-put (gnus-make-overlay from to nil t)
'face gnus-article-button-face))
(gnus-add-text-properties
from to
(let* ((entry (gnus-button-entry))
(inhibit-point-motion-hooks t)
(fun (nth 3 entry))
- (args (mapcar (lambda (group)
- (let ((string (match-string group)))
- (set-text-properties
- 0 (length string) nil string)
- string))
- (nthcdr 4 entry))))
+ (args (or (and (eq (car entry) 'gnus-button-url-regexp)
+ (get-char-property marker 'gnus-button-url))
+ (mapcar (lambda (group)
+ (let ((string (match-string group)))
+ (set-text-properties
+ 0 (length string) nil string)
+ string))
+ (nthcdr 4 entry)))))
(cond
((fboundp fun)
(apply fun args))
(1- (point))
(point)))
(when gnus-article-button-face
- (gnus-overlay-put (gnus-make-overlay b e)
+ (gnus-overlay-put (gnus-make-overlay b e nil t)
'face gnus-article-button-face))
(widget-convert-button
'link b e
(1- (point))
(point)))
(when gnus-article-button-face
- (gnus-overlay-put (gnus-make-overlay b e)
+ (gnus-overlay-put (gnus-make-overlay b e nil t)
'face gnus-article-button-face))
(widget-convert-button
'link b e
(eq gnus-newsgroup-name
(car gnus-decode-header-methods-cache)))
(setq gnus-decode-header-methods-cache (list gnus-newsgroup-name))
- (mapcar (lambda (x)
- (if (symbolp x)
- (nconc gnus-decode-header-methods-cache (list x))
- (if (and gnus-newsgroup-name
- (string-match (car x) gnus-newsgroup-name))
- (nconc gnus-decode-header-methods-cache
- (list (cdr x))))))
- gnus-decode-header-methods))
+ (dolist (x gnus-decode-header-methods)
+ (if (symbolp x)
+ (nconc gnus-decode-header-methods-cache (list x))
+ (if (and gnus-newsgroup-name
+ (string-match (car x) gnus-newsgroup-name))
+ (nconc gnus-decode-header-methods-cache
+ (list (cdr x)))))))
(let ((xlist gnus-decode-header-methods-cache))
(pop xlist)
(save-restriction
point (inhibit-read-only t))
(if region
(goto-char (car region)))
- (save-restriction
- (narrow-to-region (point) (point))
- (with-current-buffer (mm-handle-multipart-original-buffer handle)
- (let* ((mm-verify-option 'known)
- (mm-decrypt-option 'known)
- (nparts (mm-possibly-verify-or-decrypt (cdr handle) handle)))
- (unless (eq nparts (cdr handle))
- (mm-destroy-parts (cdr handle))
- (setcdr handle nparts))))
- (setq point (point))
- (gnus-mime-display-security handle)
- (goto-char (point-max)))
+ (setq point (point))
+ (with-current-buffer (mm-handle-multipart-original-buffer handle)
+ (let* ((mm-verify-option 'known)
+ (mm-decrypt-option 'known)
+ (nparts (mm-possibly-verify-or-decrypt (cdr handle) handle)))
+ (unless (eq nparts (cdr handle))
+ (mm-destroy-parts (cdr handle))
+ (setcdr handle nparts))))
+ (gnus-mime-display-security handle)
(when region
(delete-region (point) (cdr region))
(set-marker (car region) nil)
(1- (point))
(point)))
(when gnus-article-button-face
- (gnus-overlay-put (gnus-make-overlay b e)
+ (gnus-overlay-put (gnus-make-overlay b e nil t)
'face gnus-article-button-face))
(widget-convert-button
'link b e
(mm-set-handle-multipart-parameter
handle 'gnus-region
(cons (set-marker (make-marker) (point-min))
- (set-marker (make-marker) (point-max))))))
+ (set-marker (make-marker) (point-max))))
+ (goto-char (point-max))))
(defun gnus-mime-security-run-function (function)
"Run FUNCTION with the security part under point."