+2000-12-04 22:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-win.el (gnus-configure-frame): Save selected window.
+
+2000-02-15 Andrew Innes <andrewi@gnu.org>
+
+ * nnmbox.el: Require gnus-range.
+ (nnmbox-group-building-active-articles): New variable.
+ (nnmbox-group-active-articles): New variable; this is a cache of
+ all active articles by group and number.
+ (nnmbox-in-header-p): New function.
+ (nnmbox-find-article): New function.
+ (nnmbox-record-active-article): New function.
+ (nnmbox-record-deleted-article): New function.
+ (nnmbox-is-article-active-p): New function.
+ (nnmbox-retrieve-headers): Use nnmbox-find-article.
+ (nnmbox-request-article): Ditto. Also supply extra arg to
+ nnmbox-article-group-number.
+ (nnmbox-request-expire-articles): Ditto.
+ (nnmbox-request-move-article): Ditto.
+ (nnmbox-request-replace-article): Ditto.
+ (nnmbox-request-rename-group): Rename group entry in active
+ article cache.
+ (nnmbox-delete-mail): Update active article cache, unless article
+ is being replaced.
+ (nnmbox-possibly-change-newsgroup): Call nnmbox-read-mbox, rather
+ than partially duplicating it.
+ (nnmbox-article-group-number): Add extra `this-line' arg, to
+ handle articles belonging to multiple groups.
+ (nnmbox-save-mail): Update active article cache.
+ (nnmbox-read-mbox): Build active article cache when loading mbox.
+ Also do some repair work, if we find articles that are missing the
+ appropriate X-Gnus-Newsgroup lines in the header. We can usually
+ reconstruct these from Xref info.
+
+2000-12-04 18:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * mail-source.el (mail-source-report-new-mail): Use
+ nnheader-run-at-time.
+
+2000-02-15 Andrew Innes <andrewi@gnu.org>
+
+ * mail-source.el (mail-source-fetch-pop): Clear pop password when
+ an error is thrown, and then rethrow the error.
+ (mail-source-check-pop): Ditto.
+ (mail-source-start-idle-timer): Prevent multiple pop checks
+ running if the check takes a long time.
+
+2000-12-04 14:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-msg.el (gnus-msg-mail): COMPOSEFUNC should return t if
+ succeed.
+
+2000-12-04 13:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-win.el (gnus-configure-windows): Make sure
+ nntp-server-buffer is live.
+ (gnus-remove-some-windows): switch-to-buffer -> set-buffer.
+
+2000-11-21 Stefan Monnier <monnier@cs.yale.edu>
+
+ * gnus-win.el (gnus-configure-windows): switch-to-buffer -> set-buffer.
+
2000-12-04 Andreas Jaeger <aj@suse.de>
* gnus-msg.el (gnus-summary-mail-forward): Fix typos in description.
(defun gnus-msg-mail (&rest args)
"Start editing a mail message to be sent.
Like `message-mail', but with Gnus paraphernalia, particularly the
-the Gcc: header for archiving purposes."
+Gcc: header for archiving purposes."
(interactive)
(gnus-setup-message 'message
- (apply 'message-mail args)))
+ (apply 'message-mail args))
+ ;; COMPOSEFUNC should return t if succeed. Undocumented ???
+ t)
;;;###autoload
(define-mail-user-agent 'gnus-user-agent
(defun gnus-configure-frame (split &optional window)
"Split WINDOW according to SPLIT."
- (unless window
- (setq window (or (get-buffer-window (current-buffer)) (selected-window))))
- (select-window window)
- ;; This might be an old-stylee buffer config.
- (when (vectorp split)
- (setq split (append split nil)))
- (when (or (consp (car split))
- (vectorp (car split)))
- (push 1.0 split)
- (push 'vertical split))
- ;; The SPLIT might be something that is to be evaled to
- ;; return a new SPLIT.
- (while (and (not (assq (car split) gnus-window-to-buffer))
- (gnus-functionp (car split)))
- (setq split (eval split)))
- (let* ((type (car split))
- (subs (cddr split))
- (len (if (eq type 'horizontal) (window-width) (window-height)))
- (total 0)
- (window-min-width (or gnus-window-min-width window-min-width))
- (window-min-height (or gnus-window-min-height window-min-height))
- s result new-win rest comp-subs size sub)
- (cond
- ;; Nothing to do here.
- ((null split))
- ;; Don't switch buffers.
- ((null type)
- (and (memq 'point split) window))
- ;; This is a buffer to be selected.
- ((not (memq type '(frame horizontal vertical)))
- (let ((buffer (cond ((stringp type) type)
- (t (cdr (assq type gnus-window-to-buffer))))))
- (unless buffer
- (error "Invalid buffer type: %s" type))
- (let ((buf (gnus-get-buffer-create
- (gnus-window-to-buffer-helper buffer))))
- (if (eq buf (window-buffer (selected-window))) (set-buffer buf)
- (switch-to-buffer buf)))
- (when (memq 'frame-focus split)
- (setq gnus-window-frame-focus window))
- ;; We return the window if it has the `point' spec.
- (and (memq 'point split) window)))
- ;; This is a frame split.
- ((eq type 'frame)
- (unless gnus-frame-list
- (setq gnus-frame-list (list (window-frame
- (get-buffer-window (current-buffer))))))
- (let ((i 0)
- params frame fresult)
- (while (< i (length subs))
- ;; Frame parameter is gotten from the sub-split.
- (setq params (cadr (elt subs i)))
- ;; It should be a list.
- (unless (listp params)
- (setq params nil))
- ;; Create a new frame?
- (unless (setq frame (elt gnus-frame-list i))
- (nconc gnus-frame-list (list (setq frame (make-frame params))))
- (push frame gnus-created-frames))
- ;; Is the old frame still alive?
- (unless (frame-live-p frame)
- (setcar (nthcdr i gnus-frame-list)
- (setq frame (make-frame params))))
- ;; Select the frame in question and do more splits there.
- (select-frame frame)
- (setq fresult (or (gnus-configure-frame (elt subs i)) fresult))
- (incf i))
- ;; Select the frame that has the selected buffer.
- (when fresult
- (select-frame (window-frame fresult)))))
- ;; This is a normal split.
- (t
- (when (> (length subs) 0)
- ;; First we have to compute the sizes of all new windows.
- (while subs
- (setq sub (append (pop subs) nil))
- (while (and (not (assq (car sub) gnus-window-to-buffer))
- (gnus-functionp (car sub)))
- (setq sub (eval sub)))
- (when sub
- (push sub comp-subs)
- (setq size (cadar comp-subs))
- (cond ((equal size 1.0)
- (setq rest (car comp-subs))
- (setq s 0))
- ((floatp size)
- (setq s (floor (* size len))))
- ((integerp size)
- (setq s size))
- (t
- (error "Invalid size: %s" size)))
- ;; Try to make sure that we are inside the safe limits.
- (cond ((zerop s))
- ((eq type 'horizontal)
- (setq s (max s window-min-width)))
- ((eq type 'vertical)
- (setq s (max s window-min-height))))
- (setcar (cdar comp-subs) s)
- (incf total s)))
- ;; Take care of the "1.0" spec.
- (if rest
- (setcar (cdr rest) (- len total))
- (error "No 1.0 specs in %s" split))
- ;; The we do the actual splitting in a nice recursive
- ;; fashion.
- (setq comp-subs (nreverse comp-subs))
- (while comp-subs
- (if (null (cdr comp-subs))
- (setq new-win window)
- (setq new-win
- (split-window window (cadar comp-subs)
- (eq type 'horizontal))))
- (setq result (or (gnus-configure-frame
- (car comp-subs) window)
- result))
- (select-window new-win)
- (setq window new-win)
- (setq comp-subs (cdr comp-subs))))
- ;; Return the proper window, if any.
- (when result
- (select-window result))))))
+ (let ((current-window
+ (or (get-buffer-window (current-buffer)) (selected-window))))
+ (unless window
+ (setq window current-window))
+ (select-window window)
+ ;; This might be an old-stylee buffer config.
+ (when (vectorp split)
+ (setq split (append split nil)))
+ (when (or (consp (car split))
+ (vectorp (car split)))
+ (push 1.0 split)
+ (push 'vertical split))
+ ;; The SPLIT might be something that is to be evaled to
+ ;; return a new SPLIT.
+ (while (and (not (assq (car split) gnus-window-to-buffer))
+ (gnus-functionp (car split)))
+ (setq split (eval split)))
+ (let* ((type (car split))
+ (subs (cddr split))
+ (len (if (eq type 'horizontal) (window-width) (window-height)))
+ (total 0)
+ (window-min-width (or gnus-window-min-width window-min-width))
+ (window-min-height (or gnus-window-min-height window-min-height))
+ s result new-win rest comp-subs size sub)
+ (cond
+ ;; Nothing to do here.
+ ((null split))
+ ;; Don't switch buffers.
+ ((null type)
+ (and (memq 'point split) window))
+ ;; This is a buffer to be selected.
+ ((not (memq type '(frame horizontal vertical)))
+ (let ((buffer (cond ((stringp type) type)
+ (t (cdr (assq type gnus-window-to-buffer))))))
+ (unless buffer
+ (error "Invalid buffer type: %s" type))
+ (let ((buf (gnus-get-buffer-create
+ (gnus-window-to-buffer-helper buffer))))
+ (if (eq buf (window-buffer (selected-window))) (set-buffer buf)
+ (switch-to-buffer buf)))
+ (when (memq 'frame-focus split)
+ (setq gnus-window-frame-focus window))
+ ;; We return the window if it has the `point' spec.
+ (and (memq 'point split) window)))
+ ;; This is a frame split.
+ ((eq type 'frame)
+ (unless gnus-frame-list
+ (setq gnus-frame-list (list (window-frame current-window))))
+ (let ((i 0)
+ params frame fresult)
+ (while (< i (length subs))
+ ;; Frame parameter is gotten from the sub-split.
+ (setq params (cadr (elt subs i)))
+ ;; It should be a list.
+ (unless (listp params)
+ (setq params nil))
+ ;; Create a new frame?
+ (unless (setq frame (elt gnus-frame-list i))
+ (nconc gnus-frame-list (list (setq frame (make-frame params))))
+ (push frame gnus-created-frames))
+ ;; Is the old frame still alive?
+ (unless (frame-live-p frame)
+ (setcar (nthcdr i gnus-frame-list)
+ (setq frame (make-frame params))))
+ ;; Select the frame in question and do more splits there.
+ (select-frame frame)
+ (setq fresult (or (gnus-configure-frame (elt subs i)) fresult))
+ (incf i))
+ ;; Select the frame that has the selected buffer.
+ (when fresult
+ (select-frame (window-frame fresult)))))
+ ;; This is a normal split.
+ (t
+ (when (> (length subs) 0)
+ ;; First we have to compute the sizes of all new windows.
+ (while subs
+ (setq sub (append (pop subs) nil))
+ (while (and (not (assq (car sub) gnus-window-to-buffer))
+ (gnus-functionp (car sub)))
+ (setq sub (eval sub)))
+ (when sub
+ (push sub comp-subs)
+ (setq size (cadar comp-subs))
+ (cond ((equal size 1.0)
+ (setq rest (car comp-subs))
+ (setq s 0))
+ ((floatp size)
+ (setq s (floor (* size len))))
+ ((integerp size)
+ (setq s size))
+ (t
+ (error "Invalid size: %s" size)))
+ ;; Try to make sure that we are inside the safe limits.
+ (cond ((zerop s))
+ ((eq type 'horizontal)
+ (setq s (max s window-min-width)))
+ ((eq type 'vertical)
+ (setq s (max s window-min-height))))
+ (setcar (cdar comp-subs) s)
+ (incf total s)))
+ ;; Take care of the "1.0" spec.
+ (if rest
+ (setcar (cdr rest) (- len total))
+ (error "No 1.0 specs in %s" split))
+ ;; The we do the actual splitting in a nice recursive
+ ;; fashion.
+ (setq comp-subs (nreverse comp-subs))
+ (while comp-subs
+ (if (null (cdr comp-subs))
+ (setq new-win window)
+ (setq new-win
+ (split-window window (cadar comp-subs)
+ (eq type 'horizontal))))
+ (setq result (or (gnus-configure-frame
+ (car comp-subs) window)
+ result))
+ (select-window new-win)
+ (setq window new-win)
+ (setq comp-subs (cdr comp-subs))))
+ ;; Return the proper window, if any.
+ (when result
+ (select-window result)))))))
(defvar gnus-frame-split-p nil)
;; put point in the assigned buffer, and do not touch the
;; winconf.
(select-window all-visible)
+
+ ;; Make sure "the other" buffer, nntp-server-buffer, is live.
+ (unless (gnus-buffer-live-p nntp-server-buffer)
+ (nnheader-init-server-buffer))
;; Either remove all windows or just remove all Gnus windows.
(let ((frame (selected-frame)))
(gnus-delete-windows-in-gnusey-frames))
;; Just remove some windows.
(gnus-remove-some-windows)
- (switch-to-buffer nntp-server-buffer))
+ (set-buffer nntp-server-buffer))
(select-frame frame)))
(let (gnus-window-frame-focus)
- (switch-to-buffer nntp-server-buffer)
+ (set-buffer nntp-server-buffer)
(gnus-configure-frame split)
(when gnus-window-frame-focus
(select-frame (window-frame gnus-window-frame-focus))))))))
lowest-buf buf))))
(when lowest-buf
(pop-to-buffer lowest-buf)
- (switch-to-buffer nntp-server-buffer))
+ (set-buffer nntp-server-buffer))
(mapcar (lambda (b) (delete-windows-on b t)) bufs))))
(provide 'gnus-win)
(defvar pop3-leave-mail-on-server)
(autoload 'pop3-movemail "pop3")
(autoload 'pop3-get-message-count "pop3")
- (autoload 'nnheader-cancel-timer "nnheader"))
+ (autoload 'nnheader-cancel-timer "nnheader")
+ (autoload 'nnheader-run-at-time "nnheader"))
(require 'format-spec)
(defgroup mail-source nil
(or leave
(and (boundp 'pop3-leave-mail-on-server)
pop3-leave-mail-on-server))))
- (save-excursion (pop3-movemail mail-source-crash-box))))))
+ (condition-case err
+ (save-excursion (pop3-movemail mail-source-crash-box))
+ (error
+ ;; We nix out the password in case the error
+ ;; was because of a wrong password being given.
+ (setq mail-source-password-cache
+ (delq (assoc from mail-source-password-cache)
+ mail-source-password-cache))
+ (signal (car err) (cdr err))))))))
(if result
(progn
(when (eq authentication 'password)
(pop3-port port)
(pop3-authentication-scheme
(if (eq authentication 'apop) 'apop 'pass)))
- (save-excursion (pop3-get-message-count))))))
+ (condition-case err
+ (save-excursion (pop3-get-message-count))
+ (error
+ ;; We nix out the password in case the error
+ ;; was because of a wrong password being given.
+ (setq mail-source-password-cache
+ (delq (assoc from mail-source-password-cache)
+ mail-source-password-cache))
+ (signal (car err) (cdr err))))))))
(if result
;; Inform display-time that we have new mail.
(setq mail-source-new-mail-available (> result 0))
mail-source-idle-time-delay
nil
(lambda ()
- (setq mail-source-report-new-mail-idle-timer nil)
- (mail-source-check-pop mail-source-primary-source))))
+ (mail-source-check-pop mail-source-primary-source)
+ (setq mail-source-report-new-mail-idle-timer nil))))
;; Since idle timers created when Emacs is already in the idle
;; state don't get activated until Emacs _next_ becomes idle, we
;; need to force our timer to be considered active now. We do
(setq display-time-mail-function #'mail-source-new-mail-p)
;; Set up the main timer.
(setq mail-source-report-new-mail-timer
- (run-at-time t (* 60 mail-source-report-new-mail-interval)
- #'mail-source-start-idle-timer))
+ (nnheader-run-at-time
+ (* 60 mail-source-report-new-mail-interval)
+ (* 60 mail-source-report-new-mail-interval)
+ #'mail-source-start-idle-timer))
;; When you get new mail, clear "Mail" from the mode line.
(add-hook 'nnmail-post-get-new-mail-hook
'display-time-event-handler)
(require 'message)
(require 'nnmail)
(require 'nnoo)
+(require 'gnus-range)
(nnoo-declare nnmbox)
(defvoo nnmbox-active-file-coding-system nnheader-text-coding-system)
(defvoo nnmbox-active-file-coding-system-for-write nil)
+(defvar nnmbox-group-building-active-articles nil)
+(defvar nnmbox-group-active-articles nil)
\f
;;; Interface functions
(erase-buffer)
(let ((number (length sequence))
(count 0)
- article art-string start stop)
+ article start stop)
(nnmbox-possibly-change-newsgroup newsgroup server)
(while sequence
(setq article (car sequence))
- (setq art-string (nnmbox-article-string article))
(set-buffer nnmbox-mbox-buffer)
- (when (or (search-forward art-string nil t)
- (progn (goto-char (point-min))
- (search-forward art-string nil t)))
+ (when (nnmbox-find-article article)
(setq start
(save-excursion
(re-search-backward
(nnmbox-possibly-change-newsgroup newsgroup server)
(save-excursion
(set-buffer nnmbox-mbox-buffer)
- (goto-char (point-min))
- (when (search-forward (nnmbox-article-string article) nil t)
+ (when (nnmbox-find-article article)
(let (start stop)
(re-search-backward (concat "^" message-unix-mail-delimiter) nil t)
(setq start (point))
(forward-line 1))
(if (numberp article)
(cons nnmbox-current-group article)
- (nnmbox-article-group-number)))))))
+ (nnmbox-article-group-number nil)))))))
(deffoo nnmbox-request-group (group &optional server dont-check)
(nnmbox-possibly-change-newsgroup nil server)
(save-excursion
(set-buffer nnmbox-mbox-buffer)
(while (and articles is-old)
- (goto-char (point-min))
- (when (search-forward (nnmbox-article-string (car articles)) nil t)
+ (when (nnmbox-find-article (car articles))
(if (setq is-old
(nnmail-expired-article-p
newsgroup
(nnmbox-save-buffer)
;; Find the lowest active article in this group.
(let ((active (nth 1 (assoc newsgroup nnmbox-group-alist))))
- (goto-char (point-min))
- (while (and (not (search-forward
- (nnmbox-article-string (car active)) nil t))
+ (while (and (not (nnmbox-find-article (car active)))
(<= (car active) (cdr active)))
- (setcar active (1+ (car active)))
- (goto-char (point-min))))
+ (setcar active (1+ (car active)))))
(nnmbox-save-active nnmbox-group-alist nnmbox-active-file)
(nconc rest articles))))
(save-excursion
(nnmbox-possibly-change-newsgroup group server)
(set-buffer nnmbox-mbox-buffer)
- (goto-char (point-min))
- (when (search-forward (nnmbox-article-string article) nil t)
+ (when (nnmbox-find-article article)
(nnmbox-delete-mail))
(and last (nnmbox-save-buffer))))
result))
(nnmbox-possibly-change-newsgroup group)
(save-excursion
(set-buffer nnmbox-mbox-buffer)
- (goto-char (point-min))
- (if (not (search-forward (nnmbox-article-string article) nil t))
+ (if (not (nnmbox-find-article article))
nil
(nnmbox-delete-mail t t)
(insert-buffer-substring buffer)
(setq found t))
(when found
(nnmbox-save-buffer))))
+ (let ((entry (assoc group nnmbox-group-active-articles)))
+ (when entry
+ (setcar entry new-name)))
(let ((entry (assoc group nnmbox-group-alist)))
(when entry
(setcar entry new-name))
;; delimiter line.
(defun nnmbox-delete-mail (&optional force leave-delim)
;; Delete the current X-Gnus-Newsgroup line.
+ ;; First delete record of active article, unless the article is being
+ ;; replaced, indicated by FORCE being non-nil.
+ (if (not force)
+ (nnmbox-record-deleted-article (nnmbox-article-group-number t)))
(or force
(delete-region
(progn (beginning-of-line) (point))
(match-beginning 0)))
(point-max))))
(goto-char (point-min))
- ;; Only delete the article if no other groups owns it as well.
+ ;; Only delete the article if no other group owns it as well.
(when (or force (not (re-search-forward "^X-Gnus-Newsgroup: " nil t)))
(delete-region (point-min) (point-max))))))
(nnmbox-open-server server))
(when (or (not nnmbox-mbox-buffer)
(not (buffer-name nnmbox-mbox-buffer)))
- (save-excursion
- (set-buffer (setq nnmbox-mbox-buffer
- (let ((nnheader-file-coding-system
- nnmbox-file-coding-system))
- (nnheader-find-file-noselect
- nnmbox-mbox-file nil t))))
- (buffer-disable-undo)))
+ (nnmbox-read-mbox))
(when (not nnmbox-group-alist)
(nnmail-activate 'nnmbox))
(if newsgroup
(int-to-string article) " ")
(concat "\nMessage-ID: " article)))
-(defun nnmbox-article-group-number ()
+(defun nnmbox-article-group-number (this-line)
(save-excursion
- (goto-char (point-min))
+ (if this-line
+ (beginning-of-line)
+ (goto-char (point-min)))
(when (re-search-forward "^X-Gnus-Newsgroup: +\\([^:]+\\):\\([0-9]+\\) "
nil t)
(cons (buffer-substring (match-beginning 1) (match-end 1))
(string-to-int
(buffer-substring (match-beginning 2) (match-end 2)))))))
+(defun nnmbox-in-header-p (pos)
+ "Return non-nil if POS is in the header of an article."
+ (save-excursion
+ (goto-char pos)
+ (re-search-backward (concat "^" message-unix-mail-delimiter) nil t)
+ (search-forward "\n\n" nil t)
+ (< pos (point))))
+
+(defun nnmbox-find-article (article)
+ "Leaves point on the relevant X-Gnus-Newsgroup line if found."
+ ;; Check that article is in the active range first, to avoid an
+ ;; expensive exhaustive search if it isn't.
+ (if (and (numberp article)
+ (not (nnmbox-is-article-active-p article)))
+ nil
+ (let ((art-string (nnmbox-article-string article))
+ (found nil))
+ ;; There is the possibility that the X-Gnus-Newsgroup line appears
+ ;; in the body of an article (for instance, if an article has been
+ ;; forwarded from someone using Gnus as their mailer), so check
+ ;; that the line is actually part of the article header.
+ (or (and (search-forward art-string nil t)
+ (nnmbox-in-header-p (point)))
+ (progn
+ (goto-char (point-min))
+ (while (not found)
+ (setq found (and (search-forward art-string nil t)
+ (nnmbox-in-header-p (point)))))
+ found)))))
+
+(defun nnmbox-record-active-article (group-art)
+ (let* ((group (car group-art))
+ (article (cdr group-art))
+ (entry
+ (or (assoc group nnmbox-group-active-articles)
+ (progn
+ (push (list group)
+ nnmbox-group-active-articles)
+ (car nnmbox-group-active-articles)))))
+ ;; add article to index, either by building complete list
+ ;; in reverse order, or as a list of ranges.
+ (if (not nnmbox-group-building-active-articles)
+ (setcdr entry (gnus-add-to-range (cdr entry) (list article)))
+ (when (memq article (cdr entry))
+ (switch-to-buffer nnmbox-mbox-buffer)
+ (error "Article %s:%d already exists!" group article))
+ (when (and (cadr entry) (< article (cadr entry)))
+ (switch-to-buffer nnmbox-mbox-buffer)
+ (error "Article %s:%d out of order" group article))
+ (setcdr entry (cons article (cdr entry))))))
+
+(defun nnmbox-record-deleted-article (group-art)
+ (let* ((group (car group-art))
+ (article (cdr group-art))
+ (entry
+ (or (assoc group nnmbox-group-active-articles)
+ (progn
+ (push (list group)
+ nnmbox-group-active-articles)
+ (car nnmbox-group-active-articles)))))
+ ;; remove article from index
+ (setcdr entry (gnus-remove-from-range (cdr entry) (list article)))))
+
+(defun nnmbox-is-article-active-p (article)
+ (gnus-member-of-range
+ article
+ (cdr (assoc nnmbox-current-group
+ nnmbox-group-active-articles))))
+
(defun nnmbox-save-mail (group-art)
"Called narrowed to an article."
(let ((delim (concat "^" message-unix-mail-delimiter)))
(nnmail-insert-lines)
(nnmail-insert-xref group-art)
(nnmbox-insert-newsgroup-line group-art)
+ (let ((alist group-art))
+ (while alist
+ (nnmbox-record-active-article (car alist))
+ (setq alist (cdr alist))))
(run-hooks 'nnmail-prepare-save-mail-hook)
(run-hooks 'nnmbox-prepare-save-mail-hook)
group-art))
(save-excursion
(let ((delim (concat "^" message-unix-mail-delimiter))
(alist nnmbox-group-alist)
- start end number)
+ (nnmbox-group-building-active-articles t)
+ start end end-header number)
(set-buffer (setq nnmbox-mbox-buffer
(let ((nnheader-file-coding-system
nnmbox-file-coding-system))
nnmbox-mbox-file nil t))))
(buffer-disable-undo)
- ;; Go through the group alist and compare against
- ;; the mbox file.
+ ;; Go through the group alist and compare against the mbox file.
(while alist
(goto-char (point-max))
(when (and (re-search-backward
(setcdr (cadar alist) number))
(setq alist (cdr alist)))
+ ;; Examine all articles for our private X-Gnus-Newsgroup
+ ;; headers. This is done primarily as a consistency check, but
+ ;; it is convenient for building an index of the articles
+ ;; present, to avoid costly searches for missing articles
+ ;; (eg. when expiring articles).
(goto-char (point-min))
+ (setq nnmbox-group-active-articles nil)
(while (re-search-forward delim nil t)
(setq start (match-beginning 0))
- (unless (search-forward
- "\nX-Gnus-Newsgroup: "
- (save-excursion
- (setq end
- (or
- (and
- ;; skip to end of headers first, since mail
- ;; which has been respooled has additional
- ;; "From nobody" lines.
- (search-forward "\n\n" nil t)
- (re-search-forward delim nil t)
- (match-beginning 0))
- (point-max))))
- t)
+ (save-excursion
+ (search-forward "\n\n" nil t)
+ (setq end-header (point))
+ (setq end (or (and
+ (re-search-forward delim nil t)
+ (match-beginning 0))
+ (point-max))))
+ (if (search-forward "\nX-Gnus-Newsgroup: " end-header t)
+ ;; Build a list of articles in each group, remembering
+ ;; that each article may be in more than one group.
+ (progn
+ (nnmbox-record-active-article (nnmbox-article-group-number t))
+ (while (search-forward "\nX-Gnus-Newsgroup: " end-header t)
+ (nnmbox-record-active-article (nnmbox-article-group-number t))))
+ ;; The article is either new, or for some other reason
+ ;; hasn't got our private headers, so add them now. The
+ ;; only situation I've encountered when the X-Gnus-Newsgroup
+ ;; header is missing is if the article contains a forwarded
+ ;; message which does contain that header line (earlier
+ ;; versions of Gnus didn't restrict their search to the
+ ;; headers). In this case, there is an Xref line which
+ ;; provides the relevant information to construct the
+ ;; missing header(s).
(save-excursion
(save-restriction
(narrow-to-region start end)
- (nnmbox-save-mail
- (nnmail-article-group 'nnmbox-active-number)))))
- (goto-char end))))))
+ (if (re-search-forward "\nXref: [^ ]+" end-header t)
+ ;; generate headers from Xref:
+ (let (alist)
+ (while (re-search-forward " \\([^:]+\\):\\([0-9]+\\)" end-header t)
+ (push (cons (match-string 1)
+ (string-to-int (match-string 2))) alist))
+ (nnmbox-insert-newsgroup-line alist))
+ ;; this is really a new article
+ (nnmbox-save-mail
+ (nnmail-article-group 'nnmbox-active-number))))))
+ (goto-char end))
+ ;; put article lists in order
+ (setq alist nnmbox-group-active-articles)
+ (while alist
+ (setcdr (car alist) (gnus-compress-sequence (nreverse (cdar alist))))
+ (setq alist (cdr alist)))))))
(provide 'nnmbox)