*** empty log message ***
authorLars Magne Ingebrigtsen <larsi@gnus.org>
Tue, 4 Mar 1997 21:24:59 +0000 (21:24 +0000)
committerLars Magne Ingebrigtsen <larsi@gnus.org>
Tue, 4 Mar 1997 21:24:59 +0000 (21:24 +0000)
33 files changed:
GNUS-NEWS
lisp/ChangeLog
lisp/gnus-art.el
lisp/gnus-group.el
lisp/gnus-load.el
lisp/gnus-logic.el
lisp/gnus-msg.el
lisp/gnus-salt.el
lisp/gnus-score.el
lisp/gnus-soup.el
lisp/gnus-srvr.el
lisp/gnus-start.el
lisp/gnus-sum.el
lisp/gnus-uu.el
lisp/gnus-vm.el
lisp/gnus-win.el
lisp/gnus-xmas.el
lisp/gnus.el
lisp/message.el
lisp/nnbabyl.el
lisp/nndoc.el
lisp/nnfolder.el
lisp/nngateway.el [new file with mode: 0644]
lisp/nnheader.el
lisp/nnmail.el
lisp/nnmbox.el
lisp/nnmh.el
lisp/nnml.el
lisp/nnoo.el
lisp/nnsoup.el
lisp/nntp.el
texi/ChangeLog
texi/gnus.texi

