*** empty log message ***
authorLars Magne Ingebrigtsen <larsi@gnus.org>
Tue, 4 Mar 1997 03:01:31 +0000 (03:01 +0000)
committerLars Magne Ingebrigtsen <larsi@gnus.org>
Tue, 4 Mar 1997 03:01:31 +0000 (03:01 +0000)
27 files changed:
lisp/ChangeLog
lisp/doc.txt
lisp/gnus-cache.el
lisp/gnus-cite.el
lisp/gnus-ems.el
lisp/gnus-mh.el
lisp/gnus-msg.el
lisp/gnus-score.el
lisp/gnus-uu.el
lisp/gnus-vis.el
lisp/gnus-vm.el
lisp/gnus.el
lisp/nnbabyl.el
lisp/nndigest.el [deleted file]
lisp/nndoc.el
lisp/nneething.el
lisp/nnfolder.el
lisp/nnkiboze.el
lisp/nnmail.el
lisp/nnmbox.el
lisp/nnmh.el
lisp/nnml.el
lisp/nntp.el
lisp/nnvirtual.el
texi/Makefile
texi/gnus.texi
texi/refcard.tex [new file with mode: 0644]

index 4a68f4d..47eebb9 100644 (file)
@@ -1,4 +1,203 @@
-Sat Jul 22 00:26:49 1995  Lars INGEBRIGTSEN UiO  <lingebri@sunsci4.cern.ch>
+Sun Jul 30 00:00:26 1995  Lars Magne Ingebrigtsen  <lingebri@sunsci4.cern.ch>
+
+       * gnus.el (gnus-active-to-gnus-format): Ignore groups that have
+       flags that are not y, n or m.
+       (gnus-summary-expire-articles): Turn off the cache.
+       (gnus-setup-news): Read the dribble file before everything.
+       (gnus-dribble-eval-file): New function.
+
+       * gnus-ems.el (gnus-make-overlay): Use some indirection.
+
+       * gnus.el (gnus-make-threads): Would chop off threads that changed
+       subject on re-generation.
+       (gnus-make-threads-and-expunge): Ditto.
+
+       * gnus-vis.el (gnus-button-alist): Match URLS with periods
+       following. 
+
+Sat Jul 29 21:31:15 1995  Lars Magne Ingebrigtsen  <lingebri@sunsci4.cern.ch>
+
+       * gnus.el: Added &optional to all `(interactive "P")' functions. 
+       (gnus-summary-prepare-exit-hook): Changed name.
+       (gnus-summary-exit-hook): New hook.
+
+       * nnkiboze.el (nnkiboze-generate-group): Don't bug out on
+       non-active groups. 
+
+Sat Jul 29 19:40:51 1995  Lars Magne Ingebrigtsen  <lingebri@sunscipw.cern.ch>
+
+       * gnus.el: 0.98.6 is released.
+
+       * gnus.el (gnus-get-unread-articles): Would doubly activate native
+       groups. 
+       (gnus-summary-prepare-threads): Always removed dormant articles.
+       (gnus-summary-show-all-dormant): Did not show dormants.
+       (gnus-summary-show-all-expunged): Ditto for expunged.
+
+       * nntp.el (nntp-async-request-group): Would pretend to close down
+       async connections.
+
+Sat Jul 29 02:06:26 1995  Lars Magne Ingebrigtsen  <lingebri@sunscipw.cern.ch>
+
+       * gnus.el: 0.98.5. is released.
+       
+       * nntp.el (nntp-open-server-semi-internal): Define servers that we
+       can't reach as unreachable.
+
+       * nnvirtual.el (nnvirtual-create-mapping): Don't ding so much.
+
+       * nneething.el (nneething-map-file): Make sure that the .neething
+       dir exists. 
+
+Fri Jul 21 14:52:06 1995  Ulrik Dickow  <dickow@nbi.dk>
+
+       * nndoc.el (nndoc-digest-type): New variable.
+       (nndoc-set-header-dependent-regexps): Set it.
+       (nndoc-request-article): Use it -- don't unquote MIME digests.
+
+Sat Jul 29 00:54:09 1995  Lars Magne Ingebrigtsen  <lingebri@sunsci4.cern.ch>
+
+       * nntp.el (nntp-request-close): Kill all async connections.
+
+       * gnus-uu.el (gnus-uu-decode-binhex): Bugged out.
+
+Fri Jul 28 20:35:34 1995  Lars Magne Ingebrigtsen  <lingebri@sunsci4.cern.ch>
+
+       * gnus-msg.el (gnus-group-mail): Don't call `gnus-mail-hook'. 
+
+       * gnus.el (gnus-summary-mode-map): Changed `W d' to `W m'.
+       (gnus-summary-mark-unread-as-read): Would sometimes mark the wrong
+       article as read.
+       (gnus-summary-toggle-header): Wouldn't toggle headers after
+       miming. 
+       (gnus-summary-next-article): Would offer to go to the next group
+       when happening upon canceled articles.
+       (gnus-summary-insert-pseudos): Did not properly note that
+       extracetd articles were unread.
+       (gnus-summary-sort-by-number): Protect against macroism.
+       (gnus-summary-verbose-headers): Didn't turn on/off verbose
+       headers. 
+
+       * gnus-score.el (gnus-score-string): Mis-scored when matching on
+       "". 
+
+       * gnus-ems.el (gnus-ems-redefine): Remove long-lines and
+       control-chars checking for Mule.
+
+       * gnus.el (gnus-summary-prepare-unthreaded): Cull unwanted
+       articles.
+       (gnus-group-jump-to-group): If we haven't read the active file,
+       don't require a match.
+
+Thu Jul 27 13:32:12 1995  Lars Magne Ingebrigtsen  <lingebri@sunsci4.cern.ch>
+
+       * nnml.el (nnml-request-group): Didn't split mail.
+
+       * nnmh.el (nnmh-active-number): Create new groups at the drop of a
+       hat. 
+
+       * nnmail.el (nnmail-get-active): Don't activate any groups just
+       because they're mentioned in `nnmail-split-methods'.
+
+       * nnml.el (nnml-get-new-mail): Would bug out on multiple spool
+       files. 
+       * nnmbox.el (nnmbox-get-new-mail): Ditto.
+       * nnbabyl.el (nnbabyl-get-new-mail): Ditto.
+       * nnfolder.el (nnfolder-get-new-mail): Ditto.
+       (nnfolder-active-number): Don't try to switch to a group before it
+       has been "created".
+
+       * nnmh.el (nnmh-get-new-mail): Ditto.
+
+Wed Jul 26 17:18:50 1995  Lars Magne Ingebrigtsen  <lingebri@sunsci4.cern.ch>
+
+       * gnus-ems.el (gnus-ems-redefine): Would bug out on rebuiling
+       (referred) threads in XEmacs.
+
+       * gnus-msg.el (gnus-inews-insert-signature): Would insert one \n
+       too many. 
+
+Wed Jul 26 09:38:36 1995  Lars Magne Ingebrigtsen  <lingebri@sunscipw.cern.ch>
+
+       * gnus.el: 0.98.4 is released.
+
+       * gnus-msg.el (gnus-deletable-headers): Make Date a deletable
+       header. 
+
+       * nnmail.el (nnmail-split-incoming): Treat Content-length headers
+       more sanely.
+       (nnmail-split-incoming): Would totally by out.
+
+       * nnmh.el (nnmh-request-group): Give a better error message.
+
+       * gnus.el (gnus-article-date-ut): Allow futurity
+
+       * gnus-msg.el (gnus-inews-user-address): New function.
+       (gnus-inews-news): Give better error messages.
+
+       * nnml.el (nnml-request-group): Don't check so much.
+       * nnmail.el (nnmail-activate): Check everything.
+
+       * gnus-msg.el (gnus-inews-check-post): Didn't match properly on
+       from. 
+       (gnus-check-before-posting): Didn't actually check anything before
+       posting.
+
+Tue Jul 25 13:35:01 1995  Lars Magne Ingebrigtsen  <lingebri@sunsci4.cern.ch>
+
+       * gnus.el: 0.98.3 is released.
+
+       * nnml.el (nnml-request-replace-article): Would kill a random
+       buffer. 
+
+       * gnus.el (gnus-group-read-group): Doc fix.
+       (gnus-update-format-specifications): New implementation.
+       (gnus-summary-read-group): Update format specs.
+       (gnus-summary-catchup): Expose threads before catching up. Would
+       infloop. 
+       (gnus-summary-save-article): Would change window config.
+       (gnus-group-archive-directory): Changed address.
+
+       * nnmail.el (nnmail-get-split-group): Make sure that
+       nnmail-procmail-directory is a directory.
+
+Sun Jul 23 22:27:25 1995  Lars Magne Ingebrigtsen  <lingebri@sunsci4.cern.ch>
+
+       * gnus.el (gnus-summary-mark-article): Would bug out on string
+       marks. 
+
+Sun Jul 23 16:49:38 1995  Lars INGEBRIGTSEN UiO  <lingebri@sunsci4.cern.ch>
+
+       * gnus.el: 0.98.2 is released.
+
+       * nnmail.el (nnmail-split-incoming): Ignore duplicate messages,
+       but create new message-ids for messages that do not have one. 
+
+       * gnus.el (gnus-thread-sort-by-score): Totally bombed out.
+
+       * gnus-score.el (gnus-score-insert-help): Do the `select-window'
+       outside the `save-excursion'.
+
+       * gnus.el (gnus-article-mode-map): Remove the summary `s' binding.
+
+       * gnus-uu.el (gnus-uu-grab-articles): Wouldn't mark some articles
+       as read. 
+       (gnus-uu-save-files): Don't ask twice whether to overwrite a file.
+
+       * gnus.el (gnus-summary-show-thread): Avoid `save-excursion'.
+       (gnus-summary-mark-same-subject): Did not expose hidden threads,
+       and would infloop.
+
+Sat Jul 22 04:34:25 1995  Lars INGEBRIGTSEN UiO  <lingebri@sunsci4.cern.ch>
+
+       * gnus-cache.el (gnus-cache-file-name): Also translate :'s. 
+
+       * gnus.el (gnus-dribble-file-name): Use the current startup file
+       name as the basis.
+
+Sat Jul 22 00:26:49 1995  Lars INGEBRIGTSEN UiO  <lingebri@sunscipw.cern.ch>
+
+       * gnus.el: 0.98.1 is released.
 
        * gnus.el (gnus-summary-mark-unread-as-read): Don't mark already
        marked articles.
index 2879761..c95116e 100644 (file)
@@ -355,7 +355,7 @@ Save the file, and go to a shell window.
 
 Type:
 
-$ emacs -batch -l nnkiboze -f nnkiboze-generate-groups
+$ emacs -batch -l ~/.emacs -l nnkiboze -f nnkiboze-generate-groups
 
 Wait a few hours, and all articles from me, or articles about Gnus,
 will appear, as if by magic, in the nnkiboze group. You really want
index b62203d..bf7d72f 100644 (file)
 (defun gnus-cache-file-name (group article)
   (concat (file-name-as-directory gnus-cache-directory)
          (if (gnus-use-long-file-name 'not-cache)
-             group (gnus-replace-chars-in-string group ?. ?/))
+             group 
+           (let ((group (concat group "")))
+             (if (string-match ":" group)
+                 (aset group (match-beginning 0) ?/))
+             (gnus-replace-chars-in-string group ?. ?/)))
          "/" (if (stringp article) article (int-to-string article))))
 
 (defun gnus-cache-possibly-enter-article 
index 51f8ec2..2c491b7 100644 (file)
@@ -26,6 +26,7 @@
 
 (require 'gnus)
 (require 'gnus-msg)
+(require 'gnus-ems)
 
 (eval-and-compile
   (autoload 'gnus-article-add-button "gnus-vis")
@@ -141,10 +142,10 @@ Lines matching `gnus-cite-attribution-postfix' and perhaps
   ;; Create dark or light faces if necessary.
   (cond ((eq gnus-cite-face-list 'light)
         (setq gnus-cite-face-list
-            (mapcar 'gnus-make-face gnus-face-light-name-list)))
+              (mapcar 'gnus-make-face gnus-face-light-name-list)))
        ((eq gnus-cite-face-list 'dark)
         (setq gnus-cite-face-list
-            (mapcar 'gnus-make-face gnus-face-dark-name-list))))
+              (mapcar 'gnus-make-face gnus-face-dark-name-list))))
   (save-excursion
     (set-buffer gnus-article-buffer)
     (gnus-cite-parse-maybe)
@@ -278,7 +279,8 @@ See also the documentation for `gnus-article-highlight-citation'."
         gnus-cite-loose-attribution-alist nil)
   ;; Parse current buffer searching for citation prefixes.
   (goto-char (point-min))
-  (search-forward "\n\n")
+  (or (search-forward "\n\n" nil t)
+      (goto-char (point-max)))
   (let ((line (1+ (count-lines (point-min) (point))))
        (case-fold-search t)
        (max (save-excursion
@@ -519,7 +521,7 @@ See also the documentation for `gnus-article-highlight-citation'."
        (skip-chars-backward " \t")
        (setq to (point))
        (if (< from to)
-           (overlay-put (make-overlay from to) 'face face)))))
+           (gnus-overlay-put (gnus-make-overlay from to) 'face face)))))
 
 (defun gnus-cite-toggle (prefix)
   (save-excursion
index 0dec88b..86cc04a 100644 (file)
 (defvar gnus-summary-mode-hook ())
 (defvar gnus-article-mode-hook ())
 
+(defalias 'gnus-make-overlay 'make-overlay)
+(defalias 'gnus-overlay-put 'overlay-put)
+(defalias 'gnus-move-overlay 'move-overlay)
+
 ;; We do not byte-compile this file, because error messages are such a
 ;; bore.  
 
@@ -104,11 +108,11 @@ pounce directly on the real variables themselves."))
                      (setq props (nthcdr 2 props)))
                  (remove-text-properties start end ())))))
 
-      (or (fboundp 'make-overlay) (fset 'make-overlay 'make-extent))
-      (or (fboundp 'overlay-put) (fset 'overlay-put 'set-extent-property))
-      (or (fboundp 'move-overlay) 
-         (defun move-overlay (extent start end &optional buffer)
-           (set-extent-endpoints extent start end)))
+      (defalias 'gnus-make-overlay 'make-extent)
+      (defalias 'gnus-overlay-put 'set-extent-property)
+      (defun gnus-move-overlay (extent start end &optional buffer)
+       (set-extent-endpoints extent start end))
+
       (or (boundp 'standard-display-table) (setq standard-display-table nil))
       (or (boundp 'read-event) (fset 'read-event 'next-command-event))
 
@@ -438,7 +442,8 @@ call it with the value of the `gnus-data' text property."
        (let ((beg (point)))
          (gnus-summary-prepare-threads (list thread) 0)
          (save-excursion
-           (while (>= (point) beg)
+           (while (and (>= (point) beg)
+                       (not (eobp)))
              (remove-text-properties
               (1+ (gnus-point-at-bol)) (1+ (gnus-point-at-eol))
               '(gnus-number nil gnus-mark nil gnus-level nil))
@@ -592,6 +597,12 @@ call it with the value of the `gnus-data' text property."
             valstr))))
 
     (fset 'gnus-summary-make-display-table (lambda () nil))
+    
+    (if (boundp 'gnus-check-before-posting)
+       (setq gnus-check-before-posting
+             (delq 'long-lines
+                   (delq 'control-chars gnus-check-before-posting)))
+      )
     )
    ))
 
index 2888c00..b1d9b88 100644 (file)
@@ -37,7 +37,7 @@
 (require 'gnus)
 (require 'gnus-msg)
 
-(defun gnus-summary-save-article-folder (arg)
+(defun gnus-summary-save-article-folder (&optional arg)
   "Append the current article to an mh folder.
 If N is a positive number, save the N next articles.
 If N is a negative number, save the N previous articles.
@@ -141,14 +141,16 @@ The command \\[mh-yank-cur-msg] yank the original message into current buffer."
     (setq mh-sent-from-folder buffer)
     (setq mh-sent-from-msg 1)
     (setq mh-show-buffer buffer)
-    (setq mh-previous-window-config config)
-    )
+    (setq mh-previous-window-config config))
 
   ;; Then, yank original article if requested.
   (if yank
       (let ((last (point)))
        (mh-yank-cur-msg)
-       (goto-char last)))) 
+       (goto-char last)))
+
+  (run-hooks 'gnus-mail-hook))
+
 
 ;; gnus-mail-forward-using-mhe is contributed by Jun-ichiro Itoh
 ;; <itojun@ingram.mt.cs.keio.ac.jp>
@@ -181,6 +183,7 @@ The command \\[mh-yank-cur-msg] yank the original message into current buffer."
       (setq mh-sent-from-folder buffer)
       (setq mh-sent-from-msg 1)
       (setq mh-previous-window-config config)
+      (run-hooks 'gnus-mail-hook)
       )))
 
 (defun gnus-mail-other-window-using-mhe ()
@@ -193,7 +196,8 @@ The command \\[mh-yank-cur-msg] yank the original message into current buffer."
     (mh-find-path)
     (mh-send-other-window to cc subject)
     (setq mh-sent-from-folder (current-buffer))
-    (setq mh-sent-from-msg 1)))
+    (setq mh-sent-from-msg 1)
+    (run-hooks 'gnus-mail-hook)))
 
 (defun gnus-Folder-save-name (newsgroup headers &optional last-folder)
   "Generate folder name from NEWSGROUP, HEADERS, and optional LAST-FOLDER.
index 4400971..4e77b21 100644 (file)
@@ -150,7 +150,7 @@ RFC977 and RFC1036 require From, Date, Newsgroups, Subject,
 Message-ID.  Organization, Lines and X-Newsreader are optional.  If
 you want Gnus not to insert some header, remove it from this list.")
 
-(defvar gnus-deletable-headers '(Message-ID)
+(defvar gnus-deletable-headers '(Message-ID Date)
   "*Headers to be deleted if they already exists.")
 
 (defvar gnus-check-before-posting 
@@ -263,8 +263,7 @@ headers.")
 (defun gnus-group-mail ()
   "Start composing a mail."
   (interactive)
-  (funcall gnus-mail-other-window-method)
-  (run-hooks 'gnus-mail-hook))
+  (funcall gnus-mail-other-window-method))
 
 (defun gnus-group-post-news ()
   "Post an article."
@@ -531,7 +530,7 @@ will attempt to use the foreign server to post the article."
   (let* ((case-fold-search nil)
         (server-running (gnus-server-opened gnus-select-method))
         (reply gnus-article-reply)
-        error)
+        error post-result)
     (save-excursion
       ;; Connect to default NNTP server if necessary.
       ;; Suggested by yuki@flab.fujitsu.junet.
@@ -683,20 +682,25 @@ will attempt to use the foreign server to post the article."
 
       ;; Send to server. 
       (gnus-message 5 "Posting to USENET...")
-      (if (funcall gnus-inews-article-function use-group-method)
-         (progn
-           (gnus-message 5 "Posting to USENET...done")
-           (if (gnus-buffer-exists-p (car-safe reply))
-               (progn
-                 (save-excursion
-                   (set-buffer gnus-summary-buffer)
-                   (gnus-summary-mark-article-as-replied 
-                    (cdr reply))))))
-       ;; We cannot signal an error.
-       (setq error t)
-       (ding) (gnus-message 1 "Article rejected: %s" 
-                            (gnus-status-message gnus-select-method)))
-      (set-buffer-modified-p nil))
+      (setq post-result (funcall gnus-inews-article-function use-group-method))
+      (cond ((eq post-result 'illegal)
+            (setq error t)
+            (ding))
+           (post-result
+            (gnus-message 5 "Posting to USENET...done")
+            (if (gnus-buffer-exists-p (car-safe reply))
+                (progn
+                  (save-excursion
+                    (set-buffer gnus-summary-buffer)
+                    (gnus-summary-mark-article-as-replied 
+                     (cdr reply)))))
+            (set-buffer-modified-p nil))
+           (t
+            ;; We cannot signal an error.
+            (setq error t)
+            (ding)
+            (gnus-message 1 "Article rejected: %s" 
+                          (gnus-status-message gnus-select-method)))))
     ;; If NNTP server is opened by gnus-inews-news, close it by myself.
     (or server-running
        (gnus-close-server (gnus-find-method-for-group gnus-newsgroup-name)))
@@ -718,22 +722,26 @@ will attempt to use the foreign server to post the article."
        (goto-char (point-min))
        (narrow-to-region 
         (point) 
-        (re-search-forward 
-         (concat "^" (regexp-quote mail-header-separator) "$")))
+        (progn
+          (re-search-forward 
+           (concat "^" (regexp-quote mail-header-separator) "$"))
+          (match-beginning 0)))
        (goto-char (point-min))
        (and 
         ;; Check for commands in Subject.
-        (or (gnus-check-before-posting 'subject-cmsg)
-            (save-excursion
-              (if (string-match "^cmsg " (mail-fetch-field "subject"))
-                  (gnus-y-or-n-p
-                   "The control code \"cmsg \" is in the subject. Really post? ")
-                t)))
+        (or 
+         (gnus-check-before-posting 'subject-cmsg)
+         (save-excursion
+           (if (string-match "^cmsg " (mail-fetch-field "subject"))
+               (gnus-y-or-n-p
+                "The control code \"cmsg \" is in the subject. Really post? ")
+             t)))
         ;; Check for multiple identical headers.
         (or (gnus-check-before-posting 'multiple-headers)
             (save-excursion
               (let (found)
-                (while (and (not found) (re-search-forward "^[^ \t:]+: " nil t))
+                (while (and (not found) (re-search-forward "^[^ \t:]+: "
+                                                           nil t))
                   (save-excursion
                     (or (re-search-forward 
                          (concat "^" (setq found
@@ -779,11 +787,12 @@ will attempt to use the foreign server to post the article."
                   (gnus-yes-or-no-p
                    (format 
                     "The address looks strange: \"%s\". Really post? " from)))
-                 ((string-match "(.*).*(.*)")
+                 ((string-match "(.*).*(.*)" from)
                   (gnus-yes-or-no-p
                    (format
                     "The From header looks strange: \"%s\". Really post? " 
-                    from)))))))
+                    from)))
+                 (t t)))))
         )))
     ;; Check for long lines.
     (or (gnus-check-before-posting 'long-lines)
@@ -817,12 +826,13 @@ will attempt to use the foreign server to post the article."
          t))
     ;; Use the (size . checksum) variable to see whether the
     ;; article is empty or has only quoted text.
-    (or (gnus-check-before-posting 'new-text)
-       (if (and (= (buffer-size) (car gnus-article-check-size))
-                (= (gnus-article-checksum) (cdr gnus-article-check-size)))
-           (gnus-yes-or-no-p
-            "It looks like there's no new text in your article. Really post? ")
-         t))
+    (or
+     (gnus-check-before-posting 'new-text)
+     (if (and (= (buffer-size) (car gnus-article-check-size))
+             (= (gnus-article-checksum) (cdr gnus-article-check-size)))
+        (gnus-yes-or-no-p
+         "It looks like there's no new text in your article. Really post? ")
+       t))
     ;; Check the length of the signature.
     (or (gnus-check-before-posting 'signature)
        (progn
@@ -845,10 +855,11 @@ will attempt to use the foreign server to post the article."
 
 ;; Returns non-nil if this type is not to be checked.
 (defun gnus-check-before-posting (type)
-  (or (not gnus-check-before-posting)
-      (if (listp gnus-check-before-posting)
-         (memq type gnus-check-before-posting)
-       t)))
+  (not 
+   (or (not gnus-check-before-posting)
+       (if (listp gnus-check-before-posting)
+          (memq type gnus-check-before-posting)
+        t))))
 
 (defun gnus-cancel-news ()
   "Cancel an article you posted."
@@ -937,7 +948,7 @@ will attempt to use the foreign server to post the article."
     (if (and gnus-article-check-size
             (not (gnus-inews-check-post)))
        ;; Aber nein!
-       ()
+       'illegal
       ;; Looks ok, so we do the nasty.
       (save-excursion
        (set-buffer tmpbuf)
@@ -1003,15 +1014,6 @@ Headers in `gnus-required-headers' will be generated."
             (get-text-property (1+ (match-beginning 0)) 'gnus-deletable)
             (gnus-delete-line))
        (setq headers (cdr headers))))
-    ;; Insert new Sender if the From is strange. 
-    (let ((from (mail-fetch-field "from")))
-      (if (and from (not (string= (downcase from) (downcase From))))
-         (progn
-           (goto-char (point-min))    
-           (and (re-search-forward "^Sender:" nil t)
-                (delete-region (progn (beginning-of-line) (point))
-                               (progn (forward-line 1) (point))))
-           (insert "Sender: " From "\n"))))
     ;; If there are References, and no "Re: ", then the thread has
     ;; changed name. See Son-of-1036.
     (if (and (mail-fetch-field "references")
@@ -1072,7 +1074,20 @@ Headers in `gnus-required-headers' will be generated."
                   (add-text-properties 
                    (point) (match-end 0)
                    '(gnus-deletable t face italic) (current-buffer))))))
-      (setq headers (cdr headers)))))
+      (setq headers (cdr headers)))
+    ;; Insert new Sender if the From is strange. 
+    (let ((from (mail-fetch-field "from")))
+      (if (and from (not (string=
+                         (downcase (car (gnus-extract-address-components 
+                                         from)))
+                         (downcase (gnus-inews-real-user-address)))))
+         (progn
+           (goto-char (point-min))    
+           (and (re-search-forward "^Sender:" nil t)
+                (delete-region (progn (beginning-of-line) (point))
+                               (progn (forward-line 1) (point))))
+           (insert "Sender: " (gnus-inews-real-user-address) "\n"))))))
+
 
 (defun gnus-inews-insert-signature ()
   "Insert a signature file.
@@ -1099,8 +1114,9 @@ nil."
                ()
              ;; Delete any previous signatures.
              (if (search-backward "\n-- \n" nil t)
-                 (delete-region (1+ (point)) (point-max)))
-             (insert "\n-- \n")
+                 (delete-region (point) (point-max)))
+             (or (eolp) (insert "\n"))
+             (insert "-- \n")
              (if (file-exists-p signature)
                  (insert-file-contents signature)
                (insert signature))
@@ -1201,6 +1217,12 @@ a program specified by the rest of the value."
                      (t
                       (concat " (" full-name ")")))))))
 
+(defun gnus-inews-real-user-address ()
+  "Return the \"real\" user address.
+This function tries to ignore all user modifications, and 
+give as trustworthy answer as possible."
+  (concat (user-login-name) "@" (gnus-inews-full-address)))
+
 (defun gnus-inews-login-name ()
   "Return login name."
   (or gnus-user-login-name (getenv "LOGNAME") (user-login-name)))
index d8d8be6..c4f4703 100644 (file)
@@ -115,11 +115,11 @@ of the last successful match.")
 ;; Much modification of the kill (ahem, score) code and lots of the
 ;; functions are written by Per Abrahamsen <amanda@iesd.auc.dk>.
 
-(defun gnus-summary-lower-score (score)
+(defun gnus-summary-lower-score (&optional score)
   (interactive "P")
   (gnus-summary-increase-score (- (gnus-score-default score))))
 
-(defun gnus-summary-increase-score (score)
+(defun gnus-summary-increase-score (&optional score)
   (interactive "P")
   (gnus-set-global-variables)
   (let* ((nscore (gnus-score-default score))
@@ -279,8 +279,8 @@ of the last successful match.")
     (insert string ":\n\n")
     (while alist
       (insert (format " %c: %s\n" (car (car alist)) (nth idx (car alist))))
-      (setq alist (cdr alist)))
-    (select-window (get-buffer-window gnus-summary-buffer))))
+      (setq alist (cdr alist))))
+  (select-window (get-buffer-window gnus-summary-buffer)))
 
 (defun gnus-summary-header (header)
   ;; Return HEADER for current articles, or error.
@@ -1290,6 +1290,7 @@ SCORE is the score to add."
                  (forward-line 1))
              (and (string= match "") (setq match "\n"))
              (while (funcall search-func match nil t)
+               (goto-char (match-beginning 0))
                (end-of-line)
                (setq found (setq arts (get-text-property (point) 'articles)))
                ;; Found a match, update scores.
@@ -1304,7 +1305,8 @@ SCORE is the score to add."
                  (while arts
                    (setq art (car arts)
                          arts (cdr arts))
-                   (setcdr art (+ score (cdr art)))))))
+                   (setcdr art (+ score (cdr art)))))
+               (forward-line 1)))
            ;; Update expire date
            (cond ((null date))         ;Permanent entry.
                  (found                ;Match, update date.
index 27d229d..2c8ac06 100644 (file)
@@ -255,6 +255,7 @@ The headers will be included in the sequence they are matched.")
 
 (defvar gnus-uu-file-name nil)
 (defconst gnus-uu-uudecode-process nil)
+(defvar gnus-uu-binhex-article-name nil)
 
 (defvar gnus-uu-generated-file-list nil)
 (defvar gnus-uu-work-dir nil)
@@ -366,7 +367,9 @@ The headers will be included in the sequence they are matched.")
         (file-name-as-directory
          (read-file-name "Unbinhex and save in dir: "
                          gnus-uu-default-dir
-                         gnus-uu-default-dir t))))
+                         gnus-uu-default-dir))))
+  (setq gnus-uu-binhex-article-name 
+       (make-temp-name (concat gnus-uu-work-dir "binhex")))
   (gnus-uu-decode-with-method 'gnus-uu-binhex-article n dir))
 
 (defun gnus-uu-decode-uu-view (n)
@@ -418,6 +421,8 @@ The headers will be included in the sequence they are matched.")
    (list current-prefix-arg
         (read-file-name "Unbinhex, view and save in dir: "
                         gnus-uu-default-dir gnus-uu-default-dir)))
+  (setq gnus-uu-binhex-article-name 
+       (make-temp-name (concat gnus-uu-work-dir "binhex")))
   (let ((gnus-view-pseudos (or gnus-view-pseudos 'automatic)))
     (gnus-uu-decode-binhex n file)))
 
@@ -621,7 +626,7 @@ The headers will be included in the sequence they are matched.")
             (and (or (not (file-exists-p to-file))
                      (gnus-y-or-n-p (format "%s exists; overwrite? "
                                             to-file)))
-                 (copy-file file to-file 1 t))))
+                 (copy-file file to-file t t))))
       (setq files (cdr files)))
     (message "Saved %d file%s" len (if (> len 1) "s" ""))))
 
@@ -731,7 +736,6 @@ The headers will be included in the sequence they are matched.")
   "^:...............................................................$")
 (defconst gnus-uu-binhex-end-line
   ":$")
-(defvar gnus-uu-binhex-article-name nil)
 
 (defun gnus-uu-binhex-article (buffer in-state)
   (let (state start-char)
@@ -1073,9 +1077,9 @@ The headers will be included in the sequence they are matched.")
 
       (buffer-disable-undo article-buffer)
       ;; Mark article as read.
-      (run-hooks 'gnus-mark-article-hook)
       (and (memq article gnus-newsgroup-processable)
           (gnus-summary-remove-process-mark article))
+      (run-hooks 'gnus-mark-article-hook)
 
       (setq process-state (funcall process-function article-buffer state))
 
index af8959c..0030a6d 100644 (file)
@@ -172,9 +172,9 @@ will be used.")
      gnus-button-message-id 3)
     ;; This is how URLs _should_ be embedded in text...
     ("<URL:\\([^\n\r>]*\\)>" 0 t gnus-button-url 1)
-    ;; Next regexp stolen from highlight-headers.el
-    ("\\b\\(s?https?\\|ftp\\|file\\|gopher\\|news\\|telnet\\):\\(//[-a-zA-Z0-9_.]+:[0-9]*\\)?[-a-zA-Z0-9_=?#$@~`%&*+|\\/.,]+" 0 t
-     gnus-button-url 0))
+    ;; Next regexp stolen from highlight-headers.el.
+    ;; Modified by Vladimir Alexiev.
+    ("\\b\\(s?https?\\|ftp\\|file\\|gopher\\|news\\|telnet\\|wais\\):\\(//[-a-zA-Z0-9_.]+:[0-9]*\\)?[-a-zA-Z0-9_=?#$@~`%&*+|\\/.,]*[-a-zA-Z0-9_=#$@~`%&*+|\\/]" 0 t gnus-button-url 0))
   "Alist of regexps matching buttons in an article.
 
 Each entry has the form (REGEXP BUTTON FORM CALLBACK PAR...), where
@@ -689,11 +689,11 @@ gnus-netscape-start-url:
                (setq from beg)
                (setq to end)))
          (if gnus-newsgroup-selected-overlay
-             (move-overlay gnus-newsgroup-selected-overlay 
-                           from to (current-buffer))
-           (setq gnus-newsgroup-selected-overlay (make-overlay from to))
-           (overlay-put gnus-newsgroup-selected-overlay 'face 
-                        gnus-summary-selected-face))))))
+             (gnus-move-overlay gnus-newsgroup-selected-overlay 
+                                from to (current-buffer))
+           (setq gnus-newsgroup-selected-overlay (gnus-make-overlay from to))
+           (gnus-overlay-put gnus-newsgroup-selected-overlay 'face 
+                             gnus-summary-selected-face))))))
 
 ;; New implementation by Christian Limpach <Christian.Limpach@nice.ch>.
 (defun gnus-summary-highlight-line ()
@@ -1021,8 +1021,8 @@ It does this by highlighting everything after
           (let ((start (match-beginning 0))
                 (end (match-end 0)))
             (gnus-article-add-button start end 'gnus-signature-toggle end)
-            (overlay-put (make-overlay end (point-max))
-                         'face gnus-signature-face))))))
+            (gnus-overlay-put (gnus-make-overlay end (point-max))
+                              'face gnus-signature-face))))))
 
 (defun gnus-article-hide-signature ()
   "Hide the signature in an article.
@@ -1091,7 +1091,8 @@ External references are things like message-ids and URLs, as specified by
 (defun gnus-article-add-button (from to fun &optional data)
   "Create a button between FROM and TO with callback FUN and data DATA."
   (and gnus-article-button-face
-       (overlay-put (make-overlay from to) 'face gnus-article-button-face))
+       (gnus-overlay-put (gnus-make-overlay from to)
+                        'face gnus-article-button-face))
   (add-text-properties from to
                       (append (and gnus-article-mouse-face
                                    (list 'mouse-face gnus-article-mouse-face))
index 66a10d2..06eda34 100644 (file)
@@ -73,7 +73,7 @@ Has to be set before gnus-vm is loaded.")
     (vm-mode)
     tmp-folder))
   
-(defun gnus-summary-save-article-vm (arg)
+(defun gnus-summary-save-article-vm (&optional arg)
   "Append the current article to a vm folder.
 If N is a positive number, save the N next articles.
 If N is a negative number, save the N previous articles.
@@ -134,6 +134,7 @@ save those articles instead."
                             (replace-match (concat "\\1" subject))))))))
          (vm-forward-message)
          (gnus-vm-init-reply-buffer gnus-buffer)
+         (run-hooks 'gnus-mail-hook)
          (kill-buffer vm-folder))))))
 
 (defun gnus-vm-init-reply-buffer (buffer)
@@ -162,14 +163,16 @@ The command \\[vm-yank-message] yank the original message into current buffer."
               (gnus-yank-article nil))
          (kill-buffer vm-folder))))
     (if (featurep 'win-vm) nil
-      (pop-to-buffer gnus-buffer))))
+      (pop-to-buffer gnus-buffer))
+    (run-hooks 'gnus-mail-hook)))
 
 (defun gnus-mail-other-window-using-vm ()
   "Compose mail in the other window using VM."
   (interactive)
   (let ((gnus-buffer (current-buffer)))
     (vm-mail)
-    (gnus-vm-init-reply-buffer gnus-buffer)))
+    (gnus-vm-init-reply-buffer gnus-buffer))
+  (run-hooks 'gnus-mail-hook))
 
 (defun gnus-yank-article (article &optional prefix)
   ;; Based on vm-yank-message by Kyle Jones.
index c52c9a4..1ce40a9 100644 (file)
@@ -1042,10 +1042,13 @@ This hook is run before any variables are set in the summary buffer.")
 (defvar gnus-article-mode-hook nil
   "*A hook for Gnus article mode.")
 
-(defun gnus-summary-exit-hook nil
-  "*A hook called on exit from the summary buffer.
+(defun gnus-summary-prepare-exit-hook nil
+  "*A hook called when preparing to exit from the summary buffer.
 It calls `gnus-summary-expire-articles' by default.")
-(add-hook 'gnus-summary-exit-hook 'gnus-summary-expire-articles)
+(add-hook 'gnus-summary-prepare-exit-hook 'gnus-summary-expire-articles)
+
+(defun gnus-summary-exit-hook nil
+  "*A hook called on exit from the summary buffer.")
 
 (defvar gnus-open-server-hook nil
   "*A hook called just before opening connection to the news server.")
@@ -1303,7 +1306,7 @@ variable (string, integer, character, etc).")
 (defconst gnus-maintainer "gnus-bug@ifi.uio.no (The Gnus Bugfixing Girls + Boys)"
   "The mail address of the Gnus maintainers.")
 
-(defconst gnus-version "(ding) Gnus v0.98.1"
+(defconst gnus-version "(ding) Gnus v0.99"
   "Version number for this version of Gnus.")
 
 (defvar gnus-info-nodes
@@ -1724,7 +1727,6 @@ Thank you for your help in stamping out bugs.
 ;; modified by MORIOKA Tomohiko <morioka@jaist.ac.jp>
 ;;   function `substring' might cut on a middle of multi-octet
 ;;   character.
-
 (defun gnus-truncate-string (str width)
   (substring str 0 width))
 
@@ -1887,23 +1889,13 @@ Thank you for your help in stamping out bugs.
                                        (- (point) 2))) pos))
       (setq gnus-summary-mark-positions pos))))
 
-(defun gnus-format-max-width (form length)
-  (let* ((val (eval form))
-        (valstr (if (numberp val) (int-to-string val) val)))
-    (gnus-limit-string valstr length)))
-
-(defun gnus-set-mouse-face (string)
-  ;; Set mouse face property on STRING.
-  (put-text-property 0 (length string) 'mouse-face gnus-mouse-face string)
-  string)
-
-
 (defun gnus-mouse-face-function (form)
   (` (let ((string (, form)))
        (put-text-property 0 (length string) 'mouse-face gnus-mouse-face string)
        string)))
 
 (defun gnus-max-width-function (el max-width)
+  (or (numberp max-width) (signal 'wrong-type-argument '(numberp max-width)))
   (` (let* ((val (eval (, el)))
            (valstr (if (numberp val)
                        (int-to-string val) val)))
@@ -3158,6 +3150,10 @@ prompt the user for the name of an NNTP server to use."
     (gnus-clear-system)
     (nnheader-init-server-buffer)
     (gnus-read-init-file)
+
+    ;; Read the dribble file.
+    (and gnus-use-dribble-file (gnus-dribble-read-file))
+
     (let ((level (and arg (numberp arg) (> arg 0) arg))
          did-connect)
       (unwind-protect
@@ -3734,7 +3730,7 @@ If UNMARK, remove the mark instead."
 
 ;; Selecting groups.
 
-(defun gnus-group-read-group (all &optional no-article group)
+(defun gnus-group-read-group (&optional all no-article group)
   "Read news in this newsgroup.
 If the prefix argument ALL is non-nil, already read articles become
 readable. If the optional argument NO-ARTICLE is non-nil, no article
@@ -3757,7 +3753,7 @@ will be auto-selected upon group entry."
                                  (length (cdr (assq 'dormant marked)))))))
      no-article)))
 
-(defun gnus-group-select-group (all)
+(defun gnus-group-select-group (&optional all)
   "Select this newsgroup.
 No article is selected automatically.
 If argument ALL is non-nil, already read articles become readable."
@@ -3795,7 +3791,8 @@ If argument ALL is non-nil, already read articles become readable."
   "Jump to newsgroup GROUP."
   (interactive 
    (list (completing-read 
-         "Group: " gnus-active-hashtb nil (not (not gnus-read-active-file)))))
+         "Group: " gnus-active-hashtb nil 
+         (memq gnus-select-method gnus-have-read-active-file))))
 
   (if (equal group "")
       (error "Empty group name"))
@@ -4212,7 +4209,7 @@ score file entries for articles to include in the group."
 
 ;; Group catching up.
 
-(defun gnus-group-catchup-current (n &optional all)
+(defun gnus-group-catchup-current (&optional n all)
   "Mark all articles not marked as unread in current newsgroup as read.
 If prefix argument N is numeric, the ARG next newsgroups will be
 caught up. If ALL is non-nil, marked articles will also be marked as
@@ -4245,7 +4242,7 @@ caught up is returned."
       (gnus-group-next-unread-group 1)
       ret)))
 
-(defun gnus-group-catchup-current-all (n)
+(defun gnus-group-catchup-current-all (&optional n)
   "Mark all articles in current newsgroup as read.
 Cross references (Xref: header) of articles are ignored."
   (interactive "P")
@@ -4274,7 +4271,7 @@ or nil if no action could be taken."
                           (nth 3 (nth 2 entry)))))))
     num))
 
-(defun gnus-group-expire-articles (n)
+(defun gnus-group-expire-articles (&optional n)
   "Expire all expirable articles in the current newsgroup."
   (interactive "P")
   (let ((groups (gnus-group-process-prefix n))
@@ -4324,7 +4321,7 @@ or nil if no action could be taken."
       (gnus-group-update-group-line)))
   (gnus-group-position-cursor))
 
-(defun gnus-group-unsubscribe-current-group (n)
+(defun gnus-group-unsubscribe-current-group (&optional n)
   "Toggle subscription of the current group.
 If given numerical prefix, toggle the N next groups."
   (interactive "P")
@@ -4345,8 +4342,9 @@ If given numerical prefix, toggle the N next groups."
   "Toggle subscribe from/to unsubscribe GROUP.
 New newsgroup is added to .newsrc automatically."
   (interactive
-   (list (completing-read "Group: " gnus-active-hashtb nil 
-                         gnus-have-read-active-file)))
+   (list (completing-read
+         "Group: " gnus-active-hashtb nil 
+         (memq gnus-select-method gnus-have-read-active-file))))
   (let ((newsrc (gnus-gethash group gnus-newsrc-hashtb)))
     (cond (newsrc
           ;; Toggle subscription flag.
@@ -4414,7 +4412,7 @@ The killed newsgroups can be yanked by using \\[gnus-group-yank-group]."
     (beginning-of-line)                        ;Important when LINES < 1
     (gnus-group-kill-group lines)))
 
-(defun gnus-group-kill-group (n)
+(defun gnus-group-kill-group (&optional n)
   "The the next N groups.
 The killed newsgroups can be yanked by using \\[gnus-group-yank-group].
 However, only groups that were alive can be yanked; already killed 
@@ -4467,7 +4465,7 @@ newsgroup yanked is returned."
     (gnus-group-position-cursor)
     group))
       
-(defun gnus-group-list-all-groups (arg)
+(defun gnus-group-list-all-groups (&optional arg)
   "List all newsgroups with level ARG or lower.
 Default is gnus-level-unsubscribed, which lists all subscribed and most
 unsubscribed groups."
@@ -4508,15 +4506,16 @@ specify which levels you are interested in re-scanning."
       (progn
        (gnus-read-active-file)
        (gnus-get-unread-articles (or arg (1+ gnus-level-subscribed))))
-    (let ((gnus-read-active-file nil)
-         (gnus-have-read-active-file (not arg)))
+    (let ((gnus-read-active-file (not arg))
+         (gnus-have-read-active-file 
+          (and (not arg) gnus-have-read-active-file)))
       (gnus-get-unread-articles (or arg (1+ gnus-level-subscribed)))))
   (gnus-group-list-groups (or (and gnus-group-use-permanent-levels arg)
                              gnus-group-default-list-level
                              gnus-level-subscribed)
                          gnus-have-all-newsgroups))
 
-(defun gnus-group-get-new-news-this-group (n)
+(defun gnus-group-get-new-news-this-group (&optional n)
   "Check for newly arrived news in the current group (and the N-1 next groups).
 The difference between N and the number of newsgroup checked is returned.
 If N is negative, this group and the N-1 previous groups will be checked."
@@ -4580,7 +4579,7 @@ If N is negative, this group and the N-1 previous groups will be checked."
              "No description available")))))
 
 ;; Suggested by Per Abrahamsen <amanda@iesd.auc.dk>.
-(defun gnus-group-describe-all-groups (force)
+(defun gnus-group-describe-all-groups (&optional force)
   "Pop up a buffer with descriptions of all newsgroups."
   (interactive "P")
   (and force (setq gnus-description-hashtb nil))
@@ -4692,7 +4691,7 @@ If LOWEST, don't list groups with level lower than LOWEST."
   (interactive)
   (gnus-read-init-file))
 
-(defun gnus-group-check-bogus-groups (silent)
+(defun gnus-group-check-bogus-groups (&optional silent)
   "Check bogus newsgroups.
 If given a prefix, don't ask for confirmation before removing a bogus
 group."
@@ -4700,7 +4699,7 @@ group."
   (gnus-check-bogus-newsgroups (and (not silent) (not gnus-expert-user)))
   (gnus-group-list-groups nil gnus-have-all-newsgroups))
 
-(defun gnus-group-edit-global-kill (article &optional group)
+(defun gnus-group-edit-global-kill (&optional article group)
   "Edit the global kill file.
 If GROUP, edit that local kill file instead."
   (interactive "P")
@@ -5290,7 +5289,7 @@ buffer.
   (define-key gnus-summary-wash-map "\C-c" 'gnus-article-hide-citation-maybe)
   (define-key gnus-summary-wash-map "o" 'gnus-article-treat-overstrike)
   (define-key gnus-summary-wash-map "w" 'gnus-article-word-wrap)
-  (define-key gnus-summary-wash-map "d" 'gnus-article-remove-cr)
+  (define-key gnus-summary-wash-map "m" 'gnus-article-remove-cr)
   (define-key gnus-summary-wash-map "q" 'gnus-article-de-quoted-unreadable)
   (define-key gnus-summary-wash-map "f" 'gnus-article-display-x-face)
   (define-key gnus-summary-wash-map "t" 'gnus-article-date-ut)
@@ -5818,6 +5817,7 @@ If NO-ARTICLE is non-nil, no article is selected initially."
   ;; Generate the summary buffer.
   (let ((buffer-read-only nil))
     (erase-buffer)
+    (gnus-message 5 "Threading...")
     (gnus-summary-prepare-threads 
      (if gnus-show-threads
         (gnus-gather-threads 
@@ -5828,9 +5828,8 @@ If NO-ARTICLE is non-nil, no article is selected initially."
             (gnus-make-threads))))
        gnus-newsgroup-headers)
      'cull)
-    ;; Erase header retrieval message.
+    (gnus-message 5 "Threading...done")
     (gnus-summary-update-lines)
-    (message "")
     ;; Remove the final newline.
     ;;(goto-char (point-max))
     ;;(delete-char -1)
@@ -5878,7 +5877,7 @@ If NO-ARTICLE is non-nil, no article is selected initially."
   ;; `gnus-get-newsgroup-headers' and builds the trees. First we go
   ;; through the dependecies in the hash table and finds all the
   ;; roots. Roots do not refer back to any valid articles.
-  (let (roots)
+  (let (roots new-roots)
     (and gnus-fetch-old-headers (eq gnus-headers-retrieved-by 'nov)
         (gnus-build-old-threads))
     (mapatoms
@@ -5900,11 +5899,22 @@ If NO-ARTICLE is non-nil, no article is selected initially."
                                   (gnus-simplify-subject-re 
                                    (header-subject (car headers)))))
                     (progn
-                      (setq roots (cons (car headers) roots))
+                      (setq new-roots (cons (car headers) new-roots))
                       (setcdr prev (cdr headers)))
                   (setq prev headers))
                 (setq headers (cdr headers)))))))
      gnus-newsgroup-dependencies)
+
+    ;; We enter the new roots into the dependencies structure to
+    ;; ensure that any possible later thread-regeneration will be
+    ;; possible. 
+    (let ((r new-roots))
+      (while r
+       (gnus-sethash (concat (header-id (car r)) ".boo")
+                     (list nil (car r)) gnus-newsgroup-dependencies)
+       (setq r (cdr r))))
+
+    (setq roots (nconc new-roots roots))
     
     (mapcar 'gnus-trim-thread
            (apply 'append
@@ -5918,7 +5928,7 @@ If NO-ARTICLE is non-nil, no article is selected initially."
   ;; roots. Roots do not refer back to any valid articles.
   (let ((default (or gnus-summary-default-score 0))
        (below gnus-summary-expunge-below)
-       roots article)
+       roots article new-roots)
     (and gnus-fetch-old-headers (eq gnus-headers-retrieved-by 'nov)
         (gnus-build-old-threads))
     (mapatoms
@@ -5957,7 +5967,7 @@ If NO-ARTICLE is non-nil, no article is selected initially."
                       (if (not (< (or (cdr (assq (header-number (car headers))
                                                  gnus-newsgroup-scored))
                                       default) below))
-                          (setq roots (cons (car headers) roots))
+                          (setq new-roots (cons (car headers) new-roots))
                         (setq gnus-newsgroup-unreads
                               (delq (header-number (car headers))
                                     gnus-newsgroup-unreads)))
@@ -5975,7 +5985,7 @@ If NO-ARTICLE is non-nil, no article is selected initially."
                 (setq article (header-number (car headers)))
                 (if (not (< (or (cdr (assq article gnus-newsgroup-scored))
                                 default) below))
-                    (progn (setq roots (cons (car headers) roots))
+                    (progn (setq new-roots (cons (car headers) new-roots))
                            (setq prev headers))
                   (setq gnus-newsgroup-unreads 
                         (delq article gnus-newsgroup-unreads))
@@ -5996,6 +6006,17 @@ If NO-ARTICLE is non-nil, no article is selected initially."
               (setq headers (cdr headers)))))))
      gnus-newsgroup-dependencies)
 
+    ;; We enter the new roots into the dependencies structure to
+    ;; ensure that any possible later thread-regeneration will be
+    ;; possible. 
+    (let ((r new-roots))
+      (while r
+       (gnus-sethash (concat (header-id (car r)) ".boo")
+                     (list nil (car r)) gnus-newsgroup-dependencies)
+       (setq r (cdr r))))
+
+    (setq roots (nconc new-roots roots))
+    
     (mapcar 'gnus-trim-thread
            (apply 'append
                   (mapcar 'gnus-cut-thread
@@ -6125,7 +6146,7 @@ If NO-ARTICLE is non-nil, no article is selected initially."
   ;; Return header of first article in THREAD.
   ;; Note that THREAD must never, evr be anything else than a variable -
   ;; using some other form will lead to serious barfage.
-  (or (symbolp thread) (error "Wrong type argument: symbolp, THREAD"))
+  (or (symbolp thread) (signal 'wrong-type-argument '(symbolp thread)))
   ;; (8% speedup to gnus-summary-prepare, just for fun :-)
   (list 'byte-code "\10\211:\203\17\0\211@;\203\16\0A@@\207" ; 
        (vector thread) 2))
@@ -6164,11 +6185,11 @@ If NO-ARTICLE is non-nil, no article is selected initially."
 (defun gnus-thread-sort-by-score (h1 h2)
   "Sort threads by root article score.
 Unscored articles will be counted as having a score of zero."
-  (> (or (assq (header-number (gnus-thread-header h1))
-              gnus-newsgroup-scored) 
+  (> (or (cdr (assq (header-number (gnus-thread-header h1))
+                   gnus-newsgroup-scored))
         gnus-summary-default-score 0)
-     (or (assq (header-number (gnus-thread-header h2))
-              gnus-newsgroup-scored)
+     (or (cdr (assq (header-number (gnus-thread-header h2))
+                   gnus-newsgroup-scored))
         gnus-summary-default-score 0)))
 
 (defun gnus-thread-sort-by-total-score (h1 h2)
@@ -6208,7 +6229,7 @@ or a straight list of headers."
        ;; If this is a straight (sic) list of headers, then a
        ;; threaded summary display isn't required, so we just create
        ;; an unthreaded one.
-       (gnus-summary-prepare-unthreaded threads)
+       (gnus-summary-prepare-unthreaded threads cull)
 
       ;; Do the threaded display.
 
@@ -6273,8 +6294,9 @@ or a straight list of headers."
          ;; We may have to root out some bad articles...
          (and cull
               (= level 0)
-              (cond ((memq (setq number (header-number header))
-                           gnus-newsgroup-dormant)
+              (cond ((and (memq (setq number (header-number header))
+                                gnus-newsgroup-dormant)
+                          (null threads))
                      (setq header nil))
                     ((and gnus-summary-expunge-below
                           (< (or (cdr (assq number gnus-newsgroup-scored))
@@ -6322,7 +6344,7 @@ or a straight list of headers."
        (setq threads (cdr (car thread)))))))
 
 
-(defun gnus-summary-prepare-unthreaded (headers)
+(defun gnus-summary-prepare-unthreaded (headers &optional cull)
   (let (header number)
 
     ;; Do the async thing, if that is required.
@@ -6336,17 +6358,29 @@ or a straight list of headers."
            headers (cdr headers)
            number (header-number header))
 
-      (gnus-summary-insert-line
-       nil header 0 nil 
-       (cond ((memq number gnus-newsgroup-marked) gnus-ticked-mark)
-            ((memq number gnus-newsgroup-dormant) gnus-dormant-mark)
-            ((memq number gnus-newsgroup-unreads) gnus-unread-mark)
-            ((memq number gnus-newsgroup-expirable) gnus-expirable-mark)
-            (t gnus-ancient-mark))
-       (memq number gnus-newsgroup-replied)
-       (memq number gnus-newsgroup-expirable)
-       (header-subject header) nil
-       (cdr (assq number gnus-newsgroup-scored))))))
+      ;; We may have to root out some bad articles...
+      (cond 
+       ((and cull
+            (memq (setq number (header-number header))
+                  gnus-newsgroup-dormant)))
+       ((and cull gnus-summary-expunge-below
+            (< (or (cdr (assq number gnus-newsgroup-scored))
+                   gnus-summary-default-score 0)
+               gnus-summary-expunge-below))
+       (setq gnus-newsgroup-unreads 
+             (delq number gnus-newsgroup-unreads)))
+       (t
+       (gnus-summary-insert-line
+        nil header 0 nil 
+        (cond ((memq number gnus-newsgroup-marked) gnus-ticked-mark)
+              ((memq number gnus-newsgroup-dormant) gnus-dormant-mark)
+              ((memq number gnus-newsgroup-unreads) gnus-unread-mark)
+              ((memq number gnus-newsgroup-expirable) gnus-expirable-mark)
+              (t gnus-ancient-mark))
+        (memq number gnus-newsgroup-replied)
+        (memq number gnus-newsgroup-expirable)
+        (header-subject header) nil
+        (cdr (assq number gnus-newsgroup-scored))))))))
 
 (defun gnus-select-newsgroup (group &optional read-all)
   "Select newsgroup GROUP.
@@ -6391,6 +6425,7 @@ If READ-ALL is non-nil, all articles in the group are selected."
       (setq gnus-newsgroup-dependencies 
            (gnus-make-hashtable (length articles)))
       ;; Retrieve the headers and read them in.
+      (gnus-message 5 "Fetching headers...")
       (setq gnus-newsgroup-headers 
            (if (eq 'nov (setq gnus-headers-retrieved-by
                               (gnus-retrieve-headers 
@@ -6415,6 +6450,7 @@ If READ-ALL is non-nil, all articles in the group are selected."
                        (point) 
                        (search-forward "\n.\n" nil t)))))
              (gnus-get-newsgroup-headers)))
+      (gnus-message 5 "Fetching headers...done")      
       ;; Remove canceled articles from the list of unread articles.
       (setq gnus-newsgroup-unreads
            (gnus-set-sorted-intersection 
@@ -7377,7 +7413,7 @@ displayed, no centering will be performed."
       (gnus-summary-remove-process-mark (car articles))
       (setq articles (cdr articles)))))
 
-(defun gnus-summary-toggle-truncation (arg)
+(defun gnus-summary-toggle-truncation (&optional arg)
   "Toggle truncation of summary lines.
 With arg, turn line truncation on iff arg is positive."
   (interactive "P")
@@ -7386,7 +7422,7 @@ With arg, turn line truncation on iff arg is positive."
          (> (prefix-numeric-value arg) 0)))
   (redraw-display))
 
-(defun gnus-summary-reselect-current-group (all)
+(defun gnus-summary-reselect-current-group (&optional all)
   "Once exit and then reselect the current newsgroup.
 The prefix argument ALL means to select all articles."
   (interactive "P")
@@ -7402,7 +7438,7 @@ The prefix argument ALL means to select all articles."
     (gnus-group-read-group all t)
     (gnus-summary-goto-subject current-subject)))
 
-(defun gnus-summary-rescan-group (all)
+(defun gnus-summary-rescan-group (&optional all)
   "Exit the newsgroup, ask for new articles, and select the newsgroup."
   (interactive "P")
   (gnus-set-global-variables)
@@ -7465,7 +7501,7 @@ gnus-exit-group-hook is called with no arguments if that value is non-nil."
                                                  gnus-newsgroup-name))))
         (mode major-mode)
         (buf (current-buffer)))
-    (run-hooks 'gnus-summary-exit-hook)
+    (run-hooks 'gnus-summary-prepare-exit-hook)
     (gnus-summary-update-info) ; Make all changes in this group permanent.
     (set-buffer buf)
     (and gnus-use-cache (gnus-cache-possibly-remove-articles))
@@ -7503,7 +7539,8 @@ gnus-exit-group-hook is called with no arguments if that value is non-nil."
          (set-buffer (car quit-config))
          (and (eq major-mode 'gnus-summary-mode)
               (gnus-set-global-variables))
-         (gnus-configure-windows (cdr quit-config)))))))
+         (gnus-configure-windows (cdr quit-config))))
+      (run-hooks 'gnus-summary-exit-hook))))
 
 (defalias 'gnus-summary-quit 'gnus-summary-exit-no-update)
 (defun gnus-summary-exit-no-update (&optional no-questions)
@@ -7548,7 +7585,7 @@ gnus-exit-group-hook is called with no arguments if that value is non-nil."
   (and gnus-faq-buffer (gnus-configure-windows 'summary-faq))))
 
 ;; Suggested by Per Abrahamsen <amanda@iesd.auc.dk>.
-(defun gnus-summary-describe-group (force)
+(defun gnus-summary-describe-group (&optional force)
   "Describe the current newsgroup."
   (interactive "P")
   (gnus-group-describe-group force gnus-newsgroup-name))
@@ -7665,7 +7702,7 @@ If BACKWARD, go to previous group instead."
                         (set-buffer sumbuf)
                         (gnus-summary-exit)))))))))))
 
-(defun gnus-summary-prev-group (no-article)
+(defun gnus-summary-prev-group (&optional no-article)
   "Exit current newsgroup and then select previous unread newsgroup.
 If prefix argument NO-ARTICLE is non-nil, no article is selected initially."
   (interactive "P")
@@ -7673,7 +7710,7 @@ If prefix argument NO-ARTICLE is non-nil, no article is selected initially."
 
 ;; Walking around summary lines.
 
-(defun gnus-summary-first-subject (unread)
+(defun gnus-summary-first-subject (&optional unread)
   "Go to the first unread subject.
 If UNREAD is non-nil, go to the first unread article.
 Returns nil if there are no unread articles."
@@ -7757,7 +7794,7 @@ If optional argument UNREAD is non-nil, only unread article is selected."
 
 ;; Walking around summary lines with displaying articles.
 
-(defun gnus-summary-expand-window (arg)
+(defun gnus-summary-expand-window (&optional arg)
   "Make the summary buffer take up the entire Emacs frame.
 Given a prefix, will force an `article' buffer configuration."
   (interactive "P")
@@ -7822,7 +7859,7 @@ be displayed."
   "Obsolete function."
   nil)
 
-(defun gnus-summary-next-article (unread &optional subject backward)
+(defun gnus-summary-next-article (&optional unread subject backward)
   "Select the next article.
 If UNREAD, only unread articles are selected.
 If SUBJECT, only articles with SUBJECT are selected.
@@ -7832,8 +7869,9 @@ If BACKWARD, the previous article is selected instead of the next."
   (let (header)
     (cond
      ;; Is there such an article?
-     ((gnus-summary-display-article 
-       (gnus-summary-search-forward unread subject backward))
+     ((or (gnus-summary-display-article 
+          (gnus-summary-search-forward unread subject backward))
+         (eq (gnus-summary-article-mark) gnus-canceled-mark))
       (gnus-summary-position-cursor))
      ;; If not, we try the first unread, if that is wanted.
      ((and subject
@@ -7917,7 +7955,7 @@ If BACKWARD, the previous article is selected instead of the next."
   (gnus-summary-next-article t (and gnus-auto-select-same
                                    (gnus-summary-subject-string))))
 
-(defun gnus-summary-prev-article (unread &optional subject)
+(defun gnus-summary-prev-article (&optional unread subject)
   "Select the article after the current one.
 If UNREAD is non-nil, only unread articles are selected."
   (interactive "P")
@@ -7929,7 +7967,7 @@ If UNREAD is non-nil, only unread articles are selected."
   (gnus-summary-prev-article t (and gnus-auto-select-same
                                    (gnus-summary-subject-string))))
 
-(defun gnus-summary-next-page (lines &optional circular)
+(defun gnus-summary-next-page (&optional lines circular)
   "Show next page of selected article.
 If end of article, select next article.
 Argument LINES specifies lines to be scrolled up.
@@ -7961,7 +7999,7 @@ current article."
     (gnus-summary-recenter)
     (gnus-summary-position-cursor)))
 
-(defun gnus-summary-prev-page (lines)
+(defun gnus-summary-prev-page (&optional lines)
   "Show previous page of selected article.
 Argument LINES specifies lines to be scrolled down."
   (interactive "P")
@@ -8328,7 +8366,7 @@ article. If BACKWARD (the prefix) is non-nil, search backward instead."
    (goto-char (point-max))
    (and gnus-break-pages (gnus-narrow-to-page))))
 
-(defun gnus-summary-show-article (no-refetch)
+(defun gnus-summary-show-article (&optional no-refetch)
   "Force re-fetching of the current article.
 If the prefix argument NO-REFETCH is non-nil, no actual refetch will
 be performed.  The current article will simply be redisplayed."
@@ -8342,21 +8380,21 @@ be performed.  The current article will simply be redisplayed."
     (gnus-configure-windows 'article)
     (gnus-summary-position-cursor)))
 
-(defun gnus-summary-verbose-headers (arg)
+(defun gnus-summary-verbose-headers (&optional arg)
   "Toggle permanent full header display.
 If ARG is a positive number, turn header display on.
 If ARG is a negative number, turn header display off."
   (interactive "P")
   (gnus-set-global-variables)
   (gnus-summary-toggle-header arg)
-  (setq gnus-have-all-headers
+  (setq gnus-show-all-headers
        (cond ((or (not (numberp arg))
                   (zerop arg))
-              (not gnus-have-all-headers))
+              (not gnus-show-all-headers))
              ((natnump arg)
               t))))
 
-(defun gnus-summary-toggle-header (arg)
+(defun gnus-summary-toggle-header (&optional arg)
   "Show the headers if they are hidden, or hide them if they are shown.
 If ARG is a positive number, show the entire header.
 If ARG is a negative number, hide the unwanted header lines."
@@ -8370,10 +8408,20 @@ If ARG is a negative number, hide the unwanted header lines."
                                                gnus-hidden-properties)
            (if (< arg 0) (run-hooks 'gnus-article-display-hook)))
        (if (text-property-any (point-min) (point-max) 'invisible t)
-           (remove-text-properties (point-min) (point-max)
-                                   gnus-hidden-properties)
-         (let ((gnus-have-all-headers nil))
-           (run-hooks 'gnus-article-display-hook))))
+           (remove-text-properties 
+            (point-min) (point-max) gnus-hidden-properties)
+         ;; We hide the headers. This song and dance act below is
+         ;; done because `gnus-have-all-headers' is buffer-local to
+         ;; the summary buffer, and we only want to temporarily
+         ;; change it in that buffer. Ugh.
+         (let ((have gnus-have-all-headers))
+           (save-excursion
+             (set-buffer gnus-summary-buffer)
+             (setq gnus-have-all-headers nil)
+             (save-excursion
+               (set-buffer gnus-article-buffer)
+               (run-hooks 'gnus-article-display-hook))
+             (setq gnus-have-all-headers have)))))
       (set-window-point (get-buffer-window (current-buffer)) (point-min)))))
 
 (defun gnus-summary-show-all-headers ()
@@ -8382,7 +8430,7 @@ If ARG is a negative number, hide the unwanted header lines."
   (gnus-set-global-variables)
   (gnus-article-show-all-headers))
 
-(defun gnus-summary-toggle-mime (arg)
+(defun gnus-summary-toggle-mime (&optional arg)
   "Toggle MIME processing.
 If ARG is a positive number, turn MIME processing on."
   (interactive "P")
@@ -8392,7 +8440,7 @@ If ARG is a positive number, turn MIME processing on."
          (> (prefix-numeric-value arg) 0)))
   (gnus-summary-select-article t 'force))
 
-(defun gnus-summary-caesar-message (arg)
+(defun gnus-summary-caesar-message (&optional arg)
   "Caesar rotate the current article by 13.
 The numerical prefix specifies how manu places to rotate each letter
 forward."
@@ -8418,7 +8466,7 @@ forward."
 
 ;; Suggested by Brian Edmonds <bedmonds@prodigy.bc.ca>.
 
-(defun gnus-summary-move-article (n &optional to-newsgroup select-method)
+(defun gnus-summary-move-article (&optional n to-newsgroup select-method)
   "Move the current article to a different newsgroup.
 If N is a positive number, move the N next articles.
 If N is a negative number, move the N previous articles.
@@ -8519,7 +8567,7 @@ and `request-accept' functions. (Ie. mail newsgroups at present.)"
       (gnus-summary-remove-process-mark (car articles))
       (setq articles (cdr articles)))))
 
-(defun gnus-summary-respool-article (n &optional respool-method)
+(defun gnus-summary-respool-article (&optional n respool-method)
   "Respool the current article.
 The article will be squeezed through the mail spooling process again,
 which means that it will be put in some mail newsgroup or other
@@ -8551,7 +8599,7 @@ latter case, they will be copied into the relevant groups."
          (gnus-summary-copy-article n nil (intern respool-method))))))
 
 ;; Suggested by gregj@unidata.com (Gregory J. Grubbs).
-(defun gnus-summary-copy-article (n &optional to-newsgroup select-method)
+(defun gnus-summary-copy-article (&optional n to-newsgroup select-method)
   "Move the current article to a different newsgroup.
 If N is a positive number, move the N next articles.
 If N is a negative number, move the N previous articles.
@@ -8689,11 +8737,12 @@ functions. (Ie. mail newsgroups at present.)"
        ;; We go through the old list of expirable, and mark all
        ;; really expired articles as non-existant.
        (or (eq es expirable) ; If nothing was expired, we don't mark.
-           (while expirable
-             (or (memq (car expirable) es)
-                 (gnus-summary-mark-article
-                  (car expirable) gnus-canceled-mark))
-             (setq expirable (cdr expirable))))
+           (let ((gnus-use-cache nil))
+             (while expirable
+               (or (memq (car expirable) es)
+                   (gnus-summary-mark-article
+                    (car expirable) gnus-canceled-mark))
+               (setq expirable (cdr expirable)))))
        (gnus-message 6 "Expiring articles...done")))))
 
 (defun gnus-summary-expire-articles-now ()
@@ -8710,7 +8759,7 @@ deleted forever, right now."
     (gnus-summary-expire-articles)))
 
 ;; Suggested by Jack Vinson <vinson@unagi.cis.upenn.edu>.
-(defun gnus-summary-delete-article (n)
+(defun gnus-summary-delete-article (&optional n)
   "Delete the N next (mail) articles.
 This command actually deletes articles. This is not a marking
 command. The article will disappear forever from you life, never to
@@ -8801,11 +8850,6 @@ This will have permanent effect only in mail groups."
   (interactive "p")
   (gnus-summary-set-score (+ (gnus-summary-article-score) n)))
 
-(defun gnus-summary-lower-score (n)
-  "Lower the score of the current article by N."
-  (interactive "p")
-  (gnus-summary-raise-score (- n)))
-
 (defun gnus-summary-set-score (n)
   "Set the score of the current article to N."
   (interactive "p")
@@ -8856,7 +8900,7 @@ This will have permanent effect only in mail groups."
   (if level (prefix-numeric-value level) 
     gnus-score-interactive-default-score))
 
-(defun gnus-summary-raise-thread (score)
+(defun gnus-summary-raise-thread (&optional score)
   "Raise the score of the articles in the current thread with SCORE."
   (interactive "P")
   (setq score (1- (gnus-score-default score)))
@@ -8885,12 +8929,12 @@ This will have permanent effect only in mail groups."
   (interactive "p")
   (gnus-summary-raise-same-subject (- score)))
 
-(defun gnus-summary-lower-thread (score)
+(defun gnus-summary-lower-thread (&optional score)
   "Lower score of articles in the current thread with SCORE."
   (interactive "P")
   (gnus-summary-raise-thread (- (1- (gnus-score-default score)))))
 
-(defun gnus-summary-kill-same-subject-and-select (unmark)
+(defun gnus-summary-kill-same-subject-and-select (&optional unmark)
   "Mark articles which has the same subject as read, and then select the next.
 If UNMARK is positive, remove any kind of mark.
 If UNMARK is negative, tick articles."
@@ -8907,7 +8951,7 @@ If UNMARK is negative, tick articles."
     (gnus-message 7 "%d articles are marked as %s"
                  count (if unmark "unread" "read"))))
 
-(defun gnus-summary-kill-same-subject (unmark)
+(defun gnus-summary-kill-same-subject (&optional unmark)
   "Mark articles which has the same subject as read. 
 If UNMARK is positive, remove any kind of mark.
 If UNMARK is negative, tick articles."
@@ -8928,22 +8972,28 @@ If UNMARK is negative, tick articles."
   "Mark articles with same SUBJECT as read, and return marked number.
 If optional argument UNMARK is positive, remove any kinds of marks.
 If optional argument UNMARK is negative, mark articles as unread instead."
-  (let ((count 0))
+  (let ((count 1))
     (save-excursion
       (cond 
        ((null unmark)                  ; Mark as read.
        (while (and 
-               (gnus-summary-mark-article-as-read gnus-killed-mark)
+               (progn
+                 (gnus-summary-mark-article-as-read gnus-killed-mark)
+                 (gnus-summary-show-thread) t)
                (gnus-summary-search-forward nil subject))
          (setq count (1+ count))))
        ((> unmark 0)                   ; Tick.
        (while (and
-               (gnus-summary-mark-article-as-unread gnus-ticked-mark)
+               (progn
+                 (gnus-summary-mark-article-as-unread gnus-ticked-mark)
+                 (gnus-summary-show-thread) t)
                (gnus-summary-search-forward nil subject))
          (setq count (1+ count))))
        (t                              ; Mark as unread.
        (while (and
-               (gnus-summary-mark-article-as-unread gnus-unread-mark)
+               (progn
+                 (gnus-summary-mark-article-as-unread gnus-unread-mark)
+                 (gnus-summary-show-thread) t)
                (gnus-summary-search-forward nil subject))
          (setq count (1+ count)))))
       ;; Return the number of marked articles.
@@ -9312,7 +9362,7 @@ The difference between N and the number of marks cleared is returned."
        (or (memq gnus-current-article gnus-newsgroup-marked)
           (memq gnus-current-article gnus-newsgroup-dormant)
           (memq gnus-current-article gnus-newsgroup-expirable)
-          (gnus-summary-mark-article-as-read gnus-read-mark))))
+          (gnus-summary-mark-article gnus-current-article gnus-read-mark))))
 
 (defun gnus-summary-mark-region-as-read (point mark all)
   "Mark all unread articles between point and mark as read.
@@ -9391,7 +9441,7 @@ even ticked and dormant ones."
          (gnus-summary-prev-subject 1)
        (gnus-summary-position-cursor))))
 
-(defun gnus-summary-expunge-below (score)
+(defun gnus-summary-expunge-below (&optional score)
   "Remove articles with score less than SCORE."
   (interactive "P")
   (gnus-set-global-variables)
@@ -9431,24 +9481,28 @@ even ticked and dormant ones."
           (gnus-summary-mark-article nil mark))
       (forward-line 1))))
 
-(defun gnus-summary-kill-below (score)
+(defun gnus-summary-kill-below (&optional score)
   "Mark articles with score below SCORE as read."
   (interactive "P")
+  (gnus-set-global-variables)
   (gnus-summary-mark-below score gnus-killed-mark))
 
-(defun gnus-summary-clear-above (score)
+(defun gnus-summary-clear-above (&optional score)
   "Clear all marks from articles with score above SCORE."
   (interactive "P")
+  (gnus-set-global-variables)
   (gnus-summary-mark-above score gnus-unread-mark))
 
-(defun gnus-summary-tick-above (score)
+(defun gnus-summary-tick-above (&optional score)
   "Tick all articles with score above SCORE."
   (interactive "P")
+  (gnus-set-global-variables)
   (gnus-summary-mark-above score gnus-ticked-mark))
 
 (defun gnus-summary-mark-above (score mark)
   "Mark articles with score over SCORE with MARK."
   (interactive "P\ncMark: ")
+  (gnus-set-global-variables)
   (setq score (if score
                  (prefix-numeric-value score)
                (or gnus-summary-default-score 0)))
@@ -9466,6 +9520,7 @@ even ticked and dormant ones."
 (defun gnus-summary-show-all-expunged ()
   "Display all the hidden articles that were expunged for low scores."
   (interactive)
+  (gnus-set-global-variables)
   (let ((buffer-read-only nil))
     (let ((scored gnus-newsgroup-scored)
          headers h)
@@ -9481,7 +9536,7 @@ even ticked and dormant ones."
        (gnus-summary-update-lines 
         (point)
         (progn
-          (gnus-summary-prepare-threads (nreverse headers))
+          (gnus-summary-prepare-unthreaded (nreverse headers))
           (point)))))
     (goto-char (point-min))
     (gnus-summary-position-cursor)))
@@ -9489,6 +9544,7 @@ even ticked and dormant ones."
 (defun gnus-summary-show-all-dormant ()
   "Display all the hidden articles that are marked as dormant."
   (interactive)
+  (gnus-set-global-variables)
   (let ((buffer-read-only nil))
     (let ((dormant gnus-newsgroup-dormant)
          headers h)
@@ -9503,7 +9559,7 @@ even ticked and dormant ones."
        (gnus-summary-update-lines 
         (point)
         (progn
-          (gnus-summary-prepare-threads (nreverse headers))
+          (gnus-summary-prepare-unthreaded (nreverse headers))
           (point)))))
     (goto-char (point-min))
     (gnus-summary-position-cursor)))
@@ -9511,10 +9567,11 @@ even ticked and dormant ones."
 (defun gnus-summary-hide-all-dormant ()
   "Hide all dormant articles."
   (interactive)
+  (gnus-set-global-variables)
   (gnus-summary-remove-lines-marked-with (char-to-string gnus-dormant-mark))
   (gnus-summary-position-cursor))
 
-(defun gnus-summary-catchup (all &optional quietly to-here not-mark)
+(defun gnus-summary-catchup (&optional all quietly to-here not-mark)
   "Mark all articles not marked as unread in this newsgroup as read.
 If prefix argument ALL is non-nil, all articles are marked as read.
 If QUIETLY is non-nil, no questions will be asked.
@@ -9522,6 +9579,7 @@ If TO-HERE is non-nil, it should be a point in the buffer. All
 articles before this point will be marked as read.
 The number of articles marked as read is returned."
   (interactive "P")
+  (gnus-set-global-variables)
   (prog1
       (if (or quietly
              (not gnus-interactive-catchup) ;Without confirmation?
@@ -9560,6 +9618,7 @@ The number of articles marked as read is returned."
   "Mark all unticked articles before the current one as read.
 If ALL is non-nil, also mark ticked and dormant articles as read."
   (interactive)
+  (gnus-set-global-variables)
   (save-excursion
     (and (zerop (forward-line -1))
         (progn
@@ -9571,12 +9630,14 @@ If ALL is non-nil, also mark ticked and dormant articles as read."
 (defun gnus-summary-catchup-all (&optional quietly)
   "Mark all articles in this newsgroup as read."
   (interactive)
+  (gnus-set-global-variables)
   (gnus-summary-catchup t quietly))
 
-(defun gnus-summary-catchup-and-exit (all &optional quietly)
+(defun gnus-summary-catchup-and-exit (&optional all quietly)
   "Mark all articles not marked as unread in this newsgroup as read, then exit.
 If prefix argument ALL is non-nil, all articles are marked as read."
   (interactive "P")
+  (gnus-set-global-variables)
   (gnus-summary-catchup all quietly nil 'fast)
   ;; Select next newsgroup or exit.
   (if (eq gnus-auto-select-next 'quietly)
@@ -9586,23 +9647,26 @@ If prefix argument ALL is non-nil, all articles are marked as read."
 (defun gnus-summary-catchup-all-and-exit (&optional quietly)
   "Mark all articles in this newsgroup as read, and then exit."
   (interactive)
+  (gnus-set-global-variables)
   (gnus-summary-catchup-and-exit t quietly))
 
 ;; Suggested by "Arne Eofsson" <arne@hodgkin.mbi.ucla.edu>.
-(defun gnus-summary-catchup-and-goto-next-group (all)
+(defun gnus-summary-catchup-and-goto-next-group (&optional all)
   "Mark all articles in this group as read and select the next group.
 If given a prefix, mark all articles, unread as well as ticked, as
 read." 
   (interactive "P")
+  (gnus-set-global-variables)
   (gnus-summary-catchup all)
   (gnus-summary-next-group))
 
 ;; Thread-based commands.
 
-(defun gnus-summary-toggle-threads (arg)
+(defun gnus-summary-toggle-threads (&optional arg)
   "Toggle showing conversation threads.
 If ARG is positive number, turn showing conversation threads on."
   (interactive "P")
+  (gnus-set-global-variables)
   (let ((current (or (gnus-summary-article-number) gnus-newsgroup-end)))
     (setq gnus-show-threads
          (if (null arg) (not gnus-show-threads)
@@ -9614,6 +9678,7 @@ If ARG is positive number, turn showing conversation threads on."
 (defun gnus-summary-show-all-threads ()
   "Show all threads."
   (interactive)
+  (gnus-set-global-variables)
   (save-excursion
     (let ((buffer-read-only nil))
       (subst-char-in-region (point-min) (point-max) ?\^M ?\n t)))
@@ -9623,21 +9688,23 @@ If ARG is positive number, turn showing conversation threads on."
   "Show thread subtrees.
 Returns nil if no thread was there to be shown."
   (interactive)
-  (prog1
-      (save-excursion
-       (let ((buffer-read-only nil)
-             ;; first goto end then to beg, to have point at beg after let
-             (end (progn (end-of-line) (point)))
-             (beg (progn (beginning-of-line) (point))))
-         (prog1
-             ;; Any hidden lines here?
-             (search-forward "\r" end t)
-           (subst-char-in-region beg end ?\^M ?\n t))))
-    (gnus-summary-position-cursor)))
+  (gnus-set-global-variables)
+  (let ((buffer-read-only nil)
+       (orig (point))
+       ;; first goto end then to beg, to have point at beg after let
+       (end (progn (end-of-line) (point)))
+       (beg (progn (beginning-of-line) (point))))
+    (prog1
+       ;; Any hidden lines here?
+       (search-forward "\r" end t)
+      (subst-char-in-region beg end ?\^M ?\n t)
+      (goto-char orig)
+      (gnus-summary-position-cursor))))
 
 (defun gnus-summary-hide-all-threads ()
   "Hide all thread subtrees."
   (interactive)
+  (gnus-set-global-variables)
   (save-excursion
     (goto-char (point-min))
     (gnus-summary-hide-thread)
@@ -9649,6 +9716,7 @@ Returns nil if no thread was there to be shown."
   "Hide thread subtrees.
 Returns nil if no threads were there to be hidden."
   (interactive)
+  (gnus-set-global-variables)
   (let ((buffer-read-only nil)
        (start (point))
        (level (gnus-summary-thread-level))
@@ -9692,6 +9760,7 @@ If N is negative, search backward instead.
 Returns the difference between N and the number of skips actually
 done."
   (interactive "p")
+  (gnus-set-global-variables)
   (let ((backward (< n 0))
        (n (abs n)))
   (while (and (> n 0)
@@ -9706,6 +9775,7 @@ done."
 Returns the difference between N and the number of skips actually
 done."
   (interactive "p")
+  (gnus-set-global-variables)
   (gnus-summary-next-thread (- n)))
 
 (defun gnus-summary-go-down-thread (&optional same)
@@ -9737,6 +9807,7 @@ If N is negative, go up instead.
 Returns the difference between N and how many steps down that were
 taken."
   (interactive "p")
+  (gnus-set-global-variables)
   (let ((up (< n 0))
        (n (abs n)))
   (while (and (> n 0)
@@ -9753,13 +9824,15 @@ If N is negative, go up instead.
 Returns the difference between N and how many steps down that were
 taken."
   (interactive "p")
+  (gnus-set-global-variables)
   (gnus-summary-down-thread (- n)))
 
-(defun gnus-summary-kill-thread (unmark)
+(defun gnus-summary-kill-thread (&optional unmark)
   "Mark articles under current thread as read.
 If the prefix argument is positive, remove any kinds of marks.
 If the prefix argument is negative, tick articles instead."
   (interactive "P")
+  (gnus-set-global-variables)
   (if unmark
       (setq unmark (prefix-numeric-value unmark)))
   (let ((killing t)
@@ -9793,14 +9866,19 @@ If the prefix argument is negative, tick articles instead."
   "Sort summary buffer by article number.
 Argument REVERSE means reverse order."
   (interactive "P")
+  (gnus-set-global-variables)
   (gnus-summary-sort 
-   (cons 'gnus-summary-article-number 'gnus-thread-sort-by-number) reverse))
+   ;; `gnus-summary-article-number' is a macro, and `sort-subr' wants
+   ;; a function, so we wrap it.
+   (cons (lambda () (gnus-summary-article-number))
+        'gnus-thread-sort-by-number) reverse))
 
 (defun gnus-summary-sort-by-author (&optional reverse)
   "Sort summary buffer by author name alphabetically.
 If case-fold-search is non-nil, case of letters is ignored.
 Argument REVERSE means reverse order."
   (interactive "P")
+  (gnus-set-global-variables)
   (gnus-summary-sort
    (cons
     (lambda ()
@@ -9817,6 +9895,7 @@ Argument REVERSE means reverse order."
 If case-fold-search is non-nil, case of letters is ignored.
 Argument REVERSE means reverse order."
   (interactive "P")
+  (gnus-set-global-variables)
   (gnus-summary-sort
    (cons
     (lambda ()
@@ -9828,6 +9907,7 @@ Argument REVERSE means reverse order."
   "Sort summary buffer by date.
 Argument REVERSE means reverse order."
   (interactive "P")
+  (gnus-set-global-variables)
   (gnus-summary-sort
    (cons
     (lambda ()
@@ -9841,8 +9921,10 @@ Argument REVERSE means reverse order."
   "Sort summary buffer by score.
 Argument REVERSE means reverse order."
   (interactive "P")
+  (gnus-set-global-variables)
   (gnus-summary-sort 
-   (cons 'gnus-summary-article-score 'gnus-thread-sort-by-score)
+   (cons (lambda () (gnus-summary-article-score))
+        'gnus-thread-sort-by-score)
    (not reverse)))
 
 (defvar gnus-summary-already-sorted nil)
@@ -9852,12 +9934,15 @@ Argument REVERSE means reverse order."
       ()
     (let (buffer-read-only)
       (if (not gnus-show-threads)
+         ;; We do untreaded sorting...
          (progn
            (goto-char (point-min))
            (sort-subr reverse 'forward-line 'end-of-line (car predicate)))
+       ;; ... or we do threaded sorting.
        (let ((gnus-thread-sort-functions (list (cdr predicate)))
              (gnus-summary-prepare-hook nil)
              (gnus-summary-already-sorted nil))
+         ;; We do that by simply regenerating the threads.
          (gnus-summary-prepare)
          (and gnus-show-threads
               gnus-thread-hide-subtree
@@ -9876,10 +9961,10 @@ Argument REVERSE means reverse order."
 (defun gnus-sortable-date (date)
   "Make sortable string by string-lessp from DATE.
 Timezone package is used."
-  (let* ((date   (timezone-fix-time date nil nil)) ;[Y M D H M S]
-        (year   (aref date 0))
-        (month  (aref date 1))
-        (day    (aref date 2)))
+  (let* ((date (timezone-fix-time date nil nil)) ;[Y M D H M S]
+        (year (aref date 0))
+        (month (aref date 1))
+        (day (aref date 2)))
     (timezone-make-sortable-date 
      year month day 
      (timezone-make-time-string
@@ -9888,7 +9973,7 @@ Timezone package is used."
 
 ;; Summary saving commands.
 
-(defun gnus-summary-save-article (n)
+(defun gnus-summary-save-article (&optional n)
   "Save the current article using the default saver function.
 If N is a positive number, save the N next articles.
 If N is a negative number, save the N previous articles.
@@ -9896,6 +9981,7 @@ If N is nil and any articles have been marked with the process mark,
 save those articles instead.
 The variable `gnus-default-article-saver' specifies the saver function."
   (interactive "P")
+  (gnus-set-global-variables)
   (let ((articles (gnus-summary-work-articles n)))
     (while articles
       (let ((header (gnus-get-header-by-num (car articles))))
@@ -9930,43 +10016,47 @@ The variable `gnus-default-article-saver' specifies the saver function."
     (gnus-summary-position-cursor)
     n))
 
-(defun gnus-summary-pipe-output (arg)
+(defun gnus-summary-pipe-output (&optional arg)
   "Pipe the current article to a subprocess.
 If N is a positive number, pipe the N next articles.
 If N is a negative number, pipe the N previous articles.
 If N is nil and any articles have been marked with the process mark,
 pipe those articles instead."
   (interactive "P")
+  (gnus-set-global-variables)
   (let ((gnus-default-article-saver 'gnus-summary-save-in-pipe))
     (gnus-summary-save-article arg)))
 
-(defun gnus-summary-save-article-mail (arg)
+(defun gnus-summary-save-article-mail (&optional arg)
   "Append the current article to an mail file.
 If N is a positive number, save the N next articles.
 If N is a negative number, save the N previous articles.
 If N is nil and any articles have been marked with the process mark,
 save those articles instead."
   (interactive "P")
+  (gnus-set-global-variables)
   (let ((gnus-default-article-saver 'gnus-summary-save-in-mail))
     (gnus-summary-save-article arg)))
 
-(defun gnus-summary-save-article-rmail (arg)
+(defun gnus-summary-save-article-rmail (&optional arg)
   "Append the current article to an rmail file.
 If N is a positive number, save the N next articles.
 If N is a negative number, save the N previous articles.
 If N is nil and any articles have been marked with the process mark,
 save those articles instead."
   (interactive "P")
+  (gnus-set-global-variables)
   (let ((gnus-default-article-saver 'gnus-summary-save-in-rmail))
     (gnus-summary-save-article arg)))
 
-(defun gnus-summary-save-article-file (arg)
+(defun gnus-summary-save-article-file (&optional arg)
   "Append the current article to a file.
 If N is a positive number, save the N next articles.
 If N is a negative number, save the N previous articles.
 If N is nil and any articles have been marked with the process mark,
 save those articles instead."
   (interactive "P")
+  (gnus-set-global-variables)
   (let ((gnus-default-article-saver 'gnus-summary-save-in-file))
     (gnus-summary-save-article arg)))
 
@@ -10014,6 +10104,7 @@ Optional argument FILENAME specifies file name.
 Directory to save to is default to `gnus-article-save-directory' which
 is initialized from the SAVEDIR environment variable."
   (interactive)
+  (gnus-set-global-variables)
   (let ((default-name
          (funcall gnus-rmail-save-name gnus-newsgroup-name
                   gnus-current-headers gnus-newsgroup-last-rmail)))
@@ -10036,6 +10127,7 @@ Optional argument FILENAME specifies file name.
 Directory to save to is default to `gnus-article-save-directory' which
 is initialized from the SAVEDIR environment variable."
   (interactive)
+  (gnus-set-global-variables)
   (let ((default-name
          (funcall gnus-mail-save-name gnus-newsgroup-name
                   gnus-current-headers gnus-newsgroup-last-mail)))
@@ -10064,6 +10156,7 @@ Optional argument FILENAME specifies file name.
 Directory to save to is default to `gnus-article-save-directory' which
 is initialized from the SAVEDIR environment variable."
   (interactive)
+  (gnus-set-global-variables)
   (let ((default-name
          (funcall gnus-file-save-name gnus-newsgroup-name
                   gnus-current-headers gnus-newsgroup-last-file)))
@@ -10083,6 +10176,7 @@ is initialized from the SAVEDIR environment variable."
 (defun gnus-summary-save-in-pipe (&optional command)
   "Pipe this article to subprocess."
   (interactive)
+  (gnus-set-global-variables)
   (let ((command (read-string "Shell command on article: "
                              gnus-last-shell-command)))
     (if (string-equal command "")
@@ -10154,6 +10248,8 @@ is initialized from the SAVEDIR environment variable."
          (forward-line -1)
          (gnus-sethash (int-to-string gnus-reffed-article-number)
                        (car pslist) gnus-newsgroup-headers-hashtb-by-number)
+         (setq gnus-newsgroup-unreads
+               (cons gnus-reffed-article-number gnus-newsgroup-unreads))
          (setq gnus-reffed-article-number (1- gnus-reffed-article-number))
          (setq pslist (cdr pslist)))))))
 
@@ -10185,6 +10281,7 @@ is initialized from the SAVEDIR environment variable."
   (interactive
    (list (read-file-name "Copy file: " default-directory)
         (read-file-name "Copy file to: " default-directory)))
+  (gnus-set-global-variables)
   (or to (setq to (read-file-name "Copy file to: " default-directory)))
   (and (file-directory-p to) 
        (setq to (concat (file-name-as-directory to)
@@ -10196,11 +10293,13 @@ is initialized from the SAVEDIR environment variable."
 (defun gnus-summary-edit-global-kill (article)
   "Edit the \"global\" kill file."
   (interactive (list (gnus-summary-article-number)))
+  (gnus-set-global-variables)
   (gnus-group-edit-global-kill article))
 
 (defun gnus-summary-edit-local-kill ()
   "Edit a local kill file applied to the current newsgroup."
   (interactive)
+  (gnus-set-global-variables)
   (setq gnus-current-headers 
        (gnus-gethash 
         (int-to-string (gnus-summary-article-number))
@@ -10245,7 +10344,7 @@ is initialized from the SAVEDIR environment variable."
          "\C-c\C-s\C-s" "\C-c\C-s\C-d" "\C-c\C-s\C-i" "\C-x\C-s"
          "\M-g" "w" "\C-c\C-r" "\M-t" "C"
          "o" "\C-o" "|" "\M-k" "\M-K" "V" "\C-c\C-d"
-         "\C-c\C-i" "x" "X" "s" "t" "g" "?" "l"
+         "\C-c\C-i" "x" "X" "t" "g" "?" "l"
          "\C-c\C-v\C-v" "\C-d" "v" 
 ;;       "Mt" "M!" "Md" "Mr"
 ;;       "Mc" "M " "Me" "Mx" "M?" "Mb" "MB" "M#" "M\M-#" "M\M-r"
@@ -10781,31 +10880,36 @@ how much time has lapsed since DATE."
             ;; If the date is seriously mangled, the timezone
             ;; functions are liable to bug out, so we condition-case
             ;; the entire thing.  
-            (let* ((sec (condition-case ()
-                            (max (- (gnus-seconds-since-epoch 
+            (let* ((real-sec (condition-case ()
+                                 (- (gnus-seconds-since-epoch 
                                      (timezone-make-date-arpa-standard
                                       (current-time-string) 
                                       (current-time-zone) "UT"))
                                     (gnus-seconds-since-epoch 
                                      (timezone-make-date-arpa-standard 
                                       date nil "UT")))
-                                 0)
-                          (error 0)))
+                               (error 0)))
+                   (sec (abs real-sec))
                    num prev)
-              (concat
-               "X-Sent: "
-               (mapconcat 
-                (lambda (unit)
-                  (if (zerop (setq num (ffloor (/ sec (cdr unit)))))
-                      ""
-                    (setq sec (- sec (* num (cdr unit))))
-                    (prog1
-                        (concat (if prev ", " "") (int-to-string (floor num))
-                                " " (symbol-name (car unit))
-                                (if (> num 1) "s" ""))
-                      (setq prev t))))
-                gnus-article-time-units "")
-               " ago\n")))
+              (if (zerop sec)
+                  "X-Sent: Now\n"
+                (concat
+                 "X-Sent: "
+                 (mapconcat 
+                  (lambda (unit)
+                    (if (zerop (setq num (ffloor (/ sec (cdr unit)))))
+                        ""
+                      (setq sec (- sec (* num (cdr unit))))
+                      (prog1
+                          (concat (if prev ", " "") (int-to-string 
+                                                     (floor num))
+                                  " " (symbol-name (car unit))
+                                  (if (> num 1) "s" ""))
+                        (setq prev t))))
+                  gnus-article-time-units "")
+                 (if (> real-sec 0)
+                     " ago\n"
+                   " in the future\n")))))
            (t
             (error "Unknown conversion type: %s" type)))))))))
 
@@ -10960,7 +11064,7 @@ Intended to be used with gnus-article-prepare-hook."
 
 ;; Article mode commands
 
-(defun gnus-article-next-page (lines)
+(defun gnus-article-next-page (&optional lines)
   "Show next page of current article.
 If end of article, return non-nil. Otherwise return nil.
 Argument LINES specifies lines to be scrolled up."
@@ -10987,7 +11091,7 @@ Argument LINES specifies lines to be scrolled up."
        (goto-char (point-max))))
     nil))
 
-(defun gnus-article-prev-page (lines)
+(defun gnus-article-prev-page (&optional lines)
   "Show previous page of current article.
 Argument LINES specifies lines to be scrolled down."
   (interactive "P")
@@ -11139,9 +11243,10 @@ If NEWSGROUP is nil, return the global kill file name instead."
 ;;;
 
 (defvar gnus-dribble-ignore nil)
+(defvar gnus-dribble-eval-file nil)
 
 (defun gnus-dribble-file-name ()
-  (concat gnus-startup-file "-dribble"))
+  (concat gnus-current-startup-file "-dribble"))
 
 (defun gnus-dribble-open ()
   (save-excursion 
@@ -11185,10 +11290,15 @@ If NEWSGROUP is nil, return the global kill file name instead."
                  (set-buffer-modified-p t))
              (if (gnus-y-or-n-p 
                   "Auto-save file exists. Do you want to read it? ")
-                 (progn
-                   (gnus-message 5 "Reading %s..." dribble-file) 
-                   (eval-buffer (current-buffer))
-                   (gnus-message 5 "Reading %s...done" dribble-file)))))))))
+                 (setq gnus-dribble-eval-file t))))))))
+
+(defun gnus-dribble-eval-file ()
+  (if (not gnus-dribble-eval-file)
+      ()
+    (setq gnus-dribble-eval-file nil)
+    (save-excursion
+      (set-buffer gnus-dribble-buffer)
+      (eval-buffer (current-buffer)))))
 
 (defun gnus-dribble-delete-file ()
   (if (file-exists-p (gnus-dribble-file-name))
@@ -11666,7 +11776,8 @@ If RAWFILE is non-nil, the .newsrc file will also be read.
 If LEVEL is non-nil, the news will be set up at level LEVEL."
   (let ((init (not (and gnus-newsrc-alist gnus-active-hashtb (not rawfile)))))
     ;; Clear some variables to re-initialize news information.
-    (if init (setq gnus-newsrc-alist nil gnus-active-hashtb nil))
+    (if init (setq gnus-newsrc-alist nil 
+                  gnus-active-hashtb nil))
 
     ;; Read the newsrc file and create `gnus-newsrc-hashtb'.
     (if init (gnus-read-newsrc-file rawfile))
@@ -11680,7 +11791,8 @@ If LEVEL is non-nil, the news will be set up at level LEVEL."
        (gnus-read-active-file)
       (setq gnus-active-hashtb (make-vector 4095 0)))
 
-    (and init gnus-use-dribble-file (gnus-dribble-read-file))
+    ;; Possibly eval the dribble file.
+    (and init gnus-use-dribble-file (gnus-dribble-eval-file))
 
     ;; Find the number of unread articles in each non-dead group.
     (gnus-get-unread-articles (or level (1+ gnus-level-subscribed)))
@@ -11704,6 +11816,7 @@ The `-n' option line from .newsrc is respected."
          (gnus-ask-server-for-new-groups)
        (let ((groups 0)
              group new-newsgroups)
+         (gnus-message 5 "Checking for new newsgroups...")
          (or gnus-have-read-active-file (gnus-read-active-file))
          (setq gnus-newsrc-last-checked-date (current-time-string))
          (if (not gnus-killed-hashtb) (gnus-make-hashtable-from-killed))
@@ -11735,7 +11848,8 @@ The `-n' option line from .newsrc is respected."
          ;; Suggested by Per Abrahamsen <amanda@iesd.auc.dk>.
          (if (> groups 0)
              (gnus-message 6 "%d new newsgroup%s arrived." 
-                           groups (if (> groups 1) "s have" " has")))))))
+                           groups (if (> groups 1) "s have" " has"))
+           (gnus-message 6 "No new newsgroups."))))))
 
 (defun gnus-matches-options-n (group)
   ;; Returns `subscribe' if the group is to be uncoditionally
@@ -12079,7 +12193,7 @@ newsgroup."
                     (gnus-close-group group))))
                
        ;; These groups are native or secondary. 
-       (if (and (not gnus-have-read-active-file)
+       (if (and (not gnus-read-active-file)
                 (<= (nth 1 info) level))
            (setq active (gnus-activate-newsgroup (car info)))))
       
@@ -12148,67 +12262,67 @@ newsgroup."
     ;; Modify the list of read articles according to what articles 
     ;; are available; then tally the unread articles and add the
     ;; number to the group hash table entry.
-    (cond ((zerop (cdr active))
-          (setq num 0))
-         ((not range)
-          (setq num (- (1+ (cdr active)) (car active))))
-         ((not (listp (cdr range)))
-          ;; Fix a single (num . num) range according to the
-          ;; active hash table.
-          ;; Fix by Carsten Bormann <cabo@Informatik.Uni-Bremen.DE>.
-          (and (< (cdr range) (car active)) (setcdr range (1- (car active))))
-          (and (> (cdr range) (cdr active)) (setcdr range (cdr active)))
-          ;; Compute number of unread articles.
-          (setq num (max 0 (- (cdr active) 
-                              (- (1+ (cdr range)) (car range))))))
-         (t
-          ;; The read list is a list of ranges. Fix them according to
-          ;; the active hash table.
-          ;; First peel off any elements that are below the lower
-          ;; active limit. 
-          (while (and (cdr range) 
-                      (>= (car active) 
-                          (or (and (atom (car (cdr range))) (car (cdr range)))
-                              (car (car (cdr range))))))
-            (if (numberp (car range))
-                (setcar range 
-                        (cons (car range) 
-                              (or (and (numberp (car (cdr range)))
-                                       (car (cdr range))) 
-                                  (cdr (car (cdr range))))))
-              (setcdr (car range) 
-                      (or (and (numberp (nth 1 range)) (nth 1 range))
-                          (cdr (car (cdr range))))))
-            (setcdr range (cdr (cdr range))))
-          ;; Adjust the first element to be the same as the lower limit. 
-          (if (and (not (atom (car range))) 
-                   (< (cdr (car range)) (car active)))
-              (setcdr (car range) (1- (car active))))
-          ;; Then we want to peel off any elements that are higher
-          ;; than the upper active limit.  
-          (let ((srange range))
-            ;; Go past all legal elements.
-            (while (and (cdr srange) 
-                        (<= (or (and (atom (car (cdr srange)))
-                                     (car (cdr srange)))
-                                (car (car (cdr srange)))) (cdr active)))
-              (setq srange (cdr srange)))
-            (if (cdr srange)
-                ;; Nuke all remaining illegal elements.
-                (setcdr srange nil))
-
-            ;; Adjust the final element.
-            (if (and (not (atom (car srange)))
-                     (> (cdr (car srange)) (cdr active)))
-                (setcdr (car srange) (cdr active))))
-          ;; Compute the number of unread articles.
-          (while range
-            (setq num (+ num (- (1+ (or (and (atom (car range)) (car range))
-                                        (cdr (car range))))
-                                (or (and (atom (car range)) (car range))
-                                    (car (car range))))))
-            (setq range (cdr range)))
-          (setq num (max 0 (- (cdr active) num)))))
+    (cond 
+     ((zerop (cdr active))
+      (setq num 0))
+     ((not range)
+      (setq num (- (1+ (cdr active)) (car active))))
+     ((not (listp (cdr range)))
+      ;; Fix a single (num . num) range according to the
+      ;; active hash table.
+      ;; Fix by Carsten Bormann <cabo@Informatik.Uni-Bremen.DE>.
+      (and (< (cdr range) (car active)) (setcdr range (1- (car active))))
+      (and (> (cdr range) (cdr active)) (setcdr range (cdr active)))
+      ;; Compute number of unread articles.
+      (setq num (max 0 (- (cdr active) (- (1+ (cdr range)) (car range))))))
+     (t
+      ;; The read list is a list of ranges. Fix them according to
+      ;; the active hash table.
+      ;; First peel off any elements that are below the lower
+      ;; active limit. 
+      (while (and (cdr range) 
+                 (>= (car active) 
+                     (or (and (atom (car (cdr range))) (car (cdr range)))
+                         (car (car (cdr range))))))
+       (if (numberp (car range))
+           (setcar range 
+                   (cons (car range) 
+                         (or (and (numberp (car (cdr range)))
+                                  (car (cdr range))) 
+                             (cdr (car (cdr range))))))
+         (setcdr (car range) 
+                 (or (and (numberp (nth 1 range)) (nth 1 range))
+                     (cdr (car (cdr range))))))
+       (setcdr range (cdr (cdr range))))
+      ;; Adjust the first element to be the same as the lower limit. 
+      (if (and (not (atom (car range))) 
+              (< (cdr (car range)) (car active)))
+         (setcdr (car range) (1- (car active))))
+      ;; Then we want to peel off any elements that are higher
+      ;; than the upper active limit.  
+      (let ((srange range))
+       ;; Go past all legal elements.
+       (while (and (cdr srange) 
+                   (<= (or (and (atom (car (cdr srange)))
+                                (car (cdr srange)))
+                           (car (car (cdr srange)))) (cdr active)))
+         (setq srange (cdr srange)))
+       (if (cdr srange)
+           ;; Nuke all remaining illegal elements.
+           (setcdr srange nil))
+
+       ;; Adjust the final element.
+       (if (and (not (atom (car srange)))
+                (> (cdr (car srange)) (cdr active)))
+           (setcdr (car srange) (cdr active))))
+      ;; Compute the number of unread articles.
+      (while range
+       (setq num (+ num (- (1+ (or (and (atom (car range)) (car range))
+                                   (cdr (car range))))
+                           (or (and (atom (car range)) (car range))
+                               (car (car range))))))
+       (setq range (cdr range)))
+      (setq num (max 0 (- (cdr active) num)))))
     (and info
         (progn
           (and (assq 'tick marked)
@@ -12380,7 +12494,9 @@ Returns whether the updating was successful."
                                (car (car methods)))
                  (ding))
              (gnus-active-to-gnus-format (car methods))
-             (setq gnus-have-read-active-file t)
+             ;; We mark this active file as read.
+             (setq gnus-have-read-active-file
+                   (cons (car methods) gnus-have-read-active-file))
              (gnus-message 5 "%sdone" mesg)))))
        (setq methods (cdr methods))))))
 
@@ -12395,7 +12511,8 @@ Returns whether the updating was successful."
                            (if (equal method gnus-select-method)
                                (gnus-make-hashtable 
                                 (count-lines (point-min) (point-max)))
-                             (gnus-make-hashtable 4096)))))))
+                             (gnus-make-hashtable 4096))))))
+       (flag-hashtb (gnus-make-hashtable 60)))
     ;; Delete unnecessary lines.
     (goto-char (point-min))
     (while (search-forward "\nto." nil t)
@@ -12429,7 +12546,13 @@ Returns whether the updating was successful."
                  (narrow-to-region (point) (gnus-point-at-eol))
                  (setq group (let ((obarray hashtb)) (read cur)))
                  (if (and (numberp (setq max (read cur)))
-                          (numberp (setq min (read cur))))
+                          (numberp (setq min (read cur)))
+                          (progn 
+                            (skip-chars-forward " ")
+                            (not
+                             (or (= (following-char) ?=)
+                                 (= (following-char) ?x)
+                                 (= (following-char) ?j)))))
                      (set group (cons min max))
                    (set group nil))
                  ;; Enter moderated groups into a list.
@@ -12447,10 +12570,16 @@ Returns whether the updating was successful."
              (progn
                (narrow-to-region (point) (gnus-point-at-eol))
                ;; group gets set to a symbol interned in the hash table
-               ;; (what a hack!!)
+               ;; (what a hack!!) - jwz
                (setq group (let ((obarray hashtb)) (read cur)))
                (if (and (numberp (setq max (read cur)))
-                        (numberp (setq min (read cur))))
+                        (numberp (setq min (read cur)))
+                        (progn 
+                          (skip-chars-forward " ")
+                          (not
+                           (or (= (following-char) ?=)
+                               (= (following-char) ?x)
+                               (= (following-char) ?j)))))
                    (set group (cons min max))
                  (set group nil)))
            (error 
index a5521e5..02eda05 100644 (file)
@@ -55,6 +55,7 @@
 (defvar nnbabyl-current-group nil)
 (defvar nnbabyl-status-string "")
 (defvar nnbabyl-group-alist nil)
+(defvar nnbabyl-active-timestamp nil)
 
 \f
 
             (save-buffer)))
       (if incomings (run-hooks 'nnmail-read-incoming-hook))
       (while incomings
+       (setq incoming (car incomings))
        (and nnmail-delete-incoming
+            (file-exists-p incoming) 
             (file-writable-p incoming) 
             (delete-file incoming))
        (setq incomings (cdr incomings))))))
diff --git a/lisp/nndigest.el b/lisp/nndigest.el
deleted file mode 100644 (file)
index a77b391..0000000
+++ /dev/null
@@ -1,206 +0,0 @@
-;;; nndigest.el --- digest access for Gnus
-;; Copyright (C) 1995 Free Software Foundation, Inc.
-
-;; Author: Lars Magne Ingebrigtsen <larsi@ifi.uio.no>
-;; Keywords: news
-
-;; This file is part of GNU Emacs.
-
-;; GNU Emacs is free software; you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 2, or (at your option)
-;; any later version.
-
-;; GNU Emacs is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-;; GNU General Public License for more details.
-
-;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs; see the file COPYING.  If not, write to
-;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
-;;; Commentary:
-
-;;; Code:
-
-(require 'nnheader)
-
-\f
-
-(defconst nndigest-version "nndigest 0.0"
-  "nndigest version.")
-
-(defvar nndigest-current-buffer nil
-  "Current digest "group" buffer.")
-
-(defvar nndigest-status-string "")
-
-(defvar nndigest-group-alist nil)
-
-(defconst nndigest-separator "------------------------------[\n \t]*\n[^ ]+: ")
-
-\f
-
-;;; Interface functions.
-
-(defun nndigest-retrieve-headers (sequence &optional newsgroup server)
-  "Retrieve the headers for the articles in SEQUENCE.
-Newsgroup must be selected before calling this function."
-  (save-excursion
-    (set-buffer nntp-server-buffer)
-    (erase-buffer)
-    (let ((file nil)
-         (number (length sequence))
-         (count 0)
-         range
-         beg article)
-      (nndigest-possibly-change-buffer newsgroup)
-      (while sequence
-       (setq article (car sequence))
-       (if (setq range (nndigest-narrow-to-article article))
-           (progn
-             (insert (format "221 %d Article retrieved.\n" article))
-             (setq beg (point))
-             (insert-buffer-substring nndigest-current-buffer 
-                                      (car range) (cdr range))
-             (goto-char beg)
-             (if (search-forward "\n\n" nil t)
-                 (forward-char -1)
-               (goto-char (point-max))
-               (insert "\n\n"))
-             (insert (format "Lines: %d\n" (count-lines (point) (point-max))))
-             (insert ".\n")
-             (delete-region (point) (point-max))))
-       (setq sequence (cdr sequence)))
-
-      ;; Fold continuation lines.
-      (goto-char 1)
-      (while (re-search-forward "\\(\r?\n[ \t]+\\)+" nil t)
-       (replace-match " " t t))
-      'headers)))
-
-(defun nndigest-open-server (host &optional service)
-  "Open news server on HOST."
-  (setq nndigest-status-string "")
-  (nnheader-init-server-buffer))
-
-(defun nndigest-close-server (&optional server)
-  "Close news server."
-  t)
-
-(defun nndigest-server-opened (&optional server)
-  "Return server process status, T or NIL."
-  (and nntp-server-buffer
-       (get-buffer nntp-server-buffer)))
-
-(defun nndigest-status-message ()
-  "Return server status response as string."
-  nndigest-status-string)
-
-(defun nndigest-request-article (id &optional newsgroup server buffer)
-  "Select article by message ID (or number)."
-  (nndigest-possibly-change-buffer newsgroup)
-  (let ((range (nndigest-narrow-to-article id)))
-    (and range
-        (save-excursion
-          (set-buffer (or buffer nntp-server-buffer))
-          (erase-buffer)
-          (insert-buffer-substring 
-           nndigest-current-buffer (car range) (cdr range))
-          t))))
-
-(defun nndigest-request-group (group &optional server dont-check)
-  "Select news GROUP."
-  (let ((entry (assoc group nndigest-group-alist)))
-    (and entry (setq nndigest-group-alist (delq entry nndigest-group-alist))))
-  (let ((buffer (get-buffer-create (concat " *nndigest " group "*"))))
-    (setq nndigest-group-alist 
-         (cons (cons group buffer) nndigest-group-alist))
-    (save-excursion
-      (set-buffer buffer)
-      (erase-buffer)
-      (insert-buffer-substring server)))
-  (nndigest-possibly-change-buffer group)
-  (let ((num 0))
-    (save-excursion
-      (set-buffer nndigest-current-buffer)
-      (widen)
-      (goto-char (point-min))
-      (while (re-search-forward nndigest-separator nil t)
-       (setq num (1+ num)))
-      (set-buffer nntp-server-buffer)
-      (erase-buffer)
-      (insert (format "211 %d %d %d %s\n" num 1 num group))
-      t)))
-
-(defun nndigest-close-group (group &optional server)
-  (nndigest-possibly-change-buffer group)
-  (kill-buffer nndigest-current-buffer)
-  (setq nndigest-group-alist (delq (assoc group nndigest-group-alist)
-                                  nndigest-group-alist))
-  (setq nndigest-current-buffer nil)
-  t)
-
-(defun nndigest-request-list (&optional server)
-  "List active newsgoups."
-  (save-excursion
-    (set-buffer nntp-server-buffer)
-    (erase-buffer)
-    t))
-
-(defun nndigest-request-newgroups (date &optional server)
-  "List groups created after DATE."
-  (save-excursion
-    (set-buffer nntp-server-buffer)
-    (erase-buffer)
-    t))
-
-(defun nndigest-request-list-newsgroups (&optional server)
-  "List newsgroups (defined in NNTP2)."
-  (save-excursion
-    (set-buffer nntp-server-buffer)
-    (erase-buffer)
-    t))
-
-(defun nndigest-request-post (&optional server)
-  "Post a new news in current buffer."
-  (mail-send-and-exit nil))
-
-(fset 'nndigest-request-post-buffer 'nnmail-request-post-buffer)
-
-\f
-
-;;; Internal functions
-
-(defun nndigest-possibly-change-buffer (group)
-  (and group
-       (not (equal (cdr (assoc group nndigest-group-alist)) 
-                  nndigest-current-buffer))
-       (setq nndigest-current-buffer 
-            (cdr (assoc group nndigest-group-alist)))))
-
-(defun nndigest-narrow-to-article (article) 
-  (save-excursion
-    (set-buffer nndigest-current-buffer)
-    (widen)
-    (goto-char (point-min))
-    (while (and (not (zerop article))
-               (re-search-forward nndigest-separator nil t))
-      (setq article (1- article)))
-    (if (zerop article)
-       (progn
-         (goto-char (match-end 0))
-         (beginning-of-line)
-         (narrow-to-region 
-          (point)
-          (or (and (re-search-forward nndigest-separator nil t)
-                   (match-beginning 0))
-              (point-max)))
-         (cons (point-min) (point-max)))
-      nil)))
-      
-
-(provide 'nndigest)
-
-;;; nndigest.el ends here
index ab66130..5554628 100644 (file)
 (defvar nndoc-article-type 'mbox
   "*Type of the file - one of `mbox', `babyl' or `digest'.")
 
+(defvar nndoc-digest-type 'traditional
+  "Type of the last digest.  Auto-detected from the article header.
+Possible values:
+  `traditional' -- the \"lots of dashes\" (30+) rules used;
+                   we currently also do unconditional RFC 934 unquoting.
+  `rfc1341' -- RFC 1341 digest (MIME, unique boundary, no quoting).")
+
 (defconst nndoc-type-to-regexp
   (list (list 'mbox 
              (concat "^" rmail-unix-mail-delimiter)
          nil
        (nndoc-insert-article article)
        ;; Unquote quoted non-separators in digests.
-       (if (eq nndoc-article-type 'digest)
+       (if (and (eq nndoc-article-type 'digest)
+                (eq nndoc-digest-type 'traditional))
            (progn
              (goto-char (point-min))
              (while (re-search-forward "^- -"nil t)
       (save-excursion
        (set-buffer nndoc-current-buffer)
        (goto-char (point-min))
-       (and
-        (re-search-forward
-         (concat "\n\n\\|^Content-Type: multipart/digest;[ \t\n]*[ \t]"
-                 "boundary=\"\\([^\"\n]*[^\" \t\n]\\)\"")
-         nil t)
-        (match-beginning 1)
-        (setq boundary-id (buffer-substring-no-properties (match-beginning 1)
-                                                          (match-end 1))
-              b-delimiter       (concat "\n--" boundary-id "[\n \t]+")
-              nndoc-article-begin b-delimiter ; Too strict: "[ \t]*$"
-              nndoc-article-end (concat "\n--" boundary-id
-                                        "\\(--\\)?[\n \t]+")
-              nndoc-first-article b-delimiter ; ^end-of-file ends article too.
-              nndoc-end-of-file (concat "\n--" boundary-id "--[ \t]*$")))))))
+       (if (and
+            (re-search-forward
+             (concat "\n\n\\|^Content-Type: multipart/digest;[ \t\n]*[ \t]"
+                     "boundary=\"\\([^\"\n]*[^\" \t\n]\\)\"")
+             nil t)
+            (match-beginning 1))
+           (setq nndoc-digest-type 'rfc1341
+                 boundary-id (buffer-substring-no-properties
+                              (match-beginning 1) (match-end 1))
+                 b-delimiter       (concat "\n--" boundary-id "[\n \t]+")
+                 nndoc-article-begin b-delimiter ; Too strict: "[ \t]*$"
+                 nndoc-article-end (concat "\n--" boundary-id
+                                           "\\(--\\)?[\n \t]+")
+                 nndoc-first-article b-delimiter ; ^eof ends article too.
+                 nndoc-end-of-file (concat "\n--" boundary-id "--[ \t]*$"))
+         (setq nndoc-digest-type 'traditional))))))
 
 (defun nndoc-forward-article (n)
   (while (and (> n 0)
index 973fab5..0453b29 100644 (file)
                      nneething-group-alist)))))))
 
 (defun nneething-map-file ()
+  ;; We make sure that the .neething directory exists. 
+  (make-directory nneething-map-file-directory 'parents)
   ;; We store it in a special directory under the user's home dir.
   (concat (file-name-as-directory nneething-map-file-directory)
          nneething-group nneething-map-file))
index 4aef847..840d253 100644 (file)
@@ -280,7 +280,8 @@ such things as moving mail.  All buffers always get killed upon server close.")
   (or (assoc group nnfolder-group-alist)
       (let (active)
        (setq nnfolder-group-alist 
-             (cons (list group (setq active (cons 0 0))) nnfolder-group-alist))
+             (cons (list group (setq active (cons 0 0)))
+                   nnfolder-group-alist))
        (nnfolder-possibly-change-group group)
        (nnmail-save-active nnfolder-group-alist nnfolder-active-file)))
   t)
@@ -291,13 +292,6 @@ such things as moving mail.  All buffers always get killed upon server close.")
     (nnmail-find-file nnfolder-active-file)
     (setq nnfolder-group-alist (nnmail-get-active))))
 
-;;    (or nnfolder-group-alist
-;;     (nnmail-find-file nnfolder-active-file)
-;;     (progn
-;;       (setq nnfolder-group-alist (nnmail-get-active))
-;;       (nnmail-save-active nnfolder-group-alist nnfolder-active-file)
-;;       (nnmail-find-file nnfolder-active-file)))))
-
 (defun nnfolder-request-newgroups (date &optional server)
   (nnfolder-request-list server))
 
@@ -550,15 +544,13 @@ such things as moving mail.  All buffers always get killed upon server close.")
 (defun nnfolder-possibly-activate-groups (&optional group)
   (save-excursion
     ;; If we're looking for the activation of a specific group, find out
-    ;; it's real name and switch to it.
+    ;; its real name and switch to it.
     (if group (nnfolder-possibly-change-group group))
     ;; If the group alist isn't active, activate it now.
-    (or nnfolder-group-alist
-       (nnmail-activate 'nnfolder))))
+    (nnmail-activate 'nnfolder)))
 
 (defun nnfolder-active-number (group)
   (save-excursion 
-    (nnfolder-possibly-activate-groups group)
     ;; Find the next article number in GROUP.
     (let ((active (car (cdr (assoc group nnfolder-group-alist)))))
       (if active
@@ -568,7 +560,9 @@ such things as moving mail.  All buffers always get killed upon server close.")
        ;; a hat, but I don't know...
        (setq nnfolder-group-alist (cons (list group (setq active (cons 1 1)))
                                         nnfolder-group-alist)))
-      (cdr active))))
+      (cdr active))
+    (nnfolder-possibly-activate-groups group)))
+
 
 ;; This method has a problem if you've accidentally let the active list get
 ;; out of sync with the files.  This could happen, say, if you've
@@ -696,9 +690,11 @@ such things as moving mail.  All buffers always get killed upon server close.")
              (and (buffer-modified-p) (save-buffer)))
            (setq bufs (cdr bufs)))))
       (while incomings
+       (setq incoming (car incomings))
        (and 
         nnmail-delete-incoming
         (file-writable-p incoming)
+        (file-exists-p incoming)
         (delete-file incoming))
        (setq incomings (cdr incomings))))))
 
index 6b19b5a..5493b1d 100644 (file)
@@ -234,10 +234,14 @@ Finds out what articles are to be part of the nnkiboze groups."
     (save-excursion
       (set-buffer (setq nov-buffer (find-file-noselect nov-file)))
       (buffer-disable-undo (current-buffer)))
+    ;; Go through the active hashtb and add new all groups that match the 
+    ;; kiboze regexp.
     (mapatoms
      (lambda (group)
-       (if (and (string-match regexp (setq gname (symbol-name group)))
-               (not (assoc gname nnkiboze-newsrc)))
+       (if (and (string-match regexp (setq gname (symbol-name group))) ; Match
+               (not (assoc gname nnkiboze-newsrc)) ; It isn't registered
+               (numberp (car (symbol-value group))) ; It is active
+               (not (string-match "^nnkiboze:" gname))) ; Exclude kibozes
           (setq nnkiboze-newsrc 
                 (cons (cons gname (1- (car (symbol-value group))))
                       nnkiboze-newsrc))))
index 41c79ce..111683b 100644 (file)
@@ -194,6 +194,17 @@ Example:
   "*If non-nil, the mail backends will delete incoming files after splitting.
 This is nil by default for reasons of security.")
 
+(defvar nnmail-message-id-cache-length 1000
+  "*The approximate number of Message-IDs nnmail will keep in its cache.
+If this variable is nil, no checking on duplicate messages will be
+perfomed.")
+
+(defvar nnmail-message-id-cache-file "~/.nnmail-cache"
+  "*The file name of the nnmail Message-ID cache.")
+
+(defvar nnmail-delete-duplicates nil
+  "*If non-nil, nnmail will delete any duplicate mails it sees.")
+
 \f
 
 (defconst nnmail-version "nnml 0.0"
@@ -423,15 +434,17 @@ nn*-request-list should have been called before calling this function."
                                 (buffer-substring (match-beginning 2)
                                                   (match-end 2)))))
                    group-assoc))))
-    ;; In addition, add all groups mentioned in `nnmail-split-methods'.
-    (let ((methods (and (not (symbolp nnmail-split-methods))
-                       nnmail-split-methods)))
-      (while methods
-       (if (not (assoc (car (car methods)) group-assoc))
-           (setq group-assoc
-                 (cons (list (car (car methods)) (cons 1 0)) 
-                       group-assoc)))
-       (setq methods (cdr methods))))
+
+;;    ;; In addition, add all groups mentioned in `nnmail-split-methods'.
+;;    (let ((methods (and (not (symbolp nnmail-split-methods))
+;;                     nnmail-split-methods)))
+;;      (while methods
+;;     (if (not (assoc (car (car methods)) group-assoc))
+;;         (setq group-assoc
+;;               (cons (list (car (car methods)) (cons 1 0)) 
+;;                     group-assoc)))
+;;     (setq methods (cdr methods)))
+    
     group-assoc))
 
 (defun nnmail-save-active (group-assoc file-name)
@@ -475,8 +488,11 @@ FUNC will be called with the buffer narrowed to each mail."
                                       (not nnmail-resplit-incoming))
                                  (list (list group ""))
                                nnmail-split-methods))
-       start end content-length do-search)
+       start end content-length do-search message-id)
     (save-excursion
+      ;; Open the message-id cache.
+      (nnmail-cache-open)
+      ;; Insert the incoming file.
       (set-buffer (get-buffer-create " *nnmail incoming*"))
       (buffer-disable-undo (current-buffer))
       (erase-buffer)
@@ -492,6 +508,15 @@ FUNC will be called with the buffer narrowed to each mail."
            ;; Skip all the headers in case there are more "From "s...
            (if (not (search-forward "\n\n" nil t))
                (forward-line 1))
+           ;; Find the Message-ID header.
+           (save-excursion
+             (if (re-search-backward "^Message-ID:[ \t]*\\(<[^>]*>\\)" nil t)
+                 (setq message-id (buffer-substring (match-beginning 1)
+                                                    (match-end 1)))
+               ;; There is no Message-ID here, so we create one.
+               (forward-line -1)
+               (insert "Message-ID: " (setq message-id (nnmail-message-id))
+                       "\n")))
            ;; Look for a Content-Length header.
            (if (not (save-excursion
                       (and (re-search-backward 
@@ -506,13 +531,12 @@ FUNC will be called with the buffer narrowed to each mail."
                            ;; a (possibly) faulty header.
                            (progn (insert "X-") t))))
                (setq do-search t)
-             (if (save-excursion
-                   (condition-case nil
-                       (forward-char content-length)
-                     (end-of-buffer nil))
-                   (looking-at delim))
+             (if (or (= (+ (point) content-length) (point-max))
+                     (save-excursion
+                       (goto-char (+ (point) content-length))
+                       (looking-at delim)))
                  (progn
-                   (forward-char content-length)
+                   (goto-char (+ (point) content-length))
                    (setq do-search nil))
                (setq do-search t)))
            ;; Go to the beginning of the next article - or to the end
@@ -525,9 +549,15 @@ FUNC will be called with the buffer narrowed to each mail."
              (save-restriction
                (narrow-to-region start (point))
                (goto-char (point-min))
-               (funcall func)
+               ;; If this is a duplicate message, then we do not save it.
+               (if (nnmail-cache-id-exists-p message-id)
+                   (delete-region (point-min) (point-max))
+                 (nnmail-cache-insert message-id)
+                 (funcall func))
                (setq end (point-max))))
            (goto-char end)))
+      ;; Close the message-id cache.
+      (nnmail-cache-close)
       (if dont-kill
          (current-buffer)
        (kill-buffer (current-buffer))))))
@@ -716,12 +746,115 @@ See the documentation for the variable `nnmail-split-fancy' for documentation."
 ;; If FORCE, re-read the active file even if the backend is 
 ;; already activated.
 (defun nnmail-activate (backend &optional force)
-  (if (or (not (symbol-value (intern (format "%s-group-alist" backend))))
-         force)
-      (save-excursion
-       (funcall (intern (format "%s-request-list" backend)))
-       (set (intern (format "%s-group-alist" backend)) (nnmail-get-active))))
-  t)
+  (let (file timestamp file-time)
+    (if (or (not (symbol-value (intern (format "%s-group-alist" backend))))
+           force
+           (and (setq file (condition-case ()
+                               (symbol-value (intern (format "%s-active-file" 
+                                                             backend)))
+                             (error nil)))
+                (setq file-time (nth 5 (file-attributes file)))
+                (or (not
+                     (setq timestamp
+                           (condition-case ()
+                               (symbol-value (intern
+                                              (format "%s-active-timestamp" 
+                                                      backend)))
+                             (error 'none))))
+                    (not (consp timestamp))
+                    (equal timestamp '(0 0))
+                    (> (nth 0 file-time) (nth 0 timestamp))
+                    (and (= (nth 0 file-time) (nth 0 timestamp))
+                         (> (nth 1 file-time) (nth 1 timestamp))))))
+       (save-excursion
+         (or (eq timestamp 'none)
+             (set (intern (format "%s-active-timestamp" backend)) file-time))
+         (funcall (intern (format "%s-request-list" backend)))
+         (set (intern (format "%s-group-alist" backend)) 
+              (nnmail-get-active))))
+    t))
+
+(defun nnmail-message-id ()
+  (concat "<" (nnmail-unique-id) "@totally-fudged-out-message-id>"))
+
+(defvar nnmail-unique-id-char nil)
+
+(defun nnmail-number-base36 (num len)
+  (if (if (< len 0) (<= num 0) (= len 0))
+      ""
+    (concat (nnmail-number-base36 (/ num 36) (1- len))
+           (char-to-string (aref "zyxwvutsrqponmlkjihgfedcba9876543210"
+                                 (% num 36))))))
+
+(defun nnmail-unique-id ()
+  (setq nnmail-unique-id-char
+       (% (1+ (or nnmail-unique-id-char (logand (random t) (1- (lsh 1 20)))))
+          ;; (current-time) returns 16-bit ints,
+          ;; and 2^16*25 just fits into 4 digits i base 36.
+          (* 25 25)))
+  (let ((tm (if (fboundp 'current-time)
+               (current-time) '(12191 46742 287898))))
+    (concat
+     (nnmail-number-base36 (+ (car   tm) 
+                             (lsh (% nnmail-unique-id-char 25) 16)) 4)
+     (nnmail-number-base36 (+ (nth 1 tm) 
+                             (lsh (/ nnmail-unique-id-char 25) 16)) 4))))
+
+;;;
+;;; nnmail duplicate handling
+;;;
+
+(defvar nnmail-cache-buffer nil)
+
+(defun nnmail-cache-open ()
+  (if (or (not nnmail-delete-duplicates)
+         (and nnmail-cache-buffer
+              (buffer-name nnmail-cache-buffer)))
+      () ; The buffer is open.
+    (save-excursion
+      (set-buffer 
+       (setq nnmail-cache-buffer 
+            (get-buffer-create " *nnmail message-id cache*")))
+      (buffer-disable-undo (current-buffer))
+      (and (file-exists-p nnmail-message-id-cache-file)
+          (insert-file-contents nnmail-message-id-cache-file))
+      (current-buffer))))
+
+(defun nnmail-cache-close ()
+  (if (or (not nnmail-cache-buffer)
+         (not nnmail-delete-duplicates)
+         (not (buffer-name nnmail-cache-buffer))
+         (not (buffer-modified-p nnmail-cache-buffer)))
+      () ; The buffer is closed.
+    (save-excursion
+      (set-buffer nnmail-cache-buffer)
+      ;; Weed out the excess number of Message-IDs.
+      (goto-char (point-max))
+      (and (search-backward "\n" nil t nnmail-message-id-cache-length)
+          (progn
+            (beginning-of-line)
+            (delete-region (point-min) (point))))
+      ;; Save the buffer.
+      (or (file-exists-p (file-name-directory nnmail-message-id-cache-file))
+         (make-directory (file-name-directory nnmail-message-id-cache-file)
+                         t))
+      (write-region (point-min) (point-max)
+                   nnmail-message-id-cache-file nil 'silent)
+      (set-buffer-modified-p nil))))
+
+(defun nnmail-cache-insert (id)
+  (and nnmail-delete-duplicates
+       (save-excursion
+        (set-buffer nnmail-cache-buffer)
+        (goto-char (point-max))
+        (insert id "\n"))))
+
+(defun nnmail-cache-id-exists-p (id)
+  (and nnmail-delete-duplicates
+       (save-excursion
+        (set-buffer nnmail-cache-buffer)
+        (goto-char (point-max))
+        (search-backward id nil t))))
 
 
 (provide 'nnmail)
index 68279e4..d4cdae7 100644 (file)
@@ -57,6 +57,7 @@
 (defvar nnmbox-status-string "")
 
 (defvar nnmbox-group-alist nil)
+(defvar nnmbox-active-timestamp nil)
 
 \f
 
             (save-buffer)))
       (if incomings (run-hooks 'nnmail-read-incoming-hook))
       (while incomings
+       (setq incoming (car incomings))
        (and nnmail-delete-incoming
+            (file-exists-p incoming) 
             (file-writable-p incoming) 
             (delete-file incoming))
        (setq incomings (cdr incomings))))))
index dd92ec3..1bfef27 100644 (file)
                                             (car dir))
                                      group))
                    (insert (format "211 0 1 0 %s\n" group))))))
-         t))))
+         t)
+      (setq nnmh-status-string "No such group")
+      nil)))
 
 (defun nnmh-request-list (&optional server dir)
   (or dir
 (defun nnmh-active-number (group)
   "Compute the next article number in GROUP."
   (let ((active (car (cdr (assoc group nnmh-group-alist)))))
+    ;; The group wasn't known to nnmh, so we just create an active
+    ;; entry for it.   
+    (or active
+       (progn
+         (setq active (cons 1 0))
+         (setq nnmh-group-alist (cons (list group active) nnmh-group-alist))))
     (setcdr active (1+ (cdr active)))
     (while (file-exists-p
            (concat (nnmh-article-pathname group nnmh-directory)
       (if incoming 
          (message "nnmh: Reading incoming mail...done"))
       (while incomings
+       (setq incoming (car incomings))
        (and nnmail-delete-incoming
+            (file-exists-p incoming)
             (file-writable-p incoming)
             (delete-file incoming))
        (setq incomings (cdr incomings))))))
index 91d7748..3e64133 100644 (file)
@@ -191,23 +191,17 @@ all. This may very well take some time.")
     (if dont-check 
        t
       (nnml-get-new-mail group)
-      (let ((timestamp (nth 5 (file-attributes nnml-active-file))))
-       (if (or (not nnml-active-timestamp)
-               (> (nth 0 timestamp) (nth 0 nnml-active-timestamp))
-               (> (nth 1 timestamp) (nth 1 nnml-active-timestamp)))
-           (progn
-             (setq nnml-active-timestamp timestamp)
-             (nnmail-activate 'nnml 'force)))
-       (let ((active (nth 1 (assoc group nnml-group-alist))))
-         (save-excursion
-           (set-buffer nntp-server-buffer)
-           (erase-buffer)
-           (if (not active)
-               ()
-             (insert (format "211 %d %d %d %s\n" 
-                             (max (1+ (- (cdr active) (car active))) 0)
-                             (car active) (cdr active) group))
-             t)))))))
+      (nnmail-activate 'nnml)
+      (let ((active (nth 1 (assoc group nnml-group-alist))))
+       (save-excursion
+         (set-buffer nntp-server-buffer)
+         (erase-buffer)
+         (if (not active)
+             ()
+           (insert (format "211 %d %d %d %s\n" 
+                           (max (1+ (- (cdr active) (car active))) 0)
+                           (car active) (cdr active) group))
+           t))))))
 
 (defun nnml-close-group (group &optional server)
   t)
@@ -476,6 +470,8 @@ all. This may very well take some time.")
 (defun nnml-active-number (group)
   "Compute the next article number in GROUP."
   (let ((active (car (cdr (assoc group nnml-group-alist)))))
+    ;; The group wasn't known to nnml, so we just create an active
+    ;; entry for it.   
     (or active
        (progn
          (setq active (cons 1 0))
@@ -495,8 +491,7 @@ all. This may very well take some time.")
     (if (or (not nnml-get-new-mail) (not nnmail-spool-file))
        ()
       ;; We first activate all the groups.
-      (if (or (not group) (not nnml-group-alist))
-         (nnmail-activate 'nnml))
+      (if (not group) (nnmail-activate 'nnml))
       ;; The we go through all the existing spool files and split the
       ;; mail from each.
       (while spools
@@ -522,7 +517,9 @@ all. This may very well take some time.")
            (and gnus-verbose-backends
                 (message "nnml: Reading incoming mail...done"))))
       (while incomings
+       (setq incoming (car incomings))
        (and nnmail-delete-incoming
+            (file-exists-p incoming)
             (file-writable-p incoming)
             (delete-file incoming))
        (setq incomings (cdr incomings))))))
index 360888f..c2d595d 100644 (file)
@@ -199,7 +199,6 @@ instead call function `nntp-status-message' to get status message.")
    '(nntp-status-string nil)
    '(nntp-server-xover try)
    '(nntp-server-list-active-group try)
-   '(nntp-timeout-servers nil)
    '(nntp-current-group "")))
 
 \f
@@ -372,7 +371,8 @@ instead call function `nntp-status-message' to get status message.")
        ;; We cannot send QUIT command unless the process is running.
        (if (nntp-server-opened)
            (nntp-send-command nil "QUIT")))
-    (nntp-close-server-internal server)))
+    (nntp-close-server-internal server)
+    (setq nntp-timeout-servers (delete server nntp-timeout-servers))))
 
 (defalias 'nntp-request-quit (symbol-function 'nntp-close-server))
 
@@ -384,6 +384,10 @@ instead call function `nntp-status-message' to get status message.")
           (delete-process nntp-async-process)
           (and (get-buffer nntp-async-buffer)
                (kill-buffer nntp-async-buffer))))
+    (while nntp-async-group-alist
+      (and (nth 3 (car nntp-async-group-alist))
+          (delete-process (nth 3 (car nntp-async-group-alist))))
+      (setq nntp-async-group-alist (cdr nntp-async-group-alist)))
     (while nntp-server-alist
       (and 
        (setq proc (nth 1 (assq 'nntp-server-process (car nntp-server-alist))))
@@ -529,6 +533,7 @@ instead call function `nntp-status-message' to get status message.")
        (nntp-decode-text))))
 
 (defun nntp-close-group (group &optional server)
+  (setq nntp-current-group nil)
   t)
 
 (defun nntp-request-list (&optional server)
@@ -1037,7 +1042,9 @@ If SERVICE, this this as the port number."
                  ;; Added by Hallvard B Furuseth <h.b.furuseth@usit.uio.no>
                  (run-hooks 'nntp-server-opened-hook))))
          ((null server)
-          (setq nntp-status-string "NNTP server is not specified.")))
+          (setq nntp-status-string "NNTP server is not specified."))
+         (t ; We couldn't open the server.
+          (setq nntp-timeout-servers (cons server nntp-timeout-servers))))
     (and timer (cancel-timer timer))
     (message "")
     (or status
@@ -1201,20 +1208,22 @@ defining this function as macro."
     (process-send-string nntp-async-process cmd)))
 
 (defun nntp-async-request-group (group)
-  (if (string= group nntp-current-group)
+  (if (equal group nntp-current-group)
       ()
     (let ((asyncs (assoc group nntp-async-group-alist)))
       ;; A new group has been selected, so we push the current state
       ;; of async articles on an alist, and pull the old state off.
       (setq nntp-async-group-alist 
            (cons (list nntp-current-group
-                       nntp-async-articles nntp-async-fetched)
+                       nntp-async-articles nntp-async-fetched
+                       nntp-async-process)
                  (delq asyncs nntp-async-group-alist)))
       (setq nntp-current-group group)
-      (or asyncs
-         (progn
-           (setq nntp-async-articles (nth 1 asyncs))
-           (setq nntp-async-fetched (nth 2 asyncs)))))))
+      (and asyncs
+          (progn
+            (setq nntp-async-articles (nth 1 asyncs))
+            (setq nntp-async-fetched (nth 2 asyncs))
+            (setq nntp-async-process (nth 3 asyncs)))))))
 
 (provide 'nntp)
 
index 5e55123..26d314d 100644 (file)
@@ -319,8 +319,7 @@ If the stream is opened, return T, otherwise return NIL."
                  (gnus-get-unread-articles-in-group
                   info (gnus-gethash igroup gnus-active-hashtb))
                  (setq active (gnus-gethash igroup gnus-active-hashtb)))
-             (message "Couldn't open component group %s" igroup)
-             (ding)))
+             (message "Couldn't open component group %s" igroup)))
        (if (null active)
            ()
          ;; And then we do the mapping for this component group. If
index 8500862..b3f2a8b 100644 (file)
@@ -2,11 +2,15 @@ TEXI2DVI=texi2dvi
 EMACS=emacs
 MAKEINFO=$(EMACS) -batch -q -no-site-file gnus.texi -l texinfmt -f texinfo-every-node-update -f texinfo-format-buffer -f save-buffer
 # MAKEINFO=makeinfo -o gnus gnus.texi
+LATEX=latex
 
-all: gnus
+all: gnus.info refcard.dvi
 
-gnus: gnus.texi
+gnus.info: gnus.texi
        $(MAKEINFO)
 
 dvi: gnus.texi
        $(TEXI2DVI) gnus.texi
+
+refcard.dvi: refcard.tex
+       $(LATEX) refcard.tex
index b1a91bc..74e2001 100644 (file)
@@ -250,6 +250,8 @@ by Per Abrahamsen.
 @item
 Innumerable bug fixes were written by Sudish Joseph.
 @item
+The refcard was written by Vladimir Alexiev.
+@item
 I stole some pieces from the XGnus distribution by Felix Lee and JWZ.
 @item 
 nnfolder has been much enhanced by Scott Byer.
@@ -1176,19 +1178,19 @@ and then execute the command.
 @table @kbd
 @item #
 @kindex # (Group)
-@item G m
-@kindex G m (Group)
+@item M m
+@kindex M m (Group)
 @findex gnus-group-mark-group
 Set the mark on the current group (@code{gnus-group-mark-group}). 
 @item M-#
 @kindex M-# (Group)
-@item G u
-@kindex G u (Group)
+@item < u
+@kindex M u (Group)
 @findex gnus-group-unmark-group
 Remove the mark from the current group
 (@code{gnus-group-unmark-group}). 
-@item G w
-@kindex G w (Group)
+@item M w
+@kindex M w (Group)
 @findex gnus-group-mark-region
 Mark all groups between point and mark (@code{gnus-group-mark-region}). 
 @end table
@@ -1385,26 +1387,26 @@ no timeouts are done.
 This hook is run as the last step when connecting to an @sc{nntp}
 server.
 
-@findex nntp-open-rlogin
-@findex nntp-open-network-stream
-@item nntp-open-server-function
-@vindex nntp-open-server-function
-This function is used to connect to the remote system.  Two pre-made
-functions are @code{nntp-open-network-stream}, which is the default, and
-simply connects to some port or other on the remote system.  The other
-is @code{nntp-open-rlogin}, which does an rlogin on the remote system,
-and then does a telnet to the @sc{nntp} server available there.
-
-@item nntp-rlogin-parameters
-@vindex nntp-rlogin-parameters
-If you use @code{nntp-open-rlogin} as the
-@code{nntp-open-server-function}, this list will be used as the
-parameter list given to @code{rsh}.
-
-@item nntp-rlogin-user-name
-@vindex nntp-rlogin-user-name
-User name on the remote system when using the @code{rlogin} connect
-function. 
+@c @findex nntp-open-rlogin
+@c @findex nntp-open-network-stream
+@c @item nntp-open-server-function
+@c @vindex nntp-open-server-function
+@c This function is used to connect to the remote system.  Two pre-made
+@c functions are @code{nntp-open-network-stream}, which is the default, and
+@c simply connects to some port or other on the remote system.  The other
+@c is @code{nntp-open-rlogin}, which does an rlogin on the remote system,
+@c and then does a telnet to the @sc{nntp} server available there.
+@c 
+@c @item nntp-rlogin-parameters
+@c @vindex nntp-rlogin-parameters
+@c If you use @code{nntp-open-rlogin} as the
+@c @code{nntp-open-server-function}, this list will be used as the
+@c parameter list given to @code{rsh}.
+@c 
+@c @item nntp-rlogin-user-name
+@c @vindex nntp-rlogin-user-name
+@c User name on the remote system when using the @code{rlogin} connect
+@c function. 
 
 @item nntp-address
 @vindex nntp-address
@@ -1786,6 +1788,28 @@ If @code{nnmail-delete-incoming} is non-@code{nil}, the mail backends
 will delete the temporary incoming file after splitting mail into the
 proper groups.  This is @code{nil} by default for reasons of security. 
 
+@vindex nnmail-message-id-cache-length
+@vindex nnmail-message-id-cache-file
+@vindex nnmail-delete-duplicates
+@cindex duplicate mails
+If you are a member of a couple of mailing list, you will sometime
+receive two copies of the same mail. This can be quite annoying, so
+@code{nnmail} checks for and discards any duplicates it might find. To
+do this, it keeps a cache of old @code{Message-ID}s -
+@code{nnmail-message-id-cache-file}, which is @file{~/.nnmail-cache} by
+default. The approximate maximum number of @code{Message-ID}s stored
+there is controlled by the @code{nnmail-message-id-cache-length}
+variable, which is 1000 by default. (So 1000 @code{Message-ID}s will be
+stored.) If all this sounds scary to you, you can set
+@code{nnmail-delete-duplicates} to @code{nil} (which is what it is by
+default), and @code{nnmail} won't do any duplicate checking.
+
+Here's a neat feature: If you know that the recipient reads her mail
+with Gnus, and that she has @code{nnmail-delete-duplicates} set to
+@code{t}, you can send her as many insults as you like, just by using a
+@code{Message-ID} of a mail that you know that she's already received.
+Think of all the fun! She'll never see any of it! Whee!
+
 Gnus gives you all the opportunity you could possibly want for shooting
 yourself in the foot.  Let's say you create a group that will contain
 all the mail you get from your boss.  And then you accidentally
@@ -4254,10 +4278,14 @@ group and return you to the group buffer.
 @kindex Z Z (Summary)
 @kindex q (Summary)
 @findex gnus-summary-exit
+@vindex gnus-summary-exit-hook
+@vindex gnus-summary-prepare-exit-hook
 Exit the current group and update all information on the group
-(@code{gnus-summary-exit}).  @code{gnus-summary-exit-hook} is called
-before doing much of the exiting, and calls
+(@code{gnus-summary-exit}). @code{gnus-summary-prepare-exit-hook} is
+called before doing much of the exiting, and calls
 @code{gnus-summary-expire-articles} by default.
+@code{gnus-summary-exit-hook} is called after finishing the exiting
+process. 
 @item Z E
 @itemx Q
 @kindex Z E (Summary)
@@ -4895,8 +4923,8 @@ Treat overstrike (@code{gnus-article-treat-overstrike}).
 @kindex W w (Summary)
 @findex gnus-article-word-wrap
 Do word wrap (@code{gnus-article-word-wrap}).
-@item W d
-@kindex W d (Summary)
+@item W m
+@kindex W m (Summary)
 @findex gnus-article-remove-cr
 Remove CR (@code{gnus-article-remove-cr}).
 @item W q
@@ -4946,7 +4974,7 @@ Sort by date (@code{gnus-summary-sort-by-date}).
 @item V s i
 @kindex V s i (Summary)
 @findex gnus-summary-sort-by-score
-Sort by date (@code{gnus-summary-sort-by-score}).
+Sort by score (@code{gnus-summary-sort-by-score}).
 @end table
 
 These functions will work both when you use threading and when you don't
@@ -5007,9 +5035,9 @@ files.  Articles that have a score lower than
 Gnus will read any @dfn{score files} that apply to the current group
 before generating the summary buffer.
 
-There are several commands in the summary buffer that inserts score
-entries based on the current article.  You can, for instance, ask Gnus
-to lower or increase the score of all articles with a certain subject.
+There are several commands in the summary buffer that insert score
+entries based on the current article. You can, for instance, ask Gnus to
+lower or increase the score of all articles with a certain subject.
 
 There are two sorts of scoring entries: Permanent and temporary.
 Temporary score entries are self-expiring entries.  Any entries that are
@@ -5408,9 +5436,9 @@ it.
 @cindex local variables
 The value of this entry should be a list of @code{(VAR VALUE)} pairs.
 Each @var{var} will be made buffer-local to the current summary buffer,
-and set to the value specified.  This is a convenient, if albeit
-strange, way of setting variables in some groups, and you don't like
-hooks much.
+and set to the value specified. This is a convenient, if somewhat
+strange, way of setting variables in some groups if you don't like hooks
+much.
 @end table
 
 @node Score File Editing
diff --git a/texi/refcard.tex b/texi/refcard.tex
new file mode 100644 (file)
index 0000000..cef001f
--- /dev/null
@@ -0,0 +1,559 @@
+% Reference Card for (ding) Gnus 0.98
+% by Vladimir Alexiev <vladimir@cs.ualberta.ca>, 26 July 1995.
+% To be processed with latex 2.09
+\documentstyle{article}
+\textwidth 7.5in \textheight 10in \topmargin -1.0in
+%\textwidth 7.27in \textheight 10.69in \topmargin -1.69in 
+% use this alternative setting for A4 (or leave it alone if you don't mind
+% a bit of space at the top and bottom of the page).
+\oddsidemargin -0.5in \evensidemargin -0.5in
+\begin{document}
+\twocolumn\scriptsize\pagestyle{empty}
+\raggedbottom\raggedright
+\newlength{\mywidth}
+\setlength{\mywidth}{0.5\textwidth}
+\addtolength{\mywidth}{-0.75in}
+\newenvironment{keys}
+  {\nopagebreak[4]\begin{tabular}{@{}l@{\hspace{\tabcolsep}}p{\mywidth}@{}}}
+  {\end{tabular}\\}
+\catcode`\^=12 % allow ^ to be typed literally
+\def\Bar{\rule[-0.3ex]{0.5pt}{2ex}\hspace{0.1em}} % the bar | symbol
+
+\begin{center}
+{\bf\LARGE (ding) Gnus Reference Card\\}
+{\normalsize for version 0.98}
+\end{center}
+
+Gnus is complex. Currently it has some 346 interactive (user-callable)
+functions. Of these 279 have keybindings in the two major modes (Group and
+Summary/Article). Of these functions, 96 have more than one binding; some
+have 3 or even 4 bindings. The total number of keybindings is 389. In order
+to save 40\% space, every function is listed only once, under the ``more
+logical'' binding. Alternative bindings are given in parentheses in the
+beginning of the description.
+
+Many Gnus commands are affected by the numeric prefix. Normally you enter a
+prefix by holding the Meta key and typing a number, but in most Gnus modes
+you don't need to use Meta since the digits are not self-inserting. The
+prefixed behavior of commands is given in [brackets]. Often the prefix is
+used to specify:
+
+\quad [distance] How many objects to move the point over.
+
+\quad [scope] How many objects to operate on (including the current one).
+
+\quad [p/p] The ``Process/Prefix Convention'': If a prefix is specified
+then it determines how many objects to operate on. Else if there are some
+objects marked with the process mark \#, these are operated on. Else only
+the current object is affected.
+
+\quad [level] A group subscribedness level. Only groups with a lower or
+equal level will be affected by the operation. If no prefix is given,
+`gnus-group-default-list-level' is used.  If
+`gnus-group-use-permanent-levels', then a prefix to the `g' and `l'
+commands will also set the default level.
+
+\quad [score] An article score. If no prefix is given,
+`gnus-summary-default-score' is used.
+
+Some functions were not yet documented at the time of creating this
+reference card and are clearly indicated as such.
+
+\begin{keys}
+C-c C-i & Go to the Gnus info node.\\
+C-c C-b & Send a Gnus bug report.\\
+\end{keys}
+
+\section*{Group Mode}
+\begin{keys}
+RET     & (=) Select this group. [Prefix: how many articles to fetch.
+Positive: newest articles, negative: oldest ones.]\\
+SPC     & Select this group and display the first unread article. [Same
+prefix as above.]\\ 
+?       & Give a very short help message.\\
+$<$     & Go to the beginning of the Group buffer.\\
+$>$     & Go to the end of the Group buffer.\\
+,       & Jump to the unread group with the lowest level.\\
+.       & Jump to the first group with unread articles.\\
+^       & Enter the Server buffer mode.\\
+a       & Post an article to a group.\\
+b       & Find bogus groups and delete them.\\
+c       & Mark all unticked articles in this group as read (catchup). [p/p]\\
+g       & Check the server for new articles. [level]\\
+j       & Jump to a group.\\
+l       & List groups with unread articles. [level]\\
+m       & Mail a message to someone.\\
+n       & Go to the next group with unread articles. [distance]\\
+p       & (DEL) Go to the previous group with unread articles. [distance]\\
+q       & Quit Gnus.\\
+r       & Read the init file.\\
+s       & Save the `.newsrc.eld' file (and `.newsrc' if
+`gnus-save-newsrc-file').\\ 
+z       & Suspend (kill all buffers of) Gnus.\\
+B       & Browse a foreign server.\\
+C       & Mark all articles in this group as read (catchup). [p/p]\\
+F       & Find new groups and process them.\\
+L       & List all groups. [level]\\
+N       & Go to the next group. [distance]\\
+P       & Go to the previous group. [distance]\\
+Q       & Quit Gnus without saving any startup files.\\
+R       & Restart Gnus.\\
+V       & Display the Gnus version number.\\
+Z       & Clear the dribble buffer.\\
+C-c C-d & Show the description of this group. [Prefix: re-read it from the
+server.]\\ 
+C-c C-s & Sort the groups by name, number of unread articles, or level
+(depending on `gnus-group-sort-function').\\
+C-c C-x & Run all expirable articles in this group through the expiry 
+process.\\
+C-c M-C-x & Run all articles in all groups through the expiry process.\\
+C-x C-t & Transpose two groups.\\
+M-d     & Describe ALL groups. [Prefix: re-read the description from the
+server.]\\
+M-f     & Fetch this group's FAQ (using ange-ftp).\\
+M-g     & Check for new articles in this group. [p/p]\\
+M-n     & Go to the previous unread group of the same or lower level. [distance]\\
+M-p     & Go to the next unread group of the same or lower level. [distance]\\
+\end{keys}
+
+\subsection*{List Groups}
+\begin{keys}
+A a     & (C-c C-a) List all groups whose names match a regexp (apropos).\\
+A d     & List all groups whose names or descriptions match a regexp.\\ 
+A k     & (C-c C-l) List all killed groups.\\
+A m     & List groups that match a regexp and have unread articles. [level]\\
+A s     & (l) List groups with unread articles. [level]\\
+A u     & (L) List all groups. [If no prefix is given, level 7 is the
+default]\\ 
+A z     & List all zombie groups.\\
+A M     & List groups that match a regexp.\\
+\end{keys}
+
+\subsection*{Create/Edit Foreign Groups}
+The select methods are indicated in parentheses.\\*
+\begin{keys}
+G a     & Make the Gnus list archive group. (nndir over ange-ftp)\\
+G d     & Make a directory group (every file must be a posting and files
+must have numeric names). (nndir)\\
+G e     & (M-e) Edit this group's select method.\\
+G f     & Make a group based on a file. (nndoc)\\
+G h     & Make the (ding) Gnus help (documentation) group. (nndoc)\\
+G k     & Make a kiboze group. (nnkiboze)\\
+G m     & Make a new group.\\
+G p     & Edit this group's parameters.\\
+G v     & Add this group to a virtual group. [p/p]\\
+G D     & Enter a directory as a (temporary) group. (nneething without
+recording articles read.)\\
+G E     & Edit this group's info (select method, articles read, etc).\\
+G V     & Make a new empty virtual group. (nnvirtual)\\
+\end{keys}
+You can also create mail-groups and read your mail with Gnus (very useful
+if you are subscribed to any mailing lists), using one of the methods
+nnmbox, nnbabyl, nnml, nnmh, or nnfolder. Read about it in the online info
+(C-c C-i g Reading Mail RET).
+
+\subsubsection*{Soup Commands}
+\begin{keys}
+G s b   & gnus-group-brew-soup: not documented.\\
+G s p   & gnus-soup-pack-packet: not documented.\\
+G s r   & nnsoup-pack-replies: not documented.\\
+G s s   & gnus-soup-send-replies: not documented.\\
+G s w   & gnus-soup-save-areas: not documented.\\
+\end{keys}
+
+\subsection*{Mark Groups}
+\begin{keys}
+M m     & (\#) Set the process mark on this group. [scope]\\
+M u     & (M-\#) Remove the process mark from this group. [scope]\\
+M w     & Mark all groups in the current region.\\
+\end{keys}
+
+\subsection*{Unsubscribe, Kill and Yank Groups}
+\begin{keys}
+S k     & (C-k) Kill this group.\\
+S l     & Set the level of this group. [p/p]\\
+S s     & (U) Prompt for a group and toggle its subscription (Unsubscribe).\\
+S t     & (u) Toggle subscription to this group (unsubscribe). [p/p]\\
+S w     & (C-w) Kill all groups in the region.\\
+S y     & (C-y) Yank the last killed group.\\
+S z     & Kill all zombie groups.\\
+\end{keys}
+
+\subsection*{Group Subscribedness Levels}
+\begin{tabular}{|r|c|l|}
+\hline
+1 & mail groups   &              \\
+2 & mail groups   &              \\
+3 &               & subscribed   \\
+4 &               &              \\
+5 & default list level &         \\
+\hline
+6 &               &              \\
+7 &               & unsubscribed \\
+\hline
+8 &               & zombies      \\
+\hline
+9 &               & killed       \\
+\hline
+\end{tabular}
+
+\pagebreak[4]
+
+\section*{Summary and Article Modes}
+\begin{keys}
+SPC     & (A SPC, A n) Select an article, scroll it one page, move to the
+next one.\\ 
+DEL     & (A DEL, A p, b) Scroll this article one page back. [distance]\\
+RET     & Scroll this article one line forward. [distance]\\
+$<$     & (A $<$, A b) Scroll to the beginning of this article.\\
+$>$     & (A $>$, A e) Scroll to the end of this article.\\
+j       & (G g) Ask for an article number and then go to that summary line.\\
+M-n     & (G M-n) Go to the next summary line of an unread article.
+[distance]\\ 
+M-p     & (G M-p) Go to the previous summary line of an unread article. 
+[distance]\\ 
+\end{keys}
+
+\subsection*{Article Buffer Commands}
+\begin{keys}
+A c     & (C-c C-r) Do a Caesar rotate (rot13) on the article buffer.\\
+A g     & (g) (Re)fetch this article. [Prefix: just show the article.]\\
+A m     & Toggle MIME processing.\\
+A r     & (^, A^) Go to the parent of this article (the References: header).\\
+A s     & (s) Perform an isearch in the article buffer.\\
+A t     & (t) Toggle the displaying of all headers.\\
+A w     & (w) Remove page breaks (`^L') from this article.\\
+\end{keys}
+
+\subsection*{Mail-Group Commands}
+These commands (except the first one) are only valid in a mail group.\\*
+\begin{keys}
+B DEL   & Delete the mail article from disk (!). [p/p]\\
+B c     & Copy this article from any group to a mail group. [p/p]\\
+B e     & Expire all expirable articles in this group. [p/p]\\
+B i     & Import a random file into this group.\\
+B m     & Move the article from one mail group to another. [p/p]\\
+B q     & Where will the article go during fancy splitting?\\
+B r     & Respool this mail article. [p/p]\\
+B w     & (e) Edit this article.\\
+B M-C-e & Expunge (delete from disk) all expirable articles in this group
+(!). [p/p]\\ 
+\end{keys}
+
+\subsection*{Select Articles}
+These commands select the target article. They do not understand the prefix.\\*
+\begin{keys}
+G b     & (,) Go to the best article (the one with the highest score).\\
+G f     & (.) Go to the first unread article.\\
+G l     & (l) Go to the last article read.\\
+G n     & (n) Go to the next unread article.\\
+p       & Go to the previous unread article.\\
+G p     & Pop an article off the summary history and go to it.\\
+G N     & (N) Go to the next article.\\
+G P     & (P) Go to the previous article.\\
+G C-n   & (M-C-n) Go to the next article with the same subject.\\
+G C-p   & (M-C-p) Go to the previous article with the same subject.\\
+\end{keys}
+
+\subsection*{Help Commands}
+\begin{keys}
+H d     & (C-c C-d) Describe this group. [Prefix: re-read the description
+from the server.]\\
+H f     & Try to fetch the FAQ for this group using ange-ftp.\\
+H h     & Give a very short help message.\\
+H i     & (C-c C-i) Go to the Gnus info node.\\
+H v     & Display the Gnus version number.\\
+\end{keys}
+
+\subsection*{Article Thread Commands}
+\begin{keys}
+T \#    & Mark this thread with the process mark.\\
+T d     & Move to the next article in this thread (down). [distance]\\
+T h     & Hide this (sub)thread.\\
+T i     & Increase the score of this thread.\\
+T k     & (M-C-k) Mark the current (sub)thread as read. [Negative prefix:
+tick it, positive prefix: unmark it.]\\
+T l     & (M-C-l) Lower the score of this thread.\\
+T n     & Go to the next thread. [distance]\\
+T p     & Go to the previous thread. [distance]\\
+T s     & Expose the thread hidden under this article, if any.\\
+T u     & Move to the previous article in this thread (up). [distance]\\
+T H     & Hide all threads.\\
+T S     & Expose all hidden threads.\\
+T T     & (M-C-t) Toggle threading.\\
+\end{keys}
+
+\subsection*{Mark Articles}
+\begin{keys}
+d       & (M d, M r) Mark this article as read and move to the next one.
+[scope]\\ 
+D       & Mark this article as read and move to the previous one. [scope]\\
+u       & (!, M !, M t) Mark this article as interesting (tick it) and move
+to the next one. [scope]\\
+U       & Mark this article as interesting and move to the previous one.
+[scope]\\ 
+M-u     & (M SPC, M c) Clear all marks from this article and move to the next
+one. [scope]\\ 
+M-U     & Clear all marks from this article and move to the previous one.
+[scope]\\ 
+M ?     & (?) Mark this article as dormant (only followups are
+interesting). [scope]\\ 
+M b     & Set a bookmark in this article.\\
+M e     & (E, M x) Mark this article as expirable. [scope]\\
+M k     & (k) Kill all articles with the same subject then select the next
+one.\\ 
+M B     & Remove the bookmark from this article.\\
+M C     & Catchup the articles that are not marked as unread.\\
+M D     & Show all dormant articles (normally they are hidden unless they
+have any followups).\\
+M H     & Catchup (mark read) this group to point.\\
+M K     & (C-k) Kill all articles with the same subject as this one.\\
+C-w     & Mark all articles between point and mark as read.\\
+M S     & (C-c M-C-s) Show all expunged articles.\\
+M C-c   & Catchup all articles in this group.\\
+M M-r   & (x) Expunge all read (deleted) articles from the summary buffer.\\
+M M-D   & Hide all dormant articles.\\
+M M-C-r & Expunge all articles having a given mark.\\
+\end{keys}
+
+\subsubsection*{The Process Mark}
+{\samepage These commands set and remove the process mark \#. You only need
+to use it if the set of articles you want to operate on is
+non-contiguous. Else use a numeric prefix.} \\* 
+\begin{keys}
+M p a   & Mark all articles (in series order).\\
+M p p   & (\#, M \#) Mark this article.\\
+M p r   & Mark all articles in the region.\\
+M p s   & Mark all articles in the current series.\\
+M p t   & Mark all articles in this (sub)thread.\\
+M p u   & (M-\#, M M-\#) Unmark this article.\\
+M p R   & Mark all articles matching a regexp.\\
+M p S   & Mark all series that already contain a marked article.\\
+M p U   & Unmark all articles.\\
+\end{keys}
+
+\subsubsection*{Mark Based on Score}
+\begin{keys}
+M s c   & Clear all marks from all high-scored articles. [score]\\
+M s k   & Kill all low-scored articles. [score]\\
+M s m   & Mark all high-scored articles with a given mark. [score]\\
+M s u   & Mark all high-scored articles as interesting (tick them). [score]\\
+\end{keys}
+
+\subsection*{Output Articles}
+\begin{keys}
+O f     & Save this article in plain file format. [p/p]\\
+O h     & Save this article in mh folder format. [p/p]\\
+O m     & Save this article in mail format. [p/p]\\
+O o     & (o) Save this article using the default article saver. [p/p]\\
+O p     & (\Bar) Pipe this article to a shell command. [p/p]\\
+O r     & Save this article in rmail format. [p/p]\\
+O v     & Save this article in vm format. [p/p]\\
+\end{keys}
+
+\subsection*{Wash the Article Buffer}
+\begin{keys}
+W a     & Hide unwanted parts of the article. Calls W h, W C-c, W s.\\
+W b     & Make external references in the article (Message-Ids and URLs) to
+buttons.\\ 
+W c     & Hide article citation.\\
+W d     & Remove extra CRs from the article.\\
+W f     & Look for and display any X-Face headers.\\
+W h     & Hide article headers.\\
+W o     & Treat overstrike or underline in the article.\\
+W q     & Treat quoted-printable in the article.\\
+W s     & Hide article signature.\\
+W t     & Convert the article timestamp to UTC (GMT).\\
+W w     & Do word wrap in the article.\\
+W A     & Highlight this article. Calls W H, W C, W S, W b.\\
+W C     & Highlight article citation.\\
+W H     & Highlight article headers.\\
+W S     & Highlight article signature.\\
+W T     & Convert the article timestamp to time lapsed since it was sent.\\
+W C-c   & Hide article citation using a more intelligent algorithm.\\
+\end{keys}
+
+\subsection*{Followup, Reply, Forward, Cancel}
+\samepage{These commands put you in a separate post or mail buffer. After
+editing the article, send it by pressing C-c C-c.  If you are in a
+foreign group and want to post the article using the foreign server, give
+a prefix to C-c C-c.} \\* 
+\begin{keys}
+S b     & Post a followup to this article and send a reply.\\
+S c     & (C) Cancel this article (only works if it is your own).\\
+S f     & (f) Post a followup to this article.\\
+S m     & (m) Send a mail to some other person.\\
+S o m   & (C-c C-f) Forward this article by mail to a person.\\
+S o p   & Forward this article to a newsgroup.\\
+S p     & (a) Post an article to this group.\\
+S r     & (r) Mail a reply to the author of this article.\\
+S s     & Supersede this article with a new one (only for own articles).\\
+S u     & Uuencode a file and post it as a series.\\
+S B     & Post a followup, send a reply, and include the original. [p/p]\\
+S F     & (F) Post a followup and include the original. [p/p]\\
+S O m   & Digest these series and forward by mail. [p/p]\\
+S O p   & Digest these series and forward to a newsgroup.\\
+S R     & (R) Mail a reply and include the original. [p/p]\\
+\end{keys}
+If you want to cancel or supersede an article you just posted (before it
+has appeared on the server), go to the *post-news* buffer, change
+`Message-ID' to `Cancel' or `Supersedes' and send it again with C-c C-c.
+
+\subsection*{Extract Series (Uudecode etc)}
+Gnus will recognize when the current article is part of a series (multipart
+posting whose parts are identified by numbers in their subjects, e.g.\
+1/10\dots10/10) and will process the series accordingly. You can mark more
+than one series. If the posting contains any archives, they are expanded
+and gathered in a new group.\\*
+\begin{keys}
+X b     & Un-{\bf b}inhex these series. [p/p]\\
+X o     & Simply {\bf o}output these series (no decoding). [p/p]\\ 
+X p     & Unpack these {\bf p}ostscript series. [p/p]\\
+X s     & Un-{\bf s}har these series. [p/p]\\
+X u     & {\bf U}udecode these series. [p/p]\\
+\end{keys}
+
+Each one of these commands has four variants:\\*
+\begin{keys}
+X   \bf z & Decode these series. [p/p]\\
+X v \bf z & Decode and view these series. [p/p]\\
+X   \bf Z & Decode and save these series. [p/p]\\
+X v \bf Z & Decode, save and view these series. [p/p]\\
+\end{keys}
+where {\bf z} identifies the decoding method (b, o ,p ,s, u).
+
+An alternative binding for the most-often used of these commands is\\*
+\begin{keys}
+C-c C-v C-v & (X v u) Uudecode and view these series. [p/p]\\
+\end{keys}
+
+\subsection*{Exit the Current Group}
+\begin{keys}
+Z c     & (c) Mark all unticked articles as read and exit.\\
+Z n     & Mark all articles as read and go to the next group.\\
+Z C     & Mark all articles as read and exit.\\
+Z E     & (Q) Exit without updating the group information.\\
+Z G     & (M-g) Check for new articles in this group.\\
+Z N     & Exit and go to the next group.\\
+Z P     & Exit and go to the previous group.\\
+Z R     & Exit this group, and then enter it again. [Prefix: select all
+articles, read and unread.]\\
+Z Z     & (q, Z Q) Exit this group.\\
+\end{keys}
+
+\subsection*{Various Group Commands}
+\begin{keys}
+V \&    & (\&) Execute a command on all articles matching a regexp.
+[Prefix: move backwards.]\\
+V e     & (=) Expand the Summary window. [Prefix: shrink it to display the
+Article window]\\
+V k     & (M-k) Edit this group's kill file.\\
+V r     & (M-^) Fetch the article with a given Message-ID.\\
+V u     & Execute a command on all articles having the process mark.\\
+V D     & Undigestify this article into a separate group.\\
+V K     & (M-K) Edit the general kill file.\\
+V T     & (C-t) Toggle truncation of summary lines.\\
+V C-r   & Search through all previous articles for a regexp.\\
+V C-s   & Search through all subsequent articles for a regexp.\\
+\end{keys}
+
+\subsubsection*{Sort the Summary Buffer}
+\begin{keys}
+V s a   & (C-c C-s C-a) Sort the summary by author.\\
+V s d   & (C-c C-s C-d) Sort the summary by date.\\
+V s i   & (C-c C-s C-i) Sort the summary by article score.\\
+V s n   & (C-c C-s C-n) Sort the summary by article number.\\
+V s s   & (C-c C-s C-s) Sort the summary by subject.\\
+\end{keys}
+
+\subsubsection*{Article Score Commands}
+\newcommand{\B}[1]{{\bf#1})}    % bold l)etter
+\begin{keys}
+V S a   & Add a new score entry, specifying all elements.\\
+V S c   & Specify a new score file as current.\\
+V S e   & Edit the current score alist.\\
+V S f   & Edit a score file and make it the current one.\\
+V S m   & Mark all articles below a given score as read.\\
+V S s   & Set the score of this article.\\
+V S t   & Display all score rules applied to this article.\\
+V S x   & Expunge all low-scored articles. [score]\\
+V S C   & gnus-score-customize: not documented.\\
+V S S   & Display the score of this article.\\
+\bf A p m l& Make a scoring entry based on this article.\\
+\end{keys}
+
+{\samepage
+The four letters stand for:\\*
+\quad \B{A}ction: I)ncrease, L)ower;\\*
+\quad \B{p}art: a)utor (from), s)ubject, x)refs (cross-posting), d)ate, l)ines,
+message-i)d, t)references (parent), f)ollowup, b)ody, h)ead (all headers);\\*
+\quad \B{m}atch type:\\*
+\qquad string: s)ubstring, e)xact, r)egexp, f)uzzy,\\*
+\qquad date: b)efore, a)t, n)this,\\*
+\qquad number: $<$, =, $>$;\\*
+\quad \B{l}ifetime: t)emporary, p)ermanent, i)mmediate.
+
+If you type the second letter in uppercase, the remaining two are assumed
+to be s)ubstring and t)emporary. 
+If you type the third letter in uppercase, the last one is assumed to be 
+t)emporary.
+
+\quad Extra keys for manual editing of a score file:\\*
+\begin{keys}
+C-c C-c & Finish editing the score file.\\
+C-c C-d & Insert the current date as number of days.\\
+\end{keys}
+}
+
+\section*{Article Mode}
+All keys for Summary mode also work in Article mode.
+The normal navigation keys work in Article mode.
+Some additional keys are:\\*
+\begin{keys}
+C-c ^   & Get the article with the Message-Id near point.\\
+C-c C-m & Send reply to the address near point and include the original.\\
+h       & Go to the header line of the article in the summary buffer.\\
+\end{keys}
+
+\section*{Server Mode}
+To enter this mode, press `^' while in Group mode.\\*
+\begin{keys}
+SPC     & Browse this server.\\
+q       & Return to the group buffer.\\
+l       & List all servers.\\
+k       & Kill this server. [scope]\\
+y       & Yank the previously killed server.\\
+c       & Copy this server.\\
+a       & Add a new server.\\
+e       & Edit a server.\\
+\end{keys}
+
+\section*{Browse Server Mode}
+To enter this mode, press `B' while in Group mode.\\*
+\begin{keys}
+RET     & Enter the current group.\\
+SPC     & Enter the current group and display the first article.\\
+?       & Give a very short help message.\\
+l       & Exit browse mode.\\
+n       & Go to the next group. [distance]\\
+p       & Go to the previous group. [distance]\\
+q       & Exit browse mode.\\
+u       & Subscribe to the current group. [scope]\\
+\end{keys}
+
+\begin{center}\samepage
+Copyright \copyright\ 1987 Free Software Foundation, Inc.\\*
+Copyright \copyright\ 1995 Vladimir Alexiev $<$vladimir@cs.ualberta.ca$>$.\\*
+Created from the Gnus manual Copyright \copyright\ 1994 Lars Magne
+Ingebrigtsen.\\*
+and the Emacs Help Bindings feature (C-h b).\\*
+\end{center}
+
+Permission is granted to make and distribute copies of this reference card
+provided the copyright notice and this permission are preserved on all
+copies. 
+Please send corrections, additions and suggestions to the above email
+address. \hfill 26 July 1995
+\end{document}
+
+