SRI-NOSC/ncpp/mail/snd.c

Compare this file to the similar file:
Show the results in this format:

#/*
Module Name:
	snd.c

Installation:
	if $1e = finale goto finale
	cc -c snd.c
	if ! -r snd.c exit
	cc snd.o /usr/net/hnconv.c
	rm -f snd.o hnconv.o
	exit
: finale
	cc -O -c -s snd.c
	if ! -r snd.o exit
	cc -O -s snd.o /usr/net/hnconv.c
	rm -f snd.o hnconv.o
	if ! -r a.out exit
	su cp a.out /bin/snd
	rm a.out

Module History:
(((Most recent changes first)))
   change NOSC-SDL to be the HOSTNAME value in siteinfo.h; also to get the
      local IMP number from NETNUMBER in siteinfo.h
   change RAND-Unix to be NOSC-SDL
   take '\n' or EOF to be same as 'queue'
   change ISD to UNIX in 'from'
   don't include final line of dashes in unsent.mail
   delete files before leaving
   omit ' at RAND-ISD' in 'From' field for local mailboxes
   fixed write-length in unsent.mail
   restore @ as line-delete before asking for subject, not after
   added 'copy of mail for xxx' to messages for snoop copy
   restore @ as line-delete before exiting if no 'To' list given
   changed SNOOP to MAILCOPY
   check for null file name
   added message separaters
   took out ridiculous editing stuff and special \ handling, added
      ability to call re, ed, nroff
*/
#include "/usr/sys/h/siteinfo.h"
#define MSGSEP "\001\001\001\001\n"
#define MSGSEPL 5
#define loop for(;;)
/* #define SNOOP "MAILCOPY@RCC\n"  /* 0 or snoop mailbox name ended with \n */
#define SNOOP 0  /* */
#define LOCIMP (NETNUMBER&077)        /* local imp number */
#define true 1
#define false 0
#define SMALLBUFLEN 256
#define controla 001
#define controlb 002
#define controlc 003
#define controld 004
#define controlf 006
#define controlh 010
#define controlq 021
#define controlr 022
#define controls 023
#define controlw 027
#define controlx 030
#define controlz 032
#define backspace 036
#define del 0177
#define abortchar 034

int goaway1(), goaway2();

struct status
	{
	char	s_minor;
	char	s_major;
	int	s_number;
	int	s_mode;
	char	s_nlinks;
	char	s_uid;
	char	s_gid;
	char	s_size0;
	int	s_size1;
	int	s_addr[8];
	int	s_actime[2];
	int	s_modtime[2];
	} statb;

struct  {
	char    ispeed;
	char    ospeed;
	char    erase;
	char    kill;
	int     mode;
	} *sttyptr &ttys;
struct iobuf {
	int fildes;
	int nleft;
	char *nextp;
	char buff[512];
	} afilebuf, ifilebuf;
extern struct iobuf *fin;
int savekill;
int pwfd;
int afile;
int tmpfd;
int fd;
int namefd;
int mbfd;
char bigbuf[512];
char pwbuf[512];
char *pwptr;
int pwcount;
int filecnt;
int netmsgs;
char cc[SMALLBUFLEN],to[SMALLBUFLEN],subject[SMALLBUFLEN];
char answer[10];
char user[40];
char dbuf[32];
char mailbox[64],netfile[64],from[64],returnto[64];
char hostname[64];
char realname[80];
char fn1[25],fn2[25],*fnx,*fny;
char *letter,*date;
int ttys[3];
int oldmode,uid,gid,myuid;
int unsent false;
int snoopcopy false;    /* true if called by ftp for snoop's copy */
int ftp false;          /* true if called by ftp */
int snoop false;        /* becomes true if any non-Rand recipients */
int file false;
int oldfile false;
int orighost;
char hex[] "0123456789ABCDEF";

/* name:
	send

function:
	A message sending program modeled after the tenex program
	sndmsg.

parameters:
	None have been defined as of yet.

returns:
	It delivers local mail by appending it to a file called mailbox
	in the user's root.
	If mail is undeliverable, a copy of the letter is left in
	a file called unsent.mail, in the senders current directory.


 */
