[comp.mail.uucp] UnixMail to Telemail interface

ht@ashtate.UUCP (07/08/87)

I tried posting this through comp.sources.unix but I am tired of waiting
for the net.gods to post this (and have received many messages from users
since then) so I am posting this to the most appropriate group I know of:
This group.

--Haral

---------------------------------------------------------------------------

This shar archive contains the sources to a Telemail to UnixMail interface.
It is a fairly simple interface and operates as follows:

1. It logs in for each "subscribed" user on the user's Telemail account
and reads his mail (if any).  The read mail is forwarded to him on the
local UNIX system and the return path reflects "telemail!USERNAME".

2. It scans the UUCP queue for outgoing messages for a system named 
"telemail" and transfers those to a telemail spool directory.  It then
logs in for that user (if subscribed) to his Telemail account and mails
the outgoing message to the intended user under Telemail.

No user agent is provided and as such the user cannot send special 
classes of mail (such as registered, return receipt, ...), however
non-passworded registered messages *are* accepted from Telemail 
and passed on to the user as regular mail.

There is a number of planned improvements to this program, however, there
is no time.  Look at the TODO list for starters.  Also this only runs
on 4.2 BSD and 4.3 BSD systems even though it would not be very hard
to convert it to other systems.  I started some such work, but did not
finish it again due to not enough time.  As it is, it is a hack thrown
together and patched as needed to do the job.  I would appreciate new
versions of it if someone improves it in any way and especially if any
of the TODO items are done.

--Haral Tsitsivas
  ...!seismo!scgvaxd!ashtate!haral

---------------------------------------------------------------------------

# 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:
# telemail.c poll.telemail telespool Makefile README TODO telemail.1 crontab telsnap.c telsnap.1 telstats.c telstats.1 telstats.example telsnap.example

echo x - telemail.c
cat > "telemail.c" << '//E*O*F telemail.c//'
static char sccsid[] = "@(#)gtelemail.c	1.6    01/06/87";
/*
 * This software is Copyright (c) 1987 by Haral Tsitsivas
 *
 * Permission is hereby granted to copy, reproduce, redistribute or
 * otherwise use this software as long as: there is no monetary
 * profit gained specifically from the use or reproduction or this
 * software, it is not sold, rented, traded or otherwise marketed, and
 * this copyright notice is included prominently in any copy
 * made.
 *
 * The author make no claims as to the fitness or correctness of
 * this software for any use whatsoever, and it is provided as is. 
 * Any use of this software is at the user's own risk.
 */
#include <stdio.h>
#include <ctype.h>
#include <sgtty.h>
#include <signal.h>
#include <setjmp.h>
#ifdef BSD42
#include <sys/time.h>
#else
#include <time.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#ifdef BSD42
#include <sys/resource.h>
#endif

#ifdef COMMENT
/*
 * 	12/01/86, haral, changed usage of tty and calling devices to usage of 
 * 		the #define statements need to make this smarter to pick 
 *		an available device
 * 	12/02/86, haral, removed messages about login and logout on each user
 * 		and added messages about messages send to each user including
 * 		number of bytes sent per message (print a message on failures)
 *	12/03/86, haral, removed more annoying messages about connecting and 
 *		disconnecting for each user... 
 *	12/04/86, haral, changed "ifdef DEBUG" statements to "if (debug)" 
 *		statements allowing for run-time decisions on whether 
 *		diagnostic output would be printed.  The first argument 
 *		controls the debug level
 *	12/05/86, haral, prepend the string "telemail\!" to the from username
 *		via the -f sendmail option
 *	12/05/86, haral, accept registered mail (but pass it on as regular 
 *		mail) at least gtelemail no longer hangs when it finds 
 *		registered mail (looking for Command? or Action? prompts)
 *	12/05/86, haral, save messages that were not mailed succesfully to 
 *		file /usr/spool/telemail/ERRFILE (instead of dropping them 
 *		on the floor).
 *	01/06/87, haral, introduce spool directory /usr/spool/telemail where
 *		the script telespool places outgoing telemail messages.
 *		When reading mail for each user check for outgoing messages
 *		by that user and send them at that time.
 *		telemail.c is now a two-way message transmission program.
 *	01/06/87, haral, removed one lock file, now using only one lock file
 *		since it is the same one as the one UUCP uses, no more needed.
 *	01/08/87, haral, parameterized the phone number, dial device and 
 *		debug options.  Options -t -c and -d added.
 *	01/12/87, haral, added variable tmouts in mi to count the number of
 *		times timed out in the "mi" read routine. abort at MAXTMOUT.
 *	01/29/87, haral, added flow control to the sendmail part of the
 *		conversation to correct the delivery of incomplete messages.
 *	02/03/87, haral, added code to change priority when reading messages
 *		so it does not fall behind...
 *	02/06/87, haral, changed function setupline to set tty to CBREAK
 *		and TANDEM mode instead of RAW, to enable kernel flow control
 *		so characters don't get dropped on the floor where reading 
 *		messages from telemail.
 *	02/13/87, haral, only transmit printable characters to telemail (skip
 *		^Zs and the like).
 *	02/17/87, haral, look for Command? in putmail before sending next 
 *		message 
 *	02/17/87, haral, add -s option where mail only gets send to telemail,
 *		no attempt is made to read mail for each user
 *	02/20/87, haral, added purgemail to purge mail if older than 5 days
 *		so users who do not have autopurge set don't accrue charges
 *	02/23/87, haral, added control file PID for the benefit of "telsnap",
 *		which reports on facts about the telemail queue and activity
 *	02/23/87, haral, pulled LCK locking code in ulockf and added ultouch
 *		which is called periodically to reinforce the lock
 *		(otherwise it is deleted by uucp/uucico)
 *	02/26/87, haral, fixed problem with trashed lines on outgoing 
 *		 long messages (every tenth line due to reuse of buffers)
 *	02/26/87, haral, add chmod call after creating rawfile and fmtfile
 *		 to ensure the security of incoming mail against user perusal
 *	04/21/87, haral, add #defines for BSD42 for easier porting to nonBSD
 *		 and carry through the UNIX subject line with the added
 *		 message (remote from hostname) at the end of the line
 */
#endif

#define	TRUE	1
#define	FALSE	0
#define DEBUG	0
#define MAXTMOUT 10

#define SPEED	"1200"			/* speed of modem to use */
#define LOCKFILE "/usr/spool/uucp/LCK.." /* lock file prefix */
#define DIALSTR	"95486141"		/* put here the phone number */
#define CULNM	"/dev/hys1200"		/* normally a link to tty */
		/* put here the tty name or calling device as above */
#define LOCKSTR	 "/usr/spool/uucp/LCK..hys1200"	/* default lock file */
#define FORWARDMSG "Forwarded message from %s %s\r"	/* default subject */
#define HW	"VAX"	/* define your hardware for the forward message */

char	logfile[] = "/usr/spool/telemail/LOGFILE";
char	errfile[] = "/usr/spool/telemail/ERRFILE";
char	userfile[] = "/usr/spool/telemail/USERS";
char	spooldir[] = "/usr/spool/telemail";
char	cfdir[] = "/usr/spool/telemail/C";
char	dfdir[] = "/usr/spool/telemail/D";
char	bfdir[] = "/usr/spool/telemail/BAD";

char	lockfile[80];
char	dialstr[80];
char 	culnm[40];
char	modem[40], speed[40];
char 	seqnum[80];

int	ttyfp;			/* file pointer to tty line */
int	ttylock;		/* file pointer to tty lock file */
FILE	*teledir;		/* file pointer to telemail directory */
FILE	*telelog;		/* file pointer to telemail log */
FILE	*fmsgfp;		/* file pointer to formatted message file */
FILE	*rmsgfp;		/* file pointer to raw message file */
FILE	*confp;			/* file pointer to control file */
FILE	*datfp;			/* file pointer to data file */
FILE	*fp, *pp, *fopen(), *popen();

struct sgttyb   rawmode;	/* line raw mode */
struct sgttyb   savemode;	/* line initial mode */

struct stat     dbuf;

jmp_buf	env;			/* environment ptr for timeout longjump */
int 	tmouts;			/* how many times we failed to read */
char	unread;			/* last character */
char	act[] = "Action?   ";
char	cmd[] = "Command?  ";

