;; 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,
:group 'gnus-summary-visual
:type '(repeat (cons (sexp :tag "Form" nil)
face)))
+(put 'gnus-summary-highlight 'risky-local-variable t)
(defcustom gnus-alter-header-function nil
"Function called to allow alteration of article header structures.
:type '(repeat symbol)
:group 'gnus-charset)
+(defcustom gnus-newsgroup-maximum-articles nil
+ "The maximum number of articles a newsgroup.
+If this is a number, old articles in a newsgroup exceeding this number
+are silently ignored. If it is nil, no article is ignored. Note that
+setting this variable to a number might prevent you from reading very
+old articles."
+ :group 'gnus-group-select
+ :version "22.2"
+ :type '(choice (const :tag "No limit" nil)
+ integer))
+
(gnus-define-group-parameter
ignored-charsets
:type list
(eq gnus-newsgroup-name
(car gnus-decode-encoded-word-methods-cache)))
(setq gnus-decode-encoded-word-methods-cache (list gnus-newsgroup-name))
- (mapcar (lambda (x)
- (if (symbolp x)
- (nconc gnus-decode-encoded-word-methods-cache (list x))
- (if (and gnus-newsgroup-name
- (string-match (car x) gnus-newsgroup-name))
- (nconc gnus-decode-encoded-word-methods-cache
- (list (cdr x))))))
- gnus-decode-encoded-word-methods))
- (let ((xlist gnus-decode-encoded-word-methods-cache))
- (pop xlist)
- (while xlist
- (setq string (funcall (pop xlist) string))))
- string)
+ (dolist (method gnus-decode-encoded-word-methods)
+ (if (symbolp method)
+ (nconc gnus-decode-encoded-word-methods-cache (list method))
+ (if (and gnus-newsgroup-name
+ (string-match (car method) gnus-newsgroup-name))
+ (nconc gnus-decode-encoded-word-methods-cache
+ (list (cdr method)))))))
+ (dolist (method (cdr gnus-decode-encoded-word-methods-cache) string)
+ (setq string (funcall method string))))
;; Subject simplification.
(setq modified-tick (buffer-modified-tick))
(cond
((listp gnus-simplify-subject-fuzzy-regexp)
- (mapcar 'gnus-simplify-buffer-fuzzy-step
- gnus-simplify-subject-fuzzy-regexp))
+ (mapc 'gnus-simplify-buffer-fuzzy-step
+ gnus-simplify-subject-fuzzy-regexp))
(gnus-simplify-subject-fuzzy-regexp
(gnus-simplify-buffer-fuzzy-step gnus-simplify-subject-fuzzy-regexp)))
(gnus-simplify-buffer-fuzzy-step "^ *\\[[-+?*!][-+?*!]\\] *")
(gnus-define-keys (gnus-summary-thread-map "T" gnus-summary-mode-map)
"k" gnus-summary-kill-thread
+ "E" gnus-summary-expire-thread
"l" gnus-summary-lower-thread
"i" gnus-summary-raise-thread
"T" gnus-summary-toggle-threads
"g" gnus-summary-show-article
"s" gnus-summary-isearch-article
"P" gnus-summary-print-article
+ "S" gnus-sticky-article
"M" gnus-mailing-list-insinuate
"t" gnus-article-babel)
"O" gnus-uu-decode-save
"b" gnus-uu-decode-binhex
"B" gnus-uu-decode-binhex
+ "Y" gnus-uu-decode-yenc
"p" gnus-uu-decode-postscript
"P" gnus-uu-decode-postscript-and-save)
["Remove article" gnus-cache-remove-article t])
["Translate" gnus-article-babel t]
["Select article buffer" gnus-summary-select-article-buffer t]
+ ["Make article buffer sticky" gnus-sticky-article t]
["Enter digest buffer" gnus-summary-enter-digest-group t]
["Isearch article..." gnus-summary-isearch-article t]
["Beginning of the article" gnus-summary-beginning-of-article t]
["Go up thread" gnus-summary-up-thread t]
["Top of thread" gnus-summary-top-thread t]
["Mark thread as read" gnus-summary-kill-thread t]
+ ["Mark thread as expired" gnus-summary-expire-thread t]
["Lower thread score" gnus-summary-lower-thread t]
["Raise thread score" gnus-summary-raise-thread t]
["Rethread current" gnus-summary-rethread-current t]))
(erase-buffer)))
(kill-buffer (current-buffer)))
;; Sort over trustworthiness.
- (mapcar
- (lambda (relation)
- (when (gnus-dependencies-add-header
- (make-full-mail-header
- gnus-reffed-article-number
- (nth 3 relation) "" (or (nth 4 relation) "")
- (nth 1 relation)
- (or (nth 2 relation) "") 0 0 "")
- gnus-newsgroup-dependencies nil)
- (push gnus-reffed-article-number gnus-newsgroup-limit)
- (push gnus-reffed-article-number gnus-newsgroup-sparse)
- (push (cons gnus-reffed-article-number gnus-sparse-mark)
- gnus-newsgroup-reads)
- (decf gnus-reffed-article-number)))
- (sort relations 'car-less-than-car))
+ (dolist (relation (sort relations 'car-less-than-car))
+ (when (gnus-dependencies-add-header
+ (make-full-mail-header
+ gnus-reffed-article-number
+ (nth 3 relation) "" (or (nth 4 relation) "")
+ (nth 1 relation)
+ (or (nth 2 relation) "") 0 0 "")
+ gnus-newsgroup-dependencies nil)
+ (push gnus-reffed-article-number gnus-newsgroup-limit)
+ (push gnus-reffed-article-number gnus-newsgroup-sparse)
+ (push (cons gnus-reffed-article-number gnus-sparse-mark)
+ gnus-newsgroup-reads)
+ (decf gnus-reffed-article-number)))
(gnus-message 7 "Making sparse threads...done")))
(defun gnus-build-old-threads ()
(defsubst gnus-article-sort-by-author (h1 h2)
"Sort articles by root author."
- (string-lessp
+ (gnus-string<
(let ((extract (funcall
gnus-extract-address-components
(mail-header-from h1))))
(defsubst gnus-article-sort-by-recipient (h1 h2)
"Sort articles by recipient."
- (string-lessp
+ (gnus-string<
(let ((extract (funcall
gnus-extract-address-components
(or (cdr (assq 'To (mail-header-extra h1))) ""))))
(defsubst gnus-article-sort-by-subject (h1 h2)
"Sort articles by root subject."
- (string-lessp
+ (gnus-string<
(downcase (gnus-simplify-subject-re (mail-header-subject h1)))
(downcase (gnus-simplify-subject-re (mail-header-subject h2)))))
t
gnus-summary-ignore-duplicates))
(info (nth 2 entry))
- articles fetched-articles cached)
+ charset articles fetched-articles cached)
(unless (gnus-check-server
(set (make-local-variable 'gnus-current-select-method)
(gnus-find-method-for-group group)))
(error "Couldn't open server"))
+ (setq charset (gnus-group-name-charset gnus-current-select-method group))
(or (and entry (not (eq (car entry) t))) ; Either it's active...
(gnus-activate-group group) ; Or we can activate it...
(progn ; Or we bug out.
(when (equal major-mode 'gnus-summary-mode)
(gnus-kill-buffer (current-buffer)))
- (error "Couldn't activate group %s: %s"
- (gnus-group-decoded-name group) (gnus-status-message group))))
+ (error
+ "Couldn't activate group %s: %s"
+ (mm-decode-coding-string group charset)
+ (mm-decode-coding-string (gnus-status-message group) charset))))
(unless (gnus-request-group group t)
- (when (equal major-mode 'gnus-summary-mode)
- (gnus-kill-buffer (current-buffer)))
- (error "Couldn't request group %s: %s"
- (gnus-group-decoded-name group) (gnus-status-message group)))
+ (when (equal major-mode 'gnus-summary-mode)
+ (gnus-kill-buffer (current-buffer)))
+ (error "Couldn't request group %s: %s"
+ (mm-decode-coding-string group charset)
+ (mm-decode-coding-string (gnus-status-message group) charset)))
(when gnus-agent
(gnus-agent-possibly-alter-active group (gnus-active group) info)
;; articles in the group, or (if that's nil), the
;; articles in the cache.
(or
- (gnus-uncompress-range (gnus-active group))
+ (if gnus-newsgroup-maximum-articles
+ (let ((active (gnus-active group)))
+ (gnus-uncompress-range
+ (cons (max (car active)
+ (- (cdr active)
+ gnus-newsgroup-maximum-articles
+ -1))
+ (cdr active))))
+ (gnus-uncompress-range (gnus-active group)))
(gnus-cache-articles-in-group group))
;; Select only the "normal" subset of articles.
(gnus-sorted-nunion
(active (or (gnus-active group) (gnus-activate-group group)))
(last (or (cdr active)
(error "Group %s couldn't be activated " group)))
+ (bottom (if gnus-newsgroup-maximum-articles
+ (max (car active)
+ (- last gnus-newsgroup-maximum-articles -1))
+ (car active)))
first nlast unread)
;; If none are read, then all are unread.
(if (not read)
- (setq first (car active))
+ (setq first bottom)
;; If the range of read articles is a single range, then the
;; first unread article is the article after the last read
;; article. Sounds logical, doesn't it?
(if (and (not (listp (cdr read)))
- (or (< (car read) (car active))
+ (or (< (car read) bottom)
(progn (setq read (list read))
nil)))
- (setq first (max (car active) (1+ (cdr read))))
+ (setq first (max bottom (1+ (cdr read))))
;; `read' is a list of ranges.
(when (/= (setq nlast (or (and (numberp (car read)) (car read))
(caar read)))
1)
- (setq first (car active)))
+ (setq first bottom))
(while read
(when first
(while (< first nlast)
(gnus-list-range-difference
(gnus-list-range-difference
(gnus-sorted-complement
- (gnus-uncompress-range active)
+ (gnus-uncompress-range
+ (if gnus-newsgroup-maximum-articles
+ (cons (max (car active)
+ (- (cdr active)
+ gnus-newsgroup-maximum-articles
+ -1))
+ (cdr active))
+ active))
(gnus-list-of-unread-articles group))
(cdr (assq 'dormant marked)))
(cdr (assq 'tick marked))))))
(let* ((read (gnus-info-read (gnus-get-info group)))
(active (or (gnus-active group) (gnus-activate-group group)))
(last (cdr active))
+ (bottom (if gnus-newsgroup-maximum-articles
+ (max (car active)
+ (- last gnus-newsgroup-maximum-articles -1))
+ (car active)))
first nlast unread)
;; If none are read, then all are unread.
(if (not read)
- (setq first (car active))
+ (setq first bottom)
;; If the range of read articles is a single range, then the
;; first unread article is the article after the last read
;; article. Sounds logical, doesn't it?
(if (and (not (listp (cdr read)))
- (or (< (car read) (car active))
+ (or (< (car read) bottom)
(progn (setq read (list read))
nil)))
- (setq first (max (car active) (1+ (cdr read))))
+ (setq first (max bottom (1+ (cdr read))))
;; `read' is a list of ranges.
(when (/= (setq nlast (or (and (numberp (car read)) (car read))
(caar read)))
1)
- (setq first (car active)))
+ (setq first bottom))
(while read
(when first
(push (cons first nlast) unread))
(gnus-run-hooks 'gnus-summary-prepare-exit-hook)
;; If we have several article buffers, we kill them at exit.
(unless gnus-single-article-buffer
- (gnus-kill-buffer gnus-article-buffer)
- (gnus-kill-buffer gnus-original-article-buffer)
- (setq gnus-article-current nil))
+ (when (gnus-buffer-live-p gnus-article-buffer)
+ (with-current-buffer gnus-article-buffer
+ ;; Don't kill sticky article buffers
+ (unless (eq major-mode 'gnus-sticky-article-mode)
+ (gnus-kill-buffer gnus-article-buffer)
+ (setq gnus-article-current nil))))
+ (gnus-kill-buffer gnus-original-article-buffer))
(when gnus-use-cache
(gnus-cache-possibly-remove-articles)
(gnus-cache-save-buffers))
(setq group-point (point))
(if temporary
nil ;Nothing to do.
- ;; If we have several article buffers, we kill them at exit.
- (unless gnus-single-article-buffer
- (gnus-kill-buffer gnus-article-buffer)
- (gnus-kill-buffer gnus-original-article-buffer)
- (setq gnus-article-current nil))
(set-buffer buf)
(if (not gnus-kill-summary-on-exit)
(progn
(defun gnus-summary-display-article (article &optional all-header)
"Display ARTICLE in article buffer."
- (when (gnus-buffer-live-p gnus-article-buffer)
- (with-current-buffer gnus-article-buffer
- (mm-enable-multibyte)))
+ (unless (and (gnus-buffer-live-p gnus-article-buffer)
+ (with-current-buffer gnus-article-buffer
+ (eq major-mode 'gnus-article-mode)))
+ (gnus-article-setup-buffer))
(gnus-set-global-variables)
- (when (gnus-buffer-live-p gnus-article-buffer)
- (with-current-buffer gnus-article-buffer
- (setq gnus-article-charset gnus-newsgroup-charset)
- (setq gnus-article-ignored-charsets gnus-newsgroup-ignored-charsets)
- (mm-enable-multibyte)))
+ (with-current-buffer gnus-article-buffer
+ (setq gnus-article-charset gnus-newsgroup-charset)
+ (setq gnus-article-ignored-charsets gnus-newsgroup-ignored-charsets)
+ (mm-enable-multibyte))
(if (null article)
nil
(prog1
(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
+ (and to-newsgroup
+ (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
(gnus-dup-unsuppress-article article)
(let* ((from-method (gnus-find-method-for-group
gnus-newsgroup-name))
- (to-method (gnus-find-method-for-group
- to-newsgroup))
+ (to-method (or select-method
+ (gnus-find-method-for-group to-newsgroup)))
(move-is-internal (gnus-method-equal from-method to-method)))
(gnus-request-move-article
article ; Article to move
(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)
(goto-char (point-min))
(push gnus-newsgroup-limit gnus-newsgroup-limits)
(setq gnus-newsgroup-limit (copy-sequence gnus-newsgroup-limit))
- (mapcar (lambda (x) (push (mail-header-number x)
- gnus-newsgroup-limit))
- headers)
+ (dolist (x headers)
+ (push (mail-header-number x) gnus-newsgroup-limit))
(gnus-summary-prepare-unthreaded (nreverse headers))
(goto-char (point-min))
(gnus-summary-position-point)
(while (gnus-summary-go-up-thread))
(gnus-summary-article-number))
+(defun gnus-summary-expire-thread ()
+ "Mark articles under current thread as expired."
+ (interactive)
+ (gnus-summary-kill-thread 0))
+
(defun gnus-summary-kill-thread (&optional unmark)
"Mark articles under current thread as read.
If the prefix argument is positive, remove any kinds of marks.
+If the prefix argument is zero, mark thread as expired.
If the prefix argument is negative, tick articles instead."
(interactive "P")
(when unmark
(setq unmark (prefix-numeric-value unmark)))
- (let ((articles (gnus-summary-articles-in-thread)))
+ (let ((articles (gnus-summary-articles-in-thread))
+ (hide (or (null unmark) (= unmark 0))))
(save-excursion
;; Expand the thread.
(gnus-summary-show-thread)
(gnus-summary-mark-article-as-read gnus-killed-mark))
((> unmark 0)
(gnus-summary-mark-article-as-unread gnus-unread-mark))
+ ((= unmark 0)
+ (gnus-summary-mark-article-as-unread gnus-expirable-mark))
(t
(gnus-summary-mark-article-as-unread gnus-ticked-mark)))
(setq articles (cdr articles))))
- ;; Hide killed subtrees.
- (and (null unmark)
+ ;; Hide killed subtrees when hide is true.
+ (and hide
gnus-thread-hide-killed
(gnus-summary-hide-thread))
- ;; If marked as read, go to next unread subject.
- (when (null unmark)
+ ;; If hide is t, go to next unread subject.
+ (when hide
;; Go to next unread subject.
(gnus-summary-next-subject 1 t)))
(gnus-set-mode-line 'summary))
(format "these %d articles" (length articles))
"this article")))
(to-newsgroup
- (cond
- ((null split-name)
- (gnus-completing-read-with-default
- default prom
- gnus-active-hashtb
- 'gnus-valid-move-group-p
- nil prefix
- 'gnus-group-history))
- ((= 1 (length split-name))
- (gnus-completing-read-with-default
- (car split-name) prom
- gnus-active-hashtb
- 'gnus-valid-move-group-p
- nil nil
- 'gnus-group-history))
- (t
- (gnus-completing-read-with-default
- nil prom
- (mapcar 'list (nreverse split-name))
- nil nil nil
- 'gnus-group-history))))
- (to-method (gnus-server-to-method (gnus-group-method to-newsgroup))))
+ (let (active group)
+ (when (or (null split-name) (= 1 (length split-name)))
+ (setq active (gnus-make-hashtable (length gnus-active-hashtb)))
+ (mapatoms (lambda (symbol)
+ (setq group (symbol-name symbol))
+ (when (string-match "[^\000-\177]" group)
+ (setq group (gnus-group-decoded-name group)))
+ (set (intern group active) group))
+ gnus-active-hashtb))
+ (cond
+ ((null split-name)
+ (gnus-completing-read-with-default
+ default prom active 'gnus-valid-move-group-p nil prefix
+ 'gnus-group-history))
+ ((= 1 (length split-name))
+ (gnus-completing-read-with-default
+ (car split-name) prom active 'gnus-valid-move-group-p nil nil
+ 'gnus-group-history))
+ (t
+ (gnus-completing-read-with-default
+ nil prom (mapcar 'list (nreverse split-name)) nil nil nil
+ 'gnus-group-history)))))
+ (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)
(when gnus-suppress-duplicates
(gnus-dup-suppress-articles))
- ;; We might want to build some more threads first.
- (when (and gnus-fetch-old-headers
- (eq gnus-headers-retrieved-by 'nov))
- (if (eq gnus-fetch-old-headers 'invisible)
- (gnus-build-all-threads)
- (gnus-build-old-threads)))
+ (if (and gnus-fetch-old-headers
+ (eq gnus-headers-retrieved-by 'nov))
+ ;; We might want to build some more threads first.
+ (if (eq gnus-fetch-old-headers 'invisible)
+ (gnus-build-all-threads)
+ (gnus-build-old-threads))
+ ;; Mark the inserted articles that are unread as unread.
+ (setq gnus-newsgroup-unreads
+ (gnus-sorted-nunion
+ gnus-newsgroup-unreads
+ (gnus-sorted-nintersection
+ (gnus-list-of-unread-articles gnus-newsgroup-name)
+ articles)))
+ ;; Mark the inserted articles as selected so that the information
+ ;; of the marks having been changed by a user may be updated when
+ ;; exiting this group. See `gnus-summary-update-info'.
+ (dolist (art articles)
+ (setq gnus-newsgroup-unselected (delq art gnus-newsgroup-unselected))))
;; Let the Gnus agent mark articles as read.
(when gnus-agent
(gnus-agent-get-undownloaded-list))