+2003-11-20 Kevin Greiner <kgreiner@xpediantsolutions.com>
+
+ * gnus.el (gnus-agent-covered-methods): Documented use of
+ named servers, not methods, to identity agentized groups.
+ Users may now change their server configurations without having
+ the server become "unagentized".
+ (gnus-agent-covered-methods): Removed from gnus-variable-list to
+ avoid storing two copies of gnus-agent-covered-methods, one in
+ .newsrc.eld and the other in agent/lib/servers.
+ (gnus-server-to-method): Do not cache server for the nil method.
+ (gnus-method-to-server): New function. Associate named server
+ with all, even foreign, methods.
+ (gnus-agent-method-p, gnus-agent-method-p-cache): Incorporated
+ simple last-response cache to offset performance lose of having to
+ always convert methods to named servers.
+ * gnus-agent.el (gnus-agent-expire-days): Removed obsolete
+ documentation.
+ (gnus-agentize, gnus-agent-add-server, gnus-agent-remove-server):
+ Modified to support new definition of gnus-agent-covered-method.
+ (gnus-agent-read-servers): Rewritten to convert old method data
+ into server names.
+ (gnus-agent-read-servers-validate)
+ (gnus-agent-read-servers-validate-native): New functions.
+ (gnus-agent-write-servers): No longer use gnus-method-simplify as
+ it failed to simplify foreign methods.
+ (gnus-agent-close-connections, gnus-agent-synchronize-flags)
+ (gnus-agent-possibly-synchronize-flags, gnus-agent-fetch-session)
+ (gnus-agent-regenerate): Uses new gnus-agent-covered-methods
+ function as gnus-agent-covered-methods variable no longer provides
+ methods.
+ (gnus-agent-covered-methods): New function
+ (gnus-agent-expire-group, gnus-agent-expire): Final message will,
+ if gnus-verbose is greater than 4, report statistics of NOV
+ entries and files deleted as well as total bytes recovered.
+ (gnus-agent-expire-done-message): New function
+ (gnus-agent-unread-articles): Bug fix. No longer drops last
+ unread article onto read list.
+ (gnus-agent-regenerate-group): Changed prompt to use typical
+ style.
+ (gnus-agent-group-covered-p): Rewrote to internally use
+ gnus-agent-method-p.
+ * gnus-int.el (gnus-start-news-server): Partially convert old
+ gnus-agent-covered-methods to new format so that gnus-open-server
+ functions correctly.
+ * gnus-srvr.el (gnus-server-insert-server-line): Replaced
+ gnus-agent-covered-methods with gnus-agent-method-p.
+ * gnus-start.el (gnus-clear-system): Added
+ gnus-agent-covered-methods to compensate for removing it from
+ gnus-variable-list.
+ (gnus-setup-news): Complete conversion of old
+ gnus-agent-covered-methods to new format so that secondary and
+ foreign servers can be correctly opened.
+
2003-11-20 Teodor Zlatanov <tzz@lifelogs.com>
* spam.el (spam-ham-copy-or-move-routine): add respooling
:type 'integer)
(defcustom gnus-agent-expire-days 7
- "Read articles older than this will be expired.
-This can also be a list of regexp/day pairs. The regexps will be
-matched against group names."
+ "Read articles older than this will be expired."
:group 'gnus-agent
- :type '(choice (number :tag "days")
- (sexp :tag "List" nil)))
+ :type '(number :tag "days"))
(defcustom gnus-agent-expire-all nil
"If non-nil, also expire unread, ticked and dormant articles.
(defun gnus-agent-close-connections ()
"Close all methods covered by the Gnus agent."
- (let ((methods gnus-agent-covered-methods))
+ (let ((methods (gnus-agent-covered-methods)))
(while methods
(gnus-close-server (pop methods)))))
(unless gnus-agent-send-mail-function
(setq gnus-agent-send-mail-function
(or message-send-mail-real-function
- message-send-mail-function)
+ message-send-mail-function)
message-send-mail-real-function 'gnus-agent-send-mail))
(unless gnus-agent-covered-methods
- (mapcar
- (lambda (server)
- (if (memq (car (gnus-server-to-method server))
- gnus-agent-auto-agentize-methods)
- (setq gnus-agent-covered-methods
- (cons (gnus-server-to-method server)
- gnus-agent-covered-methods ))))
- (append (list gnus-select-method) gnus-secondary-select-methods))))
+ (mapc
+ (lambda (server-or-method)
+ (let ((method (gnus-server-to-method server-or-method)))
+ (when (memq (car method)
+ gnus-agent-auto-agentize-methods)
+ (push (gnus-method-to-server method)
+ gnus-agent-covered-methods)
+ (setq gnus-agent-method-p-cache nil))))
+ (cons gnus-select-method gnus-secondary-select-methods))))
(defun gnus-agent-queue-setup (&optional group-name)
"Make sure the queue group exists.
"Synchronize unplugged flags with servers."
(interactive)
(save-excursion
- (dolist (gnus-command-method gnus-agent-covered-methods)
+ (dolist (gnus-command-method (gnus-agent-covered-methods))
(when (file-exists-p (gnus-agent-lib-file "flags"))
(gnus-agent-synchronize-flags-server gnus-command-method)))))
"Synchronize flags according to `gnus-agent-synchronize-flags'."
(interactive)
(save-excursion
- (dolist (gnus-command-method gnus-agent-covered-methods)
+ (dolist (gnus-command-method (gnus-agent-covered-methods))
(when (file-exists-p (gnus-agent-lib-file "flags"))
(gnus-agent-possibly-synchronize-flags-server gnus-command-method)))))
(let ((method (gnus-server-get-method nil (gnus-server-server-name))))
(when (gnus-agent-method-p method)
(error "Server already in the agent program"))
- (push method gnus-agent-covered-methods)
+ (push (gnus-method-to-server method) gnus-agent-covered-methods)
+ (setq gnus-agent-method-p-cache nil)
(gnus-server-update-server server)
(gnus-agent-write-servers)
(gnus-message 1 "Entered %s into the Agent" server)))
(interactive (list (gnus-server-server-name)))
(unless server
(error "No server on the current line"))
- (let ((method (gnus-server-get-method nil (gnus-server-server-name))))
- (unless (gnus-agent-method-p method)
+ (let* ((server (gnus-server-server-name)))
+ (unless (member server gnus-agent-covered-methods)
(error "Server not in the agent program"))
- (setq gnus-agent-covered-methods
- (delete method gnus-agent-covered-methods))
+ (setq gnus-agent-covered-methods
+ (delete server gnus-agent-covered-methods)
+ gnus-agent-method-p-cache nil)
+
(gnus-server-update-server server)
(gnus-agent-write-servers)
(gnus-message 1 "Removed %s from the agent" server)))
(defun gnus-agent-read-servers ()
"Read the alist of covered servers."
- (mapcar (lambda (m)
- (let ((method (gnus-server-get-method
- nil
- (or m "native"))))
- (if method
- (unless (member method gnus-agent-covered-methods)
- (push method gnus-agent-covered-methods))
- (gnus-message 1 "Ignoring disappeared server `%s'" m))))
- (gnus-agent-read-file
- (nnheader-concat gnus-agent-directory "lib/servers"))))
+ (setq gnus-agent-covered-methods
+ (gnus-agent-read-file
+ (nnheader-concat gnus-agent-directory "lib/servers"))
+ gnus-agent-method-p-cache nil)
+
+ ;; I am called so early in start-up that I can not validate server
+ ;; names. When that is the case, I skip the validation. That is
+ ;; alright as the gnus startup code calls the validate methods
+ ;; directly.
+ (if gnus-server-alist
+ (gnus-agent-read-servers-validate)))
+
+(defun gnus-agent-read-servers-validate ()
+ (mapcar (lambda (server-or-method)
+ (let* ((server (if (stringp server-or-method)
+ server-or-method
+ (gnus-method-to-server server-or-method)))
+ (method (gnus-server-to-method server)))
+ (if method
+ (unless (member server gnus-agent-covered-methods)
+ (push server gnus-agent-covered-methods)
+ (setq gnus-agent-method-p-cache nil))
+ (gnus-message 1 "Ignoring disappeared server `%s'" server))))
+ (prog1 gnus-agent-covered-methods
+ (setq gnus-agent-covered-methods nil))))
+
+(defun gnus-agent-read-servers-validate-native (native-method)
+ (setq gnus-agent-covered-methods
+ (mapcar (lambda (method)
+ (if (or (not method)
+ (equal method native-method))
+ "native"
+ method)) gnus-agent-covered-methods)))
(defun gnus-agent-write-servers ()
"Write the alist of covered servers."
(file-name-coding-system nnmail-pathname-coding-system)
(pathname-coding-system nnmail-pathname-coding-system))
(with-temp-file (nnheader-concat gnus-agent-directory "lib/servers")
- (prin1 (mapcar 'gnus-method-simplify gnus-agent-covered-methods)
+ (prin1 gnus-agent-covered-methods
(current-buffer)))))
;;;
(require 'nnagent)
'nnagent))
+(defun gnus-agent-covered-methods ()
+ "Return the subset of methods that are covered by the agent."
+ (mapcar #'gnus-server-to-method gnus-agent-covered-methods))
+
;;; History functions
(defun gnus-agent-history-buffer ()
(error "No servers are covered by the Gnus agent"))
(unless gnus-plugged
(error "Can't fetch articles while Gnus is unplugged"))
- (let ((methods gnus-agent-covered-methods)
+ (let ((methods (gnus-agent-covered-methods))
groups group gnus-command-method)
(save-excursion
(while methods
(if (not group)
(gnus-agent-expire articles group force)
- (if (or (not (eq articles t))
- (yes-or-no-p
- (concat "Are you sure that you want to "
- "expire all articles in " group ".")))
- (let ((gnus-command-method (gnus-find-method-for-group group))
- (overview (gnus-get-buffer-create " *expire overview*"))
- orig)
- (unwind-protect
- (let ((active-file (gnus-agent-lib-file "active")))
- (when (file-exists-p active-file)
- (with-temp-buffer
- (nnheader-insert-file-contents active-file)
- (gnus-active-to-gnus-format
- gnus-command-method
- (setq orig (gnus-make-hashtable
- (count-lines (point-min) (point-max))))))
- (save-excursion
- (gnus-agent-expire-group-1
- group overview (gnus-gethash-safe group orig)
- articles force))
- (gnus-agent-write-active active-file orig t)))
- (kill-buffer overview))))
- (gnus-message 4 "Expiry...done")))
+ (let ( ;; Bind gnus-agent-expire-stats to enable tracking of
+ ;; expiration statistics of this single group
+ (gnus-agent-expire-stats (list 0 0 0.0)))
+ (if (or (not (eq articles t))
+ (yes-or-no-p
+ (concat "Are you sure that you want to "
+ "expire all articles in " group ".")))
+ (let ((gnus-command-method (gnus-find-method-for-group group))
+ (overview (gnus-get-buffer-create " *expire overview*"))
+ orig)
+ (unwind-protect
+ (let ((active-file (gnus-agent-lib-file "active")))
+ (when (file-exists-p active-file)
+ (with-temp-buffer
+ (nnheader-insert-file-contents active-file)
+ (gnus-active-to-gnus-format
+ gnus-command-method
+ (setq orig (gnus-make-hashtable
+ (count-lines (point-min) (point-max))))))
+ (save-excursion
+ (gnus-agent-expire-group-1
+ group overview (gnus-gethash-safe group orig)
+ articles force))
+ (gnus-agent-write-active active-file orig t)))
+ (kill-buffer overview))))
+ (gnus-message 4 (gnus-agent-expire-done-message)))))
(defun gnus-agent-expire-group-1 (group overview active articles force)
;; Internal function - requires caller to have set
(gnus-message 5 "Expiry skipping over %s" group)
(gnus-message 5 "Expiring articles in %s" group)
(gnus-agent-load-alist group)
- (let* ((info (gnus-get-info group))
+ (let* ((stats (if (boundp 'gnus-agent-expire-stats)
+ ;; Use the list provided by my caller
+ (symbol-value 'gnus-agent-expire-stats)
+ ;; otherwise use my own temporary list
+ (list 0 0 0.0)))
+ (info (gnus-get-info group))
(alist gnus-agent-article-alist)
(day (- (time-to-days (current-time))
(gnus-agent-find-parameter group 'agent-days-until-old)))
(cons (caar alist)
(caar (last alist))))
(sort articles '<)))))
- (marked ;; More articles that are exluded from the
+ (marked ;; More articles that are excluded from the
;; expiration process
(cond (gnus-agent-expire-all
;; All articles are unmarked by global decree
;; Kept articles are unread, marked, or special.
(keep
(gnus-agent-message 10
- "gnus-agent-expire: Article %d: Kept %s article."
- article-number keep)
+ "gnus-agent-expire: Article %d: Kept %s article%s."
+ article-number keep (if fetch-date " and file" ""))
(when fetch-date
(unless (file-exists-p
(concat dir (number-to-string
(let ((actions nil))
(when (memq type '(forced expired))
(ignore-errors ; Just being paranoid.
- (delete-file (concat dir (number-to-string
- article-number)))
+ (let ((file-name (concat dir (number-to-string
+ article-number))))
+ (incf (nth 2 stats) (nth 7 (file-attributes file-name)))
+ (incf (nth 1 stats))
+ (delete-file file-name))
(push "expired cached article" actions))
(setf (nth 1 entry) nil)
)
(when marker
(push "NOV entry removed" actions)
(goto-char marker)
- (gnus-delete-line))
+
+ (incf (nth 0 stats))
+
+ (let ((from (gnus-point-at-bol))
+ (to (progn (forward-line 1) (point))))
+ (incf (nth 2 stats) (- to from))
+ (delete-region from to)))
;; If considering all articles is set, I can only
;; expire article IDs that are no longer in the
(if (or (not (eq articles t))
(yes-or-no-p "Are you sure that you want to expire all \
articles in every agentized group."))
- (let ((methods gnus-agent-covered-methods)
+ (let ((methods (gnus-agent-covered-methods))
;; Bind gnus-agent-expire-current-dirs to enable tracking
;; of agent directories.
(gnus-agent-expire-current-dirs nil)
+ ;; Bind gnus-agent-expire-stats to enable tracking of
+ ;; expiration statistics across all groups
+ (gnus-agent-expire-stats (list 0 0 0.0))
gnus-command-method overview orig)
(setq overview (gnus-get-buffer-create " *expire overview*"))
(unwind-protect
(gnus-agent-write-active active-file orig t))))
(kill-buffer overview))
(gnus-agent-expire-unagentized-dirs)
- (gnus-message 4 "Expiry...done")))))
+ (gnus-message 4 (gnus-agent-expire-done-message))))))
+
+(defun gnus-agent-expire-done-message ()
+ (if (and (> gnus-verbose 4)
+ (boundp 'gnus-agent-expire-stats))
+ (let* ((stats (symbol-value 'gnus-agent-expire-stats))
+ (size (nth 2 stats))
+ (units '(B KB MB GB)))
+ (while (and (> size 1024.0)
+ (cdr units))
+ (setq size (/ size 1024.0)
+ units (cdr units)))
+
+ (format "Expiry recovered %d NOV entries, deleted %d files,\
+ and freed %f %s."
+ (nth 0 stats)
+ (nth 1 stats)
+ size (car units)))
+ "Expiry...done"))
(defun gnus-agent-expire-unagentized-dirs ()
(when (and gnus-agent-expire-unagentized-dirs
(gnus-agent-append-to-list tail-unread candidate)
nil)
((> candidate max)
- (setq read (cdr read))))))))
+ (setq read (cdr read))
+ ;; return t so that I always loop one more
+ ;; time. If I just iterated off the end of
+ ;; read, min will become nil and the current
+ ;; candidate will be added to the unread list.
+ t))))))
(while known
(gnus-agent-append-to-list tail-unread (car (pop known))))
(cdr unread)))
def)
def
select)))
- (intern-soft
- (read-string
- "Reread (nil)? (t=>all, nil=>none, some=>all downloaded): "))))
+ (catch 'mark
+ (while (let ((c (read-char-exclusive
+ "Mark as unread: (n)one / (a)ll / all (d)ownloaded articles? (n)"
+ )))
+ (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")
+ (sit-for 1)
+ t)))))
(gnus-message 5 "Regenerating in %s" group)
(let* ((gnus-command-method (or gnus-command-method
(gnus-find-method-for-group group)))
(interactive "P")
(let (regenerated)
(gnus-message 4 "Regenerating Gnus agent files...")
- (dolist (gnus-command-method gnus-agent-covered-methods)
+ (dolist (gnus-command-method (gnus-agent-covered-methods))
(let ((active-file (gnus-agent-lib-file "active"))
active-hashtb active-changed
point)
(if (eq status 'offline) 'online 'offline))))
(defun gnus-agent-group-covered-p (group)
- (member (gnus-group-method group)
- gnus-agent-covered-methods))
+ (gnus-agent-method-p (gnus-group-method group)))
(add-hook 'gnus-group-prepare-hook
(lambda ()
(defvar gnus-agent-gcc-header "X-Gnus-Agent-Gcc")
(defvar gnus-agent-meta-information-header "X-Gnus-Agent-Meta-Information")
+(defvar gnus-agent-method-p-cache nil
+ ; Reset each time gnus-agent-covered-methods is changed else
+ ; gnus-agent-method-p may mis-report a methods status.
+ )
(defvar gnus-agent-target-move-group-header "X-Gnus-Agent-Move-To")
(defvar gnus-draft-meta-information-header "X-Draft-From")
(defvar gnus-group-get-parameter-function 'gnus-group-get-parameter)
(defvar gnus-agent-fetching nil
"Whether Gnus agent is in fetching mode.")
-(defvar gnus-agent-covered-methods nil)
+(defvar gnus-agent-covered-methods nil
+ "A list of servers, NOT methods, showing which servers are covered by the agent.")
(defvar gnus-command-method nil
"Dynamically bound variable that says what the current back end is.")
gnus-newsrc-last-checked-date
gnus-newsrc-alist gnus-server-alist
gnus-killed-list gnus-zombie-list
- gnus-topic-topology gnus-topic-alist
- gnus-agent-covered-methods)
+ gnus-topic-topology gnus-topic-alist)
"Gnus variables saved in the quick startup file.")
(defvar gnus-product-variable-file-list
(cadar servers)))))
(pop servers))
(car servers)))))
- (push (cons server result) gnus-server-method-cache)
+ (when result
+ (push (cons server result) gnus-server-method-cache))
result)))
+(defsubst gnus-method-to-server (method)
+ (catch 'server-name
+ (setq method (or method gnus-select-method))
+
+ ;; Perhaps it is already in the cache.
+ (mapc (lambda (name-method)
+ (if (equal (cdr name-method) method)
+ (throw 'server-name (car name-method))))
+ gnus-server-method-cache)
+
+ (mapc
+ (lambda (server-alist)
+ (mapc (lambda (name-method)
+ (when (gnus-methods-equal-p (cdr name-method) method)
+ (unless (member name-method gnus-server-method-cache)
+ (push name-method gnus-server-method-cache))
+ (throw 'server-name (car name-method))))
+ server-alist))
+ (let ((alists (list gnus-server-alist
+ gnus-predefined-server-alist)))
+ (if gnus-select-method
+ (push (list (cons "native" gnus-select-method)) alists))
+ alists))
+
+ (let* ((name (if (member (cadr method) '(nil ""))
+ (format "%s" (car method))
+ (format "%s:%s" (car method) (cadr method))))
+ (name-method (cons name method)))
+ (unless (member name-method gnus-server-method-cache)
+ (push name-method gnus-server-method-cache))
+ name)))
+
(defsubst gnus-server-get-method (group method)
;; Input either a server name, and extended server name, or a
;; select method, and return a select method.
(defun gnus-agent-method-p (method)
"Say whether METHOD is covered by the agent."
- (member method gnus-agent-covered-methods))
+ (or (eq (car gnus-agent-method-p-cache) method)
+ (setq gnus-agent-method-p-cache
+ (cons method
+ (member (gnus-method-to-server method) gnus-agent-covered-methods))))
+ (cdr gnus-agent-method-p-cache))
(defun gnus-online (method)
(not