/* @(#) proclist -- dispatch listserv requests to catmail * * Due to a bug in SCO Unix's MMDF, we can't use listserv's * /usr/server/catmail program within an aliased pipe. For * some odd reason, MMDF strips the first internet header line * in pipes. Listserv absolutely requires that this * "From address Date" header line be present. * * The work-around is to force incoming mail for listserv and * mailing lists to land in physical mailboxes belonging to * pseudo-users. This will require creating /etc/passwd users * to receive requests for the listserver and each mailing list. * The names are insignificant and may be aliased in * /usr/mmdf/table/alias.list. You will need one for 'listserv' * and one for each supported mailing list. * * This program, intended to be run either as a crontab entry or * interactively, will look for mail for the selected user and, * if the mail file exists, will strip the MMDF Ctrl-A separators * (which confuse listserv) from each message and pipe them through * /usr/server/catmail using the arguments specified on the command * line. See the server.nr dox for more information about catmail * arguments. * * Finally, we will launch the server program to process incoming * mail. The 'serverd' field in /usr/server/config file must * specify '-1' to tell the server not to load itself into the * background. The server will only run if we have found mail and * successfully piped it through catmail. * * Usage: proclist * i.e.: proclist listserv -r -f * proclist mcycle -L MCYCLE -f * * Author: Steve Manes manes@magpie.nycenet.edu * * Manes and Associates, NYC * July 1, 1992 * * Developed for Learning Link, Linknet, Inc. * Public Broadcasting System, NYC */ #include #include #include #include #include #include #include #define SPOOLDIR "/usr/spool/mail" #define CATMAIL "/usr/server/catmail" #define SERVER "/usr/server/start" #define LOGFILE "/usr/spool/listserv/errlog" #define CTRL_A 1 #define FILENAMESIZE 128 #define RECBUFSIZE 512 #define MAXRETRIES 10 #define ERROR -1 void usage(); void log(); void main( int argc, char *argv[] ) { FILE *ofd, *catfd; int ifd, i, sz, count; struct stat Stat; struct flock Flock; int try; char buf[RECBUFSIZE+1], mailfile[FILENAMESIZE+1], workfile[FILENAMESIZE+1], catfile[FILENAMESIZE+1]; if (argc < 2) usage(); /* make sure that we have read/write access to * the user's mailfile */ sprintf(mailfile, "%s/%s", SPOOLDIR, argv[1]); if (access(mailfile, F_OK)) { log("Mailfile %s not found!\n", mailfile); exit(1); } else if (access(mailfile, R_OK)) { log("Mailfile %s: no read permission!\n", mailfile); exit(1); } else if (access(mailfile, W_OK)) { log("Mailfile %s: no write permission!\n", mailfile); exit(1); } else if (stat(mailfile, &Stat)) { log("Can't stat %s!\n", mailfile); exit(1); } else if (Stat.st_size < 1) { log("%s has no mail for me\n", mailfile); exit(1); } /* make sure we can open a pipe to listserv's catmail */ strcpy(catfile, CATMAIL); if (access(catfile, X_OK)) { log("Can't execute %s\n", catfile); exit( 1 ); } for (i=2; i < argc; i++) { /* append catmail's command line */ strcat(catfile, " "); strcat(catfile, argv[i]); } /* open the mailfile */ if ((ifd = open(mailfile, O_RDWR)) == ERROR) { log("Can't open input %s\n", mailfile); exit(1); } /* lock the mailfile from other processes */ Flock.l_type = F_WRLCK; /* write-lock only */ Flock.l_whence = 0L; /* from beginning of file */ Flock.l_start = Flock.l_len = 0L; /* till the end of file */ /* wait twenty seconds to assert a lock */ for (try=0; fcntl(ifd, F_SETLK, &Flock) < 0; try++) { if (try == MAXRETRIES) { log("Can't lock %s\n", mailfile); exit(1); } sleep(2); /* wait a coupla seconds... */ } /* copy mail file to tmp directory for processing */ sprintf(workfile, "/tmp/PROCLIST.%d", getpid()); if ((ofd = fopen(workfile, "w+")) == NULL) { log("Can't open output %s\n", workfile); exit(1); } while( (sz = read(ifd, buf, RECBUFSIZE)) > 0) fwrite(buf, sizeof(char), sz, ofd); chsize(ifd, 0L); /* make file empty */ /* unlock the file */ Flock.l_type = F_UNLCK; Flock.l_whence = 0L; /* from beginning of file */ Flock.l_start = Flock.l_len = 0L; /* till the end of file */ fcntl(ifd, F_SETLK, &Flock); close(ifd); /* and close it */ /* At this point, we have the user's mailfile copied to /tmp, * where we can operate on it without being disturbed by other * processes. We also zapped his SPOOLDIR mail so it's ready * to accept mail without us getting in the way. */ rewind(ofd); /* back to the top */ catfd = NULL; count = 0; /* page through the mail file, piping each message to catmail */ while (fgets(buf, RECBUFSIZE, ofd) != NULL) { /* MMDF's message separators make this easy, but * listserv will choke on 'em so stifle 'em */ if (buf[0] == CTRL_A) { if (catfd != NULL) { pclose(catfd); catfd = NULL; } continue; } if (catfd == NULL) { if ((catfd = popen(catfile, "w")) == NULL) { log("Can't open pipe to %s\n", buf); exit( 1 ); } count++; } fputs(buf, catfd); } if (catfd != NULL) pclose(catfd); /* close the CATMAIL pipe */ fclose(ofd); /* close the /tmp workfile... */ unlink(workfile); /* and delete it. */ log("%d message(s) processed\n", count); if (execl(SERVER, "start", "-c", NULL) == ERROR) perror(SERVER); } /*---[ usage ]------------------------------------------------------------- show program arguments --------------------------------------------------------------------------*/ void usage() { fprintf(stderr, "usage: proclist \n"); exit( 1 ); } /*---[ log ]--------------------------------------------------------------- log error messages to file LOGFILE if LOGFILE, doesn't exist, don't create it --------------------------------------------------------------------------*/ void log( va_alist ) va_dcl { va_list args; char *fmt, tbuf[20]; FILE *fd; time_t t; if ( !access(LOGFILE, W_OK) ) { /* is there a logfile? */ va_start(args); fmt = va_arg(args, char *); time(&t); if ((fd = fopen(LOGFILE, "a")) != NULL) { strftime(tbuf, 20, "%m/%d %H:%M:%S ", localtime(&t)); fprintf(fd, "%s", tbuf); vfprintf(fd, fmt, args); va_end(args); fclose(fd); } } } /* END PROCLIST */