main(argc,argv)
char *argv[];
int argc;
{
char *lp;
register char *p1, *p2;
int register i;
int vector[2];
if ((pwfd = open("/etc/passwd",0)) < 0)
	{
	printf("Couldn't open password file!\n");
	exit();
	}
afile=fopen("/usr/net/aliases",&afilebuf);

if (argc==3 && *argv[0]=='\001')          /* is being called by FTP */
{       if ((tmpfd=open(argv[1],0)) < 0)  /* second argument is file name */
	    exit();
	orighost=argv[0][1];            /* originating host */
	returnto[0] = '\0';             /* can't return this */
	p1 = "mailer";
	p2 = from;
	while(*p1++ = *p1++);
	ftp++;                          /* don't try to add header! */
	send(argv[2],0);                /* third argument is user name */
	if ((orighost&077) != LOCIMP)
	    snoop++;
	snoopcopy = argv[2];
	if (snoop && SNOOP)
	    send(SNOOP,0);
	close(tmpfd);
	unlink(argv[1]);
	exit();
}

getname(from);
findlocal(from);
p1 = mailbox;
p2 = returnto;
while(*p2++ = *p1++);   /* save user's directory for returning undeliverable*/
time(vector);           /*  mail                                            */
chkill();       /* remove @ as line delete character */
date = arpadate(vector);
printf("To: "); gather(to);
if (*to == '\000')
{       printf("Can't send mail to nobody!\n");
	rstkill();
	exit();
}
printf("cc: "); gather(cc);
rstkill();      /* restore line delete */
printf("Subject: "); gather(subject);
input();
send(to,1);
send(cc,1);
if (snoop && SNOOP)
	{returnto[0] = '\0';    /* don't want to return this copy */
	 send(SNOOP,0);
	}
if (unsent)
{       fd = creat("unsent.mail",0600);
	if (fd < 0)
	{       printf("unable to create unsent.mail\n");
		exit(1);
	}
	seek(tmpfd,0,0);
	while(i=read(tmpfd,bigbuf,512)) write(fd,bigbuf,i);
	close(fd);
	printf("A copy of this letter has been left in 'unsent.mail'\n");
}

close(tmpfd);
unlink(fnx);
exit(0);
}
/* name:
	gather

function:
	read a single line of console input into the user specified
	buffer.

algorithm:
	Read a character:
	If it is an unescaped new line, null terminate the buffer and return.
	Otherwise, stash the character into the buffer.
	If the length of the buffer has been reached, echo a new line and
	return.

parameters:
	*char	pointer to user buffer of length SMALLBUFLEN

returns:
	nothing

globals:
	SMALLBUFLEN

calls:
	getchar

called by:
	main
	send


 */
gather(sp)
char *sp;
{
register char c;
register char *p;

p = sp;
while( ((c = getchar()) != '\n') && (c > 0) )
{       *p++ = c;
	if ((p - sp) >= SMALLBUFLEN) break;
}
*p = '\0';
}


/* name:
	writef

function:
	Write a null terminated string

algorithm:
	Determine the length of the string.
	Write it out.
 CAVEAT	This call is not buffered, so use it carefully or pay the cost
	of high I/O expense.  It was writted to decrease subroutine linkage
	 global variable referencing and module size.  But those wins can
	easily be lost if writef is consistantly called with small strings.

parameters:
	int	file descriptor of output file.
	*char	pointer to null terminated string.

returns:
	int	value returned by write.

globals:

calls:
	write	(system)

called by:
	lotsa people


 */
writef(afd,str)
int afd;
char *str;
{	register int count;
	register char *s;

	s = str;
	for(count=0; *s++; count++);

	return(write(afd,str,count));
}

writef1(afd,str)        /* same as writef except convert '@' to ' at ' */
int afd;
char *str;
{       char c;
	while (c = *str++)
	{       if (c == '@') write(afd," at ",4);
		else write(afd,&c,1);
	}
}
/* name:
	input

function:
	To accept the text of the message and allow re, ed, and nroff
	to be called.

algorithm:
	Read until end-of-file, then ask for one of the following:
	mail to be sent, more input to be typed, a file to be included,
	re or ed to be called, or nroff to be called to justify the
	message.

parameters:
	none

returns:
	With a null terminated letter in the string pointed to by
	the global variable letter.

globals:
	letter	address of the buffer.

calls:
	writef
	write	system
	printf
	getchar

called by:
	main


 */
