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 *)<c);
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 *)<c);
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