+ (let ((gnus-agent-confirmation-function 'gnus-agent-batch-confirmation))
+ (gnus-group-send-queue)
+ (gnus-agent-fetch-session)))
+
+(defun gnus-agent-retrieve-headers (articles group &optional fetch-old)
+ (save-excursion
+ (gnus-agent-create-buffer)
+ (let ((gnus-decode-encoded-word-function 'identity)
+ (file (gnus-agent-article-name ".overview" group))
+ cached-articles uncached-articles)
+ (gnus-make-directory (nnheader-translate-file-chars
+ (file-name-directory file) t))
+ (when (file-exists-p file)
+ (with-current-buffer gnus-agent-overview-buffer
+ (erase-buffer)
+ (let ((nnheader-file-coding-system
+ gnus-agent-file-coding-system))
+ (nnheader-insert-nov-file file (car articles)))
+ (nnheader-find-nov-line (car articles))
+ (while (not (eobp))
+ (when (looking-at "[0-9]")
+ (push (read (current-buffer)) cached-articles))
+ (forward-line 1))
+ (setq cached-articles (nreverse cached-articles))))
+ (if (setq uncached-articles
+ (gnus-sorted-difference articles cached-articles))
+ (progn
+ (set-buffer nntp-server-buffer)
+ (erase-buffer)
+ (let (gnus-agent-cache)
+ (unless (eq 'nov
+ (gnus-retrieve-headers
+ uncached-articles group fetch-old))
+ (nnvirtual-convert-headers)))
+ (set-buffer gnus-agent-overview-buffer)
+ (erase-buffer)
+ (set-buffer nntp-server-buffer)
+ (copy-to-buffer gnus-agent-overview-buffer (point-min) (point-max))
+ (when (and uncached-articles (file-exists-p file))
+ (gnus-agent-braid-nov group uncached-articles file))
+ (set-buffer nntp-server-buffer)
+ (let ((coding-system-for-write
+ gnus-agent-file-coding-system))
+ (write-region (point-min) (point-max) file nil 'silent))
+ (gnus-agent-load-alist group)
+ (gnus-agent-save-alist group uncached-articles nil)
+ (gnus-agent-open-history)
+ (setq gnus-agent-current-history (gnus-agent-history-buffer))
+ (gnus-agent-enter-history
+ "last-header-fetched-for-session"
+ (list (cons group (nth (- (length articles) 1) articles)))
+ (time-to-days (current-time)))
+ (gnus-agent-save-history))
+ (set-buffer nntp-server-buffer)
+ (erase-buffer)
+ (insert-buffer-substring gnus-agent-overview-buffer)))
+ (if (and fetch-old
+ (not (numberp fetch-old)))
+ t ; Don't remove anything.
+ (nnheader-nov-delete-outside-range
+ (if fetch-old (max 1 (- (car articles) fetch-old))
+ (car articles))
+ (car (last articles)))
+ t)
+ 'nov))
+
+(defun gnus-agent-request-article (article group)
+ "Retrieve ARTICLE in GROUP from the agent cache."
+ (let* ((gnus-command-method (gnus-find-method-for-group group))
+ (file (concat
+ (gnus-agent-directory)
+ (gnus-agent-group-path group) "/"
+ (number-to-string article)))
+ (buffer-read-only nil))
+ (when (and (file-exists-p file)
+ (> (nth 7 (file-attributes file)) 0))
+ (erase-buffer)
+ (gnus-kill-all-overlays)
+ (let ((coding-system-for-read gnus-cache-coding-system))
+ (insert-file-contents file))
+ t)))
+
+(defun gnus-agent-regenerate-group (group &optional clean)
+ "Regenerate GROUP."
+ (let ((dir (concat (gnus-agent-directory)
+ (gnus-agent-group-path group) "/"))
+ (file (gnus-agent-article-name ".overview" group))
+ n point arts alist header new-alist changed)
+ (when (file-exists-p dir)
+ (setq arts
+ (sort (mapcar (lambda (name) (string-to-int name))
+ (directory-files dir nil "^[0-9]+$" t))
+ '<)))
+ (gnus-make-directory (nnheader-translate-file-chars
+ (file-name-directory file) t))
+ (mm-with-unibyte-buffer
+ (if (file-exists-p file)
+ (let ((nnheader-file-coding-system
+ gnus-agent-file-coding-system))
+ (nnheader-insert-file-contents file)))
+ (goto-char (point-min))
+ (while (not (eobp))
+ (while (not (or (eobp) (looking-at "[0-9]")))
+ (setq point (point))
+ (forward-line 1)
+ (delete-region point (point)))
+ (unless (eobp)
+ (setq n (read (current-buffer)))
+ (when (and arts (> n (car arts)))
+ (beginning-of-line)
+ (while (and arts (> n (car arts)))
+ (message "Regenerating NOV %s %d..." group (car arts))
+ (mm-with-unibyte-buffer
+ (nnheader-insert-file-contents
+ (concat dir (number-to-string (car arts))))
+ (goto-char (point-min))
+ (if (search-forward "\n\n" nil t)
+ (delete-region (point) (point-max))
+ (goto-char (point-max)))
+ (setq header (nnheader-parse-head t)))
+ (mail-header-set-number header (car arts))
+ (nnheader-insert-nov header)
+ (setq changed t)
+ (push (cons (car arts) t) alist)
+ (pop arts)))
+ (if (and arts (= n (car arts)))
+ (progn
+ (push (cons n t) alist)
+ (pop arts))
+ (push (cons n nil) alist))
+ (forward-line 1)))
+ (if changed
+ (let ((coding-system-for-write gnus-agent-file-coding-system))
+ (write-region (point-min) (point-max) file nil 'silent))))
+ (setq gnus-agent-article-alist nil)
+ (unless clean
+ (gnus-agent-load-alist group))
+ (setq alist (sort alist 'car-less-than-car))
+ (setq gnus-agent-article-alist (sort gnus-agent-article-alist
+ 'car-less-than-car))
+ (while (and alist gnus-agent-article-alist)
+ (cond
+ ((< (caar alist) (caar gnus-agent-article-alist))
+ (push (pop alist) new-alist))
+ ((> (caar alist) (caar gnus-agent-article-alist))
+ (push (list (car (pop gnus-agent-article-alist))) new-alist))
+ (t
+ (pop gnus-agent-article-alist)
+ (while (and gnus-agent-article-alist
+ (= (caar alist) (caar gnus-agent-article-alist)))
+ (pop gnus-agent-article-alist))
+ (push (pop alist) new-alist))))
+ (while alist
+ (push (pop alist) new-alist))
+ (while gnus-agent-article-alist
+ (push (list (car (pop gnus-agent-article-alist))) new-alist))
+ (setq gnus-agent-article-alist (nreverse new-alist))
+ (gnus-agent-save-alist group)))
+
+(defun gnus-agent-regenerate-history (group article)
+ (let ((file (concat (gnus-agent-directory)
+ (gnus-agent-group-path group) "/"
+ (number-to-string article))) id)
+ (mm-with-unibyte-buffer
+ (nnheader-insert-file-contents file)
+ (message-narrow-to-head)
+ (goto-char (point-min))
+ (if (not (re-search-forward "^Message-ID: *<\\([^>\n]+\\)>" nil t))
+ (setq id "No-Message-ID-in-article")
+ (setq id (buffer-substring (match-beginning 1) (match-end 1))))
+ (gnus-agent-enter-history
+ id (list (cons group article))
+ (time-to-days (nth 5 (file-attributes file)))))))
+
+;;;###autoload
+(defun gnus-agent-regenerate (&optional clean)
+ "Regenerate all agent covered files.
+If CLEAN, don't read existing active and agentview files."
+ (interactive "P")
+ (message "Regenerating Gnus agent files...")
+ (dolist (gnus-command-method gnus-agent-covered-methods)
+ (let ((active-file (gnus-agent-lib-file "active"))
+ history-hashtb active-hashtb active-changed
+ history-changed point)
+ (gnus-make-directory (file-name-directory active-file))
+ (if clean
+ (setq active-hashtb (gnus-make-hashtable 1000))
+ (mm-with-unibyte-buffer
+ (if (file-exists-p active-file)
+ (let ((nnheader-file-coding-system
+ gnus-agent-file-coding-system))
+ (nnheader-insert-file-contents active-file))
+ (setq active-changed t))
+ (gnus-active-to-gnus-format
+ nil (setq active-hashtb
+ (gnus-make-hashtable
+ (count-lines (point-min) (point-max)))))))
+ (gnus-agent-open-history)
+ (setq history-hashtb (gnus-make-hashtable 1000))
+ (with-current-buffer
+ (setq gnus-agent-current-history (gnus-agent-history-buffer))
+ (goto-char (point-min))
+ (forward-line 1)
+ (while (not (eobp))
+ (if (looking-at
+ "\\([^\t\n]+\\)\t[0-9]+\t\\([^ \n]+\\) \\([0-9]+\\)")
+ (progn
+ (unless (string= (match-string 1)
+ "last-header-fetched-for-session")
+ (gnus-sethash (match-string 2)
+ (cons (string-to-number (match-string 3))
+ (gnus-gethash-safe (match-string 2)
+ history-hashtb))
+ history-hashtb))
+ (forward-line 1))
+ (setq point (point))
+ (forward-line 1)
+ (delete-region point (point))
+ (setq history-changed t))))
+ (dolist (group (gnus-groups-from-server gnus-command-method))
+ (gnus-agent-regenerate-group group clean)
+ (let ((min (or (caar gnus-agent-article-alist) 1))
+ (max (or (caar (last gnus-agent-article-alist)) 0))
+ (active (gnus-gethash-safe (gnus-group-real-name group)
+ active-hashtb)))
+ (if (not active)
+ (progn
+ (setq active (cons min max)
+ active-changed t)
+ (gnus-sethash group active active-hashtb))
+ (when (> (car active) min)
+ (setcar active min)
+ (setq active-changed t))
+ (when (< (cdr active) max)
+ (setcdr active max)
+ (setq active-changed t))))
+ (let ((arts (sort (gnus-gethash-safe group history-hashtb) '<))
+ n)
+ (gnus-sethash group arts history-hashtb)
+ (while (and arts gnus-agent-article-alist)
+ (cond
+ ((> (car arts) (caar gnus-agent-article-alist))
+ (when (cdar gnus-agent-article-alist)
+ (gnus-agent-regenerate-history
+ group (caar gnus-agent-article-alist))
+ (setq history-changed t))
+ (setq n (car (pop gnus-agent-article-alist)))
+ (while (and gnus-agent-article-alist
+ (= n (caar gnus-agent-article-alist)))
+ (pop gnus-agent-article-alist)))
+ ((< (car arts) (caar gnus-agent-article-alist))
+ (setq n (pop arts))
+ (while (and arts (= n (car arts)))
+ (pop arts)))
+ (t
+ (setq n (car (pop gnus-agent-article-alist)))
+ (while (and gnus-agent-article-alist
+ (= n (caar gnus-agent-article-alist)))
+ (pop gnus-agent-article-alist))
+ (setq n (pop arts))
+ (while (and arts (= n (car arts)))
+ (pop arts)))))
+ (while gnus-agent-article-alist
+ (when (cdar gnus-agent-article-alist)
+ (gnus-agent-regenerate-history
+ group (caar gnus-agent-article-alist))
+ (setq history-changed t))
+ (pop gnus-agent-article-alist))))
+ (when history-changed
+ (message "Regenerate the history file of %s:%s"
+ (car gnus-command-method)
+ (cadr gnus-command-method))
+ (gnus-agent-save-history))
+ (gnus-agent-close-history)
+ (when active-changed
+ (message "Regenerate %s" active-file)
+ (let ((nnmail-active-file-coding-system gnus-agent-file-coding-system))
+ (gnus-write-active-file active-file active-hashtb)))))
+ (message "Regenerating Gnus agent files...done"))
+
+(defun gnus-agent-go-online (&optional force)
+ "Switch servers into online status."
+ (interactive (list t))
+ (dolist (server gnus-opened-servers)
+ (when (eq (nth 1 server) 'offline)
+ (if (if (eq force 'ask)
+ (gnus-y-or-n-p
+ (format "Switch %s:%s into online status? "
+ (caar server) (cadar server)))
+ force)
+ (setcar (nthcdr 1 server) 'close)))))
+
+(defun gnus-agent-toggle-group-plugged (group)
+ "Toggle the status of the server of the current group."
+ (interactive (list (gnus-group-group-name)))
+ (let* ((method (gnus-find-method-for-group group))
+ (status (cadr (assoc method gnus-opened-servers))))
+ (if (eq status 'offline)
+ (gnus-server-set-status method 'closed)
+ (gnus-close-server method)
+ (gnus-server-set-status method 'offline))
+ (message "Turn %s:%s from %s to %s." (car method) (cadr method)
+ (if (eq status 'offline) 'offline 'online)
+ (if (eq status 'offline) 'online 'offline))))