*** empty log message ***
authorLars Magne Ingebrigtsen <larsi@gnus.org>
Tue, 4 Mar 1997 03:40:48 +0000 (03:40 +0000)
committerLars Magne Ingebrigtsen <larsi@gnus.org>
Tue, 4 Mar 1997 03:40:48 +0000 (03:40 +0000)
21 files changed:
lisp/ChangeLog
lisp/custom.el
lisp/gnus-cite.el
lisp/gnus-cus.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.el
lisp/nnbabyl.el
lisp/nnfolder.el
lisp/nnheader.el
lisp/nnmail.el
lisp/nnmbox.el
lisp/nnmh.el
lisp/nnml.el
lisp/nntp.el
texi/Makefile
texi/gnus.texi

index ecbb849..245c531 100644 (file)
@@ -1,5 +1,167 @@
+Sun Sep 10 00:39:41 1995  Lars Ingebrigtsen  <lars@eyesore.no>
+
+       * gnus-msg.el (gnus-post-news): Set the name of the newsgroup for
+       later use.
+
+       * gnus.el (gnus-group-unsubscribe-group): Don't accept empty group
+       names. 
+
+       * nnbabyl.el (nnbabyl-get-new-mail): If moving is unsuccessful,
+       don't pretend it went ok.
+       * nnmbox.el (nnmbox-get-new-mail): Ditto.
+       * nnfolder.el (nnfolder-get-new-mail): Ditto.
+       * nnmh.el (nnmh-get-new-mail): Ditto.
+       * nnml.el (nnml-get-new-mail): Ditto.
+
+       * gnus-vis.el (gnus-group-menu-hook, gnus-summary-menu-hook,
+       gnus-article-menu-hook, gnus-server-menu-hook,
+       gnus-browse-menu-hook): New hooks. 
+
+Fri Sep  8 19:08:29 1995  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * nnmail.el (nnmail-request-post-buffer): Newer send to `sender',
+       don't put everything in the `To' header, filter the `CC' header
+       through `rmail-dont-reply-to'.
+
+Fri Sep  8 20:42:27 1995  Lars Ingebrigtsen  <lars@eyesore.no>
+
+       * gnus.el (gnus-group-make-archive-group): Wrong interactive spec.
+       (gnus-select-method): Take `gnus-nntp-service' into account for
+       backwards compatability.
+
+Thu Sep  7 22:17:33 1995  Lars Ingebrigtsen  <lars@eyesore.no>
+
+       * gnus.el (gnus-setup-news): Find new groups before finding
+       numbers of unread articles in the groups.
+
+       * gnus-score.el (gnus-summary-score-entry): Fuzzy wrong match
+       value. 
+
+       * gnus.el ('gnus-load-hook): Run this hook while loading.
+
+       * gnus-vis.el (gnus-summary-make-menu-bar): Would re-generate the
+       summary buffers on each group entry.
+
+       * gnus-score.el (gnus-score-save): Don't try to write a score file
+       unless one can.
+
+Wed Sep  6 20:38:43 1995  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * gnus-cite.el  (gnus-cite-parse-max-size): New variable.
+       (gnus-cite-parse-maybe): Use it.  
+       (gnus-cite-parse): Move parser initialization to
+       `gnus-cite-parse-maybe' and reformat.
+       * gnus-vis.el (gnus-article-add-buttons): Force citation parsing
+       if called interactively.
+       * gnus-cite.el (gnus-article-highlight-citation): Ditto.
+       (gnus-article-hide-citation): Ditto.
+       (gnus-article-hide-citation-maybe): Ditto.
+       (gnus-article-highlight): Ditto.
+       (gnus-article-highlight-some): Ditto.
+       (gnus-article-hide): Ditto.
+
+Thu Sep  7 00:52:36 1995  Lars Ingebrigtsen  <lars@eyesore.no>
+
+       * gnus.el (gnus-summary-show-thread): Expand hidden subthreads as
+       well. 
+
+Wed Sep  6 20:38:43 1995  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * gnus-msg.el (gnus-use-followup-to): New value `ask' will make
+       Gnus always ask before obeying the followup-to header.  Changed
+       default to t to confirm with the Seal.
+        (gnus-summary-followup): Support `ask' value of
+       `gnus-use-followup-to'. 
+       * nntp.el (nntp-request-post-buffer): Support `ask' value of
+       `gnus-use-followup-to'. 
+       * gnus.texi (Post): Document `ask' value of
+       `gnus-use-followup-to'.  
+
+Thu Sep  7 00:20:44 1995  Lars Ingebrigtsen  <lars@eyesore.no>
+
+       * gnus.el (gnus-select-newsgroup): Checked the server twice.
+       (gnus-select-newsgroup): Wouldn't respond properly to unwell
+       groups. 
+
+Wed Sep  6 00:11:00 1995  Lars Ingebrigtsen  <lars@eyesore.no>
+
+       * gnus.el (gnus-read-old-newsrc-el-file): Didn't parse options
+       lines from the .el file. 
+       (gnus-summary-prepare-threads): When using empty make-false-root,
+       and the subject changed, that wouldn't be reflected in the summary
+       buffer.
+
+       * nnfolder.el (nnfolder-read-folder): Make absofuckinutely sure
+       that active numbers never, ever decrease.
+
+       * nnbabyl.el (nnbabyl-request-expire-articles): Remove all text
+       props. 
+       (nnbabyl-read-mbox): If an rmail buffer is in rmail mode, make it
+       ordinary. 
+
+       * gnus.el (gnus-summary-kill-thread): Did not kill hidden
+       threads. 
+
+       * gnus-uu.el (gnus-uu-save-article): Didn't remove text props.
+
+       * gnus.el (gnus-group-make-articles-read): Would not do
+       crosspostings in one obscure instance.
+       (gnus-summary-update-mark): Would compute score-markedness even
+       when setting the process mark.
+
+Tue Sep  5 21:50:33 1995  Lars Ingebrigtsen  <lars@eyesore.no>
+
+       * gnus-msg.el (gnus-inews-news): Would choke on trailing
+       commands. Also used `replace-regexp'.
+       (gnus-inews-news): Would, for some reason, fold all lines
+       sometimes. 
+
+       * gnus-ems.el: Force our definition of `set-text-properties'. So
+       there! 
+
+       * gnus.el (gnus-summary-sort-by-subject): Sorted oddly for (1/2)
+       stuff. 
+       (gnus-request-body): Had gone missing for some reason.
+       (gnus-group-exit): Would quit out of an empty group buffer without
+       confirmation.
+
+Mon Sep  4 00:44:38 1995  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * custom.el (custom-field-face): Check that the face is defined.
+       (custom-face-tag): New function.
+       (custom-group-accept): Use it.
+       (custom-group-insert): Ditto.
+       (custom-type-properties): Give `face->other' a default value.
+       (custom-facep): New function.
+       (custom-face-lookup): Use it.
+
+Sun Sep  3 19:36:29 1995  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * custom.el (custom-local-type-properties): Added extra line of
+       documentation. 
+       (custom-valid, custom-const-valid): Changed legal to valid in doc
+       string.
+       (custom-match): More documentation.
+       (custom-field-update): Doc. clarification.
+       (custom-field-accept): Ditto.
+       (custom-type-properties): More documentation.
+
+Fri Sep  1 15:39:56 1995  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * custom.el (menu-bar): Added XEmacs and Emacs 19.28 support.
+
+Fri Sep  1 15:39:56 1995  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * custom.el (plist-put): Fixed bogus definition.  
+
+Thu Aug 31 15:21:23 1995  Per Abrahamsen  <abraham@dina.kvl.dk>
+
+       * gnus-cus.el: Removed dead code.
+
 Thu Aug 31 10:45:26 1995  Lars Magne Ingebrigtsen  <lingebri@sunsci4.cern.ch>
 
+       * gnus.el: 5.0 is released.
+
        * gnus-cus.el (gnus-face-dark-name-list): Use dark blue instead of
        sky blue.
 
index 4803e61..5baa977 100644 (file)
@@ -32,7 +32,7 @@
 ;;; Todo:  
 ;;
 ;; - Toggle documentation in three states `none', `one-line', `full'.
-;; - Function to generate a XEmacs menu from a CUSTOM.
+;; - Function to generate an XEmacs menu from a CUSTOM.
 ;; - Write TeXinfo documentation.
 ;; - Make it possible to hide sections by clicking at the level.
 ;; - Declare AUC TeX variables.
 ;; - XEmacs port.
 ;; - Allow `URL', `info', and internal hypertext buttons.
 ;; - Support meta-variables and goal directed customization.
+;; - Make it easy to declare custom types independently.
+;; - Make it possible to declare default value and type for a single
+;;   variable, storing the data in a symbol property.
+;; - Syntactic sugar for CUSTOM declarations.
+;; - Use W3 for variable documenation.
 
 ;;; Code:
 
@@ -93,15 +98,19 @@ If PROP is already a property on the list, its value is set to VAL,
 otherwise the new PROP VAL pair is added.  The new plist is returned;
 use `(setq x (plist-put x prop val))' to be sure to use the new value.
 The PLIST is modified by side effects."
-      (while plist
-       (cond ((eq (car plist) prop)
-              (setcar (cdr plist) val)
-              (setq plist nil))
-             ((null (cdr (cdr plist)))
-              (setcdr (cdr plist) (list prop val))
-              (setq plist nil))
-             (t
-              (setq plist (cdr (cdr plist))))))))
+      (if (null plist)
+         (list prop val)
+       (let ((current plist))
+         (while current
+           (cond ((eq (car current) prop)
+                  (setcar (cdr current) val)
+                  (setq current nil))
+                 ((null (cdr (cdr current)))
+                  (setcdr (cdr current) (list prop val))
+                  (setq current nil))
+                 (t
+                  (setq current (cdr (cdr current)))))))
+       plist)))
 
 (or (fboundp 'match-string)
     ;; Introduced in Emacs 19.29.
@@ -126,7 +135,12 @@ STRING should be given if the last search was by `string-match' on STRING."
                (assq x (and (boundp 'global-face-data) global-face-data))))
           t)))
 
-(if (facep 'underline)
+;; XEmacs and Emacs 19.29 facep does different things.
+(if (fboundp 'find-face)
+    (fset 'custom-facep 'find-face)
+  (fset 'custom-facep 'facep))
+
+(if (custom-facep 'underline)
     ()
   ;; No underline face in XEmacs 19.12.
   (and (fboundp 'make-face)
@@ -249,12 +263,42 @@ If called interactively, prompts for a face and face attributes."
 
 ;; Put it in the Help menu, if possible.
 (if (string-match "XEmacs" emacs-version)
-    nil
-  ;; This will not work under XEmacs.
-  (condition-case nil
-      (global-set-key [ menu-bar help-menu customize ]
-                     '("Customize..." . customize))
-    (error nil)))
+    ;; XEmacs (disabled because it doesn't work)
+    (add-menu-item '("Help") "Customize..." 'customize nil)
+  ;; Emacs 19.28 and earlier
+  (global-set-key [ menu-bar help customize ]
+                 '("Customize..." . customize))
+  ;; Emacs 19.29 and later
+  (global-set-key [ menu-bar help-menu customize ] 
+                 '("Customize..." . customize)))
+
+;; XEmacs popup-menu stolen from w3.el.
+(defun custom-x-really-popup-menu (pos title menudesc)
+  "My hacked up function to do a blocking popup menu..."
+  (let ((echo-keystrokes 0)
+       event menu)
+    (while menudesc
+      (setq menu (cons (vector (car (car menudesc))
+                              (list (car (car menudesc))) t) menu)
+           menudesc (cdr menudesc)))
+    (setq menu (cons title menu))
+    (popup-menu menu)
+    (catch 'popup-done
+      (while t
+       (setq event (next-command-event event))
+       (cond ((and (misc-user-event-p event) (stringp (car-safe                                                   (event-object event))))
+              (throw 'popup-done (event-object event)))
+             ((and (misc-user-event-p event)
+                   (or (eq (event-object event) 'abort)
+                       (eq (event-object event) 'menu-no-selection-hook)))
+              nil)
+             ((not (popup-menu-up-p))
+              (throw 'popup-done nil))
+             ((button-release-event-p event);; don't beep twice
+              nil)
+             (t
+              (beep)
+              (message "please make a choice from the menu.")))))))
 
 ;;; Categories:
 ;;
@@ -401,6 +445,7 @@ hierarchy the new entry should be added.  CUSTOM is the entry to add."
 
 (defconst custom-type-properties
   '((repeat (type . default)
+           ;; See `custom-match'.
            (import . custom-repeat-import)
            (eval . custom-repeat-eval)
            (quote . custom-repeat-quote)
@@ -414,6 +459,7 @@ hierarchy the new entry should be added.  CUSTOM is the entry to add."
            (del-tag . "[DEL]")
            (add-tag . "[INS]"))
     (pair (type . group)
+         ;; A cons-cell.
          (accept . custom-pair-accept)
          (eval . custom-pair-eval)
          (import . custom-pair-import)
@@ -421,10 +467,13 @@ hierarchy the new entry should be added.  CUSTOM is the entry to add."
          (valid . (lambda (c d) (consp d)))
          (extract . custom-pair-extract))
     (list (type . group)
+         ;; A lisp list.
          (quote . custom-list-quote)
-         (valid . (lambda (c d) (listp d)))
+         (valid . (lambda (c d)
+                    (and (listp d) (not (eq custom-nil(car d))))))
          (extract . custom-list-extract))
     (group (type . default)
+          ;; See `custom-match'.
           (face-tag . nil)
           (eval . custom-group-eval)
           (import . custom-group-import)
@@ -439,6 +488,7 @@ hierarchy the new entry should be added.  CUSTOM is the entry to add."
           (insert . custom-group-insert)
           (find . custom-group-find))
     (toggle (type . choice)
+           ;; Booleans.
            (data ((type . const)
                   (tag . "On ")
                   (default . t))
@@ -446,6 +496,7 @@ hierarchy the new entry should be added.  CUSTOM is the entry to add."
                   (tag . "Off")
                   (default . nil))))
     (choice (type . default)
+           ;; See `custom-match'.
            (query . custom-choice-query)
            (accept . custom-choice-accept)
            (extract . custom-choice-extract)
@@ -455,12 +506,14 @@ hierarchy the new entry should be added.  CUSTOM is the entry to add."
                  (default . __uninitialized__)
                  (type . const)))
     (const (type . default)
+          ;; A `const' only matches a single lisp value.
           (extract . (lambda (c f) (list (custom-default c))))
           (validate . (lambda (c f) nil))
           (valid . custom-const-valid)
           (update . custom-const-update)
           (insert . custom-const-insert))
     (face-doc (type . doc)
+             ;; A variable containing a face.
              (doc . "\
 You can customize the look of Emacs by deciding which faces should be
 used when.  If you push one of the face buttons below, you will be
@@ -565,33 +618,41 @@ Select the properties you want this face to have.")
                 (type . list))
                ((prompt . "Other")
                 (face . custom-field-value)
+                (default . __uninitialized__)
                 (type . symbol))))
     (file (type . string)
+         ;; A string containing a file or directory name.
          (directory . nil)
          (default-file . nil)
          (query . custom-file-query))
     (sexp (type . default)
+         ;; Any lisp expression.
          (width . 40)
          (default . (__uninitialized__ . "Uninitialized"))
          (read . custom-sexp-read)
          (write . custom-sexp-write))
     (symbol (type . sexp)
+           ;; A lisp symbol.
            (width . 40)
            (valid . (lambda (c d) (symbolp d))))
     (integer (type . sexp)
+            ;; A lisp integer.
             (width . 10)
             (valid . (lambda (c d) (integerp d))))
     (string (type . default)
+           ;; A lisp string.
            (width . 40) 
            (valid . (lambda (c d) (stringp d)))
            (read . custom-string-read)
            (write . custom-string-write))
     (button (type . default)
+           ;; Push me.
            (accept . ignore)
            (extract . nil)
            (validate . ignore)
            (insert . custom-button-insert))
     (doc (type . default)
+        ;; A documentation only entry with no value.
         (header . nil)
         (reset . ignore)
         (extract . nil)
@@ -631,7 +692,9 @@ Select the properties you want this face to have.")
 The format is `((SYMBOL (PROPERTY . VALUE)... )... )'.")
 
 (defconst custom-local-type-properties nil
-  "Local type properties.")
+  "Local type properties.
+Entries in this list take precedence over `custom-type-properties'.")
+
 (make-variable-buffer-local 'custom-local-type-properties)
 
 (defconst custom-nil '__uninitialized__
@@ -684,6 +747,10 @@ CUSTOM must have at least one property already."
   "Extract `tag' from CUSTOM."
   (custom-property custom 'tag))
 
+(defun custom-face-tag (custom)
+  "Extract `face-tag' from CUSTOM."
+  (custom-property custom 'face-tag))
+
 (defun custom-prompt (custom)
   "Extract `prompt' from CUSTOM.  
 If none exist, default to `tag' or, failing that, `type'."
@@ -719,12 +786,16 @@ If none exist, default to `tag' or, failing that, `type'."
   (custom-property custom 'padding))
 
 (defun custom-valid (custom value)
-  "Non-nil if CUSTOM may legally be set to VALUE."
+  "Non-nil if CUSTOM may validly be set to VALUE."
   (and (not (and (listp value) (eq custom-invalid (car value))))
        (funcall (custom-property custom 'valid) custom value)))
 
 (defun custom-import (custom value)
-  "Import CUSTOM VALUE from external variable."
+  "Import CUSTOM VALUE from external variable.
+
+This function change VALUE into a form that makes it easier to edit 
+internally.  What the internal form is exactly depends on CUSTOM.  
+The internal form is returned."
   (if (eq custom-nil value)
       (list custom-nil)
     (funcall (custom-property custom 'import) custom value)))
@@ -747,16 +818,27 @@ If none exist, default to `tag' or, failing that, `type'."
         (funcall (custom-property custom 'write) custom value))))
 
 (defun custom-read (custom string)
-  "Convert CUSTOM field content STRING into external form."
+  "Convert CUSTOM field content STRING into lisp."
   (condition-case nil
       (funcall (custom-property custom 'read) custom string)
     (error (cons custom-invalid string))))
 
 (defun custom-match (custom values)
   "Match CUSTOM with a list of VALUES.
+
 Return a cons-cell where the car is the sublist of VALUES matching CUSTOM,
-and the cdr is the remaining VALUES."
+and the cdr is the remaining VALUES.
+
+A CUSTOM is actually a regular expression over the alphabet of lisp
+types.  Most CUSTOM types are just doing a literal match, e.g. the
+`symbol' type matches any lisp symbol.  The exceptions are:
+
+group:    which corresponds to a `(' and `)' group in a regular expression.
+choice:   which corresponds to a group of `|' in a regular expression.
+repeat:   which corresponds to a `*' in a regular expression.
+optional: which corresponds to a `?', and isn't implemented yet."
   (if (memq values (list custom-nil nil))
+      ;; Nothing matches the uninitialized or empty list.
       (cons custom-nil nil)
     (funcall (custom-property custom 'match) custom values)))
 
@@ -853,7 +935,7 @@ START and END are markers to the start and end of the field."
   (funcall (custom-property (custom-field-custom field) 'query) field))
 
 (defun custom-field-accept (field value &optional original)
-  "Accept FIELD VALUE.  
+  "Store a new value into field FIELD, taking it from VALUE.
 If optional ORIGINAL is non-nil, concider VALUE for the original value."
   (let ((inhibit-point-motion-hooks t))
     (funcall (custom-property (custom-field-custom field) 'accept) 
@@ -864,10 +946,11 @@ If optional ORIGINAL is non-nil, concider VALUE for the original value."
   (let ((custom (custom-field-custom field)))
     (if (stringp custom)
        nil
-      (funcall (custom-property custom 'face) field))))
+      (let ((face (funcall (custom-property custom 'face) field)))
+       (if (custom-facep face) face nil)))))
 
 (defun custom-field-update (field)
-  "Update content of FIELD."
+  "Update the screen appearance of FIELD to correspond with the field's value."
   (let ((custom (custom-field-custom field)))
     (if (stringp custom)
        nil
@@ -900,7 +983,7 @@ If optional ORIGINAL is non-nil, concider VALUE for the original value."
                           value))))
 
 (defun custom-repeat-accept (field value &optional original)
-  "Enter content of editing FIELD."
+  "Store a new value into field FIELD, taking it from VALUE."
   (let ((values (copy-sequence (custom-field-value field)))
        (all (custom-field-value field))
        (start (custom-field-start field))
@@ -1040,7 +1123,7 @@ If optional ORIGINAL is non-nil, concider VALUE for the original value."
     result))
 
 (defun custom-pair-accept (field value &optional original)
-  "Enter content of editing FIELD with VALUE."
+  "Store a new value into field FIELD, taking it from VALUE."
   (custom-group-accept field (list (car value) (cdr value)) original))
 
 (defun custom-pair-eval (custom value)
@@ -1186,11 +1269,11 @@ If optional ORIGINAL is non-nil, concider VALUE for the original value."
        (setq data (cdr data))))))
 
 (defun custom-group-accept (field value &optional original)
-  "Enter content of editing FIELD with VALUE."
+  "Store a new value into field FIELD, taking it from VALUE."
   (let* ((values (custom-field-value field))
         (custom (custom-field-custom field))
         (from (custom-field-start field))
-        (face-tag (custom-property custom 'face-tag))
+        (face-tag (custom-face-tag custom))
         current)
     (if face-tag 
        (put-text-property from (+ from (length (custom-tag custom)))
@@ -1213,7 +1296,7 @@ If optional ORIGINAL is non-nil, concider VALUE for the original value."
         (from (point))
         (compact (custom-compact custom))
         (tag (custom-tag custom))
-        (face-tag (custom-property custom 'face-tag)))
+        (face-tag (custom-face-tag custom)))
     (cond (face-tag (custom-text-insert tag))
          (tag (custom-tag-insert tag field)))
     (or compact (custom-documentation-insert custom))
@@ -1244,7 +1327,7 @@ If optional ORIGINAL is non-nil, concider VALUE for the original value."
     field))
 
 (defun custom-choice-accept (field value &optional original)
-  "Reset content of editing FIELD."
+  "Store a new value into field FIELD, taking it from VALUE."
   (let ((custom (custom-field-custom field))
        (start (custom-field-start field))
        (end (custom-field-end field))
@@ -1318,15 +1401,25 @@ If optional ORIGINAL is non-nil, concider VALUE for the original value."
        (setq current (car data)
              data (cdr data))
        (setq alist (cons (cons (custom-prompt current) current) alist)))
-      (let ((answer (if (listp last-input-event)
-                       (x-popup-menu last-input-event
-                                     (list tag (cons "" (reverse alist))))
-                     (let ((choice (completing-read (concat tag " (default "
-                                                            default "): ") 
-                                                    alist nil t)))
-                       (if (or (null choice) (string-equal choice ""))
-                           (setq choice default))
-                       (cdr (assoc choice alist))))))
+      (let ((answer (cond ((and (fboundp 'button-press-event-p)
+                               (fboundp 'popup-menu)
+                               (button-press-event-p last-input-event))
+                          (cdr (assoc (car (custom-x-really-popup-menu 
+                                            last-input-event tag 
+                                            (reverse alist)))
+                                      alist)))
+                         ((listp last-input-event)
+                          (x-popup-menu last-input-event
+                                        (list tag (cons "" (reverse alist)))))
+                         (t 
+                          (let ((choice (completing-read (concat tag
+                                                                 " (default "
+                                                                 default 
+                                                                 "): ") 
+                                                         alist nil t)))
+                            (if (or (null choice) (string-equal choice ""))
+                                (setq choice default))
+                            (cdr (assoc choice alist)))))))
        (if answer
            (custom-field-accept field (custom-default answer)))))))
 
@@ -1378,7 +1471,7 @@ FG BG STIPPLE BOLD ITALIC UNDERLINE"
                              (or bg "default")
                              (or stipple "default")
                              bold italic underline))))
-    (if (and (facep name)
+    (if (and (custom-facep name)
             (fboundp 'make-face))
        ()
       (make-face name)
@@ -1391,8 +1484,10 @@ FG BG STIPPLE BOLD ITALIC UNDERLINE"
 
 (defun custom-face-hack (field value)
   "Face that should be used for highlighting FIELD containing VALUE."
-  (let ((custom (custom-field-custom field)))
-    (eval (funcall (custom-property custom 'export) custom value))))
+  (let* ((custom (custom-field-custom field))
+        (face (eval (funcall (custom-property custom 'export) 
+                             custom value))))
+    (if (custom-facep face) face nil)))
 
 (defun custom-const-insert (custom level)
   "Insert field for CUSTOM at nesting LEVEL in customization buffer."
@@ -1415,7 +1510,7 @@ FG BG STIPPLE BOLD ITALIC UNDERLINE"
                       'face (custom-field-face field))))
 
 (defun custom-const-valid (custom value)
-  "Non-nil if CUSTOM can legally have the value VALUE."
+  "Non-nil if CUSTOM can validly have the value VALUE."
   (equal (custom-default custom) value))
 
 (defun custom-const-face (field)
@@ -1470,6 +1565,7 @@ FG BG STIPPLE BOLD ITALIC UNDERLINE"
 
 (defun custom-default-export (custom value)
   ;; Convert CUSTOM's VALUE to external representation.
+  ;; See `custom-import'.
   (if (custom-eval custom value)
       (eval (car (custom-quote custom value)))
     value))
@@ -1516,7 +1612,7 @@ FG BG STIPPLE BOLD ITALIC UNDERLINE"
     field))
 
 (defun custom-default-accept (field value &optional original)
-  "Enter into FIELD the value VALUE."
+  "Store a new value into field FIELD, taking it from VALUE."
   (if original 
       (custom-field-original-set field value))
   (custom-field-value-set field value)
@@ -2050,8 +2146,7 @@ If the optional argument is non-nil, show text iff the argument is positive."
      from (point)
      (list 'custom-field field
           'custom-tag field
-          'face (let ((face (custom-field-face field)))
-                  (if (facep face) face nil))
+          'face (custom-field-face field)
           front-sticky t))))
 
 (defun custom-field-read (field)
@@ -2060,6 +2155,10 @@ If the optional argument is non-nil, show text iff the argument is positive."
               (buffer-substring-no-properties (custom-field-start field)
                                               (custom-field-end field))))
 
+;; Fields are shown in a special `active' face when point is inside
+;; it.  You activate the field by moving point inside (entering) it
+;; and deactivate the field by moving point outside (leaving) it.
+
 (defun custom-field-leave (field)
   ;; Deactivate FIELD.
   (let ((before-change-functions nil)
@@ -2095,11 +2194,12 @@ If the optional argument is non-nil, show text iff the argument is positive."
         (size (- end begin)))
     (cond ((< size width)
           (goto-char end)
-          (condition-case nil
+          (if (fboundp 'insert-before-markers-and-inherit)
+              ;; Emacs 19.
               (insert-before-markers-and-inherit
                (make-string (- width size) padding))
-            (error (insert-before-markers
-                    (make-string (- width size) padding))))
+            ;; XEmacs:  BUG:  Doesn't work!
+            (insert-before-markers (make-string (- width size) padding)))
           (goto-char pos))
          ((> size width)
           (let ((start (if (and (< (+ begin width) pos) (<= pos end))
@@ -2111,7 +2211,8 @@ If the optional argument is non-nil, show text iff the argument is positive."
             (goto-char pos))))))
 
 (defvar custom-field-changed nil)
-;; List of fields changed on the screen.
+;; List of fields changed on the screen but whose VALUE attribute has
+;; not yet been updated to reflect the new screen content.
 (make-variable-buffer-local 'custom-field-changed)
 
 (defun custom-field-parse (field)
index a9458e1..74120c7 100644 (file)
 
 ;;; Customization:
 
+(defvar gnus-cite-parse-max-size 25000
+  "Maximum article size (in bytes) where parsing citations is allowed.
+Set it to nil to parse all articles.")
+
 (defvar gnus-cite-prefix-regexp 
     "^[]>|:}+ ]*[]>|:}+]\\(.*>\\)?\\|^.*>"
   "Regexp matching the longest possible citation prefix on a line.")
@@ -133,7 +137,7 @@ The text matching the first grouping will be used as a button.")
 
 ;;; Commands:
 
-(defun gnus-article-highlight-citation ()
+(defun gnus-article-highlight-citation (&optional force)
   "Highlight cited text.
 Each citation in the article will be highlighted with a different face.
 The faces are taken from `gnus-cite-face-list'.
@@ -145,7 +149,7 @@ lines matches `gnus-cite-prefix-regexp' with the same prefix.
 
 Lines matching `gnus-cite-attribution-postfix' and perhaps
 `gnus-cite-attribution-prefix' are considered attribution lines."
-  (interactive)
+  (interactive (list 'force))
   ;; Create dark or light faces if necessary.
   (cond ((eq gnus-cite-face-list 'light)
         (setq gnus-cite-face-list
@@ -155,7 +159,7 @@ Lines matching `gnus-cite-attribution-postfix' and perhaps
               (mapcar 'gnus-make-face gnus-face-dark-name-list))))
   (save-excursion
     (set-buffer gnus-article-buffer)
-    (gnus-cite-parse-maybe)
+    (gnus-cite-parse-maybe force)
     (let ((buffer-read-only nil)
          (alist gnus-cite-prefix-alist)
          (faces gnus-cite-face-list)
@@ -204,13 +208,13 @@ Lines matching `gnus-cite-attribution-postfix' and perhaps
              skip (gnus-cite-find-prefix number))
        (gnus-cite-add-face number skip gnus-cite-attribution-face)))))
 
-(defun gnus-article-hide-citation ()
+(defun gnus-article-hide-citation (&optional force)
   "Hide all cited text except attribution lines.
 See the documentation for `gnus-article-highlight-citation'."
-  (interactive)
+  (interactive (list 'force))
   (save-excursion
     (set-buffer gnus-article-buffer)
-    (gnus-cite-parse-maybe)
+    (gnus-cite-parse-maybe force)
     (let ((buffer-read-only nil)
          (alist gnus-cite-prefix-alist)
          (inhibit-point-motion-hooks t)
@@ -236,7 +240,7 @@ See also the documentation for `gnus-article-highlight-citation'."
   (interactive (list 'force))
   (save-excursion
     (set-buffer gnus-article-buffer)
-    (gnus-cite-parse-maybe)
+    (gnus-cite-parse-maybe force)
     (goto-char (point-min))
     (search-forward "\n\n")
     (let ((start (point))
@@ -271,19 +275,26 @@ See also the documentation for `gnus-article-highlight-citation'."
 
 ;;; Internal functions:
 
-(defun gnus-cite-parse-maybe ()
+(defun gnus-cite-parse-maybe (&optional force)
   ;; Parse if the buffer has changes since last time.
   (if (eq gnus-article-length (- (point-max) (point-min)))
       ()
-    (setq gnus-article-length (- (point-max) (point-min)))
-    (gnus-cite-parse)))
+    ;;Reset parser information.
+    (setq gnus-cite-prefix-alist nil
+         gnus-cite-attribution-alist nil
+         gnus-cite-loose-prefix-alist nil
+         gnus-cite-loose-attribution-alist nil)
+    ;; Parse if not too large.
+    (if (and (not force) 
+            gnus-cite-parse-max-size
+            (> (buffer-size) gnus-cite-parse-max-size))
+       ()
+      (setq gnus-article-length (- (point-max) (point-min)))
+      (gnus-cite-parse))))
 
 (defun gnus-cite-parse ()
   ;; Parse and connect citation prefixes and attribution lines.
-  (setq gnus-cite-prefix-alist nil
-       gnus-cite-attribution-alist nil
-        gnus-cite-loose-prefix-alist nil
-        gnus-cite-loose-attribution-alist nil)
+  
   ;; Parse current buffer searching for citation prefixes.
   (goto-char (point-min))
   (or (search-forward "\n\n" nil t)
@@ -345,7 +356,8 @@ See also the documentation for `gnus-article-highlight-citation'."
             (setq gnus-cite-prefix-alist
                   (cons entry gnus-cite-prefix-alist)))
            (t
-            (setq gnus-cite-prefix-alist (cons entry gnus-cite-prefix-alist))
+            (setq gnus-cite-prefix-alist (cons entry
+                                               gnus-cite-prefix-alist))
             ;; Remove articles from other prefixes.
             (let ((loop alist)
                   current)
@@ -391,16 +403,21 @@ See also the documentation for `gnus-article-highlight-citation'."
   (gnus-cite-match-attributions 'small nil
                                (lambda (prefix tag)
                                  (if tag
-                                     (concat "\\`" (regexp-quote prefix) "[ \t]*" 
+                                     (concat "\\`" 
+                                             (regexp-quote prefix) "[ \t]*" 
                                              (regexp-quote tag) ">"))))
   ;; Find loose supercite citations after attributions.
   (gnus-cite-match-attributions 'small t
                                (lambda (prefix tag)
-                                 (if tag (concat "\\<" (regexp-quote tag) "\\>"))))
+                                 (if tag (concat "\\<"
+                                                 (regexp-quote tag)
+                                                 "\\>"))))
   ;; Find loose supercite citations anywhere.
   (gnus-cite-match-attributions 'small nil
                                (lambda (prefix tag)
-                                 (if tag (concat "\\<" (regexp-quote tag) "\\>"))))
+                                 (if tag (concat "\\<"
+                                                 (regexp-quote tag)
+                                                 "\\>"))))
   ;; Find nested citations after attributions.
   (gnus-cite-match-attributions 'small-if-unique t
                                (lambda (prefix tag)
index ad7c414..78354db 100644 (file)
     "turquoise"))
 
 (defvar gnus-face-dark-name-list
-  '("dark blue" "firebrick"
-    "dark green" "dark orange" "dark khaki" "dark violet"
-    "dark turquoise"))
+  '("RoyalBlue" "firebrick"
+    "dark green" "OrangeRed" "dark khaki" "dark violet"
+    "SteelBlue4"))
+; CornflowerBlue SeaGreen OrangeRed SteelBlue4 DeepPink3
+; DarkOlviveGreen4 
 
 (custom-declare '()
   '((tag . "GNUS")
@@ -67,7 +69,6 @@ WWW Browser to call when clicking on an URL button in the article buffer.
 
 You can choose between one of the predefined browsers, or `Other'.")
                  (name . gnus-button-url)
-                 (default . w3-fetch)
                  (calculate . (cond ((boundp 'browse-url-browser-function)
                                      browse-url-browser-function)
                                     ((fboundp 'w3-fetch) 
index 928b4a4..35d97c5 100644 (file)
@@ -131,7 +131,7 @@ pounce directly on the real variables themselves."))
       ;; portable!
       (or (face-differs-from-default-p 'underline)
          (funcall 'set-face-underline-p 'underline t))
-      (or (fboundp 'set-text-properties)
+      ; (or (fboundp 'set-text-properties) Fuckit!
          (defun set-text-properties (start end props &optional buffer)
            (if (or (null buffer) (bufferp buffer))
                (if props
@@ -139,7 +139,7 @@ pounce directly on the real variables themselves."))
                      (put-text-property 
                       start end (car props) (nth 1 props) buffer)
                      (setq props (nthcdr 2 props)))
-                 (remove-text-properties start end ())))))
+                 (remove-text-properties start end ()))))
 
       (defalias 'gnus-make-overlay 'make-extent)
       (defalias 'gnus-overlay-put 'set-extent-property)
index b1d9b88..3692c20 100644 (file)
@@ -80,6 +80,7 @@ Optional argument FOLDER specifies folder name."
 Optional argument YANK means yank original article.
 The command \\[mh-yank-cur-msg] yank the original message into current buffer."
   (let (from cc subject date to reply-to to-userid orig-to
+            references message-id
             (config (current-window-configuration))
             buffer)
     (pop-to-buffer gnus-article-buffer)
@@ -101,7 +102,9 @@ The command \\[mh-yank-cur-msg] yank the original message into current buffer."
              reply-to (gnus-fetch-field "reply-to")
              cc (gnus-fetch-field "cc")
              orig-to (or (gnus-fetch-field "to") "")
-             date (gnus-fetch-field "date"))
+             date (gnus-fetch-field "date")
+             references (gnus-fetch-field "references")
+             message-id (gnus-fetch-field "message-id"))
        (setq to (or reply-to from))
        (setq to-userid (mail-strip-quoted-names orig-to))
        (if (or (string-match "," orig-to)
@@ -135,7 +138,8 @@ The command \\[mh-yank-cur-msg] yank the original message into current buffer."
        "In-reply-to:"
        (concat
        (substring from 0 (string-match "  *at \\|  *@ \\| *(\\| *<" from))
-       "'s message of " date)))
+       "'s message of " date))
+      (nnheader-insert-references references message-id))
 
     ;; need this for mh-yank-cur-msg
     (setq mh-sent-from-folder buffer)
index 6db6e2f..d3b018b 100644 (file)
@@ -45,11 +45,11 @@ newsgroup name. (In that case, `gnus-signature-file' and
 If you want to insert the signature, you might put
 `gnus-inews-insert-signature' in this hook.")
 
-(defvar gnus-use-followup-to 'use
+(defvar gnus-use-followup-to t
   "*Specifies what to do with Followup-To header.
 If nil, ignore the header. If it is t, use its value, but ignore 
-`poster'. If it is neither nil nor t, which is the default, always use
-the value.") 
+`poster'.  If it is the symbol `ask', query the user before posting.
+If it is the symbol `use', always use the value.") 
 
 (defvar gnus-followup-to-function nil
   "*A variable that contains a function that returns a followup address.
@@ -298,7 +298,7 @@ If prefix argument YANK is non-nil, original article is yanked automatically."
     (set-buffer gnus-article-buffer)
     (if (and gnus-use-followup-to
             (string-equal "poster" (gnus-fetch-field "followup-to"))
-            (or (not (eq gnus-use-followup-to t))
+            (or (not (memq gnus-use-followup-to '(t ask)))
                 (not (gnus-y-or-n-p 
                       "Do you want to ignore `Followup-To: poster'? "))))
        ;; Mail to the poster. 
@@ -431,8 +431,9 @@ Type \\[describe-mode] in the buffer to get a list of commands."
             (not gnus-expert-user)
             post (not group)
             (progn
-              (setq group 
-                    (completing-read "Group: " gnus-active-hashtb))
+              (setq gnus-newsgroup-name
+                    (setq group 
+                          (completing-read "Group: " gnus-active-hashtb)))
               (or subject
                   (setq subject (read-string "Subject: ")))))
        (setq mail-reply-buffer gnus-article-copy)
@@ -574,17 +575,24 @@ will attempt to use the foreign server to post the article."
        ;; Correct newsgroups field: change sequence of spaces to comma and 
        ;; eliminate spaces around commas.  Eliminate imbedded line breaks.
        (goto-char (point-min))
-       (if (search-forward-regexp "^Newsgroups: +" nil t)
+       (if (re-search-forward "^Newsgroups: +" nil t)
            (save-restriction
              (narrow-to-region
               (point)
-              (if (re-search-forward "^[^ \t]" nil 'end)
+              (if (re-search-forward "^[^ \t]" nil t)
                   (match-beginning 0)
-                (point-max)))
+                (forward-line 1)
+                (point)))
              (goto-char (point-min))
-             (replace-regexp "\n[ \t]+" " ") ;No line breaks (too confusing)
+             (while (re-search-forward "\n[ \t]+" nil t)
+               (replace-match " " t t)) ;No line breaks (too confusing)
              (goto-char (point-min))
-             (replace-regexp "[ \t\n]*,[ \t\n]*\\|[ \t]+" ",")))
+             (while (re-search-forward "[ \t\n]*,[ \t\n]*\\|[ \t]+" nil t)
+               (replace-match "," t t))
+             (goto-char (point-min))
+             ;; Remove a trailing comma.
+             (if (re-search-forward ",$" nil t)
+                 (replace-match "" t t))))
 
        ;; Added by Per Abrahamsen <abraham@iesd.auc.dk>.
        ;; Help save the the world!
@@ -593,7 +601,8 @@ will attempt to use the foreign server to post the article."
         (let ((newsgroups (mail-fetch-field "newsgroups"))
               (followup-to (mail-fetch-field "followup-to"))
               groups to)
-          (if (and (string-match "," newsgroups) (not followup-to))
+          (if (and newsgroups
+                   (string-match "," newsgroups) (not followup-to))
               (progn
                 (while (string-match "," newsgroups)
                   (setq groups
@@ -1539,17 +1548,7 @@ mailer."
              (while follow-to
                (insert (car (car follow-to)) ": " (cdr (car follow-to)) "\n")
                (setq follow-to (cdr follow-to)))))
-       ;; Fold long references line to follow RFC1036.
-       (mail-position-on-field "References")
-       (let ((begin (- (point) (length "References: ")))
-             (fill-column 78)
-             (fill-prefix "\t"))
-         (if references (insert references))
-         (if (and references message-id) (insert " "))
-         (if message-id (insert message-id))
-         ;; The region must end with a newline to fill the region
-         ;; without inserting extra newline.
-         (fill-region-as-paragraph begin (1+ (point))))
+       (nnheader-insert-references references message-id)
        (goto-char (point-min))
        (re-search-forward
         (concat "^" (regexp-quote mail-header-separator) "$"))
index fdf8816..3836528 100644 (file)
@@ -360,8 +360,10 @@ If optional argument `SILENT' is nil, show effect of score entry."
   ;; Regexp is the default type.
   (if (eq type t) (setq type 'r))
   ;; Simplify matches...
-  (if (or (eq type 'r) (eq type 's) (eq type nil))
-      (setq match (gnus-simplify-subject-re match)))
+  (cond ((or (eq type 'r) (eq type 's) (eq type nil))
+        (setq match (if match (gnus-simplify-subject-re match) "")))
+       ((eq type 'f)
+        (setq match (gnus-simplify-subject-fuzzy match))))
   (let ((score (gnus-score-default score))
        (header (downcase header)))
     (and prompt (setq match (read-string 
@@ -390,9 +392,6 @@ If optional argument `SILENT' is nil, show effect of score entry."
       (and (= score gnus-score-interactive-default-score)
           (setq score nil))
       (let ((new (cond 
-                 ((eq type 'f)
-                  (list (gnus-simplify-subject-fuzzy match)
-                        score (and date (gnus-day-number date)) type))
                  (type
                   (list match score (and date (gnus-day-number date)) type))
                  (date
@@ -775,7 +774,9 @@ SCORE is the score to add."
              (if (zerop (buffer-size))
                  (delete-file file)
                ;; There are scores, so we write the file. 
-               (write-region (point-min) (point-max) file nil 'silent))))))
+               (and (file-writable-p file)
+                    (write-region (point-min) (point-max) 
+                                  file nil 'silent)))))))
       (kill-buffer (current-buffer)))))
   
 (defun gnus-score-headers (score-files &optional trace)
index 1daea47..47c08a7 100644 (file)
@@ -677,6 +677,10 @@ The headers will be included in the sequence they are matched.")
        (save-excursion
          (save-restriction
            (set-buffer buffer)
+           (set-text-properties (point-min) (point-max) nil)
+           ;; These two are necessary for XEmacs 19.12 fascism.
+           (put-text-property (point-min) (point-max) 'invisible nil)
+           (put-text-property (point-min) (point-max) 'intangible nil)
            (goto-char (point-min))
            (re-search-forward "\n\n")
            (setq body (buffer-substring (1- (point)) (point-max)))
index 3d23bd9..85479a4 100644 (file)
 (require 'gnus-ems)
 (require gnus-easymenu)
 (require 'custom)
+
+(defvar gnus-group-menu-hook nil
+  "*Hook run after the creation of the group mode menu.")
+
+(defvar gnus-summary-menu-hook nil
+  "*Hook run after the creation of the summary mode menu.")
+
+(defvar gnus-article-menu-hook nil
+  "*Hook run after the creation of the article mode menu.")
+
+(defvar gnus-server-menu-hook nil
+  "*Hook run after the creation of the server mode menu.")
+
+(defvar gnus-browse-menu-hook nil
+  "*Hook run after the creation of the browse mode menu.")
   
 ;;; Summary highlights.
 
@@ -329,7 +344,8 @@ variable it the real callback function.")
        ["Send a bug report" gnus-bug t]
        ["Send a mail" gnus-group-mail t]
        ["Post an article" gnus-group-post-news t]
-       ["Customize score file" gnus-score-customize (not (string-match "XEmacs" emacs-version)) ]
+       ["Customize score file" gnus-score-customize 
+        (not (string-match "XEmacs" emacs-version)) ]
        ["Check for new news" gnus-group-get-new-news t]     
        ["Delete bogus groups" gnus-group-check-bogus-groups t]
        ["Find new newsgroups" gnus-find-new-newsgroups t]
@@ -348,6 +364,7 @@ variable it the real callback function.")
        ["Edit global kill file" gnus-group-edit-global-kill t]
        ["Sort group buffer" gnus-group-sort-groups t]
        ))
+     (run-hooks 'gnus-group-menu-hook)
      )))
 
 ;; Server mode
@@ -355,42 +372,49 @@ variable it the real callback function.")
   (gnus-visual-turn-off-edit-menu 'server)
   (or
    (boundp 'gnus-server-menu)
-   (easy-menu-define
-    gnus-server-menu
-    gnus-server-mode-map
-    ""
-    '("Server"
-      ["Add" gnus-server-add-server t]
-      ["Browse" gnus-server-read-server t]
-      ["List" gnus-server-list-servers t]
-      ["Kill" gnus-server-kill-server t]
-      ["Yank" gnus-server-yank-server t]
-      ["Copy" gnus-server-copy-server t]
-      ["Edit" gnus-server-edit-server t]
-      ["Exit" gnus-server-exit t]
-      ))))
+   (progn
+     (easy-menu-define
+      gnus-server-menu
+      gnus-server-mode-map
+      ""
+      '("Server"
+       ["Add" gnus-server-add-server t]
+       ["Browse" gnus-server-read-server t]
+       ["List" gnus-server-list-servers t]
+       ["Kill" gnus-server-kill-server t]
+       ["Yank" gnus-server-yank-server t]
+       ["Copy" gnus-server-copy-server t]
+       ["Edit" gnus-server-edit-server t]
+       ["Exit" gnus-server-exit t]
+       ))
+     (run-hooks 'gnus-server-menu-hook)
+     )))
 
 ;; Browse mode
 (defun gnus-browse-make-menu-bar ()
   (gnus-visual-turn-off-edit-menu 'browse)
   (or
    (boundp 'gnus-browse-menu)
-   (easy-menu-define
-    gnus-browse-menu
-    gnus-browse-mode-map
-    ""
-    '("Browse"
-      ["Subscribe" gnus-browse-unsubscribe-current-group t]
-      ["Read" gnus-group-read-group t]
-      ["Exit" gnus-browse-exit t]
-      ))))
+   (progn
+     (easy-menu-define
+      gnus-browse-menu
+      gnus-browse-mode-map
+      ""
+      '("Browse"
+       ["Subscribe" gnus-browse-unsubscribe-current-group t]
+       ["Read" gnus-group-read-group t]
+       ["Exit" gnus-browse-exit t]
+       ))
+      (run-hooks 'gnus-browse-menu-hook)
+      )))
+
 
 ;; Summary buffer
 (defun gnus-summary-make-menu-bar ()
   (gnus-visual-turn-off-edit-menu 'summary)
 
   (or
-   (boundp 'gnus-summary-mark-menu)
+   (boundp 'gnus-summary-misc-menu)
    (progn
 
      (easy-menu-define
@@ -657,6 +681,7 @@ variable it the real callback function.")
        ["Fetch article with id..." gnus-summary-refer-article t]
        ["Redisplay" gnus-summary-show-article t]))
 
+
         
      (easy-menu-define
       gnus-summary-thread-menu
@@ -695,7 +720,7 @@ variable it the real callback function.")
        ["Reply & followup and yank" gnus-summary-followup-and-reply-with-original t]
        ["Uuencode and post" gnus-uu-post-news t]
        ))
-
+     (run-hooks 'gnus-summary-menu-hook)
      )))
 
 (defun gnus-score-set-default (var value)
@@ -871,6 +896,7 @@ If nil, the user will be asked for a duration.")
        ["Remove carriage return" gnus-article-remove-cr t]
        ["Remove quoted-unreadable" gnus-article-de-quoted-unreadable t]
        ))
+     (run-hooks 'gnus-article-menu-hook)
      )))
 
 ;;;
@@ -1153,36 +1179,36 @@ call it with the value of the `gnus-data' text property."
          (goto-char pos)
        (error "No buttons found")))))
 
-(defun gnus-article-highlight ()
+(defun gnus-article-highlight (&optional force)
   "Highlight current article.
 This function calls `gnus-article-highlight-headers',
 `gnus-article-highlight-citation', 
 `gnus-article-highlight-signature', and `gnus-article-add-buttons' to
 do the highlighting.  See the documentation for those functions."
-  (interactive)
+  (interactive (list 'force))
   (gnus-article-highlight-headers)
-  (gnus-article-highlight-citation)
+  (gnus-article-highlight-citation force)
   (gnus-article-highlight-signature)
-  (gnus-article-add-buttons))
+  (gnus-article-add-buttons force))
 
-(defun gnus-article-highlight-some ()
+(defun gnus-article-highlight-some (&optional force)
   "Highlight current article.
 This function calls `gnus-article-highlight-headers',
 `gnus-article-highlight-signature', and `gnus-article-add-buttons' to
 do the highlighting.  See the documentation for those functions."
-  (interactive)
+  (interactive (list 'force))
   (gnus-article-highlight-headers)
   (gnus-article-highlight-signature)
   (gnus-article-add-buttons))
 
-(defun gnus-article-hide ()
+(defun gnus-article-hide (&optional force)
   "Hide current article.
 This function calls `gnus-article-hide-headers',
 `gnus-article-hide-citation-maybe', and `gnus-article-hide-signature'
 to do the hiding.  See the documentation for those functions." 
-  (interactive)
+  (interactive (list 'force))
   (gnus-article-hide-headers)
-  (gnus-article-hide-citation-maybe)
+  (gnus-article-hide-citation-maybe force)
   (gnus-article-hide-signature))
 
 (defun gnus-article-highlight-headers ()
@@ -1260,19 +1286,19 @@ It does this by making everything after `gnus-signature-separator' invisible."
           (add-text-properties (match-end 0) (point-max)
                                gnus-hidden-properties)))))
 
-(defun gnus-article-add-buttons ()
+(defun gnus-article-add-buttons (&optional force)
   "Find external references in article and make them to buttons.
 
 External references are things like message-ids and URLs, as specified by 
 `gnus-button-alist'."
-  (interactive)
+  (interactive (list 'force))
   (if (eq gnus-button-last gnus-button-alist)
       ()
     (setq gnus-button-regexp (mapconcat 'car gnus-button-alist  "\\|")
          gnus-button-last gnus-button-alist))
   (save-excursion
     (set-buffer gnus-article-buffer)
-    (gnus-cite-parse-maybe)
+    (gnus-cite-parse-maybe force)
     (let ((buffer-read-only nil)
          (inhibit-point-motion-hooks t)
          (case-fold-search t))
index bdca7bd..6e1a8d7 100644 (file)
@@ -33,6 +33,8 @@
 
 ;;; Code:
 
+(eval '(run-hooks 'gnus-load-hook))
+
 (require 'mail-utils)
 (require 'timezone)
 (require 'nnheader)
@@ -82,12 +84,23 @@ If stringp, use this; if non-nil, use no host name (user name only).")
 
 ;; Customization variables
 
+;; Don't touch this variable.
+(defvar gnus-nntp-service "nntp"
+  "*NNTP service name (\"nntp\" or 119).
+This is an obsolete variable, which is scarcely used. If you use an
+nntp server for your newsgroup and want to change the port number
+used to 899, you would say something along these lines:
+
+ (setq gnus-select-method '(nntp \"my.nntp.server\" (nntp-port-number 899)))")
+
 (defvar gnus-select-method 
-  (list 'nntp (or (getenv "NNTPSERVER") 
-                 (if (and gnus-default-nntp-server
-                          (not (string= gnus-default-nntp-server "")))
-                     gnus-default-nntp-server)
-                 (system-name)))
+  (nconc
+   (list 'nntp (or (getenv "NNTPSERVER") 
+                  (if (and gnus-default-nntp-server
+                           (not (string= gnus-default-nntp-server "")))
+                      gnus-default-nntp-server)
+                  (system-name)))
+   (if (equal gnus-nntp-service "nntp") nil (list gnus-nntp-service)))
   "*Default method for selecting a newsgroup.
 This variable should be a list, where the first element is how the
 news is to be fetched, the second is the address. 
@@ -146,14 +159,6 @@ non-numeric prefix - `C-u M-x gnus', in short.")
 This variable is semi-obsolete. Use the `gnus-select-method'
 variable instead.")
 
-(defvar gnus-nntp-service "nntp"
-  "*NNTP service name (\"nntp\" or 119).
-This is an obsolete variable, which is scarcely used. If you use an
-nntp server for your newsgroup and want to change the port number
-used to 899, you would say something along these lines:
-
- (setq gnus-select-method '(nntp \"my.nntp.server\" (nntp-port-number 899)))")
-
 (defvar gnus-startup-file "~/.newsrc"
   "*Your `.newsrc' file.
 `.newsrc-SERVER' will be used instead if that exists.")
@@ -1086,6 +1091,9 @@ It calls `gnus-summary-expire-articles' by default.")
 (defvar gnus-open-server-hook nil
   "*A hook called just before opening connection to the news server.")
 
+(defvar gnus-load-hook nil
+  "*A hook run while Gnus is loaded.")
+
 (defvar gnus-startup-hook nil
   "*A hook called at startup.
 This hook is called after Gnus is connected to the NNTP server.")
@@ -1343,7 +1351,7 @@ variable (string, integer, character, etc).")
   "gnus-bug@ifi.uio.no (The Gnus Bugfixing Girls + Boys)"
   "The mail address of the Gnus maintainers.")
 
-(defconst gnus-version "Gnus v5.0"
+(defconst gnus-version "Gnus v5.0.1"
   "Version number for this version of Gnus.")
 
 (defvar gnus-info-nodes
@@ -3069,8 +3077,10 @@ Note: LIST has to be sorted over `<'."
   (define-key gnus-group-mode-map "\177" 'gnus-group-prev-unread-group)
   (define-key gnus-group-mode-map "N" 'gnus-group-next-group)
   (define-key gnus-group-mode-map "P" 'gnus-group-prev-group)
-  (define-key gnus-group-mode-map "\M-n" 'gnus-group-next-unread-group-same-level)
-  (define-key gnus-group-mode-map "\M-p" 'gnus-group-prev-unread-group-same-level)
+  (define-key gnus-group-mode-map
+    "\M-n" 'gnus-group-next-unread-group-same-level)
+  (define-key gnus-group-mode-map 
+    "\M-p" 'gnus-group-prev-unread-group-same-level)
   (define-key gnus-group-mode-map "," 'gnus-group-best-unread-group)
   (define-key gnus-group-mode-map "." 'gnus-group-first-unread-group)
   (define-key gnus-group-mode-map "u" 'gnus-group-unsubscribe-current-group)
@@ -4221,7 +4231,8 @@ ADDRESS."
     (gnus-group-make-group 
      (gnus-group-real-name name)
      (list 'nndoc name
-          (list 'nndoc-address (concat (file-name-as-directory (car path)) "doc.txt"))
+          (list 'nndoc-address 
+                (concat (file-name-as-directory (car path)) "doc.txt"))
           (list 'nndoc-article-type 'mbox))))
   (gnus-group-position-cursor))
 
@@ -4252,7 +4263,7 @@ ADDRESS."
 (defun gnus-group-make-archive-group (&optional all)
   "Create the (ding) Gnus archive group of the most recent articles.
 Given a prefix, create a full group."
-  (interactive)
+  (interactive "P")
   (let ((group (gnus-group-prefixed-name 
                (if all "ding.archives" "ding.recent") '(nndir ""))))
     (and (gnus-gethash group gnus-newsrc-hashtb)
@@ -4519,28 +4530,31 @@ New newsgroup is added to .newsrc automatically."
          "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.
-          (gnus-group-change-level 
-           newsrc (if level level (if (<= (nth 1 (nth 2 newsrc)) 
-                                          gnus-level-subscribed) 
-                                      (1+ gnus-level-subscribed)
-                                    gnus-level-default-subscribed)))
-          (gnus-group-update-group group))
-         ((and (stringp group)
-               (or (not (memq gnus-select-method gnus-have-read-active-file))
-                   (gnus-gethash group gnus-active-hashtb)))
-          ;; Add new newsgroup.
-          (gnus-group-change-level 
-           group 
-           (if level level gnus-level-default-subscribed) 
-           (or (and (member group gnus-zombie-list) 
-                    gnus-level-zombie) 
-               gnus-level-killed)
-           (and (gnus-group-group-name)
-                (gnus-gethash (gnus-group-group-name) gnus-newsrc-hashtb)))
-          (gnus-group-update-group group))
-         (t (error "No such newsgroup: %s" group)))
+    (cond
+     ((string-match "^[ \t]$" group)
+      (error "Empty group name"))
+     (newsrc
+      ;; Toggle subscription flag.
+      (gnus-group-change-level 
+       newsrc (if level level (if (<= (nth 1 (nth 2 newsrc)) 
+                                     gnus-level-subscribed) 
+                                 (1+ gnus-level-subscribed)
+                               gnus-level-default-subscribed)))
+      (gnus-group-update-group group))
+     ((and (stringp group)
+          (or (not (memq gnus-select-method gnus-have-read-active-file))
+              (gnus-gethash group gnus-active-hashtb)))
+      ;; Add new newsgroup.
+      (gnus-group-change-level 
+       group 
+       (if level level gnus-level-default-subscribed) 
+       (or (and (member group gnus-zombie-list) 
+               gnus-level-zombie) 
+          gnus-level-killed)
+       (and (gnus-group-group-name)
+           (gnus-gethash (gnus-group-group-name) gnus-newsrc-hashtb)))
+      (gnus-group-update-group group))
+     (t (error "No such newsgroup: %s" group)))
     (gnus-group-position-cursor)))
 
 (defun gnus-group-transpose-groups (n)
@@ -4869,9 +4883,10 @@ If GROUP, edit that local kill file instead."
   (interactive "P")
   (setq gnus-current-kill-article article)
   (gnus-kill-file-edit-file group)
-  (gnus-message 6
-               (substitute-command-keys
-                "Editing a global kill file (Type \\[gnus-kill-file-exit] to exit)")))
+  (gnus-message 
+   6
+   (substitute-command-keys
+    "Editing a global kill file (Type \\[gnus-kill-file-exit] to exit)")))
 
 (defun gnus-group-edit-local-kill (article group)
   "Edit a local kill file."
@@ -4914,7 +4929,6 @@ The hook gnus-suspend-gnus-hook is called before actually suspending."
 The hook `gnus-exit-gnus-hook' is called before actually exiting."
   (interactive)
   (if (or noninteractive               ;For gnus-batch-kill
-         (zerop (buffer-size))         ;No news is good news.
          (not (gnus-server-opened gnus-select-method)) ;NNTP connection closed
          (not gnus-interactive-exit)   ;Without confirmation
          gnus-expert-user
@@ -5265,8 +5279,10 @@ buffer.
   (define-key gnus-summary-mode-map "\M-p" 'gnus-summary-prev-unread-subject)
   (define-key gnus-summary-mode-map "." 'gnus-summary-first-unread-article)
   (define-key gnus-summary-mode-map "," 'gnus-summary-best-unread-article)
-  (define-key gnus-summary-mode-map "\M-s" 'gnus-summary-search-article-forward)
-  (define-key gnus-summary-mode-map "\M-r" 'gnus-summary-search-article-backward)
+  (define-key gnus-summary-mode-map 
+    "\M-s" 'gnus-summary-search-article-forward)
+  (define-key gnus-summary-mode-map 
+    "\M-r" 'gnus-summary-search-article-backward)
   (define-key gnus-summary-mode-map "<" 'gnus-summary-beginning-of-article)
   (define-key gnus-summary-mode-map ">" 'gnus-summary-end-of-article)
   (define-key gnus-summary-mode-map "j" 'gnus-summary-goto-subject)
@@ -5280,7 +5296,8 @@ buffer.
   (define-key gnus-summary-mode-map "E" 'gnus-summary-mark-as-expirable)
   (define-key gnus-summary-mode-map "\M-u" 'gnus-summary-clear-mark-forward)
   (define-key gnus-summary-mode-map "\M-U" 'gnus-summary-clear-mark-backward)
-  (define-key gnus-summary-mode-map "k" 'gnus-summary-kill-same-subject-and-select)
+  (define-key gnus-summary-mode-map 
+    "k" 'gnus-summary-kill-same-subject-and-select)
   (define-key gnus-summary-mode-map "\C-k" 'gnus-summary-kill-same-subject)
   (define-key gnus-summary-mode-map "\M-\C-k" 'gnus-summary-kill-thread)
   (define-key gnus-summary-mode-map "\M-\C-l" 'gnus-summary-lower-thread)
@@ -5299,14 +5316,19 @@ buffer.
   (define-key gnus-summary-mode-map "\C-w" 'gnus-summary-mark-region-as-read)
   (define-key gnus-summary-mode-map "\C-t" 'gnus-summary-toggle-truncation)
   (define-key gnus-summary-mode-map "?" 'gnus-summary-mark-as-dormant)
-  (define-key gnus-summary-mode-map "\C-c\M-\C-s" 'gnus-summary-show-all-expunged)
-  (define-key gnus-summary-mode-map "\C-c\C-s\C-n" 'gnus-summary-sort-by-number)
-  (define-key gnus-summary-mode-map "\C-c\C-s\C-a" 'gnus-summary-sort-by-author)
-  (define-key gnus-summary-mode-map "\C-c\C-s\C-s" 'gnus-summary-sort-by-subject)
+  (define-key gnus-summary-mode-map 
+    "\C-c\M-\C-s" 'gnus-summary-show-all-expunged)
+  (define-key gnus-summary-mode-map 
+    "\C-c\C-s\C-n" 'gnus-summary-sort-by-number)
+  (define-key gnus-summary-mode-map 
+    "\C-c\C-s\C-a" 'gnus-summary-sort-by-author)
+  (define-key gnus-summary-mode-map 
+    "\C-c\C-s\C-s" 'gnus-summary-sort-by-subject)
   (define-key gnus-summary-mode-map "\C-c\C-s\C-d" 'gnus-summary-sort-by-date)
   (define-key gnus-summary-mode-map "\C-c\C-s\C-i" 'gnus-summary-sort-by-score)
   (define-key gnus-summary-mode-map "=" 'gnus-summary-expand-window)
-  (define-key gnus-summary-mode-map "\C-x\C-s" 'gnus-summary-reselect-current-group)
+  (define-key gnus-summary-mode-map 
+    "\C-x\C-s" 'gnus-summary-reselect-current-group)
   (define-key gnus-summary-mode-map "\M-g" 'gnus-summary-rescan-group)
   (define-key gnus-summary-mode-map "w" 'gnus-summary-stop-page-breaking)
   (define-key gnus-summary-mode-map "\C-c\C-r" 'gnus-summary-caesar-message)
@@ -5330,7 +5352,8 @@ buffer.
   (define-key gnus-summary-mode-map gnus-mouse-2 'gnus-mouse-pick-article)
   (define-key gnus-summary-mode-map "m" 'gnus-summary-mail-other-window)
   (define-key gnus-summary-mode-map "a" 'gnus-summary-post-news)
-  (define-key gnus-summary-mode-map "x" 'gnus-summary-remove-lines-marked-as-read)
+  (define-key gnus-summary-mode-map 
+    "x" 'gnus-summary-remove-lines-marked-as-read)
 ; (define-key gnus-summary-mode-map "X" 'gnus-summary-remove-lines-marked-with)
   (define-key gnus-summary-mode-map "s" 'gnus-summary-isearch-article)
   (define-key gnus-summary-mode-map "t" 'gnus-summary-toggle-header)
@@ -5359,15 +5382,18 @@ buffer.
   (define-key gnus-summary-mark-map "B" 'gnus-summary-remove-bookmark)
   (define-key gnus-summary-mark-map "#" 'gnus-summary-mark-as-processable)
   (define-key gnus-summary-mark-map "\M-#" 'gnus-summary-unmark-as-processable)
-  (define-key gnus-summary-mark-map "\M-r" 'gnus-summary-remove-lines-marked-as-read)
-  (define-key gnus-summary-mark-map "\M-\C-r" 'gnus-summary-remove-lines-marked-with)
+  (define-key gnus-summary-mark-map 
+    "\M-r" 'gnus-summary-remove-lines-marked-as-read)
+  (define-key gnus-summary-mark-map 
+    "\M-\C-r" 'gnus-summary-remove-lines-marked-with)
   (define-key gnus-summary-mark-map "D" 'gnus-summary-show-all-dormant)
   (define-key gnus-summary-mark-map "\M-D" 'gnus-summary-hide-all-dormant)
   (define-key gnus-summary-mark-map "S" 'gnus-summary-show-all-expunged)
   (define-key gnus-summary-mark-map "C" 'gnus-summary-catchup)
   (define-key gnus-summary-mark-map "H" 'gnus-summary-catchup-to-here)
   (define-key gnus-summary-mark-map "\C-c" 'gnus-summary-catchup-all)
-  (define-key gnus-summary-mark-map "k" 'gnus-summary-kill-same-subject-and-select)
+  (define-key gnus-summary-mark-map 
+    "k" 'gnus-summary-kill-same-subject-and-select)
   (define-key gnus-summary-mark-map "K" 'gnus-summary-kill-same-subject)
 
   (define-prefix-command 'gnus-summary-mscore-map)
@@ -5422,7 +5448,8 @@ buffer.
   (define-key gnus-summary-exit-map "E" 'gnus-summary-exit-no-update)
   (define-key gnus-summary-exit-map "Q" 'gnus-summary-exit)
   (define-key gnus-summary-exit-map "Z" 'gnus-summary-exit)
-  (define-key gnus-summary-exit-map "n" 'gnus-summary-catchup-and-goto-next-group)
+  (define-key gnus-summary-exit-map 
+    "n" 'gnus-summary-catchup-and-goto-next-group)
   (define-key gnus-summary-exit-map "R" 'gnus-summary-reselect-current-group)
   (define-key gnus-summary-exit-map "G" 'gnus-summary-rescan-group)
   (define-key gnus-summary-exit-map "N" 'gnus-summary-next-group)
@@ -5456,14 +5483,18 @@ buffer.
   (define-key gnus-summary-wash-hide-map "h" 'gnus-article-hide-headers)
   (define-key gnus-summary-wash-hide-map "s" 'gnus-article-hide-signature)
   (define-key gnus-summary-wash-hide-map "c" 'gnus-article-hide-citation)
-  (define-key gnus-summary-wash-hide-map "\C-c" 'gnus-article-hide-citation-maybe)
+  (define-key gnus-summary-wash-hide-map 
+    "\C-c" 'gnus-article-hide-citation-maybe)
 
   (define-prefix-command 'gnus-summary-wash-highlight-map)
   (define-key gnus-summary-wash-map "H" 'gnus-summary-wash-highlight-map)
   (define-key gnus-summary-wash-highlight-map "a" 'gnus-article-highlight)
-  (define-key gnus-summary-wash-highlight-map "h" 'gnus-article-highlight-headers)
-  (define-key gnus-summary-wash-highlight-map "c" 'gnus-article-highlight-citation)
-  (define-key gnus-summary-wash-highlight-map "s" 'gnus-article-highlight-signature)
+  (define-key gnus-summary-wash-highlight-map 
+    "h" 'gnus-article-highlight-headers)
+  (define-key gnus-summary-wash-highlight-map
+    "c" 'gnus-article-highlight-citation)
+  (define-key gnus-summary-wash-highlight-map
+    "s" 'gnus-article-highlight-signature)
 
   (define-prefix-command 'gnus-summary-wash-time-map)
   (define-key gnus-summary-wash-map "T" 'gnus-summary-wash-time-map)
@@ -6151,7 +6182,8 @@ If NO-ARTICLE is non-nil, no article is selected initially."
                                   (gnus-simplify-subject-re 
                                    (mail-header-subject (car headers)))))
                     (progn
-                      (if (not (< (or (cdr (assq (mail-header-number (car headers))
+                      (if (not (< (or (cdr (assq (mail-header-number
+                                                  (car headers))
                                                  gnus-newsgroup-scored))
                                       default) below))
                           (setq new-roots (cons (car headers) new-roots))
@@ -6480,7 +6512,8 @@ or a straight list of headers."
               ((eq gnus-summary-make-false-root 'dummy)
                ;; We output a dummy root.
                (gnus-summary-insert-dummy-line 
-                nil header (mail-header-number (car (car (cdr (car thread)))))))
+                nil header (mail-header-number
+                            (car (car (cdr (car thread)))))))
               (t
                ;; We do not make a root for the gathered
                ;; sub-threads at all.  
@@ -6528,18 +6561,18 @@ or a straight list of headers."
                        gnus-ancient-mark)))
                (memq number gnus-newsgroup-replied)
                (memq number gnus-newsgroup-expirable)
-               (if (and (eq gnus-summary-make-false-root 'empty)
-                        (memq number gnus-tmp-gathered))
-                   gnus-summary-same-subject
-                 (if (or (zerop level)
-                         (and gnus-thread-ignore-subject
-                              (not (string= 
-                                    (gnus-simplify-subject-re
-                                     gnus-tmp-prev-subject)
-                                    (gnus-simplify-subject-re
-                                     subject)))))
-                     subject
-                   gnus-summary-same-subject))
+               (cond
+                ((and gnus-thread-ignore-subject
+                      (not (string= 
+                            (gnus-simplify-subject-re gnus-tmp-prev-subject)
+                            (gnus-simplify-subject-re subject))))
+                 subject)
+                ((zerop level)
+                 (if (and (eq gnus-summary-make-false-root 'empty)
+                          (memq number gnus-tmp-gathered))
+                     gnus-summary-same-subject
+                   subject))
+                (t gnus-summary-same-subject))
                (and (eq gnus-summary-make-false-root 'adopt)
                     (memq number gnus-tmp-gathered))
                (cdr (assq number gnus-newsgroup-scored)))
@@ -6560,7 +6593,8 @@ or a straight list of headers."
     ;; Do the async thing, if that is required.
     (if gnus-newsgroup-async
        (setq gnus-newsgroup-threads
-             (mapcar (lambda (h) (cons (mail-header-number h) (mail-header-lines h)))
+             (mapcar (lambda (h) 
+                       (cons (mail-header-number h) (mail-header-lines h)))
                      headers)))
 
     (while headers
@@ -6602,18 +6636,14 @@ If READ-ALL is non-nil, all articles in the group are selected."
   (let* ((entry (gnus-gethash group gnus-newsrc-hashtb))
         (info (nth 2 entry))
         articles)
-    (gnus-check-server
-     (setq gnus-current-select-method (gnus-find-method-for-group group)))
 
-    (or (gnus-check-server gnus-current-select-method)
+    (or (gnus-check-server
+        (setq gnus-current-select-method (gnus-find-method-for-group group)))
        (error "Couldn't open server"))
     
-    (or (and (null entry)
-            (gnus-activate-group group))
-       (and (eq (car entry) t)
-            (gnus-activate-group (car info)))
-       (gnus-request-group group t)
-       (progn
+    (or (and entry (not (eq (car entry) t))) ; Either it's active...
+       (gnus-activate-group group) ; Or we can activate it...
+       (progn ; Or we bug out.
          (kill-buffer (current-buffer))
          (error "Couldn't request group %s: %s" 
                 group (gnus-status-message group))))
@@ -6711,7 +6741,8 @@ If READ-ALL is non-nil, all articles in the group are selected."
           (setq gnus-newsgroup-begin 
                 (mail-header-number (car gnus-newsgroup-headers)))
           (setq gnus-newsgroup-end
-                (mail-header-number (gnus-last-element gnus-newsgroup-headers))))
+                (mail-header-number
+                 (gnus-last-element gnus-newsgroup-headers))))
       (setq gnus-reffed-article-number -1)
       ;; GROUP is successfully selected.
       (or gnus-newsgroup-headers t)))))
@@ -7031,10 +7062,22 @@ The resulting hash table is returned, or nil if no Xrefs were found."
        (let ((ids articles)
              (ticked (cdr (assq 'tick (nth 3 info))))
              (dormant (cdr (assq 'dormant (nth 3 info))))
-             id)
+             id first)
          (setq exps nil)
          (while ids
            (setq id (car ids))
+           (if (and first (> id (cdr active)))
+               (progn
+                 ;; We'll end up in this situation in one particular
+                 ;; obscure situation. If you re-scan a group and get
+                 ;; a new article that is cross-posted to a different
+                 ;; group that has not been re-scanned, you might get
+                 ;; crossposted article that has a higher number than
+                 ;; Gnus believes possible. So we re-activate this
+                 ;; group as well. This might mean doing the
+                 ;; crossposting thingie will *increase* the number
+                 ;; of articles in some groups. Tsk, tsk.
+                 (setq active (or (gnus-activate-group group) active))))
            (if (or (> id (cdr active))
                    (< id (car active))
                    (memq id ticked)
@@ -7195,7 +7238,8 @@ The resulting hash table is returned, or nil if no Xrefs were found."
                    (progn
                      (mail-header-set-xref 
                       (car (symbol-value dep))
-                      (concat (or (mail-header-xref (car (symbol-value dep))) "")
+                      (concat (or (mail-header-xref 
+                                   (car (symbol-value dep))) "")
                               (or (mail-header-xref header) "")))
                      (setq header nil))
                  (setcar (symbol-value dep) header))
@@ -7725,7 +7769,8 @@ gnus-exit-group-hook is called with no arguments if that value is non-nil."
         (mode major-mode)
         (buf (current-buffer)))
     (run-hooks 'gnus-summary-prepare-exit-hook)
-    (gnus-summary-update-info)         ; Make all changes in this group permanent.
+    ;; Make all changes in this group permanent.
+    (gnus-summary-update-info)         
     (set-buffer buf)
     (and gnus-use-cache (gnus-cache-possibly-remove-articles))
     ;; Make sure where I was, and go to next newsgroup.
@@ -8352,7 +8397,8 @@ If ALL-HEADERS is non-nil, no header lines are hidden."
     (string-to-int
      (completing-read 
       "Article number: "
-      (mapcar (lambda (headers) (list (int-to-string (mail-header-number headers))))
+      (mapcar (lambda (headers) 
+               (list (int-to-string (mail-header-number headers))))
              gnus-newsgroup-headers) 
       nil 'require-match))))
   (prog1
@@ -8548,21 +8594,23 @@ gnus-select-article-hook is not called during the search."
     (gnus-summary-select-article)
     (gnus-message 9 "Searching article: %d..." gnus-current-article)
     (setq last gnus-current-article)
-    (gnus-eval-in-buffer-window gnus-article-buffer
-                               (save-restriction
-                                 (widen)
-                                 ;; Begin search from current point.
-                                 (setq found (funcall re-search regexp nil t))))
+    (gnus-eval-in-buffer-window
+     gnus-article-buffer
+     (save-restriction
+       (widen)
+       ;; Begin search from current point.
+       (setq found (funcall re-search regexp nil t))))
     ;; Then search next articles.
     (while (and (not found)
                (gnus-summary-display-article 
                 (gnus-summary-search-subject backward nil nil)))
       (gnus-message 9 "Searching article: %d..." gnus-current-article)
-      (gnus-eval-in-buffer-window gnus-article-buffer
-                                 (save-restriction
-                                   (widen)
-                                   (goto-char (if backward (point-max) (point-min)))
-                                   (setq found (funcall re-search regexp nil t)))))
+      (gnus-eval-in-buffer-window
+       gnus-article-buffer
+       (save-restriction
+        (widen)
+        (goto-char (if backward (point-max) (point-min)))
+        (setq found (funcall re-search regexp nil t)))))
     (message "")
     ;; Adjust article pointer.
     (or (eq last gnus-current-article)
@@ -8992,7 +9040,7 @@ functions. (Ie. mail newsgroups at present.)"
        (or total (setq gnus-newsgroup-expirable es))
        ;; 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.
+       (or (eq es expirable)           ;If nothing was expired, we don't mark.
            (let ((gnus-use-cache nil))
              (while expirable
                (or (memq (car expirable) es)
@@ -9279,7 +9327,8 @@ number of articles marked is returned."
     (while (and 
            (> n 0)
            (if unmark
-               (gnus-summary-remove-process-mark (gnus-summary-article-number))
+               (gnus-summary-remove-process-mark
+                (gnus-summary-article-number))
              (gnus-summary-set-process-mark (gnus-summary-article-number)))
            (zerop (gnus-summary-next-subject (if backward -1 1) nil t)))
       (setq n (1- n)))
@@ -9537,8 +9586,9 @@ marked."
       (insert mark)
       (and plist (add-text-properties (1- (point)) (point) plist))
       (and (eq type 'unread)
-          (add-text-properties (1- (point)) (point) (list 'gnus-mark mark)))
-      (gnus-summary-update-line (eq mark gnus-unread-mark)))))
+          (progn
+            (add-text-properties (1- (point)) (point) (list 'gnus-mark mark))
+            (gnus-summary-update-line (eq mark gnus-unread-mark)))))))
   
 (defun gnus-mark-article-as-read (article &optional mark)
   "Enter ARTICLE in the pertinent lists and remove it from others."
@@ -9970,7 +10020,7 @@ Returns nil if no thread was there to be shown."
   (interactive)
   (gnus-set-global-variables)
   (let ((buffer-read-only nil)
-       (orig (point))
+       (orig (prog1 (point) (gnus-summary-hide-thread)))
        ;; 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))))
@@ -10013,7 +10063,8 @@ Returns nil if no threads were there to be hidden."
            (goto-char end)
            (search-backward "\n" start t))
        (subst-char-in-region start end ?\n ?\^M t)
-       (forward-line -1)))))
+       (forward-line -1)
+       (gnus-summary-position-cursor)))))
 
 (defun gnus-summary-go-to-next-thread (&optional previous)
   "Go to the same level (or less) next thread.
@@ -10118,6 +10169,8 @@ If the prefix argument is negative, tick articles instead."
   (let ((killing t)
        (level (gnus-summary-thread-level)))
     (save-excursion
+      ;; Expand the thread.
+      (gnus-summary-show-thread)
       (while killing
        ;; Mark the article...
        (cond ((null unmark) (gnus-summary-mark-article-as-read
@@ -10185,7 +10238,7 @@ Argument REVERSE means reverse order."
                       gnus-extract-address-components
                       (mail-header-from header))))
        (concat 
-        (downcase (gnus-simplify-subject (gnus-summary-subject-string)))
+        (downcase (gnus-simplify-subject (gnus-summary-subject-string) t))
         "\r" (or (car extract) (cdr extract)))))
     'gnus-thread-sort-by-subject)
    reverse))
@@ -10612,7 +10665,8 @@ is initialized from the SAVEDIR environment variable."
   (define-key gnus-article-mode-map "h" 'gnus-article-show-summary)
   (define-key gnus-article-mode-map "s" 'gnus-article-show-summary)
   (define-key gnus-article-mode-map "\C-c\C-m" 'gnus-article-mail)
-  (define-key gnus-article-mode-map "\C-c\C-M" 'gnus-article-mail-with-original)
+  (define-key gnus-article-mode-map 
+    "\C-c\C-M" 'gnus-article-mail-with-original)
   (define-key gnus-article-mode-map "?" 'gnus-article-describe-briefly)
   (define-key gnus-article-mode-map gnus-mouse-2 'gnus-article-push-button)
   (define-key gnus-article-mode-map "\r" 'gnus-article-press-button)
@@ -11619,131 +11673,6 @@ If NEWSGROUP is nil, return the global kill file name instead."
 ;;; Server Communication
 ;;;
 
-;; All the Gnus backends have the same interface, and should return
-;; data in a similar format. Below is an overview of what functions
-;; these packages must supply and what results they should return.
-;;
-;; Variables:
-;;
-;; `nntp-server-buffer' - All data should be returned to Gnus in this
-;; buffer. 
-;;
-;; Functions for the imaginary backend `choke':
-;;
-;; `choke-retrieve-headers ARTICLES &optional GROUP SERVER'
-;; Should return all headers for all ARTICLES, or return NOV lines for
-;; the same.
-;;
-;; `choke-request-group GROUP &optional SERVER DISCARD'
-;; Switch to GROUP. If DISCARD is nil, active information on the group
-;; must be returned.
-;;
-;; `choke-close-group GROUP &optional SERVER'
-;; Close group. Most backends won't have to do anything with this
-;; call, but it is an opportunity to clean up, if that is needed. It
-;; is called when Gnus exits a group.
-;;
-;; `choke-request-article ARTICLE &optional GROUP SERVER'
-;; Return ARTICLE, which is either an article number or
-;; message-id. Note that not all backends can return articles based on
-;; message-id. 
-;;
-;; `choke-request-list SERVER'
-;; Return a list of all newsgroups on SERVER.
-;;
-;; `choke-request-list-newsgroups SERVER'
-;; Return a list of descriptions of all newsgroups on SERVER.
-;;
-;; `choke-request-newgroups DATE &optional SERVER'
-;; Return a list of all groups that have arrived after DATE on
-;; SERVER. Note that the date doesn't have to be respected - Gnus will
-;; always check whether the groups are old or not. Backends that do
-;; not store date information may just return the entire list of
-;; groups, although this might not be a good idea in general.
-;;
-;; `choke-request-post-buffer METHOD HEADER ARTICLE-BUFFER GROUP INFO'
-;; Should return a buffer that is suitable for "posting". nnspool and
-;; nntp return a `*post-buffer*', and nnmail return a `*mail*'
-;; buffer. This function should fill out the appropriate headers. 
-;;
-;; `choke-request-post &optional SERVER'
-;; Function that will be called from a buffer to be posted. 
-;;
-;; `choke-open-server SERVER &optional ARGUMENT'
-;; Open a connection to SERVER.
-;;
-;; `choke-close-server &optional SERVER'
-;; Close the connection to SERVER.
-;;
-;; `choke-server-opened &optional SERVER'
-;; Whether the conenction to SERVER is opened or not.
-;;
-;; `choke-server-status &optional SERVER'
-;; Should return a status string (not in the nntp buffer, but as the
-;; result of the function).
-;;
-;; `choke-retrieve-groups GROUPS &optional SERVER'
-;; Optional function for retrieving active file info on all groups in
-;; GROUPS.  Two return formats are supported: The normal active file
-;; format, and a list of GROUP lines.  This function should return (as
-;; a function value) either `active' or `group', depending on what
-;; format it returns.
-;;
-;; The following functions are optional and apply only to backends
-;; that are able to control the contents of their groups totally
-;; (ie. mail backends.)  Backends that aren't able to do that
-;; shouldn't define these functions at all. Gnus will check for their
-;; presence before attempting to call them.
-;;
-;; `choke-request-expire-articles ARTICLES &optional NEWSGROUP SERVER'
-;; Should expire (according to some aging scheme) all ARTICLES. Most
-;; backends will not be able to expire articles. Should return a list
-;; of all articles that were not expired.
-;;
-;; `choke-request-move-article ARTICLE GROUP SERVER ACCEPT-FORM &optional LAST'
-;; Should move ARTICLE from GROUP on SERVER by using ACCEPT-FORM.
-;; Removes any information it has added to the article (extra headers,
-;; whatever - make it as clean as possible), and then passes the
-;; article on by evaling ACCEPT-FORM, which is normally a call to the
-;; function described below. If the ACCEPT-FORM returns a non-nil
-;; value, the article should then be deleted. If LAST is nil, that
-;; means that there will be further calls to this function. This might
-;; be taken as an advice not to save buffers/internal variables just
-;; yet, but wait until the last call to speed things up.
-;;
-;; `choke-request-accept-article GROUP &optional LAST' 
-;; The contents of the current buffer will be put into GROUP.  There
-;; should, of course, be an article in the current buffer.  This
-;; function is normally only called by the function described above,
-;; and LAST works the same way as in that function.
-;;
-;; `choke-request-replace-article ARTICLE GROUP BUFFER'
-;; Replace ARTICLE in GROUP with the contents of BUFFER.
-;; This provides an easy interface for allowing editing of
-;; articles. Note that even headers may be edited, so the backend has
-;; to update any tables (nov buffers, etc) that it maintains after
-;; replacing the article.
-;;
-;; `choke-request-create-group GROUP &optional SERVER'
-;; Create GROUP on SERVER.  This might be a new, empty group, or it
-;; might be a group that already exists, but hasn't been registered
-;; yet. 
-;;
-;; All these functions must return nil if they couldn't service the
-;; request. If the optional arguments are not supplied, some "current"
-;; or "default" values should be used. In short, one should emulate an
-;; NNTP server, in a way.
-;;
-;; If you want to write a new backend, you just have to supply the
-;; functions listed above. In addition, you must enter the new backend
-;; into the list of valid select methods:
-;; (setq gnus-valid-select-methods 
-;;       (cons '("choke" mail) gnus-valid-select-methods))
-;; The first element in this list is the name of the backend. Other
-;; elemnets may be `mail' (for mail groups),  `post' (for news
-;; groups), `none' (neither), `respool' (for groups that can control
-;; their contents). 
-
 (defun gnus-start-news-server (&optional confirm)
   "Open a method for getting news.
 If CONFIRM is non-nil, the user will be asked for an NNTP server."
@@ -11872,7 +11801,6 @@ is returned insted of the status string."
 
 (defun gnus-request-group (group &optional dont-check)
   (let ((method (gnus-find-method-for-group group)))
-                                       ;    (and t (message "%s GROUP %s" (car method) group))
     (funcall (gnus-get-function method 'request-group) 
             (gnus-group-real-name group) (nth 1 method) dont-check)))
 
@@ -11920,6 +11848,11 @@ is returned insted of the status string."
     (funcall (gnus-get-function method 'request-head) 
             article (gnus-group-real-name group) (nth 1 method))))
 
+(defun gnus-request-body (article group)
+  (let ((method (gnus-find-method-for-group group)))
+    (funcall (gnus-get-function method 'request-body) 
+            article (gnus-group-real-name group) (nth 1 method))))
+
 ;; Fix by Sudish Joseph <joseph@cis.ohio-state.edu>.
 (defun gnus-request-post-buffer (post group subject header artbuf
                                      info follow-to respect-poster)
@@ -12097,13 +12030,15 @@ If LEVEL is non-nil, the news will be set up at level LEVEL."
 
     (gnus-update-format-specifications)
 
-    ;; Find the number of unread articles in each non-dead group.
-    (let ((gnus-read-active-file (and (not level) gnus-read-active-file)))
-      (gnus-get-unread-articles (or level (1+ gnus-level-subscribed))))
     ;; Find new newsgroups and treat them.
     (if (and init gnus-check-new-newsgroups gnus-read-active-file (not level)
             (gnus-server-opened gnus-select-method))
        (gnus-find-new-newsgroups))
+
+    ;; Find the number of unread articles in each non-dead group.
+    (let ((gnus-read-active-file (and (not level) gnus-read-active-file)))
+      (gnus-get-unread-articles (or level (1+ gnus-level-subscribed))))
+
     (if (and init gnus-check-bogus-newsgroups 
             gnus-read-active-file (not level)
             (gnus-server-opened gnus-select-method))
@@ -12120,7 +12055,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...")
+         (gnus-message 5 "Looking 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))
@@ -12668,7 +12603,7 @@ newsgroup."
   (let ((method (gnus-find-method-for-group group))
        active)
     (and (gnus-check-server method)
-        ;; We escape all bugs and quits here to make it possible to
+        ;; We escape all bugs and quit here to make it possible to
         ;; continue if a group is so out-there that it reports bugs
         ;; and stuff.
         (condition-case ()
@@ -12817,16 +12752,17 @@ Returns whether the updating was successful."
                  (setq newsrc (cdr newsrc)))
                (gnus-check-server method)
                (setq list-type (gnus-retrieve-groups groups method))
-               (cond ((not list-type)
-                      (gnus-message 
-                       1 "Cannot read partial active file from %s server." 
-                       (car method))
-                      (ding)
-                      (sit-for 2))
-                     ((eq list-type 'active)
-                      (gnus-active-to-gnus-format method gnus-active-hashtb))
-                     (t
-                      (gnus-groups-to-gnus-format method gnus-active-hashtb)))))
+               (cond 
+                ((not list-type)
+                 (gnus-message 
+                  1 "Cannot read partial active file from %s server." 
+                  (car method))
+                 (ding)
+                 (sit-for 2))
+                ((eq list-type 'active)
+                 (gnus-active-to-gnus-format method gnus-active-hashtb))
+                (t
+                 (gnus-groups-to-gnus-format method gnus-active-hashtb)))))
             (t
              (if (not (gnus-request-list method))
                  (progn
@@ -13080,7 +13016,8 @@ If FORCE is non-nil, the .newsrc file is read."
                               (cdr (cdr group))))
                   gnus-newsrc-alist)))
          (if (setq m (assoc (car group) marked))
-             (setcdr (cdr (cdr info)) (cons (list (cons 'tick (cdr m))) nil))))
+             (setcdr (cdr (cdr info))
+                     (cons (list (cons 'tick (cdr m))) nil))))
        (setq newsrc (cdr newsrc)))
       (setq newsrc killed)
       (while newsrc
@@ -13096,7 +13033,11 @@ If FORCE is non-nil, the .newsrc file is read."
        (and (not (string-match "^ *options" gnus-newsrc-options))
            (setq gnus-newsrc-options (concat "options " gnus-newsrc-options)))
        (and (not (string-match "\n$" gnus-newsrc-options))
-           (setq gnus-newsrc-options (concat gnus-newsrc-options "\n")))))
+           (setq gnus-newsrc-options (concat gnus-newsrc-options "\n")))
+       ;; Finally, if we read some options lines, we parse them.
+       (or (string= gnus-newsrc-options "")
+          (gnus-newsrc-parse-options gnus-newsrc-options))))
+
     (setq gnus-newsrc-alist (nreverse gnus-newsrc-alist))
     (gnus-make-hashtable-from-newsrc-alist)))
       
@@ -13227,10 +13168,11 @@ If FORCE is non-nil, the .newsrc file is read."
                        (setq reads (cons num1 reads))
                      (setq reads 
                            (cons 
-                            (cons num1 (progn
-                                         (narrow-to-region (match-beginning 0) 
-                                                           (match-end 0))
-                                         (read buf)))
+                            (cons num1
+                                  (progn
+                                    (narrow-to-region (match-beginning 0) 
+                                                      (match-end 0))
+                                    (read buf)))
                             reads))
                      (widen)))
                ;; It was just a simple number, so we add it to the
@@ -13245,7 +13187,8 @@ If FORCE is non-nil, the .newsrc file is read."
             (t
              ;; Not numbers and not eol, so this might be a buggy
              ;; line... 
-             (or (eobp)                ; If it was eob instead of ?\n, we allow it.
+             (or (eobp)                
+                 ;; If it was eob instead of ?\n, we allow it.
                  (progn
                    ;; The line was buggy.
                    (setq group nil)
@@ -14068,7 +14011,7 @@ The list is determined from the variable gnus-score-file-alist."
        score-files)
     ;; if this group has been seen before, return the cached entry
     (if (setq score-files (assoc group gnus-score-file-alist-cache))
-       (cdr score-files)               ; ensures caching of groups with no matches
+       (cdr score-files)               ;ensures caching groups with no matches
       ;; handle the multiple match alist
       (while alist
        (and (string-match (car (car alist)) group)
index a15058b..715fb10 100644 (file)
 
     (save-excursion 
       (set-buffer nnbabyl-mbox-buffer)
+      (set-text-properties (point-min) (point-max) nil)
       (while (and articles is-old)
        (goto-char (point-min))
        (if (search-forward (nnbabyl-article-string (car articles)) nil t)
                          (nnheader-find-file-noselect 
                           nnbabyl-mbox-file nil 'raw)))
        (buffer-disable-undo (current-buffer))
+       (widen)
+       (setq buffer-read-only nil)
+       (fundamental-mode)
        
        (goto-char (point-min))
        (re-search-forward delim nil t)
         (progn
           (and gnus-verbose-backends 
                (message "nnbabyl: Reading incoming mail..."))
-          (setq incoming 
-                (nnmail-move-inbox 
-                 (car spools) (concat nnbabyl-mbox-file "-Incoming")))
-          (setq incomings (cons incoming incomings))
-          (save-excursion
-            (setq group (nnmail-get-split-group (car spools) group-in))
-            (let* ((nnmail-prepare-incoming-hook
-                    (cons 'nnbabyl-remove-incoming-delims
-                          nnmail-prepare-incoming-hook))
-                   in-buf)
-              (setq in-buf (nnmail-split-incoming 
-                            incoming 'nnbabyl-save-mail t group))
-              (set-buffer in-buf)
-              (goto-char (point-min))
-              (while (search-forward "\n\^_\n" nil t)
-                (delete-char -1))
-              (set-buffer nnbabyl-mbox-buffer)
-              (goto-char (point-max))
-              (search-backward "\n\^_" nil t)
-              (goto-char (match-end 0))
-              (insert-buffer-substring in-buf)
-              (kill-buffer in-buf)))))
+          (if (not (setq incoming 
+                         (nnmail-move-inbox 
+                          (car spools) 
+                          (concat nnbabyl-mbox-file "-Incoming"))))
+              ()
+            (setq incomings (cons incoming incomings))
+            (save-excursion
+              (setq group (nnmail-get-split-group (car spools) group-in))
+              (let* ((nnmail-prepare-incoming-hook
+                      (cons 'nnbabyl-remove-incoming-delims
+                            nnmail-prepare-incoming-hook))
+                     in-buf)
+                (setq in-buf (nnmail-split-incoming 
+                              incoming 'nnbabyl-save-mail t group))
+                (set-buffer in-buf)
+                (goto-char (point-min))
+                (while (search-forward "\n\^_\n" nil t)
+                  (delete-char -1))
+                (set-buffer nnbabyl-mbox-buffer)
+                (goto-char (point-max))
+                (search-backward "\n\^_" nil t)
+                (goto-char (match-end 0))
+                (insert-buffer-substring in-buf)
+                (kill-buffer in-buf))))))
        (setq spools (cdr spools)))
       ;; If we did indeed read any incoming spools, we save all info. 
       (and (buffer-modified-p nnbabyl-mbox-buffer) 
index eb9b8ce..fa0f385 100644 (file)
@@ -612,7 +612,7 @@ such things as moving mail.  All buffers always get killed upon server close.")
                (setq activenumber (max activenumber newnum))
                (setq activemin (min activemin newnum))))
            (setcar active (min activemin activenumber))
-           (setcdr active activenumber)
+           (setcdr active (max activenumber (cdr active)))
            (goto-char (point-min))))
 
       ;; Keep track of the active number on our own, and insert it back into
@@ -637,12 +637,11 @@ such things as moving mail.  All buffers always get killed upon server close.")
            (progn
              (narrow-to-region start end)
              (nnmail-insert-lines)
-             (setq activenumber (1+ activenumber))
-             (nnfolder-insert-newsgroup-line (cons nil activenumber))
+             (nnfolder-insert-newsgroup-line
+              (cons nil (nnfolder-active-number nnfolder-current-group)))
              (widen))))
 
       ;; Make absolutely sure that the active list reflects reality!
-      (setcdr active activenumber)
       (nnmail-save-active nnfolder-group-alist nnfolder-active-file)
       (current-buffer))))
 
@@ -664,14 +663,15 @@ such things as moving mail.  All buffers always get killed upon server close.")
         (progn
           (and gnus-verbose-backends 
                (message "nnfolder: Reading incoming mail..."))
-          (setq incoming 
-                (nnmail-move-inbox 
-                 (car spools) 
-                 (concat (file-name-as-directory nnfolder-directory)
-                         "Incoming")))
-          (setq incomings (cons incoming incomings))
-          (setq group (nnmail-get-split-group (car spools) group-in))
-          (nnmail-split-incoming incoming 'nnfolder-save-mail nil group)))
+          (if (not (setq incoming 
+                         (nnmail-move-inbox 
+                          (car spools) 
+                          (concat (file-name-as-directory nnfolder-directory)
+                                  "Incoming"))))
+              ()
+            (setq incomings (cons incoming incomings))
+            (setq group (nnmail-get-split-group (car spools) group-in))
+            (nnmail-split-incoming incoming 'nnfolder-save-mail nil group))))
        (setq spools (cdr spools)))
       ;; If we did indeed read any incoming spools, we save all info. 
       (if incoming 
index c48b9a9..bded782 100644 (file)
   "Set article author of HEADER to FROM."
   (` (aset (, header) 2 (, from))))
 
-(defalias 'nntp-header-xref 'mail-header-xref)
-(defmacro mail-header-xref (header)
-  "Return xref string in HEADER."
-  (` (aref (, header) 8)))
-
-(defalias 'nntp-set-header-xref 'mail-header-set-xref)
-(defmacro mail-header-set-xref (header xref)
-  "Set article xref of HEADER to xref."
-  (` (aset (, header) 8 (, xref))))
-
-(defalias 'nntp-header-lines 'mail-header-lines)
-(defmacro mail-header-lines (header)
-  "Return lines in HEADER."
-  (` (aref (, header) 7)))
-
-(defalias 'nntp-set-header-lines 'mail-header-set-lines)
-(defmacro mail-header-set-lines (header lines)
-  "Set article lines of HEADER to LINES."
-  (` (aset (, header) 7 (, lines))))
-
 (defalias 'nntp-header-date 'mail-header-date)
 (defmacro mail-header-date (header)
   "Return date in HEADER."
   "Set number of chars in article of HEADER to CHARS."
   (` (aset (, header) 6 (, chars))))
 
+(defalias 'nntp-header-lines 'mail-header-lines)
+(defmacro mail-header-lines (header)
+  "Return lines in HEADER."
+  (` (aref (, header) 7)))
+
+(defalias 'nntp-set-header-lines 'mail-header-set-lines)
+(defmacro mail-header-set-lines (header lines)
+  "Set article lines of HEADER to LINES."
+  (` (aset (, header) 7 (, lines))))
+
+(defalias 'nntp-header-xref 'mail-header-xref)
+(defmacro mail-header-xref (header)
+  "Return xref string in HEADER."
+  (` (aref (, header) 8)))
+
+(defalias 'nntp-set-header-xref 'mail-header-set-xref)
+(defmacro mail-header-set-xref (header xref)
+  "Set article xref of HEADER to xref."
+  (` (aset (, header) 8 (, xref))))
+
+
 ;; Various cruft the backends and Gnus need to communicate.
 
 (defvar nntp-server-buffer nil)
@@ -337,6 +338,18 @@ The buffer is not selected, just returned to the caller."
            (after-find-file error (not nowarn)))))
       buf)))
 
+(defun nnheader-insert-references (references message-id)
+  ;; Fold long references line to follow RFC1036.
+  (mail-position-on-field "References")
+  (let ((begin (gnus-point-at-bol))
+       (fill-column 78)
+       (fill-prefix "\t"))
+    (if references (insert references))
+    (if (and references message-id) (insert " "))
+    (if message-id (insert message-id))
+    ;; The region must end with a newline to fill the region
+    ;; without inserting extra newline.
+    (fill-region-as-paragraph begin (1+ (point)))))
 
 (provide 'nnheader)
 
index 61091ea..db0c8f5 100644 (file)
@@ -53,7 +53,9 @@ called narrowed to the headers with the first element of the rule as
 the argument.  It should return a non-nil value if it thinks that the
 mail belongs in that group.
 
-The last element should always have \"\" as the regexp.")
+The last element should always have \"\" as the regexp.
+
+This variable can also have a function as its value.")
 
 ;; Suggested by Erik Selberg <speed@cs.washington.edu>.
 (defvar nnmail-crosspost t
@@ -222,7 +224,7 @@ perfomed.")
                                        info follow-to respect-poster)
   (let ((method-address (cdr (assq 'to-address (nth 5 info))))
        from date to reply-to message-of
-       references message-id sender cc sendto elt)
+       references message-id cc new-cc sendto elt)
     (setq method-address
          (if (and (stringp method-address) 
                   (string= method-address ""))
@@ -255,9 +257,11 @@ perfomed.")
                   (setq message-of
                         (concat (if stop-pos (substring from 0 stop-pos) from)
                                 "'s message of " date))))
-           (setq sender (mail-fetch-field "sender"))
-           (setq cc (mail-fetch-field "cc"))
-           (setq to (mail-fetch-field "to"))
+           (setq cc (mail-strip-quoted-names (mail-fetch-field "cc")))
+           (setq to (mail-strip-quoted-names (mail-fetch-field "to")))
+           (setq new-cc (rmail-dont-reply-to 
+                         (concat (or to "")
+                                 (if cc (concat (if to ", " "") cc) ""))))
            (setq subject (mail-header-subject header))
            (or (string-match "^[Rr][Ee]:" subject)
                (setq subject (concat "Re: " subject)))
@@ -274,12 +278,12 @@ perfomed.")
              (while (setq elt (assoc "To" follow-to))
                (setq sendto (concat sendto (and sendto ", ") (cdr elt)))
                (setq follow-to (delq elt follow-to))))
-         (mail-setup (if (and follow-to (listp follow-to)) sendto
-                       (or method-address 
-                           (concat (or sender reply-to from "")
-                                   (if to (concat ", " to) "")
-                                   (if cc (concat ", " cc) ""))))
-                     subject message-of nil article-buffer nil)
+         (mail-setup (if (and follow-to (listp follow-to)) 
+                         sendto
+                       (or method-address reply-to from ""))
+                     subject message-of 
+                     (if (zerop (length new-cc)) nil new-cc)
+                     article-buffer nil)
          (auto-save-mode auto-save-default)
          ;; Note that "To" elements should already be in the message.
          (if (and follow-to (listp follow-to))
@@ -292,17 +296,7 @@ perfomed.")
                  (insert 
                   (car (car follow-to)) ": " (cdr (car follow-to)) "\n")
                  (setq follow-to (cdr follow-to)))))
-         ;; Fold long references line to follow RFC1036.
-         (mail-position-on-field "References")
-         (let ((begin (- (point) (length "References: ")))
-               (fill-column 78)
-               (fill-prefix "\t"))
-           (if references (insert references))
-           (if (and references message-id) (insert " "))
-           (if message-id (insert message-id))
-           ;; The region must end with a newline to fill the region
-           ;; without inserting extra newline.
-           (fill-region-as-paragraph begin (1+ (point))))))
+         (nnheader-insert-references references message-id)))
       (current-buffer))))
 
 (defun nnmail-find-file (file)
index 92f0bc5..500bffa 100644 (file)
         (progn
           (and gnus-verbose-backends 
                (message "nnmbox: Reading incoming mail..."))
-          (setq incoming 
-                (nnmail-move-inbox 
-                 (car spools) (concat nnmbox-mbox-file "-Incoming")))
-          (setq incomings (cons incoming incomings))
-          (save-excursion
-            (setq group (nnmail-get-split-group (car spools) group-in))
-            (let ((in-buf (nnmail-split-incoming 
-                           incoming 'nnmbox-save-mail t group)))
-              (set-buffer nnmbox-mbox-buffer)
-              (goto-char (point-max))
-              (insert-buffer-substring in-buf)
-              (kill-buffer in-buf)))))
+          (if (not (setq incoming 
+                         (nnmail-move-inbox 
+                          (car spools) 
+                          (concat nnmbox-mbox-file "-Incoming"))))
+              ()
+            (setq incomings (cons incoming incomings))
+            (save-excursion
+              (setq group (nnmail-get-split-group (car spools) group-in))
+              (let ((in-buf (nnmail-split-incoming 
+                             incoming 'nnmbox-save-mail t group)))
+                (set-buffer nnmbox-mbox-buffer)
+                (goto-char (point-max))
+                (insert-buffer-substring in-buf)
+                (kill-buffer in-buf))))))
        (setq spools (cdr spools)))
       ;; If we did indeed read any incoming spools, we save all info. 
       (and (buffer-modified-p nnmbox-mbox-buffer) 
index 8e2e3f8..ff52358 100644 (file)
         (progn
           (and gnus-verbose-backends 
                (message "nnmh: Reading incoming mail..."))
-          (setq incoming 
-                (nnmail-move-inbox 
-                 (car spools) (concat (file-name-as-directory nnmh-directory)
-                                      "Incoming")))
-          (setq incomings (cons incoming incomings))
-          (setq group (nnmail-get-split-group (car spools) group-in))
-          (nnmail-split-incoming incoming 'nnmh-save-mail nil group)))
+          (if (not (setq incoming 
+                         (nnmail-move-inbox 
+                          (car spools) 
+                          (concat (file-name-as-directory nnmh-directory)
+                                  "Incoming"))))
+              ()
+            (setq incomings (cons incoming incomings))
+            (setq group (nnmail-get-split-group (car spools) group-in))
+            (nnmail-split-incoming incoming 'nnmh-save-mail nil group))))
        (setq spools (cdr spools)))
       ;; If we did indeed read any incoming spools, we save all info. 
       (if incoming 
index d435d57..585a0c7 100644 (file)
@@ -500,12 +500,13 @@ all. This may very well take some time.")
         (progn
           (and gnus-verbose-backends 
                (message "nnml: Reading incoming mail..."))
-          (setq incoming 
-                (nnmail-move-inbox 
-                 (car spools) (concat nnml-directory "Incoming")))
-          (setq group (nnmail-get-split-group (car spools) group-in))
-          (nnmail-split-incoming incoming 'nnml-save-mail nil group)
-          (setq incomings (cons incoming incomings))))
+          (if (not (setq incoming 
+                         (nnmail-move-inbox 
+                          (car spools) (concat nnml-directory "Incoming"))))
+              ()
+            (setq group (nnmail-get-split-group (car spools) group-in))
+            (nnmail-split-incoming incoming 'nnml-save-mail nil group)
+            (setq incomings (cons incoming incomings)))))
        (setq spools (cdr spools)))
       ;; If we did indeed read any incoming spools, we save all info. 
       (if incoming 
index d7cd85d..89af48e 100644 (file)
@@ -639,7 +639,11 @@ post to this group instead.  If RESPECT-POSTER, heed the special
              (setq followup-to (mail-fetch-field "followup-to"))
              (if (or (null respect-poster) ;Ignore followup-to: field.
                      (string-equal "" followup-to) ;Bogus header.
-                     (string-equal "poster" followup-to)) ;Poster
+                     (string-equal "poster" followup-to);Poster
+                     (and (eq respect-poster 'ask)
+                          followup-to
+                          (y-or-n-p (concat "Followup to " 
+                                            followup-to "? "))))
                  (setq followup-to nil))
              (setq newsgroups
                    (or follow-to followup-to (mail-fetch-field "newsgroups")))
@@ -663,17 +667,7 @@ post to this group instead.  If RESPECT-POSTER, heed the special
                    (insert (car (car newsgroups)) ": " 
                            (cdr (car newsgroups)) "\n")
                    (setq newsgroups (cdr newsgroups)))))
-           ;; Fold long references line to follow RFC1036.
-           (mail-position-on-field "References")
-           (let ((begin (- (point) (length "References: ")))
-                 (fill-column 79)
-                 (fill-prefix "\t"))
-             (if references (insert references))
-             (if (and references message-id) (insert " "))
-             (if message-id (insert message-id))
-             ;; The region must end with a newline to fill the region
-             ;; without inserting extra newline.
-             (fill-region-as-paragraph begin (1+ (point))))
+           (nnheader-insert-references references message-id)
            (if distribution
                (progn
                  (mail-position-on-field "Distribution")
index b3f2a8b..95df3cf 100644 (file)
@@ -1,7 +1,7 @@
 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
+# MAKEINFO=makeinfo -o gnus.info gnus.texi
 LATEX=latex
 
 all: gnus.info refcard.dvi
index bf17d24..3b38ea7 100644 (file)
@@ -89,7 +89,8 @@ luck.
 * Various::                 General purpose settings.
 * Customization::           Tailoring Gnus to your needs.
 * Troubleshooting::         What you might try if things do not work.
-* The End::                 Farewell, and goodbye.
+* The End::                 Farewell and goodbye.
+* Appendix::                Technical stuff for technical people.
 * Index::                   Variable, function and concept index.
 * Key Index::               Key Index.
 @end menu
@@ -114,10 +115,12 @@ can point your (feh!) web browser to
 distribution point for the new and spiffy versions of Gnus, also know as
 The Site That Destroys Newsrcs And Drives People Mad.
 
-@dfn{(ding)}, is, of course, short for @dfn{ding is not Gnus}, which is
-a total and utter lie, but who cares? (Besides, the "Gnus" in this
-abbreviation should probably be pronounced "news" as UMEDA intended,
-which makes it a more appropriate name, don't you think?)
+During the first extended alpha period of develpment, the new Gnus was
+called "(ding) Gnus".  @dfn{(ding)}, is, of course, short for @dfn{ding
+is not Gnus}, which is a total and utter lie, but who cares? (Besides,
+the "Gnus" in this abbreviation should probably be pronounced "news" as
+UMEDA intended, which makes it a more appropriate name, don't you
+think?)
 
 In any case, after spending all that energy with coming up with a new
 and spiffy name, we decided that the name was @emph{too} spiffy, so we
@@ -130,8 +133,9 @@ and won't be released until February.  Confused?  You will be.
 @menu
 * Why?::                What's the point of Gnus?
 * Compatibility::       Just how compatible is Gnus with @sc{gnus}?
+* Conformity::          Gnus tries to conform to all standards.
 * Contributors::        Oodles of people.  
-* New Features::        A short description of all the new stuff in Gnus.
+* New Features::        Pointers to some of the new stuff in Gnus.
 * Newest Features::     Features so new that they haven't been written yet.
 @end menu
 
@@ -228,6 +232,54 @@ Problems specific to GNU XEmacs can be reported to popineau@@ese-metz.fr
 anyway, so you might have to wait longer if you mail XEmacs questions to
 me.
 
+
+@node Conformity
+@section Conformity
+
+No rebels without a clue here, ma'am.  We conform to all standards known
+to man.  Except, of course, where we disagree with the standards and/or
+conventions.
+
+@table @strong
+
+@item RFC 822
+There are no known breaches to this standard.
+
+@item RFC 1036
+There are no known breaches to this standard, either.
+
+@item Usenet Seal of Approval
+Gnus hasn't been formally through the Seal process, but I have read
+through the Seal text, and I think that Gnus would pass.
+
+@item Son-of-RFC 1036
+We do have some breaches to this one.
+
+@table @emph
+@item MIME
+Gnus does no MIME handling, and this standard-to-be seems to think that
+MIME is the bees' knees, so we have major breakage here.
+@item X-Newsreader
+This is considered to be a "vanity header", while I consider it to be
+consumer information.  After seeing so many badly formatted articles
+coming from @code{tin} and @code{Netscape} I know not to use either of
+those for posting articles.  I would not have known that if it wasn't
+for the @code{X-Newsreader} header.
+@item References
+Gnus does line breaking on this header.  I infer from RFC1036 that being
+conservative in what you output is not creating 5000-character lines, so
+it seems like a good idea to me.  However, this standard-to-be says that
+whitespace in the @code{References} header is to be preserved, so...  It
+doesn't matter one way or the other to Gnus, so if somebody tells me
+what The Way is, I'll change it.  Or not.
+@end table
+
+@end table
+
+If you ever see Gnus act noncompliantly to the texts mentioned above,
+don't hesitate to drop a note to Gnus Towers and let us know.
+
+
 @node Contributors
 @section Contributors
 @cindex contributors
@@ -285,32 +337,128 @@ all contributed code and suggestions.
 @section New Features
 @cindex new features
 
-The look of all buffers can be changed by setting format-like variables.
+@itemize @bullet
+
+@item
+The look of all buffers can be changed by setting format-like variables
+(@pxref{Group Buffer Format} and @pxref{Summary Buffer Format}). 
  
-Local spool and several @sc{nntp} servers can be used at once.  Virtual
-groups and private mail groups are featured.
+@item 
+Local spool and several @sc{nntp} servers can be used at once
+(@pxref{Foreign Groups}).  
+
+@item 
+You can combine groups into virtual groups (@pxref{nnvirtual}). 
+
+@item 
+You can read a number of different mail formats (@pxref{Reading Mail}).
+All the mail backends implement a convenient mail expiry scheme
+(@code{Expiring Old Mail Articles}). 
 
+@item
 Gnus can use various strategies for gathering threads that have lost
 their roots (thereby gathering loose sub-threads in one thread) or it
-can go back and retrieve enough headers to build a complete thread.
+can go back and retrieve enough headers to build a complete thread
+(@pxref{Customizing Threading}).
 
+@item 
 Killed groups can be displayed in the group buffer, and you can read
 them as well.
 
+@item 
 Gnus can do partial group updates - you do not have to retrieve the
-entire active file just to check for new articles in a few groups.
+entire active file just to check for new articles in a few groups
+(@pxref{The Active File}).
+
+@item 
+Gnus implements a sliding scale of subscribedness to groups
+(@pxref{Group Levels}).
+
+@item 
+You can score articles according to any number of criteria (@pxref{Score
+Files}).  You can even get Gnus to score articles for you
+(@pxref{Adaptive Scoring}). 
+
+@item 
+Gnus maintains a dribble buffer that is auto-saved the normal Emacs
+manner, so it should be difficult to lose much data on what you have
+read if your machine should go down (@pxref{Auto Save}). 
+
+@item 
+Gnus now has its own startup file to avoid cluttering up the
+@file{.emacs} file.
+
+@item 
+You can set the process mark on both groups and articles and perform
+operations on all the marked items (@pxref{Process/Prefix}).
+
+@item 
+You can grep through a subset of groups and create a group from the
+results (@pxref{nnkiboze}). 
+
+@item 
+You can list subsets of groups according to, well, anything
+(@pxref{Listing Groups}). 
+
+@item 
+You can browse foreign servers and subscribe to groups from those
+servers (@pxref{Browse Foreign Server}). 
+
+@item 
+Gnus can fetch articles asynchronously on a second connection to the
+server (@pxref{Asynchronous Fetching}).
 
-Gnus implements a sliding scale of subscribedness to groups.
+@item 
+You can cache articles locally (@pxref{Article Caching}). 
+
+@item 
+The uudecode functions have been expanded and generalized
+(@pxref{Decoding Articles}). 
+
+@item
+You can still post uuencoded articles, which was a little-known feature
+of @sc{gnus} past (@pxref{Uuencoding & Posting}).
+
+@item
+Fetching parents (and other articles) now actually works without
+glitches (@pxref{Finding the Parent}). 
+
+@item
+Gnus can fetch FAQs to and descriptions of groups (@pxref{Group
+Information}). 
+
+@item
+Digests (and other files) can be used as the basis for groups
+(@pxref{nndoc}).
+
+@item 
+Articles can be highlighted and customized (@pxref{Customizing
+Articles}). 
+
+@item
+All Gnus buffers can be customized in a difficult fashion
+(@pxref{Windows Configuration}). 
+
+@item
+You can click on buttons instead of using the keyboard
+(@pxref{Buttons}). 
+
+@end itemize
+
+This is, of course, just a @emph{short} overview of the @emph{most}
+important new features.  No, really.  There are tons more.  Yes, we have
+feeping creaturism in full effect, but nothing too gratuitous, I would
+hope. 
 
-The approach to killing has been changed.  Instead of simply killing or
-not, you can score articles for easier reading.
 
 @node Newest Features
 @section Newest Features
 @cindex todo
 
 Also known as the @dfn{todo list}.  Sure to be implemented before the
-next millennium.
+next millennium. 
+
+Be afraid.  Be very afraid.
 
 @itemize @bullet
 @item
@@ -318,14 +466,77 @@ Native @sc{mime} support is something that should be done.  I was hoping
 I could steal code from @code{Mew}, the @sc{mime} mail reader for Emacs,
 but I'm not quite sure what the status of that project is.  Gnus might
 support @sc{mime} quite soon, and it might not.
+
+@item
+@code{trn}-like trees.
+@item
+@code{nn}-like pick-and-read summary interface.
+@item 
+NoCeM support.
+@item 
+Frame configuration.
+@item
+Re-sending bounced mail and rejected articles.
+@item 
+Floating point group levels and group bubbling.
+@item
+@file{/etc/nntpserver} usage.
+@item 
+Automatic re-scan of incoming mail.
+@item
+Buttonize more stuff in the article buffer.
+@item
+A better and simpler method for specifying mail composing methods. 
+@item 
+Marks for saved, forwarded, etc articles.
+@item 
+Speed up caching and adaptive scoring.
+@item
+Gather thread by filling in missing Message-IDs.
+@item 
+Slave Gnusii to enable several Gnusii to run at once.
+@item 
+PGP support.
+@item
+Allow posting through mail-to-news gateways.
+@item
+Allow renaming mail groups in a simple fashion.
+@item
+Speed up massive group massacres.
+@item
+@code{jka-compr} isn't fully supported.
+@item
+Create better digests.
+@item
+Do better word-wrap on cited text.
+@item 
+Better X-Face support with X-Face databases and stuff. 
+@item
+Support SELF-DISCIPLINE pins.
 @item
-When the user references the parent of an article, some sort of
-re-threading should be done to build a proper tree.  The same goes for
-article expunging.  However, as it stands, it's not a trivial issue to
-re-generate parts of the summary buffer.  Generating the entire buffer
-is very easy, but slow.
+Really do unbinhexing.
+@item
+Fetching by Message-ID should work in mail groups.
+@item
+Listing of all active groups.
+@item
+XEmacs toolbar.
+@item
+Do the X-Receipt-To thing.
+@item
+Hierarchal group buffers.
+@item
+Don't kill summary buffers upon exit from the groups.
+@item
+Allow adaption on secondary marks.
 @end itemize
 
+And much, much, much more.  There is more to come than has already been
+implemented.  (But that's always true, isn't it?)
+
+You can probably sneak a look at the actual up-to-the-second todo list
+by snooping @code{<URL:http://www.ifi.uio.no/~larsi/sgnus/todo>}. 
+
 @node Terminology
 @chapter Terminology
 
@@ -750,6 +961,16 @@ groups that you aren't interested in.
 @section Startup Variables
 
 @table @code
+@item gnus-load-hook
+@vindex gnus-load-hook
+A hook that is run while Gnus is being loaded.  Note that this hook will
+normally be run just once in a single Emacs session, no matter how many
+times you start Gnus.
+
+@item gnus-startup-hook
+@vindex gnus-startup-hook
+A hook that is run after starting up Gnus successfully.
+
 @item gnus-check-bogus-newsgroups
 @vindex gnus-check-bogus-newsgroups
 If non-@code{nil}, Gnus will check for and delete all bogus groups at
@@ -758,11 +979,13 @@ startup.  A @dfn{bogus group} is a group that you have in your
 bogus groups isn't very quick, so to save time and resources, it's best
 to leave this option off, and instead do the checking for bogus groups
 once in a while from the group buffer (@pxref{Group Maintenance}).
+
 @item gnus-inhibit-startup-message
 @vindex gnus-inhibit-startup-message
 If non-@code{nil}, the startup message won't be displayed.  That way,
 your boss might not notice that you are reading news instead of doing
 your job.
+
 @item gnus-no-groups-message
 @vindex gnus-no-groups-message
 Message displayed by Gnus when no groups are available.
@@ -1742,24 +1965,21 @@ This should be one of @code{mbox}, @code{babyl} or @code{digest}.
 Reading mail with a newsreader - isn't that just plain WeIrD? But of
 course.
 
+Gnus will read the mail spool when you activate a mail group.  The mail
+file is first copied to your home directory.  What happens after that
+depends on what format you want to store your mail in.
+
 @menu
 * Creating Mail Groups::         How to create mail groups.
 * Fancy Mail Splitting::         Gnus can do hairy splitting of incoming mail.
 * Mail & Procmail::              Reading mail groups that procmail create.
 * Expiring Old Mail Articles::   Getting rid of unwanted mail.
 * Not Reading Mail::             Using mail backends for reading other files.
-@end menu
-
-Gnus will read the mail spool when you activate a mail group.  The mail
-file is first copied to your home directory.  What happens after that
-depends on what format you want to store your mail in.
-
-@menu
-* nnmbox::    Using the (quite) standard Un*x mbox.
-* nnbabyl::   Many Emacs programs use the rmail babyl format.
-* nnml::      Store your mail in a private spool?
-* nnmh::      An mhspool-like backend useful for procmail people.
-* nnfolder::  Having one file for each group.
+* nnmbox::                       Using the (quite) standard Un*x mbox.
+* nnbabyl::                      Emacs programs use the rmail babyl format.
+* nnml::                         Store your mail in a private spool?
+* nnmh::                         An mhspool-like backend.
+* nnfolder::                     Having one file for each group.
 @end menu
 
 @vindex nnmail-read-incoming-hook
@@ -2599,6 +2819,7 @@ Restart Gnus (@code{gnus-group-restart}).
 @item r
 @kindex r (Group)
 @findex gnus-group-read-init-file
+@vindex gnus-init-file
 Read the init file (@code{gnus-init-file}, which defaults to
 @file{~/.gnus}) (@code{gnus-group-read-init-file}).
 @item s
@@ -3348,8 +3569,8 @@ outgoing articles.
 If @code{nil}, always ignore the Followup-To header.  If it is @code{t},
 use its value, but ignore the special value @samp{poster}, which will
 send the followup as a reply mail to the person you are responding to.
-If it is neither @code{nil} nor @code{t}, always use the Followup-To
-value.
+If it is the symbol @code{ask}, query the user before posting.
+If it is the symbol @code{use}, always use the value.
 
 @item gnus-followup-to-function
 @vindex gnus-followup-to-function
@@ -4572,6 +4793,8 @@ encoded in some way or other.  Gnus can decode them for you.
 * Uuencoded Articles::    Uudecode articles.
 * Shared Articles::       Unshar articles.
 * PostScript Files::      Split PostScript.
+* Decoding Variables::    Variables for a happy decoding.
+* Viewing Files::         You want to look at the result of the decoding?
 @end menu
 
 All these functions use the process/prefix convention
@@ -4592,11 +4815,6 @@ Subjects that are nonstandard, like @samp{cat.gif (2/3) Part 6 of a
 series}, will not be properly recognized by any of the automatic viewing
 commands, and you have to mark the articles manually with @key{#}.
 
-@menu 
-* Decoding Variables::     Variables for a happy decoding.
-* Viewing Files::          You want to look at the result of the decoding?
-@end menu
-
 @node Uuencoded Articles
 @subsection Uuencoded Articles
 @cindex uudecode
@@ -5376,8 +5594,8 @@ directly.  In that case, the functions that return these non-file score
 alists should probably be placed before the "real" score file functions,
 to ensure that the last score file returned is the local score file.
 Phu. 
-@item gnus-kill-expiry-days
-@vindex gnus-kill-expiry-days
+@item gnus-score-expiry-days
+@vindex gnus-score-expiry-days
 This variable says how many days should pass before an unused score file
 entry is expired.  The default is 7.
 @end table
@@ -6143,11 +6361,11 @@ make them invisible if you want to make them go away.
 @node Article Keymap
 @section Article Keymap
 
-Most of the keystrokes in the summary buffer can also be used in the
-article buffer.  They should behave as if you typed them in the summary
-buffer, which means that you don't actually have to have a summary
-buffer displayed while reading.  You can do it all from the article
-buffer.
+@c Most of the keystrokes in the summary buffer can also be used in the
+@c article buffer.  They should behave as if you typed them in the summary
+@c buffer, which means that you don't actually have to have a summary
+@c buffer displayed while reading.  You can do it all from the article
+@c buffer.
 
 A few additional keystrokes are available:
 
@@ -6346,6 +6564,11 @@ Here's the method for the public spool:
 @node Servers & Methods
 @section Servers & Methods
 
+Wherever you would normally use a select method
+(eg. @code{gnus-secondary-select-method}, in the group select method,
+when browsing a foreign server) you can use a virtual server name
+instead.  This could potentially save lots of typing.  And it's nice all
+over.
 
 
 @node Various
@@ -6785,6 +7008,681 @@ not for a seat upon the dais@*
 but at the common table.@*
 @end quotation
 
+@node Appendix
+@chapter A Programmer's Guide to Gnus
+
+It is my hope that other people will figure out smart stuff that Gnus
+can do, and that other people will write those smart things as well.  To
+facilitate that I thought it would be a good idea to describe the inner
+workings of Gnus. And some of the not-so-inner workings, while I'm at
+it.
+
+You can never expect the internals of a program not to change, but I
+will be defining (in some details) the interface between Gnus and its
+backends (this is written in stone), the format of the score files
+(ditto), data structures (some are less likely to change than others)
+and general method of operations.
+
+@menu 
+* Backend Interface::        How Gnus communicates with the servers.
+* Score File Syntax::        A BNF definition of the score file standard.
+* Headers::                  How Gnus stores headers internally.
+* Ranges::                   A handy format for storing mucho numbers.
+* Group Info::               The group info format.
+@end menu
+
+
+@node Backend Interface
+@section Backend Interface
+
+Gnus doesn't know anything about nntp, spools, mail or virtual groups.
+It only knows how to talk to @dfn{virtual servers}.  A virtual server is
+a @dfn{backend} and some @dfn{backend variables}.  As examples of the
+first, we have @code{nntp}, @code{nnspool} and @code{nnmbox}.  As
+examples of the latter we have @code{nntp-port-number} and
+@code{nnmbox-directory}. 
+
+When Gnus asks for information from a backend -- say @code{nntp} -- on
+something, it will normally include a virtual server name in the
+function parameters.  (If not, the backend should use the "current"
+virtual server.)  For instance, @code{nntp-request-list} takes a virtual
+server as its only (optional) parameter.  If this virtual server hasn't
+been opened, the function should fail.
+
+Note that a virtual server name has no relation to some physical server
+name.  Take this example:
+
+@lisp
+(nntp "odd-one" 
+      (nntp-address "ifi.uio.no") 
+      (nntp-port-number 4324))
+@end lisp
+
+Here the virtual server name is @samp{"odd-one"} while the name of
+the physical server is @samp{"ifi.uio.no"}. 
+
+The backends should be able to switch between several virtual servers.
+The standard backends implement this by keeping an alist of virtual
+server environments that it pulls down/pushes up when needed.  
+
+There are two groups of interface functions: @dfn{required functions},
+which must be present, and @dfn{optional functions}, which Gnus will
+always check whether are present before attempting to call.
+
+All these functions are expected to return data in the buffer
+@code{nntp-server-buffer} (@samp{" *nntpd*"}), which is somewhat
+unfortunately named, but we'll have to live with it.  When I talk about
+"resulting data", I always refer to the data in that buffer.  When I
+talk about "return value", I talk about the function value returned by
+the function call.
+
+Some backends could be said to be @dfn{server-forming} backends, and
+some might be said to not be.  The latter are backends that generally
+only operate on one group at a time, and have no concept of "server" --
+they have a group, and they deliver info on that group and nothing more.
+
+In the examples and definitions I will refer to the imaginary backend
+@code{nnchoke}. 
+
+@menu
+* Required Backend Functions::        Functions that must be implemented.
+* Optional Backend Functions::        Functions that need not be implemented.
+@end menu
+
+
+@node Required Backend Functions
+@subsection Required Backend Functions
+
+@table @code
+
+@item (nnchoke-retrieve-headers ARTICLES &optional GROUP SERVER)
+
+@var{articles} is either a range of article numbers or a list of
+@code{Message-ID}s.  Current backends do not fully support either - only
+sequences (lists) of article numbers, and most backends do not support
+retrieval of @code{Message-ID}s.  But they should try for both. 
+
+The result data should either be HEADs or NOV lines, and the result
+value should either be @code{headers} or @code{nov} to reflect this.
+This might later be expanded to @code{various}, which will be a mixture
+of HEADs and NOV lines, but this is currently not supported by Gnus.  
+
+Here's an example HEAD:
+
+@example
+221 1056 Article retrieved.
+Path: ifi.uio.no!sturles
+From: sturles@@ifi.uio.no (Sturle Sunde)
+Newsgroups: ifi.discussion
+Subject: Re: Something very droll
+Date: 27 Oct 1994 14:02:57 +0100
+Organization: Dept. of Informatics, University of Oslo, Norway
+Lines: 26
+Message-ID: <38o8e1$a0o@@holmenkollen.ifi.uio.no>
+References: <38jdmq$4qu@@visbur.ifi.uio.no>
+NNTP-Posting-Host: holmenkollen.ifi.uio.no
+.
+@end example
+
+So a @code{headers} return value would imply that there's a number of
+these in the data buffer.
+
+Here's a BNF definition of such a buffer:
+
+@example
+headers        = *head
+head           = error / valid-head
+error-message  = [ "4" / "5" ] 2number " " <error message> eol
+valid-head     = valid-message *header "." eol
+valid-message  = "221 " <number> " Article retrieved." eol
+header         = <text> eol
+@end example
+
+If the return value is @code{nov}, the data buffer should contain
+@dfn{network overview database} lines.  These are basically fields
+separated by tabs. 
+
+@example
+nov-buffer = *nov-line
+nov-line   = 8*9 [ field <TAB> ] eol
+field      = <text except TAB>
+@end example
+
+For a closer explanation what should be in those fields,
+@xref{Headers}. 
+
+
+@item (nnchoke-open-server SERVER &optional DEFINITIONS)
+
+@var{server} is here the virtual server name.  @var{definitions} is a
+list of @code{(VARIABLE VALUE)} pairs that defines this virtual server. 
+
+If the server can't be opened, no error should be signaled.  The backend
+may then choose to refuse further attempts at connecting to this
+server.  In fact, it should do so. 
+
+If the server is opened already, this function should return a
+non-@code{nil} value.  There should be no data returned.
+
+
+@item (nnchoke-close-server &optional SERVER)
+
+Close connection to @var{server} and free all resources connected
+to it. 
+
+There should be no data returned.
+
+
+@item (nnchoke-request-close)
+
+Close connection to all servers and free all resources that the backend
+have reserved.  All buffers that have been created by that backend
+should be killed.  (Not the @code{nntp-server-buffer}, though.)
+
+There should be no data returned. 
+
+
+@item (nnchoke-server-opened &optional SERVER)
+
+This function should return whether @var{server} is opened, and that the
+connection to it is still alive.  This function should under no
+circumstances attempt to reconnect to a server that is has lost
+connection to. 
+
+There should be no data returned.
+
+
+@item (nnchoke-status-message &optional SERVER)
+
+This function should return the last error message from @var{server}. 
+
+There should be no data returned.
+
+
+@item (nnchoke-request-article ARTICLE &optional GROUP SERVER TO-BUFFER)
+
+The result data from this function should be the article specified by
+@var{article}.  This might either be a @code{Message-ID} or a number.
+It is optional whether to implement retrieval by @code{Message-ID}, but
+it would be nice if that were possible.
+
+If @var{to-buffer} is non-@code{nil}, the result data should be returned
+in this buffer instead of the normal data buffer.  This is to make it
+possible to avoid copying large amounts of data from one buffer to
+another, and Gnus mainly request articles to be inserted directly into
+its article buffer.
+
+
+@item (nnchoke-open-group GROUP &optional SERVER)
+
+Make @var{group} the current group.  
+
+There should be no data returned by this function.
+
+
+@item (nnchoke-request-group GROUP &optional SERVER)
+
+Get data on @var{group}.  This function also has the side effect of
+making @var{group} the current group. 
+
+Here's an example of some result data and a definition of the same:
+
+@example
+211 56 1000 1059 ifi.discussion
+@end example
+
+The first number is the status, which should be @samp{211}.  Next is the
+total number of articles in the group, the lowest article number, the
+highest article number, and finally the group name.  Note that the total
+number of articles may be less than one might think while just
+considering the highest and lowest article numbers, but some articles
+may have been cancelled.  Gnus just discards the total-number, so
+whether one should take the bother to generate it properly (if that is a
+problem) is left as an excercise to the reader.
+
+@example
+group-status = [ error / info ] eol
+error        = [ "4" / "5" ] 2<number> " " <Error message>
+info         = "211 " 3* [ <number> " " ] <string>
+@end example
+
+
+@item (nnchoke-close-group GROUP &optional SERVER)
+
+Close @var{group} and free any resources connected to it.  This will be
+a no-op on most backends. 
+
+There should be no data returned.
+
+
+@item (nnchoke-request-list &optional SERVER)
+
+Return a list of all groups available on @var{server}.  And that means
+@emph{all}. 
+
+Here's an example from a server that only carries two groups:
+
+@example
+ifi.test 0000002200 0000002000 y
+ifi.discussion 3324 3300 n
+@end example
+
+On each line we have a group name, then the highest article number in
+that group, the lowest article number, and finally a flag.
+
+@example
+active-file = *active-line
+active-line = name " " <number> " " <number> " " flags eol
+name        = <string>
+flags       = "n" / "y" / "m" / "x" / "j" / "=" name
+@end example
+
+The flag says whether the group is read-only (@samp{n}), is moderated
+(@samp{m}), is dead (@samp{x}), is aliased to some other group
+(@samp{=other-group} or none of the above (@samp{y}). 
+
+
+@item (nnchoke-request-post &optional SERVER)
+
+This function should post the current buffer.  It might return whether
+the posting was successful or not, but that's not required.  If, for
+instance, the posting is done asynchronously, it has generally not been
+completed by the time this function concludes.  In that case, this
+function should set up some kind of sentinel to beep the user loud and
+clear if the posting could not be completed.
+
+There should be no result data from this function. 
+
+
+@item (nnchoke-request-post-buffer POST GROUP SUBJECT HEADER ARTICLE-BUFFER INFO FOLLOW-TO RESPECT-POSTER)
+
+This function should return a buffer suitable for composing an article
+to be posted by @code{nnchoke-request-post}.  If @var{post} is
+non-@code{nil}, this is not a followup, but a totally new article.
+@var{group} is the name of the group to be posted to.  @var{subject} is
+the subject of the message.  @var{article-buffer} is the buffer being
+followed up, if that is the case.  @var{info} is the group info.
+@var{follow-to} is the group that one is supposed to re-direct the
+article to.  If @var{respect-poster} is non-@code{nil}, the special
+@samp{"poster"} value of a @code{Followup-To} header is to be respected.
+
+There should be no result data returned.
+
+@end table
+
+@node Optional Backend Functions
+@subsection Optional Backend Functions
+
+@table @code
+
+@item (nnchoke-retrieve-groups GROUPS &optional SERVER)
+
+@var{groups} is a list of groups, and this function should request data
+on all those groups.  How it does it is of no concern to Gnus, but it
+should attempt to do this in a speedy fashion.
+
+The return value of this function can be either @code{active} or
+@code{group}, which says what the format of the result data is.  The
+former is in the same format as the data from
+@code{nnchoke-request-list}, while the latter is a buffer full of lines
+in the same format as @code{nnchoke-request-group} gives.
+
+@example
+group-buffer = *active-line / *group-status
+@end example
+
+
+@item (nnchoke-request-update-info GROUP INFO &optional SERVER)
+
+A Gnus group info (@pxref{Group Info}) is handed to the backend for
+alterations.  This comes in handy if the backend really carries all the
+information (as is the case with virtual an imap groups).  This function
+may alter the info in any manner it sees fit, and should return the
+(altered) group info.  This function may alter the group info
+destructively, so no copying is needed before boogying. 
+
+There should be no result data from this function.
+
+
+@item (nnchoke-request-scan &optional GROUP SERVER)
+
+This function may be called at any time (by Gnus or anything else) to
+request that the backend check for incoming articles, in one way or
+another.  A mail backend will typically read the spool file or query the
+POP server when this function is invoked.  The @var{group} doesn't have
+to be heeded -- if the backend decides that it is too much work just
+scanning for a single group, it may do a total scan of all groups.  It
+would be nice, however, to keep things local if that's practical.
+
+There should be no result data from this function.
+
+
+@item (nnchoke-request-asynchronous GROUP &optional SERVER ARTICLES)
+
+This is a request to fetch articles asynchronously later.
+@var{articles} is an alist of @var{(article-number line-number)}.  One
+would generally expect that if one later fetches article number 4, for
+instance, some sort of asynchronous fetching of the articles after 4
+(which might be 5, 6, 7 or 11, 3, 909 depending on the order in that
+alist) would be fetched asynchronouly, but that is left up to the
+backend.  Gnus doesn't care.
+
+There should be no result data from this function.
+
+@item (nnchoke-request-group-description GROUP &optional SERVER)
+
+The result data from this function should be a description of
+@var{group}. 
+
+@example
+description-line = name <TAB> description eol
+name             = <string>
+description      = <text>
+@end example
+
+@item (nnchoke-request-list-newsgroups &optional SERVER)
+
+The result data from this function should be the description of all
+groups available on the server.
+
+@example
+description-buffer = *description-line
+@end example
+
+
+@item (nnchoke-request-newgroups DATE &optional SERVER)
+
+The result data from this function should be all groups that were
+created after @samp{date}, which is in normal human-readable date
+format.  The data should be in the active buffer format.
+
+
+@item (nnchoke-request-create-groups GROUP &optional SERVER)
+
+This function should create an empty group with name @var{group}.  
+
+There should be no return data.
+
+
+@item (nnchoke-request-expire-articles ARTICLES &optional GROUP SERVER FORCE)
+
+This function should run the expiry process on all articles in the
+@var{articles} range (which is currently a simple list of article
+numbers.)  It is left up to the backend to decide how old articles
+should be before they are removed by this function.  If @var{force} is
+non-@code{nil}, all @var{articles} should be deleted, no matter how new
+they are. 
+
+This function should return a list of articles that it did not/was not
+able to delete.
+
+There should be no result data returned.
+
+
+@item (nnchoke-request-move-article ARTICLE GROUP SERVER ACCEPT-FORM
+&optional LAST)
+
+This function should move @var{article} (which is a number) from
+@var{group} by calling @var{accept-form}.  
+
+This function should ready the article in question for moving by
+removing any header lines it has added to the article, and generally
+should "tidy up" the article.  Then it should @code{eval}
+@var{accept-form} in the buffer where the "tidy" article is.  This will
+do the actual copying.  If this @code{eval} returns a non-@code{nil}
+value, the article should be removed.
+
+If @var{last} is @code{nil}, that means that there is a high likelihood
+that there will be more requests issued shortly, so that allows some
+optimizations. 
+
+There should be no data returned. 
+
+
+@item (nnchoke-request-accept-article GROUP &optional LAST)
+
+This function takes the current buffer and inserts it into @var{group}.
+If @var{last} in @code{nil}, that means that there will be more calls to
+this function in short order.
+
+There should be no data returned.
+
+
+@item (nnchoke-request-replace-article ARTICLE GROUP BUFFER)
+
+This function should remove @var{article} (which is a number) from
+@var{group} and insert @var{buffer} there instead.
+
+There should be no data returned.
+
+@end table
+
+
+@node Score File Syntax
+@section Score File Syntax
+
+Score files are meant to be easily parsable, but yet extremely
+mallable.   It was decided that something that had the same read syntax
+as an Emacs Lisp list would fit that spec.
+
+Here's a typical score file:
+
+@lisp
+(("summary"
+  ("win95" -10000 nil s)
+  ("Gnus"))
+ ("from"
+  ("Lars" -1000))
+ (mark -100))
+@end lisp
+
+BNF definition of a score file:
+
+@example
+score-file       = "" / "(" *element ")"
+element          = rule / atom
+rule             = string-rule / number-rule / date-rule
+string-rule      = "(" quote string-header quote space *string-match ")"
+number-rule      = "(" quote number-header quote space *number-match ")"
+date-rule        = "(" quote date-header quote space *date-match ")"
+quote            = <ascii 34>
+string-header    = "subject" / "from" / "references" / "message-id" / 
+                   "xref" / "body" / "head" / "all" / "followup"
+number-header    = "lines" / "chars"
+date-header      = "date"
+string-match     = "(" quote <string> quote [ "" / [ space score [ "" / 
+                   space date [ "" / [ space string-match-t ] ] ] ] ] ")"
+score            = "nil" / <integer>
+date             = "nil" / <natural number>
+string-match-t   = "nil" / "s" / "substring" / "S" / "Substring" / 
+                   "r" / "regex" / "R" / "Regex" /
+                   "e" / "exact" / "E" / "Exact" /
+                   "f" / "fuzzy" / "F" / "Fuzzy"
+number-match     = "(" <integer> [ "" / [ space score [ "" / 
+                   space date [ "" / [ space number-match-t ] ] ] ] ] ")"
+number-match-t   = "nil" / "=" / "<" / ">" / ">=" / "<="
+date-match       = "(" quote <string> quote [ "" / [ space score [ "" / 
+                   space date [ "" / [ space date-match-t ] ] ] ] ")"
+date-match-t     = "nil" / "at" / "before" / "after"
+atom             = "(" [ required-atom / optional-atom ] ")"
+required-atom    = mark / expunge / mark-and-expunge / files /
+                   exclude-files / read-only / touched
+optional-atom    = adapt / local / eval 
+mark             = "mark" space nil-or-number
+nil-or-t         = "nil" / <integer>
+expunge          = "expunge" space nil-or-number
+mark-and-expunge = "mark-and-expunge" space nil-or-number
+files            = "files" *[ space <string> ]
+exclude-files    = "exclude-files" *[ space <string> ]
+read-only        = "read-only" [ space "nil" / space "t" ]
+adapt            = "adapt" [ space "nil" / space "t" / space adapt-rule ]
+adapt-rule       = "(" *[ <string> *[ "(" <string> <integer> ")" ] ")"
+local            = "local" *[ space "(" <string> space <form> ")" ]
+eval             = "eval" space <form>
+space            = *[ " " / <TAB> / <NEWLINE> ]
+@end example
+
+Any unrecognized elements in a score file should be ignored, but not
+discarded.  
+
+As you can see, white space is needed, but the type and amount of white
+space is irrelevant.  This means that formatting of the score file is
+left up to the programmer -- if it's simpler to just spew it all out on
+one looong line, then that's ok.
+
+The meaning of the various atoms are explained elsewhere in this
+manual. 
+
+@node Headers
+@section Headers
+
+Gnus uses internally a format for storing article headers that
+corresponds to the @sc{nov} format in a mysterious fashion.  One could
+almost suspect that the author looked at the @sc{nov} specification and
+just shamelessly @emph{stole} the entire thing, and one would be right.
+
+@dfn{Header} is a severly overloaded term.  "Header" is used in RFC1036
+to talk about lines in the head of an article (eg., @code{From}).  It is
+used by many people as a synonym for "head" -- "the header and the
+body".  (That should be avoided, in my opinion.)  And Gnus uses a format
+interanally that it calls "header", which is what I'm talking about
+here.  This is a 9-element vector, basically, with each header (ouch)
+having one slot. 
+
+These slots are, in order: @code{number}, @code{subject}, @code{from},
+@code{date}, @code{id}, @code{references}, @code{chars}, @code{lines},
+@code{xref}.  There are macros for accessing and setting these slots --
+they all have predicatable names beginning with @code{mail-header-} and
+@code{mail-header-set-}, respectively.  
+
+The @code{xref} slot is really a @code{misc} slot.  Any extra info will
+be put in there.
+
+@node Ranges
+@section Ranges
+
+@sc{gnus} introduced a concept that I found so useful that I've started
+using it a lot and have elaborated on it greatly. 
+
+The question is simple: If you have a large amount of objects that are
+identified by numbers (say, articles, to take a @emph{wild} example)
+that you want to callify as being "included", a normal sequence isn't
+very useful.  (A 200,000 length sequence is a bit long-winded.)
+
+The solution is as simple as the question: You just collapse the
+sequence. 
+
+@example
+(1 2 3 4 5 6 10 11 12)
+@end example
+
+is transformed into
+
+@example
+((1 . 6) (10 . 12))
+@end example
+
+To avoid having those nasty @samp{(13 . 13)} elements to denote a
+lonesome object, a @samp{13} is a valid element:
+
+@example
+((1 . 6) 7 (10 . 12))
+@end example
+
+This means that comparing two ranges to find out whether they are equal
+is slightly tricky:
+
+@example
+((1 . 6) 7 8 (10 . 12))
+@end example
+
+and
+
+@example
+((1 . 5) (7 . 8) (10 . 12))
+@end example
+
+are equal.  In fact, any non-descending list is a range:
+
+@example
+(1 2 3 4 5)
+@end example
+
+is a perfectly valid range, although a pretty longwinded one.  This is
+also legal:
+
+@example
+(1 . 5)
+@end example
+
+and is equal to the previous range.
+
+Here's a BNF definition of ranges.  Of course, one must remember the
+semantic requirement that the numbers are non-descending.  (Any number
+of repetition of the same number is allowed, but apt to disappear in
+range handling.)
+
+@example
+range           = simple-range / normal-range
+simple-range    = "(" number " . " number ")"
+normal-range    = "(" start-contents ")"
+contents        = "" / simple-range *[ " " contents ] / 
+                  number *[ " " contents ]
+@end example
+
+Gnus currently uses ranges to keep track of read articles and article
+marks.  I plan on implementing a number of range operators in C if The
+Powers That Be are willing to let me.  (I haven't asked yet, because I
+need to do some more thinking on what operators I need to make life
+totally range-based without ever having to convert back to normal
+sequences.) 
+
+
+@node Group Info
+@section Group Info
+
+Gnus stores all permanent info on groups in a @dfn{group info} list.
+This list is from three to six elements (or more) long and exhaustively
+describes the group.
+
+Here are two example group infos; one is a very simple group while the
+second is a more complex one:
+
+@example
+("no.group" 5 (1 . 54324))
+
+("nnml:my.mail" 3 ((1 . 5) 9 (20 . 55))
+                ((tick (15 . 19)) (replied 3 6 (19 . 23)))
+                (nnml "")
+                (auto-expire (to-address "ding@@ifi.uio.no")))
+@end example
+
+The first element is the group name as Gnus knows the group; the second
+is the group level; the third is the read articles in range format; the
+fourth is a list of article marks lists; the fifth is the select method;
+and the sixth contains the group parameters.
+
+Here's a BNF definition of the group info format:
+
+@example
+info          = "(" group space level space read 
+                [ "" / [ space marks-list [ "" / [ space method [ "" /
+                space parameters ] ] ] ] ] ")" 
+group         = quote <string> quote
+level         = <integer in the range of 1 to inf>
+read          = range
+marks-lists   = nil / "(" *marks ")"
+marks         = "(" <string> range ")"
+method        = "(" <string> *elisp-forms ")"
+parameters    = "(" *elisp-forms ")"
+@end example
+
+Actually that @samp{marks} rule is a fib.  A @samp{marks} is a
+@samp{<string>} consed on to a @samp{range}, but that's a bitch to say
+in pseudo-BNF.
+
+
 @node Index
 @chapter Index
 @printindex cp