char	teleuser[80];		/* telemail user name */
char	fromuser[80];		/* From: user */
char	passwd[10];		/* telemail user password */
char	vaxuser[20];		/* vax user name */
char	lochost[20];		/* local host name */

char	rawfile[80];		/* raw message file name */
char	fmtfile[80];		/* formatted message file name */
char	ucffile[80];		/* send control file */
char	udffile[80];		/* send data file */
char	buf[512], tbuf[512];	/* temp buffers */
int	usercount, debug, l, sendonly;

main(argc, argv)
int argc;
char *argv[];
{
	char tbuf[80];
	int i, cflag, oldpri;

	cflag = 0;
	sprintf(dialstr, "ATDT %s\r", DIALSTR);
	strcpy(lockfile, LOCKSTR);
	strcpy(culnm, CULNM);
	debug = DEBUG;
	sendonly = 0;
	i = 1;

	while (i < argc) {
		switch(argv[i][0]) {
		case '-':
			switch(argv[i][1]) {
			case 'd':
				debug = atoi(&argv[i][2]);
				break;
			case 't':
				sprintf(dialstr, "ATDT %s\r", &argv[i][2]);
				break;
			case 's':
				sendonly++;
				break;
			case 'c':
				cflag++;
				sprintf(lockfile, "%s%s", LOCKFILE, &argv[i][2]);
				sprintf(culnm, "/dev/%s", &argv[i][2]);
				break;
			default:
				printf("Don't grok %s\n", argv[i]);
			}
			break;
		default:
			printf("Don't grok %s\n", argv[i]);
		}
		i++;
	}
#ifdef COMMENT
	printf("debug: %d\ndial: %s\ndev: %s\nlock: %s\n", debug,
	dialstr, culnm, lockfile);
#endif

	getlochost();
	setuid(geteuid());
	setupline(cflag);
	usercount = 0;

	logpid("startup");
	for (;;) {
		if (!getuser())
			break;

		if (sendonly) {
			if (nomail()) {
				if (debug >= 3) {
					tag();
					fprintf(telelog, "Skipping %s\n", vaxuser);
				}
				continue;
			}
		}

 		if (!(usercount % 4)) { 
 			for (i = 0;; i++) {
				if (connect()) 
 					break;
 				if (i > 3)
 					quit(-3);
 			}
		} 
		usercount++;

		if (!maillogon()) {
			if (!reconnect())
				quit(-3);
		}
		if (!userlogon()) {
			if (!reconnect())
				quit(-3);

			if (!userlogon()) {
				if (!reconnect())
					quit(-3);

				continue;
			}
		}
#ifdef BSD42
		oldpri = getpriority(PRIO_PROCESS, 0);
		setpriority(PRIO_PROCESS, 0, -5);
#endif
		if (!sendonly)
			getmail();
#ifdef BSD42
		setpriority(PRIO_PROCESS, 0, oldpri);
#endif
		purgemail();
		if (putmail() < 0) {
			if (!reconnect())
				quit(-4);
			continue;
		}
		userlogoff();
	}
	quit(0);
}

/* ====================================================================== */

clkint()
{
	tmouts++;
	longjmp(env, TRUE);
}

/* ====================================================================== */

connect()
{
	if (!hangup(0))
		return FALSE;

	if (!dial())
		return FALSE;

	if (!netlogon()) {
		tag();
		fprintf(telelog, "Unable to access TELENET (netlogon)\n");
		return FALSE;
	}
	logpid("connected");
	return TRUE;
}

/* ====================================================================== */

deliver()
{
	int	status, bytes;
	char	mailmsg[512];
	strcpy(fmtfile, "/tmp/TMFXXXXXX");
	mktemp(fmtfile);
	format();

	sprintf(mailmsg, "/usr/lib/sendmail -eq -d9 -F%s -f%s %s < %s",
		fromuser, fromuser, vaxuser, fmtfile);

	if (debug)
		fprintf(telelog, "Mail command: %s\n", mailmsg);

	status = system(mailmsg);
	bytes = 0;
	if (stat(fmtfile, &dbuf) == 0)
		bytes = dbuf.st_size;
	if (!status) {
		tag();
		fprintf(telelog, "MAIL RECVD for %s from %s (%d bytes)\n",
			vaxuser, fromuser, bytes);
		unlink(fmtfile);
	} else {
		tag();
		fprintf(telelog, "MAIL RECV for %s failed (%d bytes) from %s (status %d)\n",
			vaxuser, bytes, fromuser, status);
		sprintf(buf, "cat %s >> %s", fmtfile, errfile);
		system(buf);
		unlink(fmtfile);
	}
	if (debug)
		fprintf(telelog, "Mail status = %d\n", status);
}

/* ====================================================================== */

dial()
{
	int	status;

	logpid("dialing");
	mo(dialstr);
	if (!expect("AT", 15)) {
		tag();
		fprintf(telelog, "Modem failure...did not echo dial command\n");
		return FALSE;
	}
	skiplf(50);
	status = expect("CONNECT", 20);
	skiplf(20);
	tag();
	if (status)
		fprintf(telelog, "Connected to TELENET\n");
	else
		fprintf(telelog, "No connection\n");

	return status;
}

/* ====================================================================== */

expect(str, timout)
char	*str;
int	timout;
{
	char	mi();
	char	c;

	if (debug > 4)
		fprintf(telelog, "\nExpect :%s:\n", str);
	while (*str) {
		c = mi(timout);

		if (c != *str) {
			if (c > 0)
				unread = c;
			return FALSE;
		}
		str++;
	}
	if (debug > 3)
		fprintf(telelog, "\nSuccess\n");

	return TRUE;
}

/* ====================================================================== */

findprompt(str, timeout)
char	*str;
int	timeout;
{
	int	retry;

	retry = 0;
	do {
		if (!skiplf(timeout)) {
			if (retry++ > 2)
				return FALSE;

			mo("\r");
			continue;
		}
	} while (!expect(str, timeout));

	return TRUE;
}

/* ====================================================================== */

format()
{
	int	j, ll, cc, from, subject, to;
	char	*s, line[135], newline[255];

	rmsgfp = fopen(rawfile, "r");
	fmsgfp = fopen(fmtfile, "w");
	chmod(fmtfile, 0600);
	cc = FALSE;
	from = FALSE;
	subject = FALSE;
	to = FALSE;

	if (fgets(line, 134, rmsgfp) == NULL) {
		fclose(rmsgfp);
		fclose(fmsgfp);
		return;
	}
	fromuser[0] = '\0';
	for (;;) {
		if (fgets(line, 134, rmsgfp) == NULL)
			break;

		if (!strncmp(line, "From:", 5)) {
			ll = strlen(line);
			if (!strlen(fromuser)) {
				for (j = 5; j < ll; j++) {
					if (line[j] != ' ') {
						strcpy(fromuser, "telemail!");
						strcat(fromuser, &line[j]);
						line[j] = '\0';
						strcat(line, fromuser);
						ll = strlen(fromuser);
						fromuser[ll-1] = '\0';
						break;
					}
				}
			}
			if (debug > 1)
				fprintf(telelog, "Mail from %s to %s\n", fromuser, vaxuser);
		}
		/*
		 * if (!strncmp(line, "From:", 5) && !from) { s = &line[5];
		 * strcpy(newline, "From:"); xlate(s, &newline[5]);
		 * fputs(newline, fmsgfp); from = TRUE; continue; } 
		 *
		 * if (!strncmp(line, "To:", 3) && !to) { s = &line[3];
		 * strcpy(newline, "To:"); xlate(s, &newline[3]);
		 * fputs(newline, fmsgfp); to = TRUE; continue; } 
		 *
		 * if (!strncmp(line, "CC:", 3) && !cc) { s = &line[3];
		 * strcpy(newline, "Cc:"); xlate(s, &newline[3]);
		 * fputs(newline, fmsgfp); cc = TRUE; to = TRUE; continue; } 
		 *
		 * if (!strncmp(line, "Subj:", 5) && !subject) { fputs(line,
		 * fmsgfp); cc = TRUE; subject = TRUE; to = TRUE; continue; } 
		 *
		 * if (strlen(line) == 1 && !subject) { if (cc || to) { cc =
		 * TRUE; subject = TRUE; to = TRUE; } else continue; } 
		 *
		 * if (!strncmp(line, "       ", 7) && !subject) { s = line;
		 * xlate(s, newline); fputs(newline, fmsgfp); continue; } 
		 *
		 */
		fputs(line, fmsgfp);
	}

	fclose(fmsgfp);
	fclose(rmsgfp);
}

