DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T a

⟦c2ac7007c⟧ TextFile

    Length: 27379 (0x6af3)
    Types: TextFile
    Names: »art.el«

Derivation

└─⟦a05ed705a⟧ Bits:30007078 DKUUG GNU 2/12/89
    └─⟦32c6b6024⟧ »./gnews-2.0-tar.Z« 
        └─⟦5d06bd818⟧ 
            └─⟦this⟧ »gnews-2.0/art.el« 

TextFile

;;; art.el: pager-mode commands for Gnews
;;; Copyright (C) 1987, 1988 by Matthew P Wiener; all rights reserved.

;;; Send bugs, complaints, suggestions etc to weemba@garnet.berkeley.edu

;; Gnews is distributed in the hope that it will be useful, but WITHOUT
;; ANY WARRANTY.  No author or distributor accepts responsibility to
;; anyone for the consequences of using it or for whether it serves any
;; particular purpose or works at all, unless he says so in writing.
;; Refer to the Gnews General License for full details.

;; Everyone is granted permission to copy, modify and redistribute Gnews,
;; but only under the conditions described in the Gnews General License.
;; A copy of this license is supposed to have been given to you along with
;; Gnews so you can know your rights and responsibilities.  It should be
;; accessible with the key sequence "ESC l l" while in News mode.  Among 
;; other things, the copyright notice and this notice must be preserved on
;; all copies.
\f


(defun article-scroll-up (arg &optional ff digest)
  "Scroll window forward upward ARG lines, or nearly a full screen if no
ARG.  Catch end of buffer errors.\n
Optional second argument FF, if non-nil, blocks an incorrect second call
to article-forward-intern."
  (condition-case ()
      (progn
	(scroll-up arg)
	(if (and article-grab-point
		 (not (if ff (save-excursion (goto-char article-grab-point)
					     (beginning-of-line)
					     (looking-at article-formfeed))))
		 (pos-visible-in-window-p article-grab-point))
	    (article-forward-intern nil ff digest)))
    (end-of-buffer (if (or gnews-edit-p
			   (= (read (article-field "Lines"))
			      (1+ (count-lines (article-min) (point-max)))))
		       (setq article-count-off-but-ok t)
		     (error "Truncated article")))))

(defun article-forward (&optional arg)
  "Scroll the current article forward one page.\n
In Lisp code (only), optional argument ARG means scroll forward that
many lines.  Interactively, use article-line, which see."
  (interactive (list nil))
  (let ((agp article-grab-point)
	(ff article-formfeed)
	(top article-formfeed-top)
	(digest article-formfeed-post))
    (if (and agp (pos-visible-in-window-p agp))
	(progn (article-forward-intern nil ff digest)
	       (if (pos-visible-in-window-p			 ; Check for
		     (save-excursion				 ; non-null
		       (goto-char agp)				 ; reading
		       (re-search-forward "[^ \n\t\f]" nil t)	 ; material:
		       (point)))				 ; if so, then
		   nil						 ; leave alone
		 (article-scroll-up arg ff digest))		 ; else scroll.
	       (if article-formfeed-top				 ; And then
		   (progn (goto-char agp)			 ; adjust the
			  (beginning-of-line)			 ; top of the
			  (if (looking-at ff) (recenter top))))) ; if needed
      (article-scroll-up arg ff digest))
    (article-%-compute)
    (if (article-done) (article-quit))
    (gnews-flush)))

(defun article-down ()
  "Scroll the current article down half a page."
  (interactive)
  (article-forward (/ (window-height) 2)))

(defun article-line (arg)
  "Scroll the current article up one line--with numeric argument ARG,
scroll that many lines."
  (interactive "p")
  (if (article-done)
      (ding)
    (article-forward arg)))

(defun article-quit ()
  "Quit the current article."
  (interactive)
  (article-forward-intern t)
  (if article-junkable (article-junk))
  (gnews-message (concat "End of article " article-current
			 "--what next " group-prompt-default
			 (if (eq article-current article-final) " $ " " ? ")))
  (group-mode)
  (gnews-flush)
  t)