input()
{
char *tp;
register char *p,c;
register int i;
char *fnt;
char *p1;
int infile;
int stat;
int npipe[2];
int pid;

p1 = bigbuf;
pid = getpid();
for (i=0; i<5; i++)
{       *p1++ = (pid&07)+'0';
	pid =>> 3;
}
*p1 = 0;
stcopy("/tmp/send",fn1);
stcat(bigbuf,fn1);
stcopy(fn1,fn2);
stcat("a",fn1);
stcat("b",fn2);
fnx = fn1;
fny = fn2;
signal(2,&goaway2);      /* make sure file is deleted if user hits del */
if ((tmpfd=creat(fnx,0666)) < 0)
{       printf("Can't create temporary file!\n");
	exit();
}
close(tmpfd);
tmpfd=open(fnx,2);      /* creat opens for output only! */
printf("Type message, end with ^D\n");

more:
while(i=read(0,bigbuf,512)) write(tmpfd,bigbuf,i); /* collect message */


loop
{       printf("\nqueue, send, re, ed, input, file, justify, ");
	printf("display, or ?: ");
	gather(bigbuf);
	if ((c=bigbuf[0]) == 's' || c == 'q' || c == '\n' || c <= 0) break;
	switch(c)
	{
	case 'r':
		if (tmpfd > 0)
		{       close(tmpfd);
			tmpfd = 0;
		}
		if (fork() == 0)
		{	setuid(getuid()&0377);
			execl("/bin/re","re",fnx,0);
			printf("can't find re\n!");
			exit();
		}
		signal(2, 1);	/* ignore dels while in re */
		wait(&stat);
		signal(2, &goaway2);	/* restore del handling */
		stcopy(fnx,bigbuf);
		stcat(".bak",bigbuf);
		unlink(bigbuf);         /* delete .bak file */
		break;
	case 'e':
		if (tmpfd > 0)
		{       close(tmpfd);
			tmpfd = 0;
		}
		if (fork() == 0)
		{	setuid(getuid()&0377);
			execl("/bin/ed","ed",fnx,0);
			printf("can't find ed!\n");
			exit();
		}
		signal(2, 1);	/* ignore dels while in ed */
		wait(&stat);
		signal(2, &goaway2);	/* restore del handling */
		break;
	case 'j':
		if (tmpfd > 0)
		{       close(tmpfd);
			tmpfd = 0;
		}
		if (fork() == 0)
		{       pipe(npipe);
			close(0);
			dup(npipe[0]);  /* make the pipe the standard input */
			writef(npipe[1],".c2 ~\n.cc ~\n~ec ~\n~~so ");
			write(npipe[1],fnx,15);
			writef(npipe[1],"\n~~pl 0\n");
			close(1);
			close(npipe[1]);
			creat(fny,0600);
			execl("/usr/bin/nroff","nroff",0);
			write(2,"can't find nroff!\n",18);
			exit(-1);
		}
		wait(&stat);
		if (((&stat & 0177400) >> 8) != -1)
		{       unlink(fnx);
			fnt = fnx; fnx = fny; fny = fnt; /* switch names */
		}
		break;

	case 'i':                       /* input from keyboard  */
		if (tmpfd <= 0)
		{       tmpfd = open(fnx,2);
			seek(tmpfd,0,2);
		}
		printf("Continue typing message, end with ^D\n");
		goto more;

	case 'f':                       /* include file         */
		printf("File: ");
		gather(bigbuf);
		if (bigbuf[0] == '\0') break;
		if ((infile=open(bigbuf,0)) < 0)
		{       printf("can't open file\n");
			break;
		}
		if (tmpfd <= 0)
		{       tmpfd = open(fnx,2);
			seek(tmpfd,0,2);
		}
		while (i=read(infile,bigbuf,512)) write(tmpfd,bigbuf,i);
		close(infile);
		printf("File has been included\n");
		break;

	case 'd':                       /* display message      */
		if (tmpfd <= 0)
			tmpfd = open(fnx,2);
		seek(tmpfd,0,0);
		printf("Message:\n\n");
		while(i=read(tmpfd,bigbuf,512)) write(1,bigbuf,i);
		break;

	case '?':
	   /*   printf("send  will wait for message to be sent\n"); */
		printf("queue will wait for local copies of the message\n");
		printf("       to be sent and will queue network copies\n");
		printf("send  is (for the time being) the same as queue\n");
		printf("input will let you type in more of the message\n");
		printf("file  will include a file as part of the message\n");
		printf("re    will call the rand editor\n");
		printf("ed    will call the unix editor\n");
		printf("justify will justify the borders of the message\n");
		printf("display will display the message\n");
		break;

	default:
		printf("For help type ?\n");
	}   /* end of switch */
}  /* end of loop */
if (c <= 0)
	printf("\n");
if (tmpfd <= 0)
	tmpfd = open(fnx,2);
}
/* name:
	chkill, rstkill, goaway1, goaway2

function:
	to remove and restore the line delete character;
	to take appropriate actions before terminating from a del.
globals:
	oldmode

calls:
	stty
	exit
	unlink

called by:
	input


 */