/* ====================================================================== */

getmail()
{
	int	status;

	mo("read\r");
	skiplf(30);
	for (;;) {
		strcpy(rawfile, "/tmp/TMRXXXXXX");
		mktemp(rawfile);

		rmsgfp = fopen(rawfile, "w");

		if (!rmsgfp) {
			tag();
			fprintf(telelog, "Could not open temporary file\n");
			return;
		}
		chmod(rawfile, 0600);
		sprintf(tbuf, "Getmsg for %s", teleuser);
		logpid(tbuf);
		status = getmsg();
		fclose(rmsgfp);

		if (status) {
			sprintf(tbuf, "Delivering to %s", vaxuser);
			logpid(tbuf);
			deliver();
			unlink(rawfile);
			mo("\r");
			skiplf(30);
		} else {
			unlink(rawfile);
			return;
		}
		logpid("msg delivered");
	}
}

/* ====================================================================== */

getmsg()
{
	int	action, command, i, output, timeout, tocnt;
	int	times; 	/* times through the timeout loop */
	char	mi(), c;

	action = 0;
	command = 0;
	output = TRUE;
	timeout = 30;
	tocnt = 0;
	times = 0;

	for (;;) {
		c = mi(timeout);

		if (action >= 0) {
			if (c == act[action]) {
				action++;
				timeout = 10;
				if (!c)
					return TRUE;
				continue;
			} else {
				if (output) {
					for (i = 0; i < action; i++)
						fwrite(&act[i], 1, 1, rmsgfp);
				}
				action = (-1);
			}
		}
		if (command >= 0) {
			if (c == cmd[command]) {
				command++;
				timeout = 10;
				if (!c)
					return FALSE;
				continue;
			} else {
				if (output) {
					for (i = 0; i < command; i++)
						fwrite(&cmd[i], 1, 1, rmsgfp);
				}
				command = (-1);
			}
		}
		if (!c) {
			if (debug > 3)
				fprintf(telelog, "\nTimeout in getmsg...trying\n");
			times++;

			if (times > 1) {	/* assume registered mail */
				if (times > 3)	/* assume ERROR */
					return(FALSE);
				mo("yes\r");
				output = TRUE;
				timeout = 30;
				action = 0;
				command = 0;
				tocnt = 0;
				continue;
			} else {			/* assume error */
				mo("\030foobar\r");
				timeout = 30;
				output = FALSE;
				action = 0;
				command = 0;
			}

			if (++tocnt > 2)
				return FALSE;

			continue;
		}
		if (c == '\n') {
			action = 0;
			command = 0;
			timeout = 30;
		} else
			timeout = 10;

		if (output)
			fwrite(&c, 1, 1, rmsgfp);
	}
}

/* ====================================================================== */

getuser()
{
	if (feof(teledir))
		return FALSE;

	fscanf(teledir, "%[^,],%[^,],%s\n",
	       teleuser, passwd, vaxuser);

	return TRUE;
}

/* ====================================================================== */

hangup(mode)
int	mode;
{
	init();
	mo("ATH\r");

	if (!expect("AT", 15)) {
		tag();
		fprintf(telelog, "Modem failure...did not echo ATH command\n");
		return FALSE;
	}
	skiplf(15);

	if (!expect("OK\n", 20)) {
		tag();
		fprintf(telelog, "Modem failure...did not get OK after ATH\n");
		return FALSE;
	}
	if (mode) {
		tag();
		fprintf(telelog, "Line disconnected\n");
	}
	return TRUE;
}

/* ====================================================================== */

init()
{
	char	mi();

	while (mi(10));
	mo("+++");
	if (skiplf(10))
		expect("OK\n", 15);
	mo("ATZ\r");
	skiplf(10);
	expect("OK\n", 15);
	sleep(2);
}

/* ====================================================================== */

lookup(in, out)
char	*in, *out;
{
	FILE	*userlist;
	int	i;
	char	tpasswd[10], tuser[80], vuser[20];

	userlist = fopen(userfile, "r");

	while (!feof(userlist)) {
		fscanf(userlist, "%[^,],%[^,],%s\n",
		       tuser, tpasswd, vuser);

		for (i = 0; i < strlen(tuser); i++) {
			if (tuser[i] != in[i])
				break;
		}

		if (i == strlen(tuser) || (!in[i] && tuser[i] == '/')) {
			strcpy(out, vuser);
			fclose(userlist);
			return;
		}
	}

	fclose(userlist);
	strcpy(out, "telemail!");
	strcat(out, in);
}

/* ====================================================================== */

maillogon()
{
	if (!findprompt("@", 20)) {
		mo("\r");
		if (!findprompt("@", 20)) {
			tag();
			fprintf(telelog, "No TELENET @ prompt at user#%d: %s\n", usercount, teleuser);
			return FALSE;
		}
	}
	mo("telemail\r");
	return TRUE;
}

/* ====================================================================== */

char 
mi(timout)
int	timout;
{
	char	c;

	if (unread) {
		c = unread;
		unread = 0;
		return (c);
	}
	tmouts = 0;

	signal(SIGALRM, clkint);	/* define interrupt handler */

	/* haral, 01/12/87, we seem to be stuck here forever... */
	if (tmouts > MAXTMOUT) {	/* let's give up after a while */
		return(FALSE);		/* to start up clean again */
	}
	if (!setjmp(env)) {
		do {
			alarm(timout);
			read(ttyfp, &c, 1);
			alarm(0);
			c = c & 0x7f;
		} while (!c || c == '\r');
	} else
		c = 0;

if (debug > 3) {
	if (!c)
		fprintf(telelog, "\nTimeout\n");
	else if (c == '\n')
		fprintf(telelog, "\n");
	else if (c < 32)
		fprintf(telelog, " %d ", c);
	else
		fprintf(telelog, "%c", c);
}

	return (c);
}

/* ====================================================================== */

mo(str)
char	*str;
{
	write(ttyfp, str, strlen(str));
}

/* ====================================================================== */

netlogon()
{
	sleep(2);
	mo("\r\r");
	if (!expect("\nTELENET\n", 30))
		return FALSE;
	skiplf(10);
	if (!expect("\nTERMINAL=", 20))
		return FALSE;
	mo("\r");
	return TRUE;
}

/* ====================================================================== */

reconnect()
{
	int i;
	for (i = 0;; i++) {
		if (connect())
			return (maillogon());
		else
			if (i > 4)
				break;
	}

	return FALSE;
}

/* ====================================================================== */

setupline(cflag)
int cflag;
{
	int	id;

	setbuf(stdout, NULL);
	telelog = fopen(logfile, "a");

	if (telelog == NULL) {
		printf("Cannot open %s\n", logfile);
		exit(-1);
	}
	setbuf(telelog, NULL);

	ulockf();

	ttyfp = open(culnm, 2);

	if (ttyfp < 0) {
		tag();
		fprintf(telelog, "Cannot open %s\n", culnm);
		unlink(lockfile);
		exit(-1);
	}
	teledir = fopen(userfile, "r");

	if (teledir == NULL) {
		tag();
		fprintf(telelog, "Cannot open %s\n", userfile);
		unlink(lockfile);
		exit(-2);
	}
	gtty(ttyfp, &savemode);
	gtty(ttyfp, &rawmode);

	rawmode.sg_flags |= CBREAK;
	rawmode.sg_flags |= TANDEM;
	rawmode.sg_flags &= ~(ECHO | CRMOD);
	rawmode.sg_ispeed = B1200;
	rawmode.sg_ospeed = B1200;

	stty(ttyfp, &rawmode);

	logpid("line set up");
}

/* ====================================================================== */

ulockf()
{
	int id;

	if (geteuid() == 0 && access(lockfile, 0) == 0) {
		tag();
		fprintf(telelog, "Cannot lock %s -- device busy\n", culnm);
		exit(-1);
	}
	ttylock = creat(lockfile, 0444);
	if (ttylock < 0) {
		tag();
		fprintf(telelog, "Cannot lock %s\n", culnm);
		exit(-1);
	}

	id = getpid();
	write(ttylock, (char *)&id, sizeof(int));
	close(ttylock);

}

