|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: S T
Length: 15521 (0x3ca1)
Types: TextFile
Names: »Spool.el«
└─⟦a05ed705a⟧ Bits:30007078 DKUUG GNU 2/12/89
└─⟦32c6b6024⟧ »./gnews-2.0-tar.Z«
└─⟦5d06bd818⟧
└─⟦this⟧ »gnews-2.0/Spool.el«
;;; Spool.el--substitute functions for reading off a news spool
;;; 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
;;; Extensively revised/fixed/tested by Hal R Peterson (hrp@hall.cray.com)
(provide 'gnews-spool)
;;; First, the basics get redefined. This must be loaded *after* Init.el
(fset 'nntp-start 'gnews-spool-start)
(fset 'nntp-exec 'gnews-spool-exec)
(fset 'article-get 'article-get-slow)
(fset 'nntp-index-exec 'gnews-spool-index-exec)
(fset 'nntp-index-start (function (lambda () t)))
(fset 'nntp-run-p (function (lambda () nil)))
;;; This won't work with fast indexing, of course, which violates the
;;; rule of filtering every NNTP command through a single function.
;;; A fast indexing for spool code is in the works.
;@@ IMPORTANT REMARK: I am unable to fully test this code. Caveat user.
;@@ Possible site dependencies are indicated below with ;@@ comments.
;;; gnews-spool-* preliminaries
(defvar n-reply-allowed t
"*Non-nil if posting is permitted.")
(defvar gnews-server-article nil
"Current article in pseudo-server.")
(defvar gnews-server-group nil
"Current group in pseudo-server.")
(defvar gnews-spool-active-file "/usr/lib/news/active")
(defvar gnews-spool-history-file "/usr/lib/news/history")
(defvar gnews-spool-newsdir "/usr/spool/news/")
(defun gnews-spool-info (&rest args)
"Set the nntp-info variable."
(setq nntp-info (mapconcat 'identity args " ")))
(defun gnews-spool-dir (gp)
"Return the directory where newsgroup GP's articles are found."
(concat gnews-spool-newsdir (gnews-replace "\\." "/" gp) "/"))
(defun gnews-spool-art (gp art)
"Return the name of the file containing newsgroup GP, article # ART."
(concat gnews-spool-newsdir (gnews-replace "\\." "/" gp) "/" art))
;@@ The regexp for matching the date and time may be different on your site.
;@@ For example, maybe "[ \t]+../../..[ \t]+..:..[ \t]+" is what you need.
(defun gnews-spool-regexp (msg-id)
"Return the regexp that matches MSG-ID in the history file, and also
brackets off the newsgroup and article number as match #1 and match #2."
(concat "^" (regexp-quote msg-id) ; Message-ID
"[ \t]../../..[ \t]..:..[ \t]" ; date/time.
"\\([^/]*\\)/\\([0-9]*\\) ")) ; group/###
\f
;;; gnews-spool-* commands and internals
(defun gnews-spool-start (msg)
"Initialize gnews-spool buffers."
(if msg (message "%sreading news spool from %s..." msg gnews-spool-machine))
(setq gnews-spool-active (find-file-noselect gnews-spool-active-file))
(gnews-spool-info (if n-reply-allowed "200" "201") news-path)
(fset 'nntp-run-p (function (lambda () t)))
(if msg (message "%sreading news spool from %s...done"
msg gnews-spool-machine)))
(defun gnews-spool-exec (clear finish comm &rest args)
"NNTP commands interpreted directly off a news spool."
(interactive
(list (not current-prefix-arg)
(read-from-minibuffer "NNTP command: ")
nil))
(if (interactive-p)
(setq args (progn
(string-match "\\<[^ ]*\\>" comm)
(if (/= (length comm) (match-end 0))
(list (substring comm (1+ (match-end 0))))))
comm (substring comm (match-beginning 0) (match-end 0)))
(if (stringp clear) (error "Uh, you forgot the clear flag, eh?")))
(if clear (nntp-clear nntp-buffer))
(let* ((b (current-buffer))
(a1prime (car args))
(a1 (concat a1prime))
(a2 (concat (gnadr args)))
(art (if a1prime
a1
(or gnews-server-article "-1"))))
(prog2
(set-buffer nntp-buffer)
(cond ((string= comm "group")
(gnews-spool-exec-group a1))
((string= comm "article")
(gnews-spool-exec-art art 'art))
((string= comm "head")
(gnews-spool-exec-art art 'head))
((string= comm "body")
(gnews-spool-exec-art art 'body))
((string= comm "stat")
(gnews-spool-exec-art art 'stat))
((string= comm "next")
(gnews-spool-exec-motion t))
((string= comm "last")
(gnews-spool-exec-motion nil))
((string= comm "list")
(gnews-spool-exec-list))
((string= comm "newgroups")
(gnews-spool-exec-newgroups (concat a1 a2)))
((string= comm "help")
(gnews-spool-exec-help))
((string= comm "quit")
(gnews-spool-exec-quit)))
(set-buffer b))))
(defun gnews-spool-exec-group (gp)
"Fake an NNTP group command."
(let ((dir (gnews-spool-dir gp)) c f l)
(if (and (file-readable-p dir)
(car (file-attributes dir)))
(gnews-string-as-buffer "" nil
(setq gnews-server-article nil)
(setq gnews-server-group gp)
(call-process "ls" nil t nil dir)
(goto-char 1)
(insert "(setq gnews-spool-group-list (gnews-spool-preen '(")
(goto-char (point-max))
(insert ")))")
(eval-current-buffer)
(if (null gnews-spool-group-list)
(gnews-spool-info "211 0 0 0" gp) ; nothing there
(sort gnews-spool-group-list '<)
(setq gnews-spool-group-tsil (reverse gnews-spool-group-list))
(setq c (length gnews-spool-group-list))
(setq f (car gnews-spool-group-list))
(setq l (car gnews-spool-group-tsil))
(gnews-spool-info "211" c f l gp)
t))
(gnews-spool-info "411 Invalid group name.")
nil)))
(defun gnews-spool-preen (grouplist)
"Remove all subgroups from GROUPLIST, a list of articles in a group."
;; First remove the leading subgroups.
(while (and grouplist (not (integerp (car grouplist))))
(setq grouplist (cdr grouplist)))
;; Now remove the embedded and trailing subgroups.
(let ((preened-list grouplist))
(while (cdr grouplist)
(if (not (integerp (gnadr grouplist)))
(setcdr grouplist (gnddr grouplist))
(setq grouplist (cdr grouplist))))
preened-list))
(defvar gnews-spool-history-lookup-prog "grep"
"External program to run when looking up a Message-ID.")
(defun gnews-spool-history-lookup-args (msg-id)
"List of arguments to pass to gnews-spool-history-lookup-prog."
(list (regexp-quote msg-id) gnews-spool-history-file))
(defun gnews-spool-exec-art (art-no part)
"Fake an NNTP article/head/body/stat command."
(let (file msg-id)
(if (and (cond ((string-match "^[0-9]+$" art-no)
(setq file (gnews-spool-art gnews-server-group art-no))
(if (let ((attributes (file-attributes file)))
(and attributes (< 0 (nth 7 attributes))))
(if (memq part '(body stat))
;; Set the Message-ID by hand
(setq msg-id (gnews-string-as-buffer "" nil
(call-process "sed" file t t
"/^Message-ID:/q")
(forward-line -1)
(forward-char 12)
(buffer-substring
(point) (gnews-eol))))
t)))
((string-match "^<.*>$" art-no)
(gnews-string-as-buffer "" nil
(apply 'call-process
gnews-spool-history-lookup-prog nil t nil
(gnews-spool-history-lookup-args art-no))
(beginning-of-buffer)
(if (re-search-forward (gnews-spool-regexp art-no)
nil t)
(setq art-no (gnews-match 2)
file (gnews-spool-art (gnews-match 1) art-no))
(setq art-no "0"
file "/meese/sucks/raw/eggs/film/at/11")))
(set-buffer nntp-buffer)))
(file-readable-p file))
(progn
(setq gnews-server-article art-no)
(cond ((eq part 'art)
(insert-file file))
((eq part 'head)
(call-process "sed" file t t "/^$/q")
(goto-char (point-max))
(delete-char -1))
((eq part 'body)
(call-process "sed" file t t "1,/^$/d")))
(gnews-spool-info (cond ((eq part 'art) "220")
((eq part 'head) "221")
((eq part 'body) "222")
((eq part 'stat) "223"))
art-no
msg-id
"Article retrieved;"
(cond ((eq part 'art) "head and body follow.")
((eq part 'head) "head follows.")
((eq part 'stat) "request text separately.")
((eq part 'body) "body follows.")))
t)
(gnews-spool-info "423 Invalid article number:" art)
nil)))
;;; ugly. There must be a cleaner way.
(defun gnews-spool-exec-motion (pfx)
"Fake an NNTP next/last command."
(let* ((art-no (and gnews-server-article
(car (read-from-string gnews-server-article))))
(art-list (cdr (memq art-no
(if pfx
gnews-spool-group-list
gnews-spool-group-tsil))))
(next-art-no (car art-list))
(next-art (concat next-art-no))
(result (if (null art-list) nil
(gnews-spool-exec-art next-art 'stat))))
(while (and (not (null art-list))
(null result))
(setq art-list (cdr art-list)
next-art (concat (car art-list))
result (if (null art-list)
nil
(gnews-spool-exec-art next-art 'stat))))
(if (null art-list)
(gnews-spool-info "421 No "
(if pfx "next" "previous")
" article to retrieve")
(setq gnews-server-article next-art))
result))
(defun gnews-spool-exec-list ()
"Fake an NNTP list command."
(insert-file gnews-spool-active-file)
(gnews-spool-info "215 Newsgroups in form \"group high low y/n\".")
t)
(defun gnews-spool-exec-newgroups (ymd hms &optional gmt) t)
(defun gnews-spool-exec-help ()
"Waste time creatively."
(if (boundp 'gnews-meese-is-a-bowbity-bowb-bowb) (load "meese.el"))
(gnews-spool-info "100 This server accepts the following commands:")
t)
(defun gnews-spool-exec-quit ()
"Fake an NNTP quit command."
(fset 'nntp-run-p '(lambda () nil))
(setq gnews-server-article nil
gnews-server-group nil)
(gnews-spool-info "205" news-path "closing connection. Goodbye.")
t)
;;; from jr@bbn.com (John Robinson):
(defun gnews-spool-index-exec (comm &rest args)
"NNTP commands for indexing interpreted directly off a news spool."
(interactive
(list (not current-prefix-arg)
(read-from-minibuffer "NNTP command: ")
nil))
(if (interactive-p)
(setq args (progn
(string-match "\\<[^ ]*\\>" comm)
(if (/= (length comm) (match-end 0))
(list (substring comm (1+ (match-end 0))))))
comm (substring comm (match-beginning 0) (match-end 0))))
(let* ((b (current-buffer))
(a1prime (car args))
(a1 (concat a1prime))
(a2 (gnadr args))
(art (if a1prime a1 (or gnews-server-article "-1"))))
(prog2
(set-buffer nntp-buffer)
(cond ((string= comm "group")
(gnews-spool-exec-group a1))
((string= comm "head")
(gnews-spool-exec-art art 'head)))
(set-buffer b))))
\f
;;; fast indexing: set news-index-fast to t.
(fset 'news-index-fast 'gnews-spool-index-fast)
(defun gnews-spool-index-fast (pfx &optional nosub in-group)
"Display an index of the proffered newsgroup."
(interactive "P")
(setq index-pop index-pop-up
nntp-index-done nil)
(or in-group (news-goto gnews-server-group nosub))
(set-buffer nntp-index-buffer)
(erase-buffer)
(gnews-buffer index-pop index-buffer)
(setq buffer-read-only)
(erase-buffer)
(setq buffer-read-only t)
(message "indexing...")
(nntp-exec t t "group" gnews-server-group)
(setq nntp-index-final (if (amark-member article-final amark)
(amark-previous-unread article-final amark)
article-final)
gnews-spool-index-files (list "-")
gnews-s-i-f gnews-spool-index-files)
(amark-loop art-no (list (cons article-current article-final))
(if (and (or index-show-kills (not (amark-member art-no amark)))
(memq art-no gnews-spool-group-list))
(progn
(setcdr gnews-s-i-f (list (concat (gnews-spool-dir
gnews-server-group)
art-no)))
(setq gnews-s-i-f (cdr gnews-s-i-f)))))
(setq nntp-index
(start-process "gnews-spool-index"
nntp-index-buffer
"/bin/sh"
"-c"
(concat "for i in "
(mapconcat 'identity
gnews-spool-index-files
" ")
";do echo :${i}:"
";sed -n \"1,/^$/p\" $i"
";done")))
(set-process-filter nntp-index 'gnews-spool-index-filter)
(index-mode)
(setq index-x-menu nil)
(if index-sort-do (index-sort))
(setq buffer-read-only)
(goto-char 1)
(mapcar '(lambda (x) (insert (format "%5dm %s\n" (car x) (cdr x))))
(cdr index-perm-marks))
(setq buffer-read-only t)
(setq index-final article-current)
(article-current-set index-final))
(defun gnews-spool-index-filter (proc string)
"Filter for fast spool indexing."
(setq nntp-index-p t)
(set-buffer nntp-index-buffer)
(setq article-field-list (list nil)
nntp-index-done nil)
(goto-char (point-max))
(insert string)
(goto-char 1)
(let* ((hook-kill-continue t)
(hook hook-kill-per)
(h (mapcar 'ignore index-headers))
(rgxp (concat "^:"
(gnews-spool-dir gnews-server-group)
"\\([0-9]+\\):"))
p q n i f g z d junk)
(while (and (not nntp-index-done)
(re-search-forward rgxp nil t)
(setq p (gnews-bol)
n (read (buffer-substring
(match-beginning 1) (match-end 1))))
(re-search-forward "^$" nil t)
(not (eobp))
(setq q (gnews-eol)))
(setq i index-headers z h)
(while z ; h gets the headers
(goto-char p)
(setcar z (if (re-search-forward
(concat "^" (car i) ": *\\(.*\\)") q t)
(buffer-substring
(match-beginning 1) (match-end 1))
""))
(setq i (cdr i) z (cdr z)))
(setq z (cdr article-field-list))
(while z ; a-f-l gets alist cdr's ""'ed
(setcdr (car z) "")
(setq z (cdr z)))
(save-excursion
(save-restriction
(narrow-to-region p q)
(goto-char p)
(forward-line 1)
(while (not (eobp))
(if (looking-at "^\\([^:]*\\): *\\(.*\\)$")
(progn (setq f (buffer-substring
(match-beginning 1) (match-end 1))
g (buffer-substring
(match-beginning 2) (match-end 2)))
(if (setq z (assoc f article-field-list))
(setcdr z g)
(nconc article-field-list (list (cons f g))))))
(forward-line 1))))
(while (and hook hook-kill-continue (not junk))
(setq junk (hook-kill-do (car hook) t)
hook (cdr hook)))
(delete-region p q)
(if (and junk (not index-show-kills))
(if (setq nntp-index-done (= n nntp-index-final))
(save-excursion
(set-buffer index-buffer)
(setq buffer-read-only)
(goto-char (point-max))
(if (not (bobp)) (delete-char -1))
(setq buffer-read-only t)
(index-done-do)))
(save-excursion
(set-buffer index-buffer)
(setq buffer-read-only)
(setq nntp-index-done (= n nntp-index-final))
(goto-char (point-max))
(if (string< "" (mapconcat 'identity h ""))
(insert (setq d (format "%5d" n)) (if junk "k" " ") " "
(index-line n index-format h index-filter index-sizes)
(if nntp-index-done "" "\n")))
(if (and index-show-p (string-match "....0" d))
(progn (message "indexing...%s" d)
(sit-for 0)))
(setq buffer-read-only t)
(if nntp-index-done (index-done-do))
(setq junk nil)
(set-buffer nntp-index-buffer))))))