From: sra@epilogue.com (Rob Austein)
Newsgroups: gnu.emacs.sources
Subject: archie.el extensions (asynch mode, completion)
Date: 8 Oct 92 00:41:33 GMT
Distribution: gnu
Organization: Epilogue Technology Corporation

I partially rewrote archie.el to run archie in an asynchronous
subprocess so one can do other things while Prospero grovels through
the bits.  While I was at it, I changed the query-mode stuff to use
keywords instead of the obscure one-character switches, and did a few
minor things to archie-mode to make it feel more like dired.

Since the entire package is so short, I'm just including it here
rather than put it up for anonymous FTP.  I'd like to hear about any
bugs, although I don't promise to fix them....

--Rob Austein <sra@epilogue.com>

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; archie.el v3.0
;;   A mock-interface to Archie for Emacs.
;;
;;   -- original version (1.0) by Brendan Kehoe (brendan@cs.widener.edu)
;;   ange-ftp extensions (2.0) by Sanjay Mathur (mathur@nas.nasa.gov)
;;   asynchronous mode   (3.0) by Rob Austein   (sra@epilogue.com)
;; 
;; This file is not part of GNU Emacs but the same permissions apply.
;; 
;; 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 1, 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, 675 Mass Ave, Cambridge, MA 02139, USA.
;;
;;

;; Usage:
;;
;; M-x archie-sez will insert the result of the query in the current buffer.
;; M-x archie creates a separate buffer from which you can find, copy
;; or run dired on any of the entries (using ange-ftp) and redo the search
;; with modified string and/or search-type.
;;

;; Installation instructions:
;;
;; Install this file as archie.el somewhere in your load-path and add the
;; following two lines to ~/.emacs. (without the semicolon's, of course)
;;
;; (autoload 'archie "archie" "Archie interface" t)
;; (autoload 'archie-sez "archie" "Insert results of archie query" t)
;;
;; You may have to change the value of archie-program and archie-server
;; as appropriate for your site.
;; archie-search-type and archie-download-directory can be modified
;; to suit personal preferences.
;;
;; For use with this package, it is also convenient to set
;;  (setq ange-ftp-generate-anonymous-password t)
;;
;;  Also, the crypt package (available in the LCD archives) is useful
;;  with archie-find-file, since most archive sites store their files
;;  in a compressed form.

;;
;; LCD Archive Entry:
;; archie|Sanjay R. Mathur|mathur@nas.nasa.gov
;; |A mock-interface to the archie program.
;; Wed Apr 22 22:31:46 1992|2.0||
;;

;; Customization variables

(defvar archie-program "archie"
  "Program that queries archie servers.")

(defvar archie-server "archie.sura.net"
  "Server for \\[archie] searches.

Known archie servers:
	archie.ans.net (USA [NY])
	archie.sura.net (USA [MD])
	archie.mcgill.ca (Canada)
	archie.funet.fi (Finland/Mainland Europe)
	archie.au (Australia)
	archie.doc.ic.ac.uk (Great Britain/Ireland)")

(defvar archie-download-directory nil
  "Default directory into which any files copied by archie-copy are
  copied. nil means to use the buffer's default-directory.")

(defconst archie-search-key-alist
  '(("exact-match" . "-e")
    ("case-sensitive-substring" . "-c")
    ("regular-expression" . "-r")
    ("substring" . "-s")
    ("exact-case-sensitive-substring" . "-ec")
    ("exact-regular-expression" . "-er")))

(defvar archie-search-type (car (car archie-search-key-alist))
  "Default search type for archie queries, from archie-search-key-alist.")

(defvar archie-l-output "[0-9]*Z *[0-9]* *\\([^ ]*\\) *\\(.*$\\)"
  "Regular expression matching the results of archie -l query. The
   two subexpressions match the host-name and the path respectively.")

(defvar archie-last-query nil)

(defvar archie-last-type nil)

(defvar archie-mode-map
  (let ((map (make-keymap)))
    (define-key map "f" 'archie-find-file)
    (define-key map "a" 'archie)
    (define-key map "a" 'archie-modify-query)
    (define-key map "c" 'archie-copy)
    (define-key map "d" 'archie-dired)
    (define-key map "n" 'archie-next-line)
    (define-key map "\C-n" 'archie-next-line)
    (define-key map " " 'archie-next-line)
    (define-key map "p" 'archie-previous-line)
    (define-key map "\C-p" 'archie-previous-line)
    (define-key map "\C-?" 'archie-previous-line)
    (define-key map "v" 'archie-view-file)
    map))

(defun archie-sez (string &optional type buffer)
  "Insert the results of an archie query on STRING into the current buffer.
Uses the function `archie' for its main work."
   (interactive
    (list (read-string "Query string: " nil)
	  (completing-read "Query type: " archie-search-key-alist
			   nil 0 archie-search-type)
	  (read-buffer "Inserting into buffer: " (buffer-name) t)))
   (let ((proc (archie string type (or buffer (current-buffer)))))
     (while (and (processp proc) (eq 'run (process-status proc)))
       (message "Waiting for archie...")
       (sit-for 0)
       (accept-process-output proc))
     (message "Waiting for archie...done")))

(defun archie (string &optional type buffer)
  "Look for STRING on an Archie server.
Optional second arg TYPE is the type of search to make -- by default, it's
`archie-search-type'.  Possible values are substring, subcase (case insensitive
substring), and regexp (a regular expression).  Interactively, a prefix arg
will make it prompt for this."
  (interactive
   (list (read-string "Query string: " nil)
	 (completing-read "Query type: " archie-search-key-alist
			  nil 0 archie-search-type)
	 nil))
  (setq type
	(or (and (stringp type) (= ?- (aref type 0)) type)
	    (cdr (assoc (or type archie-search-type) archie-search-key-alist))
	    "-e"))
  (cond ((or (eq buffer t) (bufferp buffer)
	     (and (stringp buffer) (get-buffer buffer)))
	 (or (eq buffer t)
	     (set-buffer buffer))
	 (push-mark (point) t)
	 (insert "Archie sez: \n"))
	((null buffer)
	 (set-buffer
	  (setq buffer
		(get-buffer-create (format "Archie [%s] %s" type string))))
	 (setq buffer-read-only nil)
	 (erase-buffer)
	 (setq buffer-read-only t)
	 (archie-mode))
	(t
	 (error "Bad BUFFER argument (%s)" (prin1-to-string buffer))))

  (setq archie-last-query string
	archie-last-type (or (car (rassq type archie-search-key-alist)) type))
  (pop-to-buffer (current-buffer))

  (let ((proc (start-process (format "Archie [%s] %s" type string)
			     (current-buffer) archie-program "-l"
			     "-h"  archie-server
			     type "-" string)))
    (set-process-filter proc 'archie-filter)
    (set-process-sentinel proc 'archie-sentinel)
    proc))

(defun archie-filter (proc string)
  (let ((cannot-use-save-excursion-here (current-buffer)))
    (set-buffer (process-buffer proc))
    (let (buffer-read-only)
      (insert string))
    (set-buffer cannot-use-save-excursion-here)))

(defun archie-sentinel (proc state)
  (let ((cannot-use-save-excursion-here (current-buffer)))
    (set-buffer (process-buffer proc))
    (if (eq major-mode 'archie-mode)
	(let ((match-data (match-data)))
	  (goto-char (point-min))
	  (unwind-protect
	      (if (looking-at archie-l-output)
		  (goto-char (match-beginning 1)))
	    (store-match-data match-data))))
    (set-buffer cannot-use-save-excursion-here)))

(defun archie-get-filename ()
  (save-excursion
    (beginning-of-line)
    (if (looking-at archie-l-output)
	(concat "/anonymous@"
		(buffer-substring (match-beginning 1) (match-end 1))
		":"
		(buffer-substring (match-beginning 2) (match-end 2)))
      (error "Not archie -l output"))))

(defun archie-next-line (arg)
  (interactive "p")
  (next-line arg)
  (if (looking-at archie-l-output)
      (goto-char (match-beginning 1))))

(defun archie-previous-line (arg)
  (interactive "p")
  (previous-line arg)
  (if (looking-at archie-l-output)
      (goto-char (match-beginning 1))))

(defun archie-find-file ()
  "Find the file mentioned on the current line of archie -l output.
Runs dired if the file is a directory and find-file-run-dired is non-nil."
  (interactive)
  (require 'ange-ftp)
  (find-file (archie-get-filename)))

(defun archie-view-file ()
  "View the file mentioned on the current line of archie -l output."
  (interactive)
  (require 'ange-ftp)
  (view-file (archie-get-filename)))

(defun archie-copy ()
  "Copy the file mentioned on the current line of archie -l output.
Prompts with the value of archie-download-directory, if non-nil,
as the default directory in which to copy. The file-name part can be
empty, in which case the original name is used."
  (interactive)
  (require 'ange-ftp)
  (let* ((from (archie-get-filename))
	 (from-nondir (file-name-nondirectory from))
	 (to nil))
    (if (string-equal "" from-nondir)
	(error "%s is a directory" from))
    (setq to (read-file-name
	      (format "Copy %s to: " from-nondir)
	      archie-download-directory))
    (if (file-directory-p to)
	(setq to (concat (file-name-as-directory to) from-nondir)))
    (copy-file from to 1)))
      
(defun archie-dired ()
  "Run dired on the file or directory mentioned on the current line
of archie -l output."
  (interactive)
  (require 'ange-ftp)
  (dired (file-name-directory (archie-get-filename))))

(defun archie-modify-query (string type)
  "Re-do the last archie search, with modification of the string
and/or search type."
  (interactive
   (list (read-string "String: " archie-last-query)
	 (completing-read "Query type: " archie-search-key-alist
			  nil 0 archie-search-type)))
  (archie string type))

(defun archie-mode ()
  "Major mode for interacting with the archie program.
\\[archie-find-file] finds the file on the current line,
\\[archie-copy] copies it, \\[archie-dired] runs dired on it.
\\[archie-modify-query] re-runs the last search with modifications
to the string and/or switches.

If archie-download-directory is non-nil then its value is used
as the default directory while prompting for the target file by the
archie-copy command.
\\{archie-mode-map}
Runs archie-mode-hook if non-nil."
  (kill-all-local-variables)
  (setq mode-name "Archie")
  (setq major-mode 'archie-mode)
  (use-local-map archie-mode-map)
  (set (make-local-variable 'mode-line-process) '(": %s"))
  (run-hooks 'archie-mode-hook))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; End of archie.el.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Newsgroups: gnu.emacs.sources