1 ;;; gnus-agent.el --- unplugged support for Gnus
2 ;; Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002
3 ;; Free Software Foundation, Inc.
5 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
6 ;; This file is part of GNU Emacs.
8 ;; GNU Emacs is free software; you can redistribute it and/or modify
9 ;; it under the terms of the GNU General Public License as published by
10 ;; the Free Software Foundation; either version 2, or (at your option)
13 ;; GNU Emacs is distributed in the hope that it will be useful,
14 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 ;; GNU General Public License for more details.
18 ;; You should have received a copy of the GNU General Public License
19 ;; along with GNU Emacs; see the file COPYING. If not, write to the
20 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 ;; Boston, MA 02111-1307, USA.
34 (if (featurep 'xemacs)
40 (autoload 'gnus-server-update-server "gnus-srvr"))
42 (defcustom gnus-agent-directory (nnheader-concat gnus-directory "agent/")
43 "Where the Gnus agent will store its files."
47 (defcustom gnus-agent-plugged-hook nil
48 "Hook run when plugging into the network."
52 (defcustom gnus-agent-unplugged-hook nil
53 "Hook run when unplugging from the network."
57 (defcustom gnus-agent-handle-level gnus-level-subscribed
58 "Groups on levels higher than this variable will be ignored by the Agent."
62 (defcustom gnus-agent-expire-days 7
63 "Read articles older than this will be expired.
64 This can also be a list of regexp/day pairs. The regexps will
65 be matched against group names."
69 (defcustom gnus-agent-expire-all nil
70 "If non-nil, also expire unread, ticked and dormant articles.
71 If nil, only read articles will be expired."
75 (defcustom gnus-agent-group-mode-hook nil
76 "Hook run in Agent group minor modes."
80 ;; Extracted from gnus-xmas-redefine in order to preserve user settings
81 (when (featurep 'xemacs)
82 (add-hook 'gnus-agent-group-mode-hook 'gnus-xmas-agent-group-menu-add))
84 (defcustom gnus-agent-summary-mode-hook nil
85 "Hook run in Agent summary minor modes."
89 ;; Extracted from gnus-xmas-redefine in order to preserve user settings
90 (when (featurep 'xemacs)
91 (add-hook 'gnus-agent-summary-mode-hook 'gnus-xmas-agent-summary-menu-add))
93 (defcustom gnus-agent-server-mode-hook nil
94 "Hook run in Agent summary minor modes."
98 ;; Extracted from gnus-xmas-redefine in order to preserve user settings
99 (when (featurep 'xemacs)
100 (add-hook 'gnus-agent-server-mode-hook 'gnus-xmas-agent-server-menu-add))
102 (defcustom gnus-agent-confirmation-function 'y-or-n-p
103 "Function to confirm when error happens."
108 (defcustom gnus-agent-synchronize-flags 'ask
109 "Indicate if flags are synchronized when you plug in.
110 If this is `ask' the hook will query the user."
112 :type '(choice (const :tag "Always" t)
113 (const :tag "Never" nil)
114 (const :tag "Ask" ask))
117 (defcustom gnus-agent-go-online 'ask
118 "Indicate if offline servers go online when you plug in.
119 If this is `ask' the hook will query the user."
121 :type '(choice (const :tag "Always" t)
122 (const :tag "Never" nil)
123 (const :tag "Ask" ask))
126 (defcustom gnus-agent-mark-unread-after-downloaded t
127 "Indicate whether to mark articles unread after downloaded."
132 (defcustom gnus-agent-download-marks '(download)
133 "Marks for downloading."
135 :type '(repeat (symbol :tag "Mark"))
138 (defcustom gnus-agent-consider-all-articles nil
139 "If non-nil, consider also the read articles for downloading."
144 (defcustom gnus-agent-max-fetch-size 10000000 ;; 10 Mb
145 "Chunk size for `gnus-agent-fetch-session'.
146 The function will split its article fetches into chunks smaller than
151 ;;; Internal variables
153 (defvar gnus-agent-history-buffers nil)
154 (defvar gnus-agent-buffer-alist nil)
155 (defvar gnus-agent-article-alist nil
156 "An assoc list identifying the articles whose headers have been fetched.
157 If successfully fetched, these headers will be stored in the group's overview
158 file. The key of each assoc pair is the article ID, the value of each assoc
159 pair is a flag indicating whether the identified article has been downloaded
160 \(gnus-agent-fetch-articles sets the value to the day of the download).
162 1) The last element of this list can not be expired as some
163 routines (for example, get-agent-fetch-headers) use the last
164 value to track which articles have had their headers retrieved.
165 2) The gnus-agent-regenerate may destructively modify the value.
167 (defvar gnus-agent-group-alist nil)
168 (defvar gnus-category-alist nil)
169 (defvar gnus-agent-current-history nil)
170 (defvar gnus-agent-overview-buffer nil)
171 (defvar gnus-category-predicate-cache nil)
172 (defvar gnus-category-group-cache nil)
173 (defvar gnus-agent-spam-hashtb nil)
174 (defvar gnus-agent-file-name nil)
175 (defvar gnus-agent-send-mail-function nil)
176 (defvar gnus-agent-file-coding-system 'raw-text)
177 (defvar gnus-agent-file-loading-cache nil)
178 (defvar gnus-agent-file-header-cache nil)
180 (defvar gnus-agent-auto-agentize-methods '(nntp nnimap)
181 "Initially, all servers from these methods are agentized.
182 The user may remove or add servers using the Server buffer. See Info
183 node `(gnus)Server Buffer'.")
186 (defvar gnus-headers)
193 (defun gnus-open-agent ()
195 (gnus-agent-read-servers)
197 (gnus-agent-create-buffer)
198 (add-hook 'gnus-group-mode-hook 'gnus-agent-mode)
199 (add-hook 'gnus-summary-mode-hook 'gnus-agent-mode)
200 (add-hook 'gnus-server-mode-hook 'gnus-agent-mode))
202 (defun gnus-agent-create-buffer ()
203 (if (gnus-buffer-live-p gnus-agent-overview-buffer)
205 (setq gnus-agent-overview-buffer
206 (gnus-get-buffer-create " *Gnus agent overview*"))
207 (with-current-buffer gnus-agent-overview-buffer
208 (mm-enable-multibyte))
211 (gnus-add-shutdown 'gnus-close-agent 'gnus)
213 (defun gnus-close-agent ()
214 (setq gnus-category-predicate-cache nil
215 gnus-category-group-cache nil
216 gnus-agent-spam-hashtb nil)
217 (gnus-kill-buffer gnus-agent-overview-buffer))
220 ;;; Utility functions
223 (defun gnus-agent-read-file (file)
224 "Load FILE and do a `read' there."
227 (nnheader-insert-file-contents file)
228 (goto-char (point-min))
229 (read (current-buffer)))))
231 (defsubst gnus-agent-method ()
232 (concat (symbol-name (car gnus-command-method)) "/"
233 (if (equal (cadr gnus-command-method) "")
235 (cadr gnus-command-method))))
237 (defsubst gnus-agent-directory ()
238 "The name of the Gnus agent directory."
239 (nnheader-concat gnus-agent-directory
240 (nnheader-translate-file-chars (gnus-agent-method)) "/"))
242 (defun gnus-agent-lib-file (file)
243 "The full name of the Gnus agent library FILE."
244 (expand-file-name file
245 (file-name-as-directory
246 (expand-file-name "agent.lib" (gnus-agent-directory)))))
248 ;;; Fetching setup functions.
250 (defun gnus-agent-start-fetch ()
251 "Initialize data structures for efficient fetching."
252 (gnus-agent-create-buffer))
254 (defun gnus-agent-stop-fetch ()
255 "Save all data structures and clean up."
256 (setq gnus-agent-spam-hashtb nil)
258 (set-buffer nntp-server-buffer)
261 (defmacro gnus-agent-with-fetch (&rest forms)
264 (let ((gnus-agent-fetching t))
265 (gnus-agent-start-fetch)
267 (gnus-agent-stop-fetch)))
269 (put 'gnus-agent-with-fetch 'lisp-indent-function 0)
270 (put 'gnus-agent-with-fetch 'edebug-form-spec '(body))
272 (defmacro gnus-agent-append-to-list (tail value)
273 `(setq ,tail (setcdr ,tail (cons ,value nil))))
279 (defvar gnus-agent-mode-hook nil
280 "Hook run when installing agent mode.")
282 (defvar gnus-agent-mode nil)
283 (defvar gnus-agent-mode-status '(gnus-agent-mode " Plugged"))
285 (defun gnus-agent-mode ()
286 "Minor mode for providing a agent support in Gnus buffers."
287 (let* ((buffer (progn (string-match "^gnus-\\(.*\\)-mode$"
288 (symbol-name major-mode))
289 (match-string 1 (symbol-name major-mode))))
290 (mode (intern (format "gnus-agent-%s-mode" buffer))))
291 (set (make-local-variable 'gnus-agent-mode) t)
293 (set (make-local-variable mode) t)
295 (when (gnus-visual-p 'agent-menu 'menu)
296 (funcall (intern (format "gnus-agent-%s-make-menu-bar" buffer))))
297 (unless (assq 'gnus-agent-mode minor-mode-alist)
298 (push gnus-agent-mode-status minor-mode-alist))
299 (unless (assq mode minor-mode-map-alist)
300 (push (cons mode (symbol-value (intern (format "gnus-agent-%s-mode-map"
302 minor-mode-map-alist))
303 (when (eq major-mode 'gnus-group-mode)
304 (gnus-agent-toggle-plugged gnus-plugged))
305 (gnus-run-hooks 'gnus-agent-mode-hook
306 (intern (format "gnus-agent-%s-mode-hook" buffer)))))
308 (defvar gnus-agent-group-mode-map (make-sparse-keymap))
309 (gnus-define-keys gnus-agent-group-mode-map
310 "Ju" gnus-agent-fetch-groups
311 "Jc" gnus-enter-category-buffer
312 "Jj" gnus-agent-toggle-plugged
313 "Js" gnus-agent-fetch-session
314 "JY" gnus-agent-synchronize-flags
315 "JS" gnus-group-send-queue