X-Git-Url: http://git.chise.org/gitweb/?a=blobdiff_plain;f=lisp%2Fgnus-agent.el;h=d37bd7b16649dcc75ff5704f875df49c1c83f5d9;hb=a45dd507bf71d9e3fbfb6067896554323b02b643;hp=d6162630f638239bb1f78aa728ac393d708a1ced;hpb=c878a0e90808e45d76bd8a1356dfb03de44b38b2;p=elisp%2Fgnus.git- diff --git a/lisp/gnus-agent.el b/lisp/gnus-agent.el index d616263..d37bd7b 100644 --- a/lisp/gnus-agent.el +++ b/lisp/gnus-agent.el @@ -1,7 +1,7 @@ ;;; gnus-agent.el --- unplugged support for Semi-gnus ;; Copyright (C) 1997,98 Free Software Foundation, Inc. -;; Author: Lars Magne Ingebrigtsen +;; Author: Lars Magne Ingebrigtsen ;; This file is part of GNU Emacs. ;; GNU Emacs is free software; you can redistribute it and/or modify @@ -77,6 +77,8 @@ If nil, only read articles will be expired." ;;; Internal variables +(defvar gnus-agent-meta-information-header "X-Gnus-Agent-Meta-Information") + (defvar gnus-agent-history-buffers nil) (defvar gnus-agent-buffer-alist nil) (defvar gnus-agent-article-alist nil) @@ -90,7 +92,7 @@ If nil, only read articles will be expired." (defvar gnus-agent-spam-hashtb nil) (defvar gnus-agent-file-name nil) (defvar gnus-agent-send-mail-function nil) -(defvar gnus-agent-article-file-coding-system 'no-conversion) +(defvar gnus-agent-file-coding-system 'no-conversion) ;; Dynamic variables (defvar gnus-headers) @@ -105,7 +107,7 @@ If nil, only read articles will be expired." (gnus-agent-read-servers) (gnus-category-read) (setq gnus-agent-overview-buffer - (get-buffer-create " *Gnus agent overview*")) + (gnus-get-buffer-create " *Gnus agent overview*")) (add-hook 'gnus-group-mode-hook 'gnus-agent-mode) (add-hook 'gnus-summary-mode-hook 'gnus-agent-mode) (add-hook 'gnus-server-mode-hook 'gnus-agent-mode)) @@ -127,7 +129,7 @@ If nil, only read articles will be expired." "Load FILE and do a `read' there." (nnheader-temp-write nil (ignore-errors - (insert-file-contents file) + (nnheader-insert-file-contents file) (goto-char (point-min)) (read (current-buffer))))) @@ -201,7 +203,8 @@ If nil, only read articles will be expired." (push (cons mode (symbol-value (intern (format "gnus-agent-%s-mode-map" buffer)))) minor-mode-map-alist)) - (gnus-agent-toggle-plugged gnus-plugged) + (when (eq major-mode 'gnus-group-mode) + (gnus-agent-toggle-plugged gnus-plugged)) (gnus-run-hooks 'gnus-agent-mode-hook (intern (format "gnus-agent-%s-mode-hook" buffer))))) @@ -330,19 +333,34 @@ agent minor mode in all Gnus buffers." (re-search-forward (concat "^" (regexp-quote mail-header-separator) "\n")) (replace-match "\n") + (gnus-agent-insert-meta-information 'mail) (gnus-request-accept-article "nndraft:queue"))) +(defun gnus-agent-insert-meta-information (type &optional method) + "Insert meta-information into the message that says how it's to be posted. +TYPE can be either `mail' or `news'. If the latter METHOD can +be a select method." + (save-excursion + (message-remove-header gnus-agent-meta-information-header) + (goto-char (point-min)) + (insert gnus-agent-meta-information-header ": " + (symbol-name type) " " (format "%S" method) + "\n") + (forward-char -1) + (while (search-backward "\n" nil t) + (replace-match "\\n" t t)))) + ;;; ;;; Group mode commands ;;; (defun gnus-agent-fetch-groups (n) - "Put all new articles in the current groups into the agent." + "Put all new articles in the current groups into the Agent." (interactive "P") (gnus-group-iterate n 'gnus-agent-fetch-group)) (defun gnus-agent-fetch-group (group) - "Put all new articles in GROUP into the agent." + "Put all new articles in GROUP into the Agent." (interactive (list (gnus-group-group-name))) (unless group (error "No group on the current line")) @@ -386,7 +404,7 @@ agent minor mode in all Gnus buffers." (error "Server already in the agent program")) (push method gnus-agent-covered-methods) (gnus-agent-write-servers) - (message "Entered %s into the agent" server))) + (message "Entered %s into the Agent" server))) (defun gnus-agent-remove-server (server) "Remove SERVER from the agent program." @@ -499,8 +517,8 @@ the actual number of articles toggled is returned." (let* ((gnus-command-method method) (file (gnus-agent-lib-file "active"))) (gnus-make-directory (file-name-directory file)) - (let ((coding-system-for-write gnus-agent-article-file-coding-system)) - (write-region (point-min) (point-max) file nil 'silent)) + (write-region-as-coding-system + gnus-agent-file-coding-system (point-min) (point-max) file nil 'silent) (when (file-exists-p (gnus-agent-lib-file "groups")) (delete-file (gnus-agent-lib-file "groups")))))) @@ -508,9 +526,32 @@ the actual number of articles toggled is returned." (let* ((gnus-command-method method) (file (gnus-agent-lib-file "groups"))) (gnus-make-directory (file-name-directory file)) - (write-region (point-min) (point-max) file nil 'silent)) + (write-region-as-coding-system + gnus-agent-file-coding-system (point-min) (point-max) file nil 'silent) (when (file-exists-p (gnus-agent-lib-file "active")) - (delete-file (gnus-agent-lib-file "active")))) + (delete-file (gnus-agent-lib-file "active"))))) + +(defun gnus-agent-save-group-info (method group active) + (when (gnus-agent-method-p method) + (let* ((gnus-command-method method) + (file (if nntp-server-list-active-group + (gnus-agent-lib-file "active") + (gnus-agent-lib-file "groups")))) + (gnus-make-directory (file-name-directory file)) + (nnheader-temp-write file + (when (file-exists-p file) + (nnheader-insert-file-contents file)) + (goto-char (point-min)) + (if nntp-server-list-active-group + (progn + (when (re-search-forward + (concat "^" (regexp-quote group) " ") nil t) + (gnus-delete-line)) + (insert group " " (number-to-string (cdr active)) " " + (number-to-string (car active)) " y\n")) + (when (re-search-forward (concat (regexp-quote group) " ") nil t) + (gnus-delete-line)) + (insert-buffer-substring nntp-server-buffer)))))) (defun gnus-agent-group-path (group) "Translate GROUP into a path." @@ -542,7 +583,7 @@ the actual number of articles toggled is returned." (defun gnus-agent-open-history () (save-excursion (push (cons (gnus-agent-method) - (set-buffer (get-buffer-create + (set-buffer (gnus-get-buffer-create (format " *Gnus agent %s history*" (gnus-agent-method))))) gnus-agent-history-buffers) @@ -557,8 +598,9 @@ the actual number of articles toggled is returned." (save-excursion (set-buffer gnus-agent-current-history) (gnus-make-directory (file-name-directory gnus-agent-file-name)) - (write-region (1+ (point-min)) (point-max) - gnus-agent-file-name nil 'silent))) + (write-region-as-coding-system + gnus-agent-file-coding-system + (1+ (point-min)) (point-max) gnus-agent-file-name nil 'silent))) (defun gnus-agent-close-history () (when (gnus-buffer-live-p gnus-agent-current-history) @@ -599,7 +641,7 @@ the actual number of articles toggled is returned." ;;; (defun gnus-agent-fetch-articles (group articles) - "Fetch ARTICLES from GROUP and put them into the agent." + "Fetch ARTICLES from GROUP and put them into the Agent." (when articles ;; Prune off articles that we have already fetched. (while (and articles @@ -616,15 +658,14 @@ the actual number of articles toggled is returned." (gnus-agent-group-path group) "/")) (date (gnus-time-to-day (current-time))) (case-fold-search t) - pos alists crosses id elem) + pos crosses id elem) (gnus-make-directory dir) (gnus-message 7 "Fetching articles for %s..." group) ;; Fetch the articles from the backend. (if (gnus-check-backend-function 'retrieve-articles group) (setq pos (gnus-retrieve-articles articles group)) (nnheader-temp-write nil - (let ((buf (current-buffer)) - article) + (let (article) (while (setq article (pop articles)) (when (gnus-request-article article group) (goto-char (point-max)) @@ -632,7 +673,7 @@ the actual number of articles toggled is returned." (insert-buffer-substring nntp-server-buffer))) (copy-to-buffer nntp-server-buffer (point-min) (point-max)) (setq pos (nreverse pos))))) - ;; Then save these articles into the agent. + ;; Then save these articles into the Agent. (save-excursion (set-buffer nntp-server-buffer) (while pos @@ -656,11 +697,10 @@ the actual number of articles toggled is returned." (if (not (re-search-forward "^Message-ID: *<\\([^>\n]+\\)>" nil t)) (setq id "No-Message-ID-in-article") (setq id (buffer-substring (match-beginning 1) (match-end 1)))) - (let ((coding-system-for-write - gnus-agent-article-file-coding-system)) - (write-region (point-min) (point-max) - (concat dir (number-to-string (caar pos))) - nil 'silent)) + (write-region-as-coding-system + gnus-agent-file-coding-system + (point-min) (point-max) + (concat dir (number-to-string (caar pos))) nil 'silent) (when (setq elem (assq (caar pos) gnus-agent-article-alist)) (setcdr elem t)) (gnus-agent-enter-history @@ -684,7 +724,7 @@ the actual number of articles toggled is returned." gnus-agent-group-alist)) (setcdr alist (cons (cons (cdar crosses) t) (cdr alist))) (save-excursion - (set-buffer (get-buffer-create (format " *Gnus agent overview %s*" + (set-buffer (gnus-get-buffer-create (format " *Gnus agent overview %s*" group))) (when (= (point-max) (point-min)) (push (cons group (current-buffer)) gnus-agent-buffer-alist) @@ -700,10 +740,12 @@ the actual number of articles toggled is returned." (save-excursion (while gnus-agent-buffer-alist (set-buffer (cdar gnus-agent-buffer-alist)) - (write-region (point-min) (point-max) - (gnus-agent-article-name ".overview" - (caar gnus-agent-buffer-alist)) - nil 'silent) + (write-region-as-coding-system + gnus-agent-file-coding-system + (point-min) (point-max) + (gnus-agent-article-name ".overview" + (caar gnus-agent-buffer-alist)) + nil 'silent) (pop gnus-agent-buffer-alist)) (while gnus-agent-group-alist (nnheader-temp-write (caar gnus-agent-group-alist) @@ -711,18 +753,14 @@ the actual number of articles toggled is returned." (insert "\n")) (pop gnus-agent-group-alist)))) -(defun gnus-agent-fetch-headers (group articles &optional force) - (gnus-agent-load-alist group) - ;; Find out what headers we need to retrieve. - (when articles - (while (and articles - (assq (car articles) gnus-agent-article-alist)) - (pop articles)) - (let ((arts articles)) - (while (cdr arts) - (if (assq (cadr arts) gnus-agent-article-alist) - (setcdr arts (cddr arts)) - (setq arts (cdr arts))))) +(defun gnus-agent-fetch-headers (group &optional force) + (let ((articles (if (gnus-agent-load-alist group) + (gnus-sorted-intersection + (gnus-list-of-unread-articles group) + (gnus-uncompress-range + (cons (1+ (caar (last gnus-agent-article-alist))) + (cdr (gnus-active group))))) + (gnus-list-of-unread-articles group)))) ;; Fetch them. (when articles (gnus-message 7 "Fetching headers for %s..." group) @@ -730,17 +768,6 @@ the actual number of articles toggled is returned." (set-buffer nntp-server-buffer) (unless (eq 'nov (gnus-retrieve-headers articles group)) (nnvirtual-convert-headers)) - ;; - ;; To gnus-agent-expire work fine with no Xref field in .overview - ;; Tatsuya Ichikawa - (goto-char (point-min)) - (while (not (eobp)) - (goto-char (point-at-eol)) - (insert "\t") - (forward-line 1)) - ;; Tatsuya Ichikawa - ;; To gnus-agent-expire work fine with no Xref field in .overview - ;; ;; Save these headers for later processing. (copy-to-buffer gnus-agent-overview-buffer (point-min) (point-max)) (let (file) @@ -749,9 +776,15 @@ the actual number of articles toggled is returned." (gnus-agent-braid-nov group articles file)) (gnus-make-directory (nnheader-translate-file-chars (file-name-directory file))) - (write-region (point-min) (point-max) file nil 'silent) - (gnus-agent-save-alist group articles nil)) - t)))) + (write-region-as-coding-system + gnus-agent-file-coding-system + (point-min) (point-max) file nil 'silent) + (gnus-agent-save-alist group articles nil) + (gnus-agent-enter-history + "last-header-fetched-for-session" + (list (cons group (nth (- (length articles) 1) articles))) + (gnus-time-to-day (current-time))) + articles))))) (defsubst gnus-agent-copy-nov-line (article) (let (b e) @@ -759,47 +792,48 @@ the actual number of articles toggled is returned." (setq b (point)) (if (eq article (read (current-buffer))) (setq e (progn (forward-line 1) (point))) - (setq e b)) + (progn + (beginning-of-line) + (setq e b))) (set-buffer nntp-server-buffer) (insert-buffer-substring gnus-agent-overview-buffer b e))) (defun gnus-agent-braid-nov (group articles file) - (let (beg end) - (set-buffer gnus-agent-overview-buffer) - (goto-char (point-min)) - (set-buffer nntp-server-buffer) - (erase-buffer) - (nnheader-insert-file-contents file) - (goto-char (point-min)) - (if (or (= (point-min) (point-max)) - (progn - (forward-line -1) - (< (read (current-buffer)) (car articles)))) - ;; We have only headers that are after the older headers, - ;; so we just append them. - (progn - (goto-char (point-max)) - (insert-buffer-substring gnus-agent-overview-buffer)) - ;; We do it the hard way. - (nnheader-find-nov-line (car articles)) - (gnus-agent-copy-nov-line (car articles)) - (pop articles) - (while (and articles - (not (eobp))) - (while (and (not (eobp)) - (< (read (current-buffer)) (car articles))) - (forward-line 1)) - (beginning-of-line) - (unless (eobp) - (gnus-agent-copy-nov-line (car articles)) - (setq articles (cdr articles)))) - (when articles - (let (b e) - (set-buffer gnus-agent-overview-buffer) - (setq b (point) - e (point-max)) - (set-buffer nntp-server-buffer) - (insert-buffer-substring gnus-agent-overview-buffer b e)))))) + (set-buffer gnus-agent-overview-buffer) + (goto-char (point-min)) + (set-buffer nntp-server-buffer) + (erase-buffer) + (nnheader-insert-file-contents file) + (goto-char (point-max)) + (if (or (= (point-min) (point-max)) + (progn + (forward-line -1) + (< (read (current-buffer)) (car articles)))) + ;; We have only headers that are after the older headers, + ;; so we just append them. + (progn + (goto-char (point-max)) + (insert-buffer-substring gnus-agent-overview-buffer)) + ;; We do it the hard way. + (nnheader-find-nov-line (car articles)) + (gnus-agent-copy-nov-line (car articles)) + (pop articles) + (while (and articles + (not (eobp))) + (while (and (not (eobp)) + (< (read (current-buffer)) (car articles))) + (forward-line 1)) + (beginning-of-line) + (unless (eobp) + (gnus-agent-copy-nov-line (car articles)) + (setq articles (cdr articles)))) + (when articles + (let (b e) + (set-buffer gnus-agent-overview-buffer) + (setq b (point) + e (point-max)) + (set-buffer nntp-server-buffer) + (insert-buffer-substring gnus-agent-overview-buffer b e))))) (defun gnus-agent-load-alist (group &optional dir) "Load the article-state alist for GROUP." @@ -810,7 +844,7 @@ the actual number of articles toggled is returned." (gnus-agent-article-name ".agentview" group))))) (defun gnus-agent-save-alist (group &optional articles state dir) - "Load the article-state alist for GROUP." + "Save the article-state alist for GROUP." (nnheader-temp-write (if dir (concat dir ".agentview") (gnus-agent-article-name ".agentview" group)) @@ -847,11 +881,12 @@ the actual number of articles toggled is returned." (setq gnus-command-method (car methods)) (when (or (gnus-server-opened gnus-command-method) (gnus-open-server gnus-command-method)) - (setq groups (gnus-groups-from-server (pop methods))) + (setq groups (gnus-groups-from-server (car methods))) (gnus-agent-with-fetch (while (setq group (pop groups)) (when (<= (gnus-group-level group) gnus-agent-handle-level) - (gnus-agent-fetch-group-1 group gnus-command-method)))))) + (gnus-agent-fetch-group-1 group gnus-command-method))))) + (pop methods)) (gnus-message 6 "Finished fetching articles into the Gnus agent")))) (defun gnus-agent-fetch-group-1 (group method) @@ -859,11 +894,11 @@ the actual number of articles toggled is returned." (let ((gnus-command-method method) gnus-newsgroup-dependencies gnus-newsgroup-headers gnus-newsgroup-scored gnus-headers gnus-score - gnus-use-cache articles score arts + gnus-use-cache articles arts category predicate info marks score-param) ;; Fetch headers. - (when (and (setq articles (gnus-list-of-unread-articles group)) - (gnus-agent-fetch-headers group articles)) + (when (and (or (gnus-active group) (gnus-activate-group group)) + (setq articles (gnus-agent-fetch-headers group))) ;; Parse them and see which articles we want to fetch. (setq gnus-newsgroup-dependencies (make-vector (length articles) 0)) @@ -931,8 +966,8 @@ the actual number of articles toggled is returned." (defvar gnus-category-buffer "*Agent Category*") (defvar gnus-category-line-format-alist - `((?c name ?s) - (?g groups ?d))) + `((?c gnus-tmp-name ?s) + (?g gnus-tmp-groups ?d))) (defvar gnus-category-mode-line-format-alist `((?u user-defined ?s))) @@ -1008,15 +1043,15 @@ The following commands are available: (defalias 'gnus-category-position-point 'gnus-goto-colon) (defun gnus-category-insert-line (category) - (let* ((name (car category)) - (groups (length (cadddr category)))) + (let* ((gnus-tmp-name (car category)) + (gnus-tmp-groups (length (cadddr category)))) (beginning-of-line) (gnus-add-text-properties (point) (prog1 (1+ (point)) ;; Insert the text. (eval gnus-category-line-format-spec)) - (list 'gnus-category name)))) + (list 'gnus-category gnus-tmp-name)))) (defun gnus-enter-category-buffer () "Go to the Category buffer." @@ -1028,8 +1063,7 @@ The following commands are available: (defun gnus-category-setup-buffer () (unless (get-buffer gnus-category-buffer) (save-excursion - (set-buffer (get-buffer-create gnus-category-buffer)) - (gnus-add-current-to-buffer-list) + (set-buffer (gnus-get-buffer-create gnus-category-buffer)) (gnus-category-mode)))) (defun gnus-category-prepare () @@ -1233,18 +1267,19 @@ The following commands are available: (interactive) (let ((methods gnus-agent-covered-methods) (day (- (gnus-time-to-day (current-time)) gnus-agent-expire-days)) - (expiry-hashtb (gnus-make-hashtable 1023)) gnus-command-method sym group articles history overview file histories elem art nov-file low info unreads marked article) (save-excursion - (setq overview (get-buffer-create " *expire overview*")) + (setq overview (gnus-get-buffer-create " *expire overview*")) (while (setq gnus-command-method (pop methods)) + (let ((expiry-hashtb (gnus-make-hashtable 1023))) (gnus-agent-open-history) (set-buffer (setq gnus-agent-current-history (setq history (gnus-agent-history-buffer)))) - (unless (zerop (buffer-size)) + (goto-char (point-min)) + (when (> (buffer-size) 1) (goto-char (point-min)) (while (not (eobp)) (skip-chars-forward "^\t") @@ -1270,17 +1305,19 @@ The following commands are available: info (gnus-get-info group) unreads (ignore-errors (gnus-list-of-unread-articles group)) marked (nconc (gnus-uncompress-range - (cdr (assq 'ticked (gnus-info-marks info)))) + (cdr (assq 'tick (gnus-info-marks info)))) (gnus-uncompress-range (cdr (assq 'dormant (gnus-info-marks info))))) nov-file (gnus-agent-article-name ".overview" group)) + (gnus-agent-load-alist group) (gnus-message 5 "Expiring articles in %s" group) (set-buffer overview) (erase-buffer) (when (file-exists-p nov-file) (nnheader-insert-file-contents nov-file)) (goto-char (point-min)) + (setq article 0) (while (setq elem (pop articles)) (setq article (car elem)) (when (or (null low) @@ -1290,8 +1327,15 @@ The following commands are available: (not (memq article marked)))) ;; Find and nuke the NOV line. (while (and (not (eobp)) - (< (setq art (read (current-buffer))) article)) - (forward-line 1)) + (or (not (numberp + (setq art (read (current-buffer))))) + (< art article))) + (if (file-exists-p + (gnus-agent-article-name + (number-to-string art) group)) + (forward-line 1) + ;; Remove old NOV lines that have no articles. + (gnus-delete-line))) (if (or (eobp) (/= art article)) (beginning-of-line) @@ -1303,7 +1347,53 @@ The following commands are available: (delete-file file)) ;; Schedule the history line for nuking. (push (cdr elem) histories))) - (write-region (point-min) (point-max) nov-file nil 'silent)) + (gnus-make-directory (file-name-directory nov-file)) + (write-region-as-coding-system + gnus-agent-file-coding-system + (point-min) (point-max) nov-file nil 'silent) + ;; Delete the unwanted entries in the alist. + (setq gnus-agent-article-alist + (sort gnus-agent-article-alist 'car-less-than-car)) + (let* ((alist gnus-agent-article-alist) + (prev (cons nil alist)) + (first prev) + expired) + (while (and alist + (<= (caar alist) article)) + (if (or (not (cdar alist)) + (not (file-exists-p + (gnus-agent-article-name + (number-to-string + (caar alist)) + group)))) + (progn + (push (caar alist) expired) + (setcdr prev (setq alist (cdr alist)))) + (setq prev alist + alist (cdr alist)))) + (setq gnus-agent-article-alist (cdr first)) + ;;; Mark all articles up to the first article + ;;; in `gnus-article-alist' as read. + (when (and info (caar gnus-agent-article-alist)) + (setcar (nthcdr 2 info) + (gnus-range-add + (nth 2 info) + (cons 1 (- (caar gnus-agent-article-alist) 1))))) + ;; Maybe everything has been expired from `gnus-article-alist' + ;; and so the above marking as read could not be conducted, + ;; or there are expired article within the range of the alist. + (when (and (car expired) + (or (not (caar gnus-agent-article-alist)) + (> (car expired) + (caar gnus-agent-article-alist))) ) + (setcar (nthcdr 2 info) + (gnus-add-to-range + (nth 2 info) + (nreverse expired)))) + (gnus-dribble-enter + (concat "(gnus-group-set-info '" + (gnus-prin1-to-string info) + ")")))) expiry-hashtb) (set-buffer history) (setq histories (nreverse (sort histories '<))) @@ -1312,7 +1402,7 @@ The following commands are available: (gnus-delete-line)) (gnus-agent-save-history) (gnus-agent-close-history)) - (gnus-message 4 "Expiry...done"))))) + (gnus-message 4 "Expiry...done")))))) ;;;###autoload (defun gnus-agent-batch ()