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(<ime); tm = localtime(<ime); #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