;;; gnus-sum.el --- summary mode commands for Gnus
;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
-;; 2005, 2006 Free Software Foundation, Inc.
+;; 2005, 2006, 2007 Free Software Foundation, Inc.
;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
;; Keywords: news
:group 'gnus-summary-exit
:type 'boolean)
+(defcustom gnus-summary-next-group-on-exit t
+ "If non-nil, go to the next unread newsgroup on summary exit.
+See `gnus-group-goto-unread'."
+ :link '(custom-manual "(gnus)Group Maneuvering")
+ :group 'gnus-summary-exit
+ :version "23.0" ;; No Gnus
+ :type 'boolean)
+
(defcustom gnus-fetch-old-headers nil
"*Non-nil means that Gnus will try to build threads by grabbing old headers.
If an unread article in the group refers to an older, already
:type 'boolean)
(defcustom gnus-auto-select-first t
- "*If non-nil, select the article under point.
-Which article this is is controlled by the `gnus-auto-select-subject'
-variable.
+ "If non-nil, select an article on group entry.
+An article is selected automatically when entering a group
+e.g. with \\<gnus-group-mode-map>\\[gnus-group-read-group], or via `gnus-summary-next-page' or
+`gnus-summary-catchup-and-goto-next-group'.
+
+Which article is selected is controlled by the variable
+`gnus-auto-select-subject'.
If you want to prevent automatic selection of articles in some
newsgroups, set the variable to nil in `gnus-select-group-hook'."
+ ;; Commands include...
+ ;; \\<gnus-group-mode-map>\\[gnus-group-read-group]
+ ;; \\<gnus-summary-mode-map>\\[gnus-summary-next-page]
+ ;; \\<gnus-summary-mode-map>\\[gnus-summary-catchup-and-goto-next-group]
:group 'gnus-group-select
:type '(choice (const :tag "none" nil)
(sexp :menu-tag "first" t)))
:group 'gnus-summary-maneuvering
:type 'boolean)
+(defcustom gnus-auto-select-on-ephemeral-exit 'next-noselect
+ "What article should be selected after exiting an ephemeral group.
+Valid values include:
+
+`next'
+ Select the next article.
+`next-unread'
+ Select the next unread article.
+`next-noselect'
+ Move the cursor to the next article. This is the default.
+`next-unread-noselect'
+ Move the cursor to the next unread article.
+
+If it has any other value or there is no next (unread) article, the
+article selected before entering to the ephemeral group will appear."
+ :version "23.0" ;; No Gnus
+ :group 'gnus-summary-maneuvering
+ :type '(choice :format "%{%t%}:\n %[Value Menu%] %v"
+ (const next) (const next-unread)
+ (const next-noselect) (const next-unread-noselect)
+ (sexp :tag "other" :value nil)))
+
(defcustom gnus-auto-goto-ignores 'unfetched
"*Says how to handle unfetched articles when maneuvering.
. gnus-summary-normal-read))
"*Controls the highlighting of summary buffer lines.
-A list of (FORM . FACE) pairs. When deciding how a a particular
+A list of (FORM . FACE) pairs. When deciding how a particular
summary line should be displayed, each form is evaluated. The content
of the face field after the first true form is used. You can change
how those summary lines are displayed, by editing the face field.
You can use the following variables in the FORM field.
-score: The article's score
+score: The article's score.
default: The default article score.
default-high: The default score for high scored articles.
default-low: The default score for low scored articles.
(and user-mail-address
(not (string= user-mail-address ""))
(regexp-quote user-mail-address))
- "*Regexp of From headers that may be suppressed in favor of To headers."
+ "*From headers that may be suppressed in favor of To headers.
+This can be a regexp or a list of regexps."
:version "21.1"
:group 'gnus-summary
- :type 'regexp)
+ :type '(choice regexp
+ (repeat :tag "Regexp List" regexp)))
+
+(defsubst gnus-ignored-from-addresses ()
+ (gmm-regexp-concat gnus-ignored-from-addresses))
(defcustom gnus-summary-to-prefix "-> "
"*String prefixed to the To field in the summary line when
((eq gnus-summary-gather-subject-limit 'fuzzy)
(gnus-simplify-subject-fuzzy subject))
((numberp gnus-summary-gather-subject-limit)
- (gnus-limit-string (gnus-simplify-subject-re subject)
- gnus-summary-gather-subject-limit))
+ (truncate-string-to-width (gnus-simplify-subject-re subject)
+ gnus-summary-gather-subject-limit))
(t
subject)))
"C" gnus-summary-limit-mark-excluded-as-read
"o" gnus-summary-insert-old-articles
"N" gnus-summary-insert-new-articles
+ "S" gnus-summary-limit-to-singletons
"r" gnus-summary-limit-to-replied
- "R" gnus-summary-limit-to-recipient)
+ "R" gnus-summary-limit-to-recipient
+ "A" gnus-summary-limit-to-address)
(gnus-define-keys (gnus-summary-goto-map "G" gnus-summary-mode-map)
"n" gnus-summary-next-unread-article
["Subject..." gnus-summary-limit-to-subject t]
["Author..." gnus-summary-limit-to-author t]
["Recipient..." gnus-summary-limit-to-recipient t]
+ ["Address..." gnus-summary-limit-to-address t]
["Age..." gnus-summary-limit-to-age t]
["Extra..." gnus-summary-limit-to-extra t]
["Score..." gnus-summary-limit-to-score t]
["Display Predicate" gnus-summary-limit-to-display-predicate t]
["Unread" gnus-summary-limit-to-unread t]
["Unseen" gnus-summary-limit-to-unseen t]
+ ["Singletons" gnus-summary-limit-to-singletons t]
["Replied" gnus-summary-limit-to-replied t]
["Non-dormant" gnus-summary-limit-exclude-dormant t]
["Next or process marked articles" gnus-summary-limit-to-articles t]
(defun gnus-summary-from-or-to-or-newsgroups (header gnus-tmp-from)
(let ((mail-parse-charset gnus-newsgroup-charset)
+ (ignored-from-addresses (gnus-ignored-from-addresses))
; Is it really necessary to do this next part for each summary line?
; Luckily, doesn't seem to slow things down much.
(mail-parse-ignored-charsets
(with-current-buffer gnus-summary-buffer
gnus-newsgroup-ignored-charsets)))
(or
- (and gnus-ignored-from-addresses
- (string-match gnus-ignored-from-addresses gnus-tmp-from)
+ (and ignored-from-addresses
+ (string-match ignored-from-addresses gnus-tmp-from)
(let ((extra-headers (mail-header-extra header))
to
newsgroups)
(read-string
(format
"How many articles from %s (%s %d): "
- (gnus-limit-string
- (gnus-group-decoded-name gnus-newsgroup-name)
- 35)
+ (gnus-group-decoded-name gnus-newsgroup-name)
(if initial "max" "default")
number)
(if initial
(gnus-group-jump-to-group group))
(gnus-run-hooks 'gnus-summary-exit-hook)
(unless (or quit-config
+ (not gnus-summary-next-group-on-exit)
;; If this group has disappeared from the summary
;; buffer, don't skip forwards.
(not (string= group (gnus-group-group-name))))
(gnus-configure-windows (cdr quit-config) 'force))
(gnus-configure-windows (cdr quit-config) 'force))
(when (eq major-mode 'gnus-summary-mode)
+ (if (memq gnus-auto-select-on-ephemeral-exit '(next-noselect
+ next-unread-noselect))
+ (when (zerop (cond ((eq gnus-auto-select-on-ephemeral-exit
+ 'next-noselect)
+ (gnus-summary-next-subject 1 nil t))
+ ((eq gnus-auto-select-on-ephemeral-exit
+ 'next-unread-noselect)
+ (gnus-summary-next-subject 1 t t))))
+ ;; Hide the article buffer which displays the article different
+ ;; from the one that the cursor points to in the summary buffer.
+ (gnus-configure-windows 'summary 'force))
+ (cond ((eq gnus-auto-select-on-ephemeral-exit 'next)
+ (gnus-summary-next-subject 1))
+ ((eq gnus-auto-select-on-ephemeral-exit 'next-unread)
+ (gnus-summary-next-subject 1 t))))
(gnus-summary-recenter)
(gnus-summary-position-point))))
(gnus-summary-limit articles))
(gnus-summary-position-point))))
+(defun gnus-summary-limit-to-address (address &optional not-matching)
+ "Limit the summary buffer to articles with the given ADDRESS.
+
+If NOT-MATCHING, exclude ADDRESS.
+
+To, Cc and From headers are checked. You need to include `To' and `Cc'
+in `nnmail-extra-headers'."
+ (interactive
+ (list (read-string (format "%s address (regexp): "
+ (if current-prefix-arg "Exclude" "Limit to")))
+ current-prefix-arg))
+ (when (not (equal "" address))
+ (prog1 (let* ((to
+ (if (memq 'To nnmail-extra-headers)
+ (gnus-summary-find-matching
+ (cons 'extra 'To) address 'all nil nil
+ not-matching)
+ (gnus-message
+ 1 "`To' isn't present in `nnmail-extra-headers'")
+ (sit-for 1)
+ t))
+ (cc
+ (if (memq 'Cc nnmail-extra-headers)
+ (gnus-summary-find-matching
+ (cons 'extra 'Cc) address 'all nil nil
+ not-matching)
+ (gnus-message
+ 1 "`Cc' isn't present in `nnmail-extra-headers'")
+ (sit-for 1)
+ t))
+ (from
+ (gnus-summary-find-matching "from" address
+ 'all nil nil not-matching))
+ (articles
+ (if not-matching
+ ;; We need the numbers that are in all lists:
+ (if (eq cc t)
+ (if (eq to t)
+ from
+ (mapcar (lambda (a) (car (memq a from))) to))
+ (if (eq to t)
+ (mapcar (lambda (a) (car (memq a from))) cc)
+ (mapcar (lambda (a) (car (memq a from)))
+ (mapcar (lambda (a) (car (memq a to)))
+ cc))))
+ (nconc (if (eq to t) nil to)
+ (if (eq cc t) nil cc)
+ from))))
+ (unless articles
+ (error "Found no matches for \"%s\"" address))
+ (gnus-summary-limit articles))
+ (gnus-summary-position-point))))
+
(defun gnus-summary-limit-strange-charsets-predicate (header)
(let ((string (concat (mail-header-subject header)
(mail-header-from header)))
(gnus-summary-limit articles)))
(gnus-summary-position-point))
+(defun gnus-summary-limit-to-singletons (&optional threadsp)
+ "Limit the summary buffer to articles that aren't part on any thread.
+If THREADSP (the prefix), limit to articles that are in threads."
+ (interactive "P")
+ (let ((articles nil)
+ thread-articles
+ threads)
+ (dolist (thread gnus-newsgroup-threads)
+ (if (stringp (car thread))
+ (dolist (thread (cdr thread))
+ (push thread threads))
+ (push thread threads)))
+ (dolist (thread threads)
+ (setq thread-articles (gnus-articles-in-thread thread))
+ (when (or (and threadsp
+ (> (length thread-articles) 1))
+ (and (not threadsp)
+ (= (length thread-articles) 1)))
+ (setq articles (nconc thread-articles articles))))
+ (if (not articles)
+ (message "No messages matched")
+ (gnus-summary-limit articles))
+ (gnus-summary-position-point)))
+
(defun gnus-summary-limit-to-replied (&optional unreplied)
"Limit the summary buffer to replied articles.
If UNREPLIED (the prefix), limit to unreplied articles."
(crosspost "Crosspost" "Crossposting")))
(copy-buf (save-excursion
(nnheader-set-temp-buffer " *copy article*")))
- art-group to-method new-xref article to-groups articles-to-update-marks)
+ art-group to-method new-xref article to-groups
+ articles-to-update-marks encoded)
(unless (assq action names)
(error "Unknown action %s" action))
;; Read the newsgroup name.
(gnus-article-prepare-hook nil)
(gnus-mark-article-hook nil))
(gnus-summary-select-article nil nil nil (car articles))))
- (setq to-newsgroup
- (gnus-read-move-group-name
- (cadr (assq action names))
- (symbol-value (intern (format "gnus-current-%s-group" action)))
- articles prefix))
- (set (intern (format "gnus-current-%s-group" action)) to-newsgroup))
- (setq to-method (or select-method
- (gnus-server-to-method
- (gnus-group-method to-newsgroup))))
+ (setq to-newsgroup (gnus-read-move-group-name
+ (cadr (assq action names))
+ (symbol-value
+ (intern (format "gnus-current-%s-group" action)))
+ articles prefix)
+ encoded to-newsgroup
+ to-method (gnus-server-to-method (gnus-group-method to-newsgroup)))
+ (set (intern (format "gnus-current-%s-group" action))
+ (mm-decode-coding-string
+ to-newsgroup
+ (gnus-group-name-charset to-method to-newsgroup))))
+ (unless to-method
+ (setq to-method (or select-method
+ (gnus-server-to-method
+ (gnus-group-method to-newsgroup)))))
+ (setq to-newsgroup (or encoded
+ (mm-encode-coding-string
+ to-newsgroup
+ (gnus-group-name-charset to-method to-newsgroup))))
;; Check the method we are to move this article to...
(unless (gnus-check-backend-function
'request-accept-article (car to-method))
(error "Can't open server %s" (car to-method)))
(gnus-message 6 "%s to %s: %s..."
(caddr (assq action names))
- (or (car select-method) to-newsgroup) articles)
+ (or (car select-method)
+ (gnus-group-decoded-name to-newsgroup))
+ articles)
(while articles
(setq article (pop articles))
(setq
(message-options message-options)
(message-options-set-recipient)
(mail-parse-ignored-charsets
- ',gnus-newsgroup-ignored-charsets))
+ ',gnus-newsgroup-ignored-charsets)
+ (rfc2047-header-encoding-alist
+ ',(let ((charset (gnus-group-name-charset
+ (gnus-find-method-for-group
+ gnus-newsgroup-name)
+ gnus-newsgroup-name)))
+ (append (list (cons "Newsgroups" charset)
+ (cons "Followup-To" charset)
+ (cons "Xref" charset))
+ rfc2047-header-encoding-alist))))
,(if (not raw) '(progn
(mml-to-mime)
(mml-destroy-buffers)
(gnus-sorted-nunion
(gnus-sorted-intersection gnus-newsgroup-unreads
gnus-newsgroup-downloadable)
- gnus-newsgroup-unfetched)))
+ (gnus-sorted-difference gnus-newsgroup-unfetched
+ gnus-newsgroup-cached))))
;; We actually mark all articles as canceled, which we
;; have to do when using auto-expiry or adaptive scoring.
(gnus-summary-show-all-threads)
(defun gnus-summary-reparent-children (parent children)
"Make PARENT the parent of CHILDREN.
-When called interactively, PARENT is is current article and
-CHILDREN are the process-marked articles."
+When called interactively, PARENT is the current article and CHILDREN
+are the process-marked articles."
(interactive
(list (gnus-summary-article-number)
(gnus-summary-work-articles nil)))
(mapcar 'list (nreverse split-name))
nil nil nil
'gnus-group-history))))
- (to-method (gnus-server-to-method (gnus-group-method to-newsgroup))))
+ (to-method (gnus-server-to-method (gnus-group-method to-newsgroup)))
+ encoded)
(when to-newsgroup
(if (or (string= to-newsgroup "")
(string= to-newsgroup prefix))
(setq to-newsgroup default))
(unless to-newsgroup
(error "No group name entered"))
- (or (gnus-active to-newsgroup)
- (gnus-activate-group to-newsgroup nil nil to-method)
+ (setq encoded (mm-encode-coding-string
+ to-newsgroup
+ (gnus-group-name-charset to-method to-newsgroup)))
+ (or (gnus-active encoded)
+ (gnus-activate-group encoded nil nil to-method)
(if (gnus-y-or-n-p (format "No such group: %s. Create it? "
to-newsgroup))
- (or (and (gnus-request-create-group to-newsgroup to-method)
- (gnus-activate-group
- to-newsgroup nil nil to-method)
- (gnus-subscribe-group to-newsgroup))
+ (or (and (gnus-request-create-group encoded to-method)
+ (gnus-activate-group encoded nil nil to-method)
+ (gnus-subscribe-group encoded))
(error "Couldn't create group %s" to-newsgroup)))
- (error "No such group: %s" to-newsgroup)))
- to-newsgroup))
+ (error "No such group: %s" to-newsgroup))
+ encoded)))
(defvar gnus-summary-save-parts-counter)
(read-string
(format
"How many articles from %s (%s %d): "
- (gnus-limit-string
- (gnus-group-decoded-name gnus-newsgroup-name) 35)
+ (gnus-group-decoded-name gnus-newsgroup-name)
(if initial "max" "default")
len)
(if initial