chkill()
{       gtty(0,ttys);
	savekill = ttys[1];
	sttyptr->kill = '\177';  /* change line delete to nothing! */
	signal(2,&goaway1);
	stty(0,ttys);
}

rstkill()
{       ttys[1] = savekill;
	stty(0,ttys);
	signal(2,0);
}

goaway1()
{       ttys[1] = savekill;
	stty(0,ttys);
	exit();
}

goaway2()
{       unlink(fnx);
	exit();
}



/* name:
	send

function:
	To take a list of recipients and take steps to deliver the
	message (now in the temp file) to all of them.

algorithm:
	parse off a name.
	If it is a name:, open that file and read from it for a while.
	If it is a local user id, call post
	If it is a network user id, call netpost

parameters:
	Pointer to a null terminated characterstring which is a list
	of recipients.

returns:

globals:
	unsent

calls:
	valid
	open	(system)
	printf
	network
	findlocal
	netpost
	post

called by:
	main


 */
send(list,infoflg)
char *list;
int infoflg;
{
register char *name,*curp;
register char c;
int ret;
int alias;
char *ap;

alias = false;
curp = list;
while (alias || file || *curp)
{	name = user;
	while (valid(c = file?getc(&ifilebuf):(alias?*ap++:*curp++)))
		*name++ = c;
	*name = '\0';
	switch (c)
		{
case ':':	if (file)
			{if (infoflg)
			    printf("Nested name files not allowed.\n");
			 continue;
			}


		if ((namefd = fopen(user,&ifilebuf)) < 0)
			{
			if (infoflg) printf("Couldn't open %s\n",user);
			unsent++;
			continue;
			}


		file++;
		continue;

case -1:        close(ifilebuf.fildes);
		file = false;
		continue;
case '\0':      if (!(file|alias))
			--curp;
case '\n':      if (!file && alias)
			alias = false;
case ',':
case ' ':
		if (*user == '\000') continue;
		if (infoflg) printf("%s -- ",user);
		if (ret=network(user))
		{       if (ret == -1)
			{       if (infoflg) printf("host unknown\n");
				unsent++;
				continue;
			}
			netpost(user,hostname,infoflg);
			continue;
		}
		if (!alias && findalias(user))
		{       alias++;
			ap = realname;
			if (infoflg) printf("(alias for %s)\n",realname);
			continue;
		}
		if (findlocal(user))
		{       stcat("/.mail",mailbox);
			post(infoflg);
			continue;
		}

		{       if (infoflg) printf("not a local user\n");
			unsent++;
			continue;
		}

default:        if (infoflg)
			{printf("Illegal terminator %c.\n",c);
			 printf("User name %s ignored.\n",user);
			}
		} /* end switch */
	}
} /* end send */
/* name:
	findlocal

function:
	To ascertain whether or not someone is a local user, and
	if he is, to find the name of his root directory.

algorithm:
	Rewind the password file.
	Search it for a line starting with the user name.
	If found:
		extract all the info about uid, gid mailbox, etc.
		return.
	Else, continue the search.
	Announce that he isn't a known user.

parameters:
	*char	pointer to null terminated user name.

returns:
	boolean	whether or not he was found.

globals:
	pwfd
	uid
	gid
	mailbox
	pwcount

calls:
	getpwchar
	seek	(system)

called by:
	send


 */