/* ====================================================================== */

ultouch()
{
	chmod(lockfile, 0444);
}

/* ====================================================================== */

logpid(str)
char *str;
{
	char lbuf[512];
	FILE *tfp;
	static long clock;

	if (!clock)
		time(&clock);

	sprintf(lbuf, "%s/PID", spooldir);
	if ((tfp = fopen(lbuf, "w")) != NULL) {
		fprintf(tfp, "%d\n%ld\n%s\n", getpid(), clock, str);
		fclose(tfp);
	}
}

/* ====================================================================== */

skiplf(timeout)
int	timeout;
{
	char	mi(), c;

	do {
		if (!(c = mi(timeout)))
			return FALSE;
	} while (c != '\n');

	return TRUE;
}

/* ====================================================================== */


tag()
{
	struct tm      *tm;
	struct tm      *localtime();
#ifdef BSD42
	struct timeval  tp;
	struct timezone tzp;

	gettimeofday(&tp, &tzp);
	tm = localtime(&tp.tv_sec);
#else
	long *ltime;

	clock(&ltime);
	tm = localtime(&ltime);
#endif
	fprintf(telelog, "%02d/%02d/%02d %02d:%02d:%02d   ",
		tm->tm_mon + 1,
		tm->tm_mday,
		tm->tm_year,
		tm->tm_hour,
		tm->tm_min,
		tm->tm_sec);
}

/* ====================================================================== */

quit(rc)
int	rc;
{
	sprintf(buf, "%s/PID", spooldir);
	unlink(buf);
	hangup(1);
	unlink(lockfile);
	stty(ttyfp, &savemode);
	exit(rc);
}

/* ====================================================================== */

userlogoff()
{
	mo("\r");

	ultouch();
	logpid("logging out");
	if (findprompt(cmd, 30)) {
		mo("bye\r");
		if (debug) {
			tag();
			fprintf(telelog, "User %s logged off TELEMAIL\n", teleuser);
		}
	} else {	/* probably hung */
		if (!reconnect())
			quit(-4);
	}
	logpid("logged out");
}

/* ====================================================================== */

userlogon()
{
	ultouch();
	sprintf(tbuf, "logging in %s", teleuser);
	logpid(tbuf);
	if (!findprompt("User name?  ", 30)) {
		tag();
		fprintf(telelog, "Unable to logon to TELEMAIL for %s\n", teleuser);
		return FALSE;
	}
	mo(teleuser);
	mo("\r");	/* it was !\r */

	if (!findprompt("Password?  ", 30)) {
		tag();
		fprintf(telelog, "Invalid response from TELEMAIL (password) for %s\n", teleuser);
		return FALSE;
	}
	mo(passwd);
	mo("\r");

	if (findprompt(cmd, 30)) {
		if (debug) {
			tag();
			fprintf(telelog, "User %s logged in to TELEMAIL\n", teleuser);
		}
		sprintf(tbuf, "Logged in for %s", teleuser); 
		logpid(tbuf);
		return TRUE;
	}
	tag();
	fprintf(telelog, "Unable to log user %s in to TELEMAIL\n", teleuser);
	logpid("login failure");
	return FALSE;
}

/* ====================================================================== */

xlate(in, out)
char	*in;
char	*out;
{
	char	*s, lname[80], name[80];

	for (;;) {
		while (*in == ' ')
			*out++ = *in++;

		s = name;

		while (*in != ' ' && *in != ',' && *in != '\n') {
			if (*in == '(') {
				while (*in != ')' && *in != '\n')
					in++;

				if (*in == ')')
					in++;

				continue;
			}
			*s++ = isupper(*in) ? tolower(*in) : *in;
			in++;
		}

		*s = 0;

		if (name[0]) {
			lookup(name, lname);
			s = lname;

			while (*s)
				*out++ = *s++;
		}
		if (*in == ',')
			*out++ = *in++;

		if (*in == '\n') {
			*out++ = '\n';
			*out = 0;
			return;
		}
	}
}

/* ====================================================================== */

nomail()
{
	ultouch();
	sprintf(tbuf, "/bin/ls %s/%s.*", cfdir, vaxuser);
	if ((pp = popen(tbuf, "r")) == NULL) {
		tag();		
		fprintf(telelog, "Can't fork ls for %s\n", vaxuser);
		return(-2);
	}

	while (fgets(ucffile, 79, pp) != NULL) {
		l = strlen(ucffile);
		ucffile[l-1] = '\0';
		if (stat(ucffile, &dbuf))
			continue;
		else {
			fclose(pp);
			return(0);
		}
	}
	fclose(pp);
	return(1);
}
/* ====================================================================== */

purgemail()
{
	struct tm      *localtime();
	struct timeval  tp;
	struct timezone tzp;
	struct tm      *tm;
	int l, mm, dd, pmm, pdd;

	ultouch();
	logpid("purgemail");
	mo("\r");
	if (!findprompt(cmd, 30)) 
		return(-1);

	gettimeofday(&tp, &tzp);
	tm = localtime(&tp.tv_sec);
	mm = tm->tm_mon + 1;
	dd = tm->tm_mday;
	if (dd > 5) {
		pdd = dd - 5;
		pmm = mm;
	} else {
		pmm = mm - 1;
		if (pmm == 2)
			pdd = dd + 28 - 5;
		else
			pdd = dd + 31 - 5;
		if ((pmm == 4) || (pmm == 6) || (pmm == 9) || (pmm = 11))
			pdd = dd + 30 - 5;
	}
	sprintf(buf, "purge before %02d/%02d\r", pmm, pdd);
	mo(buf);

	return(0);
}
/* ====================================================================== */

putmail()
{
	int l, i;

	ultouch();
	logpid("putmail");
	mo("\r");
	if (!findprompt(cmd, 30)) 
		return(-1);

	sprintf(tbuf, "/bin/ls %s/%s.*", cfdir, vaxuser);
	if ((pp = popen(tbuf, "r")) == NULL) {
		tag();		
		fprintf(telelog, "Can't fork ls for %s\n", vaxuser);
		return(-2);
	}

	while (fgets(ucffile, 79, pp) != NULL) {
		l = strlen(ucffile);
		ucffile[l-1] = '\0';
		if (stat(ucffile, &dbuf))
			continue;
		ultouch();
		strcpy(seqnum, ucffile);
		for (i = l-1; i > 0; i--) {
			if (ucffile[i] == '.') {
				strcpy(seqnum, &ucffile[i+1]);
				break;
			}
		}
		sprintf(tbuf, "Sending for %s [%s]", vaxuser, seqnum);
		logpid(tbuf);
		if (sendmail(ucffile) < 0) {
			fclose(pp);
			return(-1);
		}
		if (!findprompt(cmd, 30)) {
			fclose(pp);
			return(-1);
		}
	}
	logpid("putmail end.");
	ultouch();
	fclose(pp);
	return(0);
}

/* ====================================================================== */

