Phone program source
fidder at isucs1.UUCP
fidder at isucs1.UUCP
Thu Nov 8 08:59:56 AEST 1984
Here is the source to an interuser phone program written for 4.2BSD.
I consider it better then talk on a single host, but only you can
be the judge of that.
If you have any comments or susgestions please let me know. One last thing
if you have not fixed some of the the socket bugs in 4.2 you should be
carefull about running this program (esp. the bug when closing sockets
while someone has connected and you have not accepted yet.)
Ted Fidder
USENET: isucs1!fidder
CSNET: fidder at iowa-state
/* Begin PARANOIA */
#----------CUT HERE ----------------------------------------------
# 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:
# Makefile cparse.c cparse.h getuser.c phone.1 phone.c phone.h phoned.c phonemain.c phoneparse.c slotmanager.c ttycmio.c ttydumbio.c ttyio.c
echo x - Makefile
cat > "Makefile" << '//E*O*F Makefile//'
#---------------------------------------------------------
# Programmer name: Kevin Buettner
# Project: 4.2BSD Phone
#
# Module: Makefile
# Abstract:
#
# Required files: phone stuff
# Date written:
#
#-=-=-=-=-=-Revision: 11/6/84
# Name: Ted Fidder
# Reason: Redo Makefile
#
#=======================================================*/
INSTDIR= /usr/local
MANDIR= /usr/man/man1
INCLUDE= phone.h cparse.h
SRCS= phone.c getuser.c slotmanager.c phonemain.c ttyio.c ttycmio.c \
ttydumbio.c phoneparse.c cparse.c phoned.c
BIN= root
BINGRP=wheel
CFLAGS= -O
all: phone phoned
phone : phone.h phone.o getuser.o slotmanager.o phonemain.o ttyio.o ttycmio.o \
ttydumbio.o phoneparse.o cparse.o
cc ${CFLAGS} phone.o getuser.o slotmanager.o phonemain.o \
ttyio.o ttycmio.o ttydumbio.o phoneparse.o cparse.o -ltermlib -o phone
phoned : phoned.o
cc ${CFLAGS} phoned.o -o phoned
clean:
rm *.o phone phoned
xclean:
rm *.o phone phoned ${INSTDIR}/phone \
${INSTDIR}/phoned ${MANDIR}/phone.1
install: phone phoned
cp phone ${INSTDIR}/phone
chown ${BIN} ${INSTDIR}/phone
chgrp ${BINGRP} ${INSTDIR}/phone
chmod 751 ${INSTDIR}/phone
cp phoned ${INSTDIR}/phoned
chown ${BIN} ${INSTDIR}/phoned
chgrp ${BINGRP} ${INSTDIR}/phoned
chmod 751 ${INSTDIR}/phoned
cp phone.1 ${MANDIR}/phone.1
//E*O*F Makefile//
echo x - cparse.c
cat > "cparse.c" << '//E*O*F cparse.c//'
#include "cparse.h"
defaultputerrormessage();
initctab();
char *cp_ctab = (char *) 0; /* pointer to current character table */
int (*cp_puterrormessage)() = defaultputerrormessage;
char cp_badtoken[50]; /* used to store copy of token that caused error */
char *cp_errormessage; /* error message to put out */
int cparse(sstate,line)
statee *sstate; /* starting state */
char *line; /* line to parse */
{
char *argvec[100]; /* argument vector */
int argcnt; /* argument count */
char *tokvec[100]; /* token vector */
int retval; /* resultant value from call to transitions */
tokenize(line,tokvec); /* break the line up into words */
argcnt = 0; /* start the argument count out at zero */
cp_badtoken[0] = '\0'; /* null out the bad token copy */
cp_errormessage = "Unrecognized token."; /* default message */
if ((retval = transitions(sstate,tokvec,argvec,&argcnt)) < 0)
cp_puterrormessage(retval);
}
#define lcase(c) (('A'<=(c) && (c)<='Z')?((c)+' '):(c))
tokenize(l,tv)
register char *l; /* line to tokenize */
char **tv; /* vector to put the broken up line into */
{
char quotec;
static char tokenbuf[1024]; /* here is where we buffer up the tokens */
register char *tp = tokenbuf;
if (cp_ctab == (char *) 0)
initctab(); /* initialize the character table if need be */
while (*l) {
while (*l && cp_ctab[(*l)] == CP_CSKIP) l++; /* skip white space */
if (cp_ctab[(*l)] == CP_CQUOTE) {
*tv++ = tp;
quotec = *l++;
while (*l && *l != quotec)
*tp++ = *l++;
*tp++ = '\0'; /* kill the final quote */
l++;
}
else if (cp_ctab[(*l)] == CP_CCTOKEN) {
*tv++ = tp;
*tp++ = *l++;
*tp++ = '\0';
}
else if (*l) {
*tv++ = tp;
while (*l && cp_ctab[(*l)] == CP_CSTOKEN) {
*tp++ = lcase(*l);
l++; /* this can't be done in the above line!!! */
}
*tp++ = '\0';
}
}
*tv = (char *) 0; /* null terminate the token vector */
}
static defaultputerrormessage(ev)
int ev; /* errorval */
{
switch (ev) {
case CP_EEXTRAINPUT :
printf("Error: extra input encountered. (%s)\n",cp_badtoken);
break;
case CP_EUNRECOGNIZEDTOKEN :
printf("Error: %s (%s)\n",cp_errormessage,cp_badtoken);
break;
default :
printf("Error: Unknown error.\n");
break;
}
}
int transitions (s, tv, av, acp)
statee *s; /* current state */
char **tv; /* token vector */
char *av[]; /* argument vector */
int *acp; /* pointer to the argument count */
{
statee *se; /* state entry */
int retval; /* return value */
statee * findentry();
if (s == CP_NULLSTATE && *tv == (char *) 0)
return(0);
else if (s == CP_NULLSTATE) {
strncpy(cp_badtoken,*tv,sizeof(cp_badtoken)-1);
cp_badtoken[sizeof(cp_badtoken)-1] = '\0';
return(CP_EEXTRAINPUT);
}
if ((se = findentry(s,*tv,av,acp)) == CP_NULLSTATE) {
strncpy(cp_badtoken,*tv,sizeof(cp_badtoken)-1);
cp_badtoken[sizeof(cp_badtoken)-1] = '\0';
return(CP_EUNRECOGNIZEDTOKEN);
}
retval = 0;
/* Use DeMorgan's Rule on the next line to figure out what it means */
if (se->token != CP_TKNULLSTRING || **tv != '\0')
if ((retval = transitions(se->nextstate,
(se->token == CP_TKNULLSTRING) ? tv : tv+1,
av,
acp)) < 0)
return(retval);
if (se->func != CP_NULLFUNC) {
switch (se->functype) {
case CP_FTVALUE : (se->func)(retval+se->retval);
break;
case CP_FTPARAMS : (se->func)(*acp,av);
break;
case CP_FTVPARAMS: (se->func)(retval+se->retval,*acp,av);
break;
case CP_FTSHELLCMD :
{
int i;
char cmdline[300];
strcpy(cmdline,(char *) se->func);
for (i=0;i < (*acp);i++) {
strcat(cmdline," ");
strcat(cmdline,av[i]);
}
system(cmdline);
}
default : /* ignore */
break;
}
}
return(retval + se->retval);
}
statee *
findentry(s, t, av, acp)
statee *s; /* current state */
char *t; /* current token */
char *av[]; /* argument vector */
int *acp; /* pointer to argument vector */
{
statee *rv = CP_NULLSTATE;
if (t == (char *) 0) {
while (s->token != CP_TKENDMARKER)
if (s->token == CP_TKNULLSTRING)
return(s);
else if (s->token == CP_TKERRORMSG) {
cp_errormessage = (char *) s->func;
s++;
}
else
s++;
return(CP_NULLSTATE); /* no match */
}
else {
while (s->token != CP_TKENDMARKER)
if (s->token == CP_TKNULLSTRING)
rv = s++; /* skip the null string case */
else if (s->token == CP_TKERRORMSG) {
cp_errormessage = (char *) s->func;
s++;
}
else if (s->token == CP_TKDATA) {
if (cp_ctab[(*t)] == CP_CQUOTE)
av[(*acp)] = t+1;
else
av[(*acp)] = t;
(*acp)++;
return(s);
}
else if (cmptok(s->token,t))
return(s);
else
s++;
}
return(rv); /* return null string pointer maybe....otherwise
we'll return the null state pointer. */
}
static int cmptok(ss,cs)
char *ss,*cs;
{
while (*ss && *cs && *ss != '[' && *ss != ' ')
if (*ss++ != *cs++) return(0);
if (*ss == '[') ss++;
else if (*ss == ' ' && *cs == '\0') return(1);
else if (*ss == '\0' && *cs == '\0') return(1);
else return(0);
while (*ss && *cs)
if (*ss == ']') ss++;
else if (*ss++ != *cs++) return(0);
if (*cs == '\0') return(1);
else return(0);
}
static initctab()
{
char *malloc();
int i;
cp_ctab = malloc(256);
for (i=0;i<256;i++)
cp_ctab[i] = CP_CSTOKEN;
cp_ctab['\t'] = CP_CSKIP;
cp_ctab[' '] = CP_CSKIP;
cp_ctab['"'] = CP_CQUOTE;
}
cp_setctab(c,v)
char c;
char v;
{
if (cp_ctab == (char *) 0)
initctab();
cp_ctab[c] = v;
}
//E*O*F cparse.c//
echo x - cparse.h
cat > "cparse.h" << '//E*O*F cparse.h//'
/*
* cparse.h -- command parser include file
*/
/* Predefined token types */
#define CP_TKENDMARKER ((char *) 0)
#define CP_TKDATA ((char *) 1)
#define CP_TKNULLSTRING ((char *) 2)
#define CP_TKERRORMSG ((char *) 3)
/* Function Types */
#define CP_FTNONE 0 /* no associated function */
#define CP_FTPARAMS 1 /* call associated function with parameter
block */
#define CP_FTVALUE 2 /* call associated function with accumulated
return value */
#define CP_FTVPARAMS 3 /* call with both accumulated value and
parameter block */
#define CP_FTERRORMSG 4 /* corresponding function is really a string
containing error message if anything goes
wrong */
#define CP_FTSHELLCMD 5 /* corresponding function is a string of a
shell function to execute. The accumulated
parameters form the command parameters */
#define CP_NULLSTATE (statee *) 0
#define CP_NULLFUNC (int (*)()) 0
#define CP_EEXTRAINPUT -1
#define CP_EUNRECOGNIZEDTOKEN -2
/* The following macros are used in the character table to tokenize
the input. (They can be ignored for many applications) */
#define CP_CSKIP 0 /* Characters that we Skip */
#define CP_CCTOKEN 1 /* Character alone defines a Token */
#define CP_CSTOKEN 2 /* character composes part of a Token
String */
#define CP_CQUOTE 3 /* Character begins Quoted string */
typedef struct statee_ {
char *token; /* pointer to token */
struct statee_ *nextstate; /* pointer to next state */
int functype; /* function type */
int (*func)(); /* pointer to function */
int retval; /* return value */
} statee; /* command parser state entry */
/* Macros used for defining states.
* The following macros are used to define a state in the finite state
* machine the user must build to define his command language
*
* defstate(statename) is used to start the definition of a state
* endstate is used to terminate the definition of a state
*
* Between these two macros, the user may enter something of the form
* { "token-string", nextstate, functiontype, functionpointer, retval },
* where each of the parameters is of a type in statee. Usually,
* however, only a few of these parameters are of interest at a time so
* there are macros to take care of these.
*/
#define DEFSTATE(s) statee s[] = {
#define ENDSTATE ,{CP_TKENDMARKER,CP_NULLSTATE,CP_FTNONE,CP_NULLFUNC,0}};
#define NS(t,ns) {t,ns,CP_FTNONE,CP_NULLFUNC,0}
#define NULLSTR {CP_TKNULLSTRING,CP_NULLSTATE,CP_FTNONE,CP_NULLFUNC,0}
#define NULLSTR_NS(ns) {CP_TKNULLSTRING,ns,CP_FTNONE,CP_NULLFUNC,0}
#define NULLSTR_PFUNC(f) {CP_TKNULLSTRING,CP_NULLSTATE,CP_FTPARAMS,f,0}
#define NULLSTR_VFUNC(f) {CP_TKNULLSTRING,CP_NULLSTATE,CP_FTVALUE,f,0}
#define NULLSTR_PFUNC_NS(f,ns) {CP_TKNULLSTRING,ns,CP_FTPARAMS,f,0}
#define NULLSTR_VFUNC_NS(f,ns) {CP_TKNULLSTRING,ns,CP_FTVALUE,f,0}
#define DATA {CP_TKDATA,CP_NULLSTATE,CP_FTNONE,CP_NULLFUNC,0}
#define DATA_NS(ns) {CP_TKDATA,ns,CP_FTNONE,CP_NULLFUNC,0}
#define DATA_PFUNC(f) {CP_TKDATA,CP_NULLSTATE,CP_FTPARAMS,f,0}
#define DATA_VFUNC(f) {CP_TKDATA,CP_NULLSTATE,CP_FTVALUE,f,0}
#define DATA_PFUNC_NS(f,ns) {CP_TKDATA,ns,CP_FTPARAMS,f,0}
#define DATA_VFUNC_NS(f,ns) {CP_TKDATA,ns,CP_FTVALUE,f,0}
#define PFUNC(t,f) {t,CP_NULLSTATE,CP_FTPARAMS,f,0}
#define VFUNC(t,f) {t,CP_NULLSTATE,CP_FTVALUE,f,0}
#define VSUM(t,v) {t,CP_NULLSTATE,CP_FTNONE,CP_NULLFUNC,v}
#define PFUNC_NS(t,f,ns) {t,ns,CP_FTPARAMS,f,0}
#define VFUNC_NS(t,f,ns) {t,ns,CP_FTVALUE,f,0}
#define VSUM_NS(t,v,ns) {t,ns,CP_FTNONE,CP_NULLFUNC,v}
#define VPFUNC(t,f) {t,CP_NULLSTATE,CP_FTVPARAMS,f,0}
#define VPFUNC_NS(t,f,ns) {t,ns,CP_FTVPARAMS,f,0}
#define DATA_VPFUNC(f) {CP_TKDATA,CP_NULLSTATE,CP_FTVPARAMS,f,0}
#define DATA_VPFUNC_NS(f,ns) {CP_TKDATA,ns,CP_FTVPARAMS,f,0}
#define SHELLCMD(t,cmd) {t,CP_NULLSTATE,CP_FTSHELLCMD,(int (*)()) cmd,0}
#define SHELLCMD_NS(t,cmd,ns) {t,ns,CP_FTSHELLCMD,(int (*)()) cmd,0}
#define DATA_SHELLCMD(cmd) {CP_TKDATA,CP_NULLSTATE,CP_FTSHELLCMD,(int (*)()) cmd,0}
#define DATA_SHELLCMD_NS(cmd,ns) {CP_TKDATA,ns,CP_FTSHELLCMD,(int (*)()) cmd,0}
#define NULLSTR_SHELLCMD(cmd) {CP_TKNULLSTRING,CP_NULLSTATE,CP_FTSHELLCMD,\
(int (*)()) cmd,0}
#define NULLSTR_SHELLCMD_NS(cmd,ns) {CP_TKNULLSTRING,ns,CP_FTSHELLCMD,\
(int (*)()) cmd,0}
#define ERRORMSG(m) {CP_TKERRORMSG,CP_NULLSTATE,CP_FTERRORMSG,(int (*)()) m,0}
/* Useful external variables */
extern int (*cp_puterrormessage)();
extern char cp_badtoken[];
extern char *cp_errormessage;
extern char *cp_ctab; /* pointer to current character table */
//E*O*F cparse.h//
echo x - getuser.c
cat > "getuser.c" << '//E*O*F getuser.c//'
/*
* Version 2 Phone -- getuser.c
*
* This section gets information associated with a logged in user. We pass
* getuser the name and possibly a terminal and it returns the systems idea
* of the user name, whether or not his terminal can be written to, his tty,
* and his mother's birthday. (Note: a pointer to a userinformation structure
* is returned. If zero is returned, this indicates that the user is not logged
* in. -1 indicates an error opening the utmp file or accessing it.
*
*
* Program Author: Kevin A. Buettner
* Created: 7-7-84
* Revisions:
*/
#include "phone.h"
#include <utmp.h>
#include <sys/file.h>
#define UTSIZE (sizeof (struct utmp))
#define UTLSIZE (sizeof urec.ut_line)
#define UTNSIZE (sizeof urec.ut_name)
userinformation *
getuser(username,ttyname)
char *username,
*ttyname;
{
static userinformation retval;
int utfd; /* file descriptor to utmp */
int fd; /* file descriptor */
struct utmp urec; /* utmp record */
register done = 0; /* done flag */
char tfname[50]; /* built up filename */
if ((utfd = open("/etc/utmp",O_RDONLY,0)) < 0)
return((userinformation *) -1);
done = 0;
while (!done && UTSIZE == read(utfd,&urec,UTSIZE)) {
if (strncmp(username,urec.ut_name,UTNSIZE) == 0)
if (ttyname[0] == '\0')
done = 1;
else if (strncmp(ttyname,urec.ut_line,UTLSIZE) == 0)
done = 1;
}
close(utfd);
if (!done)
return((userinformation *) 0);
strncpy(retval.ttyname,urec.ut_line,UTLSIZE);
retval.ttyname[UTLSIZE] = '\0';
strncpy(retval.username,urec.ut_name,UTNSIZE);
retval.username[UTNSIZE] = '\0';
/* set the canwriteto field */
strcpy(tfname,"/dev/");
strcat(tfname,retval.ttyname);
retval.canwriteto = (0 == access(tfname,W_OK));
/* get the socket name to connect to (if possible) */
strcpy(tfname,"/tmp/V2Ph");
strcat(tfname,retval.ttyname);
if ((fd=open(tfname,0,0)) < 0)
retval.psockname[0] = '\0';
else {
read(fd,retval.psockname,40);
close(fd);
if (access(retval.psockname,F_OK) < 0)
retval.psockname[0] = '\0';
}
return(&retval);
}
//E*O*F getuser.c//
echo x - phone.1
cat > "phone.1" << '//E*O*F phone.1//'
.TH PHONE 1 "07 November 1984"
.UC 4
.SH NAME
phone \- talk to users interactively on the local host.
.SH SYNOPSIS
.B phone
person [ ttyname ]
.SH DESCRIPTION
.I Phone
is a visual communication program which
copies characters from your terminal to that of
one or more other user's terminals.
.PP
To communicate with another user just use the person's
login name.
If you want to talk to a user who is logged in more than once,
the
.I ttyname
argument may be used to indicate the
appropriate terminal name.
.PP
When you
.I phone
another user the following message is displayed on the receiving
users terminal:
.sp 2
Phone: your_name on terminal your_terminal is calling you
.br
While attempting connection the callers terminal clears and displays
the status of the call. The above message will appear on the callee's
terminal every few seconds until they either answer the call or you
cancel the call.
Once communication is established, the two parties may type
simultaneously, with their output appearing in separate windows.
.PP
While conversing with one or more users there are several possible
commands. These commands include:
.sp 2
<cntrl> L -- Replot Screen
.br
<cntrl> N -- Erase your portion of the screen.
.br
<cntrl> C/D -- Terminate Conversation. "Hangup the phone"
.br
<esc> -- Phone Command Processor escape
.br
.PP
The valid commands under the Phone Command Processor include:
.sp 2
help/? -- Help Summary
.br
who -- List Users on system
.br
exit -- same as <cntrl> c
.br
call -- Place a call to another user (conference calling)
.br
cancel -- Cancel call to a user
.br
set/show minterval -- Sets/Shows message interval (controls how fast messages
scroll on the botton line of the window.
.br
.PP
Permission to talk may be denied or granted by use of the
.I mesg
command.
.PP
Note: Phone also has a hardcopy mode for users on noncursor addressable
terminals. This operates exactly as normal mode but is line oriented and
very messy.
.PP
.SH Files
/etc/utmp to find the recipient's tty
.SH "SEE ALSO"
mesg(1), who(1), mail(1), write(1), talk(1)
.SH Bugs
Uses 4.2 sockets and can be very slow sometimes. Also on slow terminals
when users enter and leave a conversion the screen is redrawn to reflect
the new users window which is a pain on dialup terminals. If you have not
fixed the 4.2 socket bug which hangs the system at NETIPL it is not a good
idea to run this program.
//E*O*F phone.1//
echo x - phone.c
cat > "phone.c" << '//E*O*F phone.c//'
/*
* Version 2 Phone -- phone.c
*
* This section of the version 2 phone utility contains the function main.
*
* Program Author: Kevin A. Buettner
* Creation Date: 7/7/84
* Revisions:
*/
#include "phone.h"
#include <signal.h>
#include <pwd.h>
#include <stdio.h>
extern struct passwd *getpwuid();
extern userinformation * getuser();
main(argc,argv)
int argc;
char **argv;
{
userinformation *u;
char *mytty;
char *ttyname();
int dpid; /* daemon pid */
char psockname[80]; /* phone socket name */
struct passwd *pw; /* pointer to password structure */
int nodaemon(),daemonstarted(); /* predeclare for signal */
/* Check the number of arguments */
if (argc < 2) {
printf("Usage: %s username [ttyname]\r\n",argv[0]);
_exit(1);
}
/* See if the user we're trying to call is logged in, and if so
get certain information about him */
if ((u = getuser(argv[1],((argc > 2) ? argv[2] : ""))) <= 0) {
if ((int) u < 0)
printf("Error accessing /etc/utmp.\r\n");
else
printf("User not logged in.\r\n");
_exit(1);
}
/* Get the current terminal name */
if ((mytty = ttyname(0)) == 0) {
printf("You must be connected to a terminal.\n");
_exit(1);
}
/* Get my user name from the uid and the passwd file */
pw = getpwuid(getuid());
if (pw == 0) {
printf("Can't get your login name.");
_exit(1);
}
initslots();
setslot(MYSLOT,pw->pw_name,&mytty[5],pw->pw_gecos);
if (u->psockname[0] == '\0') {
if (u->canwriteto == 0) {
printf("Permission denied (Can't ring terminal).");
exit(1);
}
/* Gotta create a daemon */
signal(SIGIOT,nodaemon); /* set up signal handlers */
signal(SIGEMT,daemonstarted);
if ((dpid=vfork()) == 0) {
/* daemon branch */
signal(SIGIOT,SIG_DFL);
signal(SIGEMT,SIG_DFL);
/* try executing the phone daemon in a number of places */
execl("/usr/local/phoned","phoned",pw->pw_name,&mytty[5],
u->username,u->ttyname,0);
execl("/usr/bin/phoned","phoned",pw->pw_name,&mytty[5],
u->username,u->ttyname,0);
execl("/usr/new/phoned","phoned",pw->pw_name,&mytty[5],
u->username,u->ttyname,0);
execl("/test.bin/phoned","phoned",pw->pw_name,&mytty[5],
u->username,u->ttyname,0);
kill(getppid(),SIGIOT); /* can't do it */
exit(1);
}
else {
/* normal branch */
sigpause(0);
signal(SIGIOT,SIG_DFL);
signal(SIGEMT,SIG_DFL);
sprintf(psockname,"/tmp/pD%d",dpid);
phonemain(psockname,pw->pw_name,&mytty[5],pw->pw_gecos);
_exit(0);
}
}
else {
strcpy(psockname,u->psockname);
phonemain(psockname,pw->pw_name,&mytty[5],pw->pw_gecos);
_exit(0);
}
}
nodaemon()
{
printf("Error in starting daemon\r\n");
fflush(stdout);
_exit(1);
}
daemonstarted()
{
/* null function */
}
//E*O*F phone.c//
echo x - phone.h
cat > "phone.h" << '//E*O*F phone.h//'
/*
* Version 2 Phone: phone.h
*
* This include file contains definitions and declarations common to the
* various parts of the version 2 phone program.
*
* Author: Kevin A. Buettner
* Creation: 7/7/84
* Revision:
*/
typedef struct {
char ttyname[8]; /* terminal name */
char username[30]; /* short user name */
char realname[60]; /* his name out of the gcos field */
int canwriteto; /* flag telling us if we can write to
his tty */
char psockname[80]; /* the socket name to connect to (null
if there isn't any yet) */
char mothersbirthday[15]; /* string whose ascii
representation denotes the the date
of the user's mother's birth */
} userinformation;
typedef struct {
int inuse; /* indicates that the slot is in use */
char loginname[40]; /* the login name */
char ttyname[40]; /* name of the tty */
char realname[80]; /* real life name */
int xpos; /* current screen x-position */
int ypos; /* current screen y-position */
int topline; /* top-most line that this user gets */
int bottomline; /* bottom-most line for this user */
int lcount; /* number of lines in the line queue */
int lqhead; /* head of the line queue */
int lqtail; /* tail of the line queue */
} slottype;
typedef struct {
int llen; /* line length */
char line[132]; /* actual data in the line */
int nextl; /* index of next line (-1 is null) */
} linetype;
#define MAXSLOT 16 /* one bigger than in the phone daemon*/
#define MYSLOT (MAXSLOT-1)
extern slottype slots[];
extern linetype lines[];
extern int nslines, /* see slotmanager.c */
nflines,
nslots,
maxlines,
curslot;
extern (*announcearrival)();
extern (*announcedeparture)();
extern (*plotscr)();
extern (*puttoscr)();
extern (*putmessage)();
extern (*killcommandline)();
extern (*setupcommandline)();
extern (*putcommandcharacter)();
extern int oncommandline;
//E*O*F phone.h//
echo x - phoned.c
cat > "phoned.c" << '//E*O*F phoned.c//'
/*
* Version 2 Phone -- phoned.c
*
* This file contains the phone daemon.
*
* Program Author: Kevin A. Buettner
* Creation Date: 7/9/84
* Revisions:
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/file.h>
#include <errno.h>
#include <stdio.h>
#define MAXSLOT 15
struct {
int inuse; /* slot use indicator */
int ringsleft; /* number of rings left...-1 indicates
slot in conversation. -2 indicates
an unsolicited caller waiting to be
accepted. 0 indicates
a wait for a user to join
conversation. */
char loginname[40]; /* the login name */
char ttyname[40]; /* tty name */
char realname[80]; /* real life name */
int callerid; /* slot number of the caller */
int lastwriter; /* slot id of last writer to
this slot */
int sd; /* socket descriptor */
} slots[MAXSLOT];
char dsockname[20]; /* daemon socket name */
int lsock; /* socket that we're listening on */
struct itimerval ringinterval; /* time between rings structure */
extern ringring(); /* function which rings a terminal */
extern int errno;
main(argc,argv)
int argc;
char **argv;
{
int cslot,ceslot; /* caller and callee slots */
struct sockaddr sname; /* name of socket we're listening on */
int readmask,nfound; /* select mask and number of descrs
found in select call */
setpgrp(getpid(),getpid()); /* make ourselve's a process group */
if (argc < 5) {
printf("You should not run the phone daemon directly.\r\n");
_exit(1);
}
initslots(); /* get ready for users */
sprintf(dsockname,"/tmp/pD%d",getpid());
if ((lsock = socket(AF_UNIX,SOCK_STREAM,PF_UNSPEC)) < 0) {
perror("Error opening socket");
kill(getppid(),SIGKILL);
exit(1);
}
strcpy(sname.sa_data,dsockname);
sname.sa_family = PF_UNSPEC;
if (bind(lsock,&sname,sizeof(sname.sa_family) + strlen(sname.sa_data)) < 0) {
perror("Error binding socket");
kill(getppid(),SIGKILL);
exit(1);
}
if (listen(lsock,5) < 0) {
perror("Listen call failed");
shutdown(lsock,2);
close(lsock);
unlink(dsockname);
kill(getppid(),SIGKILL);
exit(1);
}
/* socket should be set up and ready to go now */
cslot = setslot( emptyslot(),
0, /* no rings for the caller */
argv[1], /* the login name */
argv[2], /* ttyname */
"", /* don't know real name yet */
-1, /* no caller */
-1); /* no socket descr yet */
ceslot= setslot( emptyslot(),
20, /* twenty rings */
argv[3], /* the login name */
argv[4], /* ttyname */
"", /* don't know real name yet */
cslot, /* the caller */
-1); /* no socket descriptor yet */
umask(0); /* set mode mask for all permissions */
if (makesocketnamefile(cslot) < 0) {
perror("Couldn't make socket name file");
shutdown(lsock,2);
close(lsock);
unlink(dsockname);
kill(getppid(),SIGKILL);
}
kill(getppid(),SIGEMT); /* tell parent daemon is started */
timerclear(&ringinterval.it_interval);
timerclear(&ringinterval.it_value);
ringinterval.it_interval.tv_sec = 20;
ringinterval.it_value.tv_sec = 20;
sigsetmask(~0);
signal(SIGPIPE,SIG_IGN); /* ignore broken pipe signals. We'll find
out about broken pipes when we try
to do a write */
signal(SIGALRM,ringring);
setitimer(ITIMER_REAL,&ringinterval,0);
ringring(); /* do the first ring now. */
/* This is the loop we'll sit in for most of the time */
while (1) {
readmask = buildreadmask();
sigsetmask(0); /* enable signals */
while ((nfound = select(15,&readmask,0,0,0)) < 0)
if (errno != EINTR)
errorshutdown();
sigsetmask(~0); /* disable all signals except for
SIGKILL, SIGCONT, and SIGSTOP */
decodereadmask(nfound,readmask);
}
} /* end of main for the phone daemon */
ringring() /* Rings people's terminals */
{
FILE *tf;
int i;
int callerid;
char tnam[30];
char mess[110];
for (i=0;i<MAXSLOT;i++)
if (slots[i].inuse && slots[i].ringsleft > 0) {
(slots[i].ringsleft)--;
sprintf(tnam,"/dev/%s",slots[i].ttyname);
if ((callerid = slots[i].callerid) < 0 ||
slots[callerid].inuse == 0)
killslot(i); /* won't ring if we don't know who is calling */
else if ((tf = fopen(tnam,"w")) == NULL) {
killslot(i); /* won't ring if we can't write to the term */
sprintf(mess,
"User %s on terminal %s rudely logged off or shut off his phone.",
slots[i].loginname,
slots[i].ttyname);
putmess(callerid,mess);
}
else {
fprintf(tf,
"\r\n\007Phone: %s on terminal %s is calling you.\r\n",
slots[callerid].loginname,
slots[callerid].ttyname);
fclose(tf);
sprintf(mess,"Ringing %s on %s",slots[i].loginname,
slots[i].ttyname);
putmessage(mess);
}
}
else if (slots[i].inuse && slots[i].ringsleft < 0) {
/* See if all of our sockets are still alive */
sputchar(i,001); /* try writing a SYN character to each...
if sputchar doesn't succeed it will kill
the slot for us. Note: The processes
at the other end of the socket should
ignore the SYN character */
}
}
initslots()
{
int i;
for (i=0;i<MAXSLOT;i++)
slots[i].inuse = 0;
}
killslot(sn)
int sn; /* slot number to kill */
{
int i, /* loop index */
nu; /* number used */
slots[sn].inuse = 0;
killsocketnamefile(sn);
/* Kill of the slots that this user called. */
for (i=0;i<MAXSLOT;i++)
if (slots[i].inuse && slots[i].ringsleft >= 0 &&
slots[i].callerid == sn)
slots[i].inuse = 0;
/* Inform rest of conversation of the termination of a user */
if (slots[sn].ringsleft == -1) /* make sure they are really in. */
for (i=0;i<MAXSLOT;i++)
if (slots[i].inuse && slots[i].ringsleft == -1) {
putheader(i,'t');
sputchar(i,'0'+sn); /* we're terminating sn */
}
/* Make a count of the remaining slots and see if there is anyone left */
for (nu=0,i=0;i<MAXSLOT;i++)
if (slots[i].inuse)
nu++;
if (nu < 2) { /* Shut everything down */
/* ADD CODE here to inform any remaining users that we're shutting
down operation */
shutdown(lsock,2); /* Shut down the socket we're listening on */
close(lsock); /* Then close it */
for (i=0;i<MAXSLOT;i++)
if (slots[i].inuse && slots[i].ringsleft < 0) {
shutdown(slots[i].sd,2); /* Shut down the rest of the sockets */
close(slots[i].sd); /* And close 'em up */
killsocketnamefile(i);
}
unlink(dsockname);
exit(0); /* This is where we exit normally. */
}
}
emptyslot() /* returns the first free slot */
{
int i;
for (i=0; i<MAXSLOT && slots[i].inuse;i++);
return((i>=MAXSLOT) ? -1 : i);
}
setslot ( sn,rl,loginname,ttyname,realname,callerid,socketdesc)
int sn;
int rl;
char *loginname;
char *ttyname;
char *realname;
int callerid;
int socketdesc;
{
slots[sn].inuse = 1;
slots[sn].ringsleft = rl;
strcpy(slots[sn].loginname,loginname);
strcpy(slots[sn].ttyname,ttyname);
strcpy(slots[sn].realname,realname);
slots[sn].callerid = callerid;
slots[sn].sd = socketdesc;
slots[sn].lastwriter = -1;
}
makesocketnamefile(sn)
int sn;
{
int fd;
char fname[40];
sprintf(fname,"/tmp/V2Ph%s",slots[sn].ttyname);
if ((fd=open(fname,O_CREAT|O_TRUNC|O_WRONLY,0777)) < 0)
return(-1);
if (write(fd,dsockname,strlen(dsockname)) < 0) {
close(fd);
return(-1);
}
close(fd);
return(0);
}
killsocketnamefile(sn)
int sn;
{
int fd;
char fname[40];
sprintf(fname,"/tmp/V2Ph%s",slots[sn].ttyname);
unlink(fname);
}
int buildreadmask()
{
register int retval = 1<<lsock;
register int sn;
for (sn=0;sn<MAXSLOT;sn++)
if (slots[sn].inuse && slots[sn].ringsleft == -1)
retval |= 1<<slots[sn].sd;
return(retval);
}
decodereadmask(nfound,m)
int nfound,m;
{
register int sn;
register int i;
if (m & (1<<lsock))
acceptconnection();
for (i=0;i<MAXSLOT;i++)
if (slots[i].inuse && (m & (1<<slots[i].sd)))
decodeumessage(i);
}
int findslot(loginname,ttyname) /* returns slot number of given
user...otherwise -1 */
char *loginname,*ttyname;
{
int i;
for (i=0;
i < MAXSLOT &&
!( /* (strncmp(loginname,slots[i].loginname,8) == 0) && */
(strncmp(ttyname,slots[i].ttyname,8) == 0));
i++);
return( (i >= MAXSLOT) ? -1 : i);
}
acceptconnection()
/*
* BUG: What happens if someone decides to leave in the middle of being
* informed of a new user?
*/
{
int nsd; /* new socket descriptor */
char loginname[40];
char ttyname[40];
char realname[80];
char c;
int sn; /* slot number */
int callerid; /* person who called this user */
int i; /* loop index */
if ((nsd=accept(lsock,0,0)) < 0)
errorshutdown();
if (sgetc(nsd) != ':') {
shutdown(nsd,2);
close(nsd);
return(-1);
}
sreadstr(nsd,loginname);
sreadstr(nsd,ttyname);
sreadstr(nsd,realname);
if ((sn = findslot(loginname,ttyname)) >= 0) {
callerid = slots[sn].callerid;
}
else {
callerid = -1;
sn = emptyslot();
}
setslot( sn,
-1, /* active in conversation */
loginname,
ttyname,
realname,
callerid,
nsd );
if (write(nsd,"a",1) < 0) {
/* abruptly disconnected ?? */
/* Should we do anything else here? */
shutdown(nsd,2);
close(nsd);
slots[sn].inuse = 0; /* make slot available for use again */
return;
}
putheader(sn,'a');
for (i=0;i<MAXSLOT;i++)
if (slots[i].inuse && slots[i].ringsleft == -1 && i != sn) {
putheader(i,'a'); /* put out the message header */
putuser(i,sn); /* add sn to user i */
termmsg(i); /* terminate message to i */
putuser(sn,i); /* add i to user sn (the one we just added) */
}
termmsg(sn); /* terminate the message to sn */
makesocketnamefile(sn);
return(0); /* successful */
}
errorshutdown()
{
int i;
printf("\007\r\n");
perror("Phone Daemon Error Shutdown");
/* This would be a good place for an error logger message */
printf("\007\r\n");
for (i=0;i<MAXSLOT;i++)
if (slots[i].inuse && slots[i].ringsleft < 0 && slots[i].sd >= 0) {
shutdown(slots[i].sd,2);
close(slots[i].sd);
}
shutdown(lsock,2);
close(lsock);
unlink(dsockname);
exit(1);
}
int sgetc(sd)
int sd; /* the socket descriptor */
{
int ch;
/* add timeout (use virtual timer) later on to prevent blocking */
ch = 0;
if (read(sd,&ch,1) < 0)
return(-1);
else
return(ch);
}
sreadstr(sd,buf)
int sd; /* socket descriptor */
char *buf; /* the buffer to put the stuff in...we read til : */
{
char ch;
while ((*buf = sgetc(sd)) != ':') buf++;
*buf = '\0'; /* null terminate */
}
/*
* The DLE character (020 octal) is used to introduce a message from a
* different source. The character immediately following the DLE character
* identifies the source.
*
* Character Meaning
* '0' thru '>' characters following were entered by a user for
* display. '0' corresponds to slot 0, '1' to slot 1
* and so on.
* 'a' Add user(s). One or more sequences of
* userid:login name:tty:real life name:
* are sent from the daemon. This entire sequence is
* terminated with another DLE character. The user
* context that was present before the message will
* resume. The user id will be one of the 0 thru > chars.
* 't' Terminate a user. A single character corresponding
* to the slot number (0 thru >) is sent immediately
* following the 't' indicating which user has left
* the conversation.
* 'm' characters following is a message from the daemon
* for display on the user's terminal. A DLE terminates
* the daemon message.
*
*/
sputstr(sn,s)
int sn; /* slot number (this is NOT the socket descriptor) */
char *s; /* string to write out */
{
if (!slots[sn].inuse)
return; /* someone doesn't know that this slot is out of
commission yet (or else there is a bug) */
if (write(slots[sn].sd,s,strlen(s)) < 0)
if (errno == EPIPE)
killslot(sn);
else
perror("Phone Daemon Debug (sputstr)");
}
sputchar(sn,c)
int sn; /* slot number (this is NOT the socket descriptor) */
char c; /* character to write out to socket desc associated
with the slot */
{
if (!slots[sn].inuse)
return; /* Get out */
if (write(slots[sn].sd,&c,1) < 0)
if (errno == EPIPE)
killslot(sn);
else
perror("Phone Daemon Debug (sputchar)");
}
putheader(sn,c)
int sn;
char c;
{
char buf[3];
buf[0] = 020; /* DLE character */
buf[1] = c;
buf[2] = '\0';
sputstr(sn,buf);
}
termmsg(sn)
int sn;
{
sputchar(sn,'\020');
}
putuser(sinf,snew)
int sinf, /* index into slots of user we're informing */
snew; /* new (?) user we're informing the other guy about */
{
char buf[300]; /* declare a big buffer */
sprintf(buf,"%c:%s:%s:%s:",('0'+snew), /* The user id */
slots[snew].loginname,
slots[snew].ttyname,
slots[snew].realname);
sputstr(sinf,buf);
}
putmess(sn,mess)
int sn;
char *mess;
{
short len = strlen(mess);
if (!slots[sn].inuse)
return;
putheader(sn,'m');
if (write(slots[sn].sd,&len,sizeof len) < 0)
killslot(sn);
else
sputstr(sn,mess);
}
putmessage(mess)
char *mess;
{
int i;
for (i=0;i<MAXSLOT;i++)
if (slots[i].inuse && slots[i].ringsleft == -1)
putmess(i,mess);
}
/*
* User Messages:
* Normally, we just take the character that the user has sent us and
* ship it out to everyone else in the conversation. There are exceptions
* to this however. The DLE character is used to start a special user
* message to the phone daemon. Following the DLE character (octal 020),
* is a character indicating the type of message (or action to perform).
* Following this character may be other information depending upon the type
* of message.
*
* Message Char Comment
* q quit this phone conversation
* c:login name:tty name: call user
* C:login name:tty name: cancel call to user
*
*
*/
decodeumessage(sn)
int sn; /* Slot number that character came in on */
{
char c;
if (read(slots[sn].sd,&c,1) < 0 || c == 0) {
killslot(sn);
return;
}
if (c != '\020')
shipout(sn,c);
else {
if (read(slots[sn].sd,&c,1) < 0) {
killslot(sn);
return;
}
switch (c) {
case 'q' : killslot(sn);
break;
case 'c' : calluser(sn);
break;
case 'C' : cancall(sn);
break;
}
}
}
shipout(sn,c) /* send out character c to everyone but sn */
int sn;
char c;
{
int i;
for (i=0; i < MAXSLOT; i++)
if (slots[i].inuse && slots[i].ringsleft == -1 && i != sn) {
if (sn != slots[i].lastwriter) {
slots[i].lastwriter = sn;
putheader(i,'0'+sn);
}
sputchar(i,c);
}
}
calluser(sn)
int sn;
{
char loginname[40];
char ttyname[40];
char msg[80];
if (sgetc(slots[sn].sd) != ':')
return;
sreadstr(slots[sn].sd,loginname);
sreadstr(slots[sn].sd,ttyname);
if (findslot(loginname,ttyname) != -1) {
sprintf(msg,"%s on terminal %s is already in the conversation.",
loginname,ttyname);
putmess(sn,msg);
return;
}
setslot( emptyslot(), /* get a new slot */
20, /* twenty rings */
loginname, /* login name */
ttyname, /* the tty name */
"", /* real name */
sn, /* the caller */
-1); /* no socket descr yet */
}
cancall(sn)
int sn;
{
char loginname[40];
char ttyname[40];
char theirslot;
char msg[80];
if (sgetc(slots[sn].sd) != ':')
return;
sreadstr(slots[sn].sd,loginname);
sreadstr(slots[sn].sd,ttyname);
if ((theirslot=findslot(loginname,ttyname)) == -1) {
sprintf(msg,"%s on terminal %s has never been called.",loginname,ttyname);
putmess(sn,msg);
return;
}
if (slots[theirslot].callerid != sn) {
/* Inform canceller that they can't cancel the call */
sprintf(msg,"You are not permitted to cancel the call to %s on %s.",
loginname,ttyname);
putmess(sn,msg);
return;
}
if (slots[theirslot].ringsleft < 0) {
/* Tell the caller that they can't cancel someone already in
conversation */
sprintf(msg,"%s on %s is in the conversation and can't be canceled.",
loginname,ttyname);
putmess(sn,msg);
return;
}
slots[theirslot].inuse = 0;
}
//E*O*F phoned.c//
echo x - phonemain.c
cat > "phonemain.c" << '//E*O*F phonemain.c//'
/*
* Version 2 Phone -- phonemain.c
*
* This is the main driving procedure for the version 2 phone.
*
* Program Author: Kevin Buettner
* Creation Date: 7/9/84
* Revision:
*
* I grant permission for coping and modifying this software
* in any matter as the user see fit, as long as this message
* remains in the code.
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/file.h>
#include <errno.h>
#include <signal.h>
#include <sgtty.h>
#include "phone.h"
int lastwriter; /* slotnumber of last writer to our phone */
extern errno; /* error number */
int daemonsocket; /* socket to the daemon */
extern cleanup();
phonemain(socketname,loginname,ttyname,realname)
{
struct sockaddr sname;
char message[200]; /* message to send to daemon */
char dmess[4]; /* message from daemon */
daemonsocket = socket(AF_UNIX,SOCK_STREAM,PF_UNSPEC);
strcpy(sname.sa_data,socketname);
sname.sa_family = PF_UNSPEC;
if (connect(daemonsocket,&sname,
sizeof(sname.sa_family) + strlen(sname.sa_data)) < 0)
errexit("Error connecting to daemon");
sprintf(message,":%s:%s:%s:",loginname,ttyname,realname);
if (write(daemonsocket,message,strlen(message)) < 0)
errexit("Error writing to daemon");
ttyinit();
inittdfv();
signal(SIGINT,cleanup);
signal(SIGPIPE,cleanup);
if (read(daemonsocket,dmess,1) < 0)
errexit("Error reading from daemon");
if (dmess[0] == 'a') {
/* Eat the DLE */
if (sgetchar(daemonsocket) != '\020'); /* ADD CODE to handle this */
/* Eat the a */
if (sgetchar(daemonsocket) != 'a'); /* ADD CODE to handle this */
getusers(daemonsocket);
converse(daemonsocket);
}
else {
printf("Connection rejected.\r\n");
shutdown(daemonsocket,2); /* shut down the socket */
_exit(0);
}
}
errexit(m)
char *m;
{
perror(m);
printf("\r\n");
_exit(1);
}
converse(s)
int s;
{
int readfds;
while (1) {
readfds = 1 | (1<<s);
sigsetmask(0); /* Let all signals get through */
while (select(15,&readfds,0,0,0) < 0)
if (errno != EINTR) {
setcooked();
errexit("Select Error");
}
sigblock(1<<(SIGALRM-1)); /* don't want timer interrupting us later */
if (readfds & (1<<s))
getdaemoninformation(s);
if (readfds & 1)
getkeyboardinformation(s);
}
}
getusers(sd) /* Get added users */
int sd;
{
int userid; /* character user id */
char loginname[40];
char ttyname[40];
char realname[80];
while ((userid=sgetchar(sd)) != '\020') {
if (sgetchar(sd) != ':') /* handle this later */ ;
sgetstr(sd,loginname);
sgetstr(sd,ttyname);
sgetstr(sd,realname);
setslot(userid-'0',loginname,ttyname,realname);
announcearrival(userid-'0');
}
plotscr();
}
sgetchar(sd)
int sd; /* socket descriptor */
{
int ch;
ch = 0;
if (read(sd,&ch,1) < 0 || ch == 0)
cleanup(); /* Things have gone badly indeed */
else
return(ch);
}
sgetstr(sd,buf)
int sd; /* socket descriptor */
char *buf; /* return buffer */
{
while ((*buf = sgetchar(sd)) != ':')
if (*buf) buf++; /*don't take zero's*/
*buf = '\0'; /* null terminate */
}
getdaemoninformation(sd)
int sd;
{
int ch;
ch = sgetchar(sd);
if (ch == 001) /* the syn character is sent every so often */
return;
else {
if (ch != '\020')
puttoscr(lastwriter,ch);
else {
ch = sgetchar(sd);
if ('0' <= ch && ch <= '>') {
lastwriter = ch-'0';
ch = sgetchar(sd);
puttoscr(lastwriter,ch);
}
else if (ch == 'a')
getusers(sd);
else if (ch == 'm')
getdmessage(sd);
else if (ch == 't')
terminateuser(sd);
}
}
}
getkeyboardinformation(sd)
int sd;
{
char c;
c = getch();
if (c == '\004')
cleanup();
else if (c == '\033' /* Escape */) {
if (oncommandline)
killcommandline();
else
setupcommandline();
}
else if (oncommandline)
putcommandcharacter(c);
else {
puttoscr(MYSLOT,c);
if (write(sd,&c,1) < 0) /* send it away */
cleanup();
}
}
cleanup()
{
char buf[2];
int flags;
buf[0] = '\020'; /* The DLE character */
buf[1] = 'q'; /* A q for quit */
write(daemonsocket,buf,2);
clearscreen();
ttyend();
printf("\r\n\n");
shutdown(daemonsocket,2); /* shut the socket down */
close(daemonsocket);
flags = FREAD;
ioctl(0,TIOCFLUSH,&flags);
_exit(0);
}
getdmessage(sd)
int sd;
{
short len;
char buf[512];
char *b = buf;
if (read(sd,&len,sizeof len) < 0)
cleanup();
if (read(sd,buf,len) < 0)
cleanup();
buf[len] = '\0';
putmessage(buf);
}
terminateuser(sd)
int sd;
{
char ch;
ch = sgetchar(sd); /* get the slot number to terminate */
announcedeparture(ch-'0');
killslot(ch-'0'); /* kill the slot */
if (nslots < 2)
cleanup(); /* no one left to talk to */
else
plotscr();
}
//E*O*F phonemain.c//
echo x - phoneparse.c
cat > "phoneparse.c" << '//E*O*F phoneparse.c//'
#include "cparse.h"
#include "phone.h"
#include <utmp.h>
#include <sys/file.h>
extern cleanup();
extern int msgtimeout;
/* functions that our parser definitions need to know about */
wholist(); calluser(); helpsummary(); setmtimeout(); showmtimeout();
cancelcall();
DEFSTATE(callparams)
DATA_NS(callparams),
NULLSTR
ENDSTATE
DEFSTATE(sparam)
DATA,
ERRORMSG("Integer value expected")
ENDSTATE
DEFSTATE(singleparam)
NS("=",sparam),
NULLSTR_NS(sparam)
ENDSTATE
DEFSTATE(setcommands)
PFUNC_NS("mi[nterval",setmtimeout,singleparam),
ERRORMSG("Invalid set option")
ENDSTATE
DEFSTATE(showcommands)
VFUNC("mi[nterval",showmtimeout),
ERRORMSG("Invalid show option")
ENDSTATE
DEFSTATE(canparams2)
NS("to",callparams),
NS("for",callparams),
NULLSTR_NS(callparams)
ENDSTATE
DEFSTATE(canparams)
NS("call",canparams2),
NULLSTR_NS(callparams)
ENDSTATE
DEFSTATE(primary)
VFUNC("h[elp",helpsummary), /* help commands */
VFUNC("?",helpsummary),
VFUNC("qui[t",cleanup), /* quit commands */
VFUNC("ex[it",cleanup),
VFUNC("han[gup",cleanup),
VFUNC("w[ho",wholist), /* who command */
PFUNC_NS("cal[l",calluser,callparams), /* call a user */
PFUNC_NS("can[cel",cancelcall,canparams), /* cancel a call */
NS("se[t",setcommands),
NS("sh[ow",showcommands),
ERRORMSG("Unrecognized Command")
ENDSTATE
docommand(l)
char *l;
{
extern int (*cp_puterrormessage)();
extern parsermessage();
/* the following initializations should probably be done elsewhere */
cp_puterrormessage = parsermessage;
cp_setctab('=',CP_CCTOKEN); /* the equal sign is a token by itself */
cparse(primary,l);
}
parsermessage(code)
int code;
{
char buf[200];
switch (code) {
case CP_EEXTRAINPUT :
sprintf(buf,"Error: Extra input encounted ('%s').",cp_badtoken);
putmessage(buf);
break;
case CP_EUNRECOGNIZEDTOKEN :
sprintf(buf,"Error: %s ('%s').",cp_errormessage,cp_badtoken);
putmessage(buf);
break;
default :
putmessage("Error: Unknown Parser Error.");
break;
}
}
helpsummary(code)
int code;
{
putmessage("help: Command Summary...");
putmessage("help: help -- displays this summary");
putmessage("help: who -- lists users on the system");
putmessage("help: exit -- leaves the phone program");
putmessage("help: call User [TTYName] -- calls a user");
putmessage("help: cancel User [TTYName] -- cancel a call");
putmessage("help: set minterval Value -- sets message interval");
putmessage("help: show minterval -- shows message interval");
}
setmtimeout(argc,argv)
int argc;
char **argv;
{
int val;
if (sscanf(argv[0],"%d",&val) != 1)
putmessage("set: numeric parameter required for mtimeout");
else if (val < 0 || val > 60)
putmessage("set: reasonable values required for mtimeout");
else {
char buf[100];
sprintf(buf,"set: mtimeout, old value=%d new value=%d",msgtimeout,val);
msgtimeout = val;
putmessage(buf);
}
}
showmtimeout(argc,argv)
{
char buf[100];
sprintf(buf,"show: mtimeout = %d",msgtimeout);
putmessage(buf);
}
#define UTSIZE (sizeof (struct utmp))
#define UTLSIZE (sizeof urec.ut_line)
#define UTNSIZE (sizeof urec.ut_name)
wholist(p)
int p; /* dummy parameter */
{
int ufd; /* utmp file descriptor */
struct utmp urec;
char user[50];
char ttyname[50];
char msg[100];
char buf[100];
static char facname[] = "who: ";
if ((ufd = open("/etc/utmp",O_RDONLY,0)) < 0)
putmessage("Error opening the utmp file.");
else {
strcpy(msg,facname);
while (UTSIZE == read(ufd,&urec,UTSIZE)) {
if (urec.ut_name[0] != '\0') {
user[0] = '\0';
strncat(user,urec.ut_name,UTNSIZE);
ttyname[0] = '\0';
strncat(ttyname,urec.ut_line,UTLSIZE);
sprintf(buf,"%s (%s)",user,ttyname);
if (strlen(buf)+strlen(msg) > 70) {
putmessage(msg);
strcpy(msg,facname);
strcat(msg,buf);
}
else {
if (strlen(msg) > strlen(facname))
strcat(msg,", ");
strcat(msg,buf);
}
}
}
putmessage(msg);
close(ufd);
}
}
calluser(argc,argv)
int argc;
char **argv;
{
userinformation *u;
char buf[100];
extern int daemonsocket;
userinformation *getuser();
if (argc == 0) {
putmessage("You must tell me who to call.");
return;
}
if (argc > 2) {
putmessage("Too many parameters to call. Usage is: call user ttyname.");
return;
}
if ((u = getuser(argv[0],((argc == 2) ? argv[1] : ""))) <= 0) {
if ((int) u < 0)
putmessage("Error accessing /etc/utmp.");
else if (argc == 2)
putmessage("User not logged in on that terminal.");
else
putmessage("User not logged in.");
return;
}
if (u->psockname[0] != '\0') {
putmessage("User already in a phone conversation.");
return;
}
if (u->canwriteto == 0) {
putmessage("call: Permission Denied. (Can't write to terminal)");
return;
}
sprintf(buf,"\020c:%s:%s:",u->username,u->ttyname);
write(daemonsocket,buf,strlen(buf));
sprintf(buf,"Attempting to call %s on terminal %s.",u->username,
u->ttyname);
putmessage(buf);
}
cancelcall(argc,argv)
int argc;
char **argv;
{
userinformation *u;
char buf[100];
extern int daemonsocket;
userinformation *getuser();
if (argc == 0) {
putmessage("You must tell me who to cancel the call to.");
return;
}
if (argc > 2) {
putmessage("Too many parameters to cancel. Usage is: cancel user ttyname.");
return;
}
if ((u = getuser(argv[0],((argc == 2) ? argv[1] : ""))) <= 0) {
if ((int) u < 0)
putmessage("Error accessing /etc/utmp.");
else if (argc == 2)
putmessage("User not logged in on that terminal.");
else
putmessage("User not logged in.");
return;
}
sprintf(buf,"\020C:%s:%s:",u->username,u->ttyname);
write(daemonsocket,buf,strlen(buf));
sprintf(buf,"Attempting to cancel call to %s on terminal %s.",u->username,
u->ttyname);
putmessage(buf);
}
//E*O*F phoneparse.c//
echo x - slotmanager.c
cat > "slotmanager.c" << '//E*O*F slotmanager.c//'
/*
* Version 2 Phone -- slotmanager.c
*
* Each person has a section of the screen called a slot. This code manages
* the slots.
*
* Program Author: Kevin A. Buettner
* Creation Date: 7-8-84
* Revisions:
*/
#include "phone.h"
#define MAXLINE 200 /* number of lines in the free line
pool */
linetype lines[MAXLINE]; /* lines */
slottype slots[MAXSLOT]; /* slots */
int nslots; /* number of slots in use */
int maxlines; /* maximum number of lines any given
slot is allowed to have...this will
vary with the number of slots in
use. */
int freelinepool; /* index of first line in the free
line pool */
int nslines = 24; /* number of screen lines available */
int nflines = 1; /* number of free lines at bottom of
screen. We must have at least one */
/* Procedure Name: initslots
* Description: initializes the inuse field of each slot to zero.
* Parameters: None.
* Side Effects: Obvious.
*/
initslots()
{
int i;
for (i=0;i<MAXSLOT;i++)
slots[i].inuse = 0;
nslots = 0; /* No slots used yet */
initlines(); /* also initialize the free line pool */
}
/* Procedure Name: initlines
* Description: initializes the free lines pool
* Parameters: None.
* Side Effects: Obvious.
*/
initlines()
{
register int i;
for (i=0;i<MAXLINE;i++)
lines[i].nextl = i+1;
lines[MAXLINE-1].nextl = -1;
}
/* Function Name: newslot
* Description: Returns the index of the first unused slot found.
* Parameters: None.
* Side Effects: None.
*/
int newslot()
{
int i;
for (i=0; i<MAXSLOT && !slots[i].inuse; i++);
return((i>=MAXSLOT) ? -1 : i);
}
/* Procedure Name: setslot
* Description: Fills in the login name, tty, and real life name from
* the supplied parameters.
* Parameters: slotnum -- index of slot to fill in
* loginname -- the login name
* ttyname -- terminal
* realname -- Real name of the user
* Returns: slotnum
* Side Effects: See for yourself.
*/
setslot(slotnum,loginname,ttyname,realname)
int slotnum;
char *loginname;
char *ttyname;
char *realname;
{
#define SLT slots[slotnum]
SLT.inuse = 1;
strcpy(SLT.loginname,loginname);
strcpy(SLT.ttyname,ttyname);
strcpy(SLT.realname,realname);
SLT.xpos = 0; /* initial x position */
SLT.ypos = 0; /* initial y position (within this
slot) */
SLT.lcount = 1; /* We will soon have one line */
SLT.lqhead = allocline(); /* Get a line from the free line pool */
SLT.lqtail = SLT.lqhead; /* set the tail to the head */
nslots++;
adjslots(); /* This will adjust the top and
bottom line for all slots */
return(slotnum); /* plot/replot screen */
}
/* Procedure Name: killslot
* Description: Frees up a slot and lines associated with that slot.
* Parameters: slotnum -- number of slot to remove.
* Side Effects: Other used slots will be adjusted as well.
*/
killslot(slotnum)
int slotnum;
{
register int s,t;
s = SLT.lqhead;
while (s != -1) {
t = lines[s].nextl;
freeline(s);
s = t;
}
SLT.inuse = 0;
nslots--;
adjslots(); /* Adjust the rest of the slots */
return(slotnum);
}
adjslots()
{
register int i,s;
maxlines = (nslines - nflines - 2*nslots + 1) / nslots;
i = 0;
s = 0;
for (s=0;s < MAXSLOT; s++)
if (slots[s].inuse) {
slots[s].topline = 1 + i*(maxlines + 2);
slots[s].bottomline = slots[s].topline + maxlines - 1;
i++;
while (slots[s].lcount > maxlines)
killtopline(s);
}
}
/* Function Name: allocline
* Description: Returns an index of a line allocated out of the free line
* pool.
* Parameters: None.
* Side Effects: The global variable freelinepool is modified.
*/
allocline()
{
register int t = freelinepool;
freelinepool = lines[freelinepool].nextl;
lines[t].llen = 0;
lines[t].line[0] = '\0';
lines[t].nextl = -1;
return(t);
}
/* Procedure Name: freeline
* Description: Returns a line to the free line pool.
* Parameters: l -- line to return to the free line pool.
* Side Effects: The global variable freelinepool is modified.
*/
freeline(l)
int l;
{
lines[l].nextl = freelinepool;
freelinepool = l;
}
/* Procedure Name: killtopline
* Description: Removes a line from the head of the line queue associated
* with a given slot.
* Parameters: slotnum -- number of slot to remove line from head
* Side Effects: The queue head and the number of lines in the queue
* are updated for the slot.
*/
killtopline(slotnum)
int slotnum;
{
int t = SLT.lqhead;
SLT.lqhead = lines[t].nextl;
freeline(t);
SLT.lcount--;
}
/* Procedure Name: addbottomline
* Description: adds a line to the tail of the queue (the bottom line)
* Parameters: slotnum -- number of slot to add a blank line to.
* Side Effects: The top line may be deleted if the number of lines in
* the slot is already equal to maxlines. The lcount and lqtail fields
* of the slot should also change.
*/
slt_addbottomline(slotnum)
int slotnum;
{
int t = allocline();
lines[SLT.lqtail].nextl = t;
SLT.lqtail = t;
SLT.lcount++;
if (SLT.lcount > maxlines)
killtopline(slotnum);
}
slt_addcharacter(slotnum,ch)
int slotnum;
char ch;
{
linetype *l;
l = &lines[SLT.lqtail];
l->line[l->llen] = ch;
(l->llen)++;
l->line[l->llen] = '\0';
}
slt_delcharacter(slotnum)
int slotnum;
{
linetype *l;
l = &lines[SLT.lqtail];
if (l->llen > 0) {
(l->llen)--;
l->line[l->llen] = '\0';
}
}
slt_wipeline(slotnum)
int slotnum;
{
linetype *l;
l = &lines[SLT.lqtail];
l->llen = 0;
l->line[0] = '\0';
}
char *ldelword(l,max)
linetype *l;
int max; /* maximum number of characters to search back */
{
static char buf[100]; /* here is where we store the word just
deleted */
char *w;
char *s;
s = &l->line[(l->llen)-1];
if (l->llen < max)
max = l->llen;
while (max > 0 && *s == ' ') {
s--; /* skip over trailing blanks */
max--;
}
while (max > 0 && *s != ' ') {
s--; /* skip to previous blank */
max--;
}
s++;
l->llen = s - l->line;
w = buf;
while (*w++ = *s++);
l->line[(l->llen)] = '\0';
return(buf);
}
char *slt_delword(slotnum,max)
{
return(ldelword(&lines[SLT.lqtail],max));
}
//E*O*F slotmanager.c//
echo x - ttycmio.c
cat > "ttycmio.c" << '//E*O*F ttycmio.c//'
#include "phone.h"
#include <sys/time.h>
#include <signal.h>
extern int ttype_scroller;
extern int ttype_dumb;
int (*announcearrival)();
int (*announcedeparture)();
int (*plotscr)();
int (*puttoscr)();
int (*putmessage)();
int (*killcommandline)();
int (*setupcommandline)();
int (*putcommandcharacter)();
nullfunc(){}
cm_plotscr();
cm_puttoscr();
cm_putmessage();
cm_killcommandline();
cm_setupcommandline();
cm_putcommandcharacter();
dumb_announcearrival();
dumb_announcedeparture();
dumb_puttoscr();
dumb_putmessage();
dumb_killcommandline();
dumb_setupcommandline();
dumb_putcommandcharacter();
extern int rcvals[];
char prompt[] = "Command> ";
int oncommandline; /* flag that tells us we are currently on the
command line */
int curslot = 0; /* slot to get the x and y coordinates from */
int cmdidx; /* index into line structure of command that
user is typing */
int msgqh; /* head of the message queue */
int msgqt; /* tail of the message queue */
int curmcidx; /* index of current line displayed in
the message/command area of the
screen */
int msgtimeout = 3; /* three seconds as the initial timeout */
inittdfv() /* initialize terminal dependent function variables */
{
oncommandline = 0;
if (ttype_dumb) {
int i;
announcearrival = dumb_announcearrival;
announcedeparture = dumb_announcedeparture;
putmessage = dumb_putmessage;
plotscr = nullfunc;
puttoscr = dumb_puttoscr;
killcommandline = dumb_killcommandline;
setupcommandline = dumb_setupcommandline;
putcommandcharacter = dumb_putcommandcharacter;
for (i=0;i<MAXSLOT;i++)
rcvals[i]=0;
curslot=MYSLOT;
}
else {
announcearrival = nullfunc;
announcedeparture = nullfunc;
plotscr = cm_plotscr;
puttoscr = cm_puttoscr;
putmessage = cm_putmessage;
killcommandline = cm_killcommandline;
setupcommandline = cm_setupcommandline;
putcommandcharacter = cm_putcommandcharacter;
cmdidx = -1; /* these initializations might better be done */
msgqh = -1; /* elsewhere */
msgqt = -1;
curmcidx = -1;
}
}
/*
* Below are the functions for terminals capable of moving the cursor
* about.
*/
cm_plotscr()
{
char buf[90];
int i,j,k,l;
clearscreen();
for (i=0,j=0;i<MAXSLOT;i++)
if (slots[i].inuse) {
j++;
sprintf(buf,"%s on %s (%s)",slots[i].loginname,
slots[i].ttyname,
slots[i].realname);
setpos(0,slots[i].topline-1);
putstr(buf);
slots[i].ypos = 0;
slots[i].xpos = 0;
for (l=slots[i].lqhead,k=0; l != -1; l=lines[l].nextl,k++) {
setpos(0,slots[i].topline+k);
putstr(lines[l].line);
slots[i].ypos = k;
slots[i].xpos = lines[l].llen;
}
curslot = i;
if (j < nslots) {
for (k=0;k<78;k++)
buf[k] = '-';
buf[78] = '\0';
setpos(0,slots[i].bottomline+1);
putstr(buf);
}
}
if (oncommandline) {
curslot = -1;
curmcidx = -1;
cm_putcommandline();
}
}
#define SLT slots[sn]
cm_puttoscr(sn,ch)
int sn;
{
int i;
/* Move the cursor if it is in the wrong place */
if (sn != curslot) {
curslot = sn;
setpos(SLT.xpos,SLT.topline+SLT.ypos);
}
if (ch < ' ') {
switch (ch) {
case 007 : beep();
break;
case 010 : /* backspace */
if (SLT.xpos > 0) {
SLT.xpos--;
slt_delcharacter(sn);
putstr("\b \b");
}
break;
case 011 :
/* ctrl-i -- tab */
if (SLT.xpos < 72) {
do {
putch(' ');
SLT.xpos++;
slt_addcharacter(sn,' ');
} while (SLT.xpos % 8 != 0);
}
break;
case 012 :
case 015 : /* newline */
cm_newline(sn);
break;
case 014 : /* CTRL-L -- Replot */
if (sn == MYSLOT)
plotscr();
break;
case 016 : /* CTRL-N */
cm_clearslot(sn);
break;
case 027 :
/* CTRL-W -- Clear word */
i = strlen(slt_delword(sn,80));
while (i > 0) {
SLT.xpos--;
putstr("\b \b");
i--;
}
break;
case 030 : /* CTRL-X -- Clear line */
cm_clearcurrent(sn);
break;
default : /* ignore */
if (sn == MYSLOT)
beep();
break;
}
}
else {
if (SLT.xpos > 78) {
putch('-');
slt_addcharacter(sn,'-');
cm_newline(sn);
}
putch(ch);
SLT.xpos++;
slt_addcharacter(sn,ch);
}
if (oncommandline) {
curslot = -1;
setcommandpos();
}
}
cm_newline(sn)
int sn;
{
if (SLT.ypos >= maxlines-1) {
if (ttype_scroller)
scrollup(SLT.topline,SLT.bottomline);
else {
SLT.ypos = 0;
cm_cleartop(sn);
}
}
else if (SLT.lcount == maxlines && !ttype_scroller) {
SLT.ypos++;
cm_cleartop(sn);
}
else
SLT.ypos++;
slt_addbottomline(sn);
SLT.xpos = 0;
setpos(SLT.xpos,SLT.topline+SLT.ypos);
}
cm_cleartop(sn)
int sn;
{
setpos(0,SLT.topline+SLT.ypos);
if (cleartoend() < 0) {
char buf[80];
int i,l;
l = lines[SLT.lqhead].llen;
for (i=0 ; i < l ; i++)
buf[i] = ' ';
buf[l] = '\0';
putstr(buf);
}
}
cm_clearcurrent(sn)
int sn;
{
setpos(0,SLT.topline+SLT.ypos);
if (cleartoend() < 0) {
char buf[80];
int i,l;
l = lines[SLT.lqtail].llen;
for (i=0 ; i < l ; i++)
buf[i] = ' ';
buf[l] = '\0';
putstr(buf);
}
slt_wipeline(sn);
SLT.xpos = 0;
setpos(0,SLT.topline+SLT.ypos);
}
cm_putmess()
{
int oldlen;
int i;
char buf[80];
if (curmcidx == cmdidx && msgqh == -1)
return; /* nothing to do. */
if (curmcidx == -1)
oldlen = 0;
else
oldlen = lines[curmcidx].llen;
if (curmcidx == msgqh)
delfromlq(&msgqh,&msgqt);
/* Now set curmcidx and set up buf */
if (msgqh != -1)
curmcidx = msgqh;
else
curmcidx = cmdidx;
if (curmcidx == -1)
buf[0] = '\0';
else
strcpy(buf,lines[curmcidx].line);
setpos(0,23);
if (strlen(buf) < oldlen && cleartoend() < 0) {
for (i=strlen(buf) ; i < oldlen ; i++)
buf[i] = ' ';
buf[oldlen] = '\0';
}
putstr(buf);
if (curmcidx != -1 && curmcidx != cmdidx)
cm_starttimer();
if (curslot >= 0)
setpos(slots[curslot].xpos,slots[curslot].ypos+slots[curslot].topline);
else
setcommandpos();
}
cm_starttimer()
{
struct itimerval tval;
timerclear(&tval.it_interval);
timerclear(&tval.it_value);
tval.it_value.tv_sec = msgtimeout;
signal(SIGALRM,cm_putmess);
setitimer(ITIMER_REAL,&tval,0);
}
cm_putmessage(buf)
char *buf;
{
int m;
m = allocline();
strcpy(lines[m].line,buf);
lines[m].llen = strlen(buf);
addtolq(&msgqh,&msgqt,m);
if (curmcidx == -1)
cm_putmess();
else if (curmcidx == cmdidx)
cm_putmess(); /* might want to do this another way */
}
addtolq(qhp,qtp,e) /* this should probably be moved to slotmanager.c */
int *qhp, /* pointer to the queue head */
*qtp, /* pointer to the queue tail */
e; /* element to add to the queue */
{
if (*qhp == -1) { /* queue is empty */
*qhp = e;
*qtp = e;
lines[e].nextl = -1;
}
else { /* queue isn't empty */
lines[*qtp].nextl = e;
lines[e].nextl = -1;
*qtp = e;
}
}
delfromlq(qhp,qtp) /* deletes the first element from a line queue */
int *qhp, /* pointer to the queue head index */
*qtp; /* pointer to the queue tail index */
{
int t;
if (*qhp == -1) /* queue is empty */
return; /* What is there to do with an empty queue? */
else {
t = *qhp;
if ((*qhp = lines[*qhp].nextl) == -1)
*qtp = -1;
freeline(t);
}
}
cm_clearslot(sn) /* clears a section of screen for a user */
int sn; /* slot number to clear */
{
int y; /* y-pos within slot to clear next */
register int i,l;
register int done;
char buf[100];
y = SLT.ypos - SLT.lcount + 1;
if (y<0)
y=y+maxlines;
done = 0;
while (!done) {
if ((l=lines[SLT.lqhead].llen) > 0) {
setpos(0,SLT.topline+y);
if (cleartoend() < 0) { /* then we gotta fake it */
for (i=0;i<l;i++)
buf[i] = ' ';
buf[l] = '\0';
putstr(buf);
}
}
y = (y + 1) % maxlines;
if (SLT.lqhead != SLT.lqtail)
killtopline(sn);
else {
SLT.ypos = 0;
SLT.xpos = 0;
lines[SLT.lqtail].llen = 0;
lines[SLT.lqtail].line[0] = '\0';
done = 1;
}
}
setpos(SLT.xpos,SLT.topline+SLT.ypos);
}
cm_cleartoend(xpos,ypos,len)
int xpos,ypos,len;
{
char buf[100];
register int i;
setpos(xpos,ypos);
if (cleartoend() < 0) {
for (i=0;i<len;i++)
buf[i] = ' ';
buf[len] = '\0';
putstr(buf);
}
}
cm_killcommandline()
{
curslot = MYSLOT;
if (curmcidx == cmdidx) {
cm_cleartoend(0,23,lines[cmdidx].llen); /* clear the line */
curmcidx = -1;
}
freeline(cmdidx);
cmdidx = -1; /* no more command */
oncommandline = 0;
setpos(slots[MYSLOT].xpos,slots[MYSLOT].topline+slots[MYSLOT].ypos);
}
cm_putcommandline()
{
int oldlen;
register int i;
char buf[100];
if (curmcidx == cmdidx)
return; /* no need to put anything out */
if (curmcidx < 0)
oldlen = 0;
else
oldlen = lines[curmcidx].llen;
if (curmcidx == msgqh)
delfromlq(&msgqh,&msgqt); /* get rid of message line */
strcpy(buf,lines[cmdidx].line);
setpos(0,23);
if (strlen(buf) < oldlen && cleartoend() < 0) {
for (i=strlen(buf) ; i < oldlen ; i++)
buf[i] = ' ';
buf[oldlen] = '\0';
}
putstr(buf);
if (strlen(buf) != lines[cmdidx].llen)
setpos(lines[cmdidx].llen,23); /* move to the proper spot */
curmcidx = cmdidx;
}
cm_setupcommandline()
{
cmdidx = allocline();
strcpy(lines[cmdidx].line,prompt);
lines[cmdidx].llen = strlen(prompt);
curslot = -1;
oncommandline = 1;
cm_putcommandline();
}
setcommandpos()
{
if (cmdidx != curmcidx)
setpos(0,23);
else
setpos(lines[cmdidx].llen,23);
}
cm_putcommandcharacter(ch)
char ch;
{
cm_putcommandline(); /* put it out if it isn't already there. */
if (ch < ' ')
switch (ch) {
case 010 :
if (lines[cmdidx].llen > strlen(prompt)) {
putstr("\b \b");
lines[cmdidx].llen--;
lines[cmdidx].line[lines[cmdidx].llen] = '\0';
}
else
beep();
break;
case 012 :
case 015 :
docommand(&lines[cmdidx].line[strlen(prompt)]);
cm_killcommandline();
break;
case 030 :
cm_cleartoend(strlen(prompt),23,lines[cmdidx].llen-strlen(prompt));
lines[cmdidx].line[strlen(prompt)] = '\0';
setpos(strlen(prompt),23);
break;
default :
beep();
break;
}
else if (lines[cmdidx].llen > 78)
beep();
else {
putch(ch);
lines[cmdidx].line[lines[cmdidx].llen] = ch;
lines[cmdidx].llen++;
lines[cmdidx].line[lines[cmdidx].llen] = '\0';
}
}
//E*O*F ttycmio.c//
echo x - ttydumbio.c
cat > "ttydumbio.c" << '//E*O*F ttydumbio.c//'
#include "phone.h"
#include <sys/time.h>
#include <signal.h>
#define REPLOT_C_INTERVAL 18 /* 18 characters between replots */
#define REPLOT_T_INTERVAL 6
int rcvals[MAXSLOT];
int executingcommand = 0; /* indicates that a command is executing */
extern char prompt[]; /* commandline prompt */
extern int cmdidx; /* index of command line in line table */
dumb_announcearrival(sn)
{
char buf[100];
sprintf(buf,"\r\nYou are talking to %s on %s (%s).\r\n",
slots[sn].loginname,
slots[sn].ttyname,
slots[sn].realname);
putstr(buf);
dumb_replot();
}
dumb_announcedeparture(sn)
int sn;
{
char buf[100];
sprintf(buf,"\r\n%s on %s (%s) is leaving the conversation.\r\n",
slots[sn].loginname,
slots[sn].ttyname,
slots[sn].realname);
putstr(buf);
dumb_replot();
}
dumb_putmessage(mess)
char *mess;
{
char buf[100];
if (executingcommand) {
sprintf(buf,"\r\n%s",mess);
putstr(buf);
}
else
{
sprintf(buf,"\r\n%s\r\n",mess);
putstr(buf);
dumb_replot();
}
}
dumb_replot()
{
putstr("\r\n");
if (curslot == -1) {
curslot = MYSLOT; /* fake out putcommandline */
dumb_putcommandline();
}
else {
dumb_putprompt(curslot);
putstr(lines[slots[curslot].lqtail].line);
slots[curslot].xpos += strlen(lines[slots[curslot].lqtail].line);
}
}
dumb_putprompt(sn)
int sn;
{
char buf[100];
if (sn < 0)
return;
if (sn == MYSLOT)
strcpy(buf,">");
else if (nslots == 2)
strcpy(buf,":");
else
sprintf(buf,"%s(%s):",slots[sn].loginname,slots[sn].ttyname);
slots[sn].xpos = strlen(buf);
putstr(buf);
}
dumb_printslots()
{
int i;
int l;
for (i=0;i<MAXSLOT;i++)
if (slots[i].inuse) {
printf("\r\n%s on %s (%s)::\r\n",
slots[i].loginname,
slots[i].ttyname,
slots[i].realname);
l=slots[i].lqhead;
while (l != -1) {
printf("%s\r\n",lines[l].line);
l = lines[l].nextl;
}
}
printf("---\r\n");
dumb_replot();
}
#define SLT slots[sn]
#define NEWSLOT if (curslot >= 0) rcvals[curslot]=0; rcvals[sn]=0; curslot=sn; dumb_replot();
#define PUTCH(c) if (sn == curslot) putch(c);rcvals[sn]++
#define PUTSTR(s) if (sn == curslot) putstr(s);rcvals[sn]++
dumb_puttoscr(sn,ch)
int sn;
char ch;
{
int i;
if (sn != curslot && (rcvals[sn] > REPLOT_C_INTERVAL || sn == MYSLOT)) {
NEWSLOT;
}
if (ch < ' ') {
switch (ch) {
case 007 : /* bell */
if (curslot != sn) {
NEWSLOT
}
beep();
break;
case 010 : /* backspace */
if (SLT.xpos > 0) {
SLT.xpos--;
slt_delcharacter(sn);
PUTSTR("\b \b");
}
break;
case 011 : /* CTRL-I -- tab */
if (SLT.xpos < 72) {
do {
PUTCH(' ');
SLT.xpos++;
slt_addcharacter(sn,' ');
} while (SLT.xpos % 8 != 0);
}
break;
case 012 :
case 015 : /* newline */
if (curslot != sn) {
NEWSLOT
}
PUTSTR("\n");
slt_addbottomline(sn);
SLT.xpos = 0;
dumb_putprompt(sn);
break;
case 014 : /* CTRL-L -- Replot */
if (sn == MYSLOT)
dumb_printslots();
break;
case 016 : /* CTRL-N -- Clear Slot */
/* how do we do this on a hardcopy?? */
break;
case 027 :
/* CTRL-W -- Clear word */
i = strlen(slt_delword(sn,80));
while (i > 0) {
SLT.xpos--;
PUTSTR("\b \b");
i--;
}
break;
case 030 : /* CTRL-X -- Clear Line */
slots[sn].xpos -= lines[SLT.lqtail].llen;
if (sn == curslot) {
int i;
for (i=lines[SLT.lqtail].llen; i > 0; i--)
putstr("\b \b");
}
rcvals[sn]++;
slt_wipeline(sn);
break;
default : /* ignore */
if (sn == MYSLOT)
beep();
break;
}
}
else {
if (SLT.xpos > 78) {
if (sn != curslot) {
NEWSLOT
}
PUTSTR("-\n");
slt_addcharacter(sn,'-');
slt_addbottomline(sn);
SLT.xpos = 0;
dumb_putprompt(sn);
}
PUTCH(ch);
SLT.xpos++;
slt_addcharacter(sn,ch);
}
dumb_starttimer();
}
dumb_newslot()
{
int i;
int midx;
if (curslot == -1)
curslot = MYSLOT; /* can't have it messing up on us */
midx = curslot;
rcvals[midx] = 0;
for (i=0;i<MAXSLOT;i++)
if (slots[i].inuse && rcvals[i] > rcvals[midx])
midx = i;
if (rcvals[midx] > 0) {
curslot = midx;
dumb_replot();
dumb_starttimer();
}
else if (oncommandline && curslot == MYSLOT)
curslot = -1; /* put curslot back if we didn't do anything */
}
dumb_starttimer()
{
struct itimerval tval;
timerclear(&tval.it_interval);
timerclear(&tval.it_value);
tval.it_value.tv_sec = REPLOT_T_INTERVAL;
/* three seconds to read a message */
signal(SIGALRM,dumb_newslot);
setitimer(ITIMER_REAL,&tval,0);
}
dumb_killcommandline()
{
curslot = MYSLOT;
freeline(cmdidx);
oncommandline=0;
dumb_replot();
}
dumb_setupcommandline()
{
cmdidx = allocline();
strcpy(lines[cmdidx].line,prompt);
lines[cmdidx].llen = strlen(prompt);
oncommandline = 1;
dumb_putcommandline();
}
dumb_putcommandline()
{
if (curslot == -1) {
/* Then there's nothing to do */
}
else {
putstr("\r\n");
putstr(lines[cmdidx].line);
curslot = -1;
}
}
dumb_putcommandcharacter(ch)
char ch;
{
int i;
dumb_putcommandline(); /* put out command line if need be */
if (ch < ' ')
switch (ch) {
case 010 :
if (lines[cmdidx].llen > strlen(prompt)) {
putstr("\b \b");
lines[cmdidx].llen--;
lines[cmdidx].line[lines[cmdidx].llen] = '\0';
}
else
beep();
break;
case 012 :
case 015 :
executingcommand = 1;
docommand(&lines[cmdidx].line[strlen(prompt)]);
executingcommand = 0;
dumb_killcommandline();
break;
case 030 :
for (i=lines[cmdidx].llen-strlen(prompt);i>0;i--)
putstr("\b \b");
lines[cmdidx].line[strlen(prompt)] = '\0';
lines[cmdidx].llen = strlen(prompt);
break;
default :
beep();
break;
}
else if (lines[cmdidx].llen > 78)
beep();
else {
putch(ch);
lines[cmdidx].line[lines[cmdidx].llen] = ch;
lines[cmdidx].llen++;
lines[cmdidx].line[lines[cmdidx].llen] = '\0';
}
}
//E*O*F ttydumbio.c//
echo x - ttyio.c
cat > "ttyio.c" << '//E*O*F ttyio.c//'
#include <sys/types.h>
#include <sgtty.h>
#include <signal.h>
#include <errno.h>
#include "phone.h"
static char *_al, /* add new blank line */
*_ce, /* clear to end of line */
*_cl, /* clear screen */
*_cm, /* cursor motion (heavily used) */
*_cs, /* change scrolling region */
*_dl, /* delete line (rest of lines should scroll up) */
*_do, /* down one line */
*_kb, /* sequence sent by backspace key */
*_kd, /* sequence sent by the down arrow key */
*_kl, /* sequence sent by the left arrow key */
*_kr, /* sequence sent by the right arrow key */
*_ku, /* sequence sent by the up arrow key */
*_ke, /* sequence to end cursor key mode */
*_ks, /* sequence to set cursor key mode */
*_nd, /* nondestructive space (cursor right) */
*_nl, /* newline character */
*_se, /* end standout mode */
*_sf, /* scroll forwards */
*_so, /* enter stand out mode */
*_sr, /* scroll reverse */
*_ta, /* tab character (sent) */
*_te, /* string to end programs that use cm */
*_ti, /* string to start programs that use cm */
*_up; /* Upline (cursor up) */
static char tbuf[1024]; /* the buffer needed and used by termlib */
static char area[500]; /* this is the place where all of the strings for
the capabilities above are stored. The capabilities
above are just pointers into this area */
static char *areap; /* area pointer */
static char ttype[40]; /* terminal type found from the environment */
char *UP; /* global variable needed by libtermcap.a
(spec. tgoto) */
short int ospeed; /* the output speed that we're transmitting at */
int ttype_dumb; /* terminal is incapable of moving cursor */
int ttype_scroller; /* terminal can scroll sections */
setrare()
{
struct sgttyb termb;
ioctl(0,TIOCGETP,&termb);
termb.sg_flags |= CBREAK;
termb.sg_flags &= ~ECHO;
ioctl(0,TIOCSETP,&termb);
}
setcooked()
{
struct sgttyb termb;
ioctl(0,TIOCGETP,&termb);
termb.sg_flags &= ~CBREAK;
termb.sg_flags |= ECHO;
ioctl(0,TIOCSETP,&termb);
}
ttyinit()
{
extern int errno;
int tgetent();
char *getenv();
strcpy(ttype,getenv("TERM"));
switch (tgetent(tbuf,ttype)) {
case -1 : printf("Error opening the termcap file\r\n");
printf("Dumb terminal assumed.\r\n");
ttype_dumb = 1;
ttype_scroller = 0;
break;
case 0 : printf("Terminal type not found in termcap file\r\n");
printf("Hardcopy terminal assumed.\r\n");
ttype_dumb = 1;
ttype_scroller = 0;
break;
default : gettermvars();
break;
}
setrare();
}
ttyend() /* cleanup */
{
setcooked();
}
gettermvars()
{
char *tgetstr();
int tgetflag();
areap = area;
_al = tgetstr("al",&areap);
_ce = tgetstr("ce",&areap);
_cl = tgetstr("cl",&areap);
_cm = tgetstr("cm",&areap);
_cs = tgetstr("cs",&areap);
_dl = tgetstr("dl",&areap);
_do = tgetstr("do",&areap);
_kb = tgetstr("kb",&areap);
_kd = tgetstr("kd",&areap);
_kl = tgetstr("kl",&areap);
_kr = tgetstr("kr",&areap);
_ku = tgetstr("ku",&areap);
_ke = tgetstr("ke",&areap);
_ks = tgetstr("ks",&areap);
_nd = tgetstr("nd",&areap);
_nl = tgetstr("nl",&areap);
_se = tgetstr("se",&areap);
_sf = tgetstr("sf",&areap);
_so = tgetstr("so",&areap);
_sr = tgetstr("sr",&areap);
_ta = tgetstr("ta",&areap);
_te = tgetstr("te",&areap);
_ti = tgetstr("ti",&areap);
_up = tgetstr("up",&areap);
UP = _up;
ttype_dumb = (_cm == 0 || _cl == 0);
ttype_scroller = (_cs != 0 || (_al != 0 && _dl != 0));
}
getch()
{
char ch;
read(1,&ch,1);
return(ch);
}
putch(c)
char c;
{
write(1,&c,1);
}
putstr(s)
char *s;
{
char buf[150];
int l = 0;
while (*s)
buf[l++] = (*s++);
write(1,buf,l);
}
beep()
{
putch(7);
}
clearscreen()
{
if (_cl != 0)
tputs(_cl,1,putch);
}
static char tempstr[150],*tsp;
static addtempc(c)
char c;
{
*tsp++ = c;
*tsp = '\0';
}
#define isdigit(c) ('0' <= (c) && (c) <= '9')
static my_tputs(cp) /* ignores padding..puts stuff in tempstr */
register char *cp;
{
if (cp == 0)
return;
while (isdigit(*cp))
cp++;
if (*cp == '.')
cp++;
while (isdigit(*cp))
cp++;
if (*cp == '*')
cp++;
while (*tsp++ = *cp++);
tsp--;
}
setpos(xpos,ypos)
int xpos,ypos;
{
char *tgoto();
tsp = tempstr;
*tsp = '\0';
if (_cm != 0) {
my_tputs(tgoto(_cm,xpos,ypos));
putstr(tempstr);
}
}
cleartoend()
{
int i;
if (_ce == 0)
return -1;
else {
tputs(_ce,1,putch);
return 0;
}
}
/*
* The following routine scrolls a range of lines up
*/
scrollup(top,bottom)
int top,bottom;
{
char *tgoto();
tsp = tempstr;
*tsp = '\0';
if (_cs != 0) {
my_tputs(tgoto(_cs,bottom,top));
my_tputs(tgoto(_cm,0,bottom));
my_tputs("\n");
my_tputs(tgoto(_cs,23,0));
putstr(tempstr);
}
else {
my_tputs(tgoto(_cm,0,top));
my_tputs(_dl);
my_tputs(tgoto(_cm,0,bottom));
my_tputs(_al);
putstr(tempstr);
}
}
//E*O*F ttyio.c//
echo Possible errors detected by \'wc\' [hopefully none]:
temp=/tmp/shar$$
trap "rm -f $temp; exit" 0 1 2 3 15
cat > $temp <<\!!!
54 145 1338 Makefile
235 793 5820 cparse.c
110 501 4569 cparse.h
78 270 2185 getuser.c
81 417 2406 phone.1
117 319 2879 phone.c
65 296 2150 phone.h
675 2191 16850 phoned.c
231 624 5013 phonemain.c
260 623 6185 phoneparse.c
286 964 6522 slotmanager.c
513 1318 11015 ttycmio.c
308 702 6351 ttydumbio.c
246 683 5135 ttyio.c
3259 9846 78418 total
!!!
wc Makefile cparse.c cparse.h getuser.c phone.1 phone.c phone.h phoned.c phonemain.c phoneparse.c slotmanager.c ttycmio.c ttydumbio.c ttyio.c | sed 's=[^ ]*/==' | diff -b $temp -
exit 0
More information about the Comp.sources.unix
mailing list