index a712ea2..040535b 100644 (file)
--- a/GNUS-NEWS
+++ b/GNUS-NEWS
@@ -64,3 +64,7 @@ the native server.
 *** A new command for reading collections of documents
 (nndoc with nnvirtual on top) has been added -- `M-C-d'.
 
+*** Process mark sets can be pushed and popped.
+
+*** A new mail-to-news backend makes it possible to post
+even when the NNTP server doesn't allow posting.
index 499a16a..ac8267c 100644 (file)
@@ -1,3 +1,127 @@
+Sat Aug 17 12:58:28 1996  Lars Magne Ingebrigtsen  <larsi@ifi.uio.no>
+
+       * gnus-win.el (gnus-window-configuration-element): New function. 
+       (gnus-windows-old-to-new): Use it.
+       (gnus-windows-old-to-new): Produced bogus results.
+
+       * message.el (message-cancel-message): New variable.
+
+       * gnus-srvr.el (gnus-server-mode-map): Buggy keymap.
+
+       * gnus-group.el (gnus-group-get-new-news-this-group): Illegal
+       gnus-error value.
+
+Fri Aug 16 21:22:12 1996  Lars Magne Ingebrigtsen  <lars@eyesore.no>
+
+       * nnmail.el (nnmail-replace-status, nnmail-decode-status,
+       nnmail-encode-status): New variables.
+
+       * nnml.el (nnml-article-to-file): New function.
+
+Fri Aug 16 20:26:12 1996  Kurt Swanson  <kurt@dna.lth.se>
+
+       * nnfolder.el (nnfolder-generate-active-file): Test the right
+       files. 
+
+Fri Aug 16 19:30:57 1996  Lars Magne Ingebrigtsen  <lars@eyesore.no>
+
+       * gnus-salt.el (gnus-possibly-generate-tree): Would bug out on
+       unthreaded buffers.
+
+       * gnus-xmas.el (gnus-xmas-modeline-right-extent): Disabled.
+       (gnus-xmas-modeline-left-extent): Ditto.
+
+       * gnus-group.el (gnus-group-make-menu-bar): Bugged out on
+       undefined variable.
+
+       * gnus.el (gnus-read-method): Return the virtual server name if
+       possible. 
+
+Thu Aug 15 18:15:58 1996  Lars Magne Ingebrigtsen  <lars@eyesore.no>
+
+       * nngateway.el: New file.
+
+       * nnoo.el (nnoo-define-skeleton): New macro.
+       (nnoo-define-skeleton-1): New function.
+
+       * gnus-start.el (gnus-strip-killed-list): New function.
+       (gnus-gnus-to-quick-newsrc-format): Use it.
+
+       * gnus-sum.el (gnus-summary-process-mark-set): New function.
+       (gnus-summary-yank-process-mark, gnus-summary-kill-process-mark,
+       gnus-summary-save-process-mark): New commands and keystrokes.
+
+       * nnml.el (nnml-generate-nov-file): Set modes.
+
+       * nnmail.el (nnmail-default-file-modes): New variable.
+       (nnmail-write-region): New function.
+
+       * gnus-score.el (gnus-score-score-files-1): Bind case-fold-search
+       to nil.
+
+Wed Aug 14 21:20:07 1996  Lars Magne Ingebrigtsen  <lars@eyesore.no>
+
+       * gnus-soup.el (gnus-soup-send-packet): Disable syntax checks.
+
+Wed Aug 14 20:28:09 1996  Fred Johansen  <Fred.Johansen@ifi.ntnu.no>
+
+       * gnus-logic.el (gnus-advanced-score-rule): `and' rules were
+       treated improperly.
+
+Wed Aug 14 15:29:39 1996  Lars Magne Ingebrigtsen  <lars@eyesore.no>
+
+       * gnus-salt.el (gnus-mouse-pick-article): New command. 
+
+       * gnus-art.el (gnus-button-url): Call with one argument.
+
+       * gnus-start.el (gnus-set-default-directory): New function.
+
+       * gnus-load.el (gnus-default-directory): New variable.
+
+Wed Aug 14 15:03:01 1996  Sudish Joseph  <sudish@mindspring.com>
+
+       * gnus-score.el (gnus-home-score-file): Changed syntax.
+
+Tue Aug 13 22:07:11 1996  Jan Vroonhof  <vroonhof@math.ethz.ch>
+
+       * nndoc.el (nndoc-dissect-buffer): Went into infinite loop if end
+       of file token wasn't properly detected.
+       (nndoc-type-alist): Better end-of-header regexp for
+       lanl.gov preprints
+       (nndoc-article-type): Updated doc string
+
+Mon Aug 12 21:01:25 1996  Sudish Joseph  <sudish@mindspring.com>
+
+       * nntp.el (nntp-request-newgroups): Switch to nntp-server-buffer
+       first.
+
+Tue Aug 13 09:44:46 1996  Lars Magne Ingebrigtsen  <lars@eyesore.no>
+
+       * gnus-group.el (gnus-group-sort-by-real-name): New function.
+
+       * gnus-sum.el (gnus-summary-save-article): Pass on number of
+       articles to be saved.
+
+       * gnus-art.el (gnus-article-edit-article): Remove all text props.
+       (gnus-read-save-file-name): Take an optional defaultish parameter.
+
+       * nntp.el (nntp-retrieve-groups): Saved.
+
+       * message.el (message-forward): Didn't work well with multi-line
+       separators. 
+
+       * gnus-msg.el (gnus-summary-mail-crosspost-complaint): Check
+       wheteher followup-to was restricted.
+
+       * nnsoup.el (nnsoup-store-reply): Would insert double courtesy
+       headers. 
+
+       * gnus-group.el (gnus-group-highlight-line): New `total' number. 
+
+Mon Aug 12 06:25:00 1996  Lars Magne Ingebrigtsen  <larsi@ifi.uio.no>
+
+       * gnus.el: Red Gnus v0.11 is released.
+
 Mon Aug 12 03:51:57 1996  Lars Magne Ingebrigtsen  <larsi@ifi.uio.no>
 
        * gnus-async.el (gnus-make-async-article-function): New function.
index d7860a3..089b7be 100644 (file)
@@ -152,6 +152,8 @@ If you want to run a special decoding program like nkf, use this hook.")
     (nconc '((?w (gnus-article-wash-status) ?s))
           gnus-summary-mode-line-format-alist))
 
+(defvar gnus-number-of-articles-to-be-saved nil)
+
 ;;; Provide a mapping from `gnus-*' commands to Article commands.
 
 (eval-and-compile
@@ -195,7 +197,7 @@ If you want to run a special decoding program like nkf, use this hook.")
 
 ;;; Saving functions.
 
-(defun gnus-article-save (save-buffer file)
+(defun gnus-article-save (save-buffer file &optional num)
   "Save the currently selected article."
   (unless gnus-save-all-headers
     ;; Remove headers accoring to `gnus-saved-headers'.
@@ -210,59 +212,72 @@ If you want to run a special decoding program like nkf, use this hook.")
       ;; `gnus-original-article-buffer' (or so they think),
       ;; but we bind that variable to our save-buffer.
       (set-buffer gnus-article-buffer)
-      (let ((gnus-original-article-buffer save-buffer))
+      (let* ((gnus-original-article-buffer save-buffer)
+            (filename
+             (cond
+              ((not gnus-prompt-before-saving)
+               'default)
+              ((eq gnus-prompt-before-saving 'always)
+               nil)
+              (t file)))
+            (gnus-number-of-articles-to-be-saved
+             (when (stringp filename) num))) ; Magic
        (set-buffer gnus-summary-buffer)
-       (funcall
-        gnus-default-article-saver
-        (cond
-         ((not gnus-prompt-before-saving)
-          'default)
-         ((eq gnus-prompt-before-saving 'always)
-          nil)
-         (t file)))))))
-
-(defun gnus-read-save-file-name (prompt default-name)
-  (let* ((split-name (gnus-get-split-value gnus-split-methods))
-        (file
-         ;; Let the split methods have their say.
-         (cond
-          ;; No split name was found.
-          ((null split-name)
-           (read-file-name
-            (concat prompt " (default "
-                    (file-name-nondirectory default-name) ") ")
-            (file-name-directory default-name)
-            default-name))
-          ;; A single split name was found
-          ((= 1 (length split-name))
-           (let* ((name (car split-name))
-                  (dir (cond ((file-directory-p name)
-                              (file-name-as-directory name))
-                             ((file-exists-p name) name)
-                             (t gnus-article-save-directory))))
-             (read-file-name
-              (concat prompt " (default " name ") ")
-              dir name)))
-          ;; A list of splits was found.
-          (t
-           (setq split-name (nreverse split-name))
-           (let (result)
-             (let ((file-name-history (nconc split-name file-name-history)))
-               (setq result
-                     (read-file-name
-                      (concat prompt " (`M-p' for defaults) ")
-                      gnus-article-save-directory
-                      (car split-name))))
-             (car (push result file-name-history)))))))
-    ;; Create the directory.
-    (unless (equal (directory-file-name file) file)
-      (make-directory (file-name-directory file) t))
-    ;; If we have read a directory, we append the default file name.
-    (when (file-directory-p file)
-      (setq file (concat (file-name-as-directory file)
-                        (file-name-nondirectory default-name))))
-    ;; Possibly translate some characters.
-    (nnheader-translate-file-chars file)))
+       (funcall gnus-default-article-saver filename)))))
+
+(defun gnus-read-save-file-name (prompt default-name &optional filename)
+  (cond
+   ((eq filename 'default)
+    default-name)
+   (filename filename)
+   (t
+    (let* ((split-name (gnus-get-split-value gnus-split-methods))
+          (prompt
+           (format prompt (if (and gnus-number-of-articles-to-be-saved
+                                   (> gnus-number-of-articles-to-be-saved 1))
+                              (format "these %d articles"
+                                      gnus-number-of-articles-to-be-saved)
+                            "this article")))
+          (file
+           ;; Let the split methods have their say.
+           (cond
+            ;; No split name was found.
+            ((null split-name)
+             (read-file-name
+              (concat prompt " (default "
+                      (file-name-nondirectory default-name) ") ")
+              (file-name-directory default-name)
+              default-name))
+            ;; A single split name was found
+            ((= 1 (length split-name))
+             (let* ((name (car split-name))
+                    (dir (cond ((file-directory-p name)
+                                (file-name-as-directory name))
+                               ((file-exists-p name) name)
+                               (t gnus-article-save-directory))))
+               (read-file-name
+                (concat prompt " (default " name ") ")
+                dir name)))
+            ;; A list of splits was found.
+            (t
+             (setq split-name (nreverse split-name))
+             (let (result)
+               (let ((file-name-history (nconc split-name file-name-history)))
+                 (setq result
+                       (read-file-name
+                        (concat prompt " (`M-p' for defaults) ")
+                        gnus-article-save-directory
+                        (car split-name))))
+               (car (push result file-name-history)))))))
+      ;; Create the directory.
+      (unless (equal (directory-file-name file) file)
+       (make-directory (file-name-directory file) t))
+      ;; If we have read a directory, we append the default file name.
+      (when (file-directory-p file)
+       (setq file (concat (file-name-as-directory file)
+                          (file-name-nondirectory default-name))))
+      ;; Possibly translate some characters.
+      (nnheader-translate-file-chars file)))))
 
 (defun gnus-article-archive-name (group)
   "Return the first instance of an \"Archive-name\" in the current buffer."
@@ -280,12 +295,8 @@ Directory to save to is default to `gnus-article-save-directory'."
   (let ((default-name
          (funcall gnus-rmail-save-name gnus-newsgroup-name
                   gnus-current-headers gnus-newsgroup-last-rmail)))
-    (setq filename
-         (cond ((eq filename 'default)
-                default-name)
-               (filename filename)
-               (t (gnus-read-save-file-name
-                   "Save in rmail file:" default-name))))
+    (setq filename (gnus-read-save-file-name
+                   "Save %s in rmail file:" default-name filename))
     (make-directory (file-name-directory filename) t)
     (gnus-eval-in-buffer-window gnus-original-article-buffer
       (save-excursion
@@ -304,12 +315,8 @@ Directory to save to is default to `gnus-article-save-directory'."
   (let ((default-name
          (funcall gnus-mail-save-name gnus-newsgroup-name
                   gnus-current-headers gnus-newsgroup-last-mail)))
-    (setq filename
-         (cond ((eq filename 'default)
-                default-name)
-               (filename filename)
-               (t (gnus-read-save-file-name
-                   "Save in Unix mail file:" default-name))))
+    (setq filename (gnus-read-save-file-name
+                   "Save %s in Unix mail file:" default-name filename))
     (setq filename
          (expand-file-name filename
                            (and default-name
@@ -335,12 +342,8 @@ Directory to save to is default to `gnus-article-save-directory'."
   (let ((default-name
          (funcall gnus-file-save-name gnus-newsgroup-name
                   gnus-current-headers gnus-newsgroup-last-file)))
-    (setq filename
-         (cond ((eq filename 'default)
-                default-name)
-               (filename filename)
-               (t (gnus-read-save-file-name
-                   "Save in file:" default-name))))
+    (setq filename (gnus-read-save-file-name
+                   "Save %s in file:" default-name filename))
     (make-directory (file-name-directory filename) t)
     (gnus-eval-in-buffer-window gnus-original-article-buffer
       (save-excursion
@@ -359,12 +362,8 @@ The directory to save in defaults to `gnus-article-save-directory'."
   (let ((default-name
          (funcall gnus-file-save-name gnus-newsgroup-name
                   gnus-current-headers gnus-newsgroup-last-file)))
-    (setq filename
-         (cond ((eq filename 'default)
-                default-name)
-               (filename filename)
-               (t (gnus-read-save-file-name
-                   "Save body in file:" default-name))))
+    (setq filename (gnus-read-save-file-name
+                   "Save %s body in file:" default-name filename))
     (make-directory (file-name-directory filename) t)
     (gnus-eval-in-buffer-window gnus-original-article-buffer
       (save-excursion
@@ -545,8 +544,8 @@ commands:
            (cons (list 'gnus-show-mime " MIME") minor-mode-alist)))
   (use-local-map gnus-article-mode-map)
   (gnus-update-format-specifications nil 'article-mode)
-  (make-local-variable 'page-delimiter)
-  (setq page-delimiter gnus-page-delimiter)
+  (set (make-local-variable 'page-delimiter) gnus-page-delimiter)
+  (gnus-set-default-directory)
   (buffer-disable-undo (current-buffer))
   (setq buffer-read-only t)            ;Disable modification
   (run-hooks 'gnus-article-mode-hook))
@@ -1243,6 +1242,7 @@ groups."
   (let ((winconf (current-window-configuration)))
     (set-buffer gnus-article-buffer)
     (gnus-article-edit-mode)
+    (set-text-properties (point-min) (point-max) nil)
     (gnus-configure-windows 'edit-article)
     (setq gnus-article-edit-done-function exit-func)
     (setq gnus-prev-winconf winconf)
@@ -1274,27 +1274,27 @@ groups."
        (window-start (window-start)))
     (erase-buffer)
     (insert buf)
-  (let ((winconf gnus-prev-winconf))
-    (gnus-article-mode)
-    ;; The cache and backlog have to be flushed somewhat.
-    (when gnus-use-cache
-      (gnus-cache-update-article       
-       (car gnus-article-current) (cdr gnus-article-current)))
-    (when gnus-keep-backlog
-      (gnus-backlog-remove-article 
-       (car gnus-article-current) (cdr gnus-article-current)))
-    ;; Flush original article as well.
-    (save-excursion
-      (when (get-buffer gnus-original-article-buffer)
-       (set-buffer gnus-original-article-buffer)
-       (setq gnus-original-article nil)))
-    (set-window-configuration winconf)
-    ;; Tippy-toe some to make sure that point remains where it was.
-    (let ((buf (current-buffer)))
-      (set-buffer curbuf)
-      (set-window-start (get-buffer-window (current-buffer)) window-start)
-      (goto-char p)
-      (set-buffer buf)))))
+    (let ((winconf gnus-prev-winconf))
+      (gnus-article-mode)
+      ;; The cache and backlog have to be flushed somewhat.
+      (when gnus-use-cache
+       (gnus-cache-update-article      
+        (car gnus-article-current) (cdr gnus-article-current)))
+      (when gnus-keep-backlog
+       (gnus-backlog-remove-article 
+        (car gnus-article-current) (cdr gnus-article-current)))
+      ;; Flush original article as well.
+      (save-excursion
+       (when (get-buffer gnus-original-article-buffer)
+         (set-buffer gnus-original-article-buffer)
+         (setq gnus-original-article nil)))
+      (set-window-configuration winconf)
+      ;; Tippy-toe some to make sure that point remains where it was.
+      (let ((buf (current-buffer)))
+       (set-buffer curbuf)
+       (set-window-start (get-buffer-window (current-buffer)) window-start)
+       (goto-char p)
+       (set-buffer buf)))))
       
 (defun gnus-article-edit-full-stops ()
   "Interactively repair spacing at end of sentences."
@@ -1663,7 +1663,7 @@ specified by `gnus-button-alist'."
 
 (defun gnus-button-url (address)
   "Browse ADDRESS."
-  (funcall browse-url-browser-function address browse-url-new-window-p))
+  (funcall browse-url-browser-function address))
 
 ;;; Next/prev buttons in the article buffer.
 
index 9769ed3..f89de47 100644 (file)
@@ -85,9 +85,10 @@ Ignored if `gnus-group-use-permanent-levels' is non-nil.")
   "*Function used for sorting the group buffer.
 This function will be called with group info entries as the arguments
 for the groups to be sorted.  Pre-made functions include
-`gnus-group-sort-by-alphabet', `gnus-group-sort-by-unread',
-`gnus-group-sort-by-level', `gnus-group-sort-by-score',
-`gnus-group-sort-by-method', and `gnus-group-sort-by-rank'.
+`gnus-group-sort-by-alphabet', `gnus-group-sort-by-real-name',
+`gnus-group-sort-by-unread', `gnus-group-sort-by-level',
+`gnus-group-sort-by-score', `gnus-group-sort-by-method', and
+`gnus-group-sort-by-rank'.
 
 This variable can also be a list of sorting functions. In that case,
 the most significant sort function should be the last function in the
@@ -501,8 +502,7 @@ variable.")
         (gnus-group-group-name)]
        ["Info" gnus-group-edit-group (gnus-group-group-name)])
        ("Score file"
-       ["Flush cache" gnus-score-flush-cache
-        (or gnus-score-cache gnus-short-name-score-file-cache)])
+       ["Flush cache" gnus-score-flush-cache t])
        ("Move"
        ["Next" gnus-group-next-group t]
        ["Previous" gnus-group-prev-group t]
@@ -588,6 +588,7 @@ The following commands are available:
   (buffer-disable-undo (current-buffer))
   (setq truncate-lines t)
   (setq buffer-read-only t)
+  (gnus-set-default-directory)
   (gnus-update-format-specifications nil 'group 'group-mode)
   (gnus-update-group-mark-positions)
   (gnus-make-local-hook 'post-command-hook)
@@ -904,6 +905,8 @@ If REGEXP, only list groups matching REGEXP."
         (group (gnus-group-group-name))
         (entry (gnus-group-entry group))
         (unread (if (numberp (car entry)) (car entry) 0))
+        (active (gnus-active group))
+        (total (if active (1+ (- (cdr active) (car active))) 0))
         (info (nth 2 entry))
         (method (gnus-server-get-method group (gnus-info-method info)))
         (marked (gnus-info-marks info))
@@ -1933,6 +1936,11 @@ If REVERSE, sort in reverse order."
   "Sort alphabetically."
   (string< (gnus-info-group info1) (gnus-info-group info2)))
 
+(defun gnus-group-sort-by-real-name (info1 info2)
+  "Sort alphabetically on real (unprefixed) names."
+  (string< (gnus-group-real-name (gnus-info-group info1))
+          (gnus-group-real-name (gnus-info-group info2))))
+
 (defun gnus-group-sort-by-unread (info1 info2)
   "Sort by number of unread articles."
   (let ((n1 (car (gnus-gethash (gnus-info-group info1) gnus-newsrc-hashtb)))
@@ -2473,7 +2481,7 @@ If N is negative, this group and the N-1 previous groups will be checked."
            (gnus-group-update-group group))
        (if (eq (gnus-server-status (gnus-find-method-for-group group))
                'denied)
-           (gnus-error "Server denied access")
+           (gnus-error "Server denied access")
          (gnus-error 3 "%s error: %s" group (gnus-status-message group)))))
     (when beg (goto-char beg))
     (when gnus-goto-next-group-when-activating
index 890e96c..8cf33bd 100644 (file)
@@ -31,6 +31,9 @@
 (defvar gnus-directory (or (getenv "SAVEDIR") "~/News/")
   "*Directory variable from which all other Gnus file variables are derived.")
 
+(defvar gnus-default-directory nil
+  "*Default directory for all Gnus buffers.")
+
 ;; Site dependent variables.  These variables should be defined in
 ;; paths.el.
 
@@ -353,7 +356,8 @@ slower.")
     ("nnkiboze" post virtual)
     ("nnsoup" post-mail address)
     ("nndraft" post-mail)
-    ("nnfolder" mail respool address))
+    ("nnfolder" mail respool address)
+    ("nngateway" none address prompt-address))
   "An alist of valid select methods.
 The first element of each list lists should be a string with the name
 of the select method.  The other elements may be the category of
index 963256f..8320d76 100644 (file)
@@ -86,7 +86,8 @@
       (if (not rule)
          t                             ; Empty rule is true.
        (while (and rule
-                   (gnus-advanced-score-rule (pop rule))))
+                   (gnus-advanced-score-rule (car rule)))
+         (pop rule))
        ;; If all the rules were true, then `rule' should be nil.
        (not rule)))
      ;; "Or" rule.
index 535f6fb..4f85c0f 100644 (file)
@@ -69,6 +69,23 @@ the group.")
 (defvar gnus-sent-message-ids-length 1000
   "The number of sent Message-IDs to save.")
 
+(defvar gnus-crosspost-complaint
+  "Hi,
+
+You posted the article below with the following Newsgroups header:
+
+Newsgroups: %s
+
+The %s group, at least, was an inappropriate recipient
+of this message.  Please trim your Newsgroups header to exclude this
+group before posting in the future.
+
+Thank you.
+"
+  "Format string to be inserted when complaining about crossposts.
+The first %s will be replaced by the Newsgroups header;
+the second with the current group name.")
+
 ;;; Internal variables.
 
 (defvar gnus-message-buffer "*Mail Gnus*")
@@ -580,23 +597,6 @@ The current group name will be inserted at \"%s\".")
        (insert (format gnus-nastygram-message group))
        (message-send-and-exit))))
 
-(defvar gnus-crosspost-complaint
-  "Hi,
-
-You posted the article below with the following Newsgroups header:
-
-Newsgroups: %s
-
-The %s group, at least, was an inappropriate recipient
-of this message.  Please trim your Newsgroups header to exclude this
-group before posting in the future.
-
-Thank you.
-"
-  "Format string to be inserted when complaining about crossposts.
-The first %s will be replaced by the Newsgroups header;
-the second with the current group name.")
-
 (defun gnus-summary-mail-crosspost-complaint (n)
   "Send a complaint about crossposting to the current article(s)."
   (interactive "P")
@@ -606,14 +606,19 @@ the second with the current group name.")
       (set-buffer gnus-summary-buffer)
       (gnus-summary-goto-subject article)
       (let ((group (gnus-group-real-name gnus-newsgroup-name))
-           newsgroups)
+           newsgroups followup-to)
        (gnus-summary-select-article)
        (set-buffer gnus-original-article-buffer)
-       (if (<= (length (message-tokenize-header
-                        (setq newsgroups (mail-fetch-field "newsgroups"))
-                        ", "))
-               1)
-           (gnus-message 1 "Not a crossposted article")
+       (if (and (<= (length (message-tokenize-header
+                             (setq newsgroups (mail-fetch-field "newsgroups"))
+                             ", "))
+                    1)
+                (or (not (setq followup-to (mail-fetch-field "followup-to")))
+                    (not (member group (message-tokenize-header
+                                        followup-to ", ")))))
+           (if followup-to
+               (gnus-message 1 "Followup-to restricted")
+             (gnus-message 1 "Not a crossposted article"))
          (set-buffer gnus-summary-buffer)
          (gnus-summary-reply-with-original 1)
          (set-buffer gnus-message-buffer)
index c850f7b..5ccf02b 100644 (file)
@@ -70,6 +70,7 @@ It accepts the same format specs that `gnus-summary-line-format' does.")
    "b" gnus-uu-mark-buffer
    "B" gnus-uu-unmark-buffer
    "." gnus-pick-article
+   gnus-mouse-2 gnus-pick-pick-article
    "\r" gnus-pick-start-reading))
 
 (defun gnus-pick-make-menu-bar ()
@@ -159,6 +160,12 @@ If ARG, pick the article on that line instead."
        (goto-char pos))))
   (gnus-summary-mark-as-processable 1))
 
+(defun gnus-mouse-pick-article (e)
+  (interactive "e")
+  (mouse-set-point e)
+  (save-excursion
+    (gnus-summary-mark-as-processable 1)))
+
 (defun gnus-pick-next-page ()
   "Go to the next page.  If at the end of the buffer, start reading articles."
   (interactive)
@@ -632,6 +639,7 @@ Two predefined functions are available:
   (when (save-excursion
          (set-buffer gnus-summary-buffer)
          (and gnus-use-trees
+              gnus-show-threads
               (vectorp (gnus-summary-article-header article))))
     (save-excursion
       (let ((top (save-excursion
index b617ea2..a2d5988 100644 (file)
@@ -136,9 +136,11 @@ It can be:
  * A list
    The elements in this list can be:
 
-   * `(regexp . file-name)'
-     If the `regexp' matches the group name, the `file-name' will
-     will be used as the home score file.
+   * `(regexp file-name ...)'
+     If the `regexp' matches the group name, the first `file-name' will
+     will be used as the home score file.  (Multiple filenames are
+     allowed so that one may use gnus-score-file-single-match-alist to
+     set this variable.)
 
    * A function.
      If the function returns non-nil, the result will be used
@@ -1037,9 +1039,12 @@ SCORE is the score to add."
        (delq (assoc file gnus-score-cache) gnus-score-cache)))
 
 (defun gnus-score-load-score-alist (file)
+  "Read score FILE."
   (let (alist)
     (if (not (file-readable-p file))
+       ;; Couldn't read file.
        (setq gnus-score-alist nil)
+      ;; Read file.
       (save-excursion
        (gnus-set-work-buffer)
        (insert-file-contents file)
@@ -1050,11 +1055,7 @@ SCORE is the score to add."
                (condition-case ()
                    (read (current-buffer))
                  (error 
-                  (progn
-                    (gnus-message 3 "Problem with score file %s" file)
-                    (ding) 
-                    (sit-for 2)
-                    nil))))))
+                  (gnus-error 3.2 "Problem with score file %s" file))))))
       (if (eq (car alist) 'setq)
          ;; This is an old-style score file.
          (setq gnus-score-alist (gnus-score-transform-old-to-new alist))
@@ -2228,6 +2229,7 @@ SCORE is the score to add."
   "Return all possible score files under DIR."
   (let ((files (directory-files (expand-file-name dir) t nil t))
        (regexp (gnus-score-file-regexp))
+       (case-fold-search nil)
        out file)
     (while (setq file (pop files))
       (cond 
@@ -2495,7 +2497,7 @@ If ADAPT, return the home adaptive file instead."
             ;; Regexp-file cons
             ((consp elem)
              (when (string-match (car elem) group)
-               (cdr elem))))))
+               (cadr elem))))))
     (when found
       (nnheader-concat gnus-kill-files-directory found))))
 
index c9e1a46..e000755 100644 (file)
@@ -545,7 +545,9 @@ Return whether the unpacking was successful."
                (gnus-message 5 "Sending news message to %s..."
                              (mail-fetch-field "newsgroups"))
                (sit-for 1)
-               (funcall message-send-news-function))
+               (let ((message-syntax-checks
+                      'dont-check-for-anything-just-trust-me))
+                 (funcall message-send-news-function)))
               ((string= (gnus-soup-reply-kind (car replies)) "mail")
                (gnus-message 5 "Sending mail to %s..."
                         (mail-fetch-field "to"))
index d281f72..76e24bc 100644 (file)
@@ -121,9 +121,9 @@ with some simple extensions.")
    "e" gnus-server-edit-server
 
    "O" gnus-server-open-server
-   "M-o" gnus-server-open-all-servers
+   "\M-o" gnus-server-open-all-servers
    "C" gnus-server-close-server
-   "M-c" gnus-server-close-all-servers
+   "\M-c" gnus-server-close-all-servers
    "D" gnus-server-deny-server
    "R" gnus-server-remove-denials
 
@@ -148,7 +148,7 @@ The following commands are available:
   (gnus-simplify-mode-line)
   (setq major-mode 'gnus-server-mode)
   (setq mode-name "Server")
-                                       ;  (gnus-group-set-mode-line)
+  (gnus-set-default-directory)
   (setq mode-line-process nil)
   (use-local-map gnus-server-mode-map)
   (buffer-disable-undo (current-buffer))
@@ -602,6 +602,7 @@ buffer.
   (use-local-map gnus-browse-mode-map)
   (buffer-disable-undo (current-buffer))
   (setq truncate-lines t)
+  (gnus-set-default-directory)
   (setq buffer-read-only t)
   (run-hooks 'gnus-browse-mode-hook))
 
index c90304e..5c4a23a 100644 (file)
@@ -161,7 +161,10 @@ that Gnus has no record of which groups are new and which are old, so
 the automatic new newsgroups subscription methods become meaningless.
 
 You should always set `gnus-check-new-newsgroups' to `ask-server' or
-nil if you set this variable to nil.")
+nil if you set this variable to nil.
+
+This variable can also be a regexp.  In that case, all groups that do
+not match this regexp will be removed before saving the list.")
 
 (defvar gnus-ignored-newsgroups
   (purecopy (mapconcat 'identity
@@ -2076,14 +2079,19 @@ If FORCE is non-nil, the .newsrc file is read."
   (insert ";; to read .newsrc.\n")
   (insert "(setq gnus-newsrc-file-version "
          (prin1-to-string gnus-version) ")\n")
-  (let ((variables
-        (if gnus-save-killed-list gnus-variable-list
-          ;; Remove the `gnus-killed-list' from the list of variables
-          ;; to be saved, if required.
-          (delq 'gnus-killed-list (copy-sequence gnus-variable-list))))
-       ;; Peel off the "dummy" group.
-       (gnus-newsrc-alist (cdr gnus-newsrc-alist))
-       variable)
+  (let* ((gnus-killed-list
+         (if (and gnus-save-killed-list
+                  (stringp gnus-save-killed-list))
+             (gnus-strip-killed-list)
+           gnus-killed-list))
+        (variables
+         (if gnus-save-killed-list gnus-variable-list
+           ;; Remove the `gnus-killed-list' from the list of variables
+           ;; to be saved, if required.
+           (delq 'gnus-killed-list (copy-sequence gnus-variable-list))))
+        ;; Peel off the "dummy" group.
+        (gnus-newsrc-alist (cdr gnus-newsrc-alist))
+        variable)
     ;; Insert the variables into the file.
     (while variables
       (when (and (boundp (setq variable (pop variables)))
@@ -2092,6 +2100,16 @@ If FORCE is non-nil, the .newsrc file is read."
        (prin1 (symbol-value variable) (current-buffer))
        (insert ")\n")))))
 
+(defun gnus-strip-killed-list ()
+  "Return the killed list minus the groups that match `gnus-save-killed-list'."
+  (let ((list gnus-killed-list)
+       olist)
+    (while list
+      (when (string-match gnus-save-killed-list)
+       (push (car list) olist))
+      (pop list))
+    (nreverse olist)))
+
 (defun gnus-gnus-to-newsrc-format ()
   ;; Generate and save the .newsrc file.
   (save-excursion
@@ -2293,6 +2311,11 @@ If FORCE is non-nil, the .newsrc file is read."
        (nconc gnus-valid-select-methods
               (list (apply 'list name abilities)))))
 
+(defun gnus-set-default-directory ()
+  "Set the default directory in the current buffer to `gnus-default-directory'.
+If this variable is nil, don't do anything."
+  (setq default-directory (or gnus-default-directory default-directory)))
+
 (provide 'gnus-start)
 
 ;;; gnus-start.el ends here
index 18e74f8..463502e 100644 (file)
@@ -449,6 +449,7 @@ automatically when it is selected.")
 
 (defvar gnus-original-article nil)
 (defvar gnus-article-internal-prepare-hook nil)
+(defvar gnus-newsgroup-process-stack nil)
 
 (defvar gnus-thread-indent-array nil)
 (defvar gnus-thread-indent-array-level gnus-thread-indent-level)
@@ -638,7 +639,7 @@ variable (string, integer, character, etc).")
     (gnus-summary-mark-below . global)
     gnus-newsgroup-active gnus-scores-exclude-files
     gnus-newsgroup-history gnus-newsgroup-ancient
-    gnus-newsgroup-sparse
+    gnus-newsgroup-sparse gnus-newsgroup-process-stack
     (gnus-newsgroup-adaptive . gnus-use-adaptive-scoring)
     gnus-newsgroup-adaptive-score-file (gnus-reffed-article-number . -1)
     (gnus-newsgroup-expunged-tally . 0)
@@ -1392,7 +1393,12 @@ increase the score of each group you read."
         ["Mark buffer" gnus-uu-mark-buffer t]
         ["Mark sparse" gnus-uu-mark-sparse t]
         ["Mark thread" gnus-uu-mark-thread t]
-        ["Unmark thread" gnus-uu-unmark-thread t]))
+        ["Unmark thread" gnus-uu-unmark-thread t]
+        ("Process Mark Sets"
+         ["Kill" gnus-summary-kill-process-mark t]
+         ["Yank" gnus-summary-yank-process-mark
+          gnus-newsgroup-process-stack]
+         ["Save" gnus-summary-save-process-mark t])))
        ("Scroll article"
        ["Page forward" gnus-summary-next-page t]
        ["Page backward" gnus-summary-prev-page t]
@@ -1573,6 +1579,7 @@ The following commands are available:
   (setq selective-display t)
   (setq selective-display-ellipses t)  ;Display `...'
   (setq buffer-display-table gnus-summary-display-table)
+  (gnus-set-default-directory)
   (setq gnus-newsgroup-name group)
   (make-local-variable 'gnus-summary-line-format)
   (make-local-variable 'gnus-summary-line-format-spec)
@@ -3955,6 +3962,8 @@ This is meant to be called in `gnus-article-internal-prepare-hook'."
     ;; Report back a success?
     (and header (mail-header-number header))))
 
+;;; Process/prefix in the summary buffer
+
 (defun gnus-summary-work-articles (n)
   "Return a list of articles to be worked upon.         The prefix argument,
 the list of process marked articles, and the current article will be
@@ -3991,11 +4000,41 @@ taken into consideration."
        (nreverse articles))))
    (gnus-newsgroup-processable
     ;; There are process-marked articles present.
+    ;; Save current state.
+    (gnus-summary-save-process-mark)
+    ;; Return the list.
     (reverse gnus-newsgroup-processable))
    (t
     ;; Just return the current article.
     (list (gnus-summary-article-number)))))
 
+(defun gnus-summary-save-process-mark ()
+  "Push the current set of process marked articles on the stack."
+  (interactive)
+  (push (copy-sequence gnus-newsgroup-processable)
+       gnus-newsgroup-process-stack))
+
+(defun gnus-summary-kill-process-mark ()
+  "Push the current set of process marked articles on the stack and unmark."
+  (interactive)
+  (gnus-summary-save-process-mark)
+  (gnus-summary-unmark-all-processable))
+
+(defun gnus-summary-yank-process-mark ()
+  "Pop the last process mark state off the stack and restore it."
+  (interactive)
+  (unless gnus-newsgroup-process-stack
+    (error "Empty mark stack"))
+  (gnus-summary-process-mark-set (pop gnus-newsgroup-process-stack)))
+
+(defun gnus-summary-process-mark-set (set)
+  "Make SET into the current process marked articles."
+  (gnus-summary-unmark-all-processable)
+  (while set
+    (gnus-summary-set-process-mark (pop set))))
+
+;;; Searching and stuff
+
 (defun gnus-summary-search-group (&optional backward use-level)
   "Search for next unread newsgroup.
 If optional argument BACKWARD is non-nil, search backward instead."
@@ -7362,10 +7401,11 @@ 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))
-       (save-buffer (save-excursion 
-                      (nnheader-set-temp-buffer " *Gnus Save*")))
-       header article file)
+  (let* ((articles (gnus-summary-work-articles n))
+        (save-buffer (save-excursion 
+                       (nnheader-set-temp-buffer " *Gnus Save*")))
+        (num (length articles))
+        header article file)
     (while articles
       (setq header (gnus-summary-article-header
                    (setq article (pop articles))))
@@ -7381,7 +7421,7 @@ The variable `gnus-default-article-saver' specifies the saver function."
          (set-buffer save-buffer)
          (erase-buffer)
          (insert-buffer-substring gnus-original-article-buffer))
-       (setq file (gnus-article-save save-buffer file))
+       (setq file (gnus-article-save save-buffer file num))
        (gnus-summary-remove-process-mark article)
        (unless not-saved
          (gnus-summary-set-saved-mark article))))
index bdf3f12..48152f8 100644 (file)
@@ -283,7 +283,10 @@ The headers will be included in the sequence they are matched.")
  "T" gnus-uu-unmark-thread
  "a" gnus-uu-mark-all
  "b" gnus-uu-mark-buffer
- "S" gnus-uu-mark-sparse)
+ "S" gnus-uu-mark-sparse
+ "k" gnus-summary-kill-process-mark
+ "y" gnus-summary-yank-process-mark
+ "w" gnus-summary-save-process-mark)
 
 (gnus-define-keys 
  (gnus-uu-extract-map "X" gnus-summary-mode-map)
index d102d7f..b312c6e 100644 (file)
@@ -95,7 +95,7 @@ save those articles instead."
          (cond ((eq folder 'default) default-name)
                (folder folder)
                (t (gnus-read-save-file-name 
-                   "Save article in VM folder:" default-name))))
+                   "Save %s in VM folder:" default-name))))
     (make-directory (file-name-directory folder) t)
     (set-buffer gnus-original-article-buffer)
     (save-excursion
index 7f2c3ee..03f76f8 100644 (file)
@@ -196,42 +196,54 @@ buffer configuration.")
        (error nil)))
     (pop gnus-created-frames)))
 
+(defun gnus-window-configuration-element (list)
+  (while (and list
+             (not (assq (car list) gnus-window-configuration)))
+    (pop list))
+  (cadr (assq (car list) gnus-window-configuration)))
+
 (defun gnus-windows-old-to-new (setting)
   ;; First we take care of the really, really old Gnus 3 actions.
   (when (symbolp setting)
     (setq setting
          ;; Take care of ooold GNUS 3.x values.
          (cond ((eq setting 'SelectArticle) 'article)
-               ((memq setting '(SelectSubject ExpandSubject)) 'summary)
-               ((memq setting '(SelectNewsgroup ExitNewsgroup)) 'group)
+               ((memq setting '(SelectNewsgroup SelectSubject ExpandSubject))
+                'summary)
+               ((memq setting '(ExitNewsgroup)) 'group)
                (t setting))))
   (if (or (listp setting)
          (not (and gnus-window-configuration
                    (memq setting '(group summary article)))))
       setting
-    (let* ((setting (if (eq setting 'group)
-                       (if (assq 'newsgroup gnus-window-configuration)
-                           'newsgroup
-                         'newsgroups) setting))
-          (elem (cadr (assq setting gnus-window-configuration)))
+    (let* ((elem
+           (cond 
+            ((eq setting 'group)
+             (gnus-window-configuration-element
+              '(group newsgroups ExitNewsgroup)))
+            ((eq setting 'summary)
+             (gnus-window-configuration-element
+              '(summary SelectNewsgroup SelectSubject ExpandSubject)))
+            ((eq setting 'article)
+             (gnus-window-configuration-element
+              '(article SelectArticle)))))
           (total (apply '+ elem))
           (types '(group summary article))
           (pbuf (if (eq setting 'newsgroups) 'group 'summary))
           (i 0)
-          perc
-          out)
+          perc out)
       (while (< i 3)
        (or (not (numberp (nth i elem)))
            (zerop (nth i elem))
            (progn
              (setq perc (if (= i 2)
                             1.0
-                          (/ (float (nth 0 elem)) total)))
-             (setq out (cons (if (eq pbuf (nth i types))
-                                 (list (nth i types) perc 'point)
-                               (list (nth i types) perc))
-                             out))))
-       (setq i (1+ i)))
+                          (/ (float (nth i elem)) total)))
+             (push (if (eq pbuf (nth i types))
+                       (list (nth i types) perc 'point)
+                     (list (nth i types) perc))
+                   out)))
+       (incf i))
       `(vertical 1.0 ,@(nreverse out)))))
 
 ;;;###autoload
index bec7868..7e6e1ef 100644 (file)
@@ -764,12 +764,12 @@ If HIDE, hide the text instead."
 
 (defvar gnus-xmas-modeline-left-extent 
   (let ((ext (copy-extent modeline-buffer-id-left-extent)))
-    (set-extent-property ext 'pointer gnus-xmas-pointer-glyph)
+    ;(set-extent-property ext 'pointer gnus-xmas-pointer-glyph)
     ext))
       
 (defvar gnus-xmas-modeline-right-extent 
   (let ((ext (copy-extent modeline-buffer-id-right-extent)))
-    (set-extent-property ext 'pointer gnus-xmas-pointer-glyph)
+    ;(set-extent-property ext 'pointer gnus-xmas-pointer-glyph)
     ext))
 
 (defvar gnus-xmas-modeline-glyph
index 855ca96..3f9bd19 100644 (file)
@@ -28,7 +28,7 @@
 
 (eval '(run-hooks 'gnus-load-hook))
 
-(defconst gnus-version-number "0.11"
+(defconst gnus-version-number "0.12"
   "Version number for this version of Gnus.")
 
 (defconst gnus-version (format "Red Gnus v%s" gnus-version-number)
@@ -800,7 +800,7 @@ Allow completion over sensible values."
                (read-string "Address: ")
              "")))
      ((assoc method gnus-server-alist)
-      (cdr (assoc method gnus-server-alist)))
+      method)
      (t
       (list (intern method) "")))))
 
index 4340543..2c8abc9 100644 (file)
@@ -193,6 +193,9 @@ If nil, message won't autosave.")
 (defvar message-ignored-cited-headers "."
   "Delete these headers from the messages you yank.")
 
+(defvar message-cancel-message "I am canceling my own article."
+  "Message to be inserted in the cancel message.")
+
 ;; Useful to set in site-init.el
 ;;;###autoload
 (defvar message-send-mail-function 'message-send-mail-with-sendmail
@@ -527,7 +530,7 @@ The cdr of ech entry is a function for applying the face to a region.")
   (let ((regexp (format "[%s]+" (or separator ",")))
        (beg 1)
        (first t)
-       quoted elems)
+       quoted elems paren)
     (save-excursion
       (message-set-work-buffer)
       (insert header)
@@ -539,11 +542,18 @@ The cdr of ech entry is a function for applying the face to a region.")
        (cond ((and (> (point) beg)
                    (or (eobp)
                        (and (looking-at regexp)
-                            (not quoted))))
+                            (not quoted)
+                            (not paren))))
               (push (buffer-substring beg (point)) elems)
               (setq beg (match-end 0)))
              ((= (following-char) ?\")
-              (setq quoted (not quoted)))))
+              (setq quoted (not quoted)))
+             ((and (= (following-char) ?\()
+                   (not quoted))
+              (setq paren t))
+             ((and (= (following-char) ?\))
+                   (not quoted))
+              (setq paren nil))))
       (nreverse elems))))
 
 (defun message-fetch-field (header)
@@ -2680,7 +2690,7 @@ responses here are directed to other newsgroups."))
                    (concat "Distribution: " distribution "\n")
                  "")
                mail-header-separator "\n"
-               "This is a cancel message from " from ".\n")
+               message-cancel-message)
        (message "Canceling your article...")
        (let ((message-syntax-checks 'dont-check-for-anything-just-trust-me))
          (funcall message-send-news-function))
@@ -2748,7 +2758,8 @@ header line with the old Message-ID."
 Optional NEWS will use news to forward instead of mail."
   (interactive "P")
   (let ((cur (current-buffer))
-       (subject (message-make-forward-subject)))
+       (subject (message-make-forward-subject))
+       art-beg)
     (if news (message-news nil subject) (message-mail nil subject))
     ;; Put point where we want it before inserting the forwarded
     ;; message. 
@@ -2762,13 +2773,13 @@ Optional NEWS will use news to forward instead of mail."
     (narrow-to-region (point) (point))
     ;; Insert the separators and the forwarded buffer.
     (insert message-forward-start-separator)
+    (setq art-beg (point))
     (insert-buffer-substring cur)
     (goto-char (point-max))
     (insert message-forward-end-separator)
     (set-text-properties (point-min) (point-max) nil)
     ;; Remove all unwanted headers.
-    (goto-char (point-min))
-    (forward-line 1)
+    (goto-char art-beg)
     (narrow-to-region (point) (if (search-forward "\n\n" nil t)
                                  (1- (point))
                                (point)))
index 330fe90..4f299eb 100644 (file)
                        (create-file-buffer nnbabyl-mbox-file)))
       (setq buffer-file-name nnbabyl-mbox-file)
       (insert "BABYL OPTIONS:\n\n\^_")
