*** empty log message ***
authorLars Magne Ingebrigtsen <larsi@gnus.org>
Sun, 14 Sep 1997 19:20:58 +0000 (19:20 +0000)
committerLars Magne Ingebrigtsen <larsi@gnus.org>
Sun, 14 Sep 1997 19:20:58 +0000 (19:20 +0000)
18 files changed:
lisp/ChangeLog
lisp/Makefile
lisp/gnus-agent.el
lisp/gnus-bcklg.el
lisp/gnus-draft.el [new file with mode: 0644]
lisp/gnus-int.el
lisp/gnus-msg.el
lisp/gnus-start.el
lisp/gnus-sum.el
lisp/gnus-win.el
lisp/gnus.el
lisp/message.el
lisp/nnagent.el
lisp/nndraft.el
lisp/nnmh.el
lisp/nnml.el
texi/gnus.texi
texi/message.texi

index 748e70f..155a397 100644 (file)
@@ -1,3 +1,37 @@
+Sun Sep 14 21:17:34 1997  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
+
+       * gnus.el: Quassia Gnus v0.3 is released.
+
+Sun Sep 14 01:51:45 1997  Lars Magne Ingebrigtsen  <larsi@ifi.uio.no>
+
+       * gnus-agent.el (gnus-agent-short-article): New variables.
+
+       * message.el (message-set-auto-save-file-name): Use drafts.
+
+       * nndraft.el (nndraft-request-expire-articles): Use it.
+
+       * nnmh.el (nnmh-deletable-article-p): Change.
+       (nnmh-allow-delete-final): New variable.
+
+       * gnus-msg.el (gnus-summary-send-draft): Removed.
+
+       * gnus.el (gnus-article-mark-lists): Save unsendable marks.
+
+       * gnus-sum.el (gnus-newsgroup-unsendable): New variable.
+
+       * gnus-draft.el: New file.
+
+       * gnus-sum.el (gnus-unsendable-mark): New variable.
+
+       * nndraft.el (nndraft-execute-nnmh-command): Cleanup.
+
+       * message.el (message-send-news): Use `gnus-request-post'.
+
+       * gnus-agent.el (gnus-agentize): New command.
+
+       * gnus-bcklg.el (gnus-backlog-remove-article): Remove the ident
+       from the list.
+
 Sun Sep 14 00:26:47 1997  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
 
        * gnus.el: Quassia Gnus v0.2 is released.
 Sun Sep 14 00:26:47 1997  Lars Magne Ingebrigtsen  <larsi@menja.ifi.uio.no>
 
        * gnus.el: Quassia Gnus v0.2 is released.
index 571c263..b949400 100644 (file)
@@ -12,7 +12,7 @@ clever:
        $(EMACS) $(FLAGS) -f dgnushack-compile
 
 some:
        $(EMACS) $(FLAGS) -f dgnushack-compile
 
 some:
-       $(EMACS) $(FLAGS) -f dgnushack-recompile
+       $(EMACS) $(FLAGS) -f dgnushack-compile
 
 tags:
        etags *.el
 
 tags:
        etags *.el
index daa2868..a856b76 100644 (file)
 
 ;;; Commentary:
 
 
 ;;; Commentary:
 
-;; (add-hook 'gnus-before-startup-hook 'gnus-open-agent)
-
 ;;; Code:
 
 (require 'gnus)
 (require 'gnus-cache)
 (require 'nnvirtual)
 (require 'gnus-sum)
 ;;; Code:
 
 (require 'gnus)
 (require 'gnus-cache)
 (require 'nnvirtual)
 (require 'gnus-sum)
+(eval-when-compile (require 'cl))
 
 (defcustom gnus-agent-directory (nnheader-concat gnus-directory "agent/")
   "Where the Gnus agent will store its files."
 
 (defcustom gnus-agent-directory (nnheader-concat gnus-directory "agent/")
   "Where the Gnus agent will store its files."
@@ -61,6 +60,7 @@
 (defvar gnus-category-group-cache nil)
 (defvar gnus-agent-spam-hashtb nil)
 (defvar gnus-agent-file-name nil)
 (defvar gnus-category-group-cache nil)
 (defvar gnus-agent-spam-hashtb nil)
 (defvar gnus-agent-file-name nil)
+(defvar gnus-agent-send-mail-function nil)
 
 (defvar gnus-plugged t
   "Whether Gnus is plugged or not.")
 
 (defvar gnus-plugged t
   "Whether Gnus is plugged or not.")
   (setq gnus-plugged nil)
   (gnus))
 
   (setq gnus-plugged nil)
   (gnus))
 
+;;;###autoload
+(defun gnus-agentize ()
+  "Allow Gnus to be an offline newsreader.
+The normal usage of this command is to put the following as the
+last form in your `.gnus.el' file:
+
+\(gnus-agentize)
+
+This will modify the `gnus-before-startup-hook', `gnus-post-method',
+and `message-send-mail-function' variables, and install the Gnus
+agent minor mode in all Gnus buffers."
+  (interactive)
+  (add-hook 'gnus-before-startup-hook 'gnus-open-agent)
+  (setq gnus-agent-send-mail-function message-send-mail-function
+       message-send-mail-function 'gnus-agent-send-mail))
+
+(defun gnus-agent-send-mail ()
+  (if gnus-plugged
+      (funcall gnus-agent-send-mail-function)
+    (goto-char (point-min))
+    (re-search-forward
+     (concat "^" (regexp-quote mail-header-separator) "\n"))
+    (replace-match "\n")
+    (gnus-request-accept-article "nndraft:drafts")))
+
 ;;;
 ;;; Group mode commands
 ;;;
 ;;;
 ;;; Group mode commands
 ;;;
@@ -793,6 +818,19 @@ the actual number of articles toggled is returned."
 (defvar gnus-category-mode-line-format "Gnus: %%b"
   "The format specification for the category mode line.")
 
 (defvar gnus-category-mode-line-format "Gnus: %%b"
   "The format specification for the category mode line.")
 
+(defvar gnus-agent-short-article 100
+  "Articles that have fewer lines than this are short.")
+
+(defvar gnus-agent-long-article 200
+  "Articles that have more lines than this are long.")
+
+(defvar gnus-agent-low-score 0
+  "Articles that have a score lower than this have a low score.")
+
+(defvar gnus-agent-high-score 0
+  "Articles that have a score higher than this have a high score.")
+
+
 ;;; Internal variables.
 
 (defvar gnus-category-buffer "*Agent Category*")
 ;;; Internal variables.
 
 (defvar gnus-category-buffer "*Agent Category*")
@@ -1027,20 +1065,20 @@ The following commands are available:
        (gnus-sethash string t gnus-agent-spam-hashtb)))))
 
 (defun gnus-agent-short-p ()
        (gnus-sethash string t gnus-agent-spam-hashtb)))))
 
 (defun gnus-agent-short-p ()
-  "Say whether an article is short (less than 100 lines) or not."
-  (< (mail-header-lines gnus-headers) 100))
+  "Say whether an article is short or not."
+  (< (mail-header-lines gnus-headers) gnus-agent-short-article))
 
 (defun gnus-agent-long-p ()
 
 (defun gnus-agent-long-p ()
-  "Say whether an article is long (more than 200 lines) or not."
-  (> (mail-header-lines gnus-headers) 200))
+  "Say whether an article is long or not."
+  (> (mail-header-lines gnus-headers) gnus-agent-long-article))
 
 (defun gnus-agent-low-scored-p ()
   "Say whether an article has a low score or not."
 
 (defun gnus-agent-low-scored-p ()
   "Say whether an article has a low score or not."
-  (< gnus-score gnus-summary-default-score))
+  (< gnus-score gnus-agent-low-score))
 
 (defun gnus-agent-high-scored-p ()
   "Say whether an article has a high score or not."
 
 (defun gnus-agent-high-scored-p ()
   "Say whether an article has a high score or not."
-  (> gnus-score gnus-summary-default-score))
+  (> gnus-score gnus-agent-low-score))
 
 (defun gnus-category-make-function (cat)
   "Make a function from category CAT."
 
 (defun gnus-category-make-function (cat)
   "Make a function from category CAT."
index ead87fe..d3f2ac5 100644 (file)
                     (1+ beg) 'gnus-backlog (current-buffer) (point-max)))
              (delete-region beg end)
              ;; Return success.
                     (1+ beg) 'gnus-backlog (current-buffer) (point-max)))
              (delete-region beg end)
              ;; Return success.
-             t)))))))
+             t))
+         (setq gnus-backlog-articles (delq ident gnus-backlog-articles)))))))
 
 (defun gnus-backlog-request-article (group number buffer)
   (when (numberp number)
 
 (defun gnus-backlog-request-article (group number buffer)
   (when (numberp number)
diff --git a/lisp/gnus-draft.el b/lisp/gnus-draft.el
new file mode 100644 (file)
index 0000000..fadd0aa
--- /dev/null
@@ -0,0 +1,148 @@
+;;; gnus-draft.el --- draft message support for Gnus
+;; Copyright (C) 1997 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <larsi@ifi.uio.no>
+;; Keywords: news
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING.  If not, write to the
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'gnus)
+(require 'gnus-sum)
+(require 'message)
+(require 'gnus-msg)
+(eval-when-compile (require 'cl))
+
+;;; Draft minor mode
+
+(defvar gnus-draft-mode nil
+  "Minor mode for providing a draft summary buffers.")
+
+(defvar gnus-draft-mode-map nil)
+
+(unless gnus-draft-mode-map
+  (setq gnus-draft-mode-map (make-sparse-keymap))
+
+  (gnus-define-keys gnus-draft-mode-map
+    "Dt" gnus-draft-toggle-sending
+    "De" gnus-draft-edit-message
+    "Ds" gnus-draft-send-message
+    "DS" gnus-draft-send-all-messages))
+
+(defun gnus-draft-make-menu-bar ()
+  (unless (boundp 'gnus-draft-menu)
+    (easy-menu-define
+     gnus-draft-menu gnus-draft-mode-map ""
+     '("Drafts"
+       ["Toggle whether to send" gnus-draft-toggle-sending t]))))
+
+(defun gnus-draft-mode (&optional arg)
+  "Minor mode for providing a draft summary buffers.
+
+\\{gnus-draft-mode-map}"
+  (interactive "P")
+  (when (eq major-mode 'gnus-summary-mode)
+    (if (not (set (make-local-variable 'gnus-draft-mode)
+                 (if (null arg) (not gnus-draft-mode)
+                   (> (prefix-numeric-value arg) 0))))
+       (remove-hook 'gnus-message-setup-hook 'gnus-draft-setup-message)
+      ;; Set up the menu.
+      (when (gnus-visual-p 'draft-menu 'menu)
+       (gnus-draft-make-menu-bar))
+      (gnus-add-minor-mode 'gnus-draft-mode " Draft" gnus-draft-mode-map)
+      (run-hooks 'gnus-draft-mode-hook))))
+
+;;; Commands
+
+(defun gnus-draft-toggle-sending (article)
+  "Toggle whether to send an article or not."
+  (interactive (list (gnus-summary-article-number)))
+  (if (gnus-draft-article-sendable-p article)
+      (progn
+       (push article gnus-newsgroup-unsendable)
+       (gnus-summary-mark-article article gnus-unsendable-mark))
+    (setq gnus-newsgroup-unsendable
+         (delq article gnus-newsgroup-unsendable))
+    (gnus-summary-mark-article article gnus-unread-mark))
+  (gnus-summary-position-point))
+
+(defun gnus-draft-edit-message ()
+  "Enter a mail/post buffer to edit and send the draft."
+  (interactive)
+  (gnus-set-global-variables)
+  (let ((article (gnus-summary-article-number)))
+    (gnus-draft-setup article)
+    (push
+     `((lambda ()
+        (when (buffer-name (get-buffer ,gnus-summary-buffer))
+          (save-excursion
+            (set-buffer (get-buffer ,gnus-summary-buffer))
+            (gnus-cache-possibly-remove-article ,article nil nil nil t)
+            (gnus-summary-mark-as-read ,article gnus-canceled-mark)))))
+     message-send-actions)))
+
+(defun gnus-draft-send-message (&optional n)
+  "Send the current draft."
+  (interactive "P")
+  (gnus-set-global-variables)
+  (let ((articles (gnus-summary-work-articles n))
+       article)
+    (while (setq article (pop articles))
+      (gnus-summary-remove-process-mark article)
+      (unless (memq article gnus-newsgroup-unsendable)
+       (gnus-draft-send article)
+       (gnus-summary-mark-article article gnus-canceled-mark)))))
+
+(defun gnus-draft-send (article)
+  "Send message ARTICLE."
+  (gnus-draft-setup article)
+  (message-send-and-exit))
+
+(defun gnus-draft-send-all-messages ()
+  "Send all the sendable drafts."
+  (interactive)
+  (gnus-uu-mark-buffer)
+  (gnus-draft-send-message))
+
+;;; Utility functions
+
+(defun gnus-draft-setup (article)
+  (gnus-setup-message 'forward
+    (message-mail)
+    (erase-buffer)
+    (if (not (gnus-request-restore-buffer article gnus-newsgroup-name))
+       (error "Couldn't restore the article")
+      ;; Insert the separator.
+      (goto-char (point-min))
+      (search-forward "\n\n")
+      (forward-char -1)
+      (insert mail-header-separator)
+      (forward-line 1)
+      (save-buffer 0))))
+
+(defun gnus-draft-article-sendable-p (article)
+  "Say whether ARTICLE is sendable."
+  (not (memq article gnus-newsgroup-unsendable)))
+
+(provide 'gnus-draft)
+
+;;; gnus-draft.el ends here
+
index c4e85f1..1fc205b 100644 (file)
@@ -391,7 +391,7 @@ If GROUP is nil, all groups on GNUS-COMMAND-METHOD are scanned."
             article (gnus-group-real-name group)
             (nth 1 gnus-command-method) accept-function last)))
 
             article (gnus-group-real-name group)
             (nth 1 gnus-command-method) accept-function last)))
 
