From: SNYDER@d0sb10.fnal.gov (scott snyder)
Subject: a gopher client for emacs   2/2
Organization: Source only  Discussion and requests in gnu.emacs.help.
Distribution: gnu
Date: Sat, 29 Aug 1992 23:27:20 GMT

#!/bin/sh
# this is gopher.02 (part 2 of a multipart archive)
# do not concatenate these parts, unpack them in order with /bin/sh
# file gopher.el continued
#
if test ! -r _shar_seq_.tmp; then
	echo 'Please unpack part 1 first!'
	exit 1
fi
(read Scheck
 if test "$Scheck" != 2; then
	echo Please unpack part "$Scheck" next!
	exit 1
 else
	exit 0
 fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
	echo 'x - still skipping gopher.el'
else
echo 'x - continuing file gopher.el'
sed 's/^X//' << 'SHAR_EOF' >> 'gopher.el' &&
X        (obj gopher-obj))
X
X    ;; Form the query string
X    (while vals
X
X      (if (not (zerop (length (car vals))))
X          (setq query (concat query " " (car fields) "=" (car vals))))
X
X      (setq vals (cdr vals))
X      (setq fields (cdr fields)))
X
X    ;; Use this string as the object selector.
X    (gopher-set-object-selector gopher-obj query)
X
X    ;; Retrieve the data from the server.  Unlike gopher, the CSO data
X    ;; does not use `.' as a terminator.
X    (gopher-document-object gopher-obj (current-buffer) "^[2-9]")
X
X    ;; Strip CSO control information from the buffer.
X    (gopher-clean-cso-buffer obj)))
X
X
X(defun gopher-clean-cso-buffer (obj)
X  "Strip CSO control information from the current buffer."
X
X  (let ((req "")
X        (buffer-read-only nil)
X        beg nreq)
X    (goto-char (point-min))
X    (insert "\n")
X    (while (not (eobp))
X      (cond ((and (>= (following-char) ?3) (<= (following-char) ?9))
X             (delete-char 4)
X             (insert (concat (gopher-object-selector obj) "\n")))
X            
X            ((eq (following-char) ?-)
X             (delete-char 5)
X             (setq beg (point))
X             (skip-chars-forward "^:")
X             (setq nreq (buffer-substring beg (point)))
X             (goto-char beg)
X             (or (string= req nreq)
X                 (insert (concat "--------------------------"
X                                 "-----------------------------\n")))
X             (setq req nreq)
X             (setq beg (point))
X             (skip-chars-forward "^:")
X             (forward-char)
X             (delete-region beg (point)))
X
X            (t
X             (setq beg (point))
X             (forward-line 1)
X             (delete-region beg (point))
X             (forward-line -1))
X            )
X      (forward-line 1))
X
X    (goto-char (point-min))
X    (delete-char 1)))
X
X
X;;;;--------------------------------------------------------------------------
X;;;; indices.
X;;;;
X;;;; To query an index, the search string is appended to the selector.
X;;;; The index returns a gopher directory.
X;;;;
X
X
X(defun gopher-index-object (obj oldbuf)
X  "Query a gopher directory object."
X
X  ;; Get the search string from the user.
X  (let ((str (read-from-minibuffer "Key: "))
X        (newobj (copy-sequence obj)))
X
X    ;; Append it to the selector and retrieve the modified object
X    ;; like a directory.
X    (setq str (gopher-trim-blanks str))
X    (if (> (length str) 0)
X        (progn
X          (gopher-set-object-selector newobj
X                                      (concat (gopher-object-selector obj) "\t"
X                                              str))
X          (gopher-directory-object newobj (current-buffer)))
X      )))
X
X
X
X;;;;--------------------------------------------------------------------------
X;;;; telneting.
X;;;;
X
X(defun gopher-telnet-object (obj oldbuf)
X  "Start a telnet session to a gopher object.
XIf gopher-telnet-command is nonnil, then that is a command to start
Xa telnet session in a subprocess.  Otherwise, the emacs-lisp telnet
Xpackage is used."
X  
X  ;; make the telnet argument string
X  (let ((arg (gopher-object-host obj))
X        (port (gopher-object-port obj)))
X    (if (not (zerop port))
X        (setq arg (concat arg 
X                          (if (eq system-type 'vax-vms)
X                              "/port="
X                            " ")
X                          port)))
X
X    (if gopher-telnet-command
X
X        ;; start up telnet as a separate process
X        (save-window-excursion
X          (gopher-background
X           (concat gopher-telnet-command " " arg)))
X
X      ;; use telnet-mode
X      (telnet arg)
X      ;; set things up so we can get back to the last node.
X      (gopher-make-local-vars
X       'gopher-last oldbuf
X       'gopher-telnet-process-name (concat arg "-telnet"))
X      (local-set-key "\C-cl" 'gopher-telnet-quit)
X      (local-set-key "\C-xk" 'gopher-telnet-quit)
X      )
X
X    ;; show the login info to the user
X    (if (not (zerop (length (gopher-object-selector obj))))
X        (progn
X          (beep)
X          (message (concat 
X                    "Login as: "
X                    (gopher-object-selector obj)
X                    ))
X          ))
X    ))
X
X
X(defun gopher-telnet-quit nil
X  "Clean up a telnet session and return to the previous gopher node."
X  (interactive)
X  (condition-case nil
X      (delete-process gopher-telnet-process-name)
X    (error t))
X  (gopher-last-node))
X
X
X
X;;;;--------------------------------------------------------------------------
X;;;; Various opaque objects.  Just save them in a file for now.
X;;;;
X
X(defun gopher-binary-object (obj oldbuf)
X  "Retrieve a gopher object and save it to a file,
Xwithout trying to interpret it in any way."
X  (let ((fname (read-file-name "File to save in: "))
X        (buf (gopher-get-doc-buf (gopher-object-descr obj))))
X
X    (gopher-retrieve-document-cleanly (buf
X                                       (gopher-object-selector obj)
X                                       (gopher-object-host     obj)
X                                       (gopher-object-port     obj)
X                                       'none)
X
X        (progn
X          (error "Problems retrieving object.")
X          (kill-buffer buf))
X
X      (save-excursion
X        (set-buffer buf)
X        (write-file fname))
X      (kill-buffer buf)
X      )))
X
X
X;;;;--------------------------------------------------------------------------
X;;;; forms stuff
X;;;;
X;;;; Uses some of the internal routines from forms.el to present
X;;;; a form which is not associated with a file.
X;;;;
X
X(defun gopher-form (form-name accept-action number-of-fields format-list)
X  "Display a buffer containing a form for the user to enter data.
XThe form is described by NUMBER-OF-FIELDS and FORMAT-LIST (cf. forms-mode).
XFORM-NAME is a string to put in the modeline.
XWhen the user accepts the data in the form by pressing `C-c RET', the
Xfunction ACCEPT-ACTION is called with a list of the strings which
Xthe user entered."
X
X  (switch-to-buffer (generate-new-buffer "*gopher form*"))
X
X  (gopher-make-local-vars
X   'forms-format-list   format-list
X   'forms-number-of-fields number-of-fields
X   'forms-field-sep        "\t"
X   'forms-read-only        nil
X   'forms-multi-line       nil
X   'forms--number-of-markers nil
X   'forms--markers           nil
X   'forms--format            nil
X   'forms--parser            nil
X   'forms--dynamic-text      nil
X   'forms-fields             nil
X   'forms-the-record-list    nil
X   'forms-accept-action      accept-action
X   )
X
X  (forms--process-format-list)
X  (forms--make-format)
X  (forms--make-parser)
X
X  (erase-buffer)
X
X  ;; make local variables
X  (make-local-variable 'forms--file-buffer)
X  (make-local-variable 'forms--total-records)
X  (make-local-variable 'forms--current-record)
X  (make-local-variable 'forms--the-record-list)
X  (make-local-variable 'forms--search-rexexp)
X
X  ;; set the major mode indicator
X  (setq major-mode 'gopher-form-mode)
X  (setq mode-name "gopher form")
X
X  (set-buffer-modified-p nil)
X
X  (use-local-map gopher-form-mode-map)
X
X  (forms--show-record (make-string (1- number-of-fields) ?\t))
X
X  (run-hooks 'gopher-form-mode-hooks))
X
X
X(defun gopher-form-accept nil
X  (interactive)
X
X  (funcall forms-accept-action (forms--parse-form)))
X
X(define-key gopher-form-mode-map "\C-c\r"  'gopher-form-accept)
X(define-key gopher-form-mode-map "\C-cl"   'gopher-last-node)
X
X
X;;;;--------------------------------------------------------------------------
X;;;; low-level communications routines
X;;;;
X
X(defun gopher-retrieve-document (buf sel host port &optional end-regexp)
X  "Retrieve a gopher object into BUF.
XThe object is identified by a SEL HOST PORT triple.
XOptional argument END-REGEXP is used for data which is not `.'-terminated.
XIf END-REGEXP is non-nil and not a string, then it is assumed that
Xthe data is binary, and reading will continue until the sender disconnects.
XReturns NIL if an error occured during the attempt to retrieve the
Xdocument, otherwise T.
X"
X
X
X  ;; Default is single period termination.
X  (or end-regexp (setq end-regexp "^\\.\r$"))
X
X  (save-excursion
X    (set-buffer buf)
X    (erase-buffer)
X
X    (let ((h (assoc host gopher-hostname-aliases)))
X      (if h (setq host (cdr h))))
X
X    ;; open the connection to the server
X    (let (wait
X	  (gopher-server-process
X           (condition-case nil
X               (open-network-stream "gopher" (current-buffer)
X                                    host port)
X             (error nil))))
X
X      (cond (gopher-server-process
X             
X             ;; keep the emacs end-of-process status line out of the buffer
X             (set-process-sentinel gopher-server-process 'gopher-sentinel)
X
X             ;; send the selector to the server
X             (process-send-string gopher-server-process (concat sel "\r\n"))
X
X             ;; receive the response from the server
X             ;; based on nntp.el from GNUS
X             (setq wait t)
X             (while wait
X               (if (stringp end-regexp)
X                   (progn
X                     (goto-char (point-max))
X                     (forward-line -1)))
X               (if (and (stringp end-regexp)
X                        (looking-at end-regexp))
X                   (setq wait nil)
X                 (if (not (memq (process-status gopher-server-process) '(open run)))
X                     (progn
X                       (ding)
X                       (message "gopher: connection closed")
X                       (setq wait nil))
X                   (if gopher-debug-read
X                       (message "gopher: Reading..."))
X                   (cond (gopher-buggy-accept
X                          (sit-for 1))
X                         ((and (boundp 'epoch::version) epoch::version)
X                          (accept-process-output gopher-server-process 2))
X                         (t
X                          (accept-process-output gopher-server-process))
X                         )
X                   (if gopher-debug-read
X                       (message " ")))
X                 ))
X
X             ;; be sure the net connection has gone away...
X             (condition-case nil
X                 (delete-process gopher-server-process)
X               (error t))
X
X             ;; clean up the text buffer
X             (if (stringp end-regexp)
X                 (gopher-clean-text))
X
X             t)
X
X            (t nil))
X      )))
X
X
X;;; adapted from GNUS
X(defun gopher-clean-text ()
X  "Decode text transmitted by gopher.
X0. Delete status line.
X1. Delete `^M' at end of line.
X2. Delete `.' at end of buffer (end of text mark).
X3. Delete `.' at beginning of line.   (does gopher want this?)"
X
X  ;; Insert newline at end of buffer.
X  (goto-char (point-max))
X  (if (not (bolp))
X      (insert "\n"))
X  ;; Delete `^M' at end of line.
X  (goto-char (point-min))
X  (replace-regexp "\r[^\n]*$" "")
X;  (goto-char (point-min))
X;  (while (not (eobp))
X;    (end-of-line)
X;    (if (= (preceding-char) ?\r)
X;       (delete-char -1))
X;    (forward-line 1)
X;    )
X  ;; Delete `.' at end of buffer (end of text mark).
X  (goto-char (point-max))
X  (forward-line -1)                     ;(beginning-of-line)
X  (while (looking-at "^\\.$")
X    (delete-region (point) (progn (forward-line 1) (point)))
X    (forward-line -1))
X  ;; Replace `..' at beginning of line with `.'.
X  (goto-char (point-min))
X  ;; (replace-regexp "^\\.\\." ".")
X  (while (search-forward "\n.." nil t)
X    (delete-char -1))
X  )
X
X
X(defun gopher-sentinel (proc status)
X  nil)
X
X;;; gopher.el ends here
X
X;;;(gopher.el) Local Variables:
X;;;(gopher.el) eval: (put 'gopher-retrieve-document-cleanly 'lisp-indent-hook 2)
X;;;(gopher.el) End:
X
SHAR_EOF
echo 'File gopher.el is complete' &&
chmod 0644 gopher.el ||
echo 'restore of gopher.el failed'
Wc_c="`wc -c < 'gopher.el'`"
test 47673 -eq "$Wc_c" ||
	echo 'gopher.el: original size 47673, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
rm -f _shar_seq_.tmp
echo You have unpacked the last part
exit 0
Newsgroups: gnu.emacs.sources