X-Git-Url: http://cgit.sxemacs.org/?a=blobdiff_plain;f=lisp%2Fgnus-art.el;h=f1de3f6ad3b17c2d627a3b7c6535e69b18511274;hb=d14f1cf57711b78522fb29b0a512f0e8c6e535d9;hp=c67e043d55f95c68353adbfadacf75b924fccb7e;hpb=a70e05fa2a8a81b235f01e0e9539bceda0664a3a;p=gnus diff --git a/lisp/gnus-art.el b/lisp/gnus-art.el index c67e043d5..f1de3f6ad 100644 --- a/lisp/gnus-art.el +++ b/lisp/gnus-art.el @@ -502,7 +502,10 @@ be fed to `format-time-string'." :group 'gnus-article-washing) (defcustom gnus-save-all-headers t - "*If non-nil, don't remove any headers before saving." + "*If non-nil, don't remove any headers before saving. +This will be overridden by the `:headers' property that the symbol of +the saver function, which is specified by `gnus-default-article-saver', +might have." :group 'gnus-article-saving :type 'boolean) @@ -523,14 +526,17 @@ each invocation of the saving commands." "Headers to keep if `gnus-save-all-headers' is nil. If `gnus-save-all-headers' is non-nil, this variable will be ignored. If that variable is nil, however, all headers that match this regexp -will be kept while the rest will be deleted before saving." +will be kept while the rest will be deleted before saving. This and +`gnus-save-all-headers' will be overridden by the `:headers' property +that the symbol of the saver function, which is specified by +`gnus-default-article-saver', might have." :group 'gnus-article-saving :type 'regexp) (defcustom gnus-default-article-saver 'gnus-summary-save-in-rmail "A function to save articles in your favourite format. -The function must be interactively callable (in other words, it must -be an Emacs command). +The function will be called by way of the `gnus-summary-save-article' +command, and friends such as `gnus-summary-save-article-rmail'. Gnus provides the following functions: @@ -540,7 +546,28 @@ Gnus provides the following functions: * gnus-summary-save-in-file (article format) * gnus-summary-save-body-in-file (article body) * gnus-summary-save-in-vm (use VM's folder format) -* gnus-summary-write-to-file (article format -- overwrite)." +* gnus-summary-write-to-file (article format -- overwrite) +* gnus-summary-write-body-to-file (article body -- overwrite) + +The symbol of each function may have the following properties: + +* :decode +The value non-nil means save decoded articles. This is meaningful +only with `gnus-summary-save-in-file', `gnus-summary-save-body-in-file', +`gnus-summary-write-to-file', and `gnus-summary-write-body-to-file'. + +* :function +The value specifies an alternative function which appends, not +overwrites, articles to a file. This implies that when saving many +articles at a time, `gnus-prompt-before-saving' is bound to t and all +articles are saved in a single file. This is meaningful only with +`gnus-summary-write-to-file' and `gnus-summary-write-body-to-file'. + +* :headers +The value specifies the symbol of a variable of which the value +specifies headers to be saved. If it is omitted, +`gnus-save-all-headers' and `gnus-saved-headers' control what +headers should be saved." :group 'gnus-article-saving :type '(radio (function-item gnus-summary-save-in-rmail) (function-item gnus-summary-save-in-mail) @@ -549,8 +576,49 @@ Gnus provides the following functions: (function-item gnus-summary-save-body-in-file) (function-item gnus-summary-save-in-vm) (function-item gnus-summary-write-to-file) + (function-item gnus-summary-write-body-to-file) (function))) +(defcustom gnus-article-save-coding-system + (or (and (mm-coding-system-p 'utf-8) 'utf-8) + (and (mm-coding-system-p 'iso-2022-7bit) 'iso-2022-7bit) + (and (mm-coding-system-p 'emacs-mule) 'emacs-mule) + (and (mm-coding-system-p 'escape-quoted) 'escape-quoted)) + "Coding system used to save decoded articles to a file. + +The recommended coding systems are `utf-8', `iso-2022-7bit' and so on, +which can safely encode any characters in text. This is used by the +commands including: + +* gnus-summary-save-article-file +* gnus-summary-save-article-body-file +* gnus-summary-write-article-file +* gnus-summary-write-article-body-file + +and the functions to which you may set `gnus-default-article-saver': + +* gnus-summary-save-in-file +* gnus-summary-save-body-in-file +* gnus-summary-write-to-file +* gnus-summary-write-body-to-file + +Those commands and functions save just text displayed in the article +buffer to a file if the value of this variable is non-nil. Note that +buttonized MIME parts will be lost in a saved file in that case. +Otherwise, raw articles will be saved." + :group 'gnus-article-saving + :type `(choice + :format "%{%t%}:\n %[Value Menu%] %v" + (const :tag "Save raw articles" nil) + ,@(delq nil + (mapcar + (lambda (arg) (if (mm-coding-system-p (nth 3 arg)) arg)) + '((const :tag "UTF-8" utf-8) + (const :tag "iso-2022-7bit" iso-2022-7bit) + (const :tag "Emacs internal" emacs-mule) + (const :tag "escape-quoted" escape-quoted)))) + (symbol :tag "Coding system"))) + (defcustom gnus-rmail-save-name 'gnus-plain-save-name "A function generating a file name to save articles in Rmail format. The function is called with NEWSGROUP, HEADERS, and optional LAST-FILE." @@ -834,6 +902,9 @@ image type in XEmacs if it is built with the libcompface library." (defvar gnus-decode-header-function 'mail-decode-encoded-word-region "Function used to decode headers.") +(defvar gnus-decode-address-function 'mail-decode-encoded-address-region + "Function used to decode addresses.") + (defvar gnus-article-dumbquotes-map '(("\200" "EUR") ("\202" ",") @@ -1286,6 +1357,18 @@ predicate. See Info node `(gnus)Customizing Articles'." :link '(custom-manual "(gnus)Customizing Articles") :type gnus-article-treat-custom) +(defcustom gnus-article-unfold-long-headers nil + "If non-nil, allow unfolding headers even if the header is long. +If it is a regexp, only long headers matching this regexp are unfolded. +If it is t, all long headers are unfolded. + +This variable has no effect if `gnus-treat-unfold-headers' is nil." + :version "23.0" ;; No Gnus + :group 'gnus-article-treat + :type '(choice (const nil) + (const :tag "all" t) + (regexp))) + (defcustom gnus-treat-fold-headers nil "Fold headers. Valid values are nil, t, `head', `first', `last', an integer or a @@ -1762,7 +1845,7 @@ Initialized from `text-mode-syntax-table.") (interactive) ;; This function might be inhibited. (unless gnus-inhibit-hiding - (let ((inhibit-read-only nil) + (let ((inhibit-read-only t) (case-fold-search t) (max (1+ (length gnus-sorted-header-list))) (inhibit-point-motion-hooks t) @@ -2093,16 +2176,21 @@ unfolded." (while (not (eobp)) (save-restriction (mail-header-narrow-to-field) - (let ((header (buffer-string))) + (let* ((header (buffer-string)) + (unfoldable + (or (equal gnus-article-unfold-long-headers t) + (and (stringp gnus-article-unfold-long-headers) + (string-match gnus-article-unfold-long-headers header))))) (with-temp-buffer (insert header) (goto-char (point-min)) (while (re-search-forward "\n[\t ]" nil t) (replace-match " " t t))) - (setq length (- (point-max) (point-min) 1))) - (when (< length (window-width)) - (while (re-search-forward "\n[\t ]" nil t) - (replace-match " " t t))) + (setq length (- (point-max) (point-min) 1)) + (when (or unfoldable + (< length (window-width))) + (while (re-search-forward "\n[\t ]" nil t) + (replace-match " " t t)))) (goto-char (point-max))))))) (defun gnus-article-treat-fold-headers () @@ -2149,6 +2237,39 @@ unfolded." (mail-header-fold-field) (goto-char (point-max)))))) +(defcustom gnus-article-truncate-lines default-truncate-lines + "Value of `truncate-lines' in Gnus Article buffer. +Valid values are nil, t, `head', `first', `last', an integer or a +predicate. See Info node `(gnus)Customizing Articles'." + :version "23.0" ;; No Gnus + :group 'gnus-article + ;; :link '(custom-manual "(gnus)Customizing Articles") + :type 'boolean) + +(defun gnus-article-toggle-truncate-lines (&optional arg) + "Toggle whether to fold or truncate long lines in article the buffer. +If ARG is non-nil and not a number, toggle +`gnus-article-truncate-lines' too. If ARG is a number, truncate +long lines iff arg is positive." + (interactive "P") + (cond + ((and (numberp arg) (> arg 0)) + (setq gnus-article-truncate-lines t)) + ((numberp arg) + (setq gnus-article-truncate-lines nil)) + (arg + (setq gnus-article-truncate-lines + (not gnus-article-truncate-lines)))) + (gnus-with-article-buffer + (cond + ((and (numberp arg) (> arg 0)) + (setq truncate-lines nil)) + ((numberp arg) + (setq truncate-lines t))) + ;; In versions of Emacs 22 (CVS) before 2006-05-26, + ;; `toggle-truncate-lines' needs an argument. + (toggle-truncate-lines))) + (defun gnus-article-treat-body-boundary () "Place a boundary line at the end of the headers." (interactive) @@ -2397,10 +2518,28 @@ If PROMPT (the prefix), prompt for a coding system to use." (set-buffer gnus-summary-buffer) (error)) gnus-newsgroup-ignored-charsets)) - (inhibit-read-only t)) + (inhibit-read-only t) + start) (save-restriction (article-narrow-to-head) - (funcall gnus-decode-header-function (point-min) (point-max))))) + (while (not (eobp)) + (setq start (point)) + (while (progn + (forward-line) + (if (eobp) + nil + (memq (char-after) '(?\t ? ))))) + (save-restriction + (narrow-to-region start (point)) + (goto-char start) + (if (looking-at "\ +\\(?:Resent-\\)?\\(?:From\\|Cc\\|To\\|Bcc\\|\\(?:In-\\)?Reply-To\\|Sender\ +\\|Mail-Followup-To\\|Mail-Copies-To\\|Approved\\):") + (funcall gnus-decode-address-function start (point)) + (funcall gnus-decode-header-function start (point))) + ;; `gnus-decode-*-function' uses `decode-coding-region' which + ;; moves the point to `start' in XEmacs. + (goto-char (point-max))))))) (defun article-decode-group-name () "Decode group names in `Newsgroups:'." @@ -2708,7 +2847,6 @@ Recurse into multiparts." (gnus-article-browse-html-parts handle)))))))) showed)) -;; TODO: Key binding (defun gnus-article-browse-html-article () "View \"text/html\" parts of the current article with a WWW browser." (interactive) @@ -3422,10 +3560,13 @@ This format is defined by the `gnus-article-time-format' variable." (defun gnus-article-save (save-buffer file &optional num) "Save the currently selected article." - (unless gnus-save-all-headers - ;; Remove headers according to `gnus-saved-headers'. + (when (or (get gnus-default-article-saver :headers) + (not gnus-save-all-headers)) + ;; Remove headers according to `gnus-saved-headers' or the value + ;; of the `:headers' property that the saver function might have. (let ((gnus-visible-headers - (or gnus-saved-headers gnus-visible-headers)) + (or (symbol-value (get gnus-default-article-saver :headers)) + gnus-saved-headers gnus-visible-headers)) (gnus-article-buffer save-buffer)) (save-excursion (set-buffer save-buffer) @@ -3450,7 +3591,8 @@ This format is defined by the `gnus-article-time-format' variable." (funcall gnus-default-article-saver filename))))) (defun gnus-read-save-file-name (prompt &optional filename - function group headers variable) + function group headers variable + dir-var) (let ((default-name (funcall function group headers (symbol-value variable))) result) @@ -3463,6 +3605,10 @@ This format is defined by the `gnus-article-time-format' variable." default-name) (filename filename) (t + (when (symbol-value dir-var) + (setq default-name (expand-file-name + (file-name-nondirectory default-name) + (symbol-value dir-var)))) (let* ((split-name (gnus-get-split-value gnus-split-methods)) (prompt (format prompt @@ -3527,7 +3673,11 @@ This format is defined by the `gnus-article-time-format' variable." ;; Possibly translate some characters. (nnheader-translate-file-chars file)))))) (gnus-make-directory (file-name-directory result)) - (set variable result))) + (when variable + (set variable result)) + (when dir-var + (set dir-var (file-name-directory result))) + result)) (defun gnus-article-archive-name (group) "Return the first instance of an \"Archive-name\" in the current buffer." @@ -3575,6 +3725,8 @@ Directory to save to is default to `gnus-article-save-directory'." (gnus-output-to-mail filename))))) filename) +(put 'gnus-summary-save-in-file :decode t) +(put 'gnus-summary-save-in-file :headers 'gnus-saved-headers) (defun gnus-summary-save-in-file (&optional filename overwrite) "Append this article to file. Optional argument FILENAME specifies file name. @@ -3593,13 +3745,21 @@ Directory to save to is default to `gnus-article-save-directory'." (gnus-output-to-file filename)))) filename) +(put 'gnus-summary-write-to-file :decode t) +(put 'gnus-summary-write-to-file :function 'gnus-summary-save-in-file) +(put 'gnus-summary-write-to-file :headers 'gnus-saved-headers) (defun gnus-summary-write-to-file (&optional filename) "Write this article to a file, overwriting it if the file exists. Optional argument FILENAME specifies file name. The directory to save in defaults to `gnus-article-save-directory'." - (gnus-summary-save-in-file nil t)) + (setq filename (gnus-read-save-file-name + "Save %s in file" filename + gnus-file-save-name gnus-newsgroup-name + gnus-current-headers nil 'gnus-newsgroup-last-directory)) + (gnus-summary-save-in-file filename t)) -(defun gnus-summary-save-body-in-file (&optional filename) +(put 'gnus-summary-save-body-in-file :decode t) +(defun gnus-summary-save-body-in-file (&optional filename overwrite) "Append this article body to a file. Optional argument FILENAME specifies file name. The directory to save in defaults to `gnus-article-save-directory'." @@ -3613,9 +3773,25 @@ The directory to save in defaults to `gnus-article-save-directory'." (widen) (when (article-goto-body) (narrow-to-region (point) (point-max))) + (when (and overwrite + (file-exists-p filename)) + (delete-file filename)) (gnus-output-to-file filename)))) filename) +(put 'gnus-summary-write-body-to-file :decode t) +(put 'gnus-summary-write-body-to-file + :function 'gnus-summary-save-body-in-file) +(defun gnus-summary-write-body-to-file (&optional filename) + "Write this article body to a file, overwriting it if the file exists. +Optional argument FILENAME specifies file name. +The directory to save in defaults to `gnus-article-save-directory'." + (setq filename (gnus-read-save-file-name + "Save %s body in file" filename + gnus-file-save-name gnus-newsgroup-name + gnus-current-headers nil 'gnus-newsgroup-last-directory)) + (gnus-summary-save-body-in-file filename t)) + (defun gnus-summary-save-in-pipe (&optional command) "Pipe this article to subprocess." (setq command @@ -3977,6 +4153,7 @@ commands: ;; Prevent recent Emacsen from displaying non-break space as "\ ". (set (make-local-variable 'nobreak-char-display) nil) (setq cursor-in-non-selected-windows nil) + (setq truncate-lines gnus-article-truncate-lines) (gnus-set-default-directory) (buffer-disable-undo) (setq buffer-read-only t @@ -3996,10 +4173,9 @@ commands: (setq gnus-article-buffer name) (setq gnus-original-article-buffer original) (setq gnus-article-mime-handle-alist nil) - ;; This might be a variable local to the summary buffer. - (unless gnus-single-article-buffer - (save-excursion - (set-buffer gnus-summary-buffer) + (with-current-buffer gnus-summary-buffer + ;; This might be a variable local to the summary buffer. + (unless gnus-single-article-buffer (setq gnus-article-buffer name) (setq gnus-original-article-buffer original) (gnus-set-global-variables))) @@ -4251,7 +4427,7 @@ General format specifiers can also be used. See Info node gnus-mime-button-menu gnus-mime-button-map "MIME button menu." `("MIME Part" ,@(mapcar (lambda (c) - (vector (caddr c) (car c) :enable t)) + (vector (caddr c) (car c) :active t)) gnus-mime-button-commands))) (defun gnus-mime-button-menu (event prefix) @@ -4429,9 +4605,8 @@ Deleting parts may malfunction or destroy the article; continue? ")) (handles gnus-article-mime-handles) (none "(none)") (description - (or - (mail-decode-encoded-word-string (or (mm-handle-description data) - none)))) + (mail-decode-encoded-word-string (or (mm-handle-description data) + none))) (filename (or (mail-content-type-get (mm-handle-disposition data) 'filename) none)) @@ -4497,8 +4672,10 @@ Deleting parts may malfunction or destroy the article; continue? ")) (def-type (and name (mm-default-file-encoding name)))) (and def-type (cons def-type 0)))) -(defun gnus-mime-view-part-as-type (&optional mime-type) - "Choose a MIME media type, and view the part as such." +(defun gnus-mime-view-part-as-type (&optional mime-type pred) + "Choose a MIME media type, and view the part as such. +If non-nil, PRED is a predicate to use during completion to limit the +available media-types." (interactive) (unless mime-type (setq mime-type @@ -4507,7 +4684,7 @@ Deleting parts may malfunction or destroy the article; continue? ")) (format "View as MIME type (default %s): " (car default)) (mapcar #'list (mailcap-mime-types)) - nil nil nil nil + pred nil nil nil (car default))))) (gnus-article-check-buffer) (let ((handle (get-text-property (point) 'gnus-data))) @@ -4707,12 +4884,18 @@ specified charset." (mm-inlined-types nil) (mail-parse-charset gnus-newsgroup-charset) (mail-parse-ignored-charsets - (with-current-buffer gnus-summary-buffer - gnus-newsgroup-ignored-charsets))) - (when handle - (if (mm-handle-undisplayer handle) - (mm-remove-part handle) - (mm-display-part handle))))) + (with-current-buffer gnus-summary-buffer + gnus-newsgroup-ignored-charsets)) + (type (mm-handle-media-type handle)) + (method (mailcap-mime-info type)) + (mm-enable-external t)) + (if (not (stringp method)) + (gnus-mime-view-part-as-type + nil (lambda (type) (stringp (mailcap-mime-info type)))) + (when handle + (if (mm-handle-undisplayer handle) + (mm-remove-part handle) + (mm-display-part handle)))))) (defun gnus-mime-view-part-internally (&optional handle) "View the MIME part under point with an internal viewer. @@ -4727,10 +4910,13 @@ If no internal viewer is available, use an external viewer." (with-current-buffer gnus-summary-buffer gnus-newsgroup-ignored-charsets)) (inhibit-read-only t)) - (when handle - (if (mm-handle-undisplayer handle) - (mm-remove-part handle) - (mm-display-part handle))))) + (if (not (mm-inlinable-p handle)) + (gnus-mime-view-part-as-type + nil (lambda (type) (mm-inlinable-p handle type))) + (when handle + (if (mm-handle-undisplayer handle) + (mm-remove-part handle) + (mm-display-part handle)))))) (defun gnus-mime-action-on-part (&optional action) "Do something with the MIME attachment at \(point\)." @@ -5076,7 +5262,11 @@ N is the numerical prefix." (article-goto-body) (narrow-to-region (point-min) (point)) (gnus-article-save-original-date - (gnus-treat-article 'head))))))))) + (gnus-treat-article 'head))))))) + ;; Cope with broken MIME messages. + (goto-char (point-max)) + (unless (bolp) + (insert "\n")))) (defcustom gnus-mime-display-multipart-as-mixed nil "Display \"multipart\" parts as \"multipart/mixed\". @@ -5436,17 +5626,55 @@ Provided for backwards compatibility." ;;; Article savers. (defun gnus-output-to-file (file-name) - "Append the current article to a file named FILE-NAME." - (let ((artbuf (current-buffer))) + "Append the current article to a file named FILE-NAME. +If `gnus-article-save-coding-system' is non-nil, it is used to encode +text and used as the value of the coding cookie which is added to the +top of a file. Otherwise, this function saves a raw article without +the coding cookie." + (let* ((artbuf (current-buffer)) + (file-name-coding-system nnmail-pathname-coding-system) + (coding gnus-article-save-coding-system) + (coding-system-for-read (if coding + nil ;; Rely on the coding cookie. + mm-text-coding-system)) + (coding-system-for-write (or coding + mm-text-coding-system-for-write + mm-text-coding-system)) + (exists (file-exists-p file-name))) (with-temp-buffer + (when exists + (insert-file-contents file-name) + (goto-char (point-min)) + ;; Remove the existing coding cookie. + (when (looking-at "X-Gnus-Coding-System: .+\n\n") + (delete-region (match-beginning 0) (match-end 0)))) + (goto-char (point-max)) (insert-buffer-substring artbuf) ;; Append newline at end of the buffer as separator, and then ;; save it to file. (goto-char (point-max)) (insert "\n") - (let ((file-name-coding-system nnmail-pathname-coding-system)) - (mm-append-to-file (point-min) (point-max) file-name)) - t))) + (when coding + ;; If the coding system is not suitable to encode the text, + ;; ask a user for a proper one. + (when (fboundp 'select-safe-coding-system) + (setq coding (coding-system-base + (save-window-excursion + (select-safe-coding-system (point-min) (point-max) + coding)))) + (setq coding-system-for-write + (or (cdr (assq coding '((mule-utf-8 . utf-8)))) + coding))) + (goto-char (point-min)) + ;; Add the coding cookie. + (insert (format "X-Gnus-Coding-System: -*- coding: %s; -*-\n\n" + coding-system-for-write))) + (if exists + (progn + (write-region (point-min) (point-max) file-name nil 'no-message) + (message "Appended to %s" file-name)) + (write-region (point-min) (point-max) file-name)))) + t) (defun gnus-narrow-to-page (&optional arg) "Narrow the article buffer to a page. @@ -6492,7 +6720,10 @@ address, `ask' if unsure and `invalid' if the string is invalid." "Call function FUN on argument ARG. Both FUN and ARG are supposed to be strings. ARG will be passed as a symbol to FUN." - (funcall (intern fun) (intern arg))) + (funcall (intern fun) + (if (string-match "^customize-apropos" fun) + arg + (intern arg)))) (defvar gnus-button-handle-describe-prefix "^\\(C-h\\|?\\)") @@ -6691,7 +6922,7 @@ positives are possible." 1 (>= gnus-button-emacs-level 8) gnus-button-handle-library 1) ("`\\([a-z][-a-z0-9]+\\.el\\)'" 1 (>= gnus-button-emacs-level 8) gnus-button-handle-library 1) - ("`\\([a-z][a-z0-9]+-[a-z]+-[-a-z]+\\|\\(gnus\\|message\\)-[-a-z]+\\)'" + ("`\\([a-z][a-z0-9]+-[a-z0-9]+-[-a-z0-9]*[a-z]\\|\\(gnus\\|message\\)-[-a-z]+\\)'" 0 (>= gnus-button-emacs-level 8) gnus-button-handle-symbol 1) ("`\\([a-z][a-z0-9]+-[a-z]+\\)'" 0 (>= gnus-button-emacs-level 9) gnus-button-handle-symbol 1) @@ -7568,7 +7799,7 @@ For example: ,@(delq nil (mapcar (lambda (c) (unless (eq (car c) 'undefined) - (vector (caddr c) (car c) :enable t))) + (vector (caddr c) (car c) :active t))) gnus-mime-security-button-commands)))) (defun gnus-mime-security-button-menu (event prefix)