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