-      (write-region (point-min) (point-max) nnbabyl-mbox-file t 'nomesg)))
+      (nnmail-write-region
+       (point-min) (point-max) nnbabyl-mbox-file t 'nomesg)))
 
   (if (and nnbabyl-mbox-buffer
           (buffer-name nnbabyl-mbox-buffer)
index d0eac37..30efcea 100644 (file)
@@ -100,7 +100,7 @@ One of `mbox', `babyl', `digest', `news', `rnews', `mmdf', `forward',
     (lanl-gov-announce
       (article-begin . "^\\\\\\\\\n")
       (head-begin . "^Paper.*:")
-      (head-end   . "^\\\\\\\\\n")
+      (head-end   . "\\(^\\\\\\\\.*\n\\|-----------------\\)")
       (body-begin . "")  
       (body-end   . "-------------------------------------------------")     
       (file-end   . "^Title: Recent Seminal")
@@ -489,7 +489,7 @@ One of `mbox', `babyl', `digest', `news', `rnews', `mmdf', `forward',
            (setq subject (concat (match-string 1) subject))
            (setq from (concat (match-string 2) " <" e-mail ">"))))
        ))
-    (while (string-match "(\[^)\]*)" from)
+    (while (and from (string-match "(\[^)\]*)" from))
       (setq from (replace-match "" t t from)))
     (insert "From: "  (or from "unknown")
            "\nSubject: " (or subject "(no subject)") "\n")))