(defun article-junk (&optional pfx art-no super)
  "Mark current article as junked.\n
In Lisp code, non-nil optional argument PFX (the prefix argument) means
do a local junk, and non-nil argument ART-NO is the article number to
junk.  Non-nil argument SUPER means due a superjunk: add this message-ID
to this newsgroup's hook-kills: temporary if SUPER is numeric, temporary
and permanent if t."
  (interactive "P")
  (setq hook-kill-continue)			; terminate hook processing
  (if (and (eq article-junkable 'mark) (not (interactive-p))) nil
    (if (and (not pfx) art-no)
	(let ((b (current-buffer)))
	  (save-excursion
	    (set-buffer nntp-buffer)
	    (nntp-exec t t "head" art-no)
	    (article-header-clean t))
	  (set-buffer b)))
    (setcdr (cdr (assoc group-current group-roster)) amark)
    (let ((xgp (list nil))
	  (xref (list nil))
	  (str (if (or pfx (string-match "<0>" nntp-info))
		   "" (if article-field-list
			  (article-field "Xref")	; from a read article
			(save-excursion			; from a per-hook junk
			  (set-buffer nntp-buffer)
			  (goto-char (point-max))
			  (if (re-search-backward "^Xref: \\(.*\\)" nil t)
			      (gnews-match 1)		; cross-posted
			    "")))))			; not cross-posted
	  (mid (if super
		   (if article-field-list
		       (article-field "Message-ID")
		     (save-excursion
		       (set-buffer nntp-buffer)
		       (goto-char 1)
		       (re-search-forward "^Message-ID: \\(.*\\)" nil t)
		       (gnews-match 1)))))
	  ss)
      (if (string= str "")
	  (setq xref (list nil (or art-no article-current))
		xgp (list nil group-current))
	(while (string-match "\\([^ :]+\\):\\([0-9]+\\)" str ss)
	  (nconc xgp (list (substring
			     str (match-beginning 1) (match-end 1))))
	  (nconc xref (list (string-to-int
			      (substring
				str (match-beginning 2) (match-end 2)))))
	  (setq ss (match-end 0))))
      (gnews-map (function
		   (lambda (x y)
		     (let* ((ngl (assoc x group-roster))
			    (ngam (gnddr ngl)))
		       (if (and ngl (or article-junk-unsub (gnadr ngl)))
			   (if ngam (amark-list-insert y ngam)
			     (nconc ngl (list y)))))))
	(cdr xgp)
	(cdr xref)))
    (setq group-checkpoint t
	  amark (gnddr (assoc group-current group-roster)))
    (if (and (boundp 'index-pop)		; index-mode is around
	     (not nntp-index-p)			; and we're not killing
	     (null art-no))			; but this was direct
	(let ((b (current-buffer)))
	  (save-excursion
	    (set-buffer index-buffer)
	    (goto-char 1)
	    (if (re-search-forward
		  (concat "^\\(^ *" article-current "\\).") nil t)
		(index-junk-line nil)))
	  (set-buffer b)))
    (if (interactive-p) (message "%d: junked" (or art-no article-current))))
  (gnews-flush))

(defun article-junk-local ()
  "Mark current article as junked in current newsgroup only."
  (interactive)
  (article-junk t)
  (if (interactive-p) (message "%d: junked" article-current))
  (gnews-flush))

(defun article-ignore () "Ignore this article" t)

(defun article-yes ()
  "For use within hook-kill processing: break out and set to the article."
  (setq hook-kill-continue))

(put 'article-junk 'hook-kill-junk t)
(put 'article-junk-local 'hook-kill-junk t)
(put 'article-ignore 'hook-kill-junk t)

(defun article-restart ()
  "Restart the current article."
  (interactive)
  (if (< article-final article-current)
      (ding)
    (setq buffer-read-only)
    (article-header-clean nil)
    (setq buffer-read-only t)
    (article-mode)
    (goto-char 1)
    (article-%-compute))
  (gnews-hilite)
  (gnews-flush))

(defun article-restart-verbose ()
  "Restart the current article with full headers."
  (interactive)
  (if (< article-final article-current)
      (ding)
    (article-forward-intern nil)
    (goto-char 1)
    (setq buffer-read-only)
    (gnews-delete-paragraph)
    (mapcar '(lambda (h) (insert (car h) ": " (cdr h) ?\n))
	    (cdr article-field-list))
    (goto-char 1)
    (run-hooks 'article-header-hook)
    (goto-char 1)
    (setq buffer-read-only t)
    (article-%-compute)
    (if (article-done) (article-quit) (article-mode))
    (goto-char 1))
  (gnews-flush))

(defun article-restart-reset ()
  "Completely restart the current article."
  (interactive)
  (cond ((< article-final article-current)
	 (ding))
	((and (< 0 article-current)
	      (catch 'article-nil (article-get article-current)))
	 (article-junk-local)
	 (message "whoops--this article was cancelled"))
	((= 0 article-current)
	 (article-get-msg-id (article-field "Message-ID"))))
  (gnews-flush))

(defun article-rot13 ()
  "Rot13 the current article."
  (interactive)
  (if (< article-final article-current)
      (ding)
    (setq buffer-read-only)
    (save-excursion
      (goto-char (article-min))
      (gnews-rot13 (article-min) (article-max)))
    (setq buffer-read-only t
	  gnews-rot13-p (not gnews-rot13-p))
    (article-%-compute)
    ;; note: for a-r13-r, we must return !nil if a-q
    (if (article-done) (article-quit))))

(defun article-rot13-restart ()
  "Restart and rot13 the current article."
  (interactive)
  (let (gnews-rot13-p) (article-restart))	; shield for sake of a-r13
  (article-rot13))

(defun article-rot13-forward ()
  "Scroll forward and rot13 the current article."
  (interactive)
  (or (article-rot13) (article-forward)))

(defun article-downcase ()
  "Lowercase the current article."
  (interactive)
  (if (< article-final article-current)
      (ding)
    (article-forward-intern t)
    (setq buffer-read-only)
    (save-excursion 
      (downcase-region (article-min) (article-max)))
    (setq buffer-read-only t gnews-edit-p t)
    (if (article-done) (article-quit)))
  (gnews-flush))

(defun article-ununderline ()
  "Remove underlining from the current article."
  (interactive)
  (if (< article-final article-current)
      (ding)
    (article-forward-intern t)
    (setq buffer-read-only)
    (save-excursion 
      (ununderline-region (article-min) (article-max)))
    (setq buffer-read-only t gnews-edit-p t)
    (if (article-done) (article-quit)))) ; must return !nil if quit

(defun article-back ()
  "Scroll back a page in the current article."
  (interactive)
  (if (< article-final article-current)
      (ding)
    (scroll-down nil)
    (article-%-compute))
  (move-to-window-line 0)
  (gnews-hilite)
  (gnews-flush))

(defun article-back-half ()
  "Scroll back half a page in the current article."
  (interactive)
  (if (< article-final article-current)
      (ding)
    (scroll-down (/ (window-height) 2))
    (article-%-compute)
    (if (article-done) (article-quit)))
  (move-to-window-line 0)
  (gnews-hilite)
  (gnews-flush))

(defun article-end ()
  "Go to the end of the current article."
  (interactive)
  (article-forward-intern nil)
  (end-of-buffer)
  (recenter (- (window-height) 1))
  (move-to-window-line -1)
  (sit-for 0)
  (article-%-compute)
  (if (article-done) (article-quit))
  (gnews-flush))

(defun article-grep (pfx)
  "Search for a regexp in the article--non-nil prefix argument PFX
means search backwards."
  (interactive "P")
  (article-forward-intern nil)
  (setq article-grep-directions '(re-search-forward . re-search-backward))
  (if pfx (setq article-grep-directions (nreverse article-grep-directions)))
  (funcall (car article-grep-directions) 
	   (setq article-grep-string (or (read-string "grep for: ")
					 article-grep-string))
	   nil t)
  (recenter article-grep-height)
  (article-%-compute)
  (if (article-done) (article-quit))
  (gnews-flush))

(defun article-grep-repeat (pfx)
  "Repeat previous regexp search--non-nil prefix argument PFX means
reverse search direction."
  (interactive "P")
  (if (null article-grep-string) (article-grep pfx)
    (article-forward-intern nil)
    (if pfx (setq article-grep-directions (nreverse article-grep-directions)))
    (funcall (car article-grep-directions)
	     article-grep-string nil t)
    (recenter article-grep-height)
    (article-%-compute)
    (if (article-done) (article-quit))
    (gnews-flush)))

(defun article-grep-digest (pfx)
  "Search for a digest separator--non-nil prefix argument PFX means
search backwards."
  (interactive "P")
  (article-forward-intern nil)
  (if pfx nil (forward-line 1))
  (funcall (if pfx 're-search-backward 're-search-forward)
	   article-digest-separator nil t)
  (recenter 0)
  (beginning-of-line)
  (article-%-compute)
  (if (article-done) (article-quit))
  (gnews-flush))

(defun article-skip-indent ()
  "Skip past indentation, ie, the first character on the bottom line"
  (interactive)
  (move-to-window-line -1)
  (beginning-of-line)
  (re-search-forward
    (concat "^[^" (regexp-quote
		    (char-to-string
		      (following-char))) "]") nil t)
  (beginning-of-line)
  (article-forward-intern nil)
  (recenter article-grep-height)
  (article-%-compute)
  (if (article-done) (article-quit))
  (gnews-flush))

(defun article-recenter (&optional pfx arg)
  "Recenter the current article, as in recenter.\n
In Lisp code, if optional PFX is non-nil, then ARG is passed to recenter."
  (interactive "P\np")
  (if (< article-final article-current)
      (ding)
    (recenter (cond (pfx arg)
		    ((interactive-p) nil)
		    (t 0)))
    (article-%-compute)
    (if (article-done) (article-quit)))
  (gnews-hilite)
  (gnews-flush))

(defun article-isearch-forward ()
  (interactive)
  (article-forward-intern nil)
  (isearch t)
  (article-%-compute))

(defun article-isearch-backward ()
  (interactive)
  (article-forward-intern nil)
  (isearch nil)
  (article-%-compute))

(defun article-isearch-forward-regexp ()
  (interactive)
  (article-forward-intern nil)
  (isearch t t)
  (article-%-compute))

(defun article-isearch-backward-regexp ()
  (interactive)
  (article-forward-intern nil)
  (isearch nil t)
  (article-%-compute))
\f


;;; the basic article getting primitives

;;; article-get's complexity comes from its attempt to be quick and clever.

;;; First, only the head is gotten, permitting quick checks for hook-kill
;;; purposes.  If the article passes, then the body is gotten too.  But we
;;; do a little buffering along the way, only grabbing enough of the body
;;; to get a quick display up.  If the length of the article is greater
;;; than article-big lines, then we do a full display, even if the user
;;; by default asks for just a partial display--ie, just give him something
;;; to read while waiting.  Also, the *first* character hit by a user while
;;; waiting is processed--normally all typeahead is flushed.

;;; article-get-slow is not actually that slow (except for large articles)
;;; it just has none of the above sophistication.  Being simpler, it should
;;; be less error prone, but this is counterbalanced by the fact that I work
;;; primarily with/on article-get.  At the moment, I still must use it in
;;; forward/backward pattern searches and with the spool code.  Both needs
;;; are a mystery to me.

(defun article-get (number &optional hooklist interact)
  "Display article NUMBER of the current newsgroup.\n
In Lisp code, optional argument HOOKLIST is a list of per-hooks to
apply, and a non-nil INTERACT means pretend this function was called
interactively."
  (interactive "narticle #: ")
  (setq gnews-edit-p nil
	gnews-rot13-p nil
	interact (or (interactive-p) interact))
  (if (< article-final number)
      (group-last)
    (if (nntp-exec t t "head" number)
	(let ((b (current-buffer))
	      (hook-kill-continue t)
	      lines)
	  (set-buffer nntp-buffer)
	  (if interact (article-current-set number))
	  (setq article-field-list)
	  (while (and hooklist hook-kill-continue)
	    (if (hook-kill-do (car hooklist) nil)
		(progn				; hook-kill-junk property
		  (hook-kill-junk-message number (car hooklist))
		  (set-buffer b)		; I have to doooo this?
		  (throw 'article-nil t)))	; article KILLed; try again
	    (setq hooklist (cdr hooklist)))
	  (article-header-clean t)
	  (if interact
	      (article-history-append number group-current
				      (article-field "Message-ID")))
	  (setq lines (article-effective-init-display))
	  (nntp-exec nil nil "body" number)
	  (while (and (nntp-run-p)		; catch a broken connection
		      (not nntp-eot)
		      (< (count-lines 1 (point-max))
			 (or lines
			     (window-height
			       (get-buffer-window news-buffer)))))
	    (gnews-accept-process-output nntp))
	  (if (not (nntp-run-p))
	      (news-quit
		(y-or-n-p "Connection died: save the current roster? ")))
	  (save-excursion			; get rid of NNTP info
	    (goto-char 1)
	    (re-search-forward "^222.*$")	; the NNTP info message
	    (setq nntp-info-true (gnews-match 0))
	    (replace-match ""))
	  (if lines (forward-line lines))
	  (setq article-grab-point (if lines (point)))
	  (article-display-init)
	  (nntp-finish)
	  (set-buffer nntp-buffer)
	  (goto-char 1)
	  (insert nntp-info ?\n)		; put back first field
	  (setq nntp-info nntp-info-true)
	  (set-buffer news-buffer)
	  (gnews-exec-1-pending)		; get one out before flushing
	  (if (setq article-junkable (article-done)) (article-quit)))
      (or (article-run-hooks number hooklist interact 'article-not-found-hooks)
	  (throw 'article-nil t))))		; article not found--give up
  (gnews-flush))

(defun article-get-msg-id (msg-id)
   "Display the article with message-ID MSG-ID.  Interactively, the
first message-ID that ends at point or after, if it exists, is offered
as a default choice.\n
The enclosing angle brackets are optional."
   (interactive
     (list (read-string "Message-ID: " (article-msg-id-after-point))))
   (setq gnews-edit-p)
   (if (string= (substring msg-id 0 1) "<") nil
     (setq msg-id (concat "<" msg-id)))
   (if (string= (substring msg-id -1) ">") nil
     (setq msg-id (concat msg-id ">")))
   (setq article-field-list-previous article-field-list)
   (if (nntp-exec t t "article" msg-id)
       (let (lines)
	 (set-buffer nntp-buffer)
	 (article-header-clean t)
	 (setq lines (article-effective-init-display))
	 (if lines (forward-line lines))
	 (setq article-grab-point (if lines (point)))
	 (if (cdr article-field-list)
	     (progn
	       (if (< 0 article-current)
		   (setq article-message-id msg-id
			 article-trace article-current
			 article-current 0)) ; NNTP can't return #/gp
	       (article-display-init t))
	   (message "Message-ID %s: no such article" msg-id (ding))
	   (setq article-field-list article-field-list-previous)))
     (or (article-run-hooks msg-id 0 t 'article-not-found-hooks)
	 (message "Message-ID %s: no such article" msg-id (ding))
	 (setq article-field-list article-field-list-previous)))
   (gnews-flush))

(defun article-get-slow (number &optional hook interact)
  "Display article NUMBER of the current newsgroup.\n
In Lisp code, optional argument HOOK is a list of per-hooks to apply, and
non-nil INTERACT means to pretend this function was called interactively.\n"
  (interactive "narticle #: ")
  (setq gnews-edit-p nil
	gnews-rot13-p nil
	interact (or (interactive-p) interact))
  (if (< article-final number)
      (group-last)
    (if (nntp-exec t t "article" number)
	(let ((b (current-buffer))
	      lines)
	  (set-buffer nntp-buffer)
	  (if interact (article-current-set number))
	  (article-header-clean t)
	  (if interact
	      (article-history-append number group-current
				      (article-field "Message-ID")))
	  (setq lines (article-effective-init-display))
	  (let ((article-current number)
		(hook-kill-continue t))
	    (while (and hook hook-kill-continue)
	      (if (hook-kill-do (car hook) t)
		  (progn
		    (hook-kill-junk-message number hook)
		    (set-buffer b) ; I have to doooo this?
		    (throw 'article-nil t)))	; article KILLed; try again
	      (setq hook (cdr hook))))
	  (if lines (forward-line lines))
	  (setq article-grab-point (if lines (point)))
	  (article-display-init t)
	  (if (setq article-junkable (article-done)) (article-quit)))
      (or (article-run-hooks number hooklist interact 'article-not-found-hooks)
	  (throw 'article-nil t))))		; article not found--give it up
  (gnews-flush))

(defun article-run-hooks (art-no kills interact hooks)
  "Run an article-fetching hook or through a list of article-fetchings
hooks until one of them returns non-nil.\n
This is used by the article-get-* commands to permit non-standard news
article fetching to intermix with the NNTP.  If a hook returns non-nil,
it means that Gnews is now set to the indicated article, and is ready
for the user to read the article.\n
Arguments are ART-NO, the article number or message-id of interest,
KILLS, the hook-kills that are applicable, INTERACT, non-nil if the call
is to be treated as if it were interactive, and HOOKS, the hook or list
of hooks to run through.\n
The article Message-ID's case uses 0 for KILLS, since there are no kills
associated with article-get-msg-id.\n
Each hook function should take three arguments: ART-NO, KILLS, INTERACT."
  (setq hooks (cond ((fboundp hooks) (list hooks))
		    ((boundp hooks) (eval hooks))))
  (let ((hook (car hooks)) found)
    (while (and hooks (not found))
      (if (fboundp hook)
	  (setq found (funcall hook art-no kills interact)))
      (setq hooks (cdr hooks) hook (car hooks)))
    found))
\f


;;; Gnews Edit mode

;;; Edit the display of the current article.  The article itself is
;;; of course unaffected, and any changes will be lost upon exiting
;;; the current article.  Useful for fixing things that don't quite
;;; match the expectations of your own article filters and the like.

;;; Does not change any internals, like article-field-list.

(if gnews-edit-mode-map nil
  (setq gnews-edit-mode-map (gnews-copy-keymap text-mode-map))
  (gnews-key-bind gnews-edit-mode-map
		  '(("\^c\^c".gnews-edit-exit)
		    ("\^c\^]".gnews-edit-abort)
		    ("\^c\^r".gnews-edit-rot13)
		    ("\^c?".describe-mode)
		    ("\^c\^h".gnews-describe-mode))))

(defun gnews-edit-mode ()
  "Mode to edit the current article with.  It is Text mode with a few
extra commands:\n\\<gnews-edit-mode-map>
\t\\[gnews-edit-exit] to implement the changes and return, and
\t\\[gnews-edit-abort] to ignore the changes and return.\n
\t\\[gnews-edit-rot13] to rot13 regions of text.\n
Also, there is help via:\n
\t\\[describe-mode] to summarize this mode's commands, and
\t\\[gnews-describe-mode] to describe this mode's commands.\n"
  (interactive)
  (text-mode)
  (use-local-map gnews-edit-mode-map)
  (make-local-variable 'gnews-edit-p)
  (setq major-mode 'gnews-edit-mode
	mode-name "Gnews Edit"
	gnews-edit-p nil
	gnews-read-p nil
	gnews-hook-p t)
  (run-hooks 'text-mode-hook 'gnews-edit-hook))

(defun article-edit ()
  "Edit the contents of the current article."
  (interactive)
  (article-forward-intern nil)
  (setq gnews-pre-edit-text (buffer-substring (point-min) (point-max))
	gnews-pre-edit-point (point)
	buffer-read-only nil)
  (gnews-edit-mode)
  (gnews-set-mode-line)
  (message "Use %s to implement changes, %s to abort"
	   (if (eq (key-binding "\C-c\C-c") 'gnews-edit-exit) "C-c C-c"
	     (substitute-command-keys "\\[gnews-edit-exit]"))
	   (if (eq (key-binding "\C-c\C-]") 'gnews-edit-abort) "C-c C-]"
	     (substitute-command-keys "\\[gnews-edit-abort]"))))

(defun gnews-edit-rot13 (beg end)
  "Rot13 the region."
  (interactive "*r")
  (gnews-rot13 beg end))

(defun gnews-edit-exit (edp)
  "Return to group/pager mode, with changes in effect."
  (interactive (list t))
  (setq buffer-read-only t
	gnews-edit-p (or gnews-edit-p	; once edited, always edited
			 (and edp (not (eq last-command 'article-edit)))))
  (article-mode)
  (article-%-compute)
  (if (article-done) (article-quit)))

(defun gnews-edit-abort ()
  "Return to group/pager mode, with changes ignored."
  (interactive)
  (delete-region (point-min) (point-max))
  (insert gnews-pre-edit-text)
  (goto-char gnews-pre-edit-point)
  (gnews-edit-exit nil))
\f


;;; Mail box saving

;;; If there are any other styles worth emulating, write your own, and
;;; let me know about it.  A saver is invoked only if gnews-save-style
;;; is set to the name of the saver function.

(defun gnews-output-to-rmail-file (file-name)
  "Append the current article to an Rmail file named FILE-NAME.
If the file does not exist, ask if it should be created.
If file is being visited, the message is appended to the Emacs
buffer visiting that file."
  ;; full header handling added by unido!pbinfo!michael (Michael Schmidt)
  (interactive (list (read-file-name
		       (concat "Rmail save: (default "
			       (file-name-nondirectory group-last-save)
			       ") ")
		       (file-name-directory group-last-save)
		       (if (file-directory-p group-last-save)
			   (concat group-last-save article-current)
			 group-last-save))))
  (require 'rmail)
  (if article-grab-point (article-forward-intern group-save-junk))
  (setq file-name (expand-file-name file-name)
	group-last-save file-name)
  (or (get-file-buffer file-name)
      (file-exists-p file-name)
      (if (y-or-n-p
	    (concat "\"" file-name "\" does not exist, create it? "))
	  (let ((file-buffer (create-file-buffer file-name)))
	    (save-excursion
	      (set-buffer file-buffer)
	      (rmail-insert-rmail-file-header)
	      (let ((require-final-newline nil))
		(write-region (point-min) (point-max) file-name t 1)))
	    (kill-buffer file-buffer))
	(error "Output file does not exist")))
  (save-restriction
    (widen)
    ;; Decide whether to append to a file or to an Emacs buffer.
    (save-excursion
      (let ((buf (get-file-buffer file-name))
	    (cur (current-buffer))
	    (from (reply-domain (article-field "From")))
	    (time (current-time-string))
	    (beg 1)
	    (end 1)
	    (buffer-read-only nil))
	;; now fake some Babyl
	(goto-char 1)
	(insert "\f\n1,,\n")
	(insert (format "Summary-line: %2d-%3s  %25s  #%s\n"
			(string-to-int (substring time 11 13))
			(substring time 4 7)
			(if (< (length from) 26) from (substring from 0 25))
			(article-field "Subject")))
	(mapcar '(lambda (h) (insert (car h) ": " (cdr h) ?\n))
		(cdr article-field-list))
	(insert "\n*** EOOH ***\n")
	(goto-char (point-max))
	(insert ?\^_)
	(setq end (point-max))
	(if (not buf)
	    (append-to-file beg end file-name)
	  ;; File has been visited, in buffer BUF.
	  (set-buffer buf)
	  (let ((buffer-read-only nil)
		(msg (and (boundp 'rmail-current-message)
			  rmail-current-message)))
	    ;; If MSG is non-nil, buffer is in RMAIL mode.
	    (if msg
		(progn (widen)
		       (narrow-to-region (point-max) (point-max))))
	    (insert-buffer-substring cur beg end)
	    (if msg
		(progn
		  (goto-char (point-min))
		  (widen)
		  (search-backward "\^_")
		  (narrow-to-region (point) (point-max))
		  (goto-char (1+ (point-min)))
		  (rmail-count-new-messages t)
		  (rmail-show-message msg)))))
	;; and now unfake the Babyl
	(set-buffer cur)
	(goto-char 1)
	(let ((beg (point)))
	  (search-forward "*** EOOH ***\n")
	  (delete-region beg (point)))
	(goto-char (point-max))
	(delete-char -1)))))

(defun gnews-output-to-mbox-file (file-name)
  "Append the current article to a Unix mail file named FILE-NAME."
  (interactive (list (read-file-name
		       (concat "Mbox save: (default "
			       (file-name-nondirectory group-last-save)
			       ") ")
		       (file-name-directory group-last-save)
		       (if (file-directory-p group-last-save)
			   (concat group-last-save article-current)
			 group-last-save))))
  (require 'rmail)
  (if article-grab-point (article-forward-intern group-save-junk))
  (setq file-name (expand-file-name file-name)
	group-last-save file-name)
  (let ((b (current-buffer))
	(mb (get-buffer-create "*gnews*mbox*"))
	(case-fold-search t))
    (save-excursion
      (set-buffer mb)
      (erase-buffer)
      (insert-buffer-substring b)
      (insert "\n")
      (goto-char (point-min))
      (insert "From "
	      (reply-domain (article-field "From")) " "		; MJS
	      (current-time-string) "\n")
      (while (search-forward "\nFrom " nil t)
	(forward-char -5)
	(insert ?>))
      (append-to-file (point-min) (point-max) file-name))
    (kill-buffer mb)))