findlocal(name)
char *name;
{
register char *np;
register char pwc;

/*	rewind the password file */
seek(pwfd,0,0);
pwcount = 0;

pwc = 1;
while(pwc > 0)
{	np = name;	/* search for a line starting with name */
	for(pwc = getpwchar(); pwc == *np++; pwc = getpwchar());
	if ((pwc == ':') && (*--np == '\000')) goto gotuser;
	while( (pwc != '\n') && (pwc > 0) ) pwc = getpwchar();
}
return(false);

gotuser:	/* extract all neat info from pw entry */
for(pwc = getpwchar(); pwc != ':'; pwc = getpwchar());
/* we have skipped over the password */
for(uid = 0; (pwc = getpwchar()) != ':'; uid =+ (9*uid) + pwc - '0');
for(gid = 0; (pwc = getpwchar()) != ':'; gid =+ (9*gid) + pwc - '0');
for(pwc = getpwchar(); pwc != ':'; pwc = getpwchar());
/* we have skipped over the gecos bin */
np = mailbox;
for(pwc = getpwchar(); pwc != ':'; pwc = getpwchar()) *np++ = pwc;
*np = '\000';
return(true);
}
/*name:
	findalias

function:
	To determine whether a name is in the alias file, and
	if so to replace it with the real name.

algorithm:
	Search the file for a line beginning with the name.
	If found, move the real name(s) to 'realname'.

globals:
	afile
	afilebuf
	realname

calls:
	getc(III)
	seek(II)

called by:
	send

 */
findalias(name)
char *name;
{
register char c, *p;

if (afile<0) return(false);  /* alias file could not be opened */
seek(afilebuf.fildes,0,0);
loop
{       for (p=name; *p++ == (c=getc(&afilebuf));); /* check for same name */
	if (c<0) return(false);
	if ((*--p == '\0') && (c == ':')) break;  /* got it */
	while(getc(&afilebuf) != '\n'); /* get to end of this line */
}
p = realname;              /* move stuff after : to realname */
while ((*p++ = getc(&afilebuf)) != '\n');
*--p = '\0';
*++p = '\n';
return(true);
}
/* name:
	network

function:
	To determine whether a user is a network user, and if he
	is, to break the name up into a hostname and ultimately
	a list of user names.

algorithm:
	Look for an @ in the name, if not found, not net
	Copy the hostname into a separate buffer and truncate
		it off of the user name.

parameters:
	*char	pointer to null terminated user name.

returns:
	boolean	Whether or not guy was a network user.
		(will be -1 if network site name unknown)
	and	if he was:
		Hostname has been truncated off of user name and
		put into the global buffer hostname.

globals:
	hostname.

calls:
	hnconf (not part of this source) to verify host name

called by:
	send


 */
network(name)
char *name;
{	register char *c;
	register char *d;
	int hostnum;

	for(c = name; *c; c++) if (*c == '@') goto netname;
	return(false);

netname:
	*c++ = '\000';
	d = hostname;
	while(*d++ = *c++);
	if ((hostnum=atoi(hnconv(hostname))) <= 0)
		return(-1);
	if ((hostnum&077) != LOCIMP) snoop++; /* check for rand (any host) */
	return(true);
}
/* name:
	post

function:
	To mail a letter (in tempfile) to some individual unix user.

algorithm:
	Create a mailbox if he doesn't have one.
	If he had one make sure it is not in use.
	Append the contents of the tempfile to it.
	Make recipient the owner if he wasn't already.

parameters:
	none
	but..	null terminated name of recipients directory is in in mailbox.

returns:
	boolean	Whether or not it was successfully sent.

globals:
	mailbox
	mbfd
	tmpfd
	bigbuf
	unsent

calls:
	creat
	seek
	read
	write
	printf
	stcat

called by:
	send


 */