sendmail(cfile)
char *cfile;
{
	char ltuser[80], lvuser[80], touser[80], errmsg[80], nc;
	char subject[132];
	int seq, bytes, err, l, times, i, reads, skipc, line;

	if ((confp = fopen(cfile, "r")) == NULL) {
		tag();		
		fprintf(telelog, "Can't open %s\n", cfile);
		return(1);
	}
	if (fscanf(confp, "%s %s %s %d", ltuser, lvuser, touser, &seq) != 4) {
		tag();		
		fprintf(telelog, "%s: INVALID FORMAT.\n", cfile);
		sprintf(buf, "mv %s %s", cfile, bfdir);
		system(buf);
		fclose(confp);
		return(2);
	}
	fclose(confp);
	err = 0;
	if (strcmp(vaxuser, lvuser)) {
		err++;
		sprintf(errmsg, "%s != %s", vaxuser, lvuser);
	}
	l = strlen(ltuser);	
	if (strncmp(teleuser, ltuser, l)) {
		sprintf(errmsg, "%s != %s,%d", teleuser, ltuser, l);
		err++;
	}
	if (strcmp(teleuser, ltuser) && (teleuser[l] != '/')) {
		sprintf(errmsg, "%s != %s", teleuser, ltuser);
		err++;
	}
	if (err) {
		tag();		
		fprintf(telelog, "%s: INVALID CONTROL DATA[%s+%d].\n", cfile, errmsg, err);
		sprintf(buf, "mv %s %s", cfile, bfdir);
		system(buf);
		return(3);
	}
	sprintf(udffile, "%s/%s.%d", dfdir, vaxuser, seq);
	getsubject(udffile, subject);
	if ((fp = fopen(udffile, "r")) == NULL) {
		tag();		
		fprintf(telelog, "%s: MISSING DATA FILE.\n", udffile);
		sprintf(buf, "mv %s %s", cfile, bfdir);
		system(buf);
		return(4);
	}
	mo("compose\r");
	sleep(2);
	if (!fndstr("To:  ", 15)) {
		tag();		
		fprintf(telelog, "%s: No To: prompt, aborted.\n", cfile);
		fclose(fp);
		return(-5);
	}
	mo(touser);
	mo("\r");
	sleep(1);
	if (!fndstr("CC:  ", 15)) {
		tag();		
		fprintf(telelog, "%s: No CC: prompt, aborted.\n", cfile);
		fclose(fp);
		return(-5);
	}
	mo("\r");
	sleep(1);
	if (!fndstr("Subject:  ", 15)) {
		tag();		
		fprintf(telelog, "%s: No Subject: prompt, aborted.\n", cfile);
		fclose(fp);
		return(-5);
	}
	mo(subject);
	sleep(1);
	if (!fndstr("Text:", 15)) {
		tag();		
		fprintf(telelog, "%s: No Text: prompt, aborted.\n", cfile);
		fclose(fp);
		return(-5);
	}
	if (debug >= 9) {
		fprintf(telelog, "Sending message %s\n", cfile);
	}
	signal(SIGALRM, clkint);	/* define interrupt handler */

	skipc = 1;
	setjmp(env);
	alarm(5);
	if (skipc) {		/* here skip all junk before starting */
		skipc = 0;	/* to send the message down the line */
		while (read(ttyfp, &nc, 1));
	}
	alarm(0);
	ultouch();
	line = 0;
	while (fgets(buf, 511, fp) != NULL) {
		line++;
		if ((line % 10) == 0) {
			ultouch();	/* do it every 10 lines */
			sprintf(tbuf, "Sending for %s [%s: %d]", vaxuser, seqnum, line);
			logpid(tbuf);
		}
		l = strlen(buf);
		buf[l-1] = '\r';
		if (debug >= 9) {
			fprintf(telelog, "\n:%d:", l);
			fputs(buf, telelog);
		}
		if (buf[0] == '.')
			lcico('>');
		for (i = 0; i < l; i++) {
			if (lcico(buf[i])) {
				tag();
				fprintf(telelog, "Failed on write of :%s:%c:%s:%d\n", buf, buf[i], cfile, line);
				fclose(fp);
				return(-6);
			}
		}
	}
	fclose(fp);
	sleep(5);
	mo(".\r");
	sleep(5);
	if (!fndstr("Send?  ", 15)) {
		mo(".\r");
		sleep(5);
		if (!fndstr("Send?  ", 15)) {
			tag();		
			fprintf(telelog, "%s: No Send? prompt, aborted.\n", cfile);
			return(-5);
		}
	}
	mo("y\r");
	sleep(5);
	if (!fndstr("  Msg posted ", 15)) {
		tag();		
		fprintf(telelog, "%s: Message not posted.\n", cfile);
#ifdef BSD42
		sprintf(buf, "/usr/ucb/mail -s \"unable to forward message to %s\" %s < %s",
		touser, vaxuser, udffile);
#else
		sprintf(buf, "mail -s \"unable to forward message to %s\" %s < %s",
		touser, vaxuser, udffile);
#endif
		if (system(buf)) {
			sprintf(buf, "mv %s %s", cfile, bfdir);
			system(buf);
		} else {
			unlink(cfile);
			unlink(udffile);
		}
		return(-5);
	}
	bytes = 0;
	if (stat(udffile, &dbuf) == 0)
		bytes = dbuf.st_size;
	tag();
	fprintf(telelog, "MAIL SENT to %s from %s (%d bytes)\n", 
	touser, vaxuser, bytes);
	unlink(udffile);
	unlink(cfile);
}
/* ====================================================================== */

fndstr(str, timeout)
char	*str;
int	timeout;
{
	int	retry;

	retry = 0;

	do {
		if (!skiplf(timeout)) {
			if (retry++ > 2)
				return FALSE;
			continue;
		}
	} while (!expect(str, timeout));

	return TRUE;
}