-(defun gnus-request-accept-article (group gnus-command-method &optional last)
+(defun gnus-request-accept-article (group &optional gnus-command-method last)
   ;; Make sure there's a newline at the end of the article.
   (when (stringp gnus-command-method)
     (setq gnus-command-method (gnus-server-to-method gnus-command-method)))
   ;; Make sure there's a newline at the end of the article.
   (when (stringp gnus-command-method)
     (setq gnus-command-method (gnus-server-to-method gnus-command-method)))
index fc94bb2..2cd789b 100644 (file)
@@ -1046,27 +1046,6 @@ this is a reply."
                (insert " ")))
            (insert "\n")))))))
 
                (insert " ")))
            (insert "\n")))))))
 
-(defun gnus-summary-send-draft ()
-  "Enter a mail/post buffer to edit and send the draft."
-  (interactive)
-  (gnus-set-global-variables)
-  (let (buf)
-    (if (not (setq buf (gnus-request-restore-buffer
-                       (gnus-summary-article-number) gnus-newsgroup-name)))
-       (error "Couldn't restore the article")
-      (switch-to-buffer buf)
-      (when (eq major-mode 'news-reply-mode)
-       (local-set-key "\C-c\C-c" 'gnus-inews-news))
-      ;; Insert the separator.
-      (goto-char (point-min))
-      (search-forward "\n\n")
-      (forward-char -1)
-      (insert mail-header-separator)
-      ;; Configure windows.
-      (let ((gnus-draft-buffer (current-buffer)))
-       (gnus-configure-windows 'draft t)
-       (goto-char (point))))))
-
 (gnus-add-shutdown 'gnus-inews-close 'gnus)
 
 (defun gnus-inews-close ()
 (gnus-add-shutdown 'gnus-inews-close 'gnus)
 
 (defun gnus-inews-close ()
index 6931a6f..89dd8a7 100644 (file)
@@ -690,6 +690,7 @@ prompt the user for the name of an NNTP server to use."
 
          ;; Do the actual startup.
          (gnus-setup-news nil level dont-connect)
 
          ;; Do the actual startup.
          (gnus-setup-news nil level dont-connect)
+         (gnus-draft-setup)
          ;; Generate the group buffer.
          (gnus-group-list-groups level)
          (gnus-group-first-unread-group)
          ;; Generate the group buffer.
          (gnus-group-list-groups level)
          (gnus-group-first-unread-group)
@@ -697,6 +698,15 @@ prompt the user for the name of an NNTP server to use."
          (gnus-group-set-mode-line)
          (run-hooks 'gnus-started-hook))))))
 
          (gnus-group-set-mode-line)
          (run-hooks 'gnus-started-hook))))))
 
+(defun gnus-draft-setup ()
+  "Make sure the draft group exists."
+  (unless (gnus-gethash "nndraft:draft" gnus-newsrc-hashtb)
+    (gnus-request-create-group "draft" '(nndraft ""))
+    (let ((gnus-level-default-subscribed 1))
+      (gnus-subscribe-group "nndraft:draft" nil '(nndraft "")))
+    (gnus-group-set-parameter
+     "nndraft:draft" 'gnus-dummy '((gnus-draft-mode)))))
+
 ;;;###autoload
 (defun gnus-unload ()
   "Unload all Gnus features."
 ;;;###autoload
 (defun gnus-unload ()
   "Unload all Gnus features."
index 54770d0..9489614 100644 (file)
@@ -423,6 +423,11 @@ It uses the same syntax as the `gnus-split-methods' variable."
   :group 'gnus-summary-marks
   :type 'character)
 
   :group 'gnus-summary-marks
   :type 'character)
 
+(defcustom gnus-unsendable-mark ?=
+  "*Mark used for articles that won't be sent."
+  :group 'gnus-summary-marks
+  :type 'character)
+
 (defcustom gnus-score-over-mark ?+
   "*Score mark used for articles with high scores."
   :group 'gnus-summary-marks
 (defcustom gnus-score-over-mark ?+
   "*Score mark used for articles with high scores."
   :group 'gnus-summary-marks
@@ -886,6 +891,9 @@ variable (string, integer, character, etc).")
 (defvar gnus-newsgroup-undownloaded nil
   "List of articles in the current newsgroup that haven't been downloaded..")
 
 (defvar gnus-newsgroup-undownloaded nil
   "List of articles in the current newsgroup that haven't been downloaded..")
 
+(defvar gnus-newsgroup-unsendable nil
+  "List of articles in the current newsgroup that won't be sent.")
+
 (defvar gnus-newsgroup-bookmarks nil
   "List of articles in the current newsgroup that have bookmarks.")
 
 (defvar gnus-newsgroup-bookmarks nil
   "List of articles in the current newsgroup that have bookmarks.")
 
@@ -926,6 +934,7 @@ variable (string, integer, character, etc).")
     gnus-newsgroup-replied gnus-newsgroup-expirable
     gnus-newsgroup-processable gnus-newsgroup-killed
     gnus-newsgroup-downloadable gnus-newsgroup-undownloaded
     gnus-newsgroup-replied gnus-newsgroup-expirable
     gnus-newsgroup-processable gnus-newsgroup-killed
     gnus-newsgroup-downloadable gnus-newsgroup-undownloaded
+    gnus-newsgroup-unsendable
     gnus-newsgroup-bookmarks gnus-newsgroup-dormant
     gnus-newsgroup-headers gnus-newsgroup-threads
     gnus-newsgroup-prepared gnus-summary-highlight-line-function
     gnus-newsgroup-bookmarks gnus-newsgroup-dormant
     gnus-newsgroup-headers gnus-newsgroup-threads
     gnus-newsgroup-prepared gnus-summary-highlight-line-function
@@ -2170,6 +2179,7 @@ This is all marks except unread, ticked, dormant, and expirable."
 
 (defmacro gnus-article-mark (number)
   `(cond
 
 (defmacro gnus-article-mark (number)
   `(cond
+    ((memq ,number gnus-newsgroup-unsendable) gnus-unsendable-mark)
     ((memq ,number gnus-newsgroup-undownloaded) gnus-undownloaded-mark)
     ((memq ,number gnus-newsgroup-downloadable) gnus-downloadable-mark)
     ((memq ,number gnus-newsgroup-unreads) gnus-unread-mark)
     ((memq ,number gnus-newsgroup-undownloaded) gnus-undownloaded-mark)
     ((memq ,number gnus-newsgroup-downloadable) gnus-downloadable-mark)
     ((memq ,number gnus-newsgroup-unreads) gnus-unread-mark)
index 87d7bb1..d66d0c5 100644 (file)
      (vertical 1.0
               (article 0.5)
               (message 1.0 point)))
      (vertical 1.0
               (article 0.5)
               (message 1.0 point)))
-    (draft
-     (vertical 1.0
-              (draft 1.0 point)))
     (pipe
      (vertical 1.0
               (summary 0.25 point)
     (pipe
      (vertical 1.0
               (summary 0.25 point)
index 7c7ab92..7470a71 100644 (file)
@@ -244,7 +244,7 @@ is restarted, and sometimes reloaded."
   :link '(custom-manual "(gnus)Exiting Gnus")
   :group 'gnus)
 
   :link '(custom-manual "(gnus)Exiting Gnus")
   :group 'gnus)
 
-(defconst gnus-version-number  "0.2"
+(defconst gnus-version-number "0.3"
   "Version number for this version of Gnus.")
 
 (defconst gnus-version (format "Quassia Gnus v%s" gnus-version-number)
   "Version number for this version of Gnus.")
 
 (defconst gnus-version (format "Quassia Gnus v%s" gnus-version-number)
@@ -1445,7 +1445,8 @@ want."
     (expirable . expire) (killed . killed)
     (bookmarks . bookmark) (dormant . dormant)
     (scored . score) (saved . save)
     (expirable . expire) (killed . killed)
     (bookmarks . bookmark) (dormant . dormant)
     (scored . score) (saved . save)
-    (cached . cache) (downloadable . download)))
+    (cached . cache) (downloadable . download)
+    (unsendable . unsend)))
 
 (defvar gnus-headers-retrieved-by nil)
 (defvar gnus-article-reply nil)
 
 (defvar gnus-headers-retrieved-by nil)
 (defvar gnus-article-reply nil)
@@ -1696,11 +1697,12 @@ gnus-newsrc-hashtb should be kept so that both hold the same information.")
       gnus-async-prefetch-article gnus-async-prefetch-remove-group
       gnus-async-halt-prefetch)
      ("gnus-agent" gnus-open-agent gnus-agent-get-function
       gnus-async-prefetch-article gnus-async-prefetch-remove-group
       gnus-async-halt-prefetch)
      ("gnus-agent" gnus-open-agent gnus-agent-get-function
-      gnus-agent-save-groups gnus-agent-save-active)
+      gnus-agent-save-groups gnus-agent-save-active gnus-agent-method-p)
      ("gnus-agent" :interactive t
       gnus-unplugged)
      ("gnus-vm" :interactive t gnus-summary-save-in-vm
      ("gnus-agent" :interactive t
       gnus-unplugged)
      ("gnus-vm" :interactive t gnus-summary-save-in-vm
-      gnus-summary-save-article-vm))))
+      gnus-summary-save-article-vm)
+     ("gnus-draft" :interactive t gnus-draft-mode))))
 
 ;;; gnus-sum.el thingies
 
 
 ;;; gnus-sum.el thingies
 
index 161ac26..1a6b555 100644 (file)
@@ -268,10 +268,10 @@ If t, use `message-user-organization-file'."
   :type 'file
   :group 'message-headers)
 
   :type 'file
   :group 'message-headers)
 
-(defcustom message-autosave-directory "~/"
-  ; (concat (file-name-as-directory message-directory) "drafts/")
-  "*Directory where message autosaves buffers.
-If nil, message won't autosave."
+(defcustom message-autosave-directory
+  (nnheader-concat message-directory "drafts/")
+  "*Directory where Message autosaves buffers.
+If nil, Message won't autosave."
   :group 'message-buffers
   :type 'directory)
 
   :group 'message-buffers
   :type 'directory)
 
@@ -805,6 +805,7 @@ The cdr of ech entry is a function for applying the face to a region.")
 (defvar message-buffer-list nil)
 (defvar message-this-is-news nil)
 (defvar message-this-is-mail nil)
 (defvar message-buffer-list nil)
 (defvar message-this-is-news nil)
 (defvar message-this-is-mail nil)
+(defvar message-draft-article nil)
 
 ;; Byte-compiler warning
 (defvar gnus-active-hashtb)
 
 ;; Byte-compiler warning
 (defvar gnus-active-hashtb)
@@ -1238,6 +1239,7 @@ C-c C-r  message-caesar-buffer-body (rot13 the message body)."
   (make-local-variable 'message-exit-actions) 
   (make-local-variable 'message-kill-actions)
   (make-local-variable 'message-postpone-actions)
   (make-local-variable 'message-exit-actions) 
   (make-local-variable 'message-kill-actions)
   (make-local-variable 'message-postpone-actions)
+  (make-local-variable 'message-draft-article)
   (set-syntax-table message-mode-syntax-table)
   (use-local-map message-mode-map)
   (setq local-abbrev-table message-mode-abbrev-table)
   (set-syntax-table message-mode-syntax-table)
   (use-local-map message-mode-map)
   (setq local-abbrev-table message-mode-abbrev-table)
@@ -1286,6 +1288,7 @@ C-c C-r  message-caesar-buffer-body (rot13 the message body)."
     (if (fboundp 'mail-abbrevs-setup)
        (mail-abbrevs-setup)
       (funcall (intern "mail-aliases-setup"))))
     (if (fboundp 'mail-abbrevs-setup)
        (mail-abbrevs-setup)
       (funcall (intern "mail-aliases-setup"))))
+  (message-set-auto-save-file-name)
   (run-hooks 'text-mode-hook 'message-mode-hook))
 
 \f
   (run-hooks 'text-mode-hook 'message-mode-hook))
 
 \f
@@ -1777,10 +1780,10 @@ the user from the mailer."
        ;; (mail-hist-put-headers-into-history))
        (run-hooks 'message-sent-hook)
        (message "Sending...done")
        ;; (mail-hist-put-headers-into-history))
        (run-hooks 'message-sent-hook)
        (message "Sending...done")
-       ;; If buffer has no file, mark it as unmodified and delete autosave.
-       (unless buffer-file-name
-         (set-buffer-modified-p nil)
-         (delete-auto-save-file-if-necessary t))
+       ;; Mark the buffer as unmodified and delete autosave.
+       (set-buffer-modified-p nil)
+       (delete-auto-save-file-if-necessary t)
+       (message-disassociate-draft)
        ;; Delete other mail buffers and stuff.
        (message-do-send-housekeeping)
        (message-do-actions message-send-actions)
        ;; Delete other mail buffers and stuff.
        (message-do-send-housekeeping)
        (message-do-actions message-send-actions)
@@ -2040,12 +2043,14 @@ to find out how to use this."
              (replace-match "\n")
              (backward-char 1))
            (run-hooks 'message-send-news-hook)
              (replace-match "\n")
              (backward-char 1))
            (run-hooks 'message-send-news-hook)
-           (require (car method))
-           (funcall (intern (format "%s-open-server" (car method)))
-                    (cadr method) (cddr method))
-           (setq result
-                 (funcall (intern (format "%s-request-post" (car method)))
-                          (cadr method))))
+           ;;(require (car method))
+           ;;(funcall (intern (format "%s-open-server" (car method)))
+           ;;(cadr method) (cddr method))
+           ;;(setq result
+           ;;    (funcall (intern (format "%s-request-post" (car method)))
+           ;;             (cadr method)))
+           (gnus-open-server method)
+           (setq result (gnus-request-post method)))
        (kill-buffer tembuf))
       (set-buffer messbuf)
       (if result
        (kill-buffer tembuf))
       (set-buffer messbuf)
       (if result
@@ -2998,7 +3003,6 @@ Headers already prepared in the buffer are not modified."
                   (copy-sequence message-required-mail-headers))))))
   (run-hooks 'message-signature-setup-hook)
   (message-insert-signature)
                   (copy-sequence message-required-mail-headers))))))
   (run-hooks 'message-signature-setup-hook)
   (message-insert-signature)
-  (message-set-auto-save-file-name)
   (save-restriction
     (message-narrow-to-headers)
     (run-hooks 'message-header-setup-hook))
   (save-restriction
     (message-narrow-to-headers)
     (run-hooks 'message-header-setup-hook))
@@ -3011,25 +3015,13 @@ Headers already prepared in the buffer are not modified."
 (defun message-set-auto-save-file-name ()
   "Associate the message buffer with a file in the drafts directory."
   (when message-autosave-directory
 (defun message-set-auto-save-file-name ()
   "Associate the message buffer with a file in the drafts directory."
   (when message-autosave-directory
-    (unless (file-exists-p message-autosave-directory)
-      (make-directory message-autosave-directory t))
-    (let ((name (make-temp-name
-                (expand-file-name
-                 (concat (file-name-as-directory message-autosave-directory)
-                         "msg."
-                         (nnheader-replace-chars-in-string
-                          (nnheader-replace-chars-in-string
-                           (buffer-name) ?* ?.)
-                          ?/ ?-))))))
-      (setq buffer-auto-save-file-name
-           (save-excursion
-             (prog1
-                 (progn
-                   (set-buffer (get-buffer-create " *draft tmp*"))
-                   (setq buffer-file-name name)
-                   (make-auto-save-file-name))
-               (kill-buffer (current-buffer)))))
-      (clear-visited-file-modtime))))
+    (setq message-draft-article (nndraft-request-associate-buffer "drafts"))
+    (clear-visited-file-modtime)))
+
+(defun message-disassociate-draft ()
+  "Disassociate the message buffer from the drafts directory."
+  (nndraft-request-expire-articles
+   (list message-draft-article) "drafts" nil t))
 
 \f
 
 
 \f
 
@@ -3702,7 +3694,8 @@ regexp varstr."
        (regexp "^gnus\\|^nn\\|^message"))
     (mapcar
      (lambda (local)
        (regexp "^gnus\\|^nn\\|^message"))
     (mapcar
      (lambda (local)
-       (when (and (car local)
+       (when (and (consp local)
+                 (car local)
                  (string-match regexp (symbol-name (car local))))
         (ignore-errors
           (set (make-local-variable (car local))
                  (string-match regexp (symbol-name (car local))))
         (ignore-errors
           (set (make-local-variable (car local))
index b5d967f..6b46765 100644 (file)
 (deffoo nnagent-request-newgroups (date server)
   nil)
 
 (deffoo nnagent-request-newgroups (date server)
   nil)
 
+(deffoo nnagent-request-post (&optional server)
+  (gnus-request-accept-article "nndraft:draft"))
+
 ;; Use nnml functions for just about everything.
 (nnoo-import nnagent
   (nnml))
 ;; Use nnml functions for just about everything.
 (nnoo-import nnagent
   (nnml))
index 5f2cb9a..59e54a7 100644 (file)
 ;;; Code:
 
 (require 'nnheader)
 ;;; Code:
 
 (require 'nnheader)
+(require 'nnmail)
+(require 'gnus-start)
 (require 'nnmh)
 (require 'nnoo)
 (require 'nnmh)
 (require 'nnoo)
-(eval-and-compile (require 'cl))
+(eval-when-compile (require 'cl))
 
 
-(nnoo-declare nndraft)
+(nnoo-declare nndraft
+  nnmh)
 
 
-(eval-and-compile
-  (autoload 'mail-send-and-exit "sendmail"))
-
-(defvoo nndraft-directory nil
-  "Where nndraft will store its directory.")
+(defvoo nndraft-directory (nnheader-concat message-directory "drafts/")
+  "Where nndraft will store its files."
+  nnmh-current-directory)
 
 \f
 
 
 \f
 
+(defvoo nndraft-current-group "" nil nnmh-current-group)
+(defvoo nndraft-top-directory nil nil nnmh-directory)
+(defvoo nndraft-get-new-mail nil nil nnmh-get-new-mail)
+
 (defconst nndraft-version "nndraft 1.0")
 (defconst nndraft-version "nndraft 1.0")
-(defvoo nndraft-status-string "")
+(defvoo nndraft-status-string "" nnmh-status-string)
 
 \f
 
 
 \f
 
 
 (nnoo-define-basics nndraft)
 
 
 (nnoo-define-basics nndraft)
 
+(deffoo nndraft-open-server (server &optional defs)
+  (push `(nndraft-current-group
+         ,(file-name-nondirectory (directory-file-name nndraft-directory)))
+       defs)
+  (push `(nndraft-top-directory
+         ,(file-name-directory (directory-file-name nndraft-directory)))
+       defs)
+  (nnoo-change-server 'nndraft server defs)
+  (cond
+   ((not (file-exists-p nndraft-directory))
+    (nndraft-close-server)
+    (nnheader-report 'nndraft "No such file or directory: %s"
+                    nndraft-directory))
+   ((not (file-directory-p (file-truename nndraft-directory)))
+    (nndraft-close-server)
+    (nnheader-report 'nndraft "Not a directory: %s" nndraft-directory))
+   (t
+    (nnheader-report 'nndraft "Opened server %s using directory %s"
+                    server nndraft-directory)
+    t)))
+
 (deffoo nndraft-retrieve-headers (articles &optional group server fetch-old)
   (save-excursion
     (set-buffer nntp-server-buffer)
 (deffoo nndraft-retrieve-headers (articles &optional group server fetch-old)
   (save-excursion
     (set-buffer nntp-server-buffer)
        (nnheader-fold-continuation-lines)
        'headers))))
 
        (nnheader-fold-continuation-lines)
        'headers))))
 
-(deffoo nndraft-open-server (server &optional defs)
-  (nnoo-change-server 'nndraft server defs)
-  (unless (assq 'nndraft-directory defs)
-    (setq nndraft-directory server))
-  (cond
-   ((not (file-exists-p nndraft-directory))
-    (nndraft-close-server)
-    (nnheader-report 'nndraft "No such file or directory: %s"
-                    nndraft-directory))
-   ((not (file-directory-p (file-truename nndraft-directory)))
-    (nndraft-close-server)
-    (nnheader-report 'nndraft "Not a directory: %s" nndraft-directory))
-   (t
-    (nnheader-report 'nndraft "Opened server %s using directory %s"
-                    server nndraft-directory)
-    t)))
-
 (deffoo nndraft-request-article (id &optional group server buffer)
   (when (numberp id)
     ;; We get the newest file of the auto-saved file and the
 (deffoo nndraft-request-article (id &optional group server buffer)
   (when (numberp id)
     ;; We get the newest file of the auto-saved file and the
 
 (deffoo nndraft-request-restore-buffer (article &optional group server)
   "Request a new buffer that is restored to the state of ARTICLE."
 
 (deffoo nndraft-request-restore-buffer (article &optional group server)
   "Request a new buffer that is restored to the state of ARTICLE."
-  (let ((file (nndraft-article-filename article ".state"))
-       nndraft-point nndraft-mode nndraft-buffer-name)
-    (when (file-exists-p file)
-      (load file t t t)
-      (when nndraft-buffer-name
-       (set-buffer (get-buffer-create
-                    (generate-new-buffer-name nndraft-buffer-name)))
-       (nndraft-request-article article group server (current-buffer))
-       (funcall nndraft-mode)
-       (let ((gnus-verbose-backends nil))
-         (nndraft-request-expire-articles (list article) group server t))
-       (goto-char nndraft-point))
-      nndraft-buffer-name)))
+  (when (nndraft-request-article article group server (current-buffer))
+    (let ((gnus-verbose-backends nil))
+      (nndraft-request-expire-articles (list article) group server t))
+    t))
 
 (deffoo nndraft-request-update-info (group info &optional server)
   (setcar (cddr info) nil)
 
 (deffoo nndraft-request-update-info (group info &optional server)
   (setcar (cddr info) nil)
-  (when (nth 3 info)
-    (setcar (nthcdr 3 info) nil))
+  (let (marks)
+    (when (setq marks (nth 3 info))
+      (setcar (nthcdr 3 info)
+             (if (assq 'unsend marks)
+                 (list (assq 'unsend marks))
+               nil))))
   t)
 
 (deffoo nndraft-request-associate-buffer (group)
   "Associate the current buffer with some article in the draft group."
   t)
 
 (deffoo nndraft-request-associate-buffer (group)
   "Associate the current buffer with some article in the draft group."
-  (let* ((gnus-verbose-backends nil)
-        (article (cdr (nndraft-request-accept-article
-                       group (nnoo-current-server 'nndraft) t 'noinsert)))
-        (file (nndraft-article-filename article)))
+  (let ((gnus-verbose-backends nil)
+       (buf (current-buffer))
+        article file)
+    (nnheader-temp-write nil
+      (insert-buffer buf)
+      (setq article (cdr (nndraft-request-accept-article
+                         group (nnoo-current-server 'nndraft) t 'noinsert)))
+      (setq file (nndraft-article-filename article)))
     (setq buffer-file-name file)
     (setq buffer-auto-save-file-name (make-auto-save-file-name))
     (clear-visited-file-modtime)
     article))
 
     (setq buffer-file-name file)
     (setq buffer-auto-save-file-name (make-auto-save-file-name))
     (clear-visited-file-modtime)
     article))
 
-(deffoo nndraft-request-group (group &optional server dont-check)
-  (prog1
-      (nndraft-execute-nnmh-command
-       `(nnmh-request-group group "" ,dont-check))
-    (nnheader-report 'nndraft nnmh-status-string)))
-
-(deffoo nndraft-request-list (&optional server dir)
-  (nndraft-execute-nnmh-command
-   `(nnmh-request-list nil ,dir)))
-
-(deffoo nndraft-request-newgroups (date &optional server)
-  (nndraft-execute-nnmh-command
-   `(nnmh-request-newgroups ,date ,server)))
-
-(deffoo nndraft-request-expire-articles
-  (articles group &optional server force)
-  (let ((res (nndraft-execute-nnmh-command
-             `(nnmh-request-expire-articles
-               ',articles group ,server ,force)))
-       article)
+(deffoo nndraft-request-expire-articles (articles group &optional server force)
+  (let* ((nnmh-allow-delete-final t)
+        (res (nndraft-execute-nnmh-command
+              `(nnmh-request-expire-articles
+                ',articles group ,server ,force)))
+        article)
     ;; Delete all the "state" files of articles that have been expired.
     (while articles
       (unless (memq (setq article (pop articles)) res)
     ;; Delete all the "state" files of articles that have been expired.
     (while articles
       (unless (memq (setq article (pop articles)) res)
-       (let ((file (nndraft-article-filename article ".state"))
-             (auto (nndraft-auto-save-file-name
+       (let ((auto (nndraft-auto-save-file-name
                     (nndraft-article-filename article))))
                     (nndraft-article-filename article))))
-         (when (file-exists-p file)
-           (funcall nnmail-delete-file-function file))
          (when (file-exists-p auto)
            (funcall nnmail-delete-file-function auto)))))
     res))
 
 (deffoo nndraft-request-accept-article (group &optional server last noinsert)
          (when (file-exists-p auto)
            (funcall nnmail-delete-file-function auto)))))
     res))
 
 (deffoo nndraft-request-accept-article (group &optional server last noinsert)
-  (let* ((point (point))
-        (mode major-mode)
-        (name (buffer-name))
-        (gnus-verbose-backends nil)
-        (gart (nndraft-execute-nnmh-command
-               `(nnmh-request-accept-article group ,server ,last noinsert)))
-        (state
-         (nndraft-article-filename (cdr gart) ".state")))
-    ;; Write the "state" file.
-    (save-excursion
-      (nnheader-set-temp-buffer " *draft state*")
-      (insert (format "%S\n" `(setq nndraft-mode (quote ,mode)
-                                   nndraft-point ,point
-                                   nndraft-buffer-name ,name)))
-      (write-region (point-min) (point-max) state nil 'silent)
-      (kill-buffer (current-buffer)))
-    gart))
-
-(deffoo nndraft-close-group (group &optional server)
-  t)
+  (let ((gnus-verbose-backends nil))
+    (nndraft-execute-nnmh-command
+     `(nnmh-request-accept-article group ,server ,last noinsert))))
 
 (deffoo nndraft-request-create-group (group &optional server args)
   (if (file-exists-p nndraft-directory)
 
 (deffoo nndraft-request-create-group (group &optional server args)
   (if (file-exists-p nndraft-directory)
 ;;; Low-Level Interface
 
 (defun nndraft-execute-nnmh-command (command)
 ;;; Low-Level Interface
 
 (defun nndraft-execute-nnmh-command (command)
-  (let ((dir (expand-file-name nndraft-directory)))
-    (when (string-match "/$" dir)
-      (setq dir (substring dir 0 (match-beginning 0))))
-    (string-match "/[^/]+$" dir)
-    (let ((group (substring dir (1+ (match-beginning 0))))
-          (nnmh-directory (substring dir 0 (1+ (match-beginning 0))))
-         (nnmail-keep-last-article nil)
-         (nnmh-get-new-mail nil))
-      (eval command))))
+  (let* ((dir (directory-file-name (expand-file-name nndraft-directory)))
+        (group (file-name-nondirectory dir))
+        (nnmh-directory (file-name-directory dir))
+        (nnmail-keep-last-article nil)
+        (nnmh-get-new-mail nil))
+    (eval command)))
 
 (defun nndraft-article-filename (article &rest args)
   (apply 'concat
 
 (defun nndraft-article-filename (article &rest args)
   (apply 'concat
          (make-auto-save-file-name))
       (kill-buffer (current-buffer)))))
 
          (make-auto-save-file-name))
       (kill-buffer (current-buffer)))))
 
+(nnoo-map-functions nndraft
+  (nnmh-retrieve-headers 0 nndraft-current-group 0 0)
+  (nnmh-request-group nndraft-current-group 0 0)
+  (nnmh-close-group nndraft-current-group 0)
+  (nnmh-request-list (nnoo-current-server 'nndraft) nndraft-directory)
+  (nnmh-request-newsgroups (nnoo-current-server 'nndraft) nndraft-directory))
+
 (provide 'nndraft)
 
 ;;; nndraft.el ends here
 (provide 'nndraft)
 
 ;;; nndraft.el ends here
index f91bed5..d5bd4f0 100644 (file)
@@ -60,6 +60,7 @@
 
 (defvoo nnmh-status-string "")
 (defvoo nnmh-group-alist nil)
 
 (defvoo nnmh-status-string "")
 (defvoo nnmh-group-alist nil)
+(defvoo nnmh-allow-delete-final nil)
 
 \f
 
 
 \f
 
@@ -76,8 +77,6 @@
           (large (and (numberp nnmail-large-newsgroup)
                       (> number nnmail-large-newsgroup)))
           (count 0)
           (large (and (numberp nnmail-large-newsgroup)
                       (> number nnmail-large-newsgroup)))
           (count 0)
-          ;; 1997/8/12 by MORIOKA Tomohiko
-          ;;   for XEmacs/mule.
           (pathname-coding-system 'binary)
           beg article)
       (nnmh-possibly-change-directory newsgroup server)
           (pathname-coding-system 'binary)
           beg article)
       (nnmh-possibly-change-directory newsgroup server)
   (let ((file (if (stringp id)
                  nil
                (concat nnmh-current-directory (int-to-string id))))
   (let ((file (if (stringp id)
                  nil
                (concat nnmh-current-directory (int-to-string id))))
-       ;; 1997/8/12 by MORIOKA Tomohiko
-       ;;      for XEmacs/mule.
        (pathname-coding-system 'binary)
        (nntp-server-buffer (or buffer nntp-server-buffer)))
     (and (stringp file)
        (pathname-coding-system 'binary)
        (nntp-server-buffer (or buffer nntp-server-buffer)))
     (and (stringp file)
 
 (deffoo nnmh-request-group (group &optional server dont-check)
   (let ((pathname (nnmail-group-pathname group nnmh-directory))
 
 (deffoo nnmh-request-group (group &optional server dont-check)
   (let ((pathname (nnmail-group-pathname group nnmh-directory))
-       ;; 1997/8/12 by MORIOKA Tomohiko
-       ;;      for XEmacs/mule.
        (pathname-coding-system 'binary)
        dir)
     (cond
        (pathname-coding-system 'binary)
        dir)
     (cond
     (nnmh-open-server server))
   (when newsgroup
     (let ((pathname (nnmail-group-pathname newsgroup nnmh-directory))
     (nnmh-open-server server))
   (when newsgroup
     (let ((pathname (nnmail-group-pathname newsgroup nnmh-directory))
-         ;; 1997/8/12 by MORIOKA Tomohiko
-         ;;    for XEmacs/mule.
          (pathname-coding-system 'binary))
       (if (file-directory-p pathname)
          (setq nnmh-current-directory pathname)
          (pathname-coding-system 'binary))
       (if (file-directory-p pathname)
          (setq nnmh-current-directory pathname)
   (let ((path (concat nnmh-current-directory (int-to-string article))))
     ;; Writable.
     (and (file-writable-p path)
   (let ((path (concat nnmh-current-directory (int-to-string article))))
     ;; Writable.
     (and (file-writable-p path)
-        ;; We can never delete the last article in the group.
-        (not (eq (cdr (nth 1 (assoc group nnmh-group-alist)))
-                 article)))))
+        (or
+         ;; We can never delete the last article in the group.
+         (not (eq (cdr (nth 1 (assoc group nnmh-group-alist)))
+                  article))
+         ;; Well, we can.
+         nnmh-allow-delete-final))))
 
 (provide 'nnmh)
 
 
 (provide 'nnmh)
 
index 7a0773e..ab03007 100644 (file)
@@ -194,8 +194,6 @@ all.  This may very well take some time.")
            (string-to-int (file-name-nondirectory path)))))))
 
 (deffoo nnml-request-group (group &optional server dont-check)
            (string-to-int (file-name-nondirectory path)))))))
 
 (deffoo nnml-request-group (group &optional server dont-check)
-  ;; 1997/8/12 by MORIOKA Tomohiko
-  ;;   for XEmacs/mule.
   (let ((pathname-coding-system 'binary))
     (cond
      ((not (nnml-possibly-change-directory group server))
   (let ((pathname-coding-system 'binary))
     (cond
      ((not (nnml-possibly-change-directory group server))
index d340b06..14963c9 100644 (file)
@@ -1,7 +1,7 @@
 \input texinfo                  @c -*-texinfo-*-
 
 @setfilename gnus
 \input texinfo                  @c -*-texinfo-*-
 
 @setfilename gnus
-@settitle Quassia Gnus 0.2 Manual
+@settitle Quassia Gnus 0.3 Manual
 @synindex fn cp
 @synindex vr cp
 @synindex pg cp
 @synindex fn cp
 @synindex vr cp
 @synindex pg cp
@@ -309,7 +309,7 @@ into another language, under the above conditions for modified versions.
 @tex
 
 @titlepage
 @tex
 
 @titlepage
-@title Quassia Gnus 0.2 Manual
+@title Quassia Gnus 0.3 Manual
 
 @author by Lars Magne Ingebrigtsen
 @page
 
 @author by Lars Magne Ingebrigtsen
 @page
@@ -345,7 +345,7 @@ can be gotten by any nefarious means you can think of---@sc{nntp}, local
 spool or your mbox file.  All at the same time, if you want to push your
 luck.
 
 spool or your mbox file.  All at the same time, if you want to push your
 luck.
 
-This manual corresponds to Quassia Gnus 0.2.
+This manual corresponds to Quassia Gnus 0.3.
 
 @end ifinfo
 
 
 @end ifinfo
 
@@ -7689,9 +7689,8 @@ to make Gnus try to post using the foreign server.
 * Posting Server::       What server should you post via?
 * Mail and Post::        Mailing and posting at the same time.
 * Archived Messages::    Where Gnus stores the messages you've sent.
 * Posting Server::       What server should you post via?
 * Mail and Post::        Mailing and posting at the same time.
 * Archived Messages::    Where Gnus stores the messages you've sent.
-@c * Posting Styles::       An easier way to configure some key elements.
-@c * Drafts::               Postponing messages and rejected messages.
-@c * Rejected Articles::    What happens if the server doesn't like your article?
+* Drafts::               Postponing messages and rejected messages.
+* Rejected Articles::    What happens if the server doesn't like your article?
 @end menu
 
 Also see @pxref{Canceling and Superseding} for information on how to
 @end menu
 
 Also see @pxref{Canceling and Superseding} for information on how to
@@ -8015,90 +8014,90 @@ but the latter is the preferred method.
 @c           (signature . "~/.mail-signature"))))
 @c @end lisp
 
 @c           (signature . "~/.mail-signature"))))
 @c @end lisp
 
-@c @node Drafts
-@c @section Drafts
-@c @cindex drafts
-@c 
-@c If you are writing a message (mail or news) and suddenly remember that
-@c you have a steak in the oven (or some pesto in the food processor, you
-@c craazy vegetarians), you'll probably wish there was a method to save the
-@c message you are writing so that you can continue editing it some other
-@c day, and send it when you feel its finished.
-@c 
-@c Well, don't worry about it.  Whenever you start composing a message of
-@c some sort using the Gnus mail and post commands, the buffer you get will
-@c automatically associate to an article in a special @dfn{draft} group.
-@c If you save the buffer the normal way (@kbd{C-x C-s}, for instance), the
-@c article will be saved there.  (Auto-save files also go to the draft
-@c group.) 
-@c 
-@c @cindex nndraft
-@c @vindex gnus-draft-group-directory
-@c The draft group is a special group (which is implemented as an
-@c @code{nndraft} group, if you absolutely have to know) called
-@c @samp{nndraft:drafts}.  The variable @code{gnus-draft-group-directory}
-@c controls both the name of the group and the location---the leaf element
-@c in the path will be used as the name of the group.  What makes this
-@c group special is that you can't tick any articles in it or mark any
-@c articles as read---all articles in the group are permanently unread.
-@c 
-@c If the group doesn't exist, it will be created and you'll be subscribed
-@c to it.
-@c 
-@c @findex gnus-dissociate-buffer-from-draft
-@c @kindex C-c M-d (Mail)
-@c @kindex C-c M-d (Post)
-@c @findex gnus-associate-buffer-with-draft
-@c @kindex C-c C-d (Mail)
-@c @kindex C-c C-d (Post)
-@c If you're writing some super-secret message that you later want to
-@c encode with PGP before sending, you may wish to turn the auto-saving
-@c (and association with the draft group) off.  You never know who might be
-@c interested in reading all your extremely valuable and terribly horrible
-@c and interesting secrets.  The @kbd{C-c M-d}
-@c (@code{gnus-dissociate-buffer-from-draft}) command does that for you.
-@c If you change your mind and want to turn the auto-saving back on again,
-@c @kbd{C-c C-d} (@code{gnus-associate-buffer-with-draft} does that.
-@c 
-@c @vindex gnus-use-draft
-@c To leave association with the draft group off by default, set
-@c @code{gnus-use-draft} to @code{nil}.  It is @code{t} by default. 
-@c 
-@c @findex gnus-summary-send-draft
-@c @kindex S D c (Summary)
-@c When you want to continue editing the article, you simply enter the
-@c draft group and push @kbd{S D c} (@code{gnus-summary-send-draft}) to do
-@c that.  You will be placed in a buffer where you left off.
-@c 
-@c Rejected articles will also be put in this draft group (@pxref{Rejected
-@c Articles}).
-@c 
-@c @findex gnus-summary-send-all-drafts
-@c If you have lots of rejected messages you want to post (or mail) without
-@c doing further editing, you can use the @kbd{S D a} command
-@c (@code{gnus-summary-send-all-drafts}).  This command understands the
-@c process/prefix convention (@pxref{Process/Prefix}).  
-@c 
-@c 
-@c @node Rejected Articles
-@c @section Rejected Articles
-@c @cindex rejected articles
-@c 
-@c Sometimes a news server will reject an article.  Perhaps the server
-@c doesn't like your face.  Perhaps it just feels miserable.  Perhaps
-@c @emph{there be demons}.  Perhaps you have included too much cited text.
-@c Perhaps the disk is full.  Perhaps the server is down.
-@c 
-@c These situations are, of course, totally beyond the control of Gnus.
-@c (Gnus, of course, loves the way you look, always feels great, has angels
-@c fluttering around inside of it, doesn't care about how much cited text
-@c you include, never runs full and never goes down.)  So Gnus saves these
-@c articles until some later time when the server feels better.
-@c 
-@c The rejected articles will automatically be put in a special draft group
-@c (@pxref{Drafts}).  When the server comes back up again, you'd then
-@c typically enter that group and send all the articles off.
-@c 
+@node Drafts
+@section Drafts
+@cindex drafts
+
+If you are writing a message (mail or news) and suddenly remember that
+you have a steak in the oven (or some pesto in the food processor, you
+craazy vegetarians), you'll probably wish there was a method to save the
+message you are writing so that you can continue editing it some other
+day, and send it when you feel its finished.
+
+Well, don't worry about it.  Whenever you start composing a message of
+some sort using the Gnus mail and post commands, the buffer you get will
+automatically associate to an article in a special @dfn{draft} group.
+If you save the buffer the normal way (@kbd{C-x C-s}, for instance), the
+article will be saved there.  (Auto-save files also go to the draft
+group.) 
+
+@cindex nndraft
+@vindex gnus-draft-group-directory
+The draft group is a special group (which is implemented as an
+@code{nndraft} group, if you absolutely have to know) called
+@samp{nndraft:drafts}.  The variable @code{gnus-draft-group-directory}
+controls both the name of the group and the location---the leaf element
+in the path will be used as the name of the group.  What makes this
+group special is that you can't tick any articles in it or mark any
+articles as read---all articles in the group are permanently unread.
+
+If the group doesn't exist, it will be created and you'll be subscribed
+to it.
+
+@findex gnus-dissociate-buffer-from-draft
+@kindex C-c M-d (Mail)
+@kindex C-c M-d (Post)
+@findex gnus-associate-buffer-with-draft
+@kindex C-c C-d (Mail)
+@kindex C-c C-d (Post)
+If you're writing some super-secret message that you later want to
+encode with PGP before sending, you may wish to turn the auto-saving
+(and association with the draft group) off.  You never know who might be
+interested in reading all your extremely valuable and terribly horrible
+and interesting secrets.  The @kbd{C-c M-d}
+(@code{gnus-dissociate-buffer-from-draft}) command does that for you.
+If you change your mind and want to turn the auto-saving back on again,
+@kbd{C-c C-d} (@code{gnus-associate-buffer-with-draft} does that.
+
+@vindex gnus-use-draft
+To leave association with the draft group off by default, set
+@code{gnus-use-draft} to @code{nil}.  It is @code{t} by default. 
+
+@findex gnus-summary-send-draft
+@kindex S D c (Summary)
+When you want to continue editing the article, you simply enter the
+draft group and push @kbd{S D c} (@code{gnus-summary-send-draft}) to do
+that.  You will be placed in a buffer where you left off.
+
+Rejected articles will also be put in this draft group (@pxref{Rejected
+Articles}).
+
+@findex gnus-summary-send-all-drafts
+If you have lots of rejected messages you want to post (or mail) without
+doing further editing, you can use the @kbd{S D a} command
+(@code{gnus-summary-send-all-drafts}).  This command understands the
+process/prefix convention (@pxref{Process/Prefix}).  
+
+
+@node Rejected Articles
+@section Rejected Articles
+@cindex rejected articles
+
+Sometimes a news server will reject an article.  Perhaps the server
+doesn't like your face.  Perhaps it just feels miserable.  Perhaps
+@emph{there be demons}.  Perhaps you have included too much cited text.
+Perhaps the disk is full.  Perhaps the server is down.
+
+These situations are, of course, totally beyond the control of Gnus.
+(Gnus, of course, loves the way you look, always feels great, has angels
+fluttering around inside of it, doesn't care about how much cited text
+you include, never runs full and never goes down.)  So Gnus saves these
+articles until some later time when the server feels better.
+
+The rejected articles will automatically be put in a special draft group
+(@pxref{Drafts}).  When the server comes back up again, you'd then
+typically enter that group and send all the articles off.
+
 
 @node Select Methods
 @chapter Select Methods
 
 @node Select Methods
 @chapter Select Methods
@@ -8137,6 +8136,7 @@ The different methods all have their peculiarities, of course.
 * Getting Mail::          Reading your personal mail with Gnus.
 * Other Sources::         Reading directories, files, SOUP packets.
 * Combined Groups::       Combining groups into one group.
 * Getting Mail::          Reading your personal mail with Gnus.
 * Other Sources::         Reading directories, files, SOUP packets.
 * Combined Groups::       Combining groups into one group.
+* Gnus Unplugged::        Reading news and mail offline.
 @end menu
 
 
 @end menu
 
 
@@ -10716,6 +10716,434 @@ Articles marked as read in the @code{nnkiboze} group will have
 their @sc{nov} lines removed from the @sc{nov} file.
 
 
 their @sc{nov} lines removed from the @sc{nov} file.
 
 
+@node Gnus Unplugged
+@section Gnus Unplugged
+@cindex offline
+@cindex unplugged
+@cindex Agent
+@cindex Gnus Agent
+@cindex Gnus Unplugged
+
+In olden times (ca. February '88), people used to run their newsreaders
+on big machines with permanent connections to the net.  News transport
+was dealt with by news servers, and all the newsreaders had to do was to
+read news.  Believe it or not.
+
+Nowadays most people read news and mail at home, and use some sort of
+modem to connect to the net.  To avoid running up huge phone bills, it
+would be nice to have a way to slurp down all the news and mail, hang up
+the phone, read for several hours, and then upload any responses you
+have to make.  And then you repeat the procedure.
+
+Of course, you can use news servers for doing this as well.  I've used
+@code{inn} together with @code{slurp}, @code{pop} and @code{sendmail}
+for some years, but doing that's a bore.  Moving the news server
+functionality up to the newsreader makes sense if you're the only person
+reading news on a machine.
+
+Using Gnus as an ``offline'' newsreader is quite simple.
+
+@itemize @bullet
+@item
+First, set ut Gnus as you would do if you were running it on a machine
+that has full connection to the net.  Go ahead.  I'll still be waiting
+here.
+
+@item
+Then, put the following magical incantation at the end of your
+@file{.gnus.el} file:
+
+@lisp
+(gnus-agentize)
+@end lisp
+@end itemize
+
+That's it.  Gnus is now an ``offline'' newsreader.
+
+Of course, to use it as such, you have to learn a few new commands.
+
+@menu
+* Agent Basics::           How it all is supposed to work.
+* Agent Categories::       How to tell the Gnus Agent what to download.
+* Agent Commands::         New commands for all the buffers.
+* Agent Variables::        Customizing is fun.
+@end menu
+
+
+@node Agent Basics
+@subsection Agent Basics
+
+First, let's get some terminilogy out of the way.
+
+The Gnus Agent is said to be @dfn{unplugged} when you have severed the
+connection to the net (and notified the Agent that this is the case).
+When the connection to the net is up again (and Gnus knows this), the
+Agent is @dfn{plugged}.
+
+The @dfn{local} machine is the one you're running on, and which isn't
+connected to the net continously.
+
+@dfn{Downloading} means fetching things from the net to your local
+machine.  @dfn{Uploading} is doing the opposite.
+
+Let's take a typical Gnus session using the Agent.
+
+@itemize @bullet
+
+@item
+You start Gnus with @code{gnus-unplugged}.  This brings up the Gnus
+Agent in a disconnected state.  You can read all the news that you have
+already fetched while in this mode.
+
+@item
+You then decide to see whether any new news has arrived.  You connect
+your machine to the net (using PPP or whatever), and then hit @kbd{J j}
+to make Gnus become @dfn{plugged}.
+
+@item
+You can then read the new news immediately, or you can download the news
+onto your local machine.  If you want to do the latter, you press @kbd{J
+s} to fetch all the eligible articles in all the groups.  (To let Gnus
+know which articles you want to download, @pxref{Agent Categories}.)
+
+@item
+After fetching the articles, you press @kbd{J j} to make Gnus become
+unplugged again, and you shut down the PPP thing (or whatever).  And
+then you read the news offline.
+
+@item
+And then you go to step 2.
+@end itemize
+
+
+@node Agent Categories
+@subsection Agent Categories
+
+On of the main reasons to integrate the news transport layer into the
+newsreader is to allow greater control over what articles to download.
+There's not much point in downloading huge amounts of articles, just to
+find out that you're not interested in reading any of them.  It's better
+to be somewhat more conservative in choosing what to download, and then
+mark the articles for downloading manually if it should turn out that
+you're interested in the articles anyway.
+
+The main way to control what is to be downloaded is to create a
+@dfn{category} and then assign some (or all) groups to this category. 
+Gnus has its own buffer for creating and managing categories.
+
+@menu
+* Category Syntax::       What a category looks like.
+* The Category Buffer::   A buffer for maintaining categories.
+* Category Variables::    Customize'r'Us.
+@end menu
+
+
+@node Category Syntax
+@subsubsection Category Syntax
+
+A category consists of two things.
+
+@enumerate
+@item
+A predicate which (generally) gives a rough outline of which articles
+are eligible for downloading; and
+
+@item
+a score rule which (generally) gives you a finer granularity when
+deciding what articles to download.  (Note that this @dfn{download
+score} is wholly unrelated to normal scores.)
+@end enumerate
+
+A predicate consists of predicates with logical operators sprinkled in
+between.
+
+Perhaps some examples are in order.
+
+Here's a simple predicate.  (It's the default predicate, in fact, used
+for all groups that don't belong to any other category.)
+
+@lisp
+short
+@end lisp
+
+Quite simple, eh?  This predicate is true if and only if the article is
+short (for some value of ``short'').
+
+Here's a more complex predicate:
+
+@lisp
+(or high
+    (and
+     (not low)
+     (not long)))
+@end lisp
+
+This means that an article should be downloaded if it has a high score,
+or if the score is not low and the article is not long.  You get the
+drift.
+
+The available logical operators are @code{or}, @code{and} and
+@code{not}.  (If you prefer, you can use the more ``C''-ish operators
+@samp{|}, @code{&} and @code{!} instead.)
+
+The following predicates are pre-defined, but if none of these fit what
+you want to do, you can write your own.
+
+@table @code
+@item short
+True iff the article is shorter than @code{gnus-agent-short-article}
+lines; default 100.
+
+@item long
+True iff the article is longer than @code{gnus-agent-long-article}
+lines; default 200.
+
+@item low
+True iff the article has a download score less than
+@code{gnus-agent-low-score}; default 0.
+
+@item high
+True iff the article has a download score greater than
+@code{gnus-agent-high-score}; default 0.
+
+@item spam
+True iff the Gnus Agent guesses that the article is spam.  The
+heuristics may change over time, but at present it just computes a
+checksum and see whether articles match.
+
+@item true
+Always true.
+
+@item false
+Always false.
+@end table
+
+If you want to create your own predicate function, here's what you have
+to know:  The functions are called with no parameters, but the
+@code{gnus-headers} and @code{gnus-score} dynamic variables are bound to
+useful values.
+
+Now, the syntax of the download score is the same as the syntax of
+normal score files, except that all elements that require actually
+seeing the article itself is verboten.  This means that only the
+following headers can be scored on: @code{From}, @code{Subject},
+@code{Date}, @code{Xref}, @code{Lines}, @code{Chars}, @code{Message-ID},
+and @code{References}.
+
+
+@node The Category Buffer
+@subsubsection The Category Buffer
+
+You'd normally do all category maintenance from the category buffer.
+When you enter it for the first time (with the @kbd{J c} command from
+the group buffer), you'll only see the @code{default} category.
+
+The following commands are available in this buffer:
+
+@table @kbd
+@item q
+@kindex q (Category)
+@findex gnus-category-exit
+Return to the group buffer (@code{gnus-category-exit}).
+
+@item k
+@kindex k (Category)
+@findex gnus-category-kill
+Kill the current category (@code{gnus-category-kill}).
+
+@item c
+@kindex c (Category)
+@findex gnus-category-copy
+Copy the current category (@code{gnus-category-copy}).
+
+@item a
+@kindex a (Category)
+@findex gnus-category-add
+Add a new category (@code{gnus-category-add}).
+
+@item p
+@kindex p (Category)
+@findex gnus-category-edit-predicate
+Edit the predicate of the current category
+(@code{gnus-category-edit-predicate}).
+
+@item g
+@kindex g (Category)
+@findex gnus-category-edit-groups
+Edit the list of groups belonging to the current category
+(@code{gnus-category-edit-groups}).
+
+@item s
+@kindex s (Category)
+@findex gnus-category-edit-score
+Edit the download score rule of the current category
+(@code{gnus-category-edit-score}).
+
+@item l
+@kindex l (Category)
+@findex gnus-category-list
+List all the categories (@code{gnus-category-list}).
+@end table
+
+
+@node Category Variables
+@subsubsection Category Variables
+
+@table @code
+@item gnus-category-mode-hook
+@vindex gnus-category-mode-hook
+Hook run in category buffers.
+
+@item gnus-category-line-format
+@vindex gnus-category-line-format
+Format of the lines in the category buffer (@pxref{Formatting
+Variables}).  Legal elements are:
+
+@table @samp
+@item c
+The name of the category.
+
+@item g
+The number of groups in the category.
+@end table
+
+@item gnus-category-mode-line-format
+@vindex gnus-category-mode-line-format
+Format of the category mode line.
+
+@item gnus-agent-short-article 
+@vindex gnus-agent-short-article 
+Articles that have fewer lines than this are short.  Default 100.
+
+@item gnus-agent-long-article 
+@vindex gnus-agent-long-article 
+Articles that have more lines than this are long.  Default 200.
+
+@item gnus-agent-low-score 
+@vindex gnus-agent-low-score 
+Articles that have a score lower than this have a low score.  Default
+0. 
+
+@item gnus-agent-high-score 
+@vindex gnus-agent-high-score 
+Articles that have a score higher than this have a high score.  Default
+0. 
+
+@end table
+
+
+@node Agent Commands
+@subsection Agent Commands
+
+All the Gnus Agent commands is on the @kbd{J} submap.  The @kbd{J j}
+(@code{gnus-agent-toggle-plugged} command works in all modes, and
+toggles the plugged/unplugged state of the Gnus Agent.
+
+
+@menu
+* Group Agent Commands::
+* Summary Agent Commands::
+* Server Agent Commands::
+@end menu
+
+
+@node Group Agent Commands
+@subsubsection Group Agent Commands
+
+@table @kbd
+@item J u 
+@kindex J u (Agent Group)
+@findex gnus-agent-fetch-group
+Fetch all eligible articles in the current group
+(@code{gnus-agent-fetch-group}).
+
+@item J c
+@kindex J c (Agent Group)
+@findex gnus-enter-category-buffer
+Enter the Agent category buffer (@code{gnus-enter-category-buffer}).
+
+@item J s
+@kindex J s (Agent Group)
+@findex gnus-agent-fetch-session
+Fetch all eligible articles in all groups
+(@code{gnus-agent-fetch-session}).
+
+@item J a
+@kindex J a (Agent Group)
+@findex gnus-agent-add-group
+Add the current group to an Agent category
+(@code{gnus-agent-add-group}).
+
+@end table
+
+
+@node Summary Agent Commands
+@subsubsection Summary Agent Commands
+
+@table @kbd
+@item J #
+@kindex J # (Agent Summary)
+@findex gnus-agent-mark-article
+Mark the article for downloading (@code{gnus-agent-mark-article}).
+
+@item J M-#
+@kindex J M-# (Agent Summary)
+@findex gnus-agent-unmark-article
+Remove the downloading mark from the article
+(@code{gnus-agent-unmark-article}).
+
+@item @@
+@kindex @@ (Agent Summary)
+@findex gnus-agent-toggle-mark
+Toggle whether to download the article (@code{gnus-agent-toggle-mark}).
+
+@item J c
+@kindex J c (Agent Summary)
+@findex gnus-agent-catchup
+Mark all undownloaded articles as read (@code{gnus-agent-catchup}).
+
+@end table
+
+
+@node Server Agent Commands
+@subsubsection Server Agent Commands
+
+@table @kbd
+@item J a
+@kindex J a (Agent Server)
+@findex gnus-agent-add-server
+Add the current server to the list of servers covered by the Gnus Agent
+(@code{gnus-agent-add-server}).
+
+@item J r
+@kindex J r (Agent Server)
+@findex gnus-agent-remove-server
+Remove the current server from the list of servers covered by the Gnus
+Agent (@code{gnus-agent-remove-server}).
+
+@end table
+
+
+@node Agent Variables
+@subsection Agent Variables
+
+@table @code
+@item gnus-agent-directory
+@vindex gnus-agent-directory
+Where the Gnus Agent will store its files.  The default is
+@file{~/News/agent/}.
+
+@item gnus-agent-plugged-hook
+@vindex gnus-agent-plugged-hook
+Hook run when connecting to the network.
+
+@item gnus-agent-unplugged-hook
+@vindex gnus-agent-unplugged-hook
+Hook run when disconnecting from the network.
+
+@end table
+
+
 @node Scoring
 @chapter Scoring
 @cindex scoring
 @node Scoring
 @chapter Scoring
 @cindex scoring
index 83acd94..4aae155 100644 (file)
@@ -1,7 +1,7 @@
 \input texinfo                  @c -*-texinfo-*-
 
 @setfilename message
 \input texinfo                  @c -*-texinfo-*-
 
 @setfilename message
-@settitle Message 0.2 Manual
+@settitle Message 0.3 Manual
 @synindex fn cp
 @synindex vr cp
 @synindex pg cp
 @synindex fn cp
 @synindex vr cp
 @synindex pg cp
@@ -39,7 +39,7 @@ into another language, under the above conditions for modified versions.
 @tex
 
 @titlepage
 @tex
 
 @titlepage
-@title Message 0.2 Manual
+@title Message 0.3 Manual
 
 @author by Lars Magne Ingebrigtsen
 @page
 
 @author by Lars Magne Ingebrigtsen
 @page
@@ -79,7 +79,7 @@ buffers.
 * Key Index::         List of Message mode keys.
 @end menu
 
 * Key Index::         List of Message mode keys.
 @end menu
 
-This manual corresponds to Message 0.2.  Message is distributed with
+This manual corresponds to Message 0.3.  Message is distributed with
 the Gnus distribution bearing the same version number as this manual
 has. 
 
 the Gnus distribution bearing the same version number as this manual
 has.