+2004-01-22 Jesper Harder <harder@ifa.au.dk>
+
+ * spam-stat.el (spam-stat-strip-xref): New function.
+ (spam-stat-process-directory): Use it.
+
+ * gnus-util.el (gnus-fetch-field): Don't bind case-fold-search
+ here -- it's done in message-fetch-field.
+
+2004-01-21 Kevin Greiner <kgreiner@xpediantsolutions.com>
+
+ * gnus-agent.el (gnus-agent-queue-mail,
+ gnus-agent-prompt-send-queue): New variables.
+ (gnus-agent-send-mail): Use gnus-agent-queue-mail.
+ * gnus-draft.el (gnus-group-send-queue): Pass the group name
+ "nndraft:queue" along to gnus-draft-send. Use
+ gnus-agent-prompt-send-queue.
+ (gnus-draft-send): Rebind gnus-agent-queue-mail to nil when group
+ is "nndraft:queue". Suggested by Gaute Strokkenes
+ <gs234@srcf.ucam.org>
+
+ * gnus-agent.el (agent-disable-undownloaded-faces): Removed
+ (agent-enable-undownloaded-faces): Added
+ (gnus-agent-cat-groups): Use eval-and-compile, not
+ eval-when-compile, to define gnus-agent-set-cat-groups as the setf
+ method of gnus-agent-cat-groups even when the buffer has been
+ evaled.
+ (gnus-agent-save-active,gnus-agent-save-active-1): Merged to
+ delete gnus-agent-save-active-1.
+ (gnus-agent-save-groups): Deleted. Identical to
+ gnus-agent-save-active.
+ (gnus-agent-write-active): No longer adjust agent's copy of active
+ file as agent's adjustments are now stored in their own
+ file. Removed optional parameter.
+ (gnus-agent-possibly-alter-active): Ignore groups of unagentized
+ servers. Add use of min/max range limits from server's local
+ file.
+ (gnus-agent-save-alist): Removed unused optional argument.
+ (gnus-agent-load-local,gnus-agent-read-and-cache-local),
+ (gnus-agent-read-local,gnus-agent-save-local,gnus-agent-get-local),
+ (gnus-agent-set-local): A per-server file that keeps min/max range
+ limits for articles known to the agent. Provides a fast mechanism
+ for altering many active ranges.
+ (gnus-agent-expire-group,gnus-agent-expire): No longer save the
+ active file (local makes it unnecessary).
+ (gnus-agent-regenerate-group): Fixed XEmacs compatibility.
+
+ * gnus-cus.el (agent-disable-undownloaded-faces): Removed
+ (agent-enable-undownloaded-faces): Added
+
+ * gnus-draft.el (gnus-draft-send): Bind gnus-agent-queue-mail to
+ disable it when sending to "nndraft:queue".
+ (gnus-group-send-queue): Add safety check to avoid sending queue
+ when unplugged.
+
+ * gnus-group.el (gnus-group-catchup): Use new
+ gnus-sequence-of-unread-articles, not
+ gnus-list-of-unread-articles, to avoid exhausting memory with huge
+ numbers of articles. Use gnus-range-map to avoid having to
+ uncompress the unread list.
+ (gnus-group-archive-directory,
+ gnus-group-recent-archive-directory): Fixed invalid ange-ftp
+ reference.
+
+ * gnus-range.el (gnus-range-map): Iterate over list or sequence.
+ (gnus-sorted-range-intersection): Intersection of two ranges
+ without requiring that they first be uncompressed.
+
+ * gnus-start.el (gnus-activate-group): Unless blocked by the
+ caller, possibly expand the active range to include both cached
+ and agentized articles.
+ (gnus-convert-old-newsrc): Rewrote in anticipation of having
+ multiple version-dependent converters.
+ (gnus-groups-to-gnus-format): Replaced gnus-agent-save-groups with
+ gnus-agent-save-active.
+ (gnus-save-newsrc-file): Save dirty agent range limits.
+
+ * gnus-sum.el (gnus-select-newgroup): Replaced inline code with
+ gnus-agent-possibly-alter-active.
+ (gnus-adjust-marked-articles): Faster handling of simple lists
+
2004-01-21 Jesper Harder <harder@ifa.au.dk>
* spam-stat.el (spam-stat-test-directory): New optional argument
:type '(repeat symbol)
:group 'gnus-agent)
+(defcustom gnus-agent-queue-mail t
+ "Whether and when outgoing mail should be queued by the agent. When
+`always', always queue outgoing mail. When `nil', never queue.
+Otherwise, queue if and only if unplugged."
+ :group 'gnus-agent
+ :type '(radio (const :format "Always" always)
+ (const :format "Never" nil)
+ (const :format "When plugged" t)))
+
+(defcustom gnus-agent-prompt-send-queue nil
+ "If non-nil, `gnus-group-send-queue' will prompt if called when
+unplugged."
+ :group 'gnus-agent
+ :type 'boolean)
+
;;; Internal variables
(defvar gnus-agent-history-buffers nil)
(gnus-agent-cat-defaccessor
gnus-agent-cat-score-file agent-score-file)
(gnus-agent-cat-defaccessor
- gnus-agent-cat-disable-undownloaded-faces agent-disable-undownloaded-faces)
-(gnus-agent-cat-defaccessor
gnus-agent-cat-enable-undownloaded-faces agent-enable-undownloaded-faces)
-(eval-when-compile
+(eval-and-compile
(defsetf gnus-agent-cat-groups (category) (groups)
(list 'gnus-agent-set-cat-groups category groups)))
'gnus-dummy '((gnus-draft-mode)))))
(defun gnus-agent-send-mail ()
- (if gnus-plugged
+ (if (or (not gnus-agent-queue-mail)
+ (and gnus-plugged (not (eq gnus-agent-queue-mail 'always))))
(funcall gnus-agent-send-mail-function)
(goto-char (point-min))
(re-search-forward
(setq gnus-newsgroup-downloadable
(delq article gnus-newsgroup-downloadable))
- ;; The downloadable mark is implemented as a
- ;; type of read mark. Therefore, marking the
- ;; article as unread is sufficient to clear
- ;; its downloadable flag.
(gnus-summary-mark-article article gnus-unread-mark))
(was-marked-downloadable
(gnus-summary-set-agent-mark article t)))
;;; Internal functions
;;;
-;;; NOTES:
-;;; The agent's active range is defined as follows:
-;;; If the agent has no record of the group, use the actual active
-;;; range.
-;;; If the agent has a record, set the agent's active range to
-;;; include the max limit of the actual active range.
-;;; When expiring, update the min limit to match the smallest of the
-;;; min article not expired or the min actual active range.
-
(defun gnus-agent-save-active (method)
- (gnus-agent-save-active-1 method 'gnus-active-to-gnus-format))
-
-(defun gnus-agent-save-active-1 (method function)
(when (gnus-agent-method-p method)
(let* ((gnus-command-method method)
(new (gnus-make-hashtable (count-lines (point-min) (point-max))))
(file (gnus-agent-lib-file "active")))
- (funcall function nil new)
+ (gnus-active-to-gnus-format nil new)
(gnus-agent-write-active file new)
(erase-buffer)
(nnheader-insert-file-contents file))))
-(defun gnus-agent-write-active (file new &optional literal-replacement)
- (let ((old new))
- (when (and (not literal-replacement)
- (file-exists-p file))
- (setq old (gnus-make-hashtable (count-lines (point-min) (point-max))))
- (with-temp-buffer
- (nnheader-insert-file-contents file)
- (gnus-active-to-gnus-format nil old))
- ;; Iterate over the current active groups, the current active
- ;; range may expand, but NOT CONTRACT, the agent's active range.
- (mapatoms
- (lambda (nsym)
- (let ((new-active (and nsym (boundp nsym) (symbol-value nsym))))
- (when new-active
- (let* ((osym (intern (symbol-name nsym) old))
- (old-active (and (boundp osym) (symbol-value osym))))
- (if old-active
- (let ((new-min (car new-active))
- (old-min (car old-active))
- (new-max (cdr new-active))
- (old-max (cdr old-active)))
- (if (and (integerp new-min)
- (< new-min old-min))
- (setcar old-active new-min))
- (if (and (integerp new-max)
- (> new-max old-max))
- (setcdr old-active new-max)))
- (set osym new-active))))))
- new))
+(defun gnus-agent-write-active (file new)
(gnus-make-directory (file-name-directory file))
(let ((nnmail-active-file-coding-system gnus-agent-file-coding-system))
;; The hashtable contains real names of groups. However, do NOT
;; add the foreign server prefix as gnus-active-to-gnus-format
;; will add it while reading the file.
- (gnus-write-active-file file old nil))))
+ (gnus-write-active-file file new nil)))
-(defun gnus-agent-possibly-alter-active (group active)
+(defun gnus-agent-possibly-alter-active (group active &optional info)
"Possibly expand a group's active range to include articles
downloaded into the agent."
-
-;; I can't use the agent's active file here as there is no practical
-;; mechanism to update the active ranges in that file as the oldest
-;; articles are removed from the agent.
(let* ((gnus-command-method (or gnus-command-method
- (gnus-find-method-for-group group)))
- (alist (gnus-agent-load-alist group)))
-
- (let ((new-min (or (caar gnus-agent-article-alist)
- (car active)))
- (new-max (or (caar (last gnus-agent-article-alist))
- (cdr active))))
-
- (when (< new-min (car active))
- (setcar active new-min))
- (when (> new-max (cdr active))
- (setcdr active new-max)))))
-
-(defun gnus-agent-save-groups (method)
- (gnus-agent-save-active-1 method 'gnus-groups-to-gnus-format))
+ (gnus-find-method-for-group group))))
+ (when (gnus-agent-method-p gnus-command-method)
+ (let* ((local (gnus-agent-get-local group))
+ (active-min (car active))
+ (active-max (cdr active))
+ (agent-min (or (car local) active-min))
+ (agent-max (or (cdr local) active-max)))
+
+ (when (< agent-min active-min)
+ (setcar active agent-min))
+
+ (when (> agent-max active-max)
+ (setcdr active agent-max))
+
+ (when (and info (< agent-max (- active-min 100)))
+ ;; I'm expanding the active range by such a large amount
+ ;; that there is a gap of more than 100 articles between the
+ ;; last article known to the agent and the first article
+ ;; currently available on the server. This gap contains
+ ;; articles that have been lost, mark them as read so that
+ ;; gnus doesn't waste resources trying to fetch them.
+
+ ;; NOTE: I don't do this for smaller gaps (< 100) as I don't
+ ;; want to modify the local file everytime someone restarts
+ ;; gnus. The small gap will cause a tiny performance hit
+ ;; when gnus tries, and fails, to retrieve the articles.
+ ;; Still that should be smaller than opening a buffer,
+ ;; printing this list to the buffer, and then writing it to a
+ ;; file.
+
+ (let ((read (gnus-info-read info)))
+ (gnus-info-set-read
+ info
+ (gnus-range-add
+ read
+ (list (cons (1+ agent-max)
+ (1- active-min))))))
+
+ ;; Lie about the agent's local range for this group to
+ ;; disable the set read each time this server is opened.
+ ;; NOTE: Opening this group will restore the valid local
+ ;; range but it will also expand the local range to
+ ;; incompass the new active range.
+ (gnus-agent-set-local group agent-min (1- active-min)))))))
(defun gnus-agent-save-group-info (method group active)
+ "Update a single group's active range in the agent's copy of the server's active file."
(when (gnus-agent-method-p method)
(let* ((gnus-command-method method)
(coding-system-for-write nnheader-file-coding-system)
(gnus-agent-save-alist gnus-agent-read-agentview)))
alist))))
-(defun gnus-agent-save-alist (group &optional articles state dir)
+(defun gnus-agent-save-alist (group &optional articles state)
"Save the article-state alist for GROUP."
(let* ((file-name-coding-system nnmail-pathname-coding-system)
(prev (cons nil gnus-agent-article-alist))
(setcdr (cadr prev) state)))
(setq prev (cdr prev)))
(setq gnus-agent-article-alist (cdr all))
- (if dir
- (gnus-make-directory dir)
- (gnus-make-directory (gnus-agent-article-name "" group)))
- (with-temp-file (if dir
- (expand-file-name ".agentview" dir)
- (gnus-agent-article-name ".agentview" group))
+
+ (gnus-agent-set-local group
+ (caar gnus-agent-article-alist)
+ (caar (last gnus-agent-article-alist)))
+
+ (gnus-make-directory (gnus-agent-article-name "" group))
+ (with-temp-file (gnus-agent-article-name ".agentview" group)
(cond ((eq gnus-agent-article-alist-save-format 1)
(princ gnus-agent-article-alist (current-buffer)))
((eq gnus-agent-article-alist-save-format 2)
(princ gnus-agent-article-alist-save-format (current-buffer))
(insert "\n"))))
+(defvar gnus-agent-article-local nil)
+(defvar gnus-agent-file-loading-local nil)
+
+(defun gnus-agent-load-local (&optional method)
+ "Load the METHOD'S local file. The local file contains min/max
+article counts for each of the method's subscribed groups."
+ (let ((gnus-command-method (or method gnus-command-method)))
+ (setq gnus-agent-article-local
+ (gnus-cache-file-contents
+ (gnus-agent-lib-file "local")
+ 'gnus-agent-file-loading-local
+ 'gnus-agent-read-and-cache-local))))
+
+(defun gnus-agent-read-and-cache-local (file)
+ "Load and read FILE then bind its contents to
+gnus-agent-article-local. If that variable had `dirty' (also known as
+modified) original contents, they are first saved to their own file."
+
+ (if (and gnus-agent-article-local
+ (symbol-value (intern "+dirty" gnus-agent-article-local)))
+ (gnus-agent-save-local))
+ (gnus-agent-read-local file))
+
+(defun gnus-agent-read-local (file)
+ "Load FILE and do a `read' there."
+ (let ((obarray (gnus-make-hashtable (count-lines (point-min) (point-max))))
+ (line 1))
+ (with-temp-buffer
+ (condition-case nil
+ (nnheader-insert-file-contents file)
+ (file-error))
+
+ (goto-char (point-min))
+ ;; Skip any comments at the beginning of the file (the only place where they may appear)
+ (while (= (following-char) ?\;)
+ (forward-line 1)
+ (setq line (1+ line)))
+
+ (while (not (eobp))
+ (condition-case err
+ (let (group
+ min
+ max
+ (cur (current-buffer)))
+ (setq group (read cur)
+ min (read cur)
+ max (read cur))
+
+ (when (stringp group)
+ (setq group (intern group obarray)))
+
+ ;; NOTE: The '+ 0' ensure that min and max are both numerics.
+ (set group (cons (+ 0 min) (+ 0 max))))
+ (error
+ (gnus-message 3 "Warning - invalid agent local: %s on line %d: " file line (error-message-string err))))
+ (forward-line 1)
+ (setq line (1+ line))))
+
+ (set (intern "+dirty" obarray) nil)
+ (set (intern "+method" obarray) gnus-command-method)
+ obarray))
+
+(defun gnus-agent-save-local (&optional force)
+ "Save gnus-agent-article-local under it method's agent.lib directory."
+ (let ((obarray gnus-agent-article-local))
+ (when (and obarray
+ (or force (symbol-value (intern "+dirty" obarray))))
+ (let* ((gnus-command-method (symbol-value (intern "+method" obarray)))
+ ;; NOTE: gnus-command-method is used within gnus-agent-lib-file.
+ (dest (gnus-agent-lib-file "local")))
+ (gnus-make-directory (gnus-agent-lib-file ""))
+ (with-temp-file dest
+ (let ((gnus-command-method (symbol-value (intern "+method" obarray)))
+ (file-name-coding-system nnmail-pathname-coding-system)
+ (coding-system-for-write
+ gnus-agent-file-coding-system)
+ print-level print-length item article
+ (standard-output (current-buffer)))
+ (mapatoms (lambda (symbol)
+ (cond ((not (boundp symbol))
+ nil)
+ ((member (symbol-name symbol) '("+dirty" "+method"))
+ nil)
+ (t
+ (prin1 symbol)
+ (let ((range (symbol-value symbol)))
+ (princ " ")
+ (princ (car range))
+ (princ " ")
+ (princ (cdr range))
+ (princ "\n"))))))))))))
+
+(defun gnus-agent-get-local (group)
+ (let* ((gmane (gnus-group-real-name group))
+ (gnus-command-method (gnus-find-method-for-group group))
+ (local (gnus-agent-load-local))
+ (symb (intern gmane local))
+ (minmax (and (boundp symb) (symbol-value symb))))
+ (unless minmax
+ ;; Bind these so that gnus-agent-load-alist doesn't change the
+ ;; current alist (i.e. gnus-agent-article-alist)
+ (let* ((gnus-agent-article-alist gnus-agent-article-alist)
+ (gnus-agent-file-loading-cache gnus-agent-file-loading-cache)
+ (alist (gnus-agent-load-alist group)))
+ (when alist
+ (setq minmax
+ (cons (caar alist)
+ (caar (last alist))))
+ (gnus-agent-set-local group (car minmax) (cdr minmax)
+ gmane gnus-command-method local))))
+ minmax))
+
+(defun gnus-agent-set-local (group min max &optional gmane method local)
+ (let* ((gmane (or gmane (gnus-group-real-name group)))
+ (gnus-command-method (or method (gnus-find-method-for-group group)))
+ (local (or local (gnus-agent-load-local)))
+ (symb (intern gmane local))
+ (minmax (and (boundp symb) (symbol-value symb))))
+
+ (if (cond ((and minmax
+ (or (not (eq min (car minmax)))
+ (not (eq max (cdr minmax)))))
+ (setcar minmax min)
+ (setcdr minmax max)
+ t)
+ (minmax
+ nil)
+ (t
+ (set symb (cons min max))
+ t))
+ (set (intern "+dirty" local) t))))
+
(defun gnus-agent-article-name (article group)
(expand-file-name article
(file-name-as-directory
(save-excursion
(gnus-agent-expire-group-1
group overview (gnus-gethash-safe group orig)
- articles force))
- (gnus-agent-write-active active-file orig t)))
+ articles force))))
(kill-buffer overview))))
(gnus-message 4 (gnus-agent-expire-done-message)))))
(let ((inhibit-quit t))
(unless (equal alist gnus-agent-article-alist)
(setq gnus-agent-article-alist alist)
- (gnus-agent-save-alist group)
-
- ;; The active list changed, set the agent's active range
- ;; to match the beginning of the list.
- (if alist
- (setcar active (caar alist))))
+ (gnus-agent-save-alist group))
(when (buffer-modified-p)
(gnus-make-directory dir)
(when active
(save-excursion
(gnus-agent-expire-group-1
- expiring-group overview active articles force)))))
- (gnus-agent-write-active active-file orig t))))
+ expiring-group overview active articles force))))))))
(kill-buffer overview))
(gnus-agent-expire-unagentized-dirs)
(gnus-message 4 (gnus-agent-expire-done-message))))))
def
select)))
(catch 'mark
- (while (let ((c (read-char-exclusive
- "Mark as unread: (n)one / (a)ll / all (d)ownloaded articles? (n)"
- )))
+ (while (let (c
+ (cursor-in-echo-area t)
+ (echo-keystrokes 0))
+ (message "Mark as unread: (n)one / (a)ll / all (d)ownloaded articles? (n) ")
+ (setq c (read-char-exclusive))
+
(cond ((or (eq c ?\r) (eq c ?n) (eq c ?N))
(throw 'mark nil))
((or (eq c ?a) (eq c ?A))
(throw 'mark t))
((or (eq c ?d) (eq c ?D))
(throw 'mark 'some)))
- (message "Ignoring unexpected input")
+ (gnus-message 3 "Ignoring unexpected input")
(sit-for 1)
t)))))
(let ((group (gnus-group-real-name group))
(group-active (gnus-active group)))
- (when group-active
- (let ((new-min (or (caar gnus-agent-article-alist)
- (car group-active)))
- (new-max (or (caar (last gnus-agent-article-alist))
- (cdr group-active))))
-
- (when (< new-min (car group-active))
- (setcar group-active new-min))
-
- (when (> new-max (cdr group-active))
- (setcdr group-active new-max))))))))
+ (gnus-agent-possibly-alter-active group group-active)))))
(when (and reread gnus-agent-article-alist)
(gnus-make-ascending-articles-unread
(const :format "Disable " DISABLE))
"\nEnable, or disable, agent expiration in this group or topic."
gnus-agent-cat-enable-expiration)
- (agent-disable-undownloaded-faces
- (boolean :tag "Disable Agent Faces")
- "Have the summary buffer ignore the agent's undownloaded faces.
-These faces, when used, act as a warning that an article has not been
-fetched into either the agent nor the cache. This is of most use to
-users who use the agent as a cache (i.e. they only operate on articles
-that have been downloaded). Disable to display normal article faces
-even when the article hasn't been downloaded."
- gnus-agent-cat-disable-undownloaded-faces))
+ (agent-enable-undownloaded-faces
+ (boolean :tag "Enable Agent Faces")
+ "Have the summary buffer use the agent's undownloaded faces.
+These faces, when enabled, act as a warning that an article has not
+been fetched into either the agent nor the cache. This is of most use
+to users who use the agent as a cache (i.e. they only operate on
+articles that have been downloaded). Leave disabled to display normal
+article faces even when the article hasn't been downloaded."
+gnus-agent-cat-enable-undownloaded-faces))
"Alist of group parameters that are not also topic parameters.
Each entry has the form (NAME TYPE DOC ACCESSOR), where NAME is the
(defvar gnus-agent-cat-days-until-old)
(defvar gnus-agent-cat-predicate)
(defvar gnus-agent-cat-groups)
- (defvar gnus-agent-cat-disable-undownloaded-faces)
+ (defvar gnus-agent-cat-enable-undownloaded-faces)
)
(defun gnus-trim-whitespace (s)
(widget-insert "\nVisual Settings ")
- (gnus-agent-cat-prepare-category-field agent-disable-undownloaded-faces)
+ (gnus-agent-cat-prepare-category-field agent-enable-undownloaded-faces)
(use-local-map widget-keymap)
(widget-setup)
(defun gnus-draft-send (article &optional group interactive)
"Send message ARTICLE."
- (let ((message-syntax-checks (if interactive message-syntax-checks
- 'dont-check-for-anything-just-trust-me))
- (message-hidden-headers nil)
- (message-inhibit-body-encoding (or (not group)
- (equal group "nndraft:queue")
- message-inhibit-body-encoding))
- (message-send-hook (and group (not (equal group "nndraft:queue"))
- message-send-hook))
- (message-setup-hook (and group (not (equal group "nndraft:queue"))
- message-setup-hook))
- type method move-to)
+ (let* ((is-queue (or (not group)
+ (equal group "nndraft:queue")))
+ (message-syntax-checks (if interactive message-syntax-checks
+ 'dont-check-for-anything-just-trust-me))
+ (message-hidden-headers nil)
+ (message-inhibit-body-encoding (or is-queue
+ message-inhibit-body-encoding))
+ (message-send-hook (and (not is-queue)
+ message-send-hook))
+ (message-setup-hook (and (not is-queue)
+ message-setup-hook))
+ (gnus-agent-queue-mail (and (not is-queue)
+ gnus-agent-queue-mail))
+ type method move-to)
(gnus-draft-setup article (or group "nndraft:queue"))
;; We read the meta-information that says how and where
;; this message is to be sent.
(defun gnus-group-send-queue ()
"Send all sendable articles from the queue group."
(interactive)
- (gnus-activate-group "nndraft:queue")
- (save-excursion
- (let* ((articles (nndraft-articles))
- (unsendable (gnus-uncompress-range
- (cdr (assq 'unsend
- (gnus-info-marks
- (gnus-get-info "nndraft:queue"))))))
- (gnus-posting-styles nil)
- (total (length articles))
- article)
- (while (setq article (pop articles))
- (unless (memq article unsendable)
- (let ((message-sending-message
- (format "Sending message %d of %d..."
- (- total (length articles)) total)))
- (gnus-draft-send article)))))))
+ (when (or gnus-plugged
+ (not gnus-agent-prompt-send-queue)
+ (gnus-y-or-n-p "Gnus is unplugged; really send queue? "))
+ (gnus-activate-group "nndraft:queue")
+ (save-excursion
+ (let* ((articles (nndraft-articles))
+ (unsendable (gnus-uncompress-range
+ (cdr (assq 'unsend
+ (gnus-info-marks
+ (gnus-get-info "nndraft:queue"))))))
+ (gnus-posting-styles nil)
+ (total (length articles))
+ article)
+ (while (setq article (pop articles))
+ (unless (memq article unsendable)
+ (let ((message-sending-message
+ (format "Sending message %d of %d..."
+ (- total (length articles)) total)))
+ (gnus-draft-send article))))))))
;;;###autoload
(defun gnus-draft-reminder ()
(eval-when-compile (require 'mm-url))
(defcustom gnus-group-archive-directory
- "*ftp@ftp.hpc.uh.edu:/pub/emacs/ding-list/"
+ "/ftp@ftp.hpc.uh.edu:/pub/emacs/ding-list/"
"*The address of the (ding) archives."
:group 'gnus-group-foreign
:type 'directory)
(defcustom gnus-group-recent-archive-directory
- "*ftp@ftp.hpc.uh.edu:/pub/emacs/ding-list-recent/"
+ "/ftp@ftp.hpc.uh.edu:/pub/emacs/ding-list-recent/"
"*The address of the most recent (ding) articles."
:group 'gnus-group-foreign
:type 'directory)
(let* ((entry (gnus-group-entry group))
(num (car entry))
(marks (gnus-info-marks (nth 2 entry)))
- (unread (gnus-list-of-unread-articles group)))
+ (unread (gnus-sequence-of-unread-articles group)))
;; Remove entries for this group.
(nnmail-purge-split-history (gnus-group-real-name group))
;; Do the updating only if the newsgroup isn't killed.
'del '(tick))
(list (cdr (assq 'dormant marks))
'del '(dormant))))
- (setq unread (gnus-uncompress-range
- (gnus-range-add (gnus-range-add
- unread (cdr (assq 'dormant marks)))
- (cdr (assq 'tick marks)))))
+ (setq unread (gnus-range-add (gnus-range-add
+ unread (cdr (assq 'dormant marks)))
+ (cdr (assq 'tick marks))))
(gnus-add-marked-articles group 'tick nil nil 'force)
(gnus-add-marked-articles group 'dormant nil nil 'force))
;; Do auto-expirable marks if that's required.
(when (gnus-group-auto-expirable-p group)
- (gnus-add-marked-articles group 'expire unread)
- (gnus-request-set-mark group (list (list unread 'add '(expire)))))
+ (gnus-range-map (lambda (article)
+ (gnus-add-marked-articles group 'expire (list article))
+ (gnus-request-set-mark group (list (list (list article) 'add '(expire)))))
+ unread))
(let ((gnus-newsgroup-name group))
(gnus-run-hooks 'gnus-group-catchup-group-hook))
num)))
(nreverse out)))
;;;###autoload
+(defun gnus-sorted-range-intersection (range1 range2)
+ "Return intersection of RANGE1 and RANGE2.
+RANGE1 and RANGE2 have to be sorted over <."
+ (let* (out
+ (min1 (car range1))
+ (max1 (if (numberp min1) min1 (prog1 (cdr min1) (setq min1 (car min1)))))
+ (min2 (car range2))
+ (max2 (if (numberp min2) min2 (prog1 (cdr min2) (setq min2 (car min2))))))
+ (setq range1 (cdr range1)
+ range2 (cdr range2))
+ (while (and min1 min2)
+ (cond ((< max1 min2) ; range1 preceeds range2
+ (setq range1 (cdr range1)
+ min1 nil))
+ ((< max2 min1) ; range2 preceeds range1
+ (setq range2 (cdr range2)
+ min2 nil))
+ (t ; some sort of overlap is occurring
+ (let ((min (max min1 min2))
+ (max (min max1 max2)))
+ (setq out (if (= min max)
+ (cons min out)
+ (cons (cons min max) out))))
+ (if (< max1 max2) ; range1 ends before range2
+ (setq min1 nil) ; incr range1
+ (setq min2 nil)))) ; incr range2
+ (unless min1
+ (setq min1 (car range1)
+ max1 (if (numberp min1) min1 (prog1 (cdr min1) (setq min1 (car min1))))
+ range1 (cdr range1)))
+ (unless min2
+ (setq min2 (car range2)
+ max2 (if (numberp min2) min2 (prog1 (cdr min2) (setq min2 (car min2))))
+ range2 (cdr range2))))
+ (nreverse out)))
+
+;;;###autoload
(defalias 'gnus-set-sorted-intersection 'gnus-sorted-nintersection)
;;;###autoload
(setcdr prev (cons num list)))
(cdr top)))
+(defun gnus-range-map (func range)
+ "Apply FUNC to each value contained by RANGE."
+ (while range
+ (let ((span (pop range)))
+ (if (numberp span)
+ (funcall func span)
+ (let ((first (car span))
+ (last (cdr span)))
+ (while (<= first last)
+ (funcall func first)
+ (setq first (1+ first))))))))
+
(provide 'gnus-range)
;;; gnus-range.el ends here
(require 'gnus-util)
(autoload 'message-make-date "message")
(autoload 'gnus-agent-read-servers-validate "gnus-agent")
+(autoload 'gnus-agent-save-local "gnus-agent")
(autoload 'gnus-agent-possibly-alter-active "gnus-agent")
+(eval-when-compile
+ (defvar gnus-agent-covered-methods nil)
+ (defvar gnus-agent-file-loading-local nil)
+ (defvar gnus-agent-file-loading-cache nil))
(defcustom gnus-startup-file (nnheader-concat gnus-home-directory ".newsrc")
"Your `.newsrc' file.
(setq gnus-list-of-killed-groups nil
gnus-have-read-active-file nil
gnus-agent-covered-methods nil
+ gnus-agent-file-loading-local nil
+ gnus-agent-file-loading-cache nil
gnus-server-method-cache nil
gnus-newsrc-alist nil
gnus-newsrc-hashtb nil
(gnus-active group))
(gnus-active group)
+ ;; If a cache is present, we may have to alter the active info.
+ (when gnus-use-cache
+ (inline (gnus-cache-possibly-alter-active
+ group active)))
+
+ ;; If the agent is enabled, we may have to alter the active info.
+ (when gnus-agent
+ (gnus-agent-possibly-alter-active group active))
+
(gnus-set-active group active)
;; Return the new active info.
active)))))
(let* ((range (gnus-info-read info))
(num 0))
+
+ ;; These checks are present in gnus-activate-group but skipped
+ ;; due to setting dont-check in the preceeding call.
+
;; If a cache is present, we may have to alter the active info.
(when (and gnus-use-cache info)
(inline (gnus-cache-possibly-alter-active
;; If the agent is enabled, we may have to alter the active info.
(when (and gnus-agent info)
- (gnus-agent-possibly-alter-active
- (gnus-info-group info) active))
+ (gnus-agent-possibly-alter-active (gnus-info-group info) active info))
;; Modify the list of read articles according to what articles
;; are available; then tally the unread articles and add the
(gnus-online method)
(gnus-agent-method-p method))
(progn
- (gnus-agent-save-groups method)
+ (gnus-agent-save-active method)
(gnus-active-to-gnus-format method hashtb nil real-active))
(goto-char (point-min))
(kill-buffer (current-buffer))
(gnus-message 5 "Reading %s...done" newsrc-file))))))
+(quote (;; T-gnus doesn't provide those functions.
+(defun gnus-convert-old-newsrc ()
+ "Convert old newsrc formats into the current format, if needed."
+ (let ((fcv (and gnus-newsrc-file-version
+ (gnus-continuum-version gnus-newsrc-file-version))))
+ (when fcv
+ ;; A .newsrc.eld file was loaded.
+ (let ((converters
+ (sort
+ (mapcar (lambda (date-func)
+ (cons (gnus-continuum-version (car date-func))
+ date-func))
+ ;; This is a list of converters that must be run
+ ;; to bring the newsrc file up to the current
+ ;; version. If you create an incompatibility
+ ;; with older versions, you should create an
+ ;; entry here. The entry should consist of the
+ ;; current gnus version (hardcoded so that it
+ ;; doesn't change with each release) and the
+ ;; function that must be applied to convert the
+ ;; previous version into the current version.
+ '(("September Gnus v0.1" nil gnus-convert-old-ticks)))
+ #'car-less-than-car)))
+ ;; Skip converters older than the file version
+ (while (and converters (>= fcv (caar converters)))
+ (pop converters))
+
+ ;; Perform converters to bring older version up to date.
+ (when (and converters
+ (< fcv (caar converters)))
+ (while (let (c
+ (cursor-in-echo-area t)
+ (echo-keystrokes 0))
+ (message "Convert newsrc from version '%s' to '%s'? (n/y/?)"
+ gnus-newsrc-file-version gnus-version)
+ (setq c (read-char-exclusive))
+
+ (cond ((or (eq c ?n) (eq c ?N))
+ (error "Can not start gnus using old (unconverted) newsrc"))
+ ((or (eq c ?y) (eq c ?Y))
+ nil)
+ ((eq c ?\?)
+ (message "This conversion is irreversible. \
+ You should backup your files before proceeding.")
+ (sit-for 5)
+ t)
+ (t
+ (gnus-message 3 "Ignoring unexpected input")
+ (sit-for 3)
+ t))))
+ (while (and converters (< fcv (caar converters)))
+ (let* ((converter (pop converters))
+ (convert-to (nth 1 converter))
+ (load-from (nth 2 converter))
+ (func (nth 3 converter)))
+ (when (and load-from
+ (not (fboundp func)))
+ (load load-from t))
+ (funcall func convert-to)))
+ (gnus-dribble-enter
+ (format ";Converted newsrc from version '%s' to '%s'? (n/y/?)"
+ gnus-newsrc-file-version gnus-version)))))))
+
+(defun gnus-convert-old-ticks (converting-to)
+ (let ((newsrc (cdr gnus-newsrc-alist))
+ marks info dormant ticked)
+ (while (setq info (pop newsrc))
+ (when (setq marks (gnus-info-marks info))
+ (setq dormant (cdr (assq 'dormant marks))
+ ticked (cdr (assq 'tick marks)))
+ (when (or dormant ticked)
+ (gnus-info-set-read
+ info
+ (gnus-add-to-range
+ (gnus-info-read info)
+ (nconc (gnus-uncompress-range dormant)
+ (gnus-uncompress-range ticked)))))))))
+))
+
(defun gnus-load (file &optional coding-system)
"Load FILE, but in such a way that read errors can be reported."
(with-temp-buffer
;; from the variable gnus-newsrc-alist.
(when (and (or gnus-newsrc-alist gnus-killed-list)
gnus-current-startup-file)
+ ;; Save agent range limits for the currently active method.
+ (when gnus-agent
+ (gnus-agent-save-local force))
+
(save-excursion
(if (and (or gnus-use-dribble-file gnus-slave)
(not force)
(gnus-message 8 "Saving %s..." gnus-current-startup-file)
(gnus-gnus-to-newsrc-format)
(gnus-message 8 "Saving %s...done" gnus-current-startup-file))
+
;; Save .newsrc.eld.
(set-buffer (gnus-get-buffer-create " *Gnus-newsrc*"))
(make-local-variable 'version-control)
group (gnus-status-message group)))
(when gnus-agent
- ;; The agent may be storing articles that are no longer in the
- ;; server's active range. If that is the case, the active range
- ;; needs to be expanded such that the agent's articles can be
- ;; included in the summary.
- (let* ((gnus-command-method (gnus-find-method-for-group group))
- (alist (gnus-agent-load-alist group))
- (active (gnus-active group)))
- (if (and (car alist)
- (< (caar alist) (car active)))
- (gnus-set-active group (cons (caar alist) (cdr active)))))
-
+ (gnus-agent-possibly-alter-active group (gnus-active group) info)
+
(setq gnus-summary-use-undownloaded-faces
(gnus-agent-find-parameter
group
(min (car active))
(max (cdr active))
(types gnus-article-mark-lists)
- marks var articles article mark mark-type)
+ marks var articles article mark mark-type
+ bgn end)
(dolist (marks marked-lists)
(setq mark (car marks)
;; We set the variable according to the type of the marks list,
;; and then adjust the marks to a subset of the active articles.
(cond
- ;; Adjust "simple" lists.
+ ;; Adjust "simple" lists - compressed yet unsorted
((eq mark-type 'list)
- (set var (setq articles (gnus-uncompress-range (cdr marks))))
- (when (memq mark '(tick dormant expire reply save))
- (while articles
- (when (or (< (setq article (pop articles)) min) (> article max))
- (set var (delq article (symbol-value var)))))))
+ ;; Simultaneously uncompress and clip to active range
+ (setq articles (cdr marks))
+ (while (setq article (car articles))
+ (when (cond ((consp article)
+ (setq bgn (max (car article) min)
+ end (min (cdr article) max))
+ (if (> bgn end)
+ t ; range excluded - splice out of marks
+ (setcar articles bgn) ; First value replaces range.
+ (setq bgn (1+ bgn))
+ (while (<= bgn end)
+ (setq articles (setcdr articles (cons bgn (cdr articles)))
+ bgn (1+ bgn)))
+ (setq articles (cdr articles))
+ nil))
+ ((or (< article min)
+ (> article max))
+ t ; value excluded - splice out of marks
+ )
+ (t
+ (setq articles (cdr articles))
+ nil))
+ ; perform slice to remove article
+ (setcar articles (cadr articles))
+ (setcdr articles (cddr articles))))
+ (set var (cdr marks)))
;; Adjust assocs.
((eq mark-type 'tuple)
(set var (setq articles (cdr marks)))
(while read
(when first
(while (< first nlast)
- (push first unread)
- (setq first (1+ first))))
+ (setq unread (cons first unread)
+ first (1+ first))))
(setq first (1+ (if (atom (car read)) (car read) (cdar read))))
(setq nlast (if (atom (cadr read)) (cadr read) (caadr read)))
(setq read (cdr read)))))
;; And add the last unread articles.
(while (<= first last)
- (push first unread)
- (setq first (1+ first)))
+ (setq unread (cons first unread)
+ first (1+ first)))
;; Return the list of unread articles.
(delq 0 (nreverse unread))))
(cdr (assq 'dormant marked)))
(cdr (assq 'tick marked))))))
+;; This function returns a sequence of article numbers based on the
+;; difference between the ranges of read articles in this group and
+;; the range of active articles.
+(defun gnus-sequence-of-unread-articles (group)
+ (let* ((read (gnus-info-read (gnus-get-info group)))
+ (active (or (gnus-active group) (gnus-activate-group group)))
+ (last (cdr active))
+ first nlast unread)
+ ;; If none are read, then all are unread.
+ (if (not read)
+ (setq first (car active))
+ ;; 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))
+ (progn (setq read (list read))
+ nil)))
+ (setq first (max (car active) (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)))
+ (while read
+ (when first
+ (push (cons first nlast) unread))
+ (setq first (1+ (if (atom (car read)) (car read) (cdar read))))
+ (setq nlast (if (atom (cadr read)) (cadr read) (caadr read)))
+ (setq read (cdr read)))))
+ ;; And add the last unread articles.
+ (cond ((< first last)
+ (push (cons first last) unread))
+ ((= first last)
+ (push first unread)))
+ ;; Return the sequence of unread articles.
+ (delq 0 (nreverse unread))))
+
;; Various summary commands
(defun gnus-summary-select-article-buffer ()
"Return the value of the header FIELD of current article."
(save-excursion
(save-restriction
- (let ((case-fold-search t)
- (inhibit-point-motion-hooks t))
+ (let ((inhibit-point-motion-hooks t))
(nnheader-narrow-to-headers)
(message-fetch-field field)))))
\f
;;; Code:
+(require 'mail-parse)
(defgroup spam-stat nil
"Statistical spam detection for Emacs.
;; Testing
+(defun spam-stat-strip-xref ()
+ "Strip the the Xref header."
+ (save-restriction
+ (mail-narrow-to-head)
+ (when (re-search-forward "^Xref:.*\n" nil t)
+ (delete-region (match-beginning 0) (match-end 0)))))
+
(defun spam-stat-process-directory (dir func)
"Process all the regular files in directory DIR using function FUNC."
(let* ((files (directory-files dir t "^[^.]"))
(setq count (1+ count))
(message "Reading %s: %.2f%%" dir (/ count max))
(insert-file-contents f)
+ (spam-stat-strip-xref)
(funcall func)
(erase-buffer))))))
+2004-01-21 Kevin Greiner <kgreiner@xpediantsolutions.com>
+
+ * gnus.texi (Outgoing Messages, Agent Variables): Add
+ gnus-agent-queue-mail and gnus-agent-prompt-send-queue.
+ Suggested by Gaute Strokkenes <gs234@srcf.ucam.org>
+
+ * gnus.texi (agent-disable-undownloaded-faces): Replaced with
+ agent-enable-undownloaded-faces
+
2004-01-17 Jesper Harder <harder@ifa.au.dk>
* sieve.texi (Manage Sieve API): nil -> @code{nil}.
@cindex Agent Parameters
@table @code
-@item gnus-agent-cat-name
+@item agent-cat-name
\e$BJ,N`$NL>A0!#\e(B
-@item gnus-agent-cat-groups
+@item agent-groups
\e$B$3$NJ,N`$K$"$k%0%k!<%W$N%j%9%H!#\e(B
-@item gnus-agent-cat-predicate
+@item agent-predicate
(\e$BDL>o\e(B) \e$B$I$N5-;v$r%@%&%s%m!<%I$9$k$N$,E,Ev$+$H$$$&Bg$^$+$JNX3T$rM?$($k=R\e(B
\e$B8l!#$=$7$F\e(B
-@item gnus-agent-cat-score-file
+@item agent-score-file
(\e$BDL>o\e(B) \e$B$I$N5-;v$r%@%&%s%m!<%I$9$k$+$r7h$a$k$H$-$N$h$j$-$a$N:Y$+$$%9%3%"\e(B
\e$B5,B'!#\e(B(\e$B$3$N%@%&%s%m!<%I%9%3%"\e(B (@dfn{download score}) \e$B$ODL>o$N%9%3%"$H$O\e(B
\e$BI,$:$7$b4X78$,L5$$$3$H$KCm0U$7$F$/$@$5$$!#\e(B)
-@item gnus-agent-cat-enable-expiration
+@item agent-enable-expiration
\e$B$3$N%0%k!<%W$N8E$$5-;v$r%(!<%8%'%s%H$,4|8B@Z$l>C5n$9$Y$-$+$I$&$+$r<($9\e(B
\e$B%V!<%kJQ?t!#BgDq$N%0%k!<%W$O%G%#%9%/6u4V$rO2Hq$7$J$$$?$a$K4|8B@Z$l>C5n$5\e(B
\e$B$l$k$Y$-$G$9!#$$$d!"<B:]$K$O\e(B gnus.* \e$B3,AX$O4|8B@Z$l>C5n$5$l$k$Y$-$G$O$J\e(B
\e$B$$%0%k!<%W$@$1$r4^$s$G$$$k$H8@$C$F$b!"$?$V$s:9$7;Y$($"$j$^$;$s!#\e(B
-@item gnus-agent-cat-days-until-old
+@item agent-days-until-old
\e$B4{FI$N5-;v$r4|8B@Z$l>C5n$7$F$b:9$7;Y$($J$$$3$H$rH=CG$9$kA0$K!"%(!<%8%'%s\e(B
\e$B%H$,BT$C$F$$$k$Y$-F|?t$r<($9@0?t!#\e(B
-@item gnus-agent-cat-low-score
+@item agent-low-score
@code{gnus-agent-low-score} \e$B$r>e=q$-$9$k@0?t!#\e(B
-@item gnus-agent-cat-high-score
+@item agent-high-score
@code{gnus-agent-high-score} \e$B$r>e=q$-$9$k@0?t!#\e(B
-@item gnus-agent-cat-length-when-short
+@item agent-length-when-short
@code{gnus-agent-short-article} \e$B$r>e=q$-$9$k@0?t!#\e(B
-@item gnus-agent-cat-length-when-long
+@item agent-length-when-long
@code{gnus-agent-long-article} \e$B$r>e=q$-$9$k@0?t!#\e(B
-@c @item gnus-agent-cat-disable-undownloaded-faces
-@c \e$B%@%&%s%m!<%I$5$l$F$$$J$$5-;v$r\e(B gnus-summary-*-undownloaded-face \e$B$r;H$C$F\e(B
-@c \e$B35N,%P%C%U%!$KI=<($9$Y$-\e(B @emph{\e$B$G$O$J$$\e(B} \e$B$3$H$r<($9%7%s%\%k!#CM\e(B
-@c \e$B$,\e(B @code{nil} \e$B$@$H!"B>$N%7%s%\%k$,$=$l$i$rM^@)$7$F$$$F$b!"%@%&%s%m!<%I$5\e(B
-@c \e$B$l$F$$$J$$5-;vMQ$N%U%'!<%9$r;H$($k$h$&$K$J$j$^$9!#\e(B
-
-@item gnus-agent-cat-enable-undownloaded-faces
+@item agent-enable-undownloaded-faces
\e$B%@%&%s%m!<%I$5$l$F$$$J$$5-;v$r\e(B gnus-summary-*-undownloaded-face \e$B$r;H$C$F\e(B
-\e$B35N,%P%C%U%!$KI=<($9$Y$-$G$"$k$3$H$r<($9%7%s%\%k!#CM$,\e(B @code{nil} \e$B$@$H!"\e(B
-\e$BB>$N%7%s%\%k$,$=$l$i$rM-8z$K$7$F$$$F$b!"%@%&%s%m!<%I$5$l$F$$$J$$5-;vMQ$N\e(B
-\e$B%U%'!<%9$r;H$o$J$$$h$&$K$J$j$^$9!#\e(B
+\e$B35N,%P%C%U%!$KI=<($9$Y$-$+$I$&$+$r<($9%7%s%\%k!#\e(B@code{nil} \e$B0J30$J$i$I$s\e(B
+\e$B$J%7%s%\%k$G$b!"%@%&%s%m!<%I$5$l$F$$$J$$5-;vMQ$N%U%'!<%9$r;H$&$h$&$K$J$j\e(B
+\e$B$^$9!#\e(B
@end table
\e$B$$$C$?$sJ,N`$,:n$i$l$?$i!"J,N`$NL>A0$rJQ$($k$3$H$O$G$-$^$;$s!#\e(B
\e$B;~4V$r:G>.$K$9$k$?$a$K\e(B) \e$B%(!<%8%'%s%H$r%-%c%C%7%e$H$7$F;H$&>l9g$O!"%@%&%s\e(B
\e$B%m!<%I$5$l$F$$$J$$5-;v$N%U%'!<%9$O$*$=$i$/NI$$9M$($N$h$&$K;W$($k$G$7$g$&!#\e(B
\e$B%@%&%s%m!<%I$5$l$?5-;v$KBP$7$F$9$Y$F$N;E;v\e(B (\e$B0u$rIU$1$k!"FI$`!":o=|$9\e(B
-\e$B$k\e(B) \e$B$r9T$J$($P!"$$$D$bDL>o$N%U%'!<%9$,8=$l$k$+$i$G$9!#\e(B
-
-\e$B$H$-$?$^%(!<%8%'%s%H$r;H$&%f!<%6$K$H$C$F$O!"%@%&%s%m!<%I$5$l$F$$$J$$5-;v\e(B
-\e$B$N%U%'!<%9$O!"$I$&$7$h$&$b$J$/$R$I$$9M$($G$"$k$h$&$K;W$($k$+$b$7$l$^$;$s!#\e(B
-\e$BO@E@$O!"H`$i$NBgDq$N5-;v$O%(!<%8%'%s%H$K<h$j9~$^$l$F$$$J$$$N$G!"B?$/$NDL\e(B
-\e$B>o$N%U%'!<%9$,!"%@%&%s%m!<%I$5$l$F$$$J$$5-;v$N%U%'!<%9$N1"$K2b$s$G$7$^$&\e(B
-\e$B$3$H$G$9!#$3$l$,$"$J$?$N6-6x$J$i$P!"$"$J$?$K$OFs$D$NA*Br;h$,$"$j$^$9!#Bh\e(B
-\e$B0l$K!"\e(B@code{gnus-summary-*-undownloaded-face} \e$B$N%U%'!<%972$K4X$o$k;0$D$N\e(B
-\e$B%3%s%9%;%k$r>C5n$9$k$?$a$K\e(B @code{gnus-summary-highlight} \e$B$r%+%9%?%^%$%:\e(B
-\e$B$9$k$3$H$K$h$C$F!"%@%&%s%m!<%I$5$l$F$$$J$$5-;v$N%U%'!<%9$r40A4$KM^@)$9$k\e(B
-\e$B$3$H$,$G$-$^$9!#BhFs$K!"$b$C$H@vN}$5$l$?%"%W%m!<%A$,9%$_$J$i$P!"\e(B
-@code{agent-disable-undownloaded-faces} \e$B%0%k!<%W%Q%i%a!<%?$r\e(B t \e$B$K@_Dj$7\e(B
-\e$B$F$bNI$$$G$7$g$&!#$3$N%Q%i%a!<%?$OB>$N$9$Y$F$N%(!<%8%'%s%H%Q%i%a!<%?$HF1\e(B
-\e$BMM$K!"%(!<%8%'%s%HJ,N`\e(B (@pxref{Agent Categories})\e$B!"%0%k!<%W%H%T%C\e(B
-\e$B%/\e(B (@pxref{Topic Parameters})\e$B!"$"$k$$$O8D!9$N%0%k!<%W\e(B (@pxref{Group
-Parameters}) \e$B$KBP$7$F@_Dj$9$k$3$H$,$G$-$^$9!#\e(B
+\e$B$k\e(B) \e$B$r9T$J$($P!"$$$D$bDL>o$N%U%'!<%9$,8=$l$k$+$i$G$9!#\e(B@acronym{NOV} \e$B$r\e(B
+\e$B%-%c%C%7%e$9$k$3$H$K$h$C$F%*%s%i%$%s@-G=$r2~A1$9$k$?$a$K%(!<%8%'%s%H$r;H$C\e(B
+\e$B$F$$$k%f!<%6$K$H$C$F!"%@%&%s%m!<%I$5$l$F$$$J$$5-;v$N%U%'!<%9$,8+$($k$+$b\e(B
+\e$B$7$l$J$$$3$H$O!"$^$C$?$/$>$C$H$9$k$[$I$$$d$J$3$H$G$7$g$&!#$=$l$i$N$I$N5-\e(B
+\e$B;v$b%(!<%8%'%s%H$K<h$j9~$^$l$F$$$J$$$N$G!"%@%&%s%m!<%I$5$l$F$$$J$$5-;v$N\e(B
+\e$B%U%'!<%9$N$?$a$K!"$9$Y$F$NIaDL$N%U%'!<%9$,L\N)$?$J$/$J$C$F$7$^$&$G$7$g$&!#\e(B
+
+\e$B%@%&%s%m!<%I$5$l$F$$$J$$5-;v$N%U%'!<%9$r;H$$$?$$>l9g$O!"\e(B
+@code{agent-enable-undownloaded-faces} \e$B%0%k!<%W%Q%i%a!<%?$r\e(B @code{t} \e$B$K\e(B
+\e$B@_Dj$7$F!"%@%&%s%m!<%I$5$l$F$$$J$$5-;v$N%U%'!<%9$rM-8z$K$7$J$1$l$P$J$j$^\e(B
+\e$B$;$s!#$3$N%Q%i%a!<%?$OB>$N$9$Y$F$N%(!<%8%'%s%H%Q%i%a!<%?$HF1MM$K!"%(!<%8%'\e(B
+\e$B%s%HJ,N`\e(B (@pxref{Agent Categories})\e$B!"%0%k!<%W%H%T%C%/\e(B (@pxref{Topic
+Parameters})\e$B!"$"$k$$$O8D!9$N%0%k!<%W\e(B (@pxref{Group Parameters}) \e$B$KBP$7$F\e(B
+\e$B@_Dj$9$k$3$H$,$G$-$^$9!#\e(B
@node Agent as Cache
@subsection \e$B%-%c%C%7%e$H$7$F$N%(!<%8%'%s%H\e(B
@node Outgoing Messages
@subsection \e$B:9=PMQ%a%C%;!<%8\e(B
-Gnus \e$B$,@Z$jN%$5$l$F$$$k$H$-!"A4$F$N:9=PMQ%a%C%;!<%8\e(B (\e$B%a!<%k$H%K%e!<%9$N\e(B
-\e$BN>J}\e(B) \e$B$O2<=q$-%0%k!<%W\e(B ``queue'' (@pxref{Drafts}) \e$B$K3JG<$5$l$^$9!#Ej9F$7\e(B
-\e$B$?8e$G$b!"$3$3$G$=$N%a%C%;!<%8$r8+$?$jJT=8$9$k$N$O0U$N$^$^$G$9!#\e(B
+\e$B%G%#%U%)%k%H$G!"\e(BGnus \e$B$,@Z$jN%$5$l$F$$$k$H$-!"A4$F$N:9=PMQ%a%C%;!<%8\e(B (\e$B%a!<\e(B
+\e$B%k$H%K%e!<%9$NN>J}\e(B) \e$B$O2<=q$-%0%k!<%W\e(B ``queue'' (@pxref{Drafts}) \e$B$K3JG<$5\e(B
+\e$B$l$^$9!#Ej9F$7$?8e$G$b!"$3$3$G$=$N%a%C%;!<%8$r8+$?$jJT=8$9$k$N$O0U$N$^$^\e(B
+\e$B$G$9!#\e(B
-Gnus \e$B$,:F$S:9$79~$^$l$?$H$-!"%a%C%;!<%8$rAw?.$9$k$?$a$K!"FCJL$JL?Na$r;H$C\e(B
-\e$B$F2<=q$-%0%k!<%W$+$iAw$k$3$H$b!"%0%k!<%W%P%C%U%!Fb$G\e(B @kbd{J S} \e$B$r;H$C$F!"\e(B
-\e$B2<=q$-%0%k!<%WFb$NA4$F$NAw?.2DG=%a%C%;!<%8Aw?.$9$k$3$H$b$G$-$^$9!#\e(B
+\e$BAw=P$9$k%a!<%k$,\e(B queue \e$B$5$l$k\e(B (\e$B=gHVBT$A$K$J$k\e(B) \e$B>u67$r@)8f$9$k$3$H$O2DG=\e(B
+\e$B$G$9\e(B (@code{gnus-agent-queue-mail}, @pxref{Agent Variables} \e$B;2>H\e(B)\e$B!#\e(B
+Gnus \e$B$,@Z$jN%$5$l$F$$$k>l9g!"%K%e!<%9$O>o$K\e(B queue \e$B$5$l$k$@$1$G$9!#\e(B
+
+\e$B%a%C%;!<%8$rAw?.$9$k$?$a$K!"2<=q$-%0%k!<%W$+$i!"$=$3$G;H$($kFCJL$JL?Na$r\e(B
+\e$B;H$C$FAw$k$3$H$b!"%0%k!<%W%P%C%U%!Fb$G\e(B @kbd{J S} \e$B$r;H$C$F!"2<=q$-%0%k!<\e(B
+\e$B%WFb$N$9$Y$F$NAw?.2DG=$J%a%C%;!<%8Aw?.$9$k$3$H$b$G$-$^$9!#%K%e!<%9$NEj9F\e(B
+\e$B$O\e(B Gnus \e$B$,:9$79~$^$l$F$$$k$H$-$@$1$G$-$^$9$,!"%a!<%k$O$$$D$G$bAw?.$9$k$3\e(B
+\e$B$H$,$G$-$^$9!#\e(B
+
+\e$B@Z$jN%$5$l$F$$$k$H$-$K%a!<%k$NAw?.$,$G$-$:!"$+$D@Z$jN%$5$l$F$$$k$H$-$K$&$C\e(B
+\e$B$+$j\e(B @kbd{J S} \e$B$rC!$$$F$7$^$&$3$H$,?4G[$J$i$P!"\e(BGnus \e$B$K$"$J$?$N9TF0$r3NG'\e(B
+\e$B$5$;$k$3$H$,$G$-$^$9\e(B (@code{gnus-agent-prompt-send-queue}, @pxref{Agent
+Variables} \e$B;2>H\e(B)\e$B!#\e(B
@node Agent Variables
@subsection \e$B%(!<%8%'%s%HJQ?t\e(B
\e$B5-;v$r>o$KL5;k$9$k$3$H\e(B)\e$B!"\e(B@code{unfetched} (\e$BA`:n$O%X%C%@!<$,<h$j9~$^$l$F\e(B
\e$B$$$J$$5-;v$rL5;k$9$k$3$H\e(B) \e$B$G$9!#\e(B(\e$BLuCm\e(B: \e$B$&!<$`\e(B Kevin \e$B$5$s$O2?$r8@$C$F$k$s\e(B
\e$B$@\e(B?)
+
+@item gnus-agent-queue-mail
+@vindex gnus-agent-queue-mail
+@code{gnus-agent-queue-mail} \e$B$r\e(B @code{always} \e$B$K$9$k$H!"\e(BGnus \e$B$O%a!<%k$r\e(B
+\e$B$$$-$J$jAw?.$7$F$7$^$&$N$G$O$J$/!">o$K\e(B queue (\e$B=gHVBT$A\e(B) \e$B$KF~$l$^$9!#\e(B
+@code{t} \e$B$@$C$?$i\e(B Gnus \e$B$O@Z$jN%$5$l$F$$$k$H$-$@$1%a!<%k$r\e(B queue \e$B$KF~$l$^\e(B
+\e$B$9!#\e(B@code{nil} \e$B$@$C$?$i\e(B queue \e$B$KF~$l$^$;$s!#%G%#%U%)%k%H$O\e(B @code{t} \e$B$G$9!#\e(B
+
+@item gnus-agent-prompt-send-queue
+@vindex gnus-agent-prompt-send-queue
+@code{gnus-agent-prompt-send-queue} \e$B$,Hs\e(B-@code{nil} \e$B$@$C$?$i!"@Z$jN%$5$l\e(B
+\e$B$F$$$k$N$K$b$+$+$o$i$:\e(B @kbd{J S} \e$B$rC!$$$?>l9g$K!"\e(BGnus \e$B$OK\Ev$K$=$l$r9T$J$C\e(B
+\e$B$F$bNI$$$+$I$&$+$r3NG'$7$^$9!#%G%#%U%)%k%H$O\e(B @code{nil} \e$B$G$9!#\e(B
+
+@item gnus-agent-auto-agentize-methods
+@vindex gnus-agent-auto-agentize-methods
+\e$B$"$J$?$,0JA0$K%(!<%8%'%s%H$r;H$C$?$3$H$,L5$$\e(B (\e$B$b$C$H5;=QE*$K$O!"\e(B
+@file{~/News/agent/lib/servers} \e$B$,L5$$>l9g\e(B)\e$B!"\e(BGnus \e$B$O$[$s$N>/?t$N%5!<%P!<\e(B
+\e$B$r<+F0E*$K%(!<%8%'%s%H2=$7$^$9!#$3$NJQ?t$O$I$N%P%C%/%(%s%I$r<+F0$G%(!<%8%'\e(B
+\e$B%s%H2=$9$Y$-$+$r@)8f$7$^$9!#0lHL$K!"%(!<%8%'%s%H2=$O1s3V%P%C%/%(%s%I$@$1\e(B
+\e$B$KM-MQ$G$9!#<+F0$N%(!<%8%'%s%H2=$O!"%5!<%P!<$KBP$7$F\e(B @kbd{J a} \e$B$r<B9T$9\e(B
+\e$B$k$N$HF1$88z2L$,$"$j$^$9\e(B (@pxref{Server Agent Commands})\e$B!#$b$7%U%!%$%k$,\e(B
+\e$BB8:_$9$k$J$i$P!"$=$l$i$rDI2C$7$?$j:o=|$9$k$?$a$K%5!<%P!<$r<jF0$GA`:n$7$J\e(B
+\e$B$1$l$P$J$j$^$;$s!#$3$NJQ?t$O:G=i$K\e(B Gnus \e$B$r5/F0$7$?$H$-$@$1E,MQ$5$l$^$9!#\e(B
+\e$B%G%#%U%)%k%H$O\e(B @samp{(nntp nnimap)} \e$B$G$9!#\e(B
@end table
@node Example Setup
@cindex Agent Parameters
@table @code
-@item gnus-agent-cat-name
+@item agent-cat-name
The name of the category.
-@item gnus-agent-cat-groups
+@item agent-groups
The list of groups that are in this category.
-@item gnus-agent-cat-predicate
+@item agent-predicate
A predicate which (generally) gives a rough outline of which articles
are eligible for downloading; and
-@item gnus-agent-cat-score-file
+@item agent-score-file
a score rule which (generally) gives you a finer granularity when
deciding what articles to download. (Note that this @dfn{download
score} is not necessarily related to normal scores.)
-@item gnus-agent-cat-enable-expiration
+@item agent-enable-expiration
a boolean indicating whether the agent should expire old articles in
this group. Most groups should be expired to conserve disk space. In
fact, its probably safe to say that the gnus.* hierarchy contains the
only groups that should not be expired.
-@item gnus-agent-cat-days-until-old
+@item agent-days-until-old
an integer indicating the number of days that the agent should wait
before deciding that a read article is safe to expire.
-@item gnus-agent-cat-low-score
+@item agent-low-score
an integer that overrides the value of @code{gnus-agent-low-score}.
-@item gnus-agent-cat-high-score
+@item agent-high-score
an integer that overrides the value of @code{gnus-agent-high-score}.
-@item gnus-agent-cat-length-when-short
+@item agent-length-when-short
an integer that overrides the value of
@code{gnus-agent-short-article}.
-@item gnus-agent-cat-length-when-long
+@item agent-length-when-long
an integer that overrides the value of @code{gnus-agent-long-article}.
-@c @item gnus-agent-cat-disable-undownloaded-faces
-@c a symbol indicating whether the summary buffer should @emph{not} display
-@c undownloaded articles using the gnus-summary-*-undownloaded-face
-@c faces. The symbol nil will enable the use of undownloaded faces while
-@c all other symbols disable them.
-
-@item gnus-agent-cat-enable-undownloaded-faces
+@item agent-enable-undownloaded-faces
a symbol indicating whether the summary buffer should display
undownloaded articles using the gnus-summary-*-undownloaded-face
-faces. The symbol nil will disable the use of undownloaded faces while
-all other symbols enable them.
+faces. Any symbol other than nil will enable the use of undownloaded
+faces.
@end table
The name of a category can not be changed once the category has been
each time you visit it or to minimize your connection time), the
undownloaded face will probably seem like a good idea. The reason
being that you do all of our work (marking, reading, deleting) with
-downloaded articles so the normal faces always appear.
-
-For occasional Agent users, the undownloaded faces may appear to be an
-absolutely horrible idea. The issue being that, since most of their
-articles have not been fetched into the Agent, most of the normal
-faces will be obscured by the undownloaded faces. If this is your
-situation, you have two choices available. First, you can completely
-disable the undownload faces by customizing
-@code{gnus-summary-highlight} to delete the three cons-cells that
-refer to the @code{gnus-summary-*-undownloaded-face} faces. Second, if
-you prefer to take a more fine-grained approach, you may set the
-@code{agent-disable-undownloaded-faces} group parameter to t. This
-parameter, like all other agent parameters, may be set on an Agent
-Category (@pxref{Agent Categories}), a Group Topic (@pxref{Topic
-Parameters}), or an individual group (@pxref{Group Parameters}).
+downloaded articles so the normal faces always appear. For those
+users using the agent to improve online performance by caching the NOV
+database (most users since 5.10.2), the undownloaded faces may appear
+to be an absolutely horrible idea. The issue being that, since none
+of their articles have been fetched into the Agent, all of the
+normal faces will be obscured by the undownloaded faces.
+
+If you would like to use the undownloaded faces, you must enable the
+undownloaded faces by setting the @code{agent-enable-undownloaded-faces}
+group parameter to t. This parameter, like all other agent
+parameters, may be set on an Agent Category (@pxref{Agent
+Categories}), a Group Topic (@pxref{Topic Parameters}), or an
+individual group (@pxref{Group Parameters}).
@node Agent as Cache
@subsection Agent as Cache
@node Outgoing Messages
@subsection Outgoing Messages
-When Gnus is unplugged, all outgoing messages (both mail and news) are
-stored in the draft group ``queue'' (@pxref{Drafts}). You can view
-them there after posting, and edit them at will.
+By default, when Gnus is unplugged, all outgoing messages (both mail
+and news) are stored in the draft group ``queue'' (@pxref{Drafts}).
+You can view them there after posting, and edit them at will.
-When Gnus is plugged again, you can send the messages either from the
-draft group with the special commands available there, or you can use
-the @kbd{J S} command in the group buffer to send all the sendable
-messages in the draft group.
+You can control the circumstances under which outgoing mail is queued
+(see @code{gnus-agent-queue-mail}, @pxref{Agent Variables}). Outgoing
+news is always queued when Gnus is unplugged, and never otherwise.
+You can send the messages either from the draft group with the special
+commands available there, or you can use the @kbd{J S} command in the
+group buffer to send all the sendable messages in the draft group.
+Posting news will only work when Gnus is plugged, but you can send
+mail at any time.
+If sending mail while unplugged does not work for you and you worry
+about hitting @kbd{J S} by accident when unplugged, you can have Gnus
+ask you to confirm your action (see
+@code{gnus-agent-prompt-send-queue}, @pxref{Agent Variables}).
@node Agent Variables
@subsection Agent Variables
ignores articles that have not been fetched), @code{unfetched}
(maneuvering ignores articles whose headers have not been fetched).
+@item gnus-agent-queue-mail
+@vindex gnus-agent-queue-mail
+When @code{gnus-agent-queue-mail} is @code{always}, Gnus will always
+queue mail rather than sending it straight away. When @code{t}, Gnus
+will queue mail when unplugged only. When @code{nil}, never queue
+mail. The default is @code{t}.
+
+@item gnus-agent-prompt-send-queue
+@vindex gnus-agent-prompt-send-queue
+When @code{gnus-agent-prompt-send-queue} is non-@code{nil} Gnus will
+prompt you to confirm that you really wish to proceed if you hit
+@kbd{J S} while unplugged. The default is @code{nil}.
+
@item gnus-agent-auto-agentize-methods
@vindex gnus-agent-auto-agentize-methods
If you have never used the Agent before (or more technically, if