lcico(cn)
char cn;
{
	char ch;
	int ttries, ltmout, stoped, times, gotit;

	signal(SIGALRM, clkint);	/* define interrupt handler */

	stoped = 0;
	times = 0;
	
	if (!(isprint(cn) || isspace(cn)))
		return(0);
	setjmp(env);
	ltmout = 5;
	gotit = 0;
	write(ttyfp, &cn, 1);
	if (times > 5) 		/* already through here */
		return(1);
	times++;

	for (;;) {
		alarm(ltmout);
		read(ttyfp, &ch, 1);
		alarm(0);

		ch = ch & 0x7f;
		if (debug >= 9)
			fprintf(telelog, "%c", ch);

		switch(ch) {
		case '':	/* flow control on */
			fprintf(telelog, "#");
			stoped = 1;
			ltmout = 30;
			break;
		case '':	/* flow control off */
			fprintf(telelog, "#");
			stoped = 0;
			ltmout = 5;
			if (gotit)
				return(0);
			break;
		default:		/* got a real character */
			if (stoped) {
				if (ch == cn)
					gotit++;
				break;
			}
			if (ch == cn || cn == '\r' || ch == '
				return(0); /* match or CR */
			if (debug >= 9)
				fprintf(telelog, "+");
			break;
		}
	}
}

getsubject(infile, buffer)
char infile[], buffer[];
{
	int l;
	FILE *fp;
	if ((fp = fopen(infile, "r")) == NULL) {
		sprintf(tbuf, FORWARDMSG, lochost, HW);
		strcpy(buffer, tbuf);
		return(0);
	}
	while (fgets(buf, 511, fp) != NULL) {
		if (strncmp(buf, "Subject: ", 9))
			continue;
		strcpy(buffer, &buf[9]);
		l = strlen(buffer);
		buffer[l-1] = '\0';
		sprintf(tbuf, " (remote from %s)\r", lochost);
		strcat(buffer, tbuf);
		fclose(fp);
		return(0);
	}
	sprintf(tbuf, FORWARDMSG, lochost, HW);
	strcpy(buffer, tbuf);
	fclose(fp);
	return(0);
}

getlochost()
{
#ifdef BSD4_2
	gethostname(lochost, 19);
#else
	FILE *pp, *popen();
	int l;
	if ((pp = popen("uuname -l", "r")) == NULL) {
		strcpy(lochost, "amnesia");
		return(0);
	}
	fgets(lochost, 19, pp);
	fclose(pp);
	l = strlen(lochost);
	lochost[l-1] = '\0';
#endif
	return(0);
}
//E*O*F telemail.c//

echo x - poll.telemail
cat > "poll.telemail" << '//E*O*F poll.telemail//'
#! /bin/sh
/usr/lib/uucp/telespool > /dev/null 2>&1
pid=`ps ax|grep '[0-9]:[0-9][0-9] /usr/lib/uucp/telemail'| awk '{print $1}'`
if test "$pid"
then
	if test "$1" = '-s'
	then
		echo "`date` LOCKED" >> /usr/spool/telemail/LOGFILE
		exit
	fi
	kill -10 $pid
	seq=`cat /usr/spool/telemail/SEQF`
	mv /core /usr/lib/uucp/core.$seq
 	echo "`date` terminated PID $pid" >> /usr/spool/telemail/LOGFILE
	rm /usr/spool/uucp/LCK..hys1200
	expr $seq + 1 > /usr/spool/telemail/SEQF
fi
for tty in hys1200 tty46 hys2400
do
	if test ! -f /usr/spool/uucp/LCK..$tty
	then
		/usr/lib/uucp/telemail -c$tty $* > /dev/null 2>&1
		break
	fi
done
cd /usr/spool/telemail/BAD
for i in *
do
	if test -f $i
	then
		vaxuser=`basename $i | awk -F. '{print $1}'`
		mail -s "Unable to deliver" $vaxuser < ../D/$i && rm $i ../D/$i
	fi
done

//E*O*F poll.telemail//

echo x - telespool
cat > "telespool" << '//E*O*F telespool//'
#! /bin/sh
#
#	telespool, 1/5/87, Haral Tsitsivas
#
#	convert UUCP spool files to telemail spool files
#
SPECIAL=atvax.tor/ashtontate
TUSERS=/usr/spool/telemail/USERS
USPOOL=/usr/spool/uucp
TSPOOL=/usr/spool/telemail
SEQ=/usr/spool/telemail/SEQF
HOST=`hostname`
seq=`cat ${SEQ}`
for i in `ls ${USPOOL}/C./C.telemai*`
do
	if test ! -f ${i}
	then
		break
	fi
	dfile=`head -1 ${i} | awk '{print $2}'`
	Dfile=${USPOOL}/D.${HOST}/${dfile}
	cfile=`tail -1 ${i} | awk '{print $2}'`
	Cfile=${USPOOL}/D.${HOST}X/${cfile}
	Fuser=`grep '^R ' ${Cfile} | awk '{print $2}'`
	Tuser=`grep '^C rmail' ${Cfile} | awk '{print $3}'`
	User=`grep ",${Fuser}$" ${TUSERS} | awk -F, '{print $1}'`
	if test -z "${User}"
	then
		User=$SPECIAL
		Fuser=telemail
	fi
#	echo $Dfile $Cfile $Fuser $Tuser $User $seq
	seq=`expr ${seq} '+' '1'`
	echo ${User} ${Fuser} ${Tuser} ${seq} > ${TSPOOL}/C/${Fuser}.${seq}
	mv ${Dfile} ${TSPOOL}/D/${Fuser}.${seq}
	rm ${Cfile} ${i}
#	rm ${Dfile}
done
echo $seq > ${SEQ}
//E*O*F telespool//

echo x - Makefile
cat > "Makefile" << '//E*O*F Makefile//'
SPOOL	= /usr/spool/telemail
LIB	= /usr/lib/uucp
BIN	= /usr/local
CRONTAB	= /usr/lib/crontab.local
FILES	= telemail.c poll.telemail telespool Makefile README TODO \
	telemail.1 crontab telsnap.c telsnap.1 telstats.c telstats.1 \
	telstats.example telsnap.example
# define this if BSD4_2 or later
LOCALFLAGS	= -DBSD42

telemail:	telemail.c
	cc -o telemail -g $(LOCALFLAGS) telemail.c

install:	telemail telsnap telstats
	chmod 755 telemail poll.telemail telespool telsnap
	cp telemail poll.telemail telespool $(LIB)
	cp telsnap telstats $(BIN)

setup:	
	mkdir $(SPOOL) $(SPOOL)/C $(SPOOL)/D  $(SPOOL)/BAD
	echo 'telemail Never' > $(LIB)/L.sys
	cat crontab >> $(CRONTAB)

tel.shar: $(FILES)
	shar $(FILES) > tel.shar

telsnap:	telsnap.c
	cc -o telsnap -g telsnap.c

telstats:	telstats.c
	cc -o telstats -g telstats.c
//E*O*F Makefile//

echo x - README
cat > "README" << '//E*O*F README//'
Telemail version 1.6+				January 9, 1987.

Installation procedure of the telemail program for 4.3 BSD systems.

To install this version of telemail do "make install".
If installing for the first time also do "make setup".

If you do NOT have 4.3 BSD you may have to do some editing, before
you attempt the installation.

1.	The crontab file format is different.  
	Take the "root" string out of the local crontab file.

2.	If you do not have BSD at all you will need to edit the
	telemail.c file and replace the "sendmail" command with
	something simpler such as "/bin/mail %s < %s", and use 
	only the "vaxuser" and "fmtfile" arguments.

3.	If you do not have BSD change the location of your crontab
	file in the Makefile (via the CRONTAB) variable.

4.	Change the script telespool which is used to transfer messages
	from the UUCP queue to the telemail queue.  Your directory
	structure is probably flat (as oppossed to C. and D. sub-
	directories).

5.	The system calls to get and convert the time, and priority may
	not be the same on your system.  You need to convert them (you
	could ignore the priority stuff completely).

For questions call Haral Tsitsivas at (213) 538-7692 or preferrably
send mail to:

	uucp:		ashtate!haral
	telemail:	htsitsivas/ashtontate
//E*O*F README//

echo x - TODO
cat > "TODO" << '//E*O*F TODO//'
H. Tsitsivas					05/11/87

Things still to do include:

Changing the setupline code to read L-devices to pick an appropriate
device (instead of the -s option).

Changing the "mi" routine and the "send" and "expect" routines since
most of the time is spent waiting or answering to the wrong prompts
courtesy of simplistic code on string recognition.

Make upload of text in compose mode more efficient since this is the
slowest part of the program right now...  It writes (and reads back)
a character at a time to avoid dropping blocks of text from the message
due to Telemail's being unable to keep up with a steady stream of 
1200 baud.

Accept registered mail that requires a Personal ID.

Send special mail (i.e. return receipt or registered mail).  This could
be accomplished by looking for something like "Keywords: registered,
return_receipt" in the body of the message (first line or so...).

If sending the same message to more than one telemail user, transmit
the article only once instead of the present "N" times.  Currently,
the article is broken up by "sendmail" and telemail (this program)
doesn't know about it.  I didn't want to play with "sendmail" though.

Make it more reliable on bad phone lines...

This program would be more efficient if it was running as an ADMIN 
account under Telemail so it would not have check for individual's
mailboxes...

A method to disable the automatic mail pickup for each user via the
creation of a .telemailrc file with instructions...  Useful when
traveling and only having access to telemail...
//E*O*F TODO//

echo x - telemail.1
cat > "telemail.1" << '//E*O*F telemail.1//'
.TH TELEMAIL 1 "February 23, 1987"
.UC 4
.SH NAME
telemail \- send and receive telemail messages
.SH SYNOPSIS
.B telemail
[
.B -dX
]
[
.B -cDEVICE
]
[
.B -tPHONE
]
[
.B -s
]
.br
.SH DESCRIPTION
.I Telemail
sends and receives messages for 
.B enrolled
users at periodic intervals as controlled by 
.B cron.
The crontab file should invoke the script poll.telemail at regular intervals.

Users can be enrolled to telemail by their system administrator who creates
and entry in the USERS file.  The format of the USERS file is:

username/organization,password,vaxlogin

(i.e. "htsitsivas/ashtontate,default,haral").

To forward mail by unenrolled users to telemail a special id would be
required in the USERS file under which id the messages would be forwarded,
and the SPECIAL variable in the script telespool should be accordingly 
changed.

The
.B -dX
option sets the debug mode to the value of the integer value X.  The default
is 0 (no debugging output produced).

The 
.B -cDEVICE
option sets the calling device to DEVICE.  As an example if calling on 
/dev/cua0 DEVICE would be cua0.  The default is hys1200.

The
.B -tPHONE 
option sets the phone number of the telemail system to PHONE.  For Torrance
this would be 95486141 (which is also the default).

The
.B -s 
option starts up telemail in send-only mode.  That means that no mail
will be received for any users (even though a login will be initiated
on their behalf).  This may be used to quickly send mail out without
being bogged down with receiving mail as well (and especially having to
login for dozens of users before getting to the user that wishes to send
mail).

It should be noted that telemail mail is handled as normal UUCP mail.
To send mail to a telemail user do "mail telemail!TELEUSER".  Messages
received from telemail are prepended the "telemail!" string so the "r"
option of mail will work to reply to messages.

The "telemail" command itself is reserved for the System Administrator,
as all spool files are protected from general perusal and the binary is
not set-uid.
.PP
.SH "SEE ALSO"
mail(1), sendmail(8), telsnap(1)
.SH FILES
.nf
/usr/lib/uucp/telemail		Telemail binary
/usr/lib/uucp/poll.telemail	Telemail polling script
/usr/lib/uucp/telespool		Telemail spool conversion
/usr/spool/uucp/LCK.device	Lockfile for device (UUCP)
/usr/spool/telemail/SEQF	Message sequence file
/usr/spool/telemail/USERS	User list
/usr/spool/telemail/LOGFILE	Log file
/usr/spool/telemail/ERRFILE	Error file
/usr/spool/telemail/C		Control file directory
/usr/spool/telemail/D		Data file directory
/usr/spool/telemail/BAD		Incorrect format file directory
/usr/spool/telemail/PID		PID and related telemail facts
.fi
.SH BUGS
The program may occasionally get lost amid the telemail prompts when a
bad phone line is encountered.  It is suggested that the LOGFILE is examined
from time to time for errors or suspect activity.  It is not beyond this 
program to spend lots of phone time on nothing (to the uninitiated that
means that the program occassionaly hangs on routines like alarm for no
apparent reason)...

Registered mail is accepted but is sent as a regular message under the 
UNIX mailer (since there is no way to send a registered UNIX message).

Registered messages cannot yet be sent from the VAX to telemail users.
.SH RETURN CODES
.nf
-1	Line busy or unable to lock
-2	No USERS file
-3	Failed to get a succesful connection
-4	Failed to get desired prompt
.fi
.SH AUTHOR
Modified by Haral Tsitsivas from original by John Gieselman (also A.
Felong and D. Kautter). Options added include: added  bi-directional
mailer, added telemail spool directory and uucp to telemail conversion
program, accepting registered messages, re-enforcement of uucp
lockfiles, status capability (see telsnap), more debug options, CBREAK
and TANDEM instead of RAW mode, purging of old mail and send-only mail
option.

//E*O*F telemail.1//

echo x - crontab
cat > "crontab" << '//E*O*F crontab//'
15 4,9,12,14,18	* * *	root	/usr/lib/uucp/poll.telemail
//E*O*F crontab//

echo x - telsnap.c
cat > "telsnap.c" << '//E*O*F telsnap.c//'
/*
 * This software is Copyright (c) 1987 by Haral Tsitsivas
 *
 * Permission is hereby granted to copy, reproduce, redistribute or
 * otherwise use this software as long as: there is no monetary
 * profit gained specifically from the use or reproduction or this
 * software, it is not sold, rented, traded or otherwise marketed, and
 * this copyright notice is included prominently in any copy
 * made.
 *
 * The author make no claims as to the fitness or correctness of
 * this software for any use whatsoever, and it is provided as is. 
 * Any use of this software is at the user's own risk.
 *
 *	telsnap.c, Haral Tsitsivas, 02/23/87, Version 1.0
 *
 *	print some facts about the telemail queue (like uusnap for UUCP)
 */
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>

main()
{
	struct stat dbuf;
	char buf[512], inbuf[512], last[512];
	int count, pid, ret, i, l, any;
	FILE *fp, *fopen(), *popen(), *pp;
	long ltime, clock, mins, stime, smins;

	if ((fp = fopen("/usr/spool/telemail/PID", "r")) != NULL) {
		stat("/usr/spool/telemail/PID", &dbuf);
		ltime = dbuf.st_mtime;
		time(&clock);
		mins = (clock - ltime) / (long) 60;
		fgets(buf, 511, fp);
		ret = sscanf(buf, "%d", &pid);
		if (ret == 1) {
			ret = 0;
			if (fgets(buf, 511, fp) != NULL)
				ret = sscanf(buf, "%ld", &stime);
			if (ret == 1)
				smins = (clock - stime) / (long) 60;
			else
				smins = (clock - ltime) / (long) 60;
			if (kill(pid, 0) == 0)
			printf("Telemail is running [pid %d: %ld mins]\n", pid, smins);
			else
			printf("Telemail is dead [%ld mins]\n", smins);
		}
		fgets(buf, 511, fp);
		l = strlen(buf);
		buf[l-1] = '\0';
		printf("Action \"%s\" for %ld minutes\n\n", buf, mins);
		fclose(fp);
	}
	last[0] = '\0';
	count = 0;
	buf[0] = '\0';
	any = 0;
	if ((pp = popen("/bin/ls /usr/spool/telemail/C", "r")) != NULL) {
		while (fgets(inbuf, 511, pp) != NULL) {
			if (!any) {
				printf("User     Count Request Id's\n\n");
				any++;
			}
			l = strlen(inbuf);
			inbuf[l-1] = '\0';
			for (i = 0; inbuf[i] != '\0'; i++)
				if (inbuf[i] == '.')
					break;
			inbuf[i] = '\0';
			if (!strcmp(last, inbuf)) {
				strcat(buf, " ");
				strcat(buf, &inbuf[i+1]);
				count++;
				continue;
			} 
			if (last[0]) {
				printf("%-10s %3d (%s)\n", last, count, buf);
				buf[0] = '\0';
			}
			strcpy(last, inbuf);
			count = 1;
			strcat(buf, &inbuf[i+1]);
		}
		fclose(pp);
		if (last[0]) {
			printf("%-10s %3d (%s)\n", last, count, buf);
		}
	}
	count = 0;
	if ((pp = popen("/bin/ls /usr/spool/uucp/C./C.telemai* 2> /dev/null", "r")) != NULL) {
		while (fgets(inbuf, 511, pp) != NULL) {
			l = strlen(inbuf);
			inbuf[l-1] = '\0';
			if (!stat(inbuf, &dbuf))
				count++;
		}
		fclose(pp);
	}
	if (count) {
		printf("UUCP QUEUE %3d\n", count);
	}
	last[0] = '\0';
	count = 0;
	buf[0] = '\0';
	any = 0;
	if ((pp = popen("/bin/ls /usr/spool/telemail/BAD", "r")) != NULL) {
		while (fgets(inbuf, 511, pp) != NULL) {
			if (!any) {
				any++;
				printf("\n*** BAD QUEUE ***\n\n");
			}
			l = strlen(inbuf);
			inbuf[l-1] = '\0';
			for (i = 0; inbuf[i] != '\0'; i++)
				if (inbuf[i] == '.')
					break;
			inbuf[i] = '\0';
			if (!strcmp(last, inbuf)) {
				strcat(buf, " ");
				strcat(buf, &inbuf[i+1]);
				count++;
				continue;
			} 
			if (last[0]) {
				printf("%-10s %3d (%s)\n", last, count, buf);
				buf[0] = '\0';
			}
			strcpy(last, inbuf);
			count = 1;
			strcat(buf, &inbuf[i+1]);
		}
		fclose(pp);
		if (last[0]) {
			printf("%-10s %3d (%s)\n", last, count, buf);
		}
	}
	exit(0);
}
//E*O*F telsnap.c//

echo x - telsnap.1
cat > "telsnap.1" << '//E*O*F telsnap.1//'
.TH TELSNAP 1 "February 23, 1987"
.UC 4
.SH NAME
telsnap \- report facts about the telemail queue
.SH SYNOPSIS
.B telsnap
.br
.SH DESCRIPTION
.I Telsnap
reports on items in the telemail queue, the BAD queue, the UUCP queue, 
and also on what (if anything) the "telemail" program is doing at the
moment telsnap was invoked.

The queue is reported with the headings "User", "Count" and "Request Id's"
under which the name of the requesting VAX user is listed, the number of
outgoing messages is reported, and, their internal telemail id's are also
reported (these are useful when tracking the progress of a message through
the telemail system).  

Items listed under "UUCP QUEUE" are not yet under control of telemail,
but rather, they are still located in the UUCP staging area.

Items listed under "BAD QUEUE" are waiting to be processed and returned to
the sender since they could not be delivered for some reason (such as
unknown telemail user id, or due to a clobbered or incorrect control file).
.PP
.SH "SEE ALSO"
uucp(1), mail(1), sendmail(8), telemail(1)
.SH FILES
.nf
/usr/spool/telemail/C		Control file directory
/usr/spool/telemail/BAD		Incorrect format file directory
/usr/spool/telemail/PID		PID and related telemail facts
/usr/spool/uucp/C.		UUCP Queue control file directory
.fi
.SH BUGS
This program does not correct anything, just reports on telemail status.
.SH AUTHOR
Haral Tsitsivas
//E*O*F telsnap.1//

echo x - telstats.c
cat > "telstats.c" << '//E*O*F telstats.c//'
/*
 * This software is Copyright (c) 1987 by Haral Tsitsivas
 *
 * Permission is hereby granted to copy, reproduce, redistribute or
 * otherwise use this software as long as: there is no monetary
 * profit gained specifically from the use or reproduction or this
 * software, it is not sold, rented, traded or otherwise marketed, and
 * this copyright notice is included prominently in any copy
 * made.
 *
 * The author make no claims as to the fitness or correctness of
 * this software for any use whatsoever, and it is provided as is. 
 * Any use of this software is at the user's own risk.
 *
 *	telstats.c, Haral Tsitsivas, 02/25/87, Version 1.0
 *
 *	collect statistics on telemail usage since last time program was run
 */
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>

#define LOGFILE	"/usr/spool/telemail/LOGFILE"
#define MAXUSERS 50
#define STRLEN	10
#define SLEN	40

struct stat dbuf;
char buf[512], inbuf[512], last[512];
char logfile[80];
char user[STRLEN];		/* current user name */
char users[MAXUSERS+1][STRLEN];	/* user names */
int miusers[MAXUSERS+1];	/* number of messages */
long biusers[MAXUSERS+1];	/* number of bytes */
int mousers[MAXUSERS+1];	/* number of messages */
long bousers[MAXUSERS+1];	/* number of bytes */
int musers[MAXUSERS+1];		/* number of messages */
long busers[MAXUSERS+1];	/* number of bytes */
int msgsin, msgsout;		/* total number of messages */
long bytesin, bytesout;		/* total number of bytes */
long bytes;			/* bytes per message */
int usrs;			/* users found so far */
int discs;			/* disconnects and hence connects */
int ret, i;
FILE *fp, *fopen();
char f3[SLEN], f4[SLEN], f9[SLEN];

main(argc, argv)
int argc;
char *argv[];
{
	int sum;
	int old;

	sum = 0;
	old = 0;

	/* there is room here for more options later on... */
	if (argc > 1) {
		for (i = 1; i < argc; i++) {
			switch(argv[i][0]) {
			case '-':
				switch(argv[i][1]) {
				case 's':
					sum = 1;
					break;
				case 'o':
					old = 1;
					break;
				default:
					printf("don't grok %s\n", argv[i]);
				}
				break;
			default:
				printf("don't grok %s\n", argv[i]);
			}
		}
	}

	if (old) {
		sum = 0;
		sprintf(logfile, "%s.OLD", LOGFILE);
	} else
		strcpy(logfile, LOGFILE);

	discs = 0;
	bytesin = 0;
	bytesout = 0;
	msgsin = 0;
	msgsout = 0;
	usrs = 0;
	if ((fp = fopen(logfile, "r")) == NULL) {
		printf("can't read %s\n", logfile);
		exit(-1);
	}
	while (fgets(inbuf, 511, fp) != NULL) {
		if (inbuf[0] == '#') {	/* skip flow control markers */
			for (i = 0; inbuf[i] != '\0'; i++) {
				if (inbuf[i] != '#') {
					strcpy(buf, &inbuf[i]);
					strcpy(inbuf, buf);
					break;
				}
			}
		}
		if (inbuf[2] != '/')
			continue;	/* who knows what that is... */
		sscanf(inbuf, "%*s %*s %s %s", f3, f4);
		if (!strcmp(f3, "Line") && !strcmp(f4, "disconnected")) {
			discs++;
			continue;
		}
		if (!strcmp(f3, "MAIL") && !strcmp(f4, "RECVD")) {
			recvd();
			continue;
		}
		if (!strcmp(f3, "MAIL") && !strcmp(f4, "SENT")) {
			sent();
			continue;
		}
	}
	fclose(fp);
	report();
	if (sum) {
		sprintf(buf, "cat %s >> %s.OLD", logfile, logfile);
		ret = system(buf);
		if (!ret) {
			if ((fp = fopen(logfile, "w")) != NULL) {
				fclose(fp);
			} else
				printf("Can't close out old %s\n", logfile);
		}
	}
	exit(0);
}

recvd()
{
	int indx;

	sscanf(inbuf, "%*s %*s %*s %*s %*s %s %*s %*s %s", user, f9);
	indx = indxusr(user);
	musers[indx]++;
	miusers[indx]++;
	bytes = atol(&f9[1]);
	biusers[indx] += bytes;
	busers[indx] += bytes;
	msgsin++;
	bytesin += bytes;
}

sent()
{
	int indx;

	sscanf(inbuf, "%*s %*s %*s %*s %*s %*s %*s %s %s", user, f9);
	indx = indxusr(user);
	musers[indx]++;
	mousers[indx]++;
	bytes = atol(&f9[1]);
	busers[indx] += bytes;
	bousers[indx] += bytes;
	msgsout++;
	bytesout += bytes;
}

indxusr(uname)
char *uname;
{
	int i;

	for (i = 0; i < usrs; i++) {
		if (!strcmp(users[i], uname))
			return(i);
	}
	strcpy(users[usrs], uname);
	i = usrs;
	if (usrs >= MAXUSERS) {
		strcpy(users[MAXUSERS], "other");
		return(MAXUSERS);
	}
	usrs++;
	musers[i] = 0;
	miusers[i] = 0;
	mousers[i] = 0;
	busers[i] = 0;
	biusers[i] = 0;
	bousers[i] = 0;
	return(i);
}

report() 
{
	FILE *pp, *popen();

	printf("\n%d connections established\n", discs);
	printf("\n%d Users RECVD %d msgs (%ld bytes) SENT %d msgs (%ld bytes)\n\n",
	usrs, msgsin, bytesin, msgsout, bytesout);
	if (!usrs) 
		return(0);
	printf("%-10s %-4s %10s %-4s %10s %-4s %10s\n",  
	"User", "Msgs", "Bytes", "Msgs", "Bytes", "Msgs", "Bytes");
	printf("%-10s %-4s %10s %-4s %10s %-4s %10s\n\n",  
	"Name", "Recv", "Recv", "Sent", "Sent", "Total", "Total");
	fflush(stdout);
	if ((pp = popen("sort -rn +6", "w")) != NULL) {
		for (i = 0; i < usrs; i++) {
			fprintf(pp, "%-10s %4d %10ld %4d %10ld %4d %10ld\n", 
			users[i], miusers[i], biusers[i], mousers[i], bousers[i], 
			musers[i], busers[i]);
		}
		pclose(pp);
	} else {
		for (i = 0; i < usrs; i++) {
			printf("%-10s %4d %10ld %4d %10ld %4d %10ld\n", 
			users[i], miusers[i], biusers[i], mousers[i], bousers[i], 
			musers[i], busers[i]);
		}
	}
}
//E*O*F telstats.c//

echo x - telstats.1
cat > "telstats.1" << '//E*O*F telstats.1//'
.TH TELSTATS 1 "February 25, 1987"
.UC 4
.SH NAME
telstats \- report statistics about telemail traffic
.SH SYNOPSIS
.B telstats 
[
.B \-s
]
[
.B \-o
]
.br
.SH DESCRIPTION
.I Telstats
produces statistics on telemail traffic in the form of:

.nf
XX connections established

YY Users SENT ZZ msgs (WW bytes) received VV msgs (UU bytes)

User       Msgs      Bytes
 \...

.fi
The 
.B -o
option indicates that the old file stats file should be used (the file
is cleared every night and items are appended to the old file).

The 
.B -s 
option indicates that the file should be reset when this program is run,
and before it is reset it should be appended to the old file (appropriate
permissions are required for this option).
.fi

.PP
.SH "SEE ALSO"
uucp(1), mail(1), sendmail(8), telemail(1), telsnap(1)
.SH FILES
.nf
/usr/spool/telemail/LOGFILE	LOGFILE where all the stats are kept
/usr/spool/telemail/LOGFILE.OLD	LOGFILE where all the old stats are kept
.fi
.SH AUTHOR
Haral Tsitsivas
//E*O*F telstats.1//

echo x - telstats.example
cat > "telstats.example" << '//E*O*F telstats.example//'

4 connections established

6 Users RECVD 5 msgs (10014 bytes) SENT 8 msgs (4763 bytes)

User       Msgs      Bytes Msgs      Bytes Msgs      Bytes
Name       Recv       Recv Sent       Sent Total      Total

cy            1       4298    0          0    1       4298
bobm          1       4298    0          0    1       4298
chrisc        0          0    5       2819    5       2819
dikiw         1        590    3       1944    4       2534
donnab        1        590    0          0    1        590
garyc         1        238    0          0    1        238
//E*O*F telstats.example//

echo x - telsnap.example
cat > "telsnap.example" << '//E*O*F telsnap.example//'
User     Count Request Id's

garyc        3 (355 356 357)
//E*O*F telsnap.example//

exit 0