post(infoflg)
int infoflg;
{
	register int i;

	if (stat(mailbox,&statb) < 0)
	{       mbfd = creat(mailbox,0666);
		if (mbfd < 0)
		{       if (infoflg) printf("Unable to create mailbox\n");
			unsent++;
			return(false);
		}
	}
	else
	{ /***  if (statb.s_nlinks > 1)
		{       if (infoflg) printf("Mailbox is busy\n");
			unsent++;
			return(false);
		}
	  ***/  mbfd = open(mailbox,1);
		if (mbfd < 0)
		{       if (infoflg) printf("Mailbox is busy\n");
			unsent++;
			return(false);
		}
		seek(mbfd,0,2);	/* seek end of file */
	}

	seek(tmpfd,0,0); /* rewind the file containing the message */
	write(mbfd,MSGSEP,MSGSEPL);
    /*  writef(mbfd,"Mail received for ");
	writef(mbfd,user);
	writef(mbfd,"\n");
    */  if (!ftp)
	{       write(mbfd,"Date: ",6);
		writef(mbfd,date);
		write(mbfd,"\nFrom: ",7);
		writef(mbfd,from);
		if (*subject)
		{       write(mbfd,"\nSubject: ",10);
			writef(mbfd,subject);
		}
		write(mbfd,"\nTo: ",5);
		writef1(mbfd,to);
		if (*cc)
		{       write(mbfd,"\ncc: ",5);
			writef1(mbfd,cc);
		}
		write(mbfd,"\n\n",2);
	}
	while((i = read(tmpfd,bigbuf,512)) > 0) write(mbfd,bigbuf,i);
	if (!ftp) writef(mbfd,"-------\n");
	write(mbfd,MSGSEP,MSGSEPL);
	close(mbfd);
	chown(mailbox,uid);
	if (infoflg) printf("ok\n");
	return(true);
} /* end post */
/* name:
	netpost

function:
	to attempt to mail off a piece of network mail.

algorithm:
	Contrive a unique name for a network mail file.
	Create it in the netmail daemon's mailbox
	put destination host, users and sender names into file.
	copy message into the file.

parameters:
	*char	pointer to null terminated user name
	*char	pointer to null terminated host name

returns:
	boolean	whether or not it worked

globals:
	unsent
	netmsgs		count of number of net msgs so far
	tmpfd
	bigbuf

calls:
	read
	write
	printf
	creat
	close
	stat
	chown

called by:
	send


 */
netpost(uname,hname,infoflg)
 char *uname;
 char *hname;
 int infoflg;
{
	register char *p1;
	register char *p2;
	register int i;


	p2 = netfile;
	for(p1 = "/usr/netmail/"; *p1; *p2++ = *p1++);
	crname(p2);
	mbfd = creat(netfile, 0444);
	if (mbfd < 0)
	{       if (infoflg) printf("Unable to create mailfile for %s@%s\n",
			uname,hname);
		unsent++;
		return(false);
	}

	writef(mbfd,hname);
	write (mbfd,":",1);
	writef(mbfd,uname);
	write (mbfd,":",1);
	writef(mbfd,returnto);
	write (mbfd, ":\n",2);
	if (snoopcopy)
	{       writef(mbfd,"Copy of mail received for ");
		writef(mbfd,snoopcopy);
		writef(mbfd,"\n");
	}
	if (!ftp)
	{       write(mbfd,"Date: ",6);
		writef(mbfd,date);
		write(mbfd,"\nFrom: ",7);
		writef(mbfd,from);
		writef(mbfd," at ");
		writef(mbfd,HOSTNAME);
		if (*subject)
		{       write(mbfd,"\nSubject: ",10);
			writef(mbfd,subject);
		}
		write(mbfd,"\nTo: ",5);
		writef1(mbfd,to);
		if (*cc)
		{       write(mbfd,"\ncc: ",5);
			writef1(mbfd,cc);
		}
		write(mbfd,"\n\n",2);
	}
	seek(tmpfd, 0, 0);
	while ((i = read(tmpfd,bigbuf,512)) > 0)
		write(mbfd,bigbuf,i);
	if (!ftp) writef(mbfd,"-------\n");

	close(mbfd);
	chown(netfile,myuid);
	if (infoflg) printf("queued\n");
	netmsgs++;
	return(true);
}

