comparison lisp/gnus/gnus-agent.el @ 91085:880960b70474

Merge from emacs--devo--0 Revision: emacs@sv.gnu.org/emacs--unicode--0--patch-283
author Miles Bader <miles@gnu.org>
date Sun, 11 Nov 2007 00:56:44 +0000
parents bdb3fe0ba9fa a3c27999decb
children 53108e6cea98
comparison
equal deleted inserted replaced
91084:a4347a111894 91085:880960b70474
113 "Function to confirm when error happens." 113 "Function to confirm when error happens."
114 :version "21.1" 114 :version "21.1"
115 :group 'gnus-agent 115 :group 'gnus-agent
116 :type 'function) 116 :type 'function)
117 117
118 (defcustom gnus-agent-synchronize-flags t 118 (defcustom gnus-agent-synchronize-flags nil
119 "Indicate if flags are synchronized when you plug in. 119 "Indicate if flags are synchronized when you plug in.
120 If this is `ask' the hook will query the user." 120 If this is `ask' the hook will query the user."
121 ;; If the default switches to something else than nil, then the function 121 ;; If the default switches to something else than nil, then the function
122 ;; should be fixed not be exceedingly slow. See 2005-09-20 ChangeLog entry. 122 ;; should be fixed not be exceedingly slow. See 2005-09-20 ChangeLog entry.
123 :version "21.1" 123 :version "21.1"
249 (defvar gnus-agent-spam-hashtb nil) 249 (defvar gnus-agent-spam-hashtb nil)
250 (defvar gnus-agent-file-name nil) 250 (defvar gnus-agent-file-name nil)
251 (defvar gnus-agent-send-mail-function nil) 251 (defvar gnus-agent-send-mail-function nil)
252 (defvar gnus-agent-file-coding-system 'raw-text) 252 (defvar gnus-agent-file-coding-system 'raw-text)
253 (defvar gnus-agent-file-loading-cache nil) 253 (defvar gnus-agent-file-loading-cache nil)
254 (defvar gnus-agent-total-fetched-hashtb nil)
255 (defvar gnus-agent-inhibit-update-total-fetched-for nil)
256 (defvar gnus-agent-need-update-total-fetched-for nil)
254 257
255 ;; Dynamic variables 258 ;; Dynamic variables
256 (defvar gnus-headers) 259 (defvar gnus-headers)
257 (defvar gnus-score) 260 (defvar gnus-score)
261
262 ;; Added to support XEmacs
263 (eval-and-compile
264 (unless (fboundp 'directory-files-and-attributes)
265 (defun directory-files-and-attributes (directory
266 &optional full match nosort)
267 (let (result)
268 (dolist (file (directory-files directory full match nosort))
269 (push (cons file (file-attributes file)) result))
270 (nreverse result)))))
258 271
259 ;;; 272 ;;;
260 ;;; Setup 273 ;;; Setup
261 ;;; 274 ;;;
262 275
287 (gnus-kill-buffer gnus-agent-overview-buffer)) 300 (gnus-kill-buffer gnus-agent-overview-buffer))
288 301
289 ;;; 302 ;;;
290 ;;; Utility functions 303 ;;; Utility functions
291 ;;; 304 ;;;
305
306 (defmacro gnus-agent-with-refreshed-group (group &rest body)
307 "Performs the body then updates the group's line in the group
308 buffer. Automatically blocks multiple updates due to recursion."
309 `(prog1 (let ((gnus-agent-inhibit-update-total-fetched-for t)) ,@body)
310 (when (and gnus-agent-need-update-total-fetched-for
311 (not gnus-agent-inhibit-update-total-fetched-for))
312 (save-excursion
313 (set-buffer gnus-group-buffer)
314 (setq gnus-agent-need-update-total-fetched-for nil)
315 (gnus-group-update-group ,group t)))))
292 316
293 (defun gnus-agent-read-file (file) 317 (defun gnus-agent-read-file (file)
294 "Load FILE and do a `read' there." 318 "Load FILE and do a `read' there."
295 (with-temp-buffer 319 (with-temp-buffer
296 (ignore-errors 320 (ignore-errors
343 367
344 (define-setf-method ,name (category) 368 (define-setf-method ,name (category)
345 (let* ((--category--temp-- (make-symbol "--category--")) 369 (let* ((--category--temp-- (make-symbol "--category--"))
346 (--value--temp-- (make-symbol "--value--"))) 370 (--value--temp-- (make-symbol "--value--")))
347 (list (list --category--temp--) ; temporary-variables 371 (list (list --category--temp--) ; temporary-variables
348 (list category) ; value-forms 372 (list category) ; value-forms
349 (list --value--temp--) ; store-variables 373 (list --value--temp--) ; store-variables
350 (let* ((category --category--temp--) ; store-form 374 (let* ((category --category--temp--) ; store-form
351 (value --value--temp--)) 375 (value --value--temp--))
352 (list (quote gnus-agent-cat-set-property) 376 (list (quote gnus-agent-cat-set-property)
353 category 377 category
354 (quote (quote ,prop-name)) 378 (quote (quote ,prop-name))
432 (setcdr category (cons cell (cdr category))) 456 (setcdr category (cons cell (cdr category)))
433 cell)) groups)))))) 457 cell)) groups))))))
434 458
435 (defsubst gnus-agent-cat-make (name &optional default-agent-predicate) 459 (defsubst gnus-agent-cat-make (name &optional default-agent-predicate)
436 (list name `(agent-predicate . ,(or default-agent-predicate 'false)))) 460 (list name `(agent-predicate . ,(or default-agent-predicate 'false))))
461
462 (defun gnus-agent-read-group ()
463 "Read a group name in the minibuffer, with completion."
464 (let ((def (or (gnus-group-group-name) gnus-newsgroup-name)))
465 (when def
466 (setq def (gnus-group-decoded-name def)))
467 (gnus-group-completing-read (if def
468 (concat "Group Name (" def "): ")
469 "Group Name: ")
470 nil nil t nil nil def)))
437 471
438 ;;; Fetching setup functions. 472 ;;; Fetching setup functions.
439 473
440 (defun gnus-agent-start-fetch () 474 (defun gnus-agent-start-fetch ()
441 "Initialize data structures for efficient fetching." 475 "Initialize data structures for efficient fetching."
890 (let (gnus-command-method old-command-method) 924 (let (gnus-command-method old-command-method)
891 (gnus-agent-group-pathname old-group)))) 925 (gnus-agent-group-pathname old-group))))
892 (new-command-method (gnus-find-method-for-group new-group)) 926 (new-command-method (gnus-find-method-for-group new-group))
893 (new-path (directory-file-name 927 (new-path (directory-file-name
894 (let (gnus-command-method new-command-method) 928 (let (gnus-command-method new-command-method)
895 (gnus-agent-group-pathname new-group))))) 929 (gnus-agent-group-pathname new-group))))
930 (file-name-coding-system nnmail-pathname-coding-system))
896 (gnus-rename-file old-path new-path t) 931 (gnus-rename-file old-path new-path t)
897 932
898 (let* ((old-real-group (gnus-group-real-name old-group)) 933 (let* ((old-real-group (gnus-group-real-name old-group))
899 (new-real-group (gnus-group-real-name new-group)) 934 (new-real-group (gnus-group-real-name new-group))
900 (old-active (gnus-agent-get-group-info old-command-method old-real-group))) 935 (old-active (gnus-agent-get-group-info old-command-method old-real-group)))
918 Depends upon the caller to determine whether group deletion is 953 Depends upon the caller to determine whether group deletion is
919 supported." 954 supported."
920 (let* ((command-method (gnus-find-method-for-group group)) 955 (let* ((command-method (gnus-find-method-for-group group))
921 (path (directory-file-name 956 (path (directory-file-name
922 (let (gnus-command-method command-method) 957 (let (gnus-command-method command-method)
923 (gnus-agent-group-pathname group))))) 958 (gnus-agent-group-pathname group))))
959 (file-name-coding-system nnmail-pathname-coding-system))
924 (gnus-delete-directory path) 960 (gnus-delete-directory path)
925 961
926 (let* ((real-group (gnus-group-real-name group))) 962 (let* ((real-group (gnus-group-real-name group)))
927 (gnus-agent-save-group-info command-method real-group nil) 963 (gnus-agent-save-group-info command-method real-group nil)
928 964
1283 (new (gnus-make-hashtable (count-lines (point-min) (point-max)))) 1319 (new (gnus-make-hashtable (count-lines (point-min) (point-max))))
1284 (file (gnus-agent-lib-file "active"))) 1320 (file (gnus-agent-lib-file "active")))
1285 (gnus-active-to-gnus-format nil new) 1321 (gnus-active-to-gnus-format nil new)
1286 (gnus-agent-write-active file new) 1322 (gnus-agent-write-active file new)
1287 (erase-buffer) 1323 (erase-buffer)
1288 (nnheader-insert-file-contents file)))) 1324 (let ((nnheader-file-coding-system gnus-agent-file-coding-system))
1325 (nnheader-insert-file-contents file)))))
1289 1326
1290 (defun gnus-agent-write-active (file new) 1327 (defun gnus-agent-write-active (file new)
1291 (gnus-make-directory (file-name-directory file)) 1328 (gnus-make-directory (file-name-directory file))
1292 (let ((nnmail-active-file-coding-system gnus-agent-file-coding-system)) 1329 (let ((nnmail-active-file-coding-system gnus-agent-file-coding-system))
1293 ;; The hashtable contains real names of groups. However, do NOT 1330 ;; The hashtable contains real names of groups. However, do NOT
1396 (save-excursion 1433 (save-excursion
1397 (setq oactive-max (read (current-buffer)) ;; max 1434 (setq oactive-max (read (current-buffer)) ;; max
1398 oactive-min (read (current-buffer))) ;; min 1435 oactive-min (read (current-buffer))) ;; min
1399 (cons oactive-min oactive-max)))))))) 1436 (cons oactive-min oactive-max))))))))
1400 1437
1438 (defvar gnus-agent-decoded-group-names nil
1439 "Alist of non-ASCII group names and decoded ones.")
1440
1441 (defun gnus-agent-decoded-group-name (group)
1442 "Return a decoded group name of GROUP."
1443 (or (cdr (assoc group gnus-agent-decoded-group-names))
1444 (if (string-match "[^\000-\177]" group)
1445 (let ((decoded (gnus-group-decoded-name group)))
1446 (push (cons group decoded) gnus-agent-decoded-group-names)
1447 decoded)
1448 group)))
1449
1401 (defun gnus-agent-group-path (group) 1450 (defun gnus-agent-group-path (group)
1402 "Translate GROUP into a file name." 1451 "Translate GROUP into a file name."
1403 1452
1404 ;; NOTE: This is what nnmail-group-pathname does as of Apr 2003. 1453 ;; NOTE: This is what nnmail-group-pathname does as of Apr 2003.
1405 ;; The two methods must be kept synchronized, which is why 1454 ;; The two methods must be kept synchronized, which is why
1407 1456
1408 (setq group 1457 (setq group
1409 (nnheader-translate-file-chars 1458 (nnheader-translate-file-chars
1410 (nnheader-replace-duplicate-chars-in-string 1459 (nnheader-replace-duplicate-chars-in-string
1411 (nnheader-replace-chars-in-string 1460 (nnheader-replace-chars-in-string
1412 (gnus-group-real-name (gnus-group-decoded-name group)) 1461 (gnus-group-real-name (gnus-agent-decoded-group-name group))
1413 ?/ ?_) 1462 ?/ ?_)
1414 ?. ?_))) 1463 ?. ?_)))
1415 (if (or nnmail-use-long-file-names 1464 (if (or nnmail-use-long-file-names
1416 (file-directory-p (expand-file-name group (gnus-agent-directory)))) 1465 (file-directory-p (expand-file-name group (gnus-agent-directory))))
1417 group 1466 group
1418 (mm-encode-coding-string 1467 (nnheader-replace-chars-in-string group ?. ?/)))
1419 (nnheader-replace-chars-in-string group ?. ?/)
1420 nnmail-pathname-coding-system)))
1421 1468
1422 (defun gnus-agent-group-pathname (group) 1469 (defun gnus-agent-group-pathname (group)
1423 "Translate GROUP into a file name." 1470 "Translate GROUP into a file name."
1424 ;; nnagent uses nnmail-group-pathname to read articles while 1471 ;; nnagent uses nnmail-group-pathname to read articles while
1425 ;; unplugged. The agent must, therefore, use the same directory 1472 ;; unplugged. The agent must, therefore, use the same directory
1426 ;; while plugged. 1473 ;; while plugged.
1427 (let ((gnus-command-method (or gnus-command-method 1474 (nnmail-group-pathname
1428 (gnus-find-method-for-group group)))) 1475 (gnus-group-real-name (gnus-agent-decoded-group-name group))
1429 (nnmail-group-pathname (gnus-group-real-name 1476 (if gnus-command-method
1430 (gnus-group-decoded-name group)) 1477 (gnus-agent-directory)
1431 (gnus-agent-directory)))) 1478 (let ((gnus-command-method (gnus-find-method-for-group group)))
1479 (gnus-agent-directory)))))
1432 1480
1433 (defun gnus-agent-get-function (method) 1481 (defun gnus-agent-get-function (method)
1434 (if (gnus-online method) 1482 (if (gnus-online method)
1435 (car method) 1483 (car method)
1436 (require 'nnagent) 1484 (require 'nnagent)
1530 (let* ((fetched-articles (list nil)) 1578 (let* ((fetched-articles (list nil))
1531 (tail-fetched-articles fetched-articles) 1579 (tail-fetched-articles fetched-articles)
1532 (dir (gnus-agent-group-pathname group)) 1580 (dir (gnus-agent-group-pathname group))
1533 (date (time-to-days (current-time))) 1581 (date (time-to-days (current-time)))
1534 (case-fold-search t) 1582 (case-fold-search t)
1535 pos crosses id) 1583 pos crosses id
1584 (file-name-coding-system nnmail-pathname-coding-system))
1536 1585
1537 (setcar selected-sets (nreverse (car selected-sets))) 1586 (setcar selected-sets (nreverse (car selected-sets)))
1538 (setq selected-sets (nreverse selected-sets)) 1587 (setq selected-sets (nreverse selected-sets))
1539 1588
1540 (gnus-make-directory dir) 1589 (gnus-make-directory dir)
1599 tail-fetched-articles (caar pos))) 1648 tail-fetched-articles (caar pos)))
1600 (widen) 1649 (widen)
1601 (setq pos (cdr pos))))) 1650 (setq pos (cdr pos)))))
1602 1651
1603 (gnus-agent-save-alist group (cdr fetched-articles) date) 1652 (gnus-agent-save-alist group (cdr fetched-articles) date)
1653 (gnus-agent-update-files-total-fetched-for group (cdr fetched-articles))
1654
1604 (gnus-message 7 "")) 1655 (gnus-message 7 ""))
1605 (cdr fetched-articles)))))) 1656 (cdr fetched-articles))))))
1606 1657
1607 (defun gnus-agent-unfetch-articles (group articles) 1658 (defun gnus-agent-unfetch-articles (group articles)
1608 "Delete ARTICLES that were fetched from GROUP into the agent." 1659 "Delete ARTICLES that were fetched from GROUP into the agent."
1609 (when articles 1660 (when articles
1610 (gnus-agent-load-alist group) 1661 (gnus-agent-with-refreshed-group
1611 (let* ((alist (cons nil gnus-agent-article-alist)) 1662 group
1612 (articles (sort articles #'<)) 1663 (gnus-agent-load-alist group)
1613 (next-possibility alist) 1664 (let* ((alist (cons nil gnus-agent-article-alist))
1614 (delete-this (pop articles))) 1665 (articles (sort articles #'<))
1615 (while (and (cdr next-possibility) delete-this) 1666 (next-possibility alist)
1616 (let ((have-this (caar (cdr next-possibility)))) 1667 (delete-this (pop articles)))
1617 (cond ((< delete-this have-this) 1668 (while (and (cdr next-possibility) delete-this)
1618 (setq delete-this (pop articles))) 1669 (let ((have-this (caar (cdr next-possibility))))
1619 ((= delete-this have-this) 1670 (cond
1620 (let ((timestamp (cdar (cdr next-possibility)))) 1671 ((< delete-this have-this)
1621 (when timestamp 1672 (setq delete-this (pop articles)))
1622 (let* ((file-name (concat (gnus-agent-group-pathname group) 1673 ((= delete-this have-this)
1623 (number-to-string have-this)))) 1674 (let ((timestamp (cdar (cdr next-possibility))))
1624 (delete-file file-name)))) 1675 (when timestamp
1625 1676 (let* ((file-name (concat (gnus-agent-group-pathname group)
1626 (setcdr next-possibility (cddr next-possibility))) 1677 (number-to-string have-this)))
1627 (t 1678 (size-file
1628 (setq next-possibility (cdr next-possibility)))))) 1679 (float (or (and gnus-agent-total-fetched-hashtb
1629 (setq gnus-agent-article-alist (cdr alist)) 1680 (nth 7 (file-attributes file-name)))
1630 (gnus-agent-save-alist group)))) 1681 0)))
1682 (file-name-coding-system
1683 nnmail-pathname-coding-system))
1684 (delete-file file-name)
1685 (gnus-agent-update-files-total-fetched-for
1686 group (- size-file)))))
1687
1688 (setcdr next-possibility (cddr next-possibility)))
1689 (t
1690 (setq next-possibility (cdr next-possibility))))))
1691 (setq gnus-agent-article-alist (cdr alist))
1692 (gnus-agent-save-alist group)))))
1631 1693
1632 (defun gnus-agent-crosspost (crosses article &optional date) 1694 (defun gnus-agent-crosspost (crosses article &optional date)
1633 (setq date (or date t)) 1695 (setq date (or date t))
1634 1696
1635 (let (gnus-agent-article-alist group alist beg end) 1697 (let (gnus-agent-article-alist group alist beg end)
1649 (set-buffer (gnus-get-buffer-create (format " *Gnus agent overview %s*" 1711 (set-buffer (gnus-get-buffer-create (format " *Gnus agent overview %s*"
1650 group))) 1712 group)))
1651 (when (= (point-max) (point-min)) 1713 (when (= (point-max) (point-min))
1652 (push (cons group (current-buffer)) gnus-agent-buffer-alist) 1714 (push (cons group (current-buffer)) gnus-agent-buffer-alist)
1653 (ignore-errors 1715 (ignore-errors
1654 (nnheader-insert-file-contents 1716 (let ((file-name-coding-system nnmail-pathname-coding-system))
1655 (gnus-agent-article-name ".overview" group)))) 1717 (nnheader-insert-file-contents
1718 (gnus-agent-article-name ".overview" group)))))
1656 (nnheader-find-nov-line (string-to-number (cdar crosses))) 1719 (nnheader-find-nov-line (string-to-number (cdar crosses)))
1657 (insert (string-to-number (cdar crosses))) 1720 (insert (string-to-number (cdar crosses)))
1658 (insert-buffer-substring gnus-agent-overview-buffer beg end) 1721 (insert-buffer-substring gnus-agent-overview-buffer beg end)
1659 (gnus-agent-check-overview-buffer)) 1722 (gnus-agent-check-overview-buffer))
1660 (setq crosses (cdr crosses))))) 1723 (setq crosses (cdr crosses)))))
1661 1724
1662 (defun gnus-agent-backup-overview-buffer () 1725 (defun gnus-agent-backup-overview-buffer ()
1663 (when gnus-newsgroup-name 1726 (when gnus-newsgroup-name
1664 (let ((root (gnus-agent-article-name ".overview" gnus-newsgroup-name)) 1727 (let ((root (gnus-agent-article-name ".overview" gnus-newsgroup-name))
1665 (cnt 0) 1728 (cnt 0)
1666 name) 1729 name
1730 (file-name-coding-system nnmail-pathname-coding-system))
1667 (while (file-exists-p 1731 (while (file-exists-p
1668 (setq name (concat root "~" 1732 (setq name (concat root "~"
1669 (int-to-string (setq cnt (1+ cnt))) "~")))) 1733 (int-to-string (setq cnt (1+ cnt))) "~"))))
1670 (write-region (point-min) (point-max) name nil 'no-msg) 1734 (write-region (point-min) (point-max) name nil 'no-msg)
1671 (gnus-message 1 "Created backup copy of overview in %s." name))) 1735 (gnus-message 1 "Created backup copy of overview in %s." name)))
1695 (or backed-up 1759 (or backed-up
1696 (setq backed-up (gnus-agent-backup-overview-buffer))) 1760 (setq backed-up (gnus-agent-backup-overview-buffer)))
1697 (gnus-message 1 1761 (gnus-message 1
1698 "Overview buffer contains garbage '%s'." 1762 "Overview buffer contains garbage '%s'."
1699 (buffer-substring 1763 (buffer-substring
1700 p (gnus-point-at-eol)))) 1764 p (point-at-eol))))
1701 ((= cur prev-num) 1765 ((= cur prev-num)
1702 (or backed-up 1766 (or backed-up
1703 (setq backed-up (gnus-agent-backup-overview-buffer))) 1767 (setq backed-up (gnus-agent-backup-overview-buffer)))
1704 (gnus-message 1 1768 (gnus-message 1
1705 "Duplicate overview line for %d" cur) 1769 "Duplicate overview line for %d" cur)
1713 (setq prev-num -1)) 1777 (setq prev-num -1))
1714 (t 1778 (t
1715 (setq prev-num cur))) 1779 (setq prev-num cur)))
1716 (forward-line 1))))))) 1780 (forward-line 1)))))))
1717 1781
1782 (defun gnus-agent-flush-server (&optional server-or-method)
1783 "Flush all agent index files for every subscribed group within
1784 the given SERVER-OR-METHOD. When called with nil, the current
1785 value of gnus-command-method identifies the server."
1786 (let* ((gnus-command-method (if server-or-method
1787 (gnus-server-to-method server-or-method)
1788 gnus-command-method))
1789 (alist gnus-newsrc-alist))
1790 (while alist
1791 (let ((entry (pop alist)))
1792 (when (gnus-methods-equal-p gnus-command-method (gnus-info-method entry))
1793 (gnus-agent-flush-group (gnus-info-group entry)))))))
1794
1795 (defun gnus-agent-flush-group (group)
1796 "Flush the agent's index files such that the GROUP no longer
1797 appears to have any local content. The actual content, the
1798 article files, may then be deleted using gnus-agent-expire-group.
1799 If flushing was a mistake, the gnus-agent-regenerate-group method
1800 provides an undo mechanism by reconstructing the index files from
1801 the article files."
1802 (interactive (list (gnus-agent-read-group)))
1803
1804 (let* ((gnus-command-method (or gnus-command-method
1805 (gnus-find-method-for-group group)))
1806 (overview (gnus-agent-article-name ".overview" group))
1807 (agentview (gnus-agent-article-name ".agentview" group))
1808 (file-name-coding-system nnmail-pathname-coding-system))
1809
1810 (if (file-exists-p overview)
1811 (delete-file overview))
1812 (if (file-exists-p agentview)
1813 (delete-file agentview))
1814
1815 (gnus-agent-update-view-total-fetched-for group nil gnus-command-method)
1816 (gnus-agent-update-view-total-fetched-for group t gnus-command-method)
1817
1818 ;(gnus-agent-set-local group nil nil)
1819 ;(gnus-agent-save-local t)
1820 (gnus-agent-save-group-info nil group nil)))
1821
1718 (defun gnus-agent-flush-cache () 1822 (defun gnus-agent-flush-cache ()
1823 "Flush the agent's index files such that the group no longer
1824 appears to have any local content. The actual content, the
1825 article files, is then deleted using gnus-agent-expire-group. The
1826 gnus-agent-regenerate-group method provides an undo mechanism by
1827 reconstructing the index files from the article files."
1828 (interactive)
1719 (save-excursion 1829 (save-excursion
1720 (while gnus-agent-buffer-alist 1830 (let ((file-name-coding-system nnmail-pathname-coding-system))
1721 (set-buffer (cdar gnus-agent-buffer-alist)) 1831 (while gnus-agent-buffer-alist
1722 (let ((coding-system-for-write 1832 (set-buffer (cdar gnus-agent-buffer-alist))
1723 gnus-agent-file-coding-system)) 1833 (let ((coding-system-for-write gnus-agent-file-coding-system))
1724 (write-region (point-min) (point-max) 1834 (write-region (point-min) (point-max)
1725 (gnus-agent-article-name ".overview" 1835 (gnus-agent-article-name ".overview"
1726 (caar gnus-agent-buffer-alist)) 1836 (caar gnus-agent-buffer-alist))
1727 nil 'silent)) 1837 nil 'silent))
1728 (setq gnus-agent-buffer-alist (cdr gnus-agent-buffer-alist))) 1838 (setq gnus-agent-buffer-alist (cdr gnus-agent-buffer-alist)))
1729 (while gnus-agent-group-alist 1839 (while gnus-agent-group-alist
1730 (with-temp-file (gnus-agent-article-name 1840 (with-temp-file (gnus-agent-article-name
1731 ".agentview" (caar gnus-agent-group-alist)) 1841 ".agentview" (caar gnus-agent-group-alist))
1732 (princ (cdar gnus-agent-group-alist)) 1842 (princ (cdar gnus-agent-group-alist))
1733 (insert "\n") 1843 (insert "\n")
1734 (princ 1 (current-buffer)) 1844 (princ 1 (current-buffer))
1735 (insert "\n")) 1845 (insert "\n"))
1736 (setq gnus-agent-group-alist (cdr gnus-agent-group-alist))))) 1846 (setq gnus-agent-group-alist (cdr gnus-agent-group-alist))))))
1737 1847
1738 ;;;###autoload 1848 ;;;###autoload
1739 (defun gnus-agent-find-parameter (group symbol) 1849 (defun gnus-agent-find-parameter (group symbol)
1740 "Search for GROUPs SYMBOL in the group's parameters, the group's 1850 "Search for GROUPs SYMBOL in the group's parameters, the group's
1741 topic parameters, the group's category, or the customizable 1851 topic parameters, the group's category, or the customizable
1775 (cdr active)))) 1885 (cdr active))))
1776 (gnus-uncompress-range (gnus-active group))) 1886 (gnus-uncompress-range (gnus-active group)))
1777 (gnus-list-of-unread-articles group))) 1887 (gnus-list-of-unread-articles group)))
1778 (gnus-decode-encoded-word-function 'identity) 1888 (gnus-decode-encoded-word-function 'identity)
1779 (gnus-decode-encoded-address-function 'identity) 1889 (gnus-decode-encoded-address-function 'identity)
1780 (file (gnus-agent-article-name ".overview" group))) 1890 (file (gnus-agent-article-name ".overview" group))
1891 (file-name-coding-system nnmail-pathname-coding-system))
1781 1892
1782 (unless fetch-all 1893 (unless fetch-all
1783 ;; Add articles with marks to the list of article headers we want to 1894 ;; Add articles with marks to the list of article headers we want to
1784 ;; fetch. Don't fetch articles solely on the basis of a recent or seen 1895 ;; fetch. Don't fetch articles solely on the basis of a recent or seen
1785 ;; mark, but do fetch recent or seen articles if they have other, more 1896 ;; mark, but do fetch recent or seen articles if they have other, more
1855 (gnus-agent-braid-nov group articles file) 1966 (gnus-agent-braid-nov group articles file)
1856 (let ((coding-system-for-write 1967 (let ((coding-system-for-write
1857 gnus-agent-file-coding-system)) 1968 gnus-agent-file-coding-system))
1858 (gnus-agent-check-overview-buffer) 1969 (gnus-agent-check-overview-buffer)
1859 (write-region (point-min) (point-max) file nil 'silent)) 1970 (write-region (point-min) (point-max) file nil 'silent))
1971 (gnus-agent-update-view-total-fetched-for group t)
1860 (gnus-agent-save-alist group articles nil) 1972 (gnus-agent-save-alist group articles nil)
1861 articles) 1973 articles)
1862 (ignore-errors 1974 (ignore-errors
1863 (erase-buffer) 1975 (erase-buffer)
1864 (nnheader-insert-file-contents file))))) 1976 (nnheader-insert-file-contents file)))))
1924 ;; Replacing existing NOV entry 2036 ;; Replacing existing NOV entry
1925 (delete-region (point) (progn (forward-line 1) (point)))) 2037 (delete-region (point) (progn (forward-line 1) (point))))
1926 (gnus-agent-copy-nov-line (pop articles)) 2038 (gnus-agent-copy-nov-line (pop articles))
1927 2039
1928 (ignore-errors 2040 (ignore-errors
1929 (while articles 2041 (while articles
1930 (while (let ((art (read (current-buffer)))) 2042 (while (let ((art (read (current-buffer))))
1931 (cond ((< art (car articles)) 2043 (cond ((< art (car articles))
1932 (forward-line 1) 2044 (forward-line 1)
1933 t) 2045 t)
1934 ((= art (car articles)) 2046 ((= art (car articles))
1935 (beginning-of-line) 2047 (beginning-of-line)
1936 (delete-region 2048 (delete-region
1937 (point) (progn (forward-line 1) (point))) 2049 (point) (progn (forward-line 1) (point)))
1938 nil) 2050 nil)
1939 (t 2051 (t
1940 (beginning-of-line) 2052 (beginning-of-line)
1941 nil)))) 2053 nil))))
1942 2054
1943 (gnus-agent-copy-nov-line (pop articles))))) 2055 (gnus-agent-copy-nov-line (pop articles)))))
1944 2056
1945 (goto-char (point-max)) 2057 (goto-char (point-max))
1946 2058
1947 ;; Append the remaining lines 2059 ;; Append the remaining lines
1948 (when articles 2060 (when articles
1955 (insert-buffer-substring gnus-agent-overview-buffer start) 2067 (insert-buffer-substring gnus-agent-overview-buffer start)
1956 (goto-char p)) 2068 (goto-char p))
1957 2069
1958 (setq last (or last -134217728)) 2070 (setq last (or last -134217728))
1959 (while (catch 'problems 2071 (while (catch 'problems
1960 (let (sort art) 2072 (let (sort art)
1961 (while (not (eobp)) 2073 (while (not (eobp))
1962 (setq art (gnus-agent-read-article-number)) 2074 (setq art (gnus-agent-read-article-number))
1963 (cond ((not art) 2075 (cond ((not art)
1964 ;; Bad art num - delete this line 2076 ;; Bad art num - delete this line
1965 (beginning-of-line) 2077 (beginning-of-line)
1966 (delete-region (point) (progn (forward-line 1) (point)))) 2078 (delete-region (point) (progn (forward-line 1) (point))))
1967 ((< art last) 2079 ((< art last)
1968 ;; Art num out of order - enable sort 2080 ;; Art num out of order - enable sort
1969 (setq sort t) 2081 (setq sort t)
1970 (forward-line 1)) 2082 (forward-line 1))
1971 ((= art last) 2083 ((= art last)
1972 ;; Bad repeat of art number - delete this line 2084 ;; Bad repeat of art number - delete this line
1973 (beginning-of-line) 2085 (beginning-of-line)
1974 (delete-region (point) (progn (forward-line 1) (point)))) 2086 (delete-region (point) (progn (forward-line 1) (point))))
1975 (t 2087 (t
1976 ;; Good art num 2088 ;; Good art num
1977 (setq last art) 2089 (setq last art)
1978 (forward-line 1)))) 2090 (forward-line 1))))
1979 (when sort 2091 (when sort
1980 ;; something is seriously wrong as we simply shouldn't see out-of-order data. 2092 ;; something is seriously wrong as we simply shouldn't see out-of-order data.
1981 ;; First, we'll fix the sort. 2093 ;; First, we'll fix the sort.
1982 (sort-numeric-fields 1 (point-min) (point-max)) 2094 (sort-numeric-fields 1 (point-min) (point-max))
1983 2095
1984 ;; but now we have to consider that we may have duplicate rows... 2096 ;; but now we have to consider that we may have duplicate rows...
1996 (defvar gnus-agent-read-agentview)) 2108 (defvar gnus-agent-read-agentview))
1997 2109
1998 (defun gnus-agent-load-alist (group) 2110 (defun gnus-agent-load-alist (group)
1999 "Load the article-state alist for GROUP." 2111 "Load the article-state alist for GROUP."
2000 ;; Bind free variable that's used in `gnus-agent-read-agentview'. 2112 ;; Bind free variable that's used in `gnus-agent-read-agentview'.
2001 (let ((gnus-agent-read-agentview group)) 2113 (let ((gnus-agent-read-agentview group)
2114 (file-name-coding-system nnmail-pathname-coding-system))
2002 (setq gnus-agent-article-alist 2115 (setq gnus-agent-article-alist
2003 (gnus-cache-file-contents 2116 (gnus-cache-file-contents
2004 (gnus-agent-article-name ".agentview" group) 2117 (gnus-agent-article-name ".agentview" group)
2005 'gnus-agent-file-loading-cache 2118 'gnus-agent-file-loading-cache
2006 'gnus-agent-read-agentview)))) 2119 'gnus-agent-read-agentview))))
2007 2120
2008 (defun gnus-agent-read-agentview (file) 2121 (defun gnus-agent-read-agentview (file)
2009 "Load FILE and do a `read' there." 2122 "Load FILE and do a `read' there."
2010 (with-temp-buffer 2123 (with-temp-buffer
2011 (condition-case nil 2124 (condition-case nil
2012 (progn 2125 (progn
2013 (nnheader-insert-file-contents file) 2126 (nnheader-insert-file-contents file)
2014 (goto-char (point-min)) 2127 (goto-char (point-min))
2015 (let ((alist (read (current-buffer))) 2128 (let ((alist (read (current-buffer)))
2016 (version (condition-case nil (read (current-buffer)) 2129 (version (condition-case nil (read (current-buffer))
2017 (end-of-file 0))) 2130 (end-of-file 0)))
2018 changed-version) 2131 changed-version)
2019 2132
2020 (cond 2133 (cond
2021 ((= version 0) 2134 ((= version 0)
2022 (let ((inhibit-quit t) 2135 (let ((inhibit-quit t)
2023 entry) 2136 entry)
2024 (gnus-agent-open-history) 2137 (gnus-agent-open-history)
2025 (set-buffer (gnus-agent-history-buffer)) 2138 (set-buffer (gnus-agent-history-buffer))
2026 (goto-char (point-min)) 2139 (goto-char (point-min))
2027 (while (not (eobp)) 2140 (while (not (eobp))
2028 (if (and (looking-at 2141 (if (and (looking-at
2029 "[^\t\n]+\t\\([0-9]+\\)\t\\([^ \n]+\\) \\([0-9]+\\)") 2142 "[^\t\n]+\t\\([0-9]+\\)\t\\([^ \n]+\\) \\([0-9]+\\)")
2030 (string= (match-string 2) 2143 (string= (match-string 2)
2031 gnus-agent-read-agentview) 2144 gnus-agent-read-agentview)
2032 (setq entry (assoc (string-to-number (match-string 3)) alist))) 2145 (setq entry (assoc (string-to-number (match-string 3)) alist)))
2033 (setcdr entry (string-to-number (match-string 1)))) 2146 (setcdr entry (string-to-number (match-string 1))))
2034 (forward-line 1)) 2147 (forward-line 1))
2035 (gnus-agent-close-history) 2148 (gnus-agent-close-history)
2036 (setq changed-version t))) 2149 (setq changed-version t)))
2037 ((= version 1) 2150 ((= version 1)
2038 (setq changed-version (not (= 1 gnus-agent-article-alist-save-format)))) 2151 (setq changed-version (not (= 1 gnus-agent-article-alist-save-format))))
2039 ((= version 2) 2152 ((= version 2)
2040 (let (uncomp) 2153 (let (state sequence uncomp)
2041 (mapcar 2154 (while alist
2042 (lambda (comp-list) 2155 (setq state (caar alist)
2043 (let ((state (car comp-list)) 2156 sequence (inline (gnus-uncompress-range (cdar alist)))
2044 (sequence (inline 2157 alist (cdr alist))
2045 (gnus-uncompress-range 2158 (while sequence
2046 (cdr comp-list))))) 2159 (push (cons (pop sequence) state) uncomp)))
2047 (mapcar (lambda (article-id)
2048 (setq uncomp (cons (cons article-id state) uncomp)))
2049 sequence)))
2050 alist)
2051 (setq alist (sort uncomp 'car-less-than-car))) 2160 (setq alist (sort uncomp 'car-less-than-car)))
2052 (setq changed-version (not (= 2 gnus-agent-article-alist-save-format))))) 2161 (setq changed-version (not (= 2 gnus-agent-article-alist-save-format)))))
2053 (when changed-version 2162 (when changed-version
2054 (let ((gnus-agent-article-alist alist)) 2163 (let ((gnus-agent-article-alist alist))
2055 (gnus-agent-save-alist gnus-agent-read-agentview))) 2164 (gnus-agent-save-alist gnus-agent-read-agentview)))
2056 alist)) 2165 alist))
2057 (file-error nil)))) 2166 ((end-of-file file-error)
2167 ;; The agentview file is missing.
2168 (condition-case nil
2169 ;; If the agent directory exists, attempt to perform a brute-force
2170 ;; reconstruction of its contents.
2171 (let* (alist
2172 (file-name-coding-system nnmail-pathname-coding-system)
2173 (file-attributes (directory-files-and-attributes
2174 (gnus-agent-article-name ""
2175 gnus-agent-read-agentview) nil "^[0-9]+$" t)))
2176 (while file-attributes
2177 (let ((fa (pop file-attributes)))
2178 (unless (nth 1 fa)
2179 (push (cons (string-to-number (nth 0 fa)) (time-to-days (nth 5 fa))) alist))))
2180 alist)
2181 (file-error nil))))))
2058 2182
2059 (defun gnus-agent-save-alist (group &optional articles state) 2183 (defun gnus-agent-save-alist (group &optional articles state)
2060 "Save the article-state alist for GROUP." 2184 "Save the article-state alist for GROUP."
2061 (let* ((file-name-coding-system nnmail-pathname-coding-system) 2185 (let* ((file-name-coding-system nnmail-pathname-coding-system)
2062 (prev (cons nil gnus-agent-article-alist)) 2186 (prev (cons nil gnus-agent-article-alist))
2083 (gnus-make-directory (gnus-agent-article-name "" group)) 2207 (gnus-make-directory (gnus-agent-article-name "" group))
2084 (with-temp-file (gnus-agent-article-name ".agentview" group) 2208 (with-temp-file (gnus-agent-article-name ".agentview" group)
2085 (cond ((eq gnus-agent-article-alist-save-format 1) 2209 (cond ((eq gnus-agent-article-alist-save-format 1)
2086 (princ gnus-agent-article-alist (current-buffer))) 2210 (princ gnus-agent-article-alist (current-buffer)))
2087 ((eq gnus-agent-article-alist-save-format 2) 2211 ((eq gnus-agent-article-alist-save-format 2)
2088 (let ((compressed nil)) 2212 (let ((alist gnus-agent-article-alist)
2089 (mapcar (lambda (pair) 2213 article-id day-of-download comp-list compressed)
2090 (let* ((article-id (car pair)) 2214 (while alist
2091 (day-of-download (cdr pair)) 2215 (setq article-id (caar alist)
2092 (comp-list (assq day-of-download compressed))) 2216 day-of-download (cdar alist)
2093 (if comp-list 2217 comp-list (assq day-of-download compressed)
2094 (setcdr comp-list 2218 alist (cdr alist))
2095 (cons article-id (cdr comp-list))) 2219 (if comp-list
2096 (setq compressed 2220 (setcdr comp-list (cons article-id (cdr comp-list)))
2097 (cons (list day-of-download article-id) 2221 (push (list day-of-download article-id) compressed)))
2098 compressed))) 2222 (setq alist compressed)
2099 nil)) gnus-agent-article-alist) 2223 (while alist
2100 (mapcar (lambda (comp-list) 2224 (setq comp-list (pop alist))
2101 (setcdr comp-list 2225 (setcdr comp-list
2102 (gnus-compress-sequence 2226 (gnus-compress-sequence (nreverse (cdr comp-list)))))
2103 (nreverse (cdr comp-list)))))
2104 compressed)
2105 (princ compressed (current-buffer))))) 2227 (princ compressed (current-buffer)))))
2106 (insert "\n") 2228 (insert "\n")
2107 (princ gnus-agent-article-alist-save-format (current-buffer)) 2229 (princ gnus-agent-article-alist-save-format (current-buffer))
2108 (insert "\n")))) 2230 (insert "\n"))
2231
2232 (gnus-agent-update-view-total-fetched-for group nil)))
2109 2233
2110 (defvar gnus-agent-article-local nil) 2234 (defvar gnus-agent-article-local nil)
2111 (defvar gnus-agent-file-loading-local nil) 2235 (defvar gnus-agent-file-loading-local nil)
2112 2236
2113 (defun gnus-agent-load-local (&optional method) 2237 (defun gnus-agent-load-local (&optional method)
2181 (let* ((gnus-command-method (symbol-value (intern "+method" my-obarray))) 2305 (let* ((gnus-command-method (symbol-value (intern "+method" my-obarray)))
2182 ;; NOTE: gnus-command-method is used within gnus-agent-lib-file. 2306 ;; NOTE: gnus-command-method is used within gnus-agent-lib-file.
2183 (dest (gnus-agent-lib-file "local"))) 2307 (dest (gnus-agent-lib-file "local")))
2184 (gnus-make-directory (gnus-agent-lib-file "")) 2308 (gnus-make-directory (gnus-agent-lib-file ""))
2185 2309
2186 (let ((buffer-file-coding-system gnus-agent-file-coding-system)) 2310 (let ((coding-system-for-write gnus-agent-file-coding-system)
2311 (file-name-coding-system nnmail-pathname-coding-system))
2187 (with-temp-file dest 2312 (with-temp-file dest
2188 (let ((gnus-command-method (symbol-value (intern "+method" my-obarray))) 2313 (let ((gnus-command-method (symbol-value (intern "+method" my-obarray)))
2189 (file-name-coding-system nnmail-pathname-coding-system)
2190 print-level print-length item article 2314 print-level print-length item article
2191 (standard-output (current-buffer))) 2315 (standard-output (current-buffer)))
2192 (mapatoms (lambda (symbol) 2316 (mapatoms (lambda (symbol)
2193 (cond ((not (boundp symbol)) 2317 (cond ((not (boundp symbol))
2194 nil) 2318 nil)
2195 ((member (symbol-name symbol) '("+dirty" "+method")) 2319 ((member (symbol-name symbol) '("+dirty" "+method"))
2196 nil) 2320 nil)
2197 (t 2321 (t
2198 (let ((range (symbol-value symbol))) 2322 (let ((range (symbol-value symbol)))
2199 (when range 2323 (when range
2200 (prin1 symbol) 2324 (prin1 symbol)
2201 (princ " ") 2325 (princ " ")
2202 (princ (car range)) 2326 (princ (car range))
2203 (princ " ") 2327 (princ " ")
2204 (princ (cdr range)) 2328 (princ (cdr range))
2205 (princ "\n")))))) 2329 (princ "\n"))))))
2206 my-obarray)))))))) 2330 my-obarray))))))))
2207 2331
2208 (defun gnus-agent-get-local (group &optional gmane method) 2332 (defun gnus-agent-get-local (group &optional gmane method)
2209 (let* ((gmane (or gmane (gnus-group-real-name group))) 2333 (let* ((gmane (or gmane (gnus-group-real-name group)))
2460 (gnus-summary-set-agent-mark article t)) 2584 (gnus-summary-set-agent-mark article t))
2461 (dolist (article fetched-articles) 2585 (dolist (article fetched-articles)
2462 (when gnus-agent-mark-unread-after-downloaded 2586 (when gnus-agent-mark-unread-after-downloaded
2463 (setq gnus-newsgroup-downloadable 2587 (setq gnus-newsgroup-downloadable
2464 (delq article gnus-newsgroup-downloadable)) 2588 (delq article gnus-newsgroup-downloadable))
2465 (gnus-summary-mark-article 2589 (gnus-summary-mark-article
2466 article gnus-unread-mark)) 2590 article gnus-unread-mark))
2467 (when (gnus-summary-goto-subject article nil t) 2591 (when (gnus-summary-goto-subject article nil t)
2468 (gnus-summary-update-download-mark article))) 2592 (gnus-summary-update-download-mark article)))
2469 (dolist (article unfetched-articles) 2593 (dolist (article unfetched-articles)
2470 (gnus-summary-mark-article 2594 (gnus-summary-mark-article
2471 article gnus-canceled-mark))) 2595 article gnus-canceled-mark)))
2652 (gnus-category-insert-line (pop alist))) 2776 (gnus-category-insert-line (pop alist)))
2653 (goto-char (point-min)) 2777 (goto-char (point-min))
2654 (gnus-category-position-point))) 2778 (gnus-category-position-point)))
2655 2779
2656 (defun gnus-category-name () 2780 (defun gnus-category-name ()
2657 (or (intern (get-text-property (gnus-point-at-bol) 'gnus-category)) 2781 (or (intern (get-text-property (point-at-bol) 'gnus-category))
2658 (error "No category on the current line"))) 2782 (error "No category on the current line")))
2659 2783
2660 (defun gnus-category-read () 2784 (defun gnus-category-read ()
2661 "Read the category alist." 2785 "Read the category alist."
2662 (setq gnus-category-alist 2786 (setq gnus-category-alist
2973 The articles on which the expiration process runs are selected as follows: 3097 The articles on which the expiration process runs are selected as follows:
2974 if ARTICLES is null, all read and unmarked articles. 3098 if ARTICLES is null, all read and unmarked articles.
2975 if ARTICLES is t, all articles. 3099 if ARTICLES is t, all articles.
2976 if ARTICLES is a list, just those articles. 3100 if ARTICLES is a list, just those articles.
2977 FORCE is equivalent to setting the expiration predicates to true." 3101 FORCE is equivalent to setting the expiration predicates to true."
2978 (interactive 3102 (interactive (list (gnus-agent-read-group)))
2979 (list (let ((def (or (gnus-group-group-name)
2980 gnus-newsgroup-name)))
2981 (let ((select (read-string (if def
2982 (concat "Group Name ("
2983 def "): ")
2984 "Group Name: "))))
2985 (if (and (equal "" select)
2986 def)
2987 def
2988 select)))))
2989 3103
2990 (if (not group) 3104 (if (not group)
2991 (gnus-agent-expire articles group force) 3105 (gnus-agent-expire articles group force)
2992 (let ( ;; Bind gnus-agent-expire-stats to enable tracking of 3106 (let ( ;; Bind gnus-agent-expire-stats to enable tracking of
2993 ;; expiration statistics of this single group 3107 ;; expiration statistics of this single group
2994 (gnus-agent-expire-stats (list 0 0 0.0))) 3108 (gnus-agent-expire-stats (list 0 0 0.0)))
2995 (if (or (not (eq articles t)) 3109 (if (or (not (eq articles t))
2996 (yes-or-no-p 3110 (yes-or-no-p
2997 (concat "Are you sure that you want to " 3111 (concat "Are you sure that you want to "
2998 "expire all articles in " group "? "))) 3112 "expire all articles in " group "? ")))
3018 (defun gnus-agent-expire-group-1 (group overview active articles force) 3132 (defun gnus-agent-expire-group-1 (group overview active articles force)
3019 ;; Internal function - requires caller to have set 3133 ;; Internal function - requires caller to have set
3020 ;; gnus-command-method, initialized overview buffer, and to have 3134 ;; gnus-command-method, initialized overview buffer, and to have
3021 ;; provided a non-nil active 3135 ;; provided a non-nil active
3022 3136
3023 (let ((dir (gnus-agent-group-pathname group))) 3137 (let ((dir (gnus-agent-group-pathname group))
3024 (when (boundp 'gnus-agent-expire-current-dirs) 3138 (file-name-coding-system nnmail-pathname-coding-system)
3025 (set 'gnus-agent-expire-current-dirs 3139 (decoded (gnus-agent-decoded-group-name group)))
3026 (cons dir 3140 (gnus-agent-with-refreshed-group
3027 (symbol-value 'gnus-agent-expire-current-dirs)))) 3141 group
3028 3142 (when (boundp 'gnus-agent-expire-current-dirs)
3029 (if (and (not force) 3143 (set 'gnus-agent-expire-current-dirs
3030 (eq 'DISABLE (gnus-agent-find-parameter group 3144 (cons dir
3031 'agent-enable-expiration))) 3145 (symbol-value 'gnus-agent-expire-current-dirs))))
3032 (gnus-message 5 "Expiry skipping over %s" group) 3146
3033 (gnus-message 5 "Expiring articles in %s" group) 3147 (if (and (not force)
3034 (gnus-agent-load-alist group) 3148 (eq 'DISABLE (gnus-agent-find-parameter group
3035 (let* ((bytes-freed 0) 3149 'agent-enable-expiration)))
3036 (files-deleted 0) 3150 (gnus-message 5 "Expiry skipping over %s" decoded)
3037 (nov-entries-deleted 0) 3151 (gnus-message 5 "Expiring articles in %s" decoded)
3038 (info (gnus-get-info group)) 3152 (gnus-agent-load-alist group)
3039 (alist gnus-agent-article-alist) 3153 (let* ((bytes-freed 0)
3040 (day (- (time-to-days (current-time)) 3154 (size-files-deleted 0.0)
3041 (gnus-agent-find-parameter group 'agent-days-until-old))) 3155 (files-deleted 0)
3042 (specials (if (and alist 3156 (nov-entries-deleted 0)
3043 (not force)) 3157 (info (gnus-get-info group))
3044 ;; This could be a bit of a problem. I need to 3158 (alist gnus-agent-article-alist)
3045 ;; keep the last article to avoid refetching 3159 (day (- (time-to-days (current-time))
3046 ;; headers when using nntp in the backend. At 3160 (gnus-agent-find-parameter group 'agent-days-until-old)))
3047 ;; the same time, if someone uses a backend 3161 (specials (if (and alist
3048 ;; that supports article moving then I may have 3162 (not force))
3049 ;; to remove the last article to complete the 3163 ;; This could be a bit of a problem. I need to
3050 ;; move. Right now, I'm going to assume that 3164 ;; keep the last article to avoid refetching
3051 ;; FORCE overrides specials. 3165 ;; headers when using nntp in the backend. At
3052 (list (caar (last alist))))) 3166 ;; the same time, if someone uses a backend
3053 (unreads ;; Articles that are excluded from the 3167 ;; that supports article moving then I may have
3054 ;; expiration process 3168 ;; to remove the last article to complete the
3055 (cond (gnus-agent-expire-all 3169 ;; move. Right now, I'm going to assume that
3056 ;; All articles are marked read by global decree 3170 ;; FORCE overrides specials.
3057 nil) 3171 (list (caar (last alist)))))
3058 ((eq articles t) 3172 (unreads ;; Articles that are excluded from the
3059 ;; All articles are marked read by function 3173 ;; expiration process
3060 ;; parameter 3174 (cond (gnus-agent-expire-all
3061 nil) 3175 ;; All articles are marked read by global decree
3062 ((not articles) 3176 nil)
3063 ;; Unread articles are marked protected from 3177 ((eq articles t)
3064 ;; expiration Don't call 3178 ;; All articles are marked read by function
3065 ;; gnus-list-of-unread-articles as it returns 3179 ;; parameter
3066 ;; articles that have not been fetched into the 3180 nil)
3067 ;; agent. 3181 ((not articles)
3068 (ignore-errors 3182 ;; Unread articles are marked protected from
3069 (gnus-agent-unread-articles group))) 3183 ;; expiration Don't call
3070 (t 3184 ;; gnus-list-of-unread-articles as it returns
3071 ;; All articles EXCEPT those named by the caller 3185 ;; articles that have not been fetched into the
3072 ;; are protected from expiration 3186 ;; agent.
3073 (gnus-sorted-difference 3187 (ignore-errors
3074 (gnus-uncompress-range 3188 (gnus-agent-unread-articles group)))
3075 (cons (caar alist) 3189 (t
3076 (caar (last alist)))) 3190 ;; All articles EXCEPT those named by the caller
3077 (sort articles '<))))) 3191 ;; are protected from expiration
3078 (marked ;; More articles that are excluded from the 3192 (gnus-sorted-difference
3079 ;; expiration process 3193 (gnus-uncompress-range
3080 (cond (gnus-agent-expire-all 3194 (cons (caar alist)
3081 ;; All articles are unmarked by global decree 3195 (caar (last alist))))
3082 nil) 3196 (sort articles '<)))))
3083 ((eq articles t) 3197 (marked ;; More articles that are excluded from the
3084 ;; All articles are unmarked by function 3198 ;; expiration process
3085 ;; parameter 3199 (cond (gnus-agent-expire-all
3086 nil) 3200 ;; All articles are unmarked by global decree
3087 (articles 3201 nil)
3088 ;; All articles may as well be unmarked as the 3202 ((eq articles t)
3089 ;; unreads list already names the articles we are 3203 ;; All articles are unmarked by function
3090 ;; going to keep 3204 ;; parameter
3091 nil) 3205 nil)
3092 (t 3206 (articles
3093 ;; Ticked and/or dormant articles are excluded 3207 ;; All articles may as well be unmarked as the
3094 ;; from expiration 3208 ;; unreads list already names the articles we are
3095 (nconc 3209 ;; going to keep
3096 (gnus-uncompress-range 3210 nil)
3097 (cdr (assq 'tick (gnus-info-marks info)))) 3211 (t
3098 (gnus-uncompress-range 3212 ;; Ticked and/or dormant articles are excluded
3099 (cdr (assq 'dormant 3213 ;; from expiration
3100 (gnus-info-marks info)))))))) 3214 (nconc
3101 (nov-file (concat dir ".overview")) 3215 (gnus-uncompress-range
3102 (cnt 0) 3216 (cdr (assq 'tick (gnus-info-marks info))))
3103 (completed -1) 3217 (gnus-uncompress-range
3104 dlist 3218 (cdr (assq 'dormant
3105 type) 3219 (gnus-info-marks info))))))))
3106 3220 (nov-file (concat dir ".overview"))
3107 ;; The normal article alist contains elements that look like 3221 (cnt 0)
3108 ;; (article# . fetch_date) I need to combine other 3222 (completed -1)
3109 ;; information with this list. For example, a flag indicating 3223 dlist
3110 ;; that a particular article MUST BE KEPT. To do this, I'm 3224 type)
3111 ;; going to transform the elements to look like (article# 3225
3112 ;; fetch_date keep_flag NOV_entry_marker) Later, I'll reverse 3226 ;; The normal article alist contains elements that look like
3113 ;; the process to generate the expired article alist. 3227 ;; (article# . fetch_date) I need to combine other
3114 3228 ;; information with this list. For example, a flag indicating
3115 ;; Convert the alist elements to (article# fetch_date nil 3229 ;; that a particular article MUST BE KEPT. To do this, I'm
3116 ;; nil). 3230 ;; going to transform the elements to look like (article#
3117 (setq dlist (mapcar (lambda (e) 3231 ;; fetch_date keep_flag NOV_entry_position) Later, I'll reverse
3118 (list (car e) (cdr e) nil nil)) alist)) 3232 ;; the process to generate the expired article alist.
3119 3233
3120 ;; Convert the keep lists to elements that look like (article# 3234 ;; Convert the alist elements to (article# fetch_date nil
3121 ;; nil keep_flag nil) then append it to the expanded dlist 3235 ;; nil).
3122 ;; These statements are sorted by ascending precidence of the 3236 (setq dlist (mapcar (lambda (e)
3123 ;; keep_flag. 3237 (list (car e) (cdr e) nil nil)) alist))
3124 (setq dlist (nconc dlist 3238
3125 (mapcar (lambda (e) 3239 ;; Convert the keep lists to elements that look like (article#
3126 (list e nil 'unread nil)) 3240 ;; nil keep_flag nil) then append it to the expanded dlist
3127 unreads))) 3241 ;; These statements are sorted by ascending precidence of the
3128 (setq dlist (nconc dlist 3242 ;; keep_flag.
3129 (mapcar (lambda (e) 3243 (setq dlist (nconc dlist
3130 (list e nil 'marked nil)) 3244 (mapcar (lambda (e)
3131 marked))) 3245 (list e nil 'unread nil))
3132 (setq dlist (nconc dlist 3246 unreads)))
3133 (mapcar (lambda (e) 3247 (setq dlist (nconc dlist
3134 (list e nil 'special nil)) 3248 (mapcar (lambda (e)
3135 specials))) 3249 (list e nil 'marked nil))
3136 3250 marked)))
3137 (set-buffer overview) 3251 (setq dlist (nconc dlist
3138 (erase-buffer) 3252 (mapcar (lambda (e)
3139 (buffer-disable-undo) 3253 (list e nil 'special nil))
3140 (when (file-exists-p nov-file) 3254 specials)))
3141 (gnus-message 7 "gnus-agent-expire: Loading overview...") 3255
3142 (nnheader-insert-file-contents nov-file) 3256 (set-buffer overview)
3143 (goto-char (point-min)) 3257 (erase-buffer)
3144 3258 (buffer-disable-undo)
3145 (let (p) 3259 (when (file-exists-p nov-file)
3146 (while (< (setq p (point)) (point-max)) 3260 (gnus-message 7 "gnus-agent-expire: Loading overview...")
3147 (condition-case nil 3261 (nnheader-insert-file-contents nov-file)
3148 ;; If I successfully read an integer (the plus zero 3262 (goto-char (point-min))
3149 ;; ensures a numeric type), prepend a marker entry 3263
3150 ;; to the list 3264 (let (p)
3151 (push (list (+ 0 (read (current-buffer))) nil nil 3265 (while (< (setq p (point)) (point-max))
3152 (set-marker (make-marker) p)) 3266 (condition-case nil
3153 dlist) 3267 ;; If I successfully read an integer (the plus zero
3154 (error 3268 ;; ensures a numeric type), append the position
3155 (gnus-message 1 "gnus-agent-expire: read error \ 3269 ;; to the list
3270 (push (list (+ 0 (read (current-buffer))) nil nil
3271 p)
3272 dlist)
3273 (error
3274 (gnus-message 1 "gnus-agent-expire: read error \
3156 occurred when reading expression at %s in %s. Skipping to next \ 3275 occurred when reading expression at %s in %s. Skipping to next \
3157 line." (point) nov-file))) 3276 line." (point) nov-file)))
3158 ;; Whether I succeeded, or failed, it doesn't matter. 3277 ;; Whether I succeeded, or failed, it doesn't matter.
3159 ;; Move to the next line then try again. 3278 ;; Move to the next line then try again.
3160 (forward-line 1))) 3279 (forward-line 1)))
3161 3280
3162 (gnus-message 3281 (gnus-message
3163 7 "gnus-agent-expire: Loading overview... Done")) 3282 7 "gnus-agent-expire: Loading overview... Done"))
3164 (set-buffer-modified-p nil) 3283 (set-buffer-modified-p nil)
3165 3284
3166 ;; At this point, all of the information is in dlist. The 3285 ;; At this point, all of the information is in dlist. The
3167 ;; only problem is that much of it is spread across multiple 3286 ;; only problem is that much of it is spread across multiple
3168 ;; entries. Sort then MERGE!! 3287 ;; entries. Sort then MERGE!!
3169 (gnus-message 7 "gnus-agent-expire: Sorting entries... ") 3288 (gnus-message 7 "gnus-agent-expire: Sorting entries... ")
3170 ;; If two entries have the same article-number then sort by 3289 ;; If two entries have the same article-number then sort by
3171 ;; ascending keep_flag. 3290 ;; ascending keep_flag.
3172 (let ((special 0) 3291 (let ((special 0)
3173 (marked 1) 3292 (marked 1)
3174 (unread 2)) 3293 (unread 2))
3175 (setq dlist 3294 (setq dlist
3176 (sort dlist 3295 (sort dlist
3177 (lambda (a b) 3296 (lambda (a b)
3178 (cond ((< (nth 0 a) (nth 0 b)) 3297 (cond ((< (nth 0 a) (nth 0 b))
3179 t) 3298 t)
3180 ((> (nth 0 a) (nth 0 b)) 3299 ((> (nth 0 a) (nth 0 b))
3181 nil) 3300 nil)
3182 (t 3301 (t
3183 (let ((a (or (symbol-value (nth 2 a)) 3302 (let ((a (or (symbol-value (nth 2 a))
3184 3)) 3303 3))
3185 (b (or (symbol-value (nth 2 b)) 3304 (b (or (symbol-value (nth 2 b))
3186 3))) 3305 3)))
3187 (<= a b)))))))) 3306 (<= a b))))))))
3188 (gnus-message 7 "gnus-agent-expire: Sorting entries... Done") 3307 (gnus-message 7 "gnus-agent-expire: Sorting entries... Done")
3189 (gnus-message 7 "gnus-agent-expire: Merging entries... ") 3308 (gnus-message 7 "gnus-agent-expire: Merging entries... ")
3190 (let ((dlist dlist)) 3309 (let ((dlist dlist))
3191 (while (cdr dlist) ; I'm not at the end-of-list 3310 (while (cdr dlist) ; I'm not at the end-of-list
3192 (if (eq (caar dlist) (caadr dlist)) 3311 (if (eq (caar dlist) (caadr dlist))
3193 (let ((first (cdr (car dlist))) 3312 (let ((first (cdr (car dlist)))
3194 (secnd (cdr (cadr dlist)))) 3313 (secnd (cdr (cadr dlist))))
3195 (setcar first (or (car first) 3314 (setcar first (or (car first)
3196 (car secnd))) ; fetch_date 3315 (car secnd))) ; fetch_date
3197 (setq first (cdr first) 3316 (setq first (cdr first)
3198 secnd (cdr secnd)) 3317 secnd (cdr secnd))
3199 (setcar first (or (car first) 3318 (setcar first (or (car first)
3200 (car secnd))) ; Keep_flag 3319 (car secnd))) ; Keep_flag
3201 (setq first (cdr first) 3320 (setq first (cdr first)
3202 secnd (cdr secnd)) 3321 secnd (cdr secnd))
3203 (setcar first (or (car first) 3322 (setcar first (or (car first)
3204 (car secnd))) ; NOV_entry_marker 3323 (car secnd))) ; NOV_entry_position
3205 3324
3206 (setcdr dlist (cddr dlist))) 3325 (setcdr dlist (cddr dlist)))
3207 (setq dlist (cdr dlist))))) 3326 (setq dlist (cdr dlist)))))
3208 (gnus-message 7 "gnus-agent-expire: Merging entries... Done") 3327
3209 3328 ;; Check the order of the entry positions. They should be in
3210 (let* ((len (float (length dlist))) 3329 ;; ascending order. If they aren't, the positions must be
3211 (alist (list nil)) 3330 ;; converted to markers.
3212 (tail-alist alist)) 3331 (when (catch 'sort-results
3213 (while dlist 3332 (let ((dlist dlist)
3214 (let ((new-completed (truncate (* 100.0 3333 (prev-pos -1)
3215 (/ (setq cnt (1+ cnt)) 3334 pos)
3216 len)))) 3335 (while dlist
3217 message-log-max) 3336 (if (setq pos (nth 3 (pop dlist)))
3218 (when (> new-completed completed) 3337 (if (< pos prev-pos)
3219 (setq completed new-completed) 3338 (throw 'sort-results 'unsorted)
3220 (gnus-message 7 "%3d%% completed..." completed))) 3339 (setq prev-pos pos))))))
3221 (let* ((entry (car dlist)) 3340 (gnus-message 7 "gnus-agent-expire: Unsorted overview; inserting markers to compensate.")
3222 (article-number (nth 0 entry)) 3341 (mapc (lambda (entry)
3223 (fetch-date (nth 1 entry)) 3342 (let ((pos (nth 3 entry)))
3224 (keep (nth 2 entry)) 3343 (if pos
3225 (marker (nth 3 entry))) 3344 (setf (nth 3 entry)
3226 3345 (set-marker (make-marker)
3227 (cond 3346 pos)))))
3228 ;; Kept articles are unread, marked, or special. 3347 dlist))
3229 (keep 3348
3230 (gnus-agent-message 10 3349 (gnus-message 7 "gnus-agent-expire: Merging entries... Done")
3231 "gnus-agent-expire: %s:%d: Kept %s article%s." 3350
3232 group article-number keep (if fetch-date " and file" "")) 3351 (let* ((len (float (length dlist)))
3233 (when fetch-date 3352 (alist (list nil))
3234 (unless (file-exists-p 3353 (tail-alist alist)
3235 (concat dir (number-to-string 3354 (position-offset 0)
3236 article-number))) 3355 )
3237 (setf (nth 1 entry) nil) 3356
3238 (gnus-agent-message 3 "gnus-agent-expire cleared \ 3357 (while dlist
3358 (let ((new-completed (truncate (* 100.0
3359 (/ (setq cnt (1+ cnt))
3360 len))))
3361 message-log-max)
3362 (when (> new-completed completed)
3363 (setq completed new-completed)
3364 (gnus-message 7 "%3d%% completed..." completed)))
3365 (let* ((entry (car dlist))
3366 (article-number (nth 0 entry))
3367 (fetch-date (nth 1 entry))
3368 (keep (nth 2 entry))
3369 (marker (nth 3 entry)))
3370
3371 (cond
3372 ;; Kept articles are unread, marked, or special.
3373 (keep
3374 (gnus-agent-message 10
3375 "gnus-agent-expire: %s:%d: Kept %s article%s."
3376 decoded article-number keep (if fetch-date " and file" ""))
3377 (when fetch-date
3378 (unless (file-exists-p
3379 (concat dir (number-to-string
3380 article-number)))
3381 (setf (nth 1 entry) nil)
3382 (gnus-agent-message 3 "gnus-agent-expire cleared \
3239 download flag on %s:%d as the cached article file is missing." 3383 download flag on %s:%d as the cached article file is missing."
3240 group (caar dlist))) 3384 decoded (caar dlist)))
3241 (unless marker 3385 (unless marker
3242 (gnus-message 1 "gnus-agent-expire detected a \ 3386 (gnus-message 1 "gnus-agent-expire detected a \
3243 missing NOV entry. Run gnus-agent-regenerate-group to restore it."))) 3387 missing NOV entry. Run gnus-agent-regenerate-group to restore it.")))
3244 (gnus-agent-append-to-list 3388 (gnus-agent-append-to-list
3245 tail-alist 3389 tail-alist
3246 (cons article-number fetch-date))) 3390 (cons article-number fetch-date)))
3247 3391
3248 ;; The following articles are READ, UNMARKED, and 3392 ;; The following articles are READ, UNMARKED, and
3249 ;; ORDINARY. See if they can be EXPIRED!!! 3393 ;; ORDINARY. See if they can be EXPIRED!!!
3250 ((setq type 3394 ((setq type
3251 (cond 3395 (cond
3252 ((not (integerp fetch-date)) 3396 ((not (integerp fetch-date))
3253 'read) ;; never fetched article (may expire 3397 'read) ;; never fetched article (may expire
3254 ;; right now) 3398 ;; right now)
3255 ((not (file-exists-p 3399 ((not (file-exists-p
3256 (concat dir (number-to-string 3400 (concat dir (number-to-string
3257 article-number)))) 3401 article-number))))
3258 (setf (nth 1 entry) nil) 3402 (setf (nth 1 entry) nil)
3259 'externally-expired) ;; Can't find the cached 3403 'externally-expired) ;; Can't find the cached
3260 ;; article. Handle case 3404 ;; article. Handle case
3261 ;; as though this article 3405 ;; as though this article
3262 ;; was never fetched. 3406 ;; was never fetched.
3263 3407
3264 ;; We now have the arrival day, so we see 3408 ;; We now have the arrival day, so we see
3265 ;; whether it's old enough to be expired. 3409 ;; whether it's old enough to be expired.
3266 ((< fetch-date day) 3410 ((< fetch-date day)
3267 'expired) 3411 'expired)
3268 (force 3412 (force
3269 'forced))) 3413 'forced)))
3270 3414
3271 ;; I found some reason to expire this entry. 3415 ;; I found some reason to expire this entry.
3272 3416
3273 (let ((actions nil)) 3417 (let ((actions nil))
3274 (when (memq type '(forced expired)) 3418 (when (memq type '(forced expired))
3275 (ignore-errors ; Just being paranoid. 3419 (ignore-errors ; Just being paranoid.
3276 (let* ((file-name (nnheader-concat dir (number-to-string 3420 (let* ((file-name (nnheader-concat dir (number-to-string
3277 article-number))) 3421 article-number)))
3278 (size (float (nth 7 (file-attributes file-name))))) 3422 (size (float (nth 7 (file-attributes file-name)))))
3279 (incf bytes-freed size) 3423 (incf bytes-freed size)
3280 (incf files-deleted) 3424 (incf size-files-deleted size)
3281 (delete-file file-name)) 3425 (incf files-deleted)
3282 (push "expired cached article" actions)) 3426 (delete-file file-name))
3283 (setf (nth 1 entry) nil) 3427 (push "expired cached article" actions))
3284 ) 3428 (setf (nth 1 entry) nil)
3285 3429 )
3286 (when marker 3430
3287 (push "NOV entry removed" actions) 3431 (when marker
3288 (goto-char marker) 3432 (push "NOV entry removed" actions)
3289 3433
3290 (incf nov-entries-deleted) 3434 (goto-char (if (markerp marker)
3291 3435 marker
3292 (let ((from (gnus-point-at-bol)) 3436 (- marker position-offset)))
3293 (to (progn (forward-line 1) (point)))) 3437
3294 (incf bytes-freed (- to from)) 3438 (incf nov-entries-deleted)
3295 (delete-region from to))) 3439
3296 3440 (let* ((from (point-at-bol))
3297 ;; If considering all articles is set, I can only 3441 (to (progn (forward-line 1) (point)))
3298 ;; expire article IDs that are no longer in the 3442 (freed (- to from)))
3299 ;; active range (That is, articles that preceed the 3443 (incf bytes-freed freed)
3300 ;; first article in the new alist). 3444 (incf position-offset freed)
3301 (if (and gnus-agent-consider-all-articles 3445 (delete-region from to)))
3302 (>= article-number (car active))) 3446
3303 ;; I have to keep this ID in the alist 3447 ;; If considering all articles is set, I can only
3304 (gnus-agent-append-to-list 3448 ;; expire article IDs that are no longer in the
3305 tail-alist (cons article-number fetch-date)) 3449 ;; active range (That is, articles that preceed the
3306 (push (format "Removed %s article number from \ 3450 ;; first article in the new alist).
3451 (if (and gnus-agent-consider-all-articles
3452 (>= article-number (car active)))
3453 ;; I have to keep this ID in the alist
3454 (gnus-agent-append-to-list
3455 tail-alist (cons article-number fetch-date))
3456 (push (format "Removed %s article number from \
3307 article alist" type) actions)) 3457 article alist" type) actions))
3308 3458
3309 (when actions 3459 (when actions
3310 (gnus-agent-message 8 "gnus-agent-expire: %s:%d: %s" 3460 (gnus-agent-message 8 "gnus-agent-expire: %s:%d: %s"
3311 group article-number 3461 decoded article-number
3312 (mapconcat 'identity actions ", "))))) 3462 (mapconcat 'identity actions ", ")))))
3313 (t 3463 (t
3314 (gnus-agent-message 3464 (gnus-agent-message
3315 10 "gnus-agent-expire: %s:%d: Article kept as \ 3465 10 "gnus-agent-expire: %s:%d: Article kept as \
3316 expiration tests failed." group article-number) 3466 expiration tests failed." decoded article-number)
3317 (gnus-agent-append-to-list 3467 (gnus-agent-append-to-list
3318 tail-alist (cons article-number fetch-date))) 3468 tail-alist (cons article-number fetch-date)))
3319 ) 3469 )
3320 3470
3321 ;; Clean up markers as I want to recycle this buffer 3471 ;; Remove markers as I intend to reuse this buffer again.
3322 ;; over several groups. 3472 (when (and marker
3323 (when marker 3473 (markerp marker))
3324 (set-marker marker nil)) 3474 (set-marker marker nil))
3325 3475
3326 (setq dlist (cdr dlist)))) 3476 (setq dlist (cdr dlist))))
3327 3477
3328 (setq alist (cdr alist)) 3478 (setq alist (cdr alist))
3329 3479
3330 (let ((inhibit-quit t)) 3480 (let ((inhibit-quit t))
3331 (unless (equal alist gnus-agent-article-alist) 3481 (unless (equal alist gnus-agent-article-alist)
3332 (setq gnus-agent-article-alist alist) 3482 (setq gnus-agent-article-alist alist)
3333 (gnus-agent-save-alist group)) 3483 (gnus-agent-save-alist group))
3334 3484
3335 (when (buffer-modified-p) 3485 (when (buffer-modified-p)
3336 (let ((coding-system-for-write 3486 (let ((coding-system-for-write
3337 gnus-agent-file-coding-system)) 3487 gnus-agent-file-coding-system))
3338 (gnus-make-directory dir) 3488 (gnus-make-directory dir)
3339 (write-region (point-min) (point-max) nov-file nil 3489 (write-region (point-min) (point-max) nov-file nil
3340 'silent) 3490 'silent)
3341 ;; clear the modified flag as that I'm not confused by 3491 ;; clear the modified flag as that I'm not confused by
3342 ;; its status on the next pass through this routine. 3492 ;; its status on the next pass through this routine.
3343 (set-buffer-modified-p nil))) 3493 (set-buffer-modified-p nil)
3344 3494 (gnus-agent-update-view-total-fetched-for group t)))
3345 (when (eq articles t) 3495
3346 (gnus-summary-update-info)))) 3496 (when (eq articles t)
3347 3497 (gnus-summary-update-info))))
3348 (when (boundp 'gnus-agent-expire-stats) 3498
3349 (let ((stats (symbol-value 'gnus-agent-expire-stats))) 3499 (when (boundp 'gnus-agent-expire-stats)
3350 (incf (nth 2 stats) bytes-freed) 3500 (let ((stats (symbol-value 'gnus-agent-expire-stats)))
3351 (incf (nth 1 stats) files-deleted) 3501 (incf (nth 2 stats) bytes-freed)
3352 (incf (nth 0 stats) nov-entries-deleted))) 3502 (incf (nth 1 stats) files-deleted)
3353 )))) 3503 (incf (nth 0 stats) nov-entries-deleted)))
3504
3505 (gnus-agent-update-files-total-fetched-for group (- size-files-deleted)))))))
3354 3506
3355 (defun gnus-agent-expire (&optional articles group force) 3507 (defun gnus-agent-expire (&optional articles group force)
3356 "Expire all old articles. 3508 "Expire all old articles.
3357 If you want to force expiring of certain articles, this function can 3509 If you want to force expiring of certain articles, this function can
3358 take ARTICLES, GROUP and FORCE parameters as well. 3510 take ARTICLES, GROUP and FORCE parameters as well.
3426 (let* ((keep (gnus-make-hashtable)) 3578 (let* ((keep (gnus-make-hashtable))
3427 ;; Formally bind gnus-agent-expire-current-dirs so that the 3579 ;; Formally bind gnus-agent-expire-current-dirs so that the
3428 ;; compiler will not complain about free references. 3580 ;; compiler will not complain about free references.
3429 (gnus-agent-expire-current-dirs 3581 (gnus-agent-expire-current-dirs
3430 (symbol-value 'gnus-agent-expire-current-dirs)) 3582 (symbol-value 'gnus-agent-expire-current-dirs))
3431 dir) 3583 dir
3584 (file-name-coding-system nnmail-pathname-coding-system))
3432 3585
3433 (gnus-sethash gnus-agent-directory t keep) 3586 (gnus-sethash gnus-agent-directory t keep)
3434 (while gnus-agent-expire-current-dirs 3587 (while gnus-agent-expire-current-dirs
3435 (setq dir (pop gnus-agent-expire-current-dirs)) 3588 (setq dir (pop gnus-agent-expire-current-dirs))
3436 (when (and (stringp dir) 3589 (when (and (stringp dir)
3483 deleting them?"))) 3636 deleting them?")))
3484 (while to-remove 3637 (while to-remove
3485 (let ((dir (pop to-remove))) 3638 (let ((dir (pop to-remove)))
3486 (if (gnus-y-or-n-p (format "Delete %s? " dir)) 3639 (if (gnus-y-or-n-p (format "Delete %s? " dir))
3487 (let* (delete-recursive 3640 (let* (delete-recursive
3641 files f
3488 (delete-recursive 3642 (delete-recursive
3489 (function 3643 (function
3490 (lambda (f-or-d) 3644 (lambda (f-or-d)
3491 (ignore-errors 3645 (ignore-errors
3492 (if (file-directory-p f-or-d) 3646 (if (file-directory-p f-or-d)
3493 (condition-case nil 3647 (condition-case nil
3494 (delete-directory f-or-d) 3648 (delete-directory f-or-d)
3495 (file-error 3649 (file-error
3496 (mapcar (lambda (f) 3650 (setq files (directory-files f-or-d))
3497 (or (member f '("." "..")) 3651 (while files
3498 (funcall delete-recursive 3652 (setq f (pop files))
3499 (nnheader-concat 3653 (or (member f '("." ".."))
3500 f-or-d f)))) 3654 (funcall delete-recursive
3501 (directory-files f-or-d)) 3655 (nnheader-concat
3656 f-or-d f))))
3502 (delete-directory f-or-d))) 3657 (delete-directory f-or-d)))
3503 (delete-file f-or-d))))))) 3658 (delete-file f-or-d)))))))
3504 (funcall delete-recursive dir)))))))))) 3659 (funcall delete-recursive dir))))))))))
3505 3660
3506 ;;;###autoload 3661 ;;;###autoload
3580 (save-excursion 3735 (save-excursion
3581 (gnus-agent-create-buffer) 3736 (gnus-agent-create-buffer)
3582 (let ((gnus-decode-encoded-word-function 'identity) 3737 (let ((gnus-decode-encoded-word-function 'identity)
3583 (gnus-decode-encoded-address-function 'identity) 3738 (gnus-decode-encoded-address-function 'identity)
3584 (file (gnus-agent-article-name ".overview" group)) 3739 (file (gnus-agent-article-name ".overview" group))
3585 cached-articles uncached-articles) 3740 cached-articles uncached-articles
3741 (file-name-coding-system nnmail-pathname-coding-system))
3586 (gnus-make-directory (nnheader-translate-file-chars 3742 (gnus-make-directory (nnheader-translate-file-chars
3587 (file-name-directory file) t)) 3743 (file-name-directory file) t))
3588 3744
3589 ;; Populate temp buffer with known headers 3745 ;; Populate temp buffer with known headers
3590 (when (file-exists-p file) 3746 (when (file-exists-p file)
3683 (let ((coding-system-for-write 3839 (let ((coding-system-for-write
3684 gnus-agent-file-coding-system)) 3840 gnus-agent-file-coding-system))
3685 (gnus-agent-check-overview-buffer) 3841 (gnus-agent-check-overview-buffer)
3686 (write-region (point-min) (point-max) file nil 'silent)) 3842 (write-region (point-min) (point-max) file nil 'silent))
3687 3843
3844 (gnus-agent-update-view-total-fetched-for group t)
3845
3688 ;; Update the group's article alist to include the newly 3846 ;; Update the group's article alist to include the newly
3689 ;; fetched articles. 3847 ;; fetched articles.
3690 (gnus-agent-load-alist group) 3848 (gnus-agent-load-alist group)
3691 (gnus-agent-save-alist group uncached-articles nil) 3849 (gnus-agent-save-alist group uncached-articles nil)
3692 ) 3850 )
3713 (or gnus-agent-cache 3871 (or gnus-agent-cache
3714 (not gnus-plugged)) 3872 (not gnus-plugged))
3715 (numberp article)) 3873 (numberp article))
3716 (let* ((gnus-command-method (gnus-find-method-for-group group)) 3874 (let* ((gnus-command-method (gnus-find-method-for-group group))
3717 (file (gnus-agent-article-name (number-to-string article) group)) 3875 (file (gnus-agent-article-name (number-to-string article) group))
3718 (buffer-read-only nil)) 3876 (buffer-read-only nil)
3877 (file-name-coding-system nnmail-pathname-coding-system))
3719 (when (and (file-exists-p file) 3878 (when (and (file-exists-p file)
3720 (> (nth 7 (file-attributes file)) 0)) 3879 (> (nth 7 (file-attributes file)) 0))
3721 (erase-buffer) 3880 (erase-buffer)
3722 (gnus-kill-all-overlays) 3881 (gnus-kill-all-overlays)
3723 (let ((coding-system-for-read gnus-cache-coding-system)) 3882 (let ((coding-system-for-read gnus-cache-coding-system))
3730 If REREAD is a list, the specified articles will be marked as unread. 3889 If REREAD is a list, the specified articles will be marked as unread.
3731 In addition, their NOV entries in .overview will be refreshed using 3890 In addition, their NOV entries in .overview will be refreshed using
3732 the articles' current headers. 3891 the articles' current headers.
3733 If REREAD is not nil, downloaded articles are marked as unread." 3892 If REREAD is not nil, downloaded articles are marked as unread."
3734 (interactive 3893 (interactive
3735 (list (let ((def (or (gnus-group-group-name) 3894 (list (gnus-agent-read-group)
3736 gnus-newsgroup-name)))
3737 (let ((select (read-string (if def
3738 (concat "Group Name ("
3739 def "): ")
3740 "Group Name: "))))
3741 (if (and (equal "" select)
3742 def)
3743 def
3744 select)))
3745 (catch 'mark 3895 (catch 'mark
3746 (while (let (c 3896 (while (let (c
3747 (cursor-in-echo-area t) 3897 (cursor-in-echo-area t)
3748 (echo-keystrokes 0)) 3898 (echo-keystrokes 0))
3749 (message "Mark as unread: (n)one / (a)ll / all (d)ownloaded articles? (n) ") 3899 (message "Mark as unread: (n)one / (a)ll / all (d)ownloaded articles? (n) ")
3757 (throw 'mark 'some))) 3907 (throw 'mark 'some)))
3758 (gnus-message 3 "Ignoring unexpected input") 3908 (gnus-message 3 "Ignoring unexpected input")
3759 (sit-for 1) 3909 (sit-for 1)
3760 t))))) 3910 t)))))
3761 (when group 3911 (when group
3762 (gnus-message 5 "Regenerating in %s" group) 3912 (gnus-message 5 "Regenerating in %s" group)
3763 (let* ((gnus-command-method (or gnus-command-method 3913 (let* ((gnus-command-method (or gnus-command-method
3764 (gnus-find-method-for-group group))) 3914 (gnus-find-method-for-group group)))
3765 (file (gnus-agent-article-name ".overview" group)) 3915 (file (gnus-agent-article-name ".overview" group))
3766 (dir (file-name-directory file)) 3916 (dir (file-name-directory file))
3767 point 3917 point
3768 (downloaded (if (file-exists-p dir) 3918 (file-name-coding-system nnmail-pathname-coding-system)
3919 (downloaded (if (file-exists-p dir)
3769 (sort (delq nil (mapcar (lambda (name) 3920 (sort (delq nil (mapcar (lambda (name)
3770 (and (not (file-directory-p (nnheader-concat dir name))) 3921 (and (not (file-directory-p (nnheader-concat dir name)))
3771 (string-to-number name))) 3922 (string-to-number name)))
3772 (directory-files dir nil "^[0-9]+$" t))) 3923 (directory-files dir nil "^[0-9]+$" t)))
3773 '>) 3924 '>)
3774 (progn (gnus-make-directory dir) nil))) 3925 (progn (gnus-make-directory dir) nil)))
3775 dl nov-arts 3926 dl nov-arts
3776 alist header 3927 alist header
3777 regenerated) 3928 regenerated)
3778 3929
3779 (mm-with-unibyte-buffer 3930 (mm-with-unibyte-buffer
3780 (if (file-exists-p file) 3931 (if (file-exists-p file)
3781 (let ((nnheader-file-coding-system 3932 (let ((nnheader-file-coding-system
3782 gnus-agent-file-coding-system)) 3933 gnus-agent-file-coding-system))
3783 (nnheader-insert-file-contents file))) 3934 (nnheader-insert-file-contents file)))
3784 (set-buffer-modified-p nil) 3935 (set-buffer-modified-p nil)
3785 3936
3786 ;; Load the article IDs found in the overview file. As a 3937 ;; Load the article IDs found in the overview file. As a
3787 ;; side-effect, validate the file contents. 3938 ;; side-effect, validate the file contents.
3788 (let ((load t)) 3939 (let ((load t))
3789 (while load 3940 (while load
3790 (setq load nil) 3941 (setq load nil)
3791 (goto-char (point-min)) 3942 (goto-char (point-min))
3792 (while (< (point) (point-max)) 3943 (while (< (point) (point-max))
3793 (cond ((and (looking-at "[0-9]+\t") 3944 (cond ((and (looking-at "[0-9]+\t")
3794 (<= (- (match-end 0) (match-beginning 0)) 9)) 3945 (<= (- (match-end 0) (match-beginning 0)) 9))
3795 (push (read (current-buffer)) nov-arts) 3946 (push (read (current-buffer)) nov-arts)
3796 (forward-line 1) 3947 (forward-line 1)
3797 (let ((l1 (car nov-arts)) 3948 (let ((l1 (car nov-arts))
3798 (l2 (cadr nov-arts))) 3949 (l2 (cadr nov-arts)))
3799 (cond ((and (listp reread) (memq l1 reread)) 3950 (cond ((and (listp reread) (memq l1 reread))
3800 (gnus-delete-line) 3951 (gnus-delete-line)
3801 (setq nov-arts (cdr nov-arts)) 3952 (setq nov-arts (cdr nov-arts))
3802 (gnus-message 4 "gnus-agent-regenerate-group: NOV\ 3953 (gnus-message 4 "gnus-agent-regenerate-group: NOV\
3803 entry of article %s deleted." l1)) 3954 entry of article %s deleted." l1))
3804 ((not l2) 3955 ((not l2)
3805 nil) 3956 nil)
3806 ((< l1 l2) 3957 ((< l1 l2)
3807 (gnus-message 3 "gnus-agent-regenerate-group: NOV\ 3958 (gnus-message 3 "gnus-agent-regenerate-group: NOV\
3808 entries are NOT in ascending order.") 3959 entries are NOT in ascending order.")
3809 ;; Don't sort now as I haven't verified 3960 ;; Don't sort now as I haven't verified
3810 ;; that every line begins with a number 3961 ;; that every line begins with a number
3811 (setq load t)) 3962 (setq load t))
3812 ((= l1 l2) 3963 ((= l1 l2)
3813 (forward-line -1) 3964 (forward-line -1)
3814 (gnus-message 4 "gnus-agent-regenerate-group: NOV\ 3965 (gnus-message 4 "gnus-agent-regenerate-group: NOV\
3815 entries contained duplicate of article %s. Duplicate deleted." l1) 3966 entries contained duplicate of article %s. Duplicate deleted." l1)
3816 (gnus-delete-line) 3967 (gnus-delete-line)
3817 (setq nov-arts (cdr nov-arts)))))) 3968 (setq nov-arts (cdr nov-arts))))))
3818 (t 3969 (t
3819 (gnus-message 1 "gnus-agent-regenerate-group: NOV\ 3970 (gnus-message 1 "gnus-agent-regenerate-group: NOV\
3820 entries contained line that did not begin with an article number. Deleted\ 3971 entries contained line that did not begin with an article number. Deleted\
3821 line.") 3972 line.")
3822 (gnus-delete-line)))) 3973 (gnus-delete-line))))
3823 (when load 3974 (when load
3824 (gnus-message 5 "gnus-agent-regenerate-group: Sorting NOV\ 3975 (gnus-message 5 "gnus-agent-regenerate-group: Sorting NOV\
3825 entries into ascending order.") 3976 entries into ascending order.")
3826 (sort-numeric-fields 1 (point-min) (point-max)) 3977 (sort-numeric-fields 1 (point-min) (point-max))
3827 (setq nov-arts nil)))) 3978 (setq nov-arts nil))))
3828 (gnus-agent-check-overview-buffer) 3979 (gnus-agent-check-overview-buffer)
3829 3980
3830 ;; Construct a new article alist whose nodes match every header 3981 ;; Construct a new article alist whose nodes match every header
3831 ;; in the .overview file. As a side-effect, missing headers are 3982 ;; in the .overview file. As a side-effect, missing headers are
3832 ;; reconstructed from the downloaded article file. 3983 ;; reconstructed from the downloaded article file.
3833 (while (or downloaded nov-arts) 3984 (while (or downloaded nov-arts)
3834 (cond ((and downloaded 3985 (cond ((and downloaded
3835 (or (not nov-arts) 3986 (or (not nov-arts)
3836 (> (car downloaded) (car nov-arts)))) 3987 (> (car downloaded) (car nov-arts))))
3837 ;; This entry is missing from the overview file 3988 ;; This entry is missing from the overview file
3838 (gnus-message 3 "Regenerating NOV %s %d..." group 3989 (gnus-message 3 "Regenerating NOV %s %d..." group
3839 (car downloaded)) 3990 (car downloaded))
3840 (let ((file (concat dir (number-to-string (car downloaded))))) 3991 (let ((file (concat dir (number-to-string (car downloaded)))))
3841 (mm-with-unibyte-buffer 3992 (mm-with-unibyte-buffer
3842 (nnheader-insert-file-contents file) 3993 (nnheader-insert-file-contents file)
3843 (nnheader-remove-body) 3994 (nnheader-remove-body)
3844 (setq header (nnheader-parse-naked-head))) 3995 (setq header (nnheader-parse-naked-head)))
3845 (mail-header-set-number header (car downloaded)) 3996 (mail-header-set-number header (car downloaded))
3846 (if nov-arts 3997 (if nov-arts
3847 (let ((key (concat "^" (int-to-string (car nov-arts)) 3998 (let ((key (concat "^" (int-to-string (car nov-arts))
3848 "\t"))) 3999 "\t")))
3849 (or (re-search-backward key nil t) 4000 (or (re-search-backward key nil t)
3850 (re-search-forward key)) 4001 (re-search-forward key))
3851 (forward-line 1)) 4002 (forward-line 1))
3852 (goto-char (point-min))) 4003 (goto-char (point-min)))
3853 (nnheader-insert-nov header)) 4004 (nnheader-insert-nov header))
3854 (setq nov-arts (cons (car downloaded) nov-arts))) 4005 (setq nov-arts (cons (car downloaded) nov-arts)))
3855 ((eq (car downloaded) (car nov-arts)) 4006 ((eq (car downloaded) (car nov-arts))
3856 ;; This entry in the overview has been downloaded 4007 ;; This entry in the overview has been downloaded
3857 (push (cons (car downloaded) 4008 (push (cons (car downloaded)
3858 (time-to-days 4009 (time-to-days
3859 (nth 5 (file-attributes 4010 (nth 5 (file-attributes
3860 (concat dir (number-to-string 4011 (concat dir (number-to-string
3861 (car downloaded))))))) alist) 4012 (car downloaded))))))) alist)
3862 (setq downloaded (cdr downloaded)) 4013 (setq downloaded (cdr downloaded))
3863 (setq nov-arts (cdr nov-arts))) 4014 (setq nov-arts (cdr nov-arts)))
3864 (t 4015 (t
3865 ;; This entry in the overview has not been downloaded 4016 ;; This entry in the overview has not been downloaded
3866 (push (cons (car nov-arts) nil) alist) 4017 (push (cons (car nov-arts) nil) alist)
3867 (setq nov-arts (cdr nov-arts))))) 4018 (setq nov-arts (cdr nov-arts)))))
3868 4019
3869 ;; When gnus-agent-consider-all-articles is set, 4020 ;; When gnus-agent-consider-all-articles is set,
3870 ;; gnus-agent-regenerate-group should NOT remove article IDs from 4021 ;; gnus-agent-regenerate-group should NOT remove article IDs from
3871 ;; the alist. Those IDs serve as markers to indicate that an 4022 ;; the alist. Those IDs serve as markers to indicate that an
3872 ;; attempt has been made to fetch that article's header. 4023 ;; attempt has been made to fetch that article's header.
3873 4024
3874 ;; When gnus-agent-consider-all-articles is NOT set, 4025 ;; When gnus-agent-consider-all-articles is NOT set,
3875 ;; gnus-agent-regenerate-group can remove the article ID of every 4026 ;; gnus-agent-regenerate-group can remove the article ID of every
3876 ;; article (with the exception of the last ID in the list - it's 4027 ;; article (with the exception of the last ID in the list - it's
3877 ;; special) that no longer appears in the overview. In this 4028 ;; special) that no longer appears in the overview. In this
3878 ;; situtation, the last article ID in the list implies that it, 4029 ;; situtation, the last article ID in the list implies that it,
3879 ;; and every article ID preceeding it, have been fetched from the 4030 ;; and every article ID preceeding it, have been fetched from the
3880 ;; server. 4031 ;; server.
3881 4032
3882 (if gnus-agent-consider-all-articles 4033 (if gnus-agent-consider-all-articles
3883 ;; Restore all article IDs that were not found in the overview file. 4034 ;; Restore all article IDs that were not found in the overview file.
3884 (let* ((n (cons nil alist)) 4035 (let* ((n (cons nil alist))
3885 (merged n) 4036 (merged n)
3886 (o (gnus-agent-load-alist group))) 4037 (o (gnus-agent-load-alist group)))
3887 (while o 4038 (while o
3888 (let ((nID (caadr n)) 4039 (let ((nID (caadr n))
3889 (oID (caar o))) 4040 (oID (caar o)))
3890 (cond ((not nID) 4041 (cond ((not nID)
3891 (setq n (setcdr n (list (list oID)))) 4042 (setq n (setcdr n (list (list oID))))
3892 (setq o (cdr o))) 4043 (setq o (cdr o)))
3893 ((< oID nID) 4044 ((< oID nID)
3894 (setcdr n (cons (list oID) (cdr n))) 4045 (setcdr n (cons (list oID) (cdr n)))
3895 (setq o (cdr o))) 4046 (setq o (cdr o)))
3896 ((= oID nID) 4047 ((= oID nID)
3897 (setq o (cdr o)) 4048 (setq o (cdr o))
3898 (setq n (cdr n))) 4049 (setq n (cdr n)))
3899 (t 4050 (t
3900 (setq n (cdr n)))))) 4051 (setq n (cdr n))))))
3901 (setq alist (cdr merged))) 4052 (setq alist (cdr merged)))
3902 ;; Restore the last article ID if it is not already in the new alist 4053 ;; Restore the last article ID if it is not already in the new alist
3903 (let ((n (last alist)) 4054 (let ((n (last alist))
3904 (o (last (gnus-agent-load-alist group)))) 4055 (o (last (gnus-agent-load-alist group))))
3905 (cond ((not o) 4056 (cond ((not o)
3906 nil) 4057 nil)
3907 ((not n) 4058 ((not n)
3908 (push (cons (caar o) nil) alist)) 4059 (push (cons (caar o) nil) alist))
3909 ((< (caar n) (caar o)) 4060 ((< (caar n) (caar o))
3910 (setcdr n (list (car o))))))) 4061 (setcdr n (list (car o)))))))
3911 4062
3912 (let ((inhibit-quit t)) 4063 (let ((inhibit-quit t))
3913 (if (setq regenerated (buffer-modified-p)) 4064 (if (setq regenerated (buffer-modified-p))
3914 (let ((coding-system-for-write gnus-agent-file-coding-system)) 4065 (let ((coding-system-for-write gnus-agent-file-coding-system))
3915 (write-region (point-min) (point-max) file nil 'silent))) 4066 (write-region (point-min) (point-max) file nil 'silent)))
3916 4067
3917 (setq regenerated (or regenerated 4068 (setq regenerated (or regenerated
3918 (and reread gnus-agent-article-alist) 4069 (and reread gnus-agent-article-alist)
3919 (not (equal alist gnus-agent-article-alist)))) 4070 (not (equal alist gnus-agent-article-alist))))
3920 4071
3921 (setq gnus-agent-article-alist alist) 4072 (setq gnus-agent-article-alist alist)
3922 4073
3923 (when regenerated 4074 (when regenerated
3924 (gnus-agent-save-alist group) 4075 (gnus-agent-save-alist group)
3925 4076
3926 ;; I have to alter the group's active range NOW as 4077 ;; I have to alter the group's active range NOW as
3927 ;; gnus-make-ascending-articles-unread will use it to 4078 ;; gnus-make-ascending-articles-unread will use it to
3928 ;; recalculate the number of unread articles in the group 4079 ;; recalculate the number of unread articles in the group
3929 4080
3930 (let ((group (gnus-group-real-name group)) 4081 (let ((group (gnus-group-real-name group))
3931 (group-active (or (gnus-active group) 4082 (group-active (or (gnus-active group)
3932 (gnus-activate-group group)))) 4083 (gnus-activate-group group))))
3933 (gnus-agent-possibly-alter-active group group-active))))) 4084 (gnus-agent-possibly-alter-active group group-active)))))
3934 4085
3935 (when (and reread gnus-agent-article-alist) 4086 (when (and reread gnus-agent-article-alist)
3936 (gnus-agent-synchronize-group-flags 4087 (gnus-agent-synchronize-group-flags
3937 group 4088 group
3938 (list (list 4089 (list (list
3939 (if (listp reread) 4090 (if (listp reread)
3940 reread 4091 reread
3941 (delq nil (mapcar (function (lambda (c) 4092 (delq nil (mapcar (function (lambda (c)
3942 (cond ((eq reread t) 4093 (cond ((eq reread t)
3943 (car c)) 4094 (car c))
3944 ((cdr c) 4095 ((cdr c)
3945 (car c))))) 4096 (car c)))))
3946 gnus-agent-article-alist))) 4097 gnus-agent-article-alist)))
3947 'del '(read))) 4098 'del '(read)))
3948 gnus-command-method) 4099 gnus-command-method)
3949 4100
3950 (when (gnus-buffer-live-p gnus-group-buffer) 4101 (when regenerated
3951 (gnus-group-update-group group t))) 4102 (gnus-agent-update-files-total-fetched-for group nil)))
3952 4103
3953 (gnus-message 5 "") 4104 (gnus-message 5 "")
3954 regenerated))) 4105 regenerated)))
3955 4106
3956 ;;;###autoload 4107 ;;;###autoload
3957 (defun gnus-agent-regenerate (&optional clean reread) 4108 (defun gnus-agent-regenerate (&optional clean reread)
3958 "Regenerate all agent covered files. 4109 "Regenerate all agent covered files.
3959 If CLEAN, obsolete (ignore)." 4110 If CLEAN, obsolete (ignore)."
3994 (if (eq status 'offline) 'online 'offline)))) 4145 (if (eq status 'offline) 'online 'offline))))
3995 4146
3996 (defun gnus-agent-group-covered-p (group) 4147 (defun gnus-agent-group-covered-p (group)
3997 (gnus-agent-method-p (gnus-group-method group))) 4148 (gnus-agent-method-p (gnus-group-method group)))
3998 4149
4150 (defun gnus-agent-update-files-total-fetched-for
4151 (group delta &optional method path)
4152 "Update, or set, the total disk space used by the articles that the
4153 agent has fetched."
4154 (when gnus-agent-total-fetched-hashtb
4155 (gnus-agent-with-refreshed-group
4156 group
4157 ;; if null, gnus-agent-group-pathname will calc method.
4158 (let* ((gnus-command-method method)
4159 (path (or path (gnus-agent-group-pathname group)))
4160 (entry (or (gnus-gethash path gnus-agent-total-fetched-hashtb)
4161 (gnus-sethash path (make-list 3 0)
4162 gnus-agent-total-fetched-hashtb)))
4163 (file-name-coding-system nnmail-pathname-coding-system))
4164 (when (listp delta)
4165 (if delta
4166 (let ((sum 0.0)
4167 file)
4168 (while (setq file (pop delta))
4169 (incf sum (float (or (nth 7 (file-attributes
4170 (nnheader-concat
4171 path
4172 (if (numberp file)
4173 (number-to-string file)
4174 file)))) 0))))
4175 (setq delta sum))
4176 (let ((sum (- (nth 2 entry)))
4177 (info (directory-files-and-attributes path nil "^-?[0-9]+$" t))
4178 file)
4179 (while (setq file (pop info))
4180 (incf sum (float (or (nth 8 file) 0))))
4181 (setq delta sum))))
4182
4183 (setq gnus-agent-need-update-total-fetched-for t)
4184 (incf (nth 2 entry) delta)))))
4185
4186 (defun gnus-agent-update-view-total-fetched-for
4187 (group agent-over &optional method path)
4188 "Update, or set, the total disk space used by the .agentview and
4189 .overview files. These files are calculated separately as they can be
4190 modified."
4191 (when gnus-agent-total-fetched-hashtb
4192 (gnus-agent-with-refreshed-group
4193 group
4194 ;; if null, gnus-agent-group-pathname will calc method.
4195 (let* ((gnus-command-method method)
4196 (path (or path (gnus-agent-group-pathname group)))
4197 (entry (or (gnus-gethash path gnus-agent-total-fetched-hashtb)
4198 (gnus-sethash path (make-list 3 0)
4199 gnus-agent-total-fetched-hashtb)))
4200 (file-name-coding-system nnmail-pathname-coding-system)
4201 (size (or (nth 7 (file-attributes
4202 (nnheader-concat
4203 path (if agent-over
4204 ".overview"
4205 ".agentview"))))
4206 0)))
4207 (setq gnus-agent-need-update-total-fetched-for t)
4208 (setf (nth (if agent-over 1 0) entry) size)))))
4209
4210 (defun gnus-agent-total-fetched-for (group &optional method no-inhibit)
4211 "Get the total disk space used by the specified GROUP."
4212 (unless (equal group "dummy.group")
4213 (unless gnus-agent-total-fetched-hashtb
4214 (setq gnus-agent-total-fetched-hashtb (gnus-make-hashtable 1024)))
4215
4216 ;; if null, gnus-agent-group-pathname will calc method.
4217 (let* ((gnus-command-method method)
4218 (path (gnus-agent-group-pathname group))
4219 (entry (gnus-gethash path gnus-agent-total-fetched-hashtb)))
4220 (if entry
4221 (apply '+ entry)
4222 (let ((gnus-agent-inhibit-update-total-fetched-for (not no-inhibit)))
4223 (+
4224 (gnus-agent-update-view-total-fetched-for group nil method path)
4225 (gnus-agent-update-view-total-fetched-for group t method path)
4226 (gnus-agent-update-files-total-fetched-for group nil method path)))))))
4227
3999 (provide 'gnus-agent) 4228 (provide 'gnus-agent)
4000 4229
4001 ;;; arch-tag: b0ba4afc-5229-4cee-ad25-9956daa4e91e 4230 ;;; arch-tag: b0ba4afc-5229-4cee-ad25-9956daa4e91e
4002 ;;; gnus-agent.el ends here 4231 ;;; gnus-agent.el ends here