source to "phone" system (part 3 of 4)
Jonathan C. Broome
broome at ucbvax.BERKELEY.EDU
Sun Dec 29 18:42:27 AEST 1985
#-----cut here-----cut here-----cut here-----cut here-----
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
# Makefile
# defs.h
# ../common.h
# child.c
# daemon.c
# dopage.c
# forward_program.c
# inquire.c
# list.c
# main.c
# page.c
# pagetty.c
# reinvite.c
# strsave.c
# utmp.c
# This archive created: Sat Dec 28 01:11:09 1985
export PATH; PATH=/bin:$PATH
mkdir master
cd master
echo shar: extracting "'Makefile'" '(4014 characters)'
if test -f 'Makefile'
then
echo shar: will not over-write existing file "'Makefile'"
else
cat << \!Funky!Stuff! > 'Makefile'
#
# Makefile for phoned 20 December 1985
#
# What the flags mean:
# INETD - set this if the phoned is to run a a single-threaded service
# under /etc/inetd. It expects for fd 0 to be a datagram socket
# bound to the service address that it wil receive from.
# FORK - set this when *not* under inetd if you want to server to
# fork upon startup, with the parent exiting. This is usually
# set, and does nothing if INETD is also defined.
# DPATH - the full pathanme of the conversation daemon. If phoned
# cannot find it here, it will try to find "convd" in
# /usr/local/lib, /usr/lib, and /etc.
# SERVICES - set this if phone is listed as a datagram service in
# /etc/services. This has no effect under the inetd.
# PORT - if INETD and SERVICES are not defined, this is the port
# number to listen on (overriding the default in ../common.h)
# NO_WHO - Define this if you want your site to be "secure" and not allow
# outside users to use the "who" command to see who's on ...
#CFLAGS = -O -DDPATH=\"/usr/local/lib/convd\"
CFLAGS = -O -DINETD -DDPATH=\"/usr/local/lib/convd\"
LPR = lpr -Pvax
HDRS = defs.h ../common.h
SRCS = child.c daemon.c dopage.c forward_program.c\
inquire.c list.c main.c page.c pagetty.c\
reinvite.c strsave.c utmp.c
OBJS = child.o daemon.o dopage.o forward_program.c\
inquire.o list.o main.o page.o pagetty.o\
reinvite.o strsave.o utmp.o
DEST = phoned
RDEST = /etc/phoned
.DEFAULT:
co $<
all: ${DEST}
${DEST}: ${OBJS}
/bin/rm -f ${DEST}
cc ${CFLAGS} -o ${DEST} ${OBJS}
${OBJS}: ${HDRS}
install: ${DEST}
/bin/rm -f ${RDEST}
cp ${DEST} ${RDEST}
clean:
/bin/rm -f ${DEST} core *.o
print: ${HDRS} ${SRCS}
pr -f ${HDRS} ${SRCS} | expand -4 | ${LPR}
tags: /dev/null
ctags -w ${HDRS} ${SRCS}
lint: ${HDRS} ${SRCS}
lint ${SRCS} > lint.out
shar: Makefile ${HDRS} ${SRCS}
shar -v Makefile ${HDRS} ${SRCS} > ../shar.master
dist: ${DEST}
-rcp ${DEST} buddy:${RDEST}
-rcp ${DEST} franny:${RDEST}
-rcp ${DEST} holden:${RDEST}
-rcp ${DEST} seymour:${RDEST}
-rcp ${DEST} zooey:${RDEST}
-rcp ${DEST} cory:${RDEST}
-rcp ${DEST} miro:${RDEST}
depend: ${SRCS}
mv Makefile makefile.old
sed '/^# Dependencies follow/,$$d' makefile.old > Makefile
echo '# Dependencies follow' >> Makefile
includes -so ${SRCS} >> Makefile
echo ' ' >> Makefile
echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >> Makefile
echo '# see depend: above' >> Makefile
# DO NOT DELETE THE FOLLOWING LINE
# Dependencies follow
utmp.o: /usr/include/utmp.h
utmp.o pagetty.o: /usr/include/sys/file.h
page.o main.o: /usr/include/netdb.h
main.o list.o: /usr/include/signal.h
pagetty.o page.o list.o: /usr/include/time.h
pagetty.o page.o list.o: /usr/include/sys/time.h
page.o forward_program.o: /usr/include/pwd.h
utmp.o dopage.o: /usr/include/sys/stat.h
pagetty.o main.o daemon.o: /usr/include/syslog.h
child.o: /usr/include/sys/wait.h
utmp.o reinvite.o pagetty.o page.o main.o list.o inquire.o forward_program.o \
dopage.o daemon.o child.o: /usr/include/errno.h
utmp.o reinvite.o pagetty.o pagetty.o page.o main.o main.o list.o list.o \
inquire.o forward_program.o dopage.o daemon.o daemon.o child.o: \
/usr/include/stdio.h
utmp.o reinvite.o pagetty.o page.o main.o list.o inquire.o forward_program.o \
dopage.o daemon.o child.o: /usr/include/netinet/in.h
utmp.o reinvite.o pagetty.o page.o main.o list.o inquire.o forward_program.o \
dopage.o daemon.o child.o: /usr/include/sys/socket.h
utmp.o reinvite.o pagetty.o page.o main.o list.o inquire.o forward_program.o \
dopage.o daemon.o child.o: /usr/include/sys/types.h
utmp.o reinvite.o pagetty.o page.o main.o list.o inquire.o forward_program.o \
dopage.o daemon.o child.o: ./defs.h
utmp.o reinvite.o pagetty.o page.o main.o list.o inquire.o dopage.o daemon.o \
child.o: ./../common.h
# IF YOU PUT STUFF HERE IT WILL GO AWAY
# see depend: above
!Funky!Stuff!
fi # end of overwriting check
echo shar: extracting "'defs.h'" '(2842 characters)'
if test -f 'defs.h'
then
echo shar: will not over-write existing file "'defs.h'"
else
cat << \!Funky!Stuff! > 'defs.h'
/*
* $Header: defs.h,v 1.1 85/10/28 17:38:15 broome Exp $
*/
/*
* $Log: defs.h,v $
* Revision 1.1 85/10/28 17:38:15 broome
* Initial revision
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <errno.h>
#define SOCKADDR struct sockaddr_in /* shorter to type */
/*
* One of these structures is used for each pending invitation.
*/
struct invite {
/* info about the person requesting a call */
char *caller; /* login name of person making invitation */
char *host; /* figured out from control port address */
SOCKADDR ctladdr; /* inviter's control port address */
char *convaddr; /* inviter's conversation port address */
char *callno; /* unique per-user message id from caller */
/* info about the person being requested */
char *callee; /* login name of person being requested */
char *tty; /* user's tty, if any */
char *ptty; /* tty we are actually paging */
char *home; /* his home directory */
int uid, gid; /* used for forwarding programs */
/* and bookkeeping information about the invitation itself */
int type; /* normal page or being forwarded? */
int rings; /* send a new ring when rings == 0 */
int pid; /* child notification pid */
int flags; /* various stuff about status */
char id[10]; /* identification for this request */
struct invite *prev; /* previous in doubly-linked list */
struct invite *next; /* next most recent invitation */
};
typedef struct invite INV;
#define NIL ((INV *) 0)
#define eq(a,b) (strcmp(a,b) == 0)
/* often-used functions */
char *malloc();
char *strsave();
char *findtty();
INV *lookup();
#define SIZ 512
char host[32]; /* name of this host */
char buf[SIZ]; /* general-purpose buffer */
extern int errno;
int misc; /* socket used to send out */
/* Error return values from paging routines */
#define NOT_HERE 1
#define ERR 3
#define THRESHOLD (60*10) /* ten minutes */
#define PROG (1<<0) /* was forwarded to a program */
#define FORWARD (1<<1) /* forwarded to another user/host */
#define DONTFORWARD (1<<2) /* forwarding failed - don't forward */
#define NOT_ON (1<<3) /* user is not logged on */
#define MESG_OFF (1<<4) /* user is refusing messages */
#define BUSYFILE "/.busy" /* name of forwarding file */
INV *invitations; /* list of pending invitations */
INV *freelist; /* list of free invite structs */
!Funky!Stuff!
fi # end of overwriting check
echo shar: extracting "'../common.h'" '(1266 characters)'
if test -f '../common.h'
then
echo shar: will not over-write existing file "'../common.h'"
else
cat << \!Funky!Stuff! > '../common.h'
/*
* Defines common to all the parts of the phone system.
*/
#ifndef ESC
#define ESC '\033' /* precedes all commands */
#endif
#define ACK 'y' /* good response code */
#define NAK 'n' /* not-so-good code */
/*
* Commands sent from conversation daemon to client.
*/
#define META 0200 /* high bit for command characters */
#define ADDUSER (01<<5) /* add a user to the conversation */
#define DELUSER (02<<5) /* delete a user from conversation */
#define UPDATE (03<<5) /* set screen update mode */
/*
* Commands sent from or master daemon to client.
*/
#define MESSAGE 'M' /* following is message text */
/*
* Commands sent by client to conversation or master daemons.
*/
#define ANSWER 'A' /* he got the invite, will answer */
#define CALLING 'C' /* daemon is calling the user */
#define PAGE 'P' /* page a user */
#define INQUIRE 'I' /* inquire as to whether invited */
#define REINVITE 'R' /* renew a request for paging */
#define DAEMON 'D' /* create a daemon for me */
#define WHO 'W' /* tell me who's on ... */
#define KILL 'K' /* cause the daemon to exit */
#ifndef PORT
#define PORT 1167
#endif
!Funky!Stuff!
fi # end of overwriting check
echo shar: extracting "'child.c'" '(1702 characters)'
if test -f 'child.c'
then
echo shar: will not over-write existing file "'child.c'"
else
cat << \!Funky!Stuff! > 'child.c'
#ifndef lint
static char RCSid[] = "$Header: child.c,v 1.1 85/10/28 17:38:11 broome Exp $";
#endif
/*
* $Log: child.c,v $
* Revision 1.1 85/10/28 17:38:11 broome
* Initial revision
*/
#include "../common.h"
#include "defs.h"
#include <sys/wait.h>
/*
* A more complicated sigchld handler -
* looks for the pid in the list of invitations
* and sends appropriate status messages to the callers.
*/
sigchld ()
{
register INV *inv;
union wait status;
char mbuf[SIZ];
int pid;
int exitstat;
while ((pid = wait3 (&status, WNOHANG, 0)) > 0) { /* any children? */
if (WIFSTOPPED (status)) { /* shouldn't happen */
kill (pid, 9);
exitstat = 1;
} else
exitstat = status.w_retcode;
for (inv = invitations; inv; inv = inv->next)
if (inv->pid == pid) /* does pid match? */
break;
if (inv->pid != pid) /* didn't find child - continue */
continue;
if (exitstat && (inv->flags & PROG)) /* their program has problems */
inv->flags |= DONTFORWARD;
/*
* Now send a message to the user.
* The multiple sprintf()'s aren't very pretty ...
*/
if (exitstat == 0) { /* good exit status - ok */
sprintf (buf, "%s%sing user %s@%s",
inv->id, (inv->flags & PROG) ? "Forward" : "Ring",
inv->callee, host);
if ((inv->flags & PROG) == 0) {
strcat (buf, " on ");
strcat (buf, inv->ptty);
}
} else {
sprintf (buf, "%sCannot ring %s@%s - Unknown error",
inv->id, inv->callee, host);
}
sprintf (mbuf, "%c%c%c%s", ESC, CALLING, exitstat ? NAK : ACK, buf);
if (sendto (misc, mbuf, strlen (mbuf), 0, &inv->ctladdr,
sizeof (inv->ctladdr)) < 0)
perror ("child: sendto");
}
}
!Funky!Stuff!
fi # end of overwriting check
echo shar: extracting "'daemon.c'" '(2810 characters)'
if test -f 'daemon.c'
then
echo shar: will not over-write existing file "'daemon.c'"
else
cat << \!Funky!Stuff! > 'daemon.c'
#ifndef lint
static char RCSid[] = "$Header: daemon.c,v 1.1 85/10/28 17:38:13 broome Exp $";
#endif
/*
* $Log: daemon.c,v $
* Revision 1.1 85/10/28 17:38:13 broome
* Initial revision
*
*/
#include "../common.h"
#include "defs.h"
#include <stdio.h>
#include <syslog.h>
/*
* The guy wants a daemon, so give him one ...
*/
daemon (addr)
struct sockaddr_in addr;
{
struct sockaddr_in sin; /* address of new daemon */
extern char myaddr[]; /* address of this host */
char *error();
int sock;
int pid;
int i, len;
if ((sock = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
sprintf (buf, "%c%c%cCannot create socket: %s",
ESC, DAEMON, NAK, error());
sendto (misc, buf, strlen (buf), 0, &addr, sizeof (addr));
return;
}
i = 1;
if (setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, &i, sizeof (i)))
syslog (LOG_ERR, "daemon: setsockopt: %m");
bzero ((char *)&sin, sizeof (sin));
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = 0;
sin.sin_family = AF_INET;
len = sizeof (sin);
if (bind (sock, &sin, len) < 0) {
sprintf (buf,"%c%c%cCannot bind socket: %s", ESC, DAEMON, NAK, error());
sendto (misc, buf, strlen (buf), 0, &addr, sizeof (addr));
return;
}
if (pid = fork ()) { /* parent */
if (pid == -1) { /* failed */
sprintf (buf, "%c%c%cFork failed: %s", ESC, DAEMON, NAK, error());
sendto (misc, buf, strlen (buf), 0, &addr, sizeof (addr));
}
(void) close (sock);
return;
}
len = sizeof (sin);
if (getsockname (sock, &sin, &len) < 0) {
sprintf (buf, "%c%c%cCannot get socket name: %s",
ESC, DAEMON, NAK, error());
(void) sendto (misc, buf, strlen (buf), 0, &addr, sizeof (addr));
_exit (1);
}
/* life is good */
sprintf (buf,"%c%c%c%s/%d", ESC, DAEMON, ACK, myaddr, ntohs (sin.sin_port));
sendto (misc, buf, strlen (buf), 0, &addr, sizeof (addr));
listen (sock, 5);
if (sock != 0)
if (dup2 (sock, 0)) { /* set socket to be stdin */
perror ("dup2");
syslog (LOG_ERR, "daemon: dup2 failed: %m");
}
for (i = 1; i < getdtablesize(); i++) /* close anything else */
(void) close (i);
#ifdef DPATH /* sure hope this is it! */
execl (DPATH, "convd", 0);
#else !DPATH
execl ("/usr/local/lib/convd", "convd", 0);
execl ("/usr/lib/convd", "convd", 0);
execl ("/etc/convd", "convd", 0);
#endif DPATH
#ifdef DPATH
syslog (LOG_ERR, "cannot execl %s: %m", DPATH);
#else
syslog (LOG_ERR, "cannot execl convd: %m");
#endif
sprintf (buf, "%c%c%cExecl failed: %s", ESC, DAEMON, NAK, error());
sendto (misc, buf, strlen (buf), 0, &addr, sizeof (addr));
_exit (-99);
}
/*
* Return a string with the error message.
*/
char *
error ()
{
extern int errno;
extern char *sys_errlist[];
extern int sys_nerr;
if (errno > sys_nerr)
return ("Unknown error.");
else
return (sys_errlist[errno]);
}
!Funky!Stuff!
fi # end of overwriting check
echo shar: extracting "'dopage.c'" '(1924 characters)'
if test -f 'dopage.c'
then
echo shar: will not over-write existing file "'dopage.c'"
else
cat << \!Funky!Stuff! > 'dopage.c'
#ifndef lint
static char RCSid[] = "$Header: dopage.c,v 1.1 85/10/28 17:38:16 broome Exp $";
#endif
/*
* $Log: dopage.c,v $
* Revision 1.1 85/10/28 17:38:16 broome
* Initial revision
*/
#include "../common.h"
#include "defs.h"
#include <sys/stat.h>
/*
* Handle paging one user - one invitation.
* Checks for ~/.busy, tries to do
* the right thing.
*/
_dopage (inv)
INV *inv;
{
FILE *fp; /* forward file */
char *tty; /* tty they're on */
int pid; /* child process */
int mode; /* tty status */
struct stat statb;
/*
* We won't check for forwarding if it has failed already.
* We also make sure that home isn't null - otherwise unknown
* users might be able to take advantage of root somehow ...
*/
if ((inv->flags & DONTFORWARD) == 0 && inv->home) {
strcpy (buf, inv->home);
strcat (buf, BUSYFILE);
if (stat (buf, &statb) == 0 && (statb.st_mode & (04<<3)) &&
statb.st_uid == inv->uid && (fp = fopen (buf, "r"))) {
/* file exists */
while (fgets (buf, SIZ, fp)) /* read a line */
if (*buf != '\n' && *buf != '#')
break;
fclose (fp);
if (*buf == '/' || *buf == '~') /* path to program */
return (forward_program (buf, inv)); /* so invoke it */
}
}
inv->flags &= ~PROG;
/*
* If we're here, we didn't forward it, so look for them
* on a tty and send a message to their terminal.
*/
tty = findtty (inv->callee, inv->tty, &mode);
if (mode == NOT_ON)
return (NOT_ON);
if (inv->ptty)
free (inv->ptty);
inv->ptty = strsave (tty+5); /* save name of tty being paged */
if (mode == MESG_OFF)
return (MESG_OFF);
if (pid = fork ()) { /* parent */
if (pid == -1) { /* fork failed */
perror ("fork");
inv->rings = 0; /* so try again next time */
} else
inv->pid = pid; /* save child's id */
return (0);
}
pagetty (inv, tty); /* child - do it */
/*NOTREACHED*/
}
!Funky!Stuff!
fi # end of overwriting check
echo shar: extracting "'forward_program.c'" '(3308 characters)'
if test -f 'forward_program.c'
then
echo shar: will not over-write existing file "'forward_program.c'"
else
cat << \!Funky!Stuff! > 'forward_program.c'
#ifndef lint
static char RCSid[] = "$Header: forward_program.c,v 1.1 85/10/28 17:38:17 broome Exp $";
#endif
/*
* $Log: forward_program.c,v $
* Revision 1.1 85/10/28 17:38:17 broome
* Initial revision
*/
#include "defs.h"
#include <pwd.h>
/*
* Take the pathname of a forwarding program
* and start it up.
*
* Features: the ability to give a printf-like
* format string to fill in with the caller and such.
*
* "%R" - name of recipient
* "%C" - name of caller
* "%H" - caller's host
*/
forward_program (buf, inv)
char *buf;
INV *inv;
{
int pid; /* child process */
int fd; /* fds to close */
int argc; /* count of words in command */
char *argv[32]; /* command in forward file */
inv->flags |= PROG; /* mark as being piped */
if (pid = fork()) { /* parent returns immediately */
if (pid == -1) /* fork failed */
inv->rings = 0; /* try again next time */
else
inv->pid = pid; /* save process id */
return (0);
}
/*
* We're the child process, so clean up
* and exec the program.
*/
sigblock (0); /* ignore all signals */
if (argc = expand (buf, argv, inv)) { /* it contains something */
setgid (inv->gid); /* set up permissions */
initgroups (inv->callee, inv->gid);
setuid (inv->uid); /* ... fix security */
for (fd = 0; fd < getdtablesize(); fd++) /* clean up */
(void) close (fd);
execv (argv[0], argv); /* and do it */
_exit (-99); /* bad format?? */
}
}
/*
* Given a line from the .phonerc file, expand ~user and also '%'
* substitutions (like printf) and parse into an argument vector.
*
* We use a static buffer to stick the string sinto, so as to
* avoid the malloc/free-in-interrupt routine problem.
*
* The allowed '%' substitutions are:
*
* "%R" - name of the recipient.
* "%C" - name of the calling party.
* "%H" - calling party's host.
*/
expand (inbuf, argp, inv)
char *inbuf;
char **argp;
INV *inv;
{
struct passwd *pwd;
static char outbuf[10240];
register char *i;
register char *o;
register char *n;
char *start;
char name[32];
int first;
char **ap;
i = inbuf;
o = outbuf;
ap = argp;
while (*i) {
start = o; /* save front of this word */
while (*i && *i == ' ' || *i == '\t')
i++;
for (first = 1; *i && *i != ' ' && *i != '\t'; i++) {
if (*i == '~' && first) { /* ~user */
for (i++, n = name; *i && *i != '/' && *i != ' ' && *i != '\t';)
*n++ = *i++;
i--;
*n = '\0';
if (*name == '\0') { /* use $HOME */
n = inv->home;
} else { /* lookup user in passwd file */
if (pwd = getpwnam (name))
n = pwd->pw_dir;
else
n = (char *) 0;
}
while (n && *n) /* copy dir over */
*o++ = *n++;
} else if (*i == '%') { /* do printf-like stuff */
switch (*++i) {
case 'R': n = inv->callee; /* recipient */
break;
case 'C': n = inv->caller; /* caller */
break;
case 'H': n = inv->host; /* calling host */
break;
case '%': n = "%"; /* normal percent */
break;
}
while (n && *n)
(*o++ = *n++);
} else
*o++ = *i;
}
*o++ = '\0';
if (*start != '\0')
*ap++ = start;
}
*ap = (char *) 0;
return (ap - argp);
}
!Funky!Stuff!
fi # end of overwriting check
echo shar: extracting "'inquire.c'" '(1200 characters)'
if test -f 'inquire.c'
then
echo shar: will not over-write existing file "'inquire.c'"
else
cat << \!Funky!Stuff! > 'inquire.c'
#ifndef lint
static char RCSid[] = "$Header: inquire.c,v 1.1 85/10/28 17:38:21 broome Exp $";
#endif
/*
* $Log: inquire.c,v $
* Revision 1.1 85/10/28 17:38:21 broome
* Initial revision
*/
#include "../common.h"
#include "defs.h"
/*
* Check to see if there are any pending calls for this user,
* send back the first address and delete the invite if any are found.
*/
inquire (argv, sin)
char *argv[];
struct sockaddr_in sin;
{
INV *inv;
if (inv = lookup (argv[0], argv[1])) { /* had one pending */
sprintf (buf, "%c%c%c%s", ESC, INQUIRE, ACK, inv->convaddr);
delete (inv);
} else
sprintf (buf, "%c%c%cNo messages pending.", ESC, INQUIRE, NAK);
sendto (misc, buf, strlen (buf), 0, &sin, sizeof (sin));
}
/*
* They say they answered the call, so delete it from the list.
* This routine is for future use - not used now ...
*/
answer (argv)
char *argv[];
{
INV *inv;
for (inv = invitations; inv; inv = inv->next)
if (eq (argv[0], inv->callee) && eq (argv[1], inv->convaddr)) {
sprintf (buf, "%c%c%c%s", ESC, ANSWER, ACK, inv->id);
(void) sendto (misc, buf, strlen(buf), 0, &inv->ctladdr,
sizeof (inv->ctladdr));
delete (inv);
return;
}
}
!Funky!Stuff!
fi # end of overwriting check
echo shar: extracting "'list.c'" '(3769 characters)'
if test -f 'list.c'
then
echo shar: will not over-write existing file "'list.c'"
else
cat << \!Funky!Stuff! > 'list.c'
#ifndef lint
static char RCSid[] = "$Header: list.c,v 1.1 85/10/28 17:38:22 broome Exp $";
#endif
/*
* Routines for managing the list of pending calls, including
* creating and looking for invitations.
*/
/*
* $Log: list.c,v $
* Revision 1.1 85/10/28 17:38:22 broome
* Initial revision
*/
#include "../common.h"
#include "defs.h"
#include <sys/time.h>
#include <signal.h>
#include <stdio.h>
static int requests = 0; /* number of pending invitations */
/*
* Insert a request into the pending list.
*/
insert (inv)
INV *inv;
{
/* insert into top of list */
if (invitations == NIL) {
inv->next = NIL;
invitations = inv;
} else {
inv->next = invitations;
invitations->prev = inv;
invitations = inv;
}
if (requests++ == 0) /* need to set alarm interrupt */
alarm (1); /* so start up alarm */
}
/*
* Called on SIGALRM to process pending calls ---
* go through the list of pending invitations, removing any old
* ones, trying to ring the rest.
*/
ring ()
{
register INV *inv;
register INV *next;
if (!requests) /* no pending requests **/
return;
readutmp (); /* reread /etc/utmp */
for (inv = invitations; inv; inv = next) {
next = inv->next; /* save the next one */
if (inv->rings++ == 0) /* time to page this one ??? */
dopage (inv); /* I guess so ... */
else if (inv->rings > 30) /* more than five minutes old */
delete (inv);
}
if (requests > 0) /* any requests left ??? */
alarm (5); /* set the next alarm */
#ifdef INET /* if running under inetd, exit when no more work to do */
else
exit (0);
#endif INETD
}
/*
* Page the given invitation and return a status message.
* Notice the incredible amount of indirection going on here -
* up to three (or is it four) levels !! Have to clean this up
* when we get forwarding working properly.
*/
dopage (inv)
INV *inv;
{
char rbuf[10];
int ret;
char *name;
char *tty;
name = inv->callee;
ret = _dopage (inv);
sprintf (rbuf, "%c%c%c%s", ESC, CALLING, NAK, inv->id);
if (ret == 0) /* all looks to be good */
return;
if (ret == MESG_OFF)
sprintf (buf, "%s%s@%s is refusing messages", rbuf, name, host);
else if (ret == NOT_ON)
sprintf (buf, "%s%s@%s is not logged in", rbuf, name, host);
if ((tty = inv->tty) && *tty) {
strcat (buf, " on ");
strcat (buf, tty);
}
delete (inv);
sendto (misc, buf, strlen (buf), 0, &inv->ctladdr, sizeof (inv->ctladdr));
}
/*
* Check to see if the named user is being invited by the right person.
* Returns a pointer to the invitation in question.
*
* A wildcard "*" is acceptable as the caller name - this is
* useful for answering machine programs.
*/
INV *
lookup (callee, caller)
char *callee, *caller;
{
register INV *inv;
register int all = (eq (caller, "*"));
for (inv = invitations; inv; inv = inv->next) {
if (all || eq (inv->caller, caller)) /* caller match */
if (eq (callee, inv->callee)) /* callee match */
return (inv);
}
return (NIL);
}
/*
* The usual linked-list deletion routine, with a minor
* difference - instead of deallocating the space, we simply
* place the element on a free list for future use (LIFO form)
*/
delete (ptr)
INV *ptr;
{
requests--; /* decrement number pending */
if (ptr->prev)
ptr->prev->next = ptr->next; /* set previous's next pointer */
else
invitations = ptr->next;
if (ptr->next)
ptr->next->prev = ptr->prev; /* set next's previous pointer */
ptr->next = freelist; /* add on tail of free list */
freelist = ptr; /* and make this the top */
}
!Funky!Stuff!
fi # end of overwriting check
echo shar: extracting "'main.c'" '(4574 characters)'
if test -f 'main.c'
then
echo shar: will not over-write existing file "'main.c'"
else
cat << \!Funky!Stuff! > 'main.c'
#ifndef lint
static char RCSid[] = "$Header: main.c,v 1.1 85/10/28 17:38:28 broome Exp $";
#endif
/*
* $Log: main.c,v $
* Revision 1.1 85/10/28 17:38:28 broome
* Initial revision
*
*/
#include "../common.h"
#include "defs.h"
#include <signal.h>
#include <stdio.h>
#include <syslog.h>
#include <netdb.h>
#ifdef FORK
#include <sys/ioctl.h>
#endif
char myaddr[20]; /* internet host address in ascii dot notation */
/*
* Master phone daemon, sits on known socket address and
* listens for requests... Handles invitations, acts as
* central clearinghouse for conversations.
*/
main (argc, argv)
int argc;
char *argv[];
{
#if defined(SERVICES) && !defined(INETD)
struct servent *sp, *getservbyname();
#endif
struct sockaddr_in sin;
struct hostent *hp, *gethostbyname();
extern int ring();
extern int sigchld();
int sock;
#ifndef INETD
int port = PORT;
#endif
int tty, i;
invitations = NIL;
freelist = NIL;
#ifdef INETD
if (argc != 1) {
fprintf (stderr, "%s takes no options!\n", argv[0]);
exit (1);
}
#else !INETD
if (argc > 2) {
fprintf (stderr, "Usage: %s [ port# ]\n", argv[0]);
exit (1);
}
#endif INETD
#ifndef INETD
if (argc == 2) {
if ((port = atoi (argv[1])) == 0) {
fprintf (stderr, "Bad port number: %s\n", argv[1]);
exit (1);
}
}
#endif INETD
#if defined(SERVICES) && !defined(INETD)
else {
if ((sp = getservbyname ("phone", "udp")) == (struct servent *) 0) {
fprintf (stderr, "phone/udp: unknown service.\n");
exit (1);
}
port = sp->s_port;
}
#endif SERVICES
#ifndef INETD
/* Open and initialize the socket we will take requests on */
if ((sock = socket (AF_INET, SOCK_DGRAM, 0)) < 0) {
perror ("Cannot create datagram socket");
exit (2);
}
bzero ((char *)&sin, sizeof (sin));
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = htons (port);
sin.sin_family = AF_INET;
if (bind (sock, &sin, sizeof (sin))) {
perror ("Cannot bind datagram socket");
exit (3);
}
#else INETD
sock = 0; /* inetd hands us the first packet on stdin */
#endif INETD
/* Initialize the work socket as well */
if ((misc = socket (AF_INET, SOCK_DGRAM, 0)) < 0) {
perror ("Cannot create datagram work socket");
exit (4);
}
bzero ((char *)&sin, sizeof (sin));
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = 0;
sin.sin_family = AF_INET;
if (bind (misc, &sin, sizeof (sin))) {
perror ("Cannot bind datagram work socket");
exit (5);
}
signal (SIGCHLD, sigchld);
signal (SIGALRM, ring);
gethostname (host, 32);
if ((hp = gethostbyname (host)) == (struct hostent *) 0) {
fprintf (stderr, "%s: cannot find my own address!!!\n", argv[0]);
exit (6);
}
bcopy ((char *)hp->h_addr, (char *)&sin.sin_addr, hp->h_length);
strcpy (myaddr, inet_ntoa (sin.sin_addr.s_addr));
#if defined(FORK) && !defined(INETD)
if (fork ())
exit (0);
if (sock != 0)
close (0);
i = open ("/dev/null", 0);
if (sock != 1)
dup2 (i, 1);
if (sock != 2)
dup2 (i, 2);
if ((tty = open ("/dev/tty", 0)) != -1) {
ioctl (tty, TIOCNOTTY);
close (tty);
} else
setpgrp (0, getpid ());
#endif FORK && !INETD
#ifdef LOG_ODELAY
openlog ("phoned", LOG_PID | LOG_ODELAY, 0);
#else
openlog ("phoned", LOG_PID, 0);
#endif
openutmp ();
service (sock);
exit (0);
}
/*
* Main service routine.
* Listen on the socket, process requests.
*/
service (sock)
register int sock;
{
int mask; /* can't be in a register ... darn */
int len;
register int omask;
register int rval;
register char *av[10];
register char buf[SIZ];
register int i;
struct sockaddr_in sin;
omask = 1 << sock;
for ( ;; ) {
mask = omask;
if (select (32, &mask, 0, 0, 0) <= 0)
continue;
len = sizeof (sin);
if ((rval = recvfrom (sock, buf, SIZ, 0, &sin, &len)) <= 0) {
syslog (LOG_ERR, "recvfrom: %m");
continue;
}
if (*buf != ESC)
continue;
buf[rval] = '\0';
parse (buf+2, av);
switch (buf[1]) { /* figure out command */
case PAGE: page (av, sin); break;
case REINVITE: reinvite (av, sin); break;
case INQUIRE: inquire (av, sin); break;
case ANSWER: answer (av); break;
case DAEMON: daemon (sin); break;
case WHO: who (sin); break;
case KILL: exit (0); break;
}
}
}
/*
* Parse the buffer into an argument vector.
*/
parse (buf, argv)
char *buf;
char **argv;
{
register char **ap;
register char *b;
ap = argv;
for (b = buf; b && *b && *b != '\n'; ) {
*ap++ = b;
for ( ; b && *b && *b != ':' && *b != '\n'; b++)
;
*b++ = '\0';
}
*ap = (char *) 0;
return (ap - argv);
}
!Funky!Stuff!
fi # end of overwriting check
echo shar: extracting "'page.c'" '(3334 characters)'
if test -f 'page.c'
then
echo shar: will not over-write existing file "'page.c'"
else
cat << \!Funky!Stuff! > 'page.c'
#ifndef lint
static char RCSid[] = "$Header: page.c,v 1.1 85/10/28 17:38:29 broome Exp $";
#endif
/*
* $Log: page.c,v $
* Revision 1.1 85/10/28 17:38:29 broome
* Initial revision
*
*/
#include "../common.h"
#include "defs.h"
#include <netdb.h>
#include <pwd.h>
#include <sys/time.h>
/*
* He wants us to page someone...
*
* argv points to array like this: "callno : callee:tty:caller:conv_addr"
*
* If we already have a call from the same address with the same call
* number then we assume it's a retransmission and just resend the
* same message-id (the one generated by us) and hope it will make
* it to them.
*
* We try to get the user's password entry so that we can
* look for a .busy forwarding file when we actually ring him.
*/
page (argv, sin)
char *argv[];
struct sockaddr_in sin;
{
long now;
register INV *new;
INV *seenit();
struct passwd *pw, *getpwnam();
struct hostent *hp, *gethostbyaddr();
/* first check to see if we already have the request */
if (new = seenit (argv[0], sin)) {
(void) sprintf (buf, "%c%c%c%s", ESC, PAGE, ACK, new->id);
(void) sendto (misc, buf, strlen (buf), 0, &sin, sizeof (sin));
return;
}
if (freelist) {
new = freelist; /* grab one from existing list */
freelist = new->next;
free (new->caller); /* deallocate space from last time */
free (new->callee);
free (new->host);
free (new->home);
free (new->tty);
free (new->convaddr);
if (new->ptty)
free (new->ptty);
} else { /* need to malloc new space */
if ((new = (INV *) malloc (sizeof (INV))) == (INV *) 0) {
perror ("malloc failed...");
exit (1);
}
}
new->callno = strsave (argv[0]); /* caller's form of call id */
new->callee = strsave (argv[1]); /* person being called */
new->tty = strsave (argv[2]); /* his tty */
new->caller = strsave (argv[3]); /* caller name */
new->convaddr = strsave (argv[4]); /* conversation address */
time (&now);
/*
* Acknowledge immediately. We make an id
* from the lower 4 bits of the time.
*/
sprintf (new->id, "%05ld", (now & 9999L));
sprintf (buf, "%c%c%c%s", ESC, PAGE, ACK, new->id);
sendto (misc, buf, strlen (buf), 0, &sin, sizeof (sin));
/* figure out host name */
if (hp = gethostbyaddr (&sin.sin_addr, sizeof (struct in_addr), AF_INET))
new->host = strsave (hp->h_name);
else
new->host = strsave (inet_ntoa (sin.sin_addr.s_addr));
/* save control address */
bcopy ((char *)&sin, (char *)&new->ctladdr, sizeof (struct sockaddr_in));
/* lookup callee in password file */
if (pw = getpwnam (argv[0])) {
new->home = strsave (pw->pw_dir);
new->uid = pw->pw_uid;
new->gid = pw->pw_gid;
} else
new->home = (char *) 0;
new->rings = 0; /* so they get it next time around */
new->ptty = (char *) 0;
new->prev = NIL;
insert (new); /* and add to the pending list */
}
/*
* Search through the list of invitations, looking for one
* from the same address as this, with the same call number as well.
*/
INV *
seenit (callno, addr)
char *callno;
struct sockaddr_in addr;
{
register INV *inv;
for (inv = invitations; inv; inv = inv->next)
if (strcmp (callno, inv->callno) == 0 &&
bcmp ((char *)&addr, (char *)&inv->ctladdr,
sizeof (struct sockaddr_in)) == 0)
return (inv);
return (NIL);
}
!Funky!Stuff!
fi # end of overwriting check
echo shar: extracting "'pagetty.c'" '(1602 characters)'
if test -f 'pagetty.c'
then
echo shar: will not over-write existing file "'pagetty.c'"
else
cat << \!Funky!Stuff! > 'pagetty.c'
#ifndef lint
static char RCSid[] = "$Header: pagetty.c,v 1.1 85/10/28 17:38:31 broome Exp $";
#endif
/*
* $Log: pagetty.c,v $
* Revision 1.1 85/10/28 17:38:31 broome
* Initial revision
*
*/
#include "../common.h"
#include "defs.h"
#include <sys/time.h>
#include <stdio.h>
#include <syslog.h>
#include <sys/file.h>
/*
* Page a local user to his terminal.
* We compose the message, then send it
* in one big block so as to minimise messing
* him up if he's in vi or the like.
*/
pagetty (inv, tty)
INV *inv;
char *tty;
{
struct tm *tm;
long now;
char buf[100], mesg[300];
int fd; /* tty file descriptor */
time (&now);
tm = localtime (&now);
/* Now to compose the message */
#ifdef notdef
sprintf (buf, "\r\n\7Message from Phone_Daemon@%s at %d:%02d ...\r\n",
host, tm->tm_hour, tm->tm_min);
#endif
sprintf (buf, "\r\n\7Message from the Telephone_Operator@%s at %d:%02d ...\r\n",
host, tm->tm_hour, tm->tm_min);
strcpy (mesg, buf);
sprintf (buf, "phone: connection requested by %s@%s\r\n",
inv->caller, inv->host);
strcat (mesg, buf);
sprintf (buf, "phone: respond with \"phone %s", inv->caller);
strcat (mesg, buf);
/* only list host if it differs from our own */
if (strcmp (inv->host, host)) {
strcat (mesg, "@");
strcat (mesg, inv->host);
}
strcat (mesg, "\"\r\n\r\n\7");
/* And send it */
if ((fd = open (tty, O_WRONLY, 0444)) < 0) { /* shouldn't happen */
syslog (LOG_ERR, "phoned: can't open %s: %m", tty);
_exit (-99);
}
(void) write (fd, mesg, strlen (mesg));
(void) close (fd);
_exit (0);
}
!Funky!Stuff!
fi # end of overwriting check
echo shar: extracting "'reinvite.c'" '(773 characters)'
if test -f 'reinvite.c'
then
echo shar: will not over-write existing file "'reinvite.c'"
else
cat << \!Funky!Stuff! > 'reinvite.c'
#ifndef lint
static char RCSid[] = "$Header: reinvite.c,v 1.1 85/10/28 17:38:35 broome Exp $";
#endif
/*
* $Log: reinvite.c,v $
* Revision 1.1 85/10/28 17:38:35 broome
* Initial revision
*
*/
#include "../common.h"
#include "defs.h"
/*
* Reinvite the given invitation by resetting the `rings' field to zero.
*/
reinvite (argv, sin)
char **argv;
struct sockaddr_in sin;
{
register INV *inv;
register int found = 0;
for (inv = invitations; inv; inv = inv->next) {
if (strcmp (inv->id, *argv) == 0 &&
bcmp ((char *)&sin, (char *)&(inv->ctladdr), sizeof (sin)) == 0) {
inv->rings = 0;
found = 1;
break;
}
}
sprintf (buf, "%c%c%c%s", ESC, REINVITE, found ? ACK : NAK, *argv);
sendto (misc, buf, strlen (buf), 0, &sin, sizeof (sin));
}
!Funky!Stuff!
fi # end of overwriting check
echo shar: extracting "'strsave.c'" '(407 characters)'
if test -f 'strsave.c'
then
echo shar: will not over-write existing file "'strsave.c'"
else
cat << \!Funky!Stuff! > 'strsave.c'
#ifndef lint
static char RCSid[] = "$Header: strsave.c,v 1.1 85/10/28 17:38:36 broome Exp $";
#endif
/*
* $Log: strsave.c,v $
* Revision 1.1 85/10/28 17:38:36 broome
* Initial revision
*
*/
/*
* Allocate enough space for the given string and copy it over.
*/
char *
strsave (s)
char *s;
{
char *malloc();
char *new;
if (new = malloc (strlen (s) + 1))
strcpy (new, s);
return (new);
}
!Funky!Stuff!
fi # end of overwriting check
echo shar: extracting "'utmp.c'" '(4186 characters)'
if test -f 'utmp.c'
then
echo shar: will not over-write existing file "'utmp.c'"
else
cat << \!Funky!Stuff! > 'utmp.c'
#ifndef lint
static char RCSid[] = "$Header: utmp.c,v 1.1 85/10/28 17:38:37 broome Exp $";
#endif
/*
* $Log: utmp.c,v $
* Revision 1.1 85/10/28 17:38:37 broome
* Initial revision
*/
#include "../common.h"
#include "defs.h"
#include <sys/stat.h>
#include <sys/file.h>
#include <utmp.h>
/*
* Routines for dealing with /etc/utmp.
*
* We use a statically-allocated array because readutmp() is
* called at interrupt-level and we don't want to mess up malloc()
* and free as a result.
*/
#ifndef LINELEN /* length of line for "who()" */
#define LINELEN 76 /* not 80 - for magic-cookie terminals */
#endif
#ifndef MAXUSERS
#define MAXUSERS 64
#endif
static struct utmp utbuf[MAXUSERS]; /* contents of file */
static int numents; /* number of users on */
static int utfd; /* file descriptor */
/*
* Initialize by opening the file and malloc'ing space.
*/
openutmp ()
{
register int i;
struct stat statb;
if ((utfd = open ("/etc/utmp", O_RDONLY)) < 0) {
perror ("can't open utmp");
return; /* exit?? */
}
}
/*
* Reread /etc/utmp from the open file descriptor into the buffer.
* We test/set the "here" flag so we don't try to read at interrupt level
* if we're already doing it normally at the same time. (in "who()")
*/
readutmp ()
{
static int here = 0;
int cc;
if (here)
return;
here = 1;
lseek (utfd, 0L, 0); /* rewind */
cc = read (utfd, utbuf, sizeof (utbuf)); /* and read */
numents = cc / sizeof (struct utmp);
here = 0;
}
/*
* Go through the utmp buffer, trying to find the named user,
* possibly with the tty specified.
*/
char *
findtty (user, tty, mode)
char *user;
char *tty;
int *mode;
{
static char ttybuf[15];
register int i;
register struct utmp *utmp;
struct stat statb;
*mode = NOT_ON; /* start by assuming he's not on */
for (i = 0; i < numents; i++) {
utmp = &utbuf[i];
if (*utmp->ut_name == '\0') /* noone on this port */
continue;
if (strncmp (utmp->ut_name, user, 8)) /* names don't match */
continue;
if (tty && *tty && strncmp (tty, utmp->ut_line, 8)) /* not spec'd tty */
continue;
strcpy (ttybuf, "/dev/");
strncat (ttybuf, utmp->ut_line, 8);
if (stat (ttybuf, &statb)) /* error on tty? */
continue;
if ((statb.st_mode & 02) == 0) {
*mode = MESG_OFF; /* refusing messages */
if (tty && *tty) /* they specified a particular tty */
break;
else
continue; /* see if we can find another one */
} else { /* all is okay, use this one */
*mode = 0;
return (ttybuf);
}
}
return ((char *) 0);
}
/*
* Send a "who" message to the given address ...
* We go through the utmp buffer, building LINELEN-long buffers
* and send them on over to the user.
*/
who (sin)
struct sockaddr_in sin;
{
register struct utmp *utmp;
register int i;
register int ulen;
register int len = LINELEN + 1;
register int users = 0;
char buf[LINELEN+5]; /* buffer for whole message */
char ubuf[20]; /* buffer for one user and tty */
#ifdef NO_WHO /* not allowed here ... */
sprintf (buf, "%c%c%cwho@%s: this site doesn't allow remote who.",
ESC, NAK, WHO, host);
(void) sendto (misc, buf, strlen (buf), 0, &sin, sizeof (sin));
return;
#else !NO_WHO /* not so paranoid here */
sprintf (buf, "%c%c%cwho info coming...", ESC, WHO, ACK);
sendto (misc, buf, strlen (buf), 0, &sin, sizeof (sin));
readutmp ();
buf[0] = '\0';
for (i = 0; i < numents; i++) {
utmp = &utbuf[i];
if (*utmp->ut_name == '\0') /* noone on that line */
continue;
sprintf (ubuf, " %.8s(%.5s)", utmp->ut_name, utmp->ut_line);
ulen = strlen (ubuf);
if (ulen + len + 1 < LINELEN)
strcat (buf, ubuf);
else {
if (users)
(void) sendto (misc, buf, len+4, 0, &sin, sizeof (sin));
sprintf (buf, "%c%c%cwho@%s:", ESC, MESSAGE, ACK, host);
len = strlen (buf) - 4;
strcat (buf, ubuf);
}
len += ulen;
users++;
}
if (users == 0) {
sprintf (buf, "%c%c%c%s: Noone logged on.",
ESC, MESSAGE, ACK, host);
sendto (misc, buf, strlen (buf), 0, &sin, sizeof (sin));
} else if (len)
(void) sendto (misc, buf, len+4, 0, &sin, sizeof (sin));
#endif NO_WHO
}
!Funky!Stuff!
fi # end of overwriting check
# End of shell archive
exit 0
More information about the Comp.sources.unix
mailing list