sources-request@mirror.UUCP (07/02/86)
Submitted by: Dave Taylor <pyramid!hplabs!hpldat!taylor> Mod.sources: Volume 6, Issue 38 Archive-name: elm/Part13 # Continuation of Shell Archive, created by hpldat!taylor # This is part 13 # To unpack the enclosed files, please use this file as input to the # Bourne (sh) shell. This can be most easily done by the command; # sh < thisfilename if [ ! -d utils ] then echo creating directory utils mkdir utils fi # ---------- file utils/arepdaemon.c ---------- filename="utils/arepdaemon.c" if [ -f $filename ] then echo File \"$filename\" already exists\! Skipping... filename=/dev/null # throw it away else echo extracting file utils/arepdaemon.c... fi cat << 'END-OF-FILE' > $filename /** arepdaemon.c **/ /** (C) Copyright 1986 Dave Taylor **/ /** Keep track of mail as it arrives, and respond by sending a 'recording' file to the sender as new mail is received. Note: the user program that interacts with this program is the 'autoreply' program and that should be consulted for further usage information. This program is part of the 'autoreply' system, and is designed to run every hour and check all mailboxes listed in the file "/etc/autoreply.data", where the data is in the form: username replyfile current-mailfile-size To avoid a flood of autoreplies, this program will NOT reply to mail that contains header "X-Mailer: fastmail". Further, each time the program responds to mail, the 'mailfile size' entry is updated in the file /etc/autoreply.data to allow the system to be brought down and rebooted without any loss of data or duplicate messages. This daemon also uses a lock semaphore file, /usr/spool/uucp/LCK..arep, to ensure that more than one copy of itself is never running. For this reason, it is recommended that this daemon be started up each morning from cron, since it will either start since it's needed or simply see that the file is there and disappear. Since this particular program is the main daemon answering any number of different users, it must be run with uid root. (C) 1985, Dave Taylor, HP Colorado Networks Operation **/ #include <stdio.h> #include <time.h> #include <sys/types.h> #include <sys/stat.h> #include "defs.h" static char ident[] = { WHAT_STRING }; #define arep_lock_file "/usr/spool/uucp/LCK..arep" #define autoreply_file "/etc/autoreply.data" #define fastmail "/usr/local/bin/fastmail" #define logfile "/etc/autoreply.log" /* first choice */ #define logfile2 "/tmp/autoreply.log" /* second choice */ #define BEGINNING 0 /* see fseek(3S) for info */ #define SLEEP_TIME 3600 /* run once an hour */ #define MAX_PEOPLE 20 /* max number in program */ #define EXISTS 00 /* lock file exists?? */ #define MODE 0777 /* lockfile creation mode */ #define NLEN 20 #define remove_return(s) if (strlen(s) > 0) { \ if (s[strlen(s)-1] == '\n') \ s[strlen(s)-1] = '\0'; \ } struct replyrec { char username[NLEN]; /* login name of user */ char mailfile[SLEN]; /* name of mail file */ char replyfile[SLEN]; /* name of reply file */ long mailsize; /* mail file size */ int in_list; /* for new replies */ } reply_table[MAX_PEOPLE]; FILE *logfd; /* logfile (log action) */ long autoreply_size = 0L; /* size of autoreply file */ int active = 0; /* # of people 'enrolled' */ FILE *open_logfile(); /* forward declaration */ long bytes(); /* ditto */ main() { long size; int person, data_changed; if (! lock()) exit(0); /* already running! */ while (1) { logfd = open_logfile(); /* open the log */ /* 1. check to see if autoreply table has changed.. */ if ((size = bytes(autoreply_file)) != autoreply_size) { read_autoreply_file(); autoreply_size = size; } /* 2. now for each active person... */ data_changed = 0; for (person = 0; person < active; person++) { if ((size = bytes(reply_table[person].mailfile)) != reply_table[person].mailsize) { if (size > reply_table[person].mailsize) read_newmail(person); /* else mail removed - resync */ reply_table[person].mailsize = size; data_changed++; } } /* 3. if data changed, update autoreply file */ if (data_changed) update_autoreply_file(); close_logfile(); /* close the logfile again */ /* 4. Go to sleep... */ sleep(SLEEP_TIME); } } int read_autoreply_file() { /** We're here because the autoreply file has changed size!! It could either be because someone has been added or because someone has been removed...since the list will always be in order (nice, eh?) we should have a pretty easy time of it... **/ FILE *file; char username[SLEN], replyfile[SLEN]; int person; long size; log("Autoreply data file has changed! Reading..."); if ((file = fopen(autoreply_file,"r")) == NULL) { log("No-one is using autoreply..."); return(0); } for (person = 0; person < active; person++) reply_table[person].in_list = 0; while (fscanf(file, "%s %s %dl", username, replyfile, &size) != EOF) { /* check to see if this person is already in the list */ if ((person = in_list(username)) != -1) { reply_table[person].in_list = 1; reply_table[person].mailsize = size; /* sync */ } else { /* if not, add them */ if (active == MAX_PEOPLE) { unlock(); exit(log("Couldn't add %s - already at max people!", username)); } log("adding %s to the active list", username); strcpy(reply_table[active].username, username); sprintf(reply_table[active].mailfile, "/usr/mail/%s", username); strcpy(reply_table[active].replyfile, replyfile); reply_table[active].mailsize = size; reply_table[active].in_list = 1; /* obviously! */ active++; } } /** now check to see if anyone has been removed... **/ for (person = 0; person < active; person++) if (reply_table[person].in_list == 0) { log("removing %s from the active list", reply_table[person].username); strcpy(reply_table[person].username, reply_table[active-1].username); strcpy(reply_table[person].mailfile, reply_table[active-1].mailfile); strcpy(reply_table[person].replyfile, reply_table[active-1].replyfile); reply_table[person].mailsize = reply_table[active-1].mailsize; active--; } } update_autoreply_file() { /** update the entries in the autoreply file... **/ FILE *file; register int person; if ((file = fopen(autoreply_file,"w")) == NULL) { log("Couldn't update autoreply file!"); return; } for (person = 0; person < active; person++) fprintf(file, "%s %s %ld\n", reply_table[person].username, reply_table[person].replyfile, reply_table[person].mailsize); fclose(file); printf("updated autoreply file\n"); autoreply_size = bytes(autoreply_file); } int in_list(name) char *name; { /** search the current active reply list for the specified username. return the index if found, or '-1' if not. **/ register int index; for (index = 0; index < active; index++) if (strcmp(name, reply_table[index].username) == 0) return(index); return(-1); } read_newmail(person) int person; { /** Read the new mail for the specified person. **/ FILE *mailfile; char from_whom[LONG_SLEN], subject[SLEN]; int sendit; log("New mail for %s", reply_table[person].username); if ((mailfile = fopen(reply_table[person].mailfile,"r")) == NULL) return(log("can't open mailfile for user %s", reply_table[person].username)); if (fseek(mailfile, reply_table[person].mailsize, BEGINNING) == -1) return(log("couldn't seek to %ld in mail file!", reply_table[person].mailsize)); while (get_return(mailfile, person, from_whom, subject, &sendit) != -1) if (sendit) reply_to_mail(person, from_whom, subject); return; } int get_return(file, person, from, subject, sendit) FILE *file; int person, *sendit; char *from, *subject; { /** Reads the new message and return the from and subject lines. sendit is set to true iff it isn't a machine generated msg **/ char name1[SLEN], name2[SLEN], lastname[SLEN]; char buffer[LONG_SLEN], hold_return[NLEN]; int done = 0, in_header = 0; from[0] = '\0'; *sendit = 1; while (! done) { if (fgets(buffer, LONG_SLEN, file) == NULL) return(-1); if (first_word(buffer, "From ")) { in_header++; sscanf(buffer, "%*s %s", hold_return); } else if (in_header) { if (first_word(buffer, ">From")) { sscanf(buffer,"%*s %s %*s %*s %*s %*s %*s %*s %*s %s", name1, name2); add_site(from, name2, lastname); } else if (first_word(buffer,"Subject:")) { remove_return(buffer); strcpy(subject, (char *) (buffer + 8)); } else if (first_word(buffer,"X-Mailer: fastmail")) *sendit = 0; else if (strlen(buffer) == 1) done = 1; } } if (from[0] == '\0') strcpy(from, hold_return); /* default address! */ else add_site(from, name1, lastname); /* get the user name too! */ return(0); } add_site(buffer, site, lastsite) char *buffer, *site, *lastsite; { /** add site to buffer, unless site is 'uucp', or the same as lastsite. If not, set lastsite to site. **/ char local_buffer[LONG_SLEN], *strip_parens(); if (strcmp(site, "uucp") != 0) if (strcmp(site, lastsite) != 0) { if (buffer[0] == '\0') strcpy(buffer, strip_parens(site)); /* first in list! */ else { sprintf(local_buffer,"%s!%s", buffer, strip_parens(site)); strcpy(buffer, local_buffer); } strcpy(lastsite, strip_parens(site)); /* don't want THIS twice! */ } } remove_first_word(string) char *string; { /** removes first word of string, ie up to first non-white space following a white space! **/ register int loc; for (loc = 0; string[loc] != ' ' && string[loc] != '\0'; loc++) ; while (string[loc] == ' ' || string[loc] == '\t') loc++; move_left(string, loc); } move_left(string, chars) char string[]; int chars; { /** moves string chars characters to the left DESTRUCTIVELY **/ register int i; chars--; /* index starting at zero! */ for (i=chars; string[i] != '\0' && string[i] != '\n'; i++) string[i-chars] = string[i]; string[i-chars] = '\0'; } reply_to_mail(person, from, subject) int person; char *from, *subject; { /** Respond to the message from the specified person with the specified subject... **/ char buffer[SLEN]; if (strlen(subject) == 0) strcpy(subject, "Auto-reply Mail"); else if (! first_word(subject,"Auto-reply")) { sprintf(buffer, "Auto-reply to:%s", subject); strcpy(subject, buffer); } log("auto-replying to '%s'", from); mail(from, subject, reply_table[person].replyfile, person); } reverse(string) char *string; { /** reverse string... pretty trivial routine, actually! **/ char buffer[SLEN]; register int i, j = 0; for (i = strlen(string)-1; i >= 0; i--) buffer[j++] = string[i]; buffer[j] = '\0'; strcpy(string, buffer); } long bytes(name) char *name; { /** return the number of bytes in the specified file. This is to check to see if new mail has arrived.... **/ int ok = 1; extern int errno; /* system error number! */ struct stat buffer; if (stat(name, &buffer) != 0) if (errno != 2) { unlock(); exit(fprintf(stderr,"Error %d attempting fstat on %s", errno, name)); } else ok = 0; return(ok ? buffer.st_size : 0); } mail(to, subject, filename, person) char *to, *subject, *filename; int person; { /** Mail 'file' to the user from person... **/ char buffer[VERY_LONG_STRING]; sprintf(buffer, "%s -f '%s [autoreply]' -s '%s' %s %s", fastmail, reply_table[person].username, subject, filename, to); system(buffer); } log(message, arg) char *message; char *arg; { /** Put log entry into log file. Use the format: date-time: <message> **/ struct tm *localtime(), *thetime; long time(), clock; char buffer[SLEN]; /** first off, get the time and date **/ clock = time((long *) 0); /* seconds since ??? */ thetime = localtime(&clock); /* and NOW the time... */ /** then put the message out! **/ sprintf(buffer, message, arg); fprintf(logfd,"%d/%d-%d:%02d: %s\n", thetime->tm_mon+1, thetime->tm_mday, thetime->tm_hour, thetime->tm_min, buffer); } FILE *open_logfile() { /** open the logfile. returns a valid file descriptor **/ FILE *fd; if ((fd = fopen(logfile, "a")) == 0) if ((fd = fopen(logfile2, "a")) == 0) { unlock(); exit(1); /* give up! */ } return( (FILE *) fd); } close_logfile() { /** Close the logfile until needed again. **/ fclose(logfd); } char *strip_parens(string) char *string; { /** Return string with all parenthesized information removed. This is a non-destructive algorithm... **/ static char buffer[LONG_SLEN]; register int i, depth = 0, buffer_index = 0; for (i=0; i < strlen(string); i++) { if (string[i] == '(') depth++; else if (string[i] == ')') depth--; else if (depth == 0) buffer[buffer_index++] = string[i]; } buffer[buffer_index] = '\0'; return( (char *) buffer); } /*** LOCK and UNLOCK - ensure only one copy of this daemon running at any given time by using a file existance semaphore (wonderful stuff!) ***/ lock() { /** Try to create the lock file. If it's there, or we can't create it for some stupid reason, return zero, otherwise, a non-zero return code indicates success in locking this process in. **/ if (access(arep_lock_file, EXISTS) == 0) return(0); /* file already exists!! */ if (creat(arep_lock_file, MODE) == -1) return(0); /* can't create file!! */ return(1); } unlock() { /** remove lock file if it's there! **/ (void) unlink(arep_lock_file); } END-OF-FILE if [ "$filename" != "/dev/null" ] then size=`wc -c < $filename` if [ $size != 13380 ] then echo $filename changed - should be 13380 bytes, not $size bytes fi chmod 666 $filename fi # ---------- file utils/autoreply.c ---------- filename="utils/autoreply.c" if [ -f $filename ] then echo File \"$filename\" already exists\! Skipping... filename=/dev/null # throw it away else echo extracting file utils/autoreply.c... fi cat << 'END-OF-FILE' > $filename /** autoreply.c **/ /** This is the front-end for the autoreply system, and performs two functions: it either adds the user to the list of people using the autoreply function (starting the daemon if no-one else) or removes a user from the list of people. Usage: autoreply filename autoreply "off" or autoreply [to find current status] (C) 1986, Dave Taylor **/ #include <stdio.h> #include <errno.h> #include <sys/types.h> #include <sys/stat.h> #include "defs.h" static char ident[] = { WHAT_STRING }; #define READ_ACCESS 04 /* is file readable? */ #define tempdir "/tmp/arep" /* file prefix */ #define autoreply_file "/etc/autoreply.data" /* autoreply data file */ extern int errno; /* system error code */ char username[NLEN]; /* login name of user */ main(argc, argv) int argc; char *argv[]; { char filename[SLEN]; if (argc > 2) { printf("Usage: %s <filename>\tto start autoreply,\n", argv[0]); printf(" %s off\t\tto turn off autoreply\n", argv[0]); printf(" or %s \t\tto check current status\n", argv[0]); exit(1); } (void) cuserid(username); if (argc == 1 || strcmp(argv[1], "off") == 0) remove_user((argc == 1)); else { strcpy(filename, argv[1]); if (access(filename,READ_ACCESS) != 0) { printf("Error: Can't read file '%s'\n", filename); exit(1); } if (filename[0] != '/') /* prefix home directory */ sprintf(filename,"%s/%s", getenv("HOME"), argv[1]); add_user(filename); } exit(0); } remove_user(stat_only) int stat_only; { /** Remove the user from the list of currently active autoreply people. If 'stat_only' is set, then just list the name of the file being used to autoreply with, if any. **/ FILE *temp, *repfile; char tempfile[SLEN], user[SLEN], filename[SLEN]; int c, copied = 0, found = 0; long filesize, bytes(); if (! stat_only) { sprintf(tempfile, "%s.%06d", tempdir, getpid()); if ((temp = fopen(tempfile, "w")) == NULL) { printf("Error: couldn't open tempfile '%s'. Not removed\n", tempfile); exit(1); } } if ((repfile = fopen(autoreply_file, "r")) == NULL) { if (stat_only) { printf("You're not currently autoreplying to mail.\n"); exit(0); } printf("No-one is autoreplying to their mail!\n"); exit(0); } /** copy out of real replyfile... **/ while (fscanf(repfile, "%s %s %ld", user, filename, &filesize) != EOF) if (strcmp(user, username) != 0) { if (! stat_only) { copied++; fprintf(tempfile, "%s %s %ld\n", user, filename, filesize); } } else { if (stat_only) { printf("You're currently autoreplying to mail with the file %s\n", filename); exit(0); } found++; } fclose(temp); fclose(repfile); if (! found) { printf("You're not currently autoreplying to mail%s\n", stat_only? "." : "!"); if (! stat_only) unlink(tempfile); exit(! stat_only); } /** now copy tempfile back into replyfile **/ if (copied == 0) { /* removed the only person! */ unlink(autoreply_file); } else { /* save everyone else */ if ((temp = fopen(tempfile,"r")) == NULL) { printf("Error: couldn't reopen tempfile '%s'. Not removed.\n", tempfile); unlink(tempfile); exit(1); } if ((repfile = fopen(autoreply_file, "w")) == NULL) { printf( "Error: couldn't reopen autoreply file for writing! Not removed.\n"); unlink(tempfile); exit(1); } while ((c = getc(temp)) != EOF) putc(c, repfile); fclose(temp); fclose(repfile); } unlink(tempfile); if (found > 1) printf("Warning: your username appeared %d times!! Removed all\n", found); else printf("You've been removed from the autoreply table.\n"); } add_user(filename) char *filename; { /** add the user to the autoreply file... **/ FILE *repfile; char mailfile[SLEN]; long bytes(); if ((repfile = fopen(autoreply_file, "a")) == NULL) { printf("Error: couldn't open the autoreply file! Not added\n"); exit(1); } sprintf(mailfile,"%s/%s", mailhome, username); fprintf(repfile,"%s %s %ld\n", username, filename, bytes(mailfile)); fclose(repfile); printf("You've been added to the autoreply system.\n"); } long bytes(name) char *name; { /** return the number of bytes in the specified file. This is to check to see if new mail has arrived.... **/ int ok = 1; extern int errno; /* system error number! */ struct stat buffer; if (stat(name, &buffer) != 0) if (errno != 2) exit(fprintf(stderr,"Error %d attempting fstat on %s", errno, name)); else ok = 0; return(ok ? buffer.st_size : 0L); } END-OF-FILE if [ "$filename" != "/dev/null" ] then size=`wc -c < $filename` if [ $size != 4746 ] then echo $filename changed - should be 4746 bytes, not $size bytes fi chmod 666 $filename fi # ---------- file utils/fastmail.c ---------- filename="utils/fastmail.c" if [ -f $filename ] then echo File \"$filename\" already exists\! Skipping... filename=/dev/null # throw it away else echo extracting file utils/fastmail.c... fi cat << 'END-OF-FILE' > $filename /** fastmail.c **/ /** This program is specifically written for group mailing lists and such batch type mail processing. It does NOT use aliases at all, it does NOT read the /etc/password file to find the From: name of the user and does NOT expand any addresses. It is meant purely as a front-end for either /bin/mail or /usr/lib/sendmail (according to what is available on the current system). **** This program should be used with CAUTION ***** (C) Copyright 1985 Dave Taylor **/ /** The calling sequence for this program is: fastmail {args} filename full-email-address where args could be any (or all) of; -b bcc-list (Blind carbon copies to) -c cc-list (carbon copies to) -d (debug on) -f from (from name) -r reply-to-address (Reply-To:) -s subject (subject of message) **/ #include <stdio.h> #ifdef BSD # include <sys/time.h> #else # include <time.h> #endif #include "defs.h" static char ident[] = { WHAT_STRING }; #define binrmail "/bin/rmail" #define temphome "/tmp/fastmail." #define DONE 0 #define ERROR -1 char *optional_arg; /* optional argument as we go */ int opt_index; /* argnum + 1 when we leave */ char *arpa_dayname[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "" }; char *arpa_monname[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", ""}; char *get_arpa_date(); #ifdef BSD char *timezone(); #else extern char *tzname[]; #endif main(argc, argv) int argc; char *argv[]; { FILE *tempfile; char hostname[NLEN], username[NLEN], from_string[SLEN], subject[SLEN]; char filename[SLEN], tempfilename[SLEN], command_buffer[256]; char replyto[SLEN], cc_list[SLEN], bcc_list[SLEN], to_list[SLEN]; int c, sendmail_available, debug = 0; replyto[0] = '\0'; cc_list[0] = '\0'; bcc_list[0] = '\0'; while ((c = get_options(argc, argv, "b:c:df:r:s:")) > 0) { switch (c) { case 'b' : strcpy(bcc_list, optional_arg); break; case 'c' : strcpy(cc_list, optional_arg); break; case 'd' : debug++; break; case 'f' : strcpy(from_string, optional_arg); break; case 'r' : strcpy(replyto, optional_arg); break; case 's' : strcpy(subject, optional_arg); break; } } if (c == ERROR) { fprintf(stderr,"Usage: fastmail {args} filename address(es)\n"); fprintf(stderr, " where {args} can be;\n"); fprintf(stderr,"\t-b bcc-list\n\t-c cc-list\n\t-d\n\t-f from-name\n"); fprintf(stderr, "\t-r reply-to\n\t-s subject\n\n"); exit(1); } if (opt_index > argc) { fprintf(stderr,"Usage: fastmail {args} filename address(es)\n"); fprintf(stderr, " where {args} can be;\n"); fprintf(stderr,"\t-b bcc-list\n\t-c cc-list\n\t-d\n\t-f from-name\n"); fprintf(stderr, "\t-r reply-to\n\t-s subject\n\n"); exit(1); } strcpy(filename, argv[opt_index++]); if (opt_index > argc) { fprintf(stderr,"Usage: fastmail {args} filename address(es)\n"); fprintf(stderr, " where {args} can be;\n"); fprintf(stderr,"\t-b bcc-list\n\t-c cc-list\n\t-d\n\t-f from-name\n"); fprintf(stderr, "\t-r reply-to\n\t-s subject\n\n"); exit(1); } gethostname(hostname, sizeof(hostname)); strcpy(username, getlogin()); if (strlen(username) == 0) cuserid(username); if (access(filename, READ_ACCESS) == -1) exit(fprintf(stderr, "Error: can't find file %s!\n", filename)); sprintf(tempfilename, "%s%d", temphome, getpid()); if ((tempfile = fopen(tempfilename, "w")) == NULL) exit(fprintf(stderr, "Couldn't open temp file %s\n", tempfilename)); if (strlen(from_string) > 0) fprintf(tempfile, "From: %s!%s (%s)\n", hostname, username, from_string); else fprintf(tempfile, "From: %s!%s\n", hostname, username); fprintf(tempfile, "Date: %s\n", get_arpa_date()); if (strlen(subject) > 0) fprintf(tempfile, "Subject: %s\n", subject); if (strlen(replyto) > 0) fprintf(tempfile, "Reply-To: %s\n", replyto); while (opt_index < argc) sprintf(to_list, "%s%s%s", to_list, (strlen(to_list) > 0? ", ":""), argv[opt_index++]); fprintf(tempfile, "To: %s\n", to_list); if (strlen(cc_list) > 0) fprintf(tempfile, "Cc: %s\n", cc_list); if (strlen(bcc_list) > 0) fprintf(tempfile, "Bcc: %s\n", bcc_list); /* trust xport */ fprintf(tempfile, "X-Mailer: fastmail [version %s]\n", VERSION); fprintf(tempfile, "\n"); fclose(tempfile); /** now we'll cat both files to /bin/rmail or sendmail... **/ sendmail_available = (access(sendmail, EXECUTE_ACCESS) != -1); printf("Mailing to %s%s%s%s%s [via %s]\n", to_list, (strlen(cc_list) > 0 ? " ":""), cc_list, (strlen(bcc_list) > 0 ? " ":""), bcc_list, sendmail_available? "sendmail" : "rmail"); sprintf(command_buffer, "cat %s %s | %s '%s %s %s'", tempfilename, filename, sendmail_available? sendmail : mailer, to_list, cc_list, bcc_list); if (debug) printf("%s\n", command_buffer); system(command_buffer); unlink(tempfilename); } char *get_arpa_date() { /** returns an ARPA standard date. The format for the date according to DARPA document RFC-822 is exemplified by; Mon, 12 Aug 85 6:29:08 MST **/ static char buffer[SLEN]; /* static character buffer */ struct tm *the_time, /* Time structure, see CTIME(3C) */ *localtime(); long junk; /* time in seconds.... */ #ifdef BSD struct timeval time_val; struct timezone time_zone; #endif #ifdef BSD gettimeofday(&time_val, &time_zone); junk = time_val.tv_sec; #else junk = time(0); /* this must be here for it to work! */ #endif the_time = localtime(&junk); sprintf(buffer, "%s, %d %s %d %d:%02d:%02d %s", arpa_dayname[the_time->tm_wday], the_time->tm_mday % 32, arpa_monname[the_time->tm_mon], the_time->tm_year % 100, the_time->tm_hour % 24, the_time->tm_min % 61, the_time->tm_sec % 61, #ifdef BSD timezone(time_zone.tz_minuteswest, time_zone.tz_dsttime)); #else tzname[the_time->tm_isdst]); #endif return( (char *) buffer); } /** Starting argument parsing routine. Called as "get_options(argc, argv, options)" where options is a string of the form "abc:d" indicating that 'a' 'b' and 'd' are flags and 'c' is a flag with a trailing argument. Optional arguments are returned in the external char * variable "optional_arg", and the external int "opt_index" is set to the first entry in the argv list that wasn't processed (ie after the flags). For example, the C compiler would have something of the form getopt(argc, argv, "Oo:l:") to allow "cc -O -o output -l lib file.c" (C) Copyright 1986, Dave Taylor **/ int _indx = 1, _argnum = 1; int get_options(argc, argv, options) int argc; char *argv[], *options; { /** Returns the character argument next, and optionally instantiates "argument" to the argument associated with the particular option **/ char *word, *strchr(); if (_indx >= strlen(argv[_argnum])) { _argnum++; _indx = 1; /* zeroeth char is '-' */ } if (_argnum >= argc) { opt_index = argc; return(DONE); } if (argv[_argnum][0] != '-') { opt_index = _argnum; return(DONE); } word = strchr(options, argv[_argnum][_indx++]); if (strlen(word) == 0) return(ERROR); if (word[1] == ':') { /** Two possibilities - either tailing end of this argument or the next argument in the list **/ if (_indx < strlen(argv[_argnum])) { /* first possibility */ optional_arg = (char *) (argv[_argnum] + _indx); _argnum++; _indx = 1; } else { /* second choice */ if (++_argnum >= argc) return(ERROR); /* no argument!! */ optional_arg = (char *) argv[_argnum++]; _indx = 1; } } return((int) word[0]); } END-OF-FILE if [ "$filename" != "/dev/null" ] then size=`wc -c < $filename` if [ $size != 7799 ] then echo $filename changed - should be 7799 bytes, not $size bytes fi chmod 666 $filename fi # ---------- file utils/from.c ---------- filename="utils/from.c" if [ -f $filename ] then echo File \"$filename\" already exists\! Skipping... filename=/dev/null # throw it away else echo extracting file utils/from.c... fi cat << 'END-OF-FILE' > $filename /** from.c **/ /** print out whom each message is from in the pending mailbox or specified one, including a subject line if available.. Added PREFER_UUCP knowledge 6/86 (C) Copyright 1986 Dave Taylor **/ #include <stdio.h> #include "defs.h" static char ident[] = { WHAT_STRING }; #define LINEFEED (char) 10 #define metachar(c) (c == '=' || c == '+' || c == '%') FILE *mailfile; char *expand_define(); main(argc, argv) int argc; char *argv[]; { char infile[LONG_SLEN], username[SLEN]; if (argc > 2) exit(printf("Usage: %s {filename}\n", argv[0])); if (argc == 2) strcpy(infile, argv[1]); else { strcpy(username, getlogin()); if (strlen(username) == 0) cuserid(username); sprintf(infile,"%s/%s",mailhome, username); } if (metachar(infile[0])) if (expand(infile) == 0) printf("%s: couldn't expand filename %s!\n", argv[0], infile); if ((mailfile = fopen(infile,"r")) == NULL) { if (argc == 1) printf("No mail!\n"); else printf("%s: Couldn't open file %s\n", argv[0], infile); } else if (read_headers()==0) printf("No messages in mailbox!\n"); } int read_headers() { /** read the headers, output as found **/ char buffer[LONG_SLEN], from_whom[SLEN], subject[SLEN]; register int subj = 0, in_header = 1, count = 0; while (fgets(buffer, LONG_SLEN, mailfile) != NULL) { if (first_word(buffer,"From ")) { if (real_from(buffer, from_whom)) { subj = 0; in_header = 1; } } else if (in_header) { if (first_word(buffer,">From")) forwarded(buffer, from_whom); /* return address */ else if (first_word(buffer,"Subject:") || first_word(buffer,"Re:")) { if (! subj++) { remove_first_word(buffer); strcpy(subject, buffer); } } else if (first_word(buffer,"From:")) parse_arpa_from(buffer, from_whom); else if (buffer[0] == LINEFEED) { in_header = 0; /* in body of message! */ show_header(from_whom, subject); from_whom[0] = 0; subject[0] = 0; count++; } } } return(count); } int real_from(buffer, who) char *buffer, *who; { /***** returns true iff 's' has the seven 'from' fields, initializing the who to the sender *****/ char junk[80]; junk[0] = '\0'; sscanf(buffer, "%*s %s %*s %*s %*s %*s %s", who, junk); return(junk[0] != '\0'); } forwarded(buffer, who) char *buffer, *who; { /** change 'from' and date fields to reflect the ORIGINATOR of the message by iteratively parsing the >From fields... **/ char machine[80], buff[80]; machine[0] = '\0'; sscanf(buffer, "%*s %s %*s %*s %*s %*s %*s %*s %*s %s", who, machine); if (machine[0] == '\0') /* try for srm address */ sscanf(buffer, "%*s %s %*s %*s %*s %*s %*s %*s %s", who, machine); if (machine[0] == '\0') sprintf(buff,"anonymous"); else sprintf(buff,"%s!%s", machine, who); strncpy(who, buff, 80); } remove_first_word(string) char *string; { /** removes first word of string, ie up to first non-white space following a white space! **/ register int loc; for (loc = 0; string[loc] != ' ' && string[loc] != '\0'; loc++) ; while (string[loc] == ' ' || string[loc] == '\t') loc++; move_left(string, loc); } move_left(string, chars) char string[]; int chars; { /** moves string chars characters to the left DESTRUCTIVELY **/ register int i; chars--; /* index starting at zero! */ for (i=chars; string[i] != '\0' && string[i] != '\n'; i++) string[i-chars] = string[i]; string[i-chars] = '\0'; } show_header(from, subject) char *from, *subject; { /** output header in clean format, including abbreviation of return address if more than one machine name is contained within it! **/ char buffer[SLEN]; int loc, i=0, exc=0; #ifdef PREFER_UUCP if (chloc(from,'!') != -1 && in_string(from, BOGUS_INTERNET)) from[strlen(from) - strlen(BOGUS_INTERNET)] = '\0'; #endif loc = strlen(from); while (exc < 2 && loc > 0) if (from[--loc] == '!') exc++; if (exc == 2) { /* lots of machine names! Get last one */ loc++; while (loc < strlen(from) && loc < SLEN) buffer[i++] = from[loc++]; buffer[i] = '\0'; printf("%-20s %s\n", buffer, subject); } else printf("%-20s %s\n", from, subject); } parse_arpa_from(buffer, newfrom) char *buffer, *newfrom; { /** try to parse the 'From:' line given... It can be in one of two formats: From: Dave Taylor <hpcnou!dat> or From: hpcnou!dat (Dave Taylor) Change 'newfrom' ONLY if sucessfully parsed this entry and the resulting name is non-null! **/ char temp_buffer[SLEN], *temp; register int i, j = 0; temp = (char *) temp_buffer; temp[0] = '\0'; no_ret(buffer); /* blow away '\n' char! */ if (lastch(buffer) == '>') { for (i=strlen("From: "); buffer[i] != '\0' && buffer[i] != '<' && buffer[i] != '('; i++) temp[j++] = buffer[i]; temp[j] = '\0'; } else if (lastch(buffer) == ')') { for (i=strlen(buffer)-2; buffer[i] != '\0' && buffer[i] != '(' && buffer[i] != '<'; i--) temp[j++] = buffer[i]; temp[j] = '\0'; reverse(temp); } if (strlen(temp) > 0) { /* mess with buffer... */ /* remove leading spaces... */ while (whitespace(temp[0])) temp = (char *) (temp + 1); /* increment address! */ /* remove trailing spaces... */ i = strlen(temp) - 1; while (whitespace(temp[i])) temp[i--] = '\0'; /* if anything is left, let's change 'from' value! */ if (strlen(temp) > 0) strcpy(newfrom, temp); } } reverse(string) char *string; { /** reverse string... pretty trivial routine, actually! **/ char buffer[SLEN]; register int i, j = 0; for (i = strlen(string)-1; i >= 0; i--) buffer[j++] = string[i]; buffer[j] = '\0'; strcpy(string, buffer); } int expand(infile) char *infile; { /** Expand the filename since the first character is a meta- character that should expand to the "maildir" variable in the users ".elmrc" file... Note: this is a brute force way of getting the entry out of the .elmrc file, and isn't recommended for the faint of heart! **/ FILE *rcfile; char buffer[SLEN], *expanded_dir, *home, *getenv(), *bufptr; int foundit = 0; bufptr = (char *) buffer; /* same address */ if ((home = getenv("HOME")) == NULL) { printf( "Can't expand environment variable $HOME to find .elmrc file!\n"); exit(1); } sprintf(buffer, "%s/%s", home, elmrcfile); if ((rcfile = fopen(buffer, "r")) == NULL) { printf("Can't open your \".elmrc\" file (%s) for reading!\n", buffer); exit(1); } while (fgets(buffer, SLEN, rcfile) != NULL && ! foundit) { if (strncmp(buffer, "maildir", 7) == 0 || strncmp(buffer, "folders", 7) == 0) { while (*bufptr != '=' && *bufptr) bufptr++; bufptr++; /* skip the equals sign */ while (whitespace(*bufptr) && *bufptr) bufptr++; home = bufptr; /* remember this address */ while (! whitespace(*bufptr) && *bufptr != '\n') bufptr++; *bufptr = '\0'; /* remove trailing space */ foundit++; } } fclose(rcfile); /* be nice... */ if (! foundit) { printf("Couldn't find \"maildir\" in your .elmrc file!\n"); exit(1); } /** Home now points to the string containing your maildir, with no leading or trailing white space... **/ expanded_dir = expand_define(home); sprintf(buffer, "%s%s%s", expanded_dir, (expanded_dir[strlen(expanded_dir)-1] == '/' || infile[0] == '/') ? "" : "/", (char *) infile+1); strcpy(infile, buffer); } char *expand_define(maildir) char *maildir; { /** This routine expands any occurances of "~" or "$var" in the users definition of their maildir directory out of their .elmrc file. Again, another routine not for the weak of heart or staunch of will! **/ static char buffer[SLEN]; /* static buffer AIEE!! */ char name[SLEN], /* dynamic buffer!! (?) */ *nameptr, /* pointer to name?? */ *value; /* char pointer for munging */ if (*maildir == '~') sprintf(buffer, "%s%s", getenv("HOME"), ++maildir); else if (*maildir == '$') { /* shell variable */ /** break it into a single word - the variable name **/ strcpy(name, (char *) maildir + 1); /* hurl the '$' */ nameptr = (char *) name; while (*nameptr != '/' && *nameptr) nameptr++; *nameptr = '\0'; /* null terminate */ /** got word "name" for expansion **/ if ((value = getenv(name)) == NULL) { printf("Couldn't expand shell variable $%s in .elmrc!\n", name); exit(1); } sprintf(buffer, "%s%s", value, maildir + strlen(name) + 1); } return( ( char *) buffer); } END-OF-FILE if [ "$filename" != "/dev/null" ] then size=`wc -c < $filename` if [ $size != 8783 ] then echo $filename changed - should be 8783 bytes, not $size bytes fi chmod 666 $filename fi # ---------- file utils/newmail.c ---------- filename="utils/newmail.c" if [ -f $filename ] then echo File \"$filename\" already exists\! Skipping... filename=/dev/null # throw it away else echo extracting file utils/newmail.c... fi cat << 'END-OF-FILE' > $filename /** newmail.c **/ /** Keep track of the mail for the current user...if new mail arrives, output a line of the form; Mail has arrived from <name> - <subject> where <name> is either the persons full name, or machine!login. If there is no subject, it will say. Added: you can specify a file other than the mailbox to keep track of - if an argument is given, the program will try to use it as a filename... Also, the program will quit when you log off of the machine. (C) 1986, Dave Taylor **/ #ifdef AUTO_BACKGROUND #include <signal.h> /* background jobs ignore some signals... */ #endif #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include "defs.h" static char ident[] = { WHAT_STRING }; #define LINEFEED (char) 10 #define BEGINNING 0 /* seek fseek(3S) */ #define SLEEP_TIME 60 #define NO_SUBJECT "(No Subject Specified)" FILE *mailfile; long bytes(); main(argc, argv) int argc; char *argv[]; { char filename[LONG_SLEN]; long size, newsize; if (argc > 2) fprintf(stderr, "Usage: %s [filename] &\n", argv[0]); else if (argc == 2) { strcpy(filename, argv[1]); if (access(filename, ACCESS_EXISTS) == -1) { fprintf(stderr,"%s: Can't open file %s to keep track of!\n", argv[0], filename); exit(1); } } else sprintf(filename,"%s/%s",mailhome, getlogin()); #ifdef AUTO_BACKGROUND if (fork()) /* automatically puts this task in background! */ exit(0); signal(SIGINT, SIG_IGN); signal(SIGQUIT, SIG_IGN); signal(SIGHUP, SIG_DFL); /* so we exit when logged out */ #endif size = bytes(filename); mailfile = (FILE *) NULL; while (1) { #ifndef AUTO_BACKGROUND /* won't work if we're nested this deep! */ if (getppid() == 1) /* we've lost our shell! */ exit(); #endif /** Note the lack of error checking on the fopen() (Philip Peake did!) - this is okay since if it fails we don't have any mail and we can sleep(60) and try again later... **/ if (mailfile == (FILE *) NULL) mailfile = fopen(filename,"r"); if ((newsize = bytes(filename)) > size) { /* new mail */ fseek(mailfile, size, BEGINNING); /* skip all current mail */ size = newsize; printf("\n\r"); /* blank lines surrounding message */ read_headers(); printf("\n\r"); } else if (newsize != size) { size = newsize; /* mail's been removed... */ (void) fclose(mailfile); /* close it and ... */ mailfile = (FILE *) NULL; /* let's reopen the file */ } sleep(SLEEP_TIME); } } int read_headers() { /** read the headers, output as found **/ char buffer[LONG_SLEN], from_whom[SLEN], subject[SLEN]; register int subj = 0, in_header = 1, count = 0; while (fgets(buffer, LONG_SLEN, mailfile) != NULL) { if (first_word(buffer,"From ")) { if (real_from(buffer, from_whom)) { subj = 0; in_header = 1; } } else if (in_header) { if (first_word(buffer,">From")) forwarded(buffer, from_whom); /* return address */ else if (first_word(buffer,"Subject:") || first_word(buffer,"Re:")) { if (! subj++) { remove_first_word(buffer); strcpy(subject, buffer); } } else if (first_word(buffer,"From:")) parse_arpa_from(buffer, from_whom); else if (buffer[0] == LINEFEED) { in_header = 0; /* in body of message! */ show_header(from_whom, subject); from_whom[0] = 0; subject[0] = 0; count++; } } } return(count); } int real_from(buffer, who) char *buffer, *who; { /***** returns true iff 's' has the seven 'from' fields, initializing the who to the sender *****/ char junk[80]; junk[0] = '\0'; sscanf(buffer, "%*s %s %*s %*s %*s %*s %s", who, junk); return(junk[0] != '\0'); } forwarded(buffer, who) char *buffer, *who; { /** change 'from' and date fields to reflect the ORIGINATOR of the message by iteratively parsing the >From fields... **/ char machine[80], buff[80]; machine[0] = '\0'; sscanf(buffer, "%*s %s %*s %*s %*s %*s %*s %*s %*s %s", who, machine); if (machine[0] == '\0') /* try for srm address */ sscanf(buffer, "%*s %s %*s %*s %*s %*s %*s %*s %s", who, machine); if (machine[0] == '\0') sprintf(buff,"anonymous"); else sprintf(buff,"%s!%s", machine, who); strncpy(who, buff, 80); } remove_first_word(string) char *string; { /** removes first word of string, ie up to first non-white space following a white space! **/ register int loc; for (loc = 0; string[loc] != ' ' && string[loc] != '\0'; loc++) ; while (string[loc] == ' ' || string[loc] == '\t') loc++; move_left(string, loc); } move_left(string, chars) char string[]; int chars; { /** moves string chars characters to the left DESTRUCTIVELY **/ register int i; chars--; /* index starting at zero! */ for (i=chars; string[i] != '\0' && string[i] != '\n'; i++) string[i-chars] = string[i]; string[i-chars] = '\0'; } show_header(from, subject) char *from, *subject; { /** output header in clean format, including abbreviation of return address if more than one machine name is contained within it! **/ char buffer[SLEN]; int loc, i=0, exc=0; #ifdef PREFER_UUCP if (chloc(from, '!') != -1 && in_string(from, BOGUS_INTERNET)) from[strlen(from) - strlen(BOGUS_INTERNET)] = '\0'; #endif loc = strlen(from); while (exc < 2 && loc > 0) if (from[--loc] == '!') exc++; if (exc == 2) { /* lots of machine names! Get last one */ loc++; while (loc < strlen(from) && loc < SLEN) buffer[i++] = from[loc++]; buffer[i] = '\0'; strcpy(from, buffer); } if (strlen(subject) < 2) strcpy(subject, NO_SUBJECT); printf(">> New mail from %s - %s\n\r", from, subject); } parse_arpa_from(buffer, newfrom) char *buffer, *newfrom; { /** try to parse the 'From:' line given... It can be in one of two formats: From: Dave Taylor <hpcnou!dat> or From: hpcnou!dat (Dave Taylor) Change 'newfrom' ONLY if sucessfully parsed this entry and the resulting name is non-null! **/ char temp_buffer[SLEN], *temp; register int i, j = 0; temp = (char *) temp_buffer; temp[0] = '\0'; no_ret(buffer); /* blow away '\n' char! */ if (lastch(buffer) == '>') { for (i=strlen("From: "); buffer[i] != '\0' && buffer[i] != '<' && buffer[i] != '('; i++) temp[j++] = buffer[i]; temp[j] = '\0'; } else if (lastch(buffer) == ')') { for (i=strlen(buffer)-2; buffer[i] != '\0' && buffer[i] != '(' && buffer[i] != '<'; i--) temp[j++] = buffer[i]; temp[j] = '\0'; reverse(temp); } if (strlen(temp) > 0) { /* mess with buffer... */ /* remove leading spaces... */ while (whitespace(temp[0])) temp = (char *) (temp + 1); /* increment address! */ /* remove trailing spaces... */ i = strlen(temp) - 1; while (whitespace(temp[i])) temp[i--] = '\0'; /* if anything is left, let's change 'from' value! */ if (strlen(temp) > 0) strcpy(newfrom, temp); } } reverse(string) char *string; { /** reverse string... pretty trivial routine, actually! **/ char buffer[SLEN]; register int i, j = 0; for (i = strlen(string)-1; i >= 0; i--) buffer[j++] = string[i]; buffer[j] = '\0'; strcpy(string, buffer); } long bytes(name) char *name; { /** return the number of bytes in the specified file. This is to check to see if new mail has arrived.... **/ int ok = 1; extern int errno; /* system error number! */ struct stat buffer; if (stat(name, &buffer) != 0) if (errno != 2) exit(fprintf(stderr,"Error %d attempting fstat on %s", errno, name)); else ok = 0; return(ok ? buffer.st_size : 0); } END-OF-FILE if [ "$filename" != "/dev/null" ] then size=`wc -c < $filename` if [ $size != 7761 ] then echo $filename changed - should be 7761 bytes, not $size bytes fi chmod 666 $filename fi # ---------- file utils/newalias.c ---------- filename="utils/newalias.c" if [ -f $filename ] then echo File \"$filename\" already exists\! Skipping... filename=/dev/null # throw it away else echo extracting file utils/newalias.c... fi cat << 'END-OF-FILE' > $filename /** newalias.c **/ /** (C) Copyright 1986 Dave Taylor **/ /** Install a new set of aliases for the 'Elm' mailer. If invoked with a specific filename, it assumes that it is working with an individual users alias tables, and generates the .alias.hash and .alias.data files in their home directory. If, however, it is invoked with no arguments, then it assumes that the user is updating the system alias file and uses the defaults for everything. The format for the input file is; alias1, alias2, ... : username : address or alias1, alias2, ... : groupname: member, member, member, ... member, member, member, ... "-q" flag added: 6/17/86 **/ #ifdef BSD # include <sys/file.h> #else # include <fcntl.h> #endif #include <stdio.h> #include "defs.h" /* ELM system definitions */ static char ident[] = { WHAT_STRING }; #ifndef TAB # define TAB '\t' /* TAB character! */ #endif #define alias_hash ".alias_hash" #define alias_data ".alias_data" #define alias_text ".alias_text" #define group(string) (strpbrk(string,", ") != NULL) struct alias_rec shash_table[MAX_SALIASES]; /* the actual hash table */ struct alias_rec uhash_table[MAX_UALIASES]; /* the actual hash table */ int hash_table_loaded=0; /* is system table actually loaded? */ int buff_loaded; /* for file input overlap... */ int error= 0; /* if errors, don't save! */ int system=0; /* system file updating? */ int count=0; /* how many aliases so far? */ long offset = 0L; /* data file line offset! */ main(argc, argv) int argc; char *argv[]; { FILE *in, *data; char inputname[SLEN], hashname[SLEN], dataname[SLEN]; char home[SLEN], buffer[LONG_STRING]; int hash, count = 0, owner, quiet = 0; if (argc != 1) if (strcmp(argv[1], "-q") == 0) quiet++; else exit(printf("Usage: %s\n", argv[0])); owner = getuid(); if (owner == 0 && ! quiet) { /* being run by root! */ printf("Would you like to update the system aliases? (y/n)"); gets(buffer, 2); if (buffer[0] == 'y' || buffer[0] == 'Y') { printf("Updating the system alias file...\n"); sprintf(inputname, "%s/%s", mailhome, alias_text); sprintf(hashname, "%s/%s", mailhome, alias_hash); sprintf(dataname, "%s/%s", mailhome, alias_data); system++; init_table(shash_table, MAX_SALIASES); } else printf("Updating your personal alias file...\n"); } if (! system) { if (strcpy(home, getenv("HOME")) == NULL) exit(printf("Confused: No HOME variable in environment!\n")); sprintf(inputname, "%s/%s", home, alias_text); sprintf(hashname, "%s/%s", home, alias_hash); sprintf(dataname, "%s/%s", home, alias_data); init_table(uhash_table, MAX_UALIASES); read_in_system(shash_table, sizeof shash_table); } if ((in = fopen(inputname,"r")) == NULL) exit(printf("Couldn't open %s for input!\n", inputname)); if ((hash = open(hashname, O_WRONLY | O_CREAT, 0644)) == -1) exit(printf("Couldn't open %s for output!\n", hashname)); if ((data = fopen(dataname,"w")) == NULL) exit(printf("Couldn't open %s for output!\n", dataname)); buff_loaded = 0; /* file buffer empty right now! */ while (get_alias(in, buffer) != -1) { if (system) put_alias(data, buffer, shash_table, MAX_SALIASES); else put_alias(data, buffer, uhash_table, MAX_UALIASES); count++; } if (error) { printf("\n** Not saving tables! Please fix and re-run %s!\n", argv[0]); exit(1); } else { if (system) write(hash, shash_table, sizeof shash_table); else write(hash, uhash_table, sizeof uhash_table); close(hash); fclose(data); close(in); printf("Processed %d aliases\n", count); exit(0); } } int get_alias(file, buffer) FILE *file; char *buffer; { /* load buffer with the next complete alias from the file. (this can include reading in multiple lines and appending them all together!) Returns EOF after last entry in file. Lines that start with '#' are assumed to be comments and are ignored. White space as the first field of a line is taken to indicate that this line is a continuation of the previous. */ static char mybuffer[SLEN]; int done = 0, first_read = 1; /** get the first line of the entry... **/ buffer[0] = '\0'; /* zero out line */ do { if (get_line(file, mybuffer, first_read) == -1) return(-1); first_read = 0; if (mybuffer[0] != '#') strcpy(buffer, mybuffer); } while (strlen(buffer) == 0); /** now read in the rest (if there is any!) **/ do { if (get_line(file, mybuffer, first_read) == -1) { buff_loaded = 0; /* force a read next pass! */ return(0); /* okay. let's just hand 'buffer' back! */ } done = (mybuffer[0] != ' ' && mybuffer[0] != TAB); if (mybuffer[0] != '#' && ! done) strcat(buffer, mybuffer); done = (done && mybuffer[0] != '#'); } while (! done); return(0); /* no sweat! */ } put_alias(data, buffer, table, size) FILE *data; char *buffer; struct alias_rec table[]; int size; { /** break buffer down into two pieces: aliases, and address, throwing away the username (comment) field. Make the appropriate entries in the table (size) **/ char aliases[LONG_STRING], address[LONG_STRING]; int i = 0, j = 0; remove_all(' ', TAB, buffer); for (i=0; buffer[i] != ':' && i < LONG_STRING; i++) aliases[i] = buffer[i]; aliases[i] = '\0'; for (i=strlen(buffer)-1; buffer[i] != ':' && i > 0; i--) address[j++] = buffer[i]; address[j] = '\0'; reverse(address); add_to_table(data, aliases, address, table, size); } int get_line(file, buffer, first_line) FILE *file; char *buffer; int first_line; { /** read line from file. If first_line and buff_loaded, then just return! **/ int stat; if (first_line && buff_loaded) { buff_loaded = 1; return; } buff_loaded = 1; /* we're going to get SOMETHING in the buffer */ stat = fgets(buffer, SLEN, file) == NULL ? -1 : 0; if (stat != -1) no_ret(buffer); return(stat); } reverse(string) char *string; { /** reverse the order of the characters in string... uses a bubble-sort type of algorithm! **/ register int f, l; char c; f = 0; l = strlen(string) - 1; while (f < l) { c = string[f]; string[f] = string[l]; string[l] = c; f++; l--; } } add_to_table(data, aliases, address, table, size) FILE *data; char *aliases, *address; struct alias_rec table[]; int size; { /** add address to datafile, incrementing offset count (bytes), then for each alias in the aliases string, add to the hash table, with the associated pointer value! **/ static char buf[SLEN], *word; long additive = 1L; word = buf; /* use the allocated space! */ if (group(address)) { check_group(address, aliases); if (error) return; /* don't do work if we aren't to save it! */ fprintf(data, "!%s\n", address); additive = 2L; } else { if (error) return; /* don't do work if we aren't to save it! */ fprintf(data, "%s\n", address); } while ((word = (char *) strtok(aliases,", ")) != NULL) { add_to_hash_table(word, offset, table, size); aliases = NULL; /* let's get ALL entries via 'strtok' */ count++; } if ( system ? count > MAX_SALIASES-35 : count > MAX_UALIASES-21) { printf("** Too many aliases in file! **\n"); error++; } offset = (offset + (long) strlen(address) + additive); } remove_all(c1, c2, string) char c1, c2, *string; { /* remove all occurances of character 'c' from string. */ char buffer[LONG_STRING]; register int i = 0, j = 0; for (i = 0; string[i] != '\0' && i < LONG_STRING; i++) if (string[i] != c1 && string[i] != c2) buffer[j++] = string[i]; buffer[j] = '\0'; strcpy(string, buffer); } add_to_hash_table(word, offset, table, size) char *word; long offset; struct alias_rec table[]; int size; { /** add word and offset to current hash table. **/ register int loc; if (strlen(word) > 20) exit(printf("Bad alias name: %s. Too long.\n", word)); loc = hash_it(word, size); while (table[loc].name[0] != '\0' && strcmp(table[loc].name, word) != 0) loc = loc + 1 % size; if (table[loc].name[0] == '\0') { strcpy(table[loc].name, word); table[loc].byte = offset; } else printf("** Duplicate alias '%s' in file. Multiples ignored.\n", word); } int hash_it(string, table_size) char *string; { /** compute the hash function of the string, returning it (mod table_size) **/ register int i, sum = 0; for (i=0; string[i] != '\0'; i++) sum += (int) string[i]; return(sum % table_size); } init_table(table, size) struct alias_rec table[]; int size; { /** initialize hash table! **/ register int i; for (i=0; i < size; i++) table[i].name[0] = '\0'; } read_in_system(table, size) struct alias_rec table[]; int size; { /** read in the system hash table...to check for group aliases from the user alias file (to ensure that there are no names in the user group files that are not purely contained within either alias table) **/ int fd; char fname[SLEN]; sprintf(fname, "%s/%s", mailhome, alias_hash); if ((fd = open(fname, O_RDONLY)) == -1) return; /* no sweat: flag 'hash_table_loaded' not set! */ (void) read(fd, table, size); close(fd); hash_table_loaded++; } check_group(names, groupname) char *names, *groupname; { /** one by one make sure each name in the group is defined in either the system alias file or the user alias file. This search is linearly dependent, so all group aliases in the source file should appear LAST, after all the user aliases! **/ char *word, *bufptr, buffer[LONG_STRING]; strcpy(buffer, names); bufptr = (char *) buffer; while ((word = (char *) strtok(bufptr,", ")) != NULL) { if (! can_find(word)) if (! valid_name(word)) { error++; printf("** Alias %s in group %s is bad!\n", word, groupname); } bufptr = NULL; } } int can_find(name) char *name; { /** find name in either hash table...use 'system' variable to determine if we should look in both or just system.... **/ register int loc; if (strlen(name) > 20) { error++; printf("** Bad alias name: %s. Too long.\n", name); return(1); /* fake out: don't want 2 error messages! */ } /** system alias table... **/ if (hash_table_loaded || system) { loc = hash_it(name, MAX_SALIASES); while (strcmp(name, shash_table[loc].name) != 0 && shash_table[loc].name[0] != '\0') loc = (loc + 1) % MAX_SALIASES; if (strcmp(name, shash_table[loc].name) == 0) return(1); /* found it! */ } if (! system) { /* okay! Let's check the user alias file! */ loc = hash_it(name, MAX_UALIASES); while (strcmp(name, uhash_table[loc].name) != 0 && uhash_table[loc].name[0] != '\0') loc = (loc + 1) % MAX_UALIASES; if (strcmp(name, uhash_table[loc].name) == 0) return(1); /* found it! */ } return(0); } END-OF-FILE if [ "$filename" != "/dev/null" ] then size=`wc -c < $filename` if [ $size != 11051 ] then echo $filename changed - should be 11051 bytes, not $size bytes fi chmod 666 $filename fi # ---------- file utils/printmail.c ---------- filename="utils/printmail.c" if [ -f $filename ] then echo File \"$filename\" already exists\! Skipping... filename=/dev/null # throw it away else echo extracting file utils/printmail.c... fi cat << 'END-OF-FILE' > $filename /** printmail.c **/ /** print mail, adding a formfeed between each message **/ /** Modified to use stdin if being fed from a pipe. **/ /** (C) Copyright 1985, Dave Taylor **/ #include <stdio.h> #include "defs.h" static char ident[] = { WHAT_STRING }; #define dashes \ "\n\n------------------------------------------------------------------------------\n\n" #define FF "\014" /* form feed! */ FILE *mailfile; char separator[80]; main(argc, argv) int argc; char *argv[]; { char infile[80], username[40], c; strcpy(separator, FF); *argv++; /* get past argv[0] */ if (argc > 1) if (strcmp(*argv, "-d") == 0) { strcpy(separator, dashes); --argc; *argv++; } if (argc > 1 && *argv[0] == '-') exit(fprintf(stderr, "Usage: printmail {-d} {filename (s)}\n")); if (argc == 1) { strcpy(username, getlogin()); if (strlen(username) == 0) cuserid(username); if (isatty(fileno(stdin))) { /* normal invokation... */ sprintf(infile,"%s/%s",mailhome, username); if ((mailfile = fopen(infile,"r")) == NULL) { fprintf(stderr, "No mail!\n"); exit(0); } } else mailfile = stdin; /* read from stdin! */ if (read_headers() == 0) fprintf(stderr, "No messages in mailbox!\n"); } if (argc > 1) /* more than one file - delimit each */ if (strcmp(separator, FF) != 0) printf("\t\t\t%s\n%s", *argv, separator); else printf("\t\t\t%s\n\n", *argv); /* Don't put a formfeed! */ while (--argc) { if ((mailfile = fopen(*argv,"r")) == NULL) { fprintf(stderr, "Could not open file '%s'!", *argv); break; } else if (read_headers() == 0) fprintf(stderr, "No messages in mailbox '%s'!\n", *argv); *argv++; if (argc) { if (strcmp(separator, FF) != 0) printf("%s\t\t\t%s%s", separator, *argv, separator); else printf("%s\t\t\t%s\n\n", separator, *argv); } } } int read_headers() { char buffer[100]; register int count = 0; while (fgets(buffer, 100, mailfile) != NULL) if (first_word(buffer,"From ")) { if (real_from(buffer)) { printf("%s%s", count ? separator : "", buffer); count++; } } else printf("%s", buffer); return(count); } int real_from(buffer) char *buffer; { /***** returns true iff 's' has the seven 'from' fields *****/ char junk[80]; junk[0] = '\0'; sscanf(buffer, "%*s %*s %*s %*s %*s %*s %s", junk); return(junk[0] != '\0'); } END-OF-FILE if [ "$filename" != "/dev/null" ] then size=`wc -c < $filename` if [ $size != 2472 ] then echo $filename changed - should be 2472 bytes, not $size bytes fi chmod 666 $filename fi echo end of this archive file.... exit 0