/* name:
	getname 

function:
	To find out the name of the user who forked me.

algorithm:
	Get my real user id and look it up in the password table

parameters:
	*char	pointer to buffer where name should be placed.

returns:
	*char pointer to buffer wher callers's name was placed.

globals:

calls:
	getuid
	getpw
	printf

called by:
	main


 */
getname(caller)
char *caller;
{
char linebuf[100];
char *cp,*lp;

myuid = getuid() & 0377;
if (getpw(myuid, linebuf))
{
	printf("Your user id is not in the password file?!?\n");
	exit();
}
cp = caller;
lp = linebuf;
while(*lp != ':') *cp++ = *lp++;
*cp = '\000';
return(caller);
}


char getpwchar()
{
tryagain:
	if (pwcount > 0)
	{	pwcount--;
		return(*pwptr++);
	}
	else
	{	pwcount = read(pwfd,pwbuf,512);
		if (pwcount <= 0) return(-1);
		pwptr = pwbuf;
		goto tryagain;
	}
}
valid(ch)
char ch;
{
return(((ch >= 'a') && (ch <= 'z')) | ((ch >= '0') && (ch <= '9')) |
	(ch == '.') | (ch == '/') | (ch == '-') | (ch == ';') |
	(ch == '@') | (ch == '(') | (ch == ')') |
	((ch >= 'A') && (ch <= 'Z'))   );
}
stcopy(a,b)
char *a,*b;
{
register char *p,*q;
p = a;
q = b;
while(*q++ = *p++);
}


stcat(latter,former)
char *latter,*former;
{
register char *fp,*lp;
fp = former;
lp = latter;
while (*fp++);
fp--;
while (*fp++ = *lp++);
}
/* name:
	arpadate

function:
	to get an ARPA format date (format described in rfc 680)

algorithm:
	Get the unix format date and jumble it around to be arpa format
	Unix format is:
	day mmm dd hh:mm:ss yyyy
	Arpa format is:
	dd mmm yyyy at hhmm-zzz

parameters:
	pointer to the doubleword time

returns:
	pointer to the arpa format date corresponding to that time

globals:
	dbuf

calls:
	ctime
	localtime

called by:
	main


 */
char *arpadate(tvec)
 int tvec[2];
{	register int *i;
	register char *p;
	register char *t;

	t = ctime(tvec);
	p = dbuf;

	*p++ = t[8];
	*p++ = t[9];
	*p++ = ' ';
	*p++ = t[4];
	*p++ = t[5];
	*p++ = t[6];
	*p++ = ' ';
	*p++ = t[20];
	*p++ = t[21];
	*p++ = t[22];
	*p++ = t[23];
	*p++ = ' ';
	*p++ = 'a';
	*p++ = 't';
	*p++ = ' ';
	*p++ = t[11];
	*p++ = t[12];
	*p++ = t[14];
	*p++ = t[15];
	*p++ = '-';
	*p++ = 'P';
	i = localtime(tvec);
	if (i[8]) *p++ = 'D';
	else *p++ = 'S';
	*p++ = 'T';
	*p++ = '\000';

	return(dbuf);
}
/*name:
	crname

function:
	to create a unique file name

algorithm:
	use the process id number, the date and time, and a reference count,
	convert to hexadecimal

paramters:
	pointer to where the name is to be stored

globals:
	hex

calls:
	getpid
	time

called by:
	netpost

*/
crname(q)
  char *q;
{
	int i;
	int tvec[4];
	char *p;

	p = &tvec[0];
	tvec[2] = getpid();
	tvec[3] = filecnt++;
	if (filecnt==256)
		{filecnt = 0;
		sleep(1);
		}
	time(tvec);
	for (i=7; i; --i)
	{       *q++ = hex[(*p>>4)&017];
		*q++ = hex[ *p++  &017];
	}
	*q = '\0';
}