[comp.emacs] Experimental talk mode for GNU emacs.

ray@gibbs.physics.purdue.edu (Ray Moody) (06/11/89)

    Here is a talk mode for emacs.  I consider this version to be
experimental because it uses too much CPU time to be truly useful.  If
you have suggestions for improvements, or if you want a copy of the
final version, send mail to ray@maxwell.physics.purdue.edu.

    You need a special version of talk for this to work.  The source
for this is included.  It is based on berkeley source that is freely
redistributable (of course!!).

    Enjoy!

								Ray
-------------------------------------------------------------------------------
# This is a shell archive.  Remove anything before this line, then
# unpack it by saving it in a file and typing "sh file".  (Files
# unpacked will be owned by you and have default permissions.)
#
# This archive contains:
# talk.el Makefile ctl.c ctl_transact.c display.c get_addrs.c get_names.c init_disp.c invite.c io.c look_up.c msgs.c talk.c talk.h talk_ctl.h

echo x - talk.el
cat > "talk.el" << '//E*O*F talk.el//'
;; Run talk under Emacs
;; Copyright (C) 1989 G. Ray Moody, III. (ray@maxwell.physics.purdue.edu)

;; This file is not (yet) part of GNU Emacs.

;; This file 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.
;; Refer to the GNU General Public License for full details.

;; Everyone is granted permission to copy, modify and redistribute
;; this file, but only under the conditions described in the
;; GNU General Public License.   A copy of this license is
;; supposed to have been given to you along with GNU Emacs so you
;; can know your rights and responsibilities.  It should be in a
;; file named COPYING.  Among other things, the copyright notice
;; and this notice must be preserved on all copies.

;; This version of talk is experimental!!  It uses too much CPU time to be
;; useful.  If you have suggestions for improvements, or if you want a
;; copy of the final version, send mail to ray@maxwell.physics.purdue.edu.

;; The talk-mode syntax table is really weird.  Everything character is
;; a word constituent except spaces.  It is this way so that talk and
;; emacs can agree as to what a word is (see display.c)

(defvar talk-mode-syntax-table nil
  "Syntax table to use in talk-mode.")

(if (null talk-mode-syntax-table)
    (let ((i 0))
      (setq talk-mode-syntax-table (make-syntax-table))
      (while (> (length talk-mode-syntax-table) i)
	(modify-syntax-entry i "w" talk-mode-syntax-table)
	(setq i (1+ i)))
      (modify-syntax-entry ?  " " talk-mode-syntax-table)))

(defvar talk-mode-map nil
  "Keymap to use in talk-mode.")