@@ -526,8 +526,8 @@ One of `mbox', `babyl', `digest', `news', `rnews', `mmdf', `forward',
               (funcall nndoc-head-begin-function))
              (nndoc-head-begin 
               (nndoc-search nndoc-head-begin)))
-       (if (and nndoc-file-end
-                (looking-at nndoc-file-end))
+       (if (or (>= (point) (point-max)) (and nndoc-file-end
+                (looking-at nndoc-file-end)))
            (goto-char (point-max))
          (setq head-begin (point))
          (nndoc-search (or nndoc-head-end "^$"))
index eab9621..558ac21 100644 (file)
@@ -521,24 +521,21 @@ time saver for large mailboxes.")
              (setq nnfolder-buffer-alist (delq inf nnfolder-buffer-alist))
              (setq inf nil)))
       
-       (if inf
-           ()
+       (unless inf
          (save-excursion
            (setq file (nnfolder-group-pathname group))
-           (if (file-directory-p (file-truename file))
-               ()
+           (unless (file-directory-p (file-truename file))
              (unless (file-exists-p file)
                (unless (file-exists-p (file-name-directory file))
                  (make-directory (file-name-directory file) t))
-               (write-region 1 1 file t 'nomesg))
+               (nnmail-write-region 1 1 file t 'nomesg))
              (setq nnfolder-current-buffer
                    (nnfolder-read-folder file scanning))
-             (if nnfolder-current-buffer 
-                 (progn
-                   (set-buffer nnfolder-current-buffer)
-                   (setq nnfolder-buffer-alist 
-                         (cons (list group nnfolder-current-buffer)
-                               nnfolder-buffer-alist)))))))))
+             (when nnfolder-current-buffer 
+               (set-buffer nnfolder-current-buffer)
+               (setq nnfolder-buffer-alist 
+                     (cons (list group nnfolder-current-buffer)
+                           nnfolder-buffer-alist))))))))
     (setq nnfolder-current-group group)))
 
 (defun nnfolder-save-mail (&optional group)
@@ -755,15 +752,15 @@ time saver for large mailboxes.")
   (interactive)
   (nnmail-activate 'nnfolder)
   (let ((files (directory-files nnfolder-directory))
-       file)
+        file)
     (while (setq file (pop files))
       (when (and (not (backup-file-name-p file))
-                (nnheader-mail-file-mbox-p file))
-       (nnheader-message 5 "Adding group %s..." file)
-       (push (list file (cons 1 0)) nnfolder-group-alist)
-       (nnfolder-possibly-change-group file)
-;;     (nnfolder-read-folder file)
-       (nnfolder-close-group file))
+                 (nnheader-mail-file-mbox-p
+                 (concat nnfolder-directory file)))
+        (nnheader-message 5 "Adding group %s..." file)
+        (push (list file (cons 1 0)) nnfolder-group-alist)
+        (nnfolder-possibly-change-group file)
+        (nnfolder-close-group file))
       (message ""))))
 
 (defun nnfolder-group-pathname (group)
diff --git a/lisp/nngateway.el b/lisp/nngateway.el
new file mode 100644 (file)
index 0000000..5eb9bbb
--- /dev/null
@@ -0,0 +1,79 @@
+;;; nngateway.el --- posting news via mail gateways
+;; Copyright (C) 1996 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@ifi.uio.no>
+;; Keywords: news, mail
+
+;; 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, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'nnoo)
+(require 'message)
+
+(nnoo-declare nngateway)
+
+(defvoo nngateway-address nil
+  "Address of the mail-to-news gateway.")
+
+(defvoo nngateway-header-transformation 'nngateway-simple-header-transformation
+  "Function to be called to rewrite the news headers into mail headers.
+It is called narrowed to the headers to be transformed with one
+parameter -- the gateway address.")
+
+;;; Interface functions
+
+(nnoo-define-basics nngateway)
+(nnoo-define-skeleton nngateway)
+
+(deffoo nngateway-open-server (server &optional defs)
+  (if (nngateway-server-opened server)
+      t
+    (unless (assq 'nngateway-address defs)
+      (setq defs (append defs (list (list 'nntp-address server)))))
+    (nnoo-change-server 'nntp server defs)))
+
+(deffoo nngateway-request-post (&optional server)
+  (when (or (nngateway-server-opened server)
+           (nngateway-open-server server))
+    ;; Rewrite the header.
+    (let ((buf (current-buffer)))
+      (nnheader-temp-write nil
+       (insert-buffer-substring buf)
+       (message-narrow-to-head)
+       (funcall nngateway-header-transformation nngateway-address)
+       (widen)
+       (let (message-required-mail-headers)
+         (message-send-mail))))))
+
+;;; Internal functions
+
+(defun nngateway-simple-header-transformation (gateway)
+  "Transform the headers to use GATEWAY."
+  (let ((newsgroups (mail-fetch-field "newsgroups")))
+    (message-remove-header "to")
+    (message-remove-header "cc")
+    (goto-char (point-min))
+    (insert "To: " (nnheader-replace-chars-in-string newsgroups ?. ?-)
+           "@" gateway "\n")))
+    
+(provide 'nngateway)
+
+;;; nngateway.el ends here
index f8fe16e..9ee5a59 100644 (file)
@@ -483,7 +483,11 @@ The first string in ARGS can be a format string."
   nil)
 
 (defun nnheader-get-report (backend)
-  (message "%s" (symbol-value (intern (format "%s-status-string" backend)))))
+  "Get the most recent report from BACKEND."
+  (condition-case ()
+      (message "%s" (symbol-value (intern (format "%s-status-string"
+                                                 backend))))
+    (error (message ""))))
 
 (defun nnheader-insert (format &rest args)
   "Clear the communicaton buffer and insert FORMAT and ARGS into the buffer.
index 157d20c..d9cd825 100644 (file)
@@ -74,6 +74,9 @@ new mail into folder numbers that Gnus has marked as expired.")
 If nil, groups like \"mail.misc\" will end up in directories like
 \"mail/misc/\".")
 
+(defvar nnmail-default-file-modes 384
+  "Set the mode bits of all new mail files to this integer.")
+
 (defvar nnmail-expiry-wait 7
   "*Expirable articles that are older than this will be expired.
 This variable can either be a number (which will be interpreted as a
@@ -484,7 +487,8 @@ nn*-request-list should have been called before calling this function."
                          (caadr group))))
        (unless (file-exists-p (file-name-directory file-name))
          (make-directory (file-name-directory file-name) t))
-       (write-region 1 (point-max) (expand-file-name file-name) nil 'nomesg)
+       (nnmail-write-region
+        1 (point-max) (expand-file-name file-name) nil 'nomesg)
        (kill-buffer (current-buffer))))))
 
 (defun nnmail-get-split-group (file group)
@@ -1031,8 +1035,8 @@ See the documentation for the variable `nnmail-split-fancy' for documentation."
       (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)
+      (nnmail-write-region (point-min) (point-max)
+                          nnmail-message-id-cache-file nil 'silent)
       (set-buffer-modified-p nil)
       (setq nnmail-cache-buffer nil)
       ;;(kill-buffer (current-buffer))
@@ -1199,6 +1203,70 @@ See the documentation for the variable `nnmail-split-fancy' for documentation."
       (unless (re-search-forward "^Message-Id:" nil t)
        (insert "Message-ID: " (nnmail-message-id) "\n")))))
 
+(defun nnmail-write-region (start end filename &optional append visit lockname)
+  "Do a `write-region', and then set the file modes."
+  (write-region start end filename append visit lockname)
+  (set-file-modes filename nnmail-default-file-modes))
+
+;;;
+;;; Status functions
+;;;
+
+(defun nnmail-replace-status (name value)
+  "Make status NAME and VALUE part of the current status line."
+  (save-restriction
+    (message-narrow-to-head)
+    (let ((status (nnmail-decode-status)))
+      (setq status (delq (member name status) status))
+      (when value
+       (push (cons name value) status))
+      (message-remove-header "status")
+      (goto-char (point-max))
+      (insert "Status: " (nnmail-encode-status status) "\n"))))
+
+(defun nnmail-decode-status ()
+  "Return a status-value alist from STATUS."
+  (goto-char (point-min))
+  (when (re-search-forward "^Status: " nil t)
+    (let (name value status)
+      (save-restriction
+       ;; Narrow to the status.
+       (narrow-to-region
+        (point)
+        (if (re-search-forward "^[^ \t]" nil t)
+            (1- (point))
+          (point-max)))
+       ;; Go through all elements and add them to the list.
+       (goto-char (point-min))
+       (while (re-search-forward "[^ \t=]+" nil t)
+         (setq name (match-string 0))
+         (if (not (= (following-char) ?=))
+             ;; Implied "yes".
+             (setq value "yes")
+           (forward-char 1)
+           (if (not (= (following-char) ?\"))
+               (if (not (looking-at "[^ \t]"))
+                   ;; Implied "no".
+                   (setq value "no")
+                 ;; Unquoted value.
+                 (setq value (match-string 0))
+                 (goto-char (match-end 0)))
+             ;; Quoted value.
+             (setq value (read (current-buffer)))))
+         (push (cons name value) status)))
+      status)))
+
+(defun nnmail-encode-status (status)
+  "Return a status string from STATUS."
+  (mapconcat
+   (lambda (elem)
+     (concat
+      (car elem) "="
+      (if (string-match "[ \t]" (cdr elem))
+         (prin1-to-string (cdr elem))
+       (cdr elem))))
+   status " "))
+
 (run-hooks 'nnmail-load-hook)
            
 (provide 'nnmail)
index dd46c99..01b08e6 100644 (file)
 (defun nnmbox-read-mbox ()
   (nnmail-activate 'nnmbox)
   (if (not (file-exists-p nnmbox-mbox-file))
-      (write-region 1 1 nnmbox-mbox-file t 'nomesg))
+      (nnmail-write-region 1 1 nnmbox-mbox-file t 'nomesg))
   (if (and nnmbox-mbox-buffer
           (buffer-name nnmbox-mbox-buffer)
           (save-excursion
index eb90b42..cad9cb4 100644 (file)
     (nnmh-possibly-create-directory group)
     (condition-case ()
        (progn
-         (write-region 
+         (nnmail-write-region 
           (point-min) (point-max)
           (concat nnmh-current-directory (int-to-string article))
           nil (if (nnheader-be-verbose 5) nil 'nomesg))
              ;; It was already saved, so we just make a hard link.
              (funcall nnmail-crosspost-link-function first file t)
            ;; Save the article.
-           (write-region (point-min) (point-max) file nil nil)
+           (nnmail-write-region (point-min) (point-max) file nil nil)
            (setq first file)))
        (setq ga (cdr ga))))
     group-art))
       (insert ";; Gnus article active file for " group "\n\n")
       (insert "(setq nnmh-newsgroup-articles '")
       (insert (prin1-to-string articles) ")\n")
-      (write-region (point-min) (point-max) nnmh-file nil 'nomesg)
+      (nnmail-write-region (point-min) (point-max) nnmh-file nil 'nomesg)
       (kill-buffer (current-buffer)))))
 
 (defun nnmh-deletable-article-p (group article)
index 7f77141..a836216 100644 (file)
@@ -172,11 +172,7 @@ all. This may very well take some time.")
                                             (car group-num) 
                                             nnml-directory)))))))
          (setq path (concat gpath (int-to-string (cdr group-num)))))
-      (unless nnml-article-file-alist
-       (setq nnml-article-file-alist
-             (nnheader-article-to-file-alist nnml-current-directory)))
-      (when (setq file (cdr (assq id nnml-article-file-alist)))
-       (setq path (concat nnml-current-directory file))))
+      (setq path (nnml-article-to-file id)))
     (cond 
      ((not path)
       (nnheader-report 'nnml "No such article: %s" id))
@@ -348,12 +344,13 @@ all. This may very well take some time.")
     (nnml-possibly-create-directory group)
     (let ((chars (nnmail-insert-lines))
          (art (concat (int-to-string article) "\t"))
-         headers)
+         headers file)
       (when (condition-case ()
                (progn
-                 (write-region 
+                 (nnmail-write-region 
                   (point-min) (point-max)
-                  (concat nnml-current-directory (int-to-string article))
+                  (setq file (concat nnml-current-directory
+                                     (int-to-string article)))
                   nil (if (nnheader-be-verbose 5) nil 'nomesg))
                  t)
              (error nil))
@@ -444,9 +441,29 @@ all. This may very well take some time.")
        (nnmail-save-active nnml-group-alist nnml-active-file)
        t))))
 
+(deffoo nnml-set-status (article name value &optional group server)
+  (nnml-possibly-change-directory group server)
+  (let ((file (nnml-article-to-file article)))
+    (cond
+     ((not (file-exists-p file))
+      (nnheader-report 'nnml "File %s does not exist" file))
+     (t
+      (nnheader-temp-write file
+       (nnheader-insert-file-contents-literally file)
+       (nnmail-replace-status name value))
+      t))))
+
 \f
 ;;; Internal functions.
 
+(defun nnml-article-to-file (article)
+  (unless nnml-article-file-alist
+    (setq nnml-article-file-alist
+         (nnheader-article-to-file-alist nnml-current-directory)))
+  (let (file)
+    (when (setq file (cdr (assq article nnml-article-file-alist)))
+      (concat nnml-current-directory file))))
+
 (defun nnml-deletable-article-p (group article)
   "Say whether ARTICLE in GROUP can be deleted."
   (let (file path)
@@ -576,8 +593,8 @@ all. This may very well take some time.")
              ;; It was already saved, so we just make a hard link.
              (funcall nnmail-crosspost-link-function first file t)
            ;; Save the article.
-           (write-region (point-min) (point-max) file nil 
-                         (if (nnheader-be-verbose 5) nil 'nomesg))
+           (nnmail-write-region (point-min) (point-max) file nil 
+                                (if (nnheader-be-verbose 5) nil 'nomesg))
            (setq first file)))
        (setq ga (cdr ga))))
     ;; Generate a nov line for this article. We generate the nov
@@ -666,9 +683,8 @@ all. This may very well take some time.")
     (while nnml-nov-buffer-alist
       (when (buffer-name (cdar nnml-nov-buffer-alist))
        (set-buffer (cdar nnml-nov-buffer-alist))
-       (and (buffer-modified-p)
-            (write-region 
-             1 (point-max) (buffer-file-name) nil 'nomesg))
+       (when (buffer-modified-p)
+         (nnmail-write-region 1 (point-max) (buffer-file-name) nil 'nomesg))
        (set-buffer-modified-p nil)
        (kill-buffer (current-buffer)))
       (setq nnml-nov-buffer-alist (cdr nnml-nov-buffer-alist)))))
@@ -759,8 +775,7 @@ all. This may very well take some time.")
        (setq files (cdr files)))
       (save-excursion
        (set-buffer nov-buffer)
-       (write-region 1 (point-max) (expand-file-name nov) nil
-                     'nomesg)
+       (nnmail-write-region 1 (point-max) nov nil 'nomesg)
        (kill-buffer (current-buffer))))))
 
 (defun nnml-nov-delete-article (group article)
index e189135..58f4c0f 100644 (file)
@@ -26,7 +26,7 @@
 ;;; Code:
 
 (require 'nnheader)
-(eval-when-compile (require 'cl))
+(require 'cl)
 
 (defvar nnoo-definition-alist nil)
 (defvar nnoo-state-alist nil)
        (buffer-name nntp-server-buffer)))
 
 (defmacro nnoo-define-basics (backend)
+  "Define `close-server', `server-opened' and `status-message'."
   `(eval-and-compile
      (nnoo-define-basics-1 ',backend)))
 
             (server &optional defs)
           (nnoo-change-server ',backend server defs))))
 
+(defmacro nnoo-define-skeleton (backend)
+  "Define all required backend functions for BACKEND.
+All functions will return nil and report an error."
+  `(eval-and-compile
+     (nnoo-define-skeleton-1 ',backend)))
+
+(defun nnoo-define-skeleton-1 (backend)
+  (let ((functions '(retrieve-headers
+                    request-close server-opened request-article
+                    open-group request-group close-group
+                    request-list request-post))
+       function)
+    (while (setq function (pop functions))
+      (eval `(deffoo ,(nnoo-symbol backend function) 
+                (&optional server)
+              (nnheader-report ',backend ,(format "%s-%s not implemented"
+                                                  backend function)))))))
 (provide 'nnoo)
 
 ;;; nnoo.el ends here.
index 03e80fe..31ef601 100644 (file)
@@ -620,11 +620,6 @@ The SOUP packet file name will be inserted at the %s.")
          ;; require one newline at the end.
          (or (= (preceding-char) ?\n)
              (insert ?\n))
-         (when (and news
-                    (equal kind "mail")
-                    (or (mail-fetch-field "cc")
-                        (mail-fetch-field "to")))
-           (message-insert-courtesy-copy))
          (let ((case-fold-search t))
            ;; Change header-delimiter to be what sendmail expects.
            (goto-char (point-min))
index 4d84707..cbb7801 100644 (file)
@@ -236,6 +236,79 @@ server there that you can connect to. See also `nntp-open-connection-function'")
        (copy-to-buffer nntp-server-buffer (point-min) (point-max))
        'headers))))
 
+(deffoo nntp-retrieve-groups (groups &optional server)
+  "Retrieve group info on GROUPS."
+  (nntp-possibly-change-group nil server)
+  (save-excursion
+    (set-buffer nntp-server-buffer)
+    ;; The first time this is run, this variable is `try'.  So we
+    ;; try.   
+    (when (eq nntp-server-list-active-group 'try)
+      (nntp-try-list-active (car groups)))
+    (erase-buffer)
+    (let ((count 0)
+         (received 0)
+         (last-point (point-min))
+         (command (if nntp-server-list-active-group "LIST ACTIVE" "GROUP")))
+      (while groups
+       ;; Send the command to the server.
+       (nntp-send-command nil command (car groups))
+       (setq groups (cdr groups))
+       (setq count (1+ count))
+       ;; Every 400 requests we have to read the stream in
+       ;; order to avoid deadlocks.
+       (when (or (null groups)         ;All requests have been sent.
+                 (zerop (% count nntp-maximum-request)))
+         (nntp-accept-response)
+         (while (progn
+                  (goto-char last-point)
+                  ;; Count replies.
+                  (while (re-search-forward "^[0-9]" nil t)
+                    (setq received (1+ received)))
+                  (setq last-point (point))
+                  (< received count))
+           (nntp-accept-response))))
+
+      ;; Wait for the reply from the final command.
+      (when nntp-server-list-active-group
+       (goto-char (point-max))
+       (re-search-backward "^[0-9]" nil t)
+       (when (looking-at "^[23]")
+         (while (progn
+                  (goto-char (- (point-max) 3))
+                  (not (looking-at "^\\.\r?\n")))
+           (nntp-accept-response))))
+
+      ;; Now all replies are received. We remove CRs.
+      (goto-char (point-min))
+      (while (search-forward "\r" nil t)
+       (replace-match "" t t))
+
+      (if (not nntp-server-list-active-group)
+         'group
+       ;; We have read active entries, so we just delete the
+       ;; superfluos gunk.
+       (goto-char (point-min))
+       (while (re-search-forward "^[.2-5]" nil t)
+         (delete-region (match-beginning 0) 
+                        (progn (forward-line 1) (point))))
+       'active))))
+
+ (defun nntp-try-list-active (group)
+  (nntp-list-active-group group)
+  (save-excursion
+    (set-buffer nntp-server-buffer)
+    (goto-char (point-min))
+    (cond ((looking-at "5[0-9]+")
+          (setq nntp-server-list-active-group nil))
+         (t
+          (setq nntp-server-list-active-group t)))))
+
+(deffoo nntp-list-active-group (group &optional server)
+  "Return the active info on GROUP (which can be a regexp."
+  (nntp-possibly-change-group group server)
+  (nntp-send-command "^.*\r?\n" "LIST ACTIVE" group))
+
 (deffoo nntp-request-article (article &optional group server buffer command)
   (nntp-possibly-change-group group server)
   (when (nntp-send-command-and-decode
@@ -312,16 +385,18 @@ server there that you can connect to. See also `nntp-open-connection-function'")
 
 (deffoo nntp-request-newgroups (date &optional server)
   (nntp-possibly-change-group nil server)
-  (let* ((date (timezone-parse-date date))
-        (time-string
-         (format "%s%02d%02d %s%s%s"
-                 (substring (aref date 0) 2) (string-to-int (aref date 1)) 
-                 (string-to-int (aref date 2)) (substring (aref date 3) 0 2)
-                 (substring 
-                  (aref date 3) 3 5) (substring (aref date 3) 6 8))))
-    (prog1
-       (nntp-send-command "^\\.\r?\n" "NEWGROUPS" time-string)
-      (nntp-decode-text))))
+  (save-excursion
+    (set-buffer nntp-server-buffer)
+    (let* ((date (timezone-parse-date date))
+          (time-string
+           (format "%s%02d%02d %s%s%s"
+                   (substring (aref date 0) 2) (string-to-int (aref date 1)) 
+                   (string-to-int (aref date 2)) (substring (aref date 3) 0 2)
+                   (substring 
+                    (aref date 3) 3 5) (substring (aref date 3) 6 8))))
+      (prog1
+         (nntp-send-command "^\\.\r?\n" "NEWGROUPS" time-string)
+       (nntp-decode-text)))))
 
 (deffoo nntp-request-post (&optional server)
   (nntp-possibly-change-group nil server)
index e560530..2b926ce 100644 (file)
@@ -1,3 +1,23 @@
+Thu Aug 15 17:59:12 1996  Lars Magne Ingebrigtsen  <lars@eyesore.no>
+
+       * gnus.texi (Followups To Yourself): Addition.
+       (Setting Process Marks): Addition.
+       (Process/Prefix): Addition.
+       (Startup Files): Addition.
+       (Mail-To-News Gateways): New.
+
+Wed Aug 14 15:02:14 1996  Lars Magne Ingebrigtsen  <lars@eyesore.no>
+
+       * gnus.texi (Home Score File): Fix.
+       (Various Various): New.
+
+Tue Aug 13 10:38:47 1996  Lars Magne Ingebrigtsen  <lars@eyesore.no>
+
+       * gnus.texi (Error Messaging): New.
+       (Mail Backend Variables): Fix.
+       (Foreign Groups): Added references.
+       (Sorting Groups): Addition.
+
 Sun Aug 11 02:52:37 1996  Lars Magne Ingebrigtsen  <lars@eyesore.no>
 
        * gnus.texi (User-Defined Specs): Correction.
index c1fc058..95e0f31 100644 (file)
@@ -311,6 +311,7 @@ the program.
 @end menu
 
 
+
 @node Starting Up
 @chapter Starting Gnus
 @cindex starting up
@@ -735,7 +736,10 @@ will also means that Gnus has no record of what groups are new or old,
 so the automatic new groups subscription methods become meaningless.
 You should always set @code{gnus-check-new-newsgroups} to @code{nil} or
 @code{ask-server} if you set this variable to @code{nil} (@pxref{New
-Groups}).
+Groups}).  This variable can also be a regular expression.  If that's
+the case, remove all groups that do not match this regexp before
+saving.  This can be useful in certain obscure situations that involve
+several servers where not all servers support @code{ask-server}.
 
 @vindex gnus-startup-file
 The @code{gnus-startup-file} variable says where the startup files are.
@@ -1100,6 +1104,9 @@ The level of the group.
 The score of the group.
 @item ticked 
 The number of ticked articles in the group.
+@item total
+The total number of articles in the group.  Or rather, MAX-NUMBER minus
+MIN-NUMBER.
 @item topic
 When using the topic minor mode, this variable is bound to the current
 topic being inserted.
@@ -1594,8 +1601,8 @@ Enter a buffer where you can edit the group info
 @item G d
 @kindex G d (Group)
 @findex gnus-group-make-directory-group
-Make a directory group.  You will be prompted for a directory name
-(@code{gnus-group-make-directory-group}).  
+Make a directory group (@pxref{Directory Groups}).  You will be prompted
+for a directory name (@code{gnus-group-make-directory-group}).
 
 @item G h 
 @kindex G h (Group)
@@ -1625,6 +1632,7 @@ strings to match on headers (@code{gnus-group-make-kiboze-group}).
 @findex gnus-group-enter-directory
 Read an arbitrary directory as if with were a newsgroup with the
 @code{nneething} backend (@code{gnus-group-enter-directory}).
+@xref{Anything Groups}. 
 
 @item G f
 @kindex G f (Group)
@@ -1636,7 +1644,7 @@ command, you will be prompted for a file name and a file type.
 Currently supported types are @code{babyl}, @code{mbox}, @code{digest},
 @code{mmdf}, @code{news}, @code{rnews}, @code{clari-briefs}, and
 @code{forward}.  If you run this command without a prefix, Gnus will
-guess at the file type.
+guess at the file type.  @xref{Document Groups}.
 
 @item G DEL
 @kindex G DEL (Group)
@@ -1651,7 +1659,7 @@ absolutely sure of what you are doing.
 @kindex G V (Group)
 @findex gnus-group-make-empty-virtual
 Make a new, fresh, empty @code{nnvirtual} group
-(@code{gnus-group-make-empty-virtual}).
+(@code{gnus-group-make-empty-virtual}).  @xref{Virtual Groups}.
 
 @item G v
 @kindex G v (Group)
@@ -1923,6 +1931,10 @@ include:
 @findex gnus-group-sort-by-alphabet
 Sort the group names alphabetically.  This is the default.
 
+@item gnus-group-sort-by-real-name
+@findex gnus-group-sort-by-real-name
+Sort the group alphabetically on the real (unprefixed) group names.
+
 @item gnus-group-sort-by-level
 @findex gnus-group-sort-by-level
 Sort by group level.
@@ -3763,6 +3775,25 @@ Mark all articles in series order (@code{gnus-uu-mark-series}).
 @findex gnus-uu-mark-buffer
 Mark all articles in the buffer in the order they appear
 (@code{gnus-uu-mark-buffer}). 
+
+@item M P k
+@kindex M P k (Summary)
+@findex gnus-summary-kill-process-mark
+Push the current process mark set onto the stack and unmark all articles
+(@code{gnus-summary-kill-process-mark}).
+
+@item M P y
+@kindex M P y (Summary)
+@findex gnus-summary-yank-process-mark
+Pop the previous process mark set from the stack and restore it
+(@code{gnus-summary-yank-process-mark}).
+
+@item M P w
+@kindex M P w (Summary)
+@findex gnus-summary-save-process-mark
+Push the current process mark set onto the stack
+(@code{gnus-summary-save-process-mark}).
+
 @end table
 
 
@@ -6387,6 +6418,13 @@ mechanism is quite likely to be somewhat inefficient, but not overly
 so.  It's certainly preferrable to reading the same articles more than
 once.
 
+Duplicate suppression is not a very subtle instrument.  It's more like a
+sledge hammer than anything else.  It works in a very simple
+fashion---if you have marked an article as read, it adds this Message-ID
+to a cache.  The next time it sees this Message-ID, it will mark the
+article as read the the @samp{M} mark.  It doesn't care what group it
+saw the article in.
+
 @table @code
 @item gnus-suppress-duplicates
 @vindex gnus-suppress-duplicates
@@ -7987,9 +8025,17 @@ directory.  The default is @samp{movemail}.
 @cindex incoming mail files
 @cindex deleting incoming files
 If non-@code{nil}, the mail backends will delete the temporary incoming
-file after splitting mail into the proper groups.  This is @code{t} by
+file after splitting mail into the proper groups.  This is @code{nil} by
 default for reasons of security.
 
+Since Red Gnus is an alpha release, it is to be expected to lose mail.
+(No Gnus release since (ding) Gnus 0.10 (or something like that) have
+lost mail, I think, but that's not the point.)  By not deleting the
+Incoming* files, one can be sure to not lose mail -- if Gnus totally
+whacks out, one can always recover what was lost.
+
+Delete the @file{Incoming*} files at will.
+
 @item nnmail-use-long-file-names
 @vindex nnmail-use-long-file-names
 If non-@code{nil}, the mail backends will use long file and directory
@@ -8601,10 +8647,11 @@ below allow Gnus to view directories and files as if they were
 newsgroups.
 
 @menu
-* Directory Groups::   You can read a directory as if it was a newsgroup.
-* Anything Groups::    Dired?  Who needs dired?
-* Document Groups::    Single files can be the basis of a group.
-* SOUP::               Reading @sc{SOUP} packets ``offline''.
+* Directory Groups::      You can read a directory as if it was a newsgroup.
+* Anything Groups::       Dired?  Who needs dired?
+* Document Groups::       Single files can be the basis of a group.
+* SOUP::                  Reading @sc{SOUP} packets ``offline''.
+* Mail-To-News Gateways:: Posting articles via mail-to-news gateways.
 @end menu
 
 
@@ -8757,11 +8804,12 @@ If you have some old archived articles that you want to insert into your
 new & spiffy Gnus mail backend, @code{nndoc} can probably help you with
 that.  Say you have an old @file{RMAIL} file with mail that you now want
 to split into your new @code{nnml} groups.  You look at that file using
-@code{nndoc}, set the process mark on all the articles in the buffer
-(@kbd{M P b}, for instance), and then re-spool (@kbd{B r}) using
-@code{nnml}.  If all goes well, all the mail in the @file{RMAIL} file is
-now also stored in lots of @code{nnml} directories, and you can delete
-that pesky @file{RMAIL} file.  If you have the guts!  
+@code{nndoc} (using the @kbd{G f} command in the group buffer
+(@pxref{Foreign Groups})), set the process mark on all the articles in
+the buffer (@kbd{M P b}, for instance), and then re-spool (@kbd{B r})
+using @code{nnml}.  If all goes well, all the mail in the @file{RMAIL}
+file is now also stored in lots of @code{nnml} directories, and you can
+delete that pesky @file{RMAIL} file.  If you have the guts!
 
 Virtual server variables:
 
@@ -9150,6 +9198,57 @@ system you just use the first line.  If you only want mail to be
 @sc{soup}ed you use the second.
 
 
+@node Mail-To-News Gateways
+@subsection Mail-To-News Gateways
+@cindex mail-to-news gateways
+@cindex gateways
+
+If your local @code{nntp} server doesn't allow posting, for some reason
+or other, you can post using one of the numerous mail-to-news gateways.
+The @code{nngateway} backend provides the interface.
+
+Note that you can't read anything from this backend---it can only be
+used to post with.
+
+Server variables:
+
+@table @code
+@item nngateway-address 
+@vindex nngateway-address 
+This is the address of the mail-to-news gateway.
+
+@item nngateway-header-transformation
+@vindex nngateway-header-transformation
+News headers have often have to be transformed in some odd way or other
+for the mail-to-news gateway to accept it.  This variable says what 
+transformation should be called, and defaults to
+@code{nngateway-simple-header-transformation}.  The function is called
+narrowed to the headers to be transformed and with one parameter---the
+gateway address.
+
+This default function just inserts a new @code{To} header based on the
+@code{Newsgroups} header and the gateway address---an article with this
+@code{Newsgroups} header:
+
+@example
+Newsgroups: alt.religion.emacs
+@end example
+
+will get this @code{From} header inserted:
+
+@example
+To: alt-religion-emacs@@GATEWAY
+@end example
+
+@end table
+
+So, to use this, simply say something like:
+
+@lisp
+(setq gnus-post-method '(nngateway "GATEWAY.ADDRESS"))
+@end lisp
+
+
 @node Combined Groups
 @section Combined Groups
 
@@ -10145,7 +10244,7 @@ A list.  The elements in this list can be:
 
 @enumerate
 @item 
-@var{(regexp file-name)}.  If the @var{regexp} matches the group name,
+@var{(regexp file-name)}.  If the @var{regexp} matches the group name,
 the @var{file-name} will will be used as the home score file.
 
 @item 
@@ -10185,9 +10284,9 @@ their own home score files:
 @lisp
 (setq gnus-home-score-file
       ;; All groups that match the regexp "\\.emacs"
-      '("\\.emacs" "emacs.SCORE")
+      '("\\.emacs" "emacs.SCORE")
       ;; All the comp groups in one score file
-       ("^comp" "comp.SCORE"))
+       ("^comp" "comp.SCORE"))
 @end lisp
    
 @vindex gnus-home-adapt-file
@@ -10230,6 +10329,28 @@ your own article.
 These two functions are both primarily meant to be used in hooks like
 @code{message-sent-hook}.  
 
+If you look closely at your own @code{Message-ID}, you'll notice that
+the first two or three characters are always the same.  Here's two of
+mine:  
+
+@example
+<x6u3u47icf.fsf@@eyesore.no>
+<x6sp9o7ibw.fsf@@eyesore.no>
+@end example
+
+So ``my'' ident on this machine is @samp{x6}.  This can be
+exploited---the following rule will raise the score on all followups to
+myself: 
+
+@lisp
+("references" 
+ "<x6[0-9a-z]+\\.fsf@.*eyesore.no>" 1000 nil r)
+@end lisp
+
+Whether it's the first two or first three characters that are ``yours''
+is system-dependent.
+
+
 @node Scoring Tips
 @section Scoring Tips
 @cindex scoring tips
@@ -10936,6 +11057,11 @@ process mark, just perform the operation on the current article.
 Quite simple, really, but it needs to be made clear so that surprises
 are avoided.
 
+Commands that react to the process mark will push the current list of
+process marked articles onto a stack and will then clear all process
+marked articles.  You can restore the previous configuration with the
+@kbd{M P y} command (@pxref{Setting Process Marks}).
+
 @vindex gnus-summary-goto-unread
 One thing that seems to shock & horrify lots of people is that, for
 instance, @kbd{3 d} does exactly the same as @kbd{d} @kbd{d} @kbd{d}.
@@ -12015,6 +12141,21 @@ To use moderation mode in these two groups, say:
 
 @table @code
 
+@item gnus-directory
+@vindex gnus-directory
+All Gnus directories will be initialized from this variable, which
+defaults to the @samp{SAVEDIR} environment variable, or @file{~/News/}
+if that variable isn't set.
+
+@item gnus-default-directory
+@vindex gnus-default-directory
+Not related to the above variable at all---this variable says what the
+default directory of all Gnus buffers should be.  If you issue commands
+like @kbd{C-x C-f}, the prompt you'll get starts in the current buffer's
+default directory.  If this variable is @code{nil} (which is the
+default), the default directory will be the default directory of the
+buffer you were in when you started Gnus.
+
 @item gnus-verbose
 @vindex gnus-verbose
 This variable is an integer between zero and ten.  The higher the value,
@@ -13017,6 +13158,7 @@ In the examples and definitions I will refer to the imaginary backend
 @menu
 * Required Backend Functions::        Functions that must be implemented.
 * Optional Backend Functions::        Functions that need not be implemented.
+* Error Messaging::                   How to get messages and report errors.
 * Writing New Backends::              Extending old backends.
 * Hooking New Backends Into Gnus::    What has to be done on the Gnus end.
 @end menu
@@ -13450,10 +13592,38 @@ There should be no data returned.
 @end table
 
 
+@node Error Messaging
+@subsubsection Error Messaging
+
+@findex nnheader-report
+@findex nnheader-get-report
+The backends should use the function @code{nnheader-report} to report
+error conditions---they should not raise errors when they aren't able to
+perform a request.  The first argument to this function is the backend
+symbol, and the rest are interpreted as arguments to @code{format} if
+there are many of them, or just a string if there is one of them.
+This function always returns @code{nil}.
+
+@lisp
+(nnheader-report 'nnchoke "You did something totally bogus")
+
+(nnheader-report 'nnchoke "Could not request group %s" group)
+@end lisp
+
+Gnus, in turn, will call @code{nnheader-get-report} when it gets a
+@code{nil} back from a server, and this function returns the most
+recently reported message for the backend in question.  This function
+takes one argument---the server symbol.
+
+Internally, these function access @var{backend}@code{-status-string}, so
+the @code{nnchoke} backend will have its error message stored in
+@code{nnchoke-status-string}. 
+
+
 @node Writing New Backends
 @subsubsection Writing New Backends
 
-The various backends share many similarities.  @code{nnml} is just like
+Many backends are quite similar.  @code{nnml} is just like
 @code{nnspool}, but it allows you to edit the articles on the server.
 @code{nnmh} is just like @code{nnml}, but it doesn't use an active file,
 and it doesn't maintain overview databases.  @code{nndir} is just like