(if (null talk-mode-map)
    (progn
      (setq talk-mode-map (make-keymap))
      (define-key talk-mode-map " " 'talk-char)
      (define-key talk-mode-map "!" 'talk-char)
      (define-key talk-mode-map "\"" 'talk-char)
      (define-key talk-mode-map "#" 'talk-char)
      (define-key talk-mode-map "$" 'talk-char)
      (define-key talk-mode-map "%" 'talk-char)
      (define-key talk-mode-map "&" 'talk-char)
      (define-key talk-mode-map "'" 'talk-char)
      (define-key talk-mode-map "(" 'talk-char)
      (define-key talk-mode-map ")" 'talk-char)
      (define-key talk-mode-map "*" 'talk-char)
      (define-key talk-mode-map "+" 'talk-char)
      (define-key talk-mode-map "," 'talk-char)
      (define-key talk-mode-map "-" 'talk-char)
      (define-key talk-mode-map "." 'talk-char)
      (define-key talk-mode-map "/" 'talk-char)
      (define-key talk-mode-map "0" 'talk-char)
      (define-key talk-mode-map "1" 'talk-char)
      (define-key talk-mode-map "2" 'talk-char)
      (define-key talk-mode-map "3" 'talk-char)
      (define-key talk-mode-map "4" 'talk-char)
      (define-key talk-mode-map "5" 'talk-char)
      (define-key talk-mode-map "6" 'talk-char)
      (define-key talk-mode-map "7" 'talk-char)
      (define-key talk-mode-map "8" 'talk-char)
      (define-key talk-mode-map "9" 'talk-char)
      (define-key talk-mode-map ":" 'talk-char)
      (define-key talk-mode-map ";" 'talk-char)
      (define-key talk-mode-map "<" 'talk-char)
      (define-key talk-mode-map "=" 'talk-char)
      (define-key talk-mode-map ">" 'talk-char)
      (define-key talk-mode-map "?" 'talk-char)
      (define-key talk-mode-map "@" 'talk-char)
      (define-key talk-mode-map "A" 'talk-char)
      (define-key talk-mode-map "B" 'talk-char)
      (define-key talk-mode-map "C" 'talk-char)
      (define-key talk-mode-map "D" 'talk-char)
      (define-key talk-mode-map "E" 'talk-char)
      (define-key talk-mode-map "F" 'talk-char)
      (define-key talk-mode-map "G" 'talk-char)
      (define-key talk-mode-map "H" 'talk-char)
      (define-key talk-mode-map "I" 'talk-char)
      (define-key talk-mode-map "J" 'talk-char)
      (define-key talk-mode-map "K" 'talk-char)
      (define-key talk-mode-map "L" 'talk-char)
      (define-key talk-mode-map "M" 'talk-char)
      (define-key talk-mode-map "N" 'talk-char)
      (define-key talk-mode-map "O" 'talk-char)
      (define-key talk-mode-map "P" 'talk-char)
      (define-key talk-mode-map "Q" 'talk-char)
      (define-key talk-mode-map "R" 'talk-char)
      (define-key talk-mode-map "S" 'talk-char)
      (define-key talk-mode-map "T" 'talk-char)
      (define-key talk-mode-map "U" 'talk-char)
      (define-key talk-mode-map "V" 'talk-char)
      (define-key talk-mode-map "W" 'talk-char)
      (define-key talk-mode-map "X" 'talk-char)
      (define-key talk-mode-map "Y" 'talk-char)
      (define-key talk-mode-map "Z" 'talk-char)
      (define-key talk-mode-map "[" 'talk-char)
      (define-key talk-mode-map "\\" 'talk-char)
      (define-key talk-mode-map "]" 'talk-char)
      (define-key talk-mode-map "^" 'talk-char)
      (define-key talk-mode-map "_" 'talk-char)
      (define-key talk-mode-map "`" 'talk-char)
      (define-key talk-mode-map "a" 'talk-char)
      (define-key talk-mode-map "b" 'talk-char)
      (define-key talk-mode-map "c" 'talk-char)
      (define-key talk-mode-map "d" 'talk-char)
      (define-key talk-mode-map "e" 'talk-char)
      (define-key talk-mode-map "f" 'talk-char)
      (define-key talk-mode-map "g" 'talk-char)
      (define-key talk-mode-map "h" 'talk-char)
      (define-key talk-mode-map "i" 'talk-char)
      (define-key talk-mode-map "j" 'talk-char)
      (define-key talk-mode-map "k" 'talk-char)
      (define-key talk-mode-map "l" 'talk-char)
      (define-key talk-mode-map "m" 'talk-char)
      (define-key talk-mode-map "n" 'talk-char)
      (define-key talk-mode-map "o" 'talk-char)
      (define-key talk-mode-map "p" 'talk-char)
      (define-key talk-mode-map "q" 'talk-char)
      (define-key talk-mode-map "r" 'talk-char)
      (define-key talk-mode-map "s" 'talk-char)
      (define-key talk-mode-map "t" 'talk-char)
      (define-key talk-mode-map "u" 'talk-char)
      (define-key talk-mode-map "v" 'talk-char)
      (define-key talk-mode-map "w" 'talk-char)
      (define-key talk-mode-map "x" 'talk-char)
      (define-key talk-mode-map "y" 'talk-char)
      (define-key talk-mode-map "z" 'talk-char)
      (define-key talk-mode-map "{" 'talk-char)
      (define-key talk-mode-map "|" 'talk-char)
      (define-key talk-mode-map "}" 'talk-char)
      (define-key talk-mode-map "~" 'talk-char)
      (define-key talk-mode-map "\C-m" 'talk-newline)
      (define-key talk-mode-map "\C-c\C-u" 'talk-kill)
      (define-key talk-mode-map "\C-c\C-w" 'talk-werase)
      (define-key talk-mode-map "\C-?" 'talk-erase)
      (define-key talk-mode-map "\C-c\C-c" 'talk-quit)))

;; The beginning of line markers are kept so that we know when a line
;; is totally empty.  We erase any line that becomes totally empty.
;; If the beginning of line marker is nil, then no line is open.  One
;; will be opened in talk-process-char when there is something to print.
;; These variables are local.

(defvar talk-my-bol-marker nil
  "Pointer to the beginning of my current line.")

(defvar talk-his-bol-marker nil
  "Pointer to the beginning of his current line.")

;; The current markers point to where the next character is going to be
;; inserted.  It is important that they point to point-max when there is
;; no line open.  These variables are local.

(defvar talk-my-current-marker nil
  "Where your characters appear.")

(defvar talk-his-current-marker nil
  "Where his characters appear.")

;; The names of the people talking.  talk-his-name is whatever argument
;; was given to talk, and talk-my-name is either "user" or "user@host".  The
;; "user@host" style is used if there is no "@" (or "!" or ":" or ".") in
;; talk-his-name.  These variables are local.

(defvar talk-my-name nil
  "Name to insert in front of your lines.")

(defvar talk-his-name nil
  "Name to insert in front of his lines.")

;; This variable is intended for customization.  Set it to true if you
;; don't want to display blank lines.  It is useful when people using
;; talk outside of emacs send zillions of blank lines in order to empty
;; their window.

(defvar talk-omit-blank-lines nil
  "*Non-nil means to insert blank lines too.")

;; This variable is also intended for customization.  God only knows
;; why anyone would want to change it, but just in case....
;; If it does not end with a space, talk-process-word-kill can delete it.

(defvar talk-arrow " -> "
  "*Thingy to separate names from text.  Must end with a space.")

;; Here is the main entry point.  Set up a buffer, making a new one if
;; necessary.  Switch to the buffer and start a process if none is running.
;; Go into talk mode and initialize the local variables that talk-mode made
;; (and cleared with kill-all-local-variables).  We use pipes (see
;; process-connection-type) instead of ptys so that talk will see
;; characters as soon as we send them.  (Yes, I know, I can set cbreak mode,
;; but why do thing the hard way?)

(defun talk (victum)
  "Talk with another user."
  (interactive "sTalk with: ")
  (let ((buffer (get-buffer-create (concat "*" victum "-talk*"))) proc status)
    (switch-to-buffer buffer)
    (setq proc (get-buffer-process buffer))
    (if proc (setq status (process-status proc)))
    (if (memq status '(run stop))
	nil
      (if proc (delete-process proc))
      (let ((process-connection-type nil))
	(setq proc (start-process "talk" buffer "talk" "-emacs" victum)))
      (set-process-filter proc 'talk-filter)
      (talk-mode)
      (setq talk-my-current-marker (point-max-marker))
      (setq talk-his-current-marker (point-max-marker))
      (setq talk-his-name victum)
      (if (string-match "@\\|!\\|:\\|\\." victum)
	  (setq talk-my-name (format "%s@%s" (user-login-name) (system-name)))
	(setq talk-my-name (user-login-name))))))

;; Talk mode is just like any other major mode...  Nothing exciting here...
;; We keep talk buffers read-only so that functions not defined here can
;; not change the contents.

(defun talk-mode ()
  (interactive)
  (kill-all-local-variables)
  (setq major-mode 'talk-mode)
  (setq mode-name "Talk")
  (setq mode-line-process '(": %s"))
  (set-syntax-table talk-mode-syntax-table)
  (use-local-map talk-mode-map)
  (setq buffer-read-only t)
  (make-local-variable 'talk-my-bol-marker)
  (make-local-variable 'talk-his-bol-marker)
  (make-local-variable 'talk-my-current-marker)
  (make-local-variable 'talk-his-current-marker)
  (make-local-variable 'talk-my-name)
  (make-local-variable 'talk-his-name)
  (run-hooks 'talk-mode-hook))

;; Talk-char gets called when a ordinary character is pushed.  It serves
;; the same purpose as self-insert-command, except that anything inserted
;; is also send to the talk process.  Point is set to talk-my-current-marker
;; before any insertion so that characters are inserted at the right
;; place even if point has been moved elsewhere (for instance, to view
;; previously transmitted text.)

(defun talk-char ()
  (interactive)
  (goto-char talk-my-current-marker)
  (talk-process-char last-command-char talk-my-name 'talk-my-bol-marker)
  (set-marker talk-my-current-marker (point))
  (send-string (get-buffer-process (current-buffer)) (char-to-string last-command-char)))

;; Talk-newline gets called when return is pushed.  Works just like talk-char
;; except that talk-process-newline is called instead of talk-process-char.

(defun talk-newline ()
  (interactive)
  (goto-char talk-my-current-marker)
  (talk-process-newline talk-my-name 'talk-my-bol-marker)
  (set-marker talk-my-current-marker (point))
  (send-string (get-buffer-process (current-buffer)) "\n"))

;; Talk-kill gets called when the line kill sequence (\C-c \C-u) is pushed.
;; It works just like talk-char except that talk-process-kill is called
;; instead of talk-process-char.

(defun talk-kill ()
  (interactive)
  (goto-char talk-my-current-marker)
  (talk-process-kill 'talk-my-bol-marker)
  (set-marker talk-my-current-marker (point))
  (send-string (get-buffer-process (current-buffer)) "\C-u"))

;; Talk-werase gets called when the word erase sequence (\C-c \C-w) is pushed.
;; It works just like talk-char except that talk-process-werase is called
;; instead of talk-process-char.

(defun talk-werase ()
  (interactive)
  (goto-char talk-my-current-marker)
  (talk-process-werase 'talk-my-bol-marker)
  (set-marker talk-my-current-marker (point))
  (send-string (get-buffer-process (current-buffer)) "\C-w"))

;; Talk-werase gets called when the character erase sequence (\C-c \C-w) is
;; pushed.  It works just like talk-char except that talk-process-werase is
;; called instead of talk-process-char.

(defun talk-erase ()
  (interactive)
  (goto-char talk-my-current-marker)
  (talk-process-erase 'talk-my-bol-marker)
  (set-marker talk-my-current-marker (point))
  (send-string (get-buffer-process (current-buffer)) "\C-?"))

;; Talk-quit is called when we indicate that we are finished (by pushing
;; \C-c \C-c).  It sends a signal to talk.  Talk will tell us [Connection
;; closed.  Exiting] and then die.

(defun talk-quit ()
  (interactive)
  (interrupt-process))

;; Talk filter is talk's filter (obviously).  We call talk-dispatch with
;; each character to dispatch the character to the proper talk-process-*
;; function.  These are the same talk-process-* functions that are called
;; to perform services on behalf of the local user.

(defun talk-filter (process output)
  (save-excursion
    (set-buffer (process-buffer process))
    (goto-char talk-his-current-marker)
    (mapcar 'talk-dispatch output)
    (set-marker talk-his-current-marker (point))))

;; Talk-dispatch is just a big switch statement.  Nothing exciting here.
;; Some control characters are used for special purposes.

(defun talk-dispatch (char)
  (cond
   ((equal char ?\001)
    (message "[Connection established]")
    (ding))
   ((equal char ?\002)
    (message "[Connection closed. Exiting]"))
   ((equal char ?\003)
    (message "[Waiting for your party to respond]"))
   ((equal char ?\004)
    (message "[Waiting to connect with caller]"))
   ((equal char ?\005)
    (message "[answer #0]"))
   ((equal char ?\006)
    (message "[Your party is not logged on]"))
   ((equal char ?\007)
    (message "[Target machine is too confused to talk to us]"))
   ((equal char ?\010)
    (message "[Target machine does not recognize us]"))
   ((equal char ?\013)
    (message "[Your party is refusing messages]"))
   ((equal char ?\014)
    (message "[Target machine can not handle remote talk]"))
   ((equal char ?\015)
    (message "[Target machine indicates protocol mismatch]"))
   ((equal char ?\016)
    (message "[Target machine indicates protocol botch (addr)]"))
   ((equal char ?\017)
    (message "[Target machine indicates protocol botch (ctl_addr)]"))
   ((equal char ?\020)
    (message "[Trying to connect to your party's talk daemon]"))
   ((equal char ?\020)
    (message "[No connection yet]"))
   ((equal char ?\022)
    (message "[Connection closing. Exiting]"))
   ((equal char ?\023)
    (message "[Ringing your party again]"))
   ((equal char ?\024)
    (message "[Checking for invitation on caller's machine]"))
   ((equal char ?\n)
    (talk-process-newline talk-his-name 'talk-his-bol-marker))
   ((equal char ?\C-u)
    (talk-process-kill 'talk-his-bol-marker))
   ((equal char ?\C-w)
    (talk-process-werase 'talk-his-bol-marker))
   ((equal char ?\C-?)
    (talk-process-erase 'talk-his-bol-marker))
   (t
    (talk-process-char char talk-his-name 'talk-his-bol-marker))))

;; Talk process char is called when the local user or remote user
;; pushes any character.  Talk-bol-marker is going to be either
;; 'talk-his-bol-marker or 'talk-my-bol-marker.  (We need to pass it
;; by name so we can change the proper variable (in the set statement)).
;; We perform our actions at point and return with point set to where
;; the next character should be inserted.

(defun talk-process-char (char talk-name talk-bol-marker)
  (let ((buffer-read-only nil))
    (if (null (eval talk-bol-marker))
	(progn
	  (insert-before-markers talk-name talk-arrow "\n")
	  (backward-char)
	  (set talk-bol-marker (point-marker))))
    (insert char)))

;; Talk process newline is called when the local user or remote user
;; pushes newline.  Talk-bol-marker is going to be either
;; 'talk-his-bol-marker or 'talk-my-bol-marker.  (We need to pass it
;; by name so we can change the proper variable (in the set statement)).
;; We perform our actions at point and return with point set to where
;; the next character should be inserted (i.e., point-max).

(defun talk-process-newline (talk-name talk-bol-marker)
  (let ((buffer-read-only nil))
    (if (and (null talk-omit-blank-lines) (null (eval talk-bol-marker)))
	  (insert-before-markers talk-name talk-arrow "\n\n"))
    (if (eval talk-bol-marker)
	(progn
	  (set-marker (eval talk-bol-marker) nil)
	  (set talk-bol-marker nil)
	  (insert "\n")
	  (goto-char (point-max))))))

;; Talk-process-kill is just like talk-process-newline except that we
;; erase a line instead of creating a new one.

(defun talk-process-kill (talk-bol-marker)
  (if (eval talk-bol-marker)
      (let ((buffer-read-only nil))
	(forward-char)
	(kill-line -1)
	(set-marker (eval talk-bol-marker) nil)
	(set talk-bol-marker nil)
	(goto-char (point-max)))))  

;; Talk-process-kill is just like talk-process-newline except that we
;; erase a line instead of creating a new one.

(defun talk-process-werase (talk-bol-marker)
  (if (eval talk-bol-marker)
      (let ((buffer-read-only nil))
	(backward-kill-word 1)
	(if (equal (marker-position (eval talk-bol-marker)) (point))
	    (talk-process-kill talk-bol-marker)))))

;; Talk-process-erase is just like talk-process-kill except that we
;; erase a line instead of creating a new one.

(defun talk-process-erase (talk-bol-marker)
  (if (eval talk-bol-marker)
      (let ((buffer-read-only nil))
	(delete-backward-char 1)
	(if (equal (marker-position (eval talk-bol-marker)) (point))
	    (talk-process-kill talk-bol-marker)))))
//E*O*F talk.el//

echo x - Makefile
cat > "Makefile" << '//E*O*F Makefile//'
#
# Copyright (c) 1987 Regents of the University of California.
# All rights reserved.
#
# Redistribution and use in source and binary forms are permitted
# provided that the above copyright notice and this paragraph are
# duplicated in all such forms and that any documentation,
# advertising materials, and other materials related to such
# distribution and use acknowledge that the software was developed
# by the University of California, Berkeley.  The name of the
# University may not be used to endorse or promote products derived
# from this software without specific prior written permission.
# THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
# WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
#
# Modified for use with emacs by Ray Moody (ray@maxwell.physics.purdue.edu)
#
#	@(#)Makefile	5.8 (Berkeley) 7/6/88
#
CFLAGS=	-O -DEMACS
LIBC=	/lib/libc.a
SRCS=	talk.c get_names.c display.c io.c ctl.c init_disp.c \
	msgs.c get_addrs.c ctl_transact.c invite.c look_up.c
OBJS=	talk.o get_names.o display.o io.o ctl.o init_disp.o \
	msgs.o get_addrs.o ctl_transact.o invite.o look_up.o

all: talk

talk:	${OBJS} ${LIBC}
	${CC} -o $@ ${CFLAGS} ${OBJS} -lcurses -ltermlib

clean: FRC
	rm -f ${OBJS} core talk

depend: FRC
	mkdep ${CFLAGS} ${SRCS}

install: FRC
	install -s -o bin -g bin -m 755 talk ${DESTDIR}/usr/ucb/talk

lint: FRC
	lint ${CFLAGS} ${SRCS}

tags: FRC
	ctags ${SRCS}

FRC:

# DO NOT DELETE THIS LINE -- mkdep uses it.
# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.

talk.o: talk.c talk.h /usr/include/curses.h /usr/include/stdio.h
talk.o: /usr/include/sgtty.h /usr/include/sys/ioctl.h
talk.o: /usr/include/sys/ttychars.h /usr/include/sys/ttydev.h
talk.o: /usr/include/utmp.h
get_names.o: get_names.c talk.h /usr/include/curses.h /usr/include/stdio.h
get_names.o: /usr/include/sgtty.h /usr/include/sys/ioctl.h
get_names.o: /usr/include/sys/ttychars.h /usr/include/sys/ttydev.h
get_names.o: /usr/include/utmp.h /usr/include/sys/param.h
get_names.o: /usr/include/sys/types.h /usr/include/signal.h
get_names.o: /usr/include/machine/trap.h /usr/include/machine/machparam.h
get_names.o: /usr/include/machine/endian.h /usr/include/protocols/talkd.h
get_names.o: /usr/include/sys/types.h /usr/include/sys/socket.h
get_names.o: /usr/include/pwd.h
display.o: display.c talk.h /usr/include/curses.h /usr/include/stdio.h
display.o: /usr/include/sgtty.h /usr/include/sys/ioctl.h
display.o: /usr/include/sys/ttychars.h /usr/include/sys/ttydev.h
display.o: /usr/include/utmp.h
io.o: io.c talk.h /usr/include/curses.h /usr/include/stdio.h
io.o: /usr/include/sgtty.h /usr/include/sys/ioctl.h /usr/include/sys/ttychars.h
io.o: /usr/include/sys/ttydev.h /usr/include/utmp.h /usr/include/stdio.h
io.o: /usr/include/errno.h /usr/include/sys/time.h /usr/include/time.h
ctl.o: ctl.c talk_ctl.h /usr/include/sys/types.h /usr/include/protocols/talkd.h
ctl.o: /usr/include/sys/types.h /usr/include/sys/socket.h
ctl.o: /usr/include/netinet/in.h talk.h /usr/include/curses.h
ctl.o: /usr/include/stdio.h /usr/include/sgtty.h /usr/include/sys/ioctl.h
ctl.o: /usr/include/sys/ttychars.h /usr/include/sys/ttydev.h
ctl.o: /usr/include/utmp.h /usr/include/errno.h
init_disp.o: init_disp.c talk.h /usr/include/curses.h /usr/include/stdio.h
init_disp.o: /usr/include/sgtty.h /usr/include/sys/ioctl.h
init_disp.o: /usr/include/sys/ttychars.h /usr/include/sys/ttydev.h
init_disp.o: /usr/include/utmp.h /usr/include/signal.h
init_disp.o: /usr/include/machine/trap.h
msgs.o: msgs.c /usr/include/signal.h /usr/include/machine/trap.h
msgs.o: /usr/include/stdio.h /usr/include/sys/time.h /usr/include/time.h talk.h
msgs.o: /usr/include/curses.h /usr/include/stdio.h /usr/include/sgtty.h
msgs.o: /usr/include/sys/ioctl.h /usr/include/sys/ttychars.h
msgs.o: /usr/include/sys/ttydev.h /usr/include/utmp.h
get_addrs.o: get_addrs.c talk_ctl.h /usr/include/sys/types.h
get_addrs.o: /usr/include/protocols/talkd.h /usr/include/sys/types.h
get_addrs.o: /usr/include/sys/socket.h /usr/include/netinet/in.h talk.h
get_addrs.o: /usr/include/curses.h /usr/include/stdio.h /usr/include/sgtty.h
get_addrs.o: /usr/include/sys/ioctl.h /usr/include/sys/ttychars.h
get_addrs.o: /usr/include/sys/ttydev.h /usr/include/utmp.h /usr/include/errno.h
get_addrs.o: /usr/include/netdb.h
ctl_transact.o: ctl_transact.c talk_ctl.h /usr/include/sys/types.h
ctl_transact.o: /usr/include/protocols/talkd.h /usr/include/sys/types.h
ctl_transact.o: /usr/include/sys/socket.h /usr/include/netinet/in.h talk.h
ctl_transact.o: /usr/include/curses.h /usr/include/stdio.h /usr/include/sgtty.h
ctl_transact.o: /usr/include/sys/ioctl.h /usr/include/sys/ttychars.h
ctl_transact.o: /usr/include/sys/ttydev.h /usr/include/utmp.h
ctl_transact.o: /usr/include/errno.h /usr/include/sys/time.h
ctl_transact.o: /usr/include/time.h
invite.o: invite.c talk_ctl.h /usr/include/sys/types.h
invite.o: /usr/include/protocols/talkd.h /usr/include/sys/types.h
invite.o: /usr/include/sys/socket.h /usr/include/netinet/in.h talk.h
invite.o: /usr/include/curses.h /usr/include/stdio.h /usr/include/sgtty.h
invite.o: /usr/include/sys/ioctl.h /usr/include/sys/ttychars.h
invite.o: /usr/include/sys/ttydev.h /usr/include/utmp.h /usr/include/errno.h
invite.o: /usr/include/sys/time.h /usr/include/time.h /usr/include/signal.h
invite.o: /usr/include/machine/trap.h /usr/include/setjmp.h
look_up.o: look_up.c talk_ctl.h /usr/include/sys/types.h
look_up.o: /usr/include/protocols/talkd.h /usr/include/sys/types.h
look_up.o: /usr/include/sys/socket.h /usr/include/netinet/in.h talk.h
look_up.o: /usr/include/curses.h /usr/include/stdio.h /usr/include/sgtty.h
look_up.o: /usr/include/sys/ioctl.h /usr/include/sys/ttychars.h
look_up.o: /usr/include/sys/ttydev.h /usr/include/utmp.h /usr/include/errno.h

# IF YOU PUT ANYTHING HERE IT WILL GO AWAY
//E*O*F Makefile//

echo x - ctl.c
cat > "ctl.c" << '//E*O*F ctl.c//'
/*
 * Copyright (c) 1983 Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms are permitted
 * provided that the above copyright notice and this paragraph are
 * duplicated in all such forms and that any documentation,
 * advertising materials, and other materials related to such
 * distribution and use acknowledge that the software was developed
 * by the University of California, Berkeley.  The name of the
 * University may not be used to endorse or promote products derived
 * from this software without specific prior written permission.
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

#ifndef lint
static char sccsid[] = "@(#)ctl.c	5.4 (Berkeley) 6/29/88";
#endif /* not lint */

/*
 * This file handles haggling with the various talk daemons to
 * get a socket to talk to. sockt is opened and connected in
 * the progress
 */

#include "talk_ctl.h"

struct	sockaddr_in daemon_addr = { AF_INET };
struct	sockaddr_in ctl_addr = { AF_INET };
struct	sockaddr_in my_addr = { AF_INET };

	/* inet addresses of the two machines */
struct	in_addr my_machine_addr;
struct	in_addr his_machine_addr;

u_short daemon_port;	/* port number of the talk daemon */

int	ctl_sockt;
int	sockt;
int	invitation_waiting = 0;

CTL_MSG msg;

open_sockt()
{
	int length;

	my_addr.sin_addr = my_machine_addr;
	my_addr.sin_port = 0;
	sockt = socket(AF_INET, SOCK_STREAM, 0);
	if (sockt <= 0)
		p_error("Bad socket");
	if (bind(sockt, &my_addr, sizeof(my_addr)) != 0)
		p_error("Binding local socket");
	length = sizeof(my_addr);
	if (getsockname(sockt, &my_addr, &length) == -1)
		p_error("Bad address for socket");
}

/* open the ctl socket */
open_ctl() 
{
	int length;

	ctl_addr.sin_port = 0;
	ctl_addr.sin_addr = my_machine_addr;
	ctl_sockt = socket(AF_INET, SOCK_DGRAM, 0);
	if (ctl_sockt <= 0)
		p_error("Bad socket");
	if (bind(ctl_sockt, &ctl_addr, sizeof(ctl_addr), 0) != 0)
		p_error("Couldn't bind to control socket");
	length = sizeof(ctl_addr);
	if (getsockname(ctl_sockt, &ctl_addr, &length) == -1)
		p_error("Bad address for ctl socket");
}

/* print_addr is a debug print routine */
print_addr(addr)
	struct sockaddr_in addr;
{
	int i;

	printf("addr = %x, port = %o, family = %o zero = ",
		addr.sin_addr, addr.sin_port, addr.sin_family);
	for (i = 0; i<8;i++)
	printf("%o ", (int)addr.sin_zero[i]);
	putchar('\n');
}
//E*O*F ctl.c//

echo x - ctl_transact.c
cat > "ctl_transact.c" << '//E*O*F ctl_transact.c//'
/*
 * Copyright (c) 1983 Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms are permitted
 * provided that the above copyright notice and this paragraph are
 * duplicated in all such forms and that any documentation,
 * advertising materials, and other materials related to such
 * distribution and use acknowledge that the software was developed
 * by the University of California, Berkeley.  The name of the
 * University may not be used to endorse or promote products derived
 * from this software without specific prior written permission.
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

#ifndef lint
static char sccsid[] = "@(#)ctl_transact.c	5.4 (Berkeley) 6/29/88";
#endif /* not lint */

#include "talk_ctl.h"
#include <sys/time.h>

#define CTL_WAIT 2	/* time to wait for a response, in seconds */

/*
 * SOCKDGRAM is unreliable, so we must repeat messages if we have
 * not recieved an acknowledgement within a reasonable amount
 * of time
 */
ctl_transact(target, msg, type, rp)
	struct in_addr target;
	CTL_MSG msg;
	int type;
	CTL_RESPONSE *rp;
{
	int read_mask, ctl_mask, nready, cc;
	struct timeval wait;

	msg.type = type;
	daemon_addr.sin_addr = target;
	daemon_addr.sin_port = daemon_port;
	ctl_mask = 1 << ctl_sockt;

	/*
	 * Keep sending the message until a response of
	 * the proper type is obtained.
	 */
	do {
		wait.tv_sec = CTL_WAIT;
		wait.tv_usec = 0;
		/* resend message until a response is obtained */
		do {
			cc = sendto(ctl_sockt, (char *)&msg, sizeof (msg), 0,
				&daemon_addr, sizeof (daemon_addr));
			if (cc != sizeof (msg)) {
				if (errno == EINTR)
					continue;
				p_error("Error on write to talk daemon");
			}
			read_mask = ctl_mask;
			nready = select(32, &read_mask, 0, 0, &wait);
			if (nready < 0) {
				if (errno == EINTR)
					continue;
				p_error("Error waiting for daemon response");
			}
		} while (nready == 0);
		/*
		 * Keep reading while there are queued messages 
		 * (this is not necessary, it just saves extra
		 * request/acknowledgements being sent)
		 */
		do {
			cc = recv(ctl_sockt, (char *)rp, sizeof (*rp), 0);
			if (cc < 0) {
				if (errno == EINTR)
					continue;
				p_error("Error on read from talk daemon");
			}
			read_mask = ctl_mask;
			/* an immediate poll */
			timerclear(&wait);
			nready = select(32, &read_mask, 0, 0, &wait);
		} while (nready > 0 && (rp->vers != TALK_VERSION ||
		    rp->type != type));
	} while (rp->vers != TALK_VERSION || rp->type != type);
	rp->id_num = ntohl(rp->id_num);
	rp->addr.sa_family = ntohs(rp->addr.sa_family);
}
//E*O*F ctl_transact.c//

echo x - display.c
cat > "display.c" << '//E*O*F display.c//'
/*
 * Copyright (c) 1983 Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms are permitted
 * provided that the above copyright notice and this paragraph are
 * duplicated in all such forms and that any documentation,
 * advertising materials, and other materials related to such
 * distribution and use acknowledge that the software was developed
 * by the University of California, Berkeley.  The name of the
 * University may not be used to endorse or promote products derived
 * from this software without specific prior written permission.
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
#ifdef	EMACS
 * Modified for use with emacs by Ray Moody (ray@maxwell.physics.purdue.edu).
#endif	EMACS
 */

#ifndef lint
static char sccsid[] = "@(#)display.c	5.3 (Berkeley) 6/29/88";
#endif /* not lint */

/*
 * The window 'manager', initializes curses and handles the actual
 * displaying of text
 */
#include "talk.h"

xwin_t	my_win;
xwin_t	his_win;
WINDOW	*line_win;

int	curses_initialized = 0;

#ifdef	EMACS
int	emacs = 0;
#endif	/* EMACS */

/*
 * max HAS to be a function, it is called with
 * a argument of the form --foo at least once.
 */
max(a,b)
	int a, b;
{

	return (a > b ? a : b);
}

/*
 * Display some text on somebody's window, processing some control
 * characters while we are at it.
 */
display(win, text, size)
	register xwin_t *win;
	register char *text;
	int size;
{
	register int i;
	char cch;

	for (i = 0; i < size; i++) {
		if (*text == '\n') {
			xscroll(win, 0);
			text++;
			continue;
		}
		/* erase character */
		if (*text == win->cerase) {
			wmove(win->x_win, win->x_line, max(--win->x_col, 0));
			getyx(win->x_win, win->x_line, win->x_col);
			waddch(win->x_win, ' ');
			wmove(win->x_win, win->x_line, win->x_col);
			getyx(win->x_win, win->x_line, win->x_col);
			text++;
			continue;
		}
		/*
		 * On word erase search backwards until we find
		 * the beginning of a word or the beginning of
		 * the line.
		 */
		if (*text == win->werase) {
			int endcol, xcol, i, c;

			endcol = win->x_col;
			xcol = endcol - 1;
			while (xcol >= 0) {
				c = readwin(win->x_win, win->x_line, xcol);
				if (c != ' ')
					break;
				xcol--;
			}
			while (xcol >= 0) {
				c = readwin(win->x_win, win->x_line, xcol);
				if (c == ' ')
					break;
				xcol--;
			}
			wmove(win->x_win, win->x_line, xcol + 1);
			for (i = xcol + 1; i < endcol; i++)
				waddch(win->x_win, ' ');
			wmove(win->x_win, win->x_line, xcol + 1);
			getyx(win->x_win, win->x_line, win->x_col);
			continue;
		}
		/* line kill */
		if (*text == win->kill) {
			wmove(win->x_win, win->x_line, 0);
			wclrtoeol(win->x_win);
			getyx(win->x_win, win->x_line, win->x_col);
			text++;
			continue;
		}
		if (*text == '\f') {
			if (win == &my_win)
				wrefresh(curscr);
			text++;
			continue;
		}
		if (win->x_col == COLS-1) {
			/* check for wraparound */
			xscroll(win, 0);
		}
		if (*text < ' ' && *text != '\t') {
			waddch(win->x_win, '^');
			getyx(win->x_win, win->x_line, win->x_col);
			if (win->x_col == COLS-1) /* check for wraparound */
				xscroll(win, 0);
			cch = (*text & 63) + 64;
			waddch(win->x_win, cch);
		} else
			waddch(win->x_win, *text);
		getyx(win->x_win, win->x_line, win->x_col);
		text++;
	}
	wrefresh(win->x_win);
}

/*
 * Read the character at the indicated position in win
 */
readwin(win, line, col)
	WINDOW *win;
{
	int oldline, oldcol;
	register int c;

	getyx(win, oldline, oldcol);
	wmove(win, line, col);
	c = winch(win);
	wmove(win, oldline, oldcol);
	return (c);
}

/*
 * Scroll a window, blanking out the line following the current line
 * so that the current position is obvious
 */
xscroll(win, flag)
	register xwin_t *win;
	int flag;
{

	if (flag == -1) {
		wmove(win->x_win, 0, 0);
		win->x_line = 0;
		win->x_col = 0;
		return;
	}
	win->x_line = (win->x_line + 1) % win->x_nlines;
	win->x_col = 0;
	wmove(win->x_win, win->x_line, win->x_col);
	wclrtoeol(win->x_win);
	wmove(win->x_win, (win->x_line + 1) % win->x_nlines, win->x_col);
	wclrtoeol(win->x_win);
	wmove(win->x_win, win->x_line, win->x_col);
}

#ifdef	EMACS
/*
 * Output routine for emacs.  Expand control characters int hat notation.
 * Replace word, character, and line kill characters with ^W, ^?, and ^U
 * (These characters are hardwired into talk.el).  Ignore /f.
 */
output(win, text, size)
	register xwin_t *win;
	register char *text;
	int size;
{
	register int i;
	char cch;

	for (i = 0; i < size; i++) {
		/* erase character */
		if (*text == win->cerase) {
			printf("\177");
			text++;
			continue;
		}
		/* word erase character */
		if (*text == win->werase) {
			printf("\027");
			text++;
			continue;
		}
		/* line kill */
		if (*text == win->kill) {
			printf("\025");
			text++;
			continue;
		}
		if (*text == '\f') {
			text++;
			continue;
		}
		if (*text < ' ' && *text != '\t' && *text != '\n') {
			printf("^%c", (*text & 63) + 64);
		} else
			printf("%c", *text);
		text++;
	}
	fflush(stdout);
}
#endif	/* EMACS */
//E*O*F display.c//

echo x - get_addrs.c
cat > "get_addrs.c" << '//E*O*F get_addrs.c//'
/*
 * Copyright (c) 1983 Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms are permitted
 * provided that the above copyright notice and this paragraph are
 * duplicated in all such forms and that any documentation,
 * advertising materials, and other materials related to such
 * distribution and use acknowledge that the software was developed
 * by the University of California, Berkeley.  The name of the
 * University may not be used to endorse or promote products derived
 * from this software without specific prior written permission.
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

#ifndef lint
static char sccsid[] = "@(#)get_addrs.c	5.4 (Berkeley) 6/29/88";
#endif /* not lint */

#include "talk_ctl.h"
#include <netdb.h>

get_addrs(my_machine_name, his_machine_name)
	char *my_machine_name, *his_machine_name;
{
	struct hostent *hp;
	struct servent *sp;

	msg.pid = htonl(getpid());
	/* look up the address of the local host */
	hp = gethostbyname(my_machine_name);
	if (hp == (struct hostent *) 0) {
		fprintf(stderr,
		    "talk: %s: Can't figure out network address.\n",
		    my_machine_name);
		exit(-1);
	}
	bcopy(hp->h_addr, (char *)&my_machine_addr, hp->h_length);
	/*
	 * If the callee is on-machine, just copy the
	 * network address, otherwise do a lookup...
	 */
	if (strcmp(his_machine_name, my_machine_name)) {
		hp = gethostbyname(his_machine_name);
		if (hp == (struct hostent *) 0 ) {
			fprintf(stderr,
			    "talk: %s: Can't figure out network address.\n",
			    his_machine_name);
			exit(-1);
		}
		bcopy(hp->h_addr, (char *) &his_machine_addr, hp->h_length);
	} else
		his_machine_addr = my_machine_addr;
	/* find the server's port */
	sp = getservbyname("ntalk", "udp");
	if (sp == 0) {
		fprintf(stderr, "talk: %s/%s: service is not registered.\n",
		     "ntalk", "udp");
		exit(-1);
	}
	daemon_port = sp->s_port;
}
//E*O*F get_addrs.c//

echo x - get_names.c
cat > "get_names.c" << '//E*O*F get_names.c//'
/*
 * Copyright (c) 1983 Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms are permitted
 * provided that the above copyright notice and this paragraph are
 * duplicated in all such forms and that any documentation,
 * advertising materials, and other materials related to such
 * distribution and use acknowledge that the software was developed
 * by the University of California, Berkeley.  The name of the
 * University may not be used to endorse or promote products derived
 * from this software without specific prior written permission.
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
#ifdef	EMACS
 * Modified for use with emacs by Ray Moody (ray@maxwell.physics.purdue.edu).
#endif	EMACS
 */

#ifndef lint
static char sccsid[] = "@(#)get_names.c	5.5 (Berkeley) 6/29/88";
#endif /* not lint */

#include "talk.h"
#include <sys/param.h>
#include <protocols/talkd.h>
#include <pwd.h>

char	*getlogin();
char	*ttyname();
char	*rindex();
extern	CTL_MSG msg;

/*
 * Determine the local and remote user, tty, and machines
 */
get_names(argc, argv)
	int argc;
	char *argv[];
{
	char hostname[MAXHOSTNAMELEN];
	char *his_name, *my_name;
	char *my_machine_name, *his_machine_name;
	char *my_tty, *his_tty;
	register char *cp;

	if (argc < 2 ) {
		printf("Usage: talk user [ttyname]\n");
		exit(-1);
	}

#ifdef	EMACS
	/*
	 * Emacs *always* uses a pipe.
	 */
	if (! emacs && !isatty(0)) {
#else	/* not EMACS */
	if (!isatty(0)) {
#endif	/* not EMACS */
		printf("Standard input must be a tty, not a pipe or a file\n");
		exit(-1);
	}
	if ((my_name = getlogin()) == NULL) {
		struct passwd *pw;

		if ((pw = getpwuid(getuid())) == NULL) {
			printf("You don't exist. Go away.\n");
			exit(-1);
		}
		my_name = pw->pw_name;
	}
	gethostname(hostname, sizeof (hostname));
	my_machine_name = hostname;
	/* check for, and strip out, the machine name of the target */
	for (cp = argv[1]; *cp && !any(*cp, "@:!."); cp++)
		;
	if (*cp == '\0') {
		/* this is a local to local talk */
		his_name = argv[1];
		his_machine_name = my_machine_name;
	} else {
		if (*cp++ == '@') {
			/* user@host */
			his_name = argv[1];
			his_machine_name = cp;
		} else {
			/* host.user or host!user or host:user */
			his_name = cp;
			his_machine_name = argv[1];
		}
		*--cp = '\0';
	}
	if (argc > 2)
		his_tty = argv[2];	/* tty name is arg 2 */
	else
		his_tty = "";
	get_addrs(my_machine_name, his_machine_name);
	/*
	 * Initialize the message template.
	 */
	msg.vers = TALK_VERSION;
	msg.addr.sa_family = htons(AF_INET);
	msg.ctl_addr.sa_family = htons(AF_INET);
	msg.id_num = htonl(0);
	strncpy(msg.l_name, my_name, NAME_SIZE);
	msg.l_name[NAME_SIZE - 1] = '\0';
	strncpy(msg.r_name, his_name, NAME_SIZE);
	msg.r_name[NAME_SIZE - 1] = '\0';
	strncpy(msg.r_tty, his_tty, TTY_SIZE);
	msg.r_tty[TTY_SIZE - 1] = '\0';
}

static
any(c, cp)
	register char c, *cp;
{

	while (*cp)
		if (c == *cp++)
			return (1);
	return (0);
}
//E*O*F get_names.c//

echo x - init_disp.c
cat > "init_disp.c" << '//E*O*F init_disp.c//'
/*
 * Copyright (c) 1983 Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms are permitted
 * provided that the above copyright notice and this paragraph are
 * duplicated in all such forms and that any documentation,
 * advertising materials, and other materials related to such
 * distribution and use acknowledge that the software was developed
 * by the University of California, Berkeley.  The name of the
 * University may not be used to endorse or promote products derived
 * from this software without specific prior written permission.
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
#ifdef	EMACS
 * Modified for use with emacs by Ray Moody (ray@maxwell.physics.purdue.edu).
#endif	EMACS
 */

#ifndef lint
static char sccsid[] = "@(#)init_disp.c	5.3 (Berkeley) 6/29/88";
#endif /* not lint */

/*
 * Initialization code for the display package,
 * as well as the signal handling routines.
 */

#include "talk.h"
#include <signal.h>

/* 
 * Set up curses, catch the appropriate signals,
 * and build the various windows.
 */
init_display()
{
	void sig_sent();
	struct sigvec sigv;

#ifdef	EMACS
	if (! emacs) {
		initscr();
	}
#else	/* not EMACS */
	initscr();
#endif	/* not EMACS */

	(void) sigvec(SIGTSTP, (struct sigvec *)0, &sigv);
	sigv.sv_mask |= sigmask(SIGALRM);
	(void) sigvec(SIGTSTP, &sigv, (struct sigvec *)0);

#ifdef	EMACS
	if (! emacs) {
		curses_initialized = 1;
		clear();
		refresh();
		noecho();
		crmode();
	}
#else	/* not EMACS */
	curses_initialized = 1;
	clear();
	refresh();
	noecho();
	crmode();
#endif	/* not EMACS */

	signal(SIGINT, sig_sent);
	signal(SIGPIPE, sig_sent);
	/* curses takes care of ^Z */

#ifdef	EMACS
	if (! emacs) {
		my_win.x_nlines = LINES / 2;
		my_win.x_ncols = COLS;
		my_win.x_win = newwin(my_win.x_nlines, my_win.x_ncols, 0, 0);
		scrollok(my_win.x_win, FALSE);
		wclear(my_win.x_win);

		his_win.x_nlines = LINES / 2 - 1;
		his_win.x_ncols = COLS;
		his_win.x_win = newwin(his_win.x_nlines, his_win.x_ncols,
		    my_win.x_nlines+1, 0);
		scrollok(his_win.x_win, FALSE);
		wclear(his_win.x_win);

		line_win = newwin(1, COLS, my_win.x_nlines, 0);
		box(line_win, '-', '-');
		wrefresh(line_win);
	}
#else	/* not EMACS */
	my_win.x_nlines = LINES / 2;
	my_win.x_ncols = COLS;
	my_win.x_win = newwin(my_win.x_nlines, my_win.x_ncols, 0, 0);
	scrollok(my_win.x_win, FALSE);
	wclear(my_win.x_win);

	his_win.x_nlines = LINES / 2 - 1;
	his_win.x_ncols = COLS;
	his_win.x_win = newwin(his_win.x_nlines, his_win.x_ncols,
	    my_win.x_nlines+1, 0);
	scrollok(his_win.x_win, FALSE);
	wclear(his_win.x_win);

	line_win = newwin(1, COLS, my_win.x_nlines, 0);
	box(line_win, '-', '-');
	wrefresh(line_win);
#endif	/* not EMACS */

	/* let them know we are working on it */

#ifdef	EMACS
	if (emacs) {
		current_state = "\020";
	} else {
		current_state = "No connection yet";
	}
#else	/* not EMACS */
	current_state = "No connection yet";
#endif	/* not EMACS */
}

/*
 * Trade edit characters with the other talk. By agreement
 * the first three characters each talk transmits after
 * connection are the three edit characters.
 */
set_edit_chars()
{
	char buf[3];
	int cc;
	struct sgttyb tty;
	struct ltchars ltc;
	
#ifdef	EMACS
	if (emacs) {
		my_win.cerase = '\177';	/* \C-? (hardwired into talk.el) */
		my_win.kill = '\025';   /* \C-w (hardwired into talk.el) */
		my_win.werase = '\027';	/* \C-u (hardwired into talk.el) */
	} else {
		ioctl(0, TIOCGETP, &tty);
		ioctl(0, TIOCGLTC, (struct sgttyb *)&ltc);
		my_win.cerase = tty.sg_erase;
		my_win.kill = tty.sg_kill;
		if (ltc.t_werasc == (char) -1)
			my_win.werase = '\027';	 /* control W */
		else
			my_win.werase = ltc.t_werasc;
	}
#else	/* not EMACS */
	ioctl(0, TIOCGETP, &tty);
	ioctl(0, TIOCGLTC, (struct sgttyb *)&ltc);
	my_win.cerase = tty.sg_erase;
	my_win.kill = tty.sg_kill;
	if (ltc.t_werasc == (char) -1)
		my_win.werase = '\027';	 /* control W */
	else
		my_win.werase = ltc.t_werasc;
#endif	/* not EMACS */

	buf[0] = my_win.cerase;
	buf[1] = my_win.kill;
	buf[2] = my_win.werase;
	cc = write(sockt, buf, sizeof(buf));
	if (cc != sizeof(buf) )
		p_error("Lost the connection");
	cc = read(sockt, buf, sizeof(buf));
	if (cc != sizeof(buf) )
		p_error("Lost the connection");
	his_win.cerase = buf[0];
	his_win.kill = buf[1];
	his_win.werase = buf[2];
}

void
sig_sent()
{

#ifdef	EMACS
	if (emacs) {
		message("\022");
	} else {	
		message("Connection closing. Exiting");
	}
#else	/* not EMACS */
	message("Connection closing. Exiting");
#endif	/* not EMACS */

	quit();
}

/*
 * All done talking...hang up the phone and reset terminal thingy's
 */
quit()
{

	if (curses_initialized) {
		wmove(his_win.x_win, his_win.x_nlines-1, 0);
		wclrtoeol(his_win.x_win);
		wrefresh(his_win.x_win);
		endwin();
	}
	if (invitation_waiting)
		send_delete();
	exit(0);
}
//E*O*F init_disp.c//

echo x - invite.c
cat > "invite.c" << '//E*O*F invite.c//'
/*
 * Copyright (c) 1983 Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms are permitted
 * provided that the above copyright notice and this paragraph are
 * duplicated in all such forms and that any documentation,
 * advertising materials, and other materials related to such
 * distribution and use acknowledge that the software was developed
 * by the University of California, Berkeley.  The name of the
 * University may not be used to endorse or promote products derived
 * from this software without specific prior written permission.
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
#ifdef	EMACS
 * Modified for use with emacs by Ray Moody (ray@maxwell.physics.purdue.edu).
#endif	EMACS
 */

#ifndef lint
static char sccsid[] = "@(#)invite.c	5.5 (Berkeley) 6/29/88";
#endif /* not lint */

#include "talk_ctl.h"
#include <sys/time.h>
#include <signal.h>
#include <setjmp.h>

/*
 * There wasn't an invitation waiting, so send a request containing
 * our sockt address to the remote talk daemon so it can invite
 * him 
 */

/*
 * The msg.id's for the invitations
 * on the local and remote machines.
 * These are used to delete the 
 * invitations.
 */
int	local_id, remote_id;
void	re_invite();
jmp_buf invitebuf;

invite_remote()
{
	int nfd, read_mask, template, new_sockt;
	struct itimerval itimer;
	CTL_RESPONSE response;

	itimer.it_value.tv_sec = RING_WAIT;
	itimer.it_value.tv_usec = 0;
	itimer.it_interval = itimer.it_value;
	if (listen(sockt, 5) != 0)
		p_error("Error on attempt to listen for caller");
	msg.addr = *(struct sockaddr *)&my_addr;
	msg.addr.sa_family = htons(msg.addr.sa_family);
	msg.id_num = htonl(-1);		/* an impossible id_num */
	invitation_waiting = 1;
	announce_invite();
	/*
	 * Shut off the automatic messages for a while,
	 * so we can use the interupt timer to resend the invitation
	 */
	end_msgs();
	setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0);
#ifdef	EMACS
	if (emacs) {
		message("\003");
	} else {
		message("Waiting for your party to respond");
	}
#else	/* not EMACS */
	message("Waiting for your party to respond");
#endif	/* not EMACS */

	signal(SIGALRM, re_invite);
	(void) setjmp(invitebuf);
	while ((new_sockt = accept(sockt, 0, 0)) < 0) {
		if (errno == EINTR)
			continue;
		p_error("Unable to connect with your party");
	}
	close(sockt);
	sockt = new_sockt;

	/*
	 * Have the daemons delete the invitations now that we
	 * have connected.
	 */
#ifdef	EMACS
	if (emacs) {
		current_state = "\003";
	} else {
		current_state = "Waiting for your party to respond";
	}
#else	/* not EMACS */
	current_state = "Waiting for your party to respond";
#endif	/* not EMACS */

	start_msgs();

	msg.id_num = htonl(local_id);
	ctl_transact(my_machine_addr, msg, DELETE, &response);
	msg.id_num = htonl(remote_id);
	ctl_transact(his_machine_addr, msg, DELETE, &response);
	invitation_waiting = 0;
}

/*
 * Routine called on interupt to re-invite the callee
 */
void
re_invite()
{

#ifdef	EMACS
	if (emacs) {
		message("\023");
	} else {
		message("Ringing your party again");
	}
#else	/* not EMACS */
	message("Ringing your party again");
#endif	/* not EMACS */
	current_line++;
	/* force a re-announce */
	msg.id_num = htonl(remote_id + 1);
	announce_invite();
	longjmp(invitebuf, 1);
}

static	char *answers[] = {
	"answer #0",					/* SUCCESS */
	"Your party is not logged on",			/* NOT_HERE */
	"Target machine is too confused to talk to us",	/* FAILED */
	"Target machine does not recognize us",		/* MACHINE_UNKNOWN */
	"Your party is refusing messages",		/* PERMISSION_REFUSED */
	"Target machine can not handle remote talk",	/* UNKNOWN_REQUEST */
	"Target machine indicates protocol mismatch",	/* BADVERSION */
	"Target machine indicates protocol botch (addr)",/* BADADDR */
	"Target machine indicates protocol botch (ctl_addr)",/* BADCTLADDR */
};
#define	NANSWERS	(sizeof (answers) / sizeof (answers[0]))

#ifdef	EMACS
static char *answer_codes[] = {
	"\005",						/* SUCCESS */
	"\006",						/* NOT_HERE */
	"\007",						/* FAILED */
	"\010",						/* MACHINE_UNKNOWN */
	"\013",						/* PERMISSION_REFUSED */
	"\014",						/* UNKNOWN_REQUEST */
	"\015",						/* BADVERSION */
	"\016",						/* BADADDR */
	"\017",						/* BADCTLADDR */
};
#endif	EMACS

/*
 * Transmit the invitation and process the response
 */
announce_invite()
{
	CTL_RESPONSE response;

#ifdef	EMACS
	if (emacs) {
		current_state = "\020";
	} else {
		current_state = "Trying to connect to your party's talk daemon";
	}
#else	/* not EMACS */
	current_state = "Trying to connect to your party's talk daemon";
#endif	/* not EMACS */

	ctl_transact(his_machine_addr, msg, ANNOUNCE, &response);
	remote_id = response.id_num;
	if (response.answer != SUCCESS) {
		if (response.answer < NANSWERS)

#ifdef	EMACS
			if (emacs) {
				message(answer_codes[response.answer]);
			} else {
				message(answers[response.answer]);
			}
#else	/* not EMACS */
			message(answers[response.answer]);
#endif	/* not EMACS */
		
		quit();
	}
	/* leave the actual invitation on my talk daemon */
	ctl_transact(my_machine_addr, msg, LEAVE_INVITE, &response);
	local_id = response.id_num;
}

/*
 * Tell the daemon to remove your invitation
 */
send_delete()
{

	msg.type = DELETE;
	/*
	 * This is just a extra clean up, so just send it
	 * and don't wait for an answer
	 */
	msg.id_num = htonl(remote_id);
	daemon_addr.sin_addr = his_machine_addr;
	if (sendto(ctl_sockt, &msg, sizeof (msg), 0, &daemon_addr,
	    sizeof (daemon_addr)) != sizeof(msg))
		perror("send_delete (remote)");
	msg.id_num = htonl(local_id);
	daemon_addr.sin_addr = my_machine_addr;
	if (sendto(ctl_sockt, &msg, sizeof (msg), 0, &daemon_addr,
	    sizeof (daemon_addr)) != sizeof (msg))
		perror("send_delete (local)");
}
//E*O*F invite.c//

echo x - io.c
cat > "io.c" << '//E*O*F io.c//'
/*
 * Copyright (c) 1983 Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms are permitted
 * provided that the above copyright notice and this paragraph are
 * duplicated in all such forms and that any documentation,
 * advertising materials, and other materials related to such
 * distribution and use acknowledge that the software was developed
 * by the University of California, Berkeley.  The name of the
 * University may not be used to endorse or promote products derived
 * from this software without specific prior written permission.
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
#ifdef	EMACS
 * Modified for use with emacs by Ray Moody (ray@maxwell.physics.purdue.edu).
#endif	EMACS
 */

#ifndef lint
static char sccsid[] = "@(#)io.c	5.3 (Berkeley) 6/29/88";
#endif /* not lint */

/*
 * This file contains the I/O handling and the exchange of 
 * edit characters. This connection itself is established in
 * ctl.c
 */

#include "talk.h"
#include <stdio.h>
#include <errno.h>
#include <sys/time.h>

#define A_LONG_TIME 10000000
#define STDIN_MASK (1<<fileno(stdin))	/* the bit mask for standard
					   input */
extern int errno;

/*
 * The routine to do the actual talking
 */
talk()
{
	register int read_template, sockt_mask;
	int read_set, nb;
	char buf[BUFSIZ];
	struct timeval wait;

#ifdef	EMACS
	if (emacs) {
		message("\001");
	} else {
		message("Connection established\007\007\007");
	}
#else	/* not EMACS */
	message("Connection established\007\007\007");
#endif	/* not EMACS */

	current_line = 0;
	sockt_mask = (1<<sockt);

	/*
	 * Wait on both the other process (sockt_mask) and 
	 * standard input ( STDIN_MASK )
	 */
	read_template = sockt_mask | STDIN_MASK;
	forever {
		read_set = read_template;
		wait.tv_sec = A_LONG_TIME;
		wait.tv_usec = 0;
		nb = select(32, &read_set, 0, 0, &wait);
		if (nb <= 0) {
			if (errno == EINTR) {
				read_set = read_template;
				continue;
			}
			/* panic, we don't know what happened */
			p_error("Unexpected error from select");
			quit();
		}
		if (read_set & sockt_mask) { 
			/* There is data on sockt */
			nb = read(sockt, buf, sizeof buf);
			if (nb <= 0) {
#ifdef	EMACS
				if (emacs) {
					message("\002");
				} else {
					message("Connection closed. Exiting");
				}
#else	/* not EMACS */
				message("Connection closed. Exiting");
#endif	/* not EMACS */
				quit();
			}
#ifdef	EMACS
			if (emacs) {
				/*
				 * Output is a special function defined
				 * only if you compile with -DEMACS.
				 * It translates the characters in buf
				 * into stuff emacs can handle and
				 * sends it to stdout (and flushes stdout).
				 */
				output(&his_win, buf, nb);
			} else {
				display(&his_win, buf, nb);
			}
#else	/* not EMACS */
			display(&his_win, buf, nb);
#endif	/* not EMACS */
		}
		if (read_set & STDIN_MASK) {
			/*
			 * We can't make the tty non_blocking, because
			 * curses's output routines would screw up
			 */
			ioctl(0, FIONREAD, (struct sgttyb *) &nb);
			nb = read(0, buf, nb);
#ifdef	EMACS
			if (! emacs) {
				display(&my_win, buf, nb);
			}
#else	/* not EMACS */
			display(&my_win, buf, nb);
#endif	/* not EMACS */
			/* might lose data here because sockt is non-blocking */
			write(sockt, buf, nb);
		}
	}
}

extern	int errno;
extern	int sys_nerr;
extern	char *sys_errlist[];

/*
 * p_error prints the system error message on the standard location
 * on the screen and then exits. (i.e. a curses version of perror)
 */
p_error(string) 
	char *string;
{
	char *sys;

	sys = "Unknown error";
	if (errno < sys_nerr)
		sys = sys_errlist[errno];
#ifdef	EMACS
	if (emacs) {
		printf("[%s: %s (%d)]\n", string, sys, errno);
	} else {
		wmove(my_win.x_win, current_line%my_win.x_nlines, 0);
		wprintw(my_win.x_win, "[%s : %s (%d)]\n", string, sys, errno);
		wrefresh(my_win.x_win);
		move(LINES-1, 0);
		refresh();
	}
#else	/* not EMACS */
	wmove(my_win.x_win, current_line%my_win.x_nlines, 0);
	wprintw(my_win.x_win, "[%s : %s (%d)]\n", string, sys, errno);
	wrefresh(my_win.x_win);
	move(LINES-1, 0);
	refresh();
#endif	/* not EMACS */
	quit();
}

/*
 * Display string in the standard location
 */
message(string)
	char *string;
{

#ifdef	EMACS
	/*
	 * Emacs messages are single character commands.  We use almost
	 * all of the available control characters, except tab and newline,
	 * which may appear in input.  We reserve ^U, ^W, and ^? for erasing
	 */
	if (emacs) {
		printf("%s", string);
		fflush(stdout);
	} else {
		wmove(my_win.x_win, current_line%my_win.x_nlines, 0);
		wprintw(my_win.x_win, "[%s]\n", string);
		wrefresh(my_win.x_win);
	}
#else	/* not EMACS */
	wmove(my_win.x_win, current_line%my_win.x_nlines, 0);
	wprintw(my_win.x_win, "[%s]\n", string);
	wrefresh(my_win.x_win);
#endif	/* not EMACS */
}
//E*O*F io.c//

echo x - look_up.c
cat > "look_up.c" << '//E*O*F look_up.c//'
/*
 * Copyright (c) 1983 Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms are permitted
 * provided that the above copyright notice and this paragraph are
 * duplicated in all such forms and that any documentation,
 * advertising materials, and other materials related to such
 * distribution and use acknowledge that the software was developed
 * by the University of California, Berkeley.  The name of the
 * University may not be used to endorse or promote products derived
 * from this software without specific prior written permission.
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
#ifdef	EMACS
 * Modified for use with emacs by Ray Moody (ray@maxwell.physics.purdue.edu).
#endif	EMACS
 */

#ifndef lint
static char sccsid[] = "@(#)look_up.c	5.4 (Berkeley) 6/29/88";
#endif /* not lint */

#include "talk_ctl.h"

/*
 * See if the local daemon has an invitation for us.
 */
check_local()
{
	CTL_RESPONSE response;
	register CTL_RESPONSE *rp = &response;

	/* the rest of msg was set up in get_names */
	msg.ctl_addr = *(struct sockaddr *)&ctl_addr;
	msg.ctl_addr.sa_family = htons(msg.ctl_addr.sa_family);
	/* must be initiating a talk */
	if (!look_for_invite(rp))
		return (0);
	/*
	 * There was an invitation waiting for us, 
	 * so connect with the other (hopefully waiting) party 
	 */
#ifdef	EMACS
	if (emacs) {
		current_state = "\004";
	} else {
		current_state = "Waiting to connect with caller";
	}
#else	/* not EMACS */
	current_state = "Waiting to connect with caller";
#endif	/* not EMACS */

	do {
		if (rp->addr.sa_family != AF_INET)
			p_error("Response uses invalid network address");
		errno = 0;
		if (connect(sockt, &rp->addr, sizeof (rp->addr)) != -1)
			return (1);
	} while (errno == EINTR);
	if (errno == ECONNREFUSED) {
		/*
		 * The caller gave up, but his invitation somehow
		 * was not cleared. Clear it and initiate an 
		 * invitation. (We know there are no newer invitations,
		 * the talkd works LIFO.)
		 */
		ctl_transact(his_machine_addr, msg, DELETE, rp);
		close(sockt);
		open_sockt();
		return (0);
	}
	p_error("Unable to connect with initiator");
	/*NOTREACHED*/
}

/*
 * Look for an invitation on 'machine'
 */
look_for_invite(rp)
	CTL_RESPONSE *rp;
{
	struct in_addr machine_addr;

#ifdef	EMACS
	if (emacs) {
		current_state = "\024";
	} else {
		current_state = "Checking for invitation on caller's machine";
	}
#else	/* not EMACS */
	current_state = "Checking for invitation on caller's machine";
#endif	/* not EMACS */

	ctl_transact(his_machine_addr, msg, LOOK_UP, rp);
	/* the switch is for later options, such as multiple invitations */
	switch (rp->answer) {

	case SUCCESS:
		msg.id_num = htonl(rp->id_num);
		return (1);

	default:
		/* there wasn't an invitation waiting for us */
		return (0);
	}
}
//E*O*F look_up.c//

echo x - msgs.c
cat > "msgs.c" << '//E*O*F msgs.c//'
/*
 * Copyright (c) 1983 Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms are permitted
 * provided that the above copyright notice and this paragraph are
 * duplicated in all such forms and that any documentation,
 * advertising materials, and other materials related to such
 * distribution and use acknowledge that the software was developed
 * by the University of California, Berkeley.  The name of the
 * University may not be used to endorse or promote products derived
 * from this software without specific prior written permission.
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

#ifndef lint
static char sccsid[] = "@(#)msgs.c	5.4 (Berkeley) 6/29/88";
#endif /* not lint */

/* 
 * A package to display what is happening every MSG_INTERVAL seconds
 * if we are slow connecting.
 */

#include <signal.h>
#include <stdio.h>
#include <sys/time.h>
#include "talk.h"

#define MSG_INTERVAL 4

char	*current_state;
int	current_line = 0;

disp_msg()
{

	message(current_state);
}

start_msgs()
{
	struct itimerval itimer;

	message(current_state);
	signal(SIGALRM, disp_msg);
	itimer.it_value.tv_sec = itimer.it_interval.tv_sec = MSG_INTERVAL;
	itimer.it_value.tv_usec = itimer.it_interval.tv_usec = 0;
	setitimer(ITIMER_REAL, &itimer, (struct timerval *)0);
}

end_msgs()
{
	struct itimerval itimer;

	timerclear(&itimer.it_value);
	timerclear(&itimer.it_interval);
	setitimer(ITIMER_REAL, &itimer, (struct timerval *)0);
	signal(SIGALRM, SIG_DFL);
}
//E*O*F msgs.c//

echo x - talk.c
cat > "talk.c" << '//E*O*F talk.c//'
/*
 * Copyright (c) 1983 Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms are permitted
 * provided that the above copyright notice and this paragraph are
 * duplicated in all such forms and that any documentation,
 * advertising materials, and other materials related to such
 * distribution and use acknowledge that the software was developed
 * by the University of California, Berkeley.  The name of the
 * University may not be used to endorse or promote products derived
 * from this software without specific prior written permission.
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

#ifndef lint
char copyright[] =
"@(#) Copyright (c) 1983 Regents of the University of California.\n\
 All rights reserved.\n";
#endif /* not lint */

#ifndef lint
static char sccsid[] = "@(#)talk.c	5.4 (Berkeley) 6/29/88";
#endif /* not lint */

#include "talk.h"

/*
 * talk:	A visual form of write. Using sockets, a two way 
 *		connection is set up between the two people talking. 
 *		With the aid of curses, the screen is split into two 
 *		windows, and each users text is added to the window,
 *		one character at a time...
 *
 *		Written by Kipp Hickman
 *		
 *		Modified to run under 4.1a by Clem Cole and Peter Moore
 *		Modified to run between hosts by Peter Moore, 8/19/82
 *		Modified to run under 4.1c by Peter Moore 3/17/83
 */

main(argc, argv)
	int argc;
	char *argv[];
{

#ifdef	EMACS
	if (argc > 1 && strcmp(argv[1], "-emacs") == 0) {
		emacs = 1;
		argv++;
		argc--;
	}
#endif	/* EMACS */

	get_names(argc, argv);
	init_display();
	open_ctl();
	open_sockt();
	start_msgs();
	if (!check_local())
		invite_remote();
	end_msgs();
	set_edit_chars();
	talk();
}
//E*O*F talk.c//

echo x - talk.h
cat > "talk.h" << '//E*O*F talk.h//'
/*
 * Copyright (c) 1983 Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms are permitted
 * provided that the above copyright notice and this paragraph are
 * duplicated in all such forms and that any documentation,
 * advertising materials, and other materials related to such
 * distribution and use acknowledge that the software was developed
 * by the University of California, Berkeley.  The name of the
 * University may not be used to endorse or promote products derived
 * from this software without specific prior written permission.
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
#ifdef	EMACS
 * Modified for use with emacs by Ray Moody (ray@maxwell.physics.purdue.edu)
#endif	EMACS
 *	@(#)talk.h	5.4 (Berkeley) 6/29/88
 */

#include <curses.h>
#include <utmp.h>

#define forever		for(;;)

int	quit();

#ifdef	EMACS
extern	int emacs;
#endif	/* EMACS */

extern	int sockt;
extern	int curses_initialized;
extern	int invitation_waiting;

extern	char *current_state;
extern	int current_line;

typedef struct xwin {
	WINDOW	*x_win;
	int	x_nlines;
	int	x_ncols;
	int	x_line;
	int	x_col;
	char	kill;
	char	cerase;
	char	werase;
} xwin_t;

extern	xwin_t my_win;
extern	xwin_t his_win;
extern	WINDOW *line_win;
//E*O*F talk.h//

echo x - talk_ctl.h
cat > "talk_ctl.h" << '//E*O*F talk_ctl.h//'
/*
 * Copyright (c) 1983 Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms are permitted
 * provided that the above copyright notice and this paragraph are
 * duplicated in all such forms and that any documentation,
 * advertising materials, and other materials related to such
 * distribution and use acknowledge that the software was developed
 * by the University of California, Berkeley.  The name of the
 * University may not be used to endorse or promote products derived
 * from this software without specific prior written permission.
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 *
 *	@(#)talk_ctl.h	5.4 (Berkeley) 6/29/88
 */

#include <sys/types.h>
#include <protocols/talkd.h>
#include <netinet/in.h>
#include "talk.h"
#include <errno.h>

extern	int errno;

extern	struct sockaddr_in daemon_addr;
extern	struct sockaddr_in ctl_addr;
extern	struct sockaddr_in my_addr;
extern	struct in_addr my_machine_addr;
extern	struct in_addr his_machine_addr;
extern	u_short daemon_port;
extern	int ctl_sockt;
extern	CTL_MSG msg;
//E*O*F talk_ctl.h//

exit 0