rsalz@uunet.uu.net (Rich Salz) (04/14/89)
Submitted-by: dsinc!syd@uunet.UU.NET (Syd Weinstein) Posting-number: Volume 18, Issue 103 Archive-name: elm2.2/part24 #!/bin/sh # this is part 24 of a multipart archive # do not concatenate these parts, unpack them in order with /bin/sh # file utils/newalias.c continued # CurArch=24 if test ! -r s2_seq_.tmp then echo "Please unpack part 1 first!" exit 1; fi ( read Scheck if test "$Scheck" != $CurArch then echo "Please unpack part $Scheck next!" exit 1; else exit 0; fi ) < s2_seq_.tmp || exit 1 echo "x - Continuing file utils/newalias.c" sed 's/^X//' << 'SHAR_EOF' >> utils/newalias.c X exit(1); X } X X loc = hash_it(word, size); X X while (table[loc].name[0] != '\0' && strcmp(table[loc].name, word) != 0) X loc = (loc + 1) % size; X X if (table[loc].name[0] == '\0') { X strcpy(table[loc].name, word); X table[loc].byte = offset; X } X else X printf("** Duplicate alias '%s' in file. Multiples ignored.\n", X word); X} X Xint Xhash_it(string, table_size) Xchar *string; X{ X /** compute the hash function of the string, returning X it (mod table_size) **/ X X register int i, sum = 0; X X for (i=0; string[i] != '\0'; i++) X sum += (int) string[i]; X X return(sum % table_size); X} X Xinit_table(table, size) Xstruct alias_rec table[]; Xint size; X{ X /** initialize hash table! **/ X X register int i; X X for (i=0; i < size; i++) X table[i].name[0] = '\0'; X} X Xread_in_system(table, size) Xstruct alias_rec table[]; Xint size; X{ X /** read in the system hash table...to check for group aliases X from the user alias file (to ensure that there are no names X in the user group files that are not purely contained within X either alias table) **/ X X int fd; X char fname[SLEN]; X X sprintf(fname, "%s/%s", mailhome, ALIAS_HASH); X X if ((fd = open(fname, O_RDONLY)) == -1) X return; /* no sweat: flag 'hash_table_loaded' not set! */ X X (void) read(fd, table, size); X close(fd); X hash_table_loaded++; X} X Xcheck_group(names, groupname) Xchar *names, *groupname; X{ X /** one by one make sure each name in the group is defined X in either the system alias file or the user alias file. X This search is linearly dependent, so all group aliases X in the source file should appear LAST, after all the user X aliases! **/ X X char *word, *bufptr, buffer[LONG_STRING]; X X strcpy(buffer, names); X bufptr = (char *) buffer; X X while ((word = (char *) strtok(bufptr,", ")) != NULL) { X if (! can_find(word)) X if (! valid_name(word)) { X error++; X printf("** Alias %s in group %s is bad!\n", word, groupname); X } X bufptr = NULL; X } X} X Xint Xcan_find(name) Xchar *name; X{ X /** find name in either hash table...use 'is_system' variable to X determine if we should look in both or just system.... **/ X X register int loc; X X if (strlen(name) > 20) { X error++; X printf("** Bad alias name: %s. Too long.\n", name); X return(1); /* fake out: don't want 2 error messages! */ X } X X /** system alias table... **/ X if (hash_table_loaded || is_system) { X loc = hash_it(name, MAX_SALIASES); X X while (strcmp(name, shash_table[loc].name) != 0 && X shash_table[loc].name[0] != '\0') X loc = (loc + 1) % MAX_SALIASES; X X if (strcmp(name, shash_table[loc].name) == 0) X return(1); /* found it! */ X } X X if (! is_system) { /* okay! Let's check the user alias file! */ X loc = hash_it(name, MAX_UALIASES); X X while (strcmp(name, uhash_table[loc].name) != 0 && X uhash_table[loc].name[0] != '\0') X loc = (loc + 1) % MAX_UALIASES; X X if (strcmp(name, uhash_table[loc].name) == 0) X return(1); /* found it! */ X } X X return(0); X} X Xextract_comment(comment, buffer, first, last) Xchar *comment, *buffer; Xint first, last; X{ X /** Buffer contains a comment, located between the first and last X values. Copy that into 'comment', but remove leading and X trailing white space. Note also that it doesn't copy past X a comma, so `unpublishable' comments can be of the form; X dave: Dave Taylor, HP Labs : taylor@hplabs X and the output will be "taylor@hplabs (Dave Taylor)". X **/ X X register int loc = 0; X X /** first off, skip the LEADING white space... **/ X X while (whitespace(buffer[first])) first++; X X /** now let's backup the 'last' value until we hit a non-whitespace **/ X X last -= 2; /* starts at ch AFTER equals.. */ X while (whitespace(buffer[last])) last--; X X /** now a final check to make sure we're still talking about a X reasonable string (rather than a "joe :: joe@dec" type string) **/ X X if (first < last) { X /* one more check - let's find the comma, if present... */ X for (loc=first; loc < last; loc++) X if (buffer[loc] == ',') { X last = loc-1; X break; X } X loc = 0; X while (first <= last) X comment[loc++] = buffer[first++]; X comment[loc] = '\0'; X } X} X Xupdate_alias_file_locations() X{ X /** a short-term routine to ensure that the data files are X moved into the correct directory... **/ X X char source[SLEN], dest[SLEN]; X X /** first let's create the directory if it ain't there... **/ X X sprintf(source, "%s/.elm", home); X X /** Some systems don't have a mkdir call - how inconvienient! **/ X#ifdef MKDIR X (void) mkdir(source, 0700); X#else X system("mkdir $HOME/.elm"); X system("chmod 700 $HOME/.elm"); X#endif /* MKDIR */ X X /** now *link* the files... **/ X X sprintf(source, "%s/.alias_text", home); X sprintf(dest, "%s/%s", home, ALIAS_TEXT); X link(source, dest); X X sprintf(source, "%s/.alias_hash", home); X sprintf(dest, "%s/%s", home, ALIAS_HASH); X link(source, dest); X X sprintf(source, "%s/.alias_data", home); X sprintf(dest, "%s/%s", home, ALIAS_DATA); X link(source, dest); X X printf("\n*** Moved all data files into %s/.elm directory ***\n\n", X home); X} SHAR_EOF echo "File utils/newalias.c is complete" chmod 0444 utils/newalias.c || echo "restore of utils/newalias.c fails" echo "x - extracting utils/newmail.c (Text)" sed 's/^X//' << 'SHAR_EOF' > utils/newmail.c && X Xstatic char rcsid[] = "@(#)$Id: newmail.c,v 2.16 89/03/25 21:47:55 syd Exp $"; X X/******************************************************************************* X * The Elm Mail System - $Revision: 2.16 $ $State: Exp $ X * X * Copyright (c) 1986, 1987 Dave Taylor X * Copyright (c) 1988, 1989 USENET Community Trust X ******************************************************************************* X * Bug reports, patches, comments, suggestions should be sent to: X * X * Syd Weinstein, Elm Coordinator X * elm@dsinc.UUCP dsinc!elm X * X ******************************************************************************* X * $Log: newmail.c,v $ X * Revision 2.16 89/03/25 21:47:55 syd X * Initial 2.2 Release checkin X * X * X ******************************************************************************/ X X/** This is actually two programs folded into one - 'newmail()' and X 'wnewmail()'. They perform essentially the same function, to X monitor the mail arriving in a set of/a mailbox or folder, but X newmail is designed to run in background on a terminal, and X wnewmail is designed to have a window of its own to run in. X X The main difference is that wnewmail checks for mail more often. X X The usage parameters are: X X -i <interval> how often to check for mail X (default: 60 secs if newmail, X 10 secs if wnewmail) X X <filename> name of a folder to monitor X (can prefix with '+'/'=', or can X default to the incoming mailbox) X X <filename>=prefix file to monitor, output with specified X prefix when mail arrives. X X If we're monitoring more than one mailbox the program will prefix X each line output (if 'newmail') or each cluster of mail (if 'wnewmail') X with the basename of the folder the mail has arrived in. In the X interest of exhaustive functionality, you can also use the "=prefix" X suffix (eh?) to specify your own strings to prefix messages with. X X The output format is either: X X newmail: X >> New mail from <user> - <subject> X >> Priority mail from <user> - <subject> X X >> <folder>: from <user> - <subject> X >> <folder>: Priority from <user> - <subject> X X wnewmail: X <user> - <subject> X Priority: <user> - <subject> X X <folder>: <user> - <subject> X <folder>: Priority: <user> - <subject>\fR X X**/ X X#include <stdio.h> X#include <errno.h> X#include <sys/types.h> X#include <sys/stat.h> X X#include "defs.h" X X#include <signal.h> /* background jobs ignore some signals... */ X Xstatic char ident[] = { WHAT_STRING }; X X#define LINEFEED (char) 10 X#define BEGINNING 0 /* seek fseek(3S) */ X#define DEFAULT_INTERVAL 60 X X#define MAX_FOLDERS 25 /* max we can keep track of */ X X#define NO_SUBJECT "(No Subject Specified)" X X#define metachar(c) (c == '+' || c == '=' || c == '%') X Xchar *getusername(); Xlong bytes(); X Xstruct folder_struct { X char foldername[SLEN]; X char prefix[NLEN]; X FILE *fd; X long filesize; X } folders[MAX_FOLDERS]; X Xint interval_time, /* how long to sleep between checks */ X debug = 0, /* include verbose debug output? */ X in_window = 0, /* are we running as 'wnewmail'? */ X total_folders = 0, /* # of folders we're monitoring */ X current_folder = 0; /* struct pointer for looping */ X Xchar hostname[SLEN], /* name of machine we're on */ X hostdomain[SLEN]; /* name of domain we're in */ X X#ifdef BSD Xextern int errno; X#endif X Xmain(argc, argv) Xint argc; Xchar *argv[]; X{ X extern char *optarg; X extern int optind, opterr; X char *ptr; X int c, i, done; X long lastsize, X newsize; /* file size for comparison.. */ X X#ifdef HOSTCOMPILED X strncpy(hostname, HOSTNAME, sizeof(hostname)); X#else X gethostname(hostname, sizeof(hostname)); X#endif X gethostdomain(hostdomain, sizeof(hostdomain)); X X interval_time = DEFAULT_INTERVAL; X opterr = 0; X X /** let's see if the first character of the basename of the X command invoked is a 'w' (e.g. have we been called as X 'wnewmail' rather than just 'newmail'?) X **/ X X for (i=0, ptr=(argv[0] + strlen(argv[0])-1); !i && ptr > argv[0]; ptr--) X if (*ptr == '/') { X in_window = (*(ptr+1) == 'w'); X i++; X } X X if (ptr == argv[0] && i == 0 && argv[0][0] == 'w') X in_window = 1; X X while ((c = getopt(argc, argv, "di:w")) != EOF) { X switch (c) { X case 'd' : debug++; break; X case 'i' : interval_time = atoi(optarg); break; X case 'w' : in_window = 1; break; X default : usage(); exit(1); X } X } X X if (interval_time < 10) X fprintf(stderr, X"Warning: interval set to %d second%s. I hope you know what you're doing!\n", X interval_time, interval_time == 1 ? "" : "s"); X X /* now let's parse the foldernames, if any are given */ X X if (optind >= argc) /* get default */ X add_default_folder(); X else { X while (optind < argc) X add_folder(argv[optind++]); X pad_prefixes(); /* for nice output...*/ X } X X#ifdef AUTO_BACKGROUND X if (! in_window) { X if (fork()) /* automatically puts this task in background! */ X exit(0); X X (void) signal(SIGINT, SIG_IGN); X (void) signal(SIGQUIT, SIG_IGN); X } X#endif X (void) signal(SIGHUP, SIG_DFL); X X if (in_window && ! debug) X printf("Incoming mail:\n"); X X while (1) { X X#ifndef AUTO_BACKGROUND /* won't work if we're nested this deep! */ X if (getppid() == 1) /* we've lost our shell! */ X exit(); X#endif X if (! isatty(1)) /* we're not sending output to a tty any more */ X exit(); X X if (debug) printf("\n----\n"); X X for (i = 0; i < total_folders; i++) { X X if (debug) X printf("[checking folder #%d: %s]\n", i, folders[i].foldername); X X if (folders[i].fd == (FILE *) NULL) { X X if ((folders[i].fd = fopen(folders[i].foldername,"r")) == NULL) X if (errno == EACCES) { X fprintf(stderr, "\nPermission to monitor %s denied!\n\n", X folders[i].foldername); X sleep(5); X exit(1); X } X } X X if ((newsize = bytes(folders[i].foldername)) > X folders[i].filesize) { /* new mail has arrived! */ X X if (debug) X printf( X "\tnew mail has arrived! old size = %ld, new size=%ld\n", X folders[i].filesize, newsize); X X /* skip what we've read already... */ X X if (fseek(folders[i].fd, folders[i].filesize, X BEGINNING) != 0) X perror("fseek()"); X X folders[i].filesize = newsize; X X if (in_window) X putchar((char) 007); /* BEEP!*/ X else X printf("\n\r"); /* blank lines surrounding message */ X X read_headers(i); /* read and display new mail! */ X X if (! in_window) X printf("\n\r"); X } X else if (newsize != folders[i].filesize) { /* file SHRUNK! */ X X folders[i].filesize = bytes(folders[i].foldername); X (void) fclose(folders[i].fd); /* close it and ... */ X folders[i].fd = (FILE *) NULL; /* let's reopen the file */ X X lastsize = folders[i].filesize; X done = 0; X X while (! done) { X sleep(0); /* basically gives up our CPU slice */ X newsize = bytes(folders[i].foldername); X if (newsize != lastsize) X lastsize = newsize; X else X done++; X } X X folders[i].filesize = newsize; X } X } X X sleep(interval_time); X } X} X Xint Xread_headers(current_folder) Xint current_folder; X{ X /** read the headers, output as found given current_folder, X the prefix of that folder, and whether we're in a window X or not. X **/ X X char buffer[SLEN], from_whom[SLEN], subject[SLEN]; X register int subj = 0, in_header = 1, count = 0, priority=0; X X while (fgets(buffer, SLEN, folders[current_folder].fd) != NULL) { X if (first_word(buffer,"From ")) { X if (real_from(buffer, from_whom)) { X subj = 0; X priority = 0; X in_header = 1; X subject[0] ='\0'; X from_whom[0] ='\0'; X } X } X else if (in_header) { X if (first_word(buffer,">From")) X forwarded(buffer, from_whom); /* return address */ X else if (first_word(buffer,"Subject:") || X first_word(buffer,"Re:")) { X if (! subj++) { X remove_first_word(buffer); X strcpy(subject, buffer); X } X } X else if (first_word(buffer,"Priority:")) X priority++; X else if (first_word(buffer,"From:")) X parse_arpa_from(buffer, from_whom); X else if (buffer[0] == LINEFEED) { X in_header = 0; /* in body of message! */ X show_header(priority, from_whom, subject, current_folder); X count++; X } X } X } X return(count); X} X Xadd_folder(name) Xchar *name; X{ X /* add the specified folder to the list of folders...ignore any X problems we may having finding it (user could be monitoring X a mailbox that doesn't currently exist, for example) X */ X X char *cp, buf[SLEN]; X X if (current_folder > MAX_FOLDERS) { X fprintf(stderr, X "Sorry, but I can only keep track of %d folders.\n", MAX_FOLDERS); X exit(1); X } X X /* now let's rip off the suffix "=<string>" if it's there... */ X X for (cp = name + strlen(name); cp > name+1 && *cp != '=' ; cp--) X /* just keep stepping backwards */ ; X X /* if *cp isn't pointing to the first character we'e got something! */ X X if (cp > name+1) { X X *cp++ = '\0'; /* null terminate the filename & get prefix */ X X if (metachar(*cp)) cp++; X X strcpy(folders[current_folder].prefix, cp); X } X else { /* nope, let's get the basename of the file */ X for (cp = name + strlen(name); cp > name && *cp != '/'; cp--) X /* backing up a bit... */ ; X X if (metachar(*cp)) cp++; X if (*cp == '/') cp++; X X strcpy(folders[current_folder].prefix, cp); X } X X /* and next let's see what kind of weird prefix chars this user X might be testing us with. We can have '+'|'='|'%' to expand X or a file located in the incoming mail dir... X */ X X if (metachar(name[0])) X expand_filename(name, folders[current_folder].foldername); X else if (access(name, 00) == -1) { X /* let's try it in the mail home directory */ X sprintf(buf, "%s%s", mailhome, name); X if (access(buf, 00) != -1) /* aha! */ X strcpy(folders[current_folder].foldername, buf); X else X strcpy(folders[current_folder].foldername, name); X } X else X strcpy(folders[current_folder].foldername, name); X X /* now let's try to actually open the file descriptor and grab X a size... */ X X if ((folders[current_folder].fd = X fopen(folders[current_folder].foldername, "r")) == NULL) X if (errno == EACCES) { X fprintf(stderr, "\nPermission to monitor \"%s\" denied!\n\n", X folders[current_folder].foldername); X exit(1); X } X X folders[current_folder].filesize = X bytes(folders[current_folder].foldername); X X /* and finally let's output what we did */ X X if (debug) X printf("folder %d: \"%s\" <%s> %s, size = %ld\n", X current_folder, X folders[current_folder].foldername, X folders[current_folder].prefix, X folders[current_folder].fd == NULL? "not found" : "opened", X folders[current_folder].filesize); X X /* and increment current-folder please! */ X X current_folder++; X total_folders++; X} X Xadd_default_folder() X{ X char *cp; X X /* this routine will add the users home mailbox as the folder X * to monitor. Since there'll only be one folder we'll never X * prefix it either... X * determine mail file from environment variable if found, X * else use password entry X */ X if ((cp = getenv("MAIL")) == NULL) X sprintf(folders[0].foldername, "%s%s", mailhome, getusername()); X else X strcpy(folders[0].foldername, cp); X X folders[0].fd = fopen(folders[0].foldername, "r"); X folders[0].filesize = bytes(folders[0].foldername); X X if (debug) X printf("default folder: \"%s\" <%s> %s, size = %ld\n", X folders[0].foldername, X folders[0].prefix, X folders[0].fd == NULL? "not found" : "opened", X folders[0].filesize); X X total_folders = 1; X} X Xint Xreal_from(buffer, who) Xchar *buffer, *who; X{ X /***** returns true iff 's' has the seven 'from' fields, X initializing the who to the sender *****/ X X char junk[SLEN]; X X junk[0] = '\0'; X sscanf(buffer, "%*s %s %*s %*s %*s %*s %s", X who, junk); X return(junk[0] != '\0'); X} X Xforwarded(buffer, who) Xchar *buffer, *who; X{ X /** change 'from' and date fields to reflect the ORIGINATOR of X the message by iteratively parsing the >From fields... **/ X X char machine[SLEN], buff[SLEN]; X X machine[0] = '\0'; X sscanf(buffer, "%*s %s %*s %*s %*s %*s %*s %*s %*s %*s %s", X who, machine); X X if(machine[0] == '\0') /* try for address with timezone in date */ X sscanf(buffer, "%*s %s %*s %*s %*s %*s %*s %*s %*s %s", X who, machine); X X if (machine[0] == '\0') /* try for srm address */ X sscanf(buffer, "%*s %s %*s %*s %*s %*s %*s %*s %s", X who, machine); X X if (machine[0] == '\0') X sprintf(buff,"anonymous"); X else X sprintf(buff,"%s!%s", machine, who); X X strncpy(who, buff, SLEN); X} X X Xremove_first_word(string) Xchar *string; X{ /** removes first word of string, ie up to first non-white space X following a white space! **/ X X register int loc; X X for (loc = 0; string[loc] != ' ' && string[loc] != '\0'; loc++) X ; X X while (string[loc] == ' ' || string[loc] == '\t') X loc++; X X move_left(string, loc); X} X Xmove_left(string, chars) Xchar string[]; Xint chars; X{ X /** moves string chars characters to the left DESTRUCTIVELY **/ X X register int i; X X chars--; /* index starting at zero! */ X X for (i=chars; string[i] != '\0' && string[i] != '\n'; i++) X string[i-chars] = string[i]; X X string[i-chars] = '\0'; X} X Xshow_header(priority, from, subject, current_folder) Xint priority; Xchar *from, *subject; Xint current_folder; X{ X /** output header in clean format, including abbreviation X of return address if more than one machine name is X contained within it! **/ X char buffer[SLEN]; X int loc, i=0, exc=0; X X#ifndef INTERNET X /* Remove bogus "@host.domain" string. */ X X sprintf(buffer, "@%s%s", hostname, hostdomain); X X if (chloc(from, '!') != -1 && in_string(from, buffer)) X from[strlen(from) - strlen(buffer)] = '\0'; X#endif X X loc = strlen(from); X X while (exc < 2 && loc > 0) X if (from[--loc] == '!') X exc++; X X if (exc == 2) { /* lots of machine names! Get last one */ X loc++; X while (loc < strlen(from) && loc < SLEN) X buffer[i++] = from[loc++]; X buffer[i] = '\0'; X strcpy(from, buffer); X } X X if (strlen(subject) < 2) X strcpy(subject, NO_SUBJECT); X X if (in_window) X if (total_folders > 1) X printf("%s: %s%s -- %s\n", X folders[current_folder].prefix, X priority? "Priority " : "", from, subject); X else X printf("%s%s -- %s\n", X priority? "Priority " : "", from, subject); X else X if (total_folders > 1) X printf(">> %s: %sail from %s - %s\n\r", X folders[current_folder].prefix, X priority? "Priority m" : "M", from, subject); X else X printf(">> %sail from %s - %s\n\r", X priority? "Priority m" : "M", from, subject); X} X Xparse_arpa_from(buffer, newfrom) Xchar *buffer, *newfrom; X{ X /** try to parse the 'From:' line given... It can be in one of X two formats: X From: Dave Taylor <hpcnou!dat> X or From: hpcnou!dat (Dave Taylor) X Change 'newfrom' ONLY if sucessfully parsed this entry and X the resulting name is non-null! X **/ X X char temp_buffer[SLEN], *temp; X register int i, j = 0, in_parens; X X temp = (char *) temp_buffer; X temp[0] = '\0'; X X no_ret(buffer); /* blow away '\n' char! */ X X if (lastch(buffer) == '>') { X for (i=strlen("From: "); buffer[i] != '\0' && buffer[i] != '<' && X buffer[i] != '('; i++) X temp[j++] = buffer[i]; X temp[j] = '\0'; X } X else if (lastch(buffer) == ')') { X in_parens = 1; X for (i=strlen(buffer)-2; buffer[i] != '\0' && buffer[i] != '<'; i--) { X switch(buffer[i]) { X case ')': in_parens++; X break; X case '(': in_parens--; X break; X } X if(!in_parens) break; X temp[j++] = buffer[i]; X } X temp[j] = '\0'; X reverse(temp); X } X X if (strlen(temp) > 0) { /* mess with buffer... */ X X /* remove leading spaces... */ X X while (whitespace(temp[0])) X temp = (char *) (temp + 1); /* increment address! */ X X /* remove trailing spaces... */ X X i = strlen(temp) - 1; X X while (whitespace(temp[i])) X temp[i--] = '\0'; X X /* if anything is left, let's change 'from' value! */ X X if (strlen(temp) > 0) X strcpy(newfrom, temp); X } X} X Xreverse(string) Xchar *string; X{ X /** reverse string... pretty trivial routine, actually! **/ X X char buffer[SLEN]; X register int i, j = 0; X X for (i = strlen(string)-1; i >= 0; i--) X buffer[j++] = string[i]; X X buffer[j] = '\0'; X X strcpy(string, buffer); X} X Xlong Xbytes(name) Xchar *name; X{ X /** return the number of bytes in the specified file. This X is to check to see if new mail has arrived.... **/ X X int ok = 1; X extern int errno; /* system error number! */ X struct stat buffer; X X if (stat(name, &buffer) != 0) X if (errno != 2) { X fprintf(stderr,"Error %d attempting fstat on %s", errno, name); X exit(1); X } X else X ok = 0; X X return(ok ? buffer.st_size : 0); X} X Xchar *getusername() X{ X /** Getting the username on some systems is a real pain, so... X This routine is guaranteed to return a usable username **/ X X char *return_value, *getlogin(), *cuserid(); X X if ((return_value = getlogin()) == NULL) X if ((return_value = cuserid(NULL)) == NULL) { X printf("Newmail: I can't get username!\n"); X exit(1); X } X X return( (char *) return_value); X} X Xusage() X{ X /* print a nice friendly usage message */ X X fprintf(stderr, X"\nUsage: %s [-d] [-i interval] [-w] {folders}\n"); X fprintf(stderr, "\nWhere:\n"); X fprintf(stderr, " -d\tturns on debugging output\n"); X fprintf(stderr, X" -i D\tsets the interval checking time to 'D' seconds\n"); X fprintf(stderr, X" -w\tforces 'window'-style output, and bypasses auto-background\n\n"); X fprintf(stderr, X"folders can be specified by relative or absolute path names, can be the name\n"); X fprintf(stderr, X"of a mailbox in the incoming mail directory to check, or can have one of the\n"); X fprintf(stderr, X"standard Elm mail directory prefix chars (e.g. '+', '=' or '%').\n"); X fprintf(stderr, X"Furthermore, any folder can have '=string' as a suffix to indicate a folder\n"); X fprintf(stderr, X"identifier other than the basename of the file\n\n"); X} X X Xexpand_filename(name, store_space) Xchar *name, *store_space; X{ X strcpy(store_space, name); X if (expand(store_space) == 0) { X fprintf(stderr,"Sorry, but I couldn't expand \"%s\"\n",name); X exit(1); X } X} X Xpad_prefixes() X{ X /** This simple routine is to ensure that we have a nice X output format. What it does is whip through the different X prefix strings we've been given, figures out the maximum X length, then space pads the other prefixes to match. X **/ X X register int i, j, len = 0; X X for (i=0; i < total_folders; i++) X if (len < (j=strlen(folders[i].prefix))) X len = j; X X for (i=0; i < total_folders; i++) X for (j = strlen(folders[i].prefix); j < len; j++) X strcat(folders[i].prefix, " "); X} SHAR_EOF chmod 0444 utils/newmail.c || echo "restore of utils/newmail.c fails" echo "x - extracting utils/printmail (Text)" sed 's/^X//' << 'SHAR_EOF' > utils/printmail && X: Use /bin/sh X# printmail: part of the Elm mail system X# @(#)$Id: printmail,v 2.1 89/03/03 17:46:47 syd Exp $ X Xif [ "$1" = "-p" ]; then X flags="-p";shift Xfi X Xif [ "$1" != "" ]; then X if [ ! -r $1 ]; then X echo printmail: cannot open folder $1 1>&2 X exit 1 X else X flags="$flags -f $1" X fi Xfi X X# and now invoke readmsg Xexec readmsg $flags \* SHAR_EOF chmod 0444 utils/printmail || echo "restore of utils/printmail fails" echo "x - extracting utils/readmsg.c (Text)" sed 's/^X//' << 'SHAR_EOF' > utils/readmsg.c && X Xstatic char rcsid[] = "@(#)$Id: readmsg.c,v 2.7 89/03/25 21:47:57 syd Exp $"; X X/******************************************************************************* X * The Elm Mail System - $Revision: 2.7 $ $State: Exp $ X * X * Copyright (c) 1986, 1987 Dave Taylor X * Copyright (c) 1988, 1989 USENET Community Trust X ******************************************************************************* X * Bug reports, patches, comments, suggestions should be sent to: X * X * Syd Weinstein, Elm Coordinator X * elm@dsinc.UUCP dsinc!elm X * X ******************************************************************************* X * $Log: readmsg.c,v $ X * Revision 2.7 89/03/25 21:47:57 syd X * Initial 2.2 Release checkin X * X * X ******************************************************************************/ X X/** This routine adds the functionality of the "~r" command to the Elm mail X system while still allowing the user to use the editor of their choice. X X The program, without any arguments, tries to read a file in the users home X directory called ".readmsg" (actually defined in the sysdefs.h system X defines file) and if it finds it reads the current message. If it doesn't X find it, it will return a usage error. X X The program can also be called with an explicit message number, list of X message numbers, or a string to match in the message (including the header). X NOTE that when you use the string matching option it will match the first X message containing that EXACT (case sensitive) string and then exit. X**/ X X#include <stdio.h> X#include <ctype.h> X X#include "defs.h" X X/** three defines for what level of headers to display **/ X X#define ALL 1 X#define WEED 2 X#define NONE 3 X X#define metachar(c) (c == '=' || c == '+' || c == '%') X Xstatic char ident[] = { WHAT_STRING }; X X#define MAX_LIST 25 /* largest single list of arguments */ X X#define LAST_MESSAGE 9999 /* last message in list ('$' char) */ X#define LAST_CHAR '$' /* char to delimit last message.. */ X#define STAR '*' /* char to delimit all messages... */ X Xint read_message[MAX_LIST]; /* list of messages to read */ Xint messages = 0; /* index into list of messages */ X Xint numcmp(); /* strcmp, but for numbers */ Xchar *words(), /* function defined below... */ X *expand_define(); /* ditto... */ X X Xextern char *optarg; /* for parsing the ... */ Xextern int optind; /* .. starting arguments */ X Xchar *getenv(); /* keep lint happy */ X Xmain(argc, argv) Xint argc; Xchar *argv[]; X{ X FILE *file; /* generic file descriptor! */ X char filename[SLEN], /* filename buffer */ X infile[SLEN], /* input filename */ X buffer[SLEN], /* file reading buffer */ X string[SLEN], /* string match buffer */ X *cp; X X int current_in_queue = 0, /* these are used for... */ X current = 0, /* ...going through msgs */ X list_all_messages = 0, /* just list 'em all?? */ X num, /* for argument parsing */ X page_breaks = 0, /* use "^L" breaks?? */ X total, /* number of msgs current */ X include_headers = WEED, /* flag: include msg header? */ X last_message = 0, /* flag: read last message? */ X not_in_header = 0, /* flag: in msg header? */ X string_match = 0; /* flag: using string match? */ X X /**** start of the actual program ****/ X X while ((num = getopt(argc, argv, "nhf:p")) != EOF) { X switch (num) { X case 'n' : include_headers = NONE; break; X case 'h' : include_headers = ALL; break; X case 'f' : strcpy(infile, optarg); X if (metachar(infile[0])) X if (expand(infile) == 0) X printf("%s: couldn't expand filename %s!\n", X argv[0], infile); X break; X case 'p' : page_breaks++; break; X case '?' : printf( X "Usage: %s [-n|-h] [-f filename] [-p] <message list>\n", X argv[0]); X exit(1); X } X } X X /** whip past the starting arguments so that we're pointing X to the right stuff... **/ X X *argv++; /* past the program name... */ X X while (optind-- > 1) { X *argv++; X argc--; X } X X /** now let's figure out the parameters to the program... **/ X X if (argc == 1) { /* no arguments... called from 'Elm'? */ X sprintf(filename, "%s/%s", getenv("HOME"), readmsg_file); X if ((file = fopen(filename, "r")) != NULL) { X fscanf(file, "%d", &(read_message[messages++])); X fclose(file); X } X else { /* no arguments AND no .readmsg file!! */ X fprintf(stderr, X "Usage: readmsg [-n|-h] [-f filename] [-p] <message list>\n"); X exit(1); X } X } X else if (! isdigit(*argv[0]) && *argv[0] != LAST_CHAR && X *argv[0] != STAR) { X string_match++; X X while (*argv) X sprintf(string, "%s%s%s", string, string[0] == '\0'? "" : " ", X *argv++); X } X else if (*argv[0] == STAR) /* all messages.... */ X list_all_messages++; X else { /* list of nums */ X X while (--argc > 0) { X num = -1; X X sscanf(*argv,"%d", &num); X X if (num < 0) { X if (*argv[0] == LAST_CHAR) { X last_message++; X num = LAST_MESSAGE; X } X else { X fprintf(stderr,"I don't understand what '%s' means...\n", X *argv); X exit(1); X } X } X else if (num == 0) { /* another way to say "last" */ X last_message++; X num = LAST_MESSAGE; X } X X *argv++; X X read_message[messages++] = num; X } X X /** and now sort 'em to ensure they're in a reasonable order... **/ X X qsort(read_message, messages, sizeof(int), numcmp); X } X X /** Now let's get to the mail file... **/ X X if (strlen(infile) == 0) { X if ((cp = getenv("MAIL")) == NULL) X sprintf(infile, "%s/%s", mailhome, getenv("LOGNAME")); X else X strcpy(infile, cp); X } X X if ((file = fopen(infile, "r")) == NULL) { X printf("But you have no mail! [ file = %d ]\n", infile); X exit(0); X } X X /** Now it's open, let's display some 'ole messages!! **/ X X if (string_match || last_message) { /* pass through it once */ X X if (last_message) { X total = count_messages(file); /* instantiate count */ X for (num=0; num < messages; num++) X if (read_message[num] == LAST_MESSAGE) X read_message[num] = total; X } X else if (string_match) X match_string(file, string); /* stick msg# in list */ X X if (total == 0 && ! string_match) { X printf("There aren't any messages to read!\n"); X exit(0); X } X } X X /** now let's have some fun! **/ X X while (fgets(buffer, SLEN, file) != NULL) { X if (real_from(buffer)) { X if (! list_all_messages) { X if (current == read_message[current_in_queue]) X current_in_queue++; X if (current_in_queue >= messages) X exit(0); X } X current++; X not_in_header = 0; /* we're in the header! */ X } X if (current == read_message[current_in_queue] || list_all_messages) X if (include_headers==ALL || not_in_header) X printf("%s", buffer); X else if (strlen(buffer) < 2) { X not_in_header++; X if (include_headers==WEED) X list_saved_headers(page_breaks); X } X else if (include_headers==WEED) X possibly_save(buffer); /* check to see if we want this */ X } X X exit(0); X} X Xint Xcount_messages(file) XFILE *file; X{ X /** Returns the number of messages in the file **/ X X char buffer[SLEN]; X int count = 0; X X while (fgets(buffer, SLEN, file) != NULL) X if (strncmp(buffer, "From ", 5) == 0) X count++; X X rewind( file ); X return( count ); X} X Xmatch_string(mailfile, string) XFILE *mailfile; Xchar *string; X{ X /** Increment "messages" and put the number of the message X in the message_count[] buffer until we match the specified X string... **/ X X char buffer[SLEN]; X int message_count = 0; X X while (fgets(buffer, SLEN, mailfile) != NULL) { X if (strncmp(buffer, "From ", 5) == 0) X message_count++; X X if (in_string(buffer, string)) { X read_message[messages++] = message_count; X rewind(mailfile); X return; X } X } X X fprintf(stderr,"Couldn't find message containing '%s'\n", string); X exit(1); X} X Xint Xnumcmp(a, b) Xint *a, *b; X{ X /** compare 'a' to 'b' returning less than, equal, or greater X than, accordingly. X **/ X X return(*a - *b); X} X Xstatic char from[SLEN], subject[SLEN], date[SLEN], to[SLEN]; X Xpossibly_save(buffer) Xchar *buffer; X{ X /** Check to see what "buffer" is...save it if it looks X interesting... We'll always try to get SOMETHING X by tearing apart the "From " line... **/ X X if (strncmp(buffer, "Date:", 5) == 0) X strcpy(date, buffer); X else if (strncmp(buffer, "Subject:", 8) == 0) X strcpy(subject,buffer); X else if (strncmp(buffer,"From:", 5) == 0) X strcpy(from, buffer); X else if (strncmp(buffer,"To: ", 3) == 0) X strncpy(to, buffer, SLEN); X else if (strncmp(buffer,"From ", 5) == 0) { X sprintf(from, "From: %s\n", words(2,1, buffer)); X sprintf(date,"Date: %s", words(3,7, buffer)); X to[0] = '\0'; X } X} X Xlist_saved_headers(page_break) Xint page_break; X{ X /** This routine will display the information saved from the X message being listed...If it displays anything it'll end X with a blank line... **/ X X register int displayed_line = FALSE; X static int messages_listed = 0; X X if (messages_listed++) X if (page_break) X putchar(FORMFEED); X else X printf( X"\n--------------------------------------------------------------------\n\n\n"); X X if (strlen(from) > 0) { printf("%s", from); displayed_line++;} X if (strlen(subject) > 0) { printf("%s", subject); displayed_line++;} X if (strlen(to) > 0) { printf("%s", to); displayed_line++;} X if (strlen(date) > 0) { printf("%s", date); displayed_line++;} X X if (displayed_line) X putchar('\n'); X} X Xchar *words(word, num_words, buffer) Xint word, num_words; Xchar *buffer; X{ X /** Return a buffer starting at 'word' and containing 'num_words' X words from buffer. Assume white space will delimit each word. X **/ X X static char internal_buffer[SLEN]; X char *wordptr, *bufptr, mybuffer[SLEN], *strtok(); X int wordnumber = 0, copying_words = 0; X X internal_buffer[0] = '\0'; /* initialize */ X X strcpy(mybuffer, buffer); X bufptr = (char *) mybuffer; /* and setup */ X X while ((wordptr = strtok(bufptr, " \t")) != NULL) { X if (++wordnumber == word) { X strcpy(internal_buffer, wordptr); X copying_words++; X num_words--; X } X else if (copying_words) { X strcat(internal_buffer, " "); X strcat(internal_buffer, wordptr); X num_words--; X } X X if (num_words < 1) X return((char *) internal_buffer); X X bufptr = NULL; X } X X return( (char *) internal_buffer); X} X Xint Xexpand(infile) Xchar *infile; X{ X /** Expand the filename since the first character is a meta- X character that should expand to the "maildir" variable X in the users ".elmrc" file... X X Note: this is a brute force way of getting the entry out X of the .elmrc file, and isn't recommended for the faint X of heart! X **/ X X FILE *rcfile; X char buffer[SLEN], *expanded_dir, *home, *getenv(), *bufptr; X int foundit = 0; X X bufptr = (char *) buffer; /* same address */ X X if ((home = getenv("HOME")) == NULL) { X printf( X "Can't expand environment variable $HOME to find .elmrc file!\n"); X exit(1); X } X X sprintf(buffer, "%s/%s", home, elmrcfile); X X if ((rcfile = fopen(buffer, "r")) == NULL) { X printf("Can't open your \".elmrc\" file (%s) for reading!\n", X buffer); X exit(1); X } X X while (fgets(buffer, SLEN, rcfile) != NULL && ! foundit) { X if (strncmp(buffer, "maildir", 7) == 0 || X strncmp(buffer, "folders", 7) == 0) { X while (*bufptr != '=' && *bufptr) X bufptr++; X bufptr++; /* skip the equals sign */ X while (whitespace(*bufptr) && *bufptr) X bufptr++; X home = bufptr; /* remember this address */ X X while (! whitespace(*bufptr) && *bufptr != '\n') X bufptr++; X X *bufptr = '\0'; /* remove trailing space */ X foundit++; X } X } X X fclose(rcfile); /* be nice... */ X X if (! foundit) { X printf("Couldn't find \"maildir\" in your .elmrc file!\n"); X exit(1); X } X X /** Home now points to the string containing your maildir, with X no leading or trailing white space... X **/ X X expanded_dir = expand_define(home); X X sprintf(buffer, "%s%s%s", expanded_dir, X (expanded_dir[strlen(expanded_dir)-1] == '/' || X infile[0] == '/') ? "" : "/", (char *) infile+1); X X strcpy(infile, buffer); X} X Xchar *expand_define(maildir) Xchar *maildir; X{ X /** This routine expands any occurances of "~" or "$var" in X the users definition of their maildir directory out of X their .elmrc file. X X Again, another routine not for the weak of heart or staunch X of will! X **/ X X static char buffer[SLEN]; /* static buffer AIEE!! */ X char name[SLEN], /* dynamic buffer!! (?) */ X *nameptr, /* pointer to name?? */ X *value; /* char pointer for munging */ X X if (*maildir == '~') X sprintf(buffer, "%s%s", getenv("HOME"), ++maildir); X else if (*maildir == '$') { /* shell variable */ X X /** break it into a single word - the variable name **/ X X strcpy(name, (char *) maildir + 1); /* hurl the '$' */ X nameptr = (char *) name; X while (*nameptr != '/' && *nameptr) nameptr++; X *nameptr = '\0'; /* null terminate */ X X /** got word "name" for expansion **/ X X if ((value = getenv(name)) == NULL) { X printf("Couldn't expand shell variable $%s in .elmrc!\n", name); X exit(1); X } X sprintf(buffer, "%s%s", value, maildir + strlen(name) + 1); X } X else X strcpy(buffer, maildir); X X return( ( char *) buffer); X} X Xint Xreal_from(buffer) Xchar *buffer; X{ X /***** Returns true iff 's' has the seven 'from' fields, (or X 8 - some machines include the TIME ZONE!!!) *****/ X X char sixthword[STRING], seventhword[STRING], X eighthword[STRING], ninthword[STRING]; X X /* From <user> <day> <month> <day> <hr:min:sec> <year> */ X X if(strncmp(buffer, "From ", 5) != 0) X return(FALSE); X X /* Extract 6th, 7th, 8th, and 9th words */ X seventhword[0] = eighthword[0] = ninthword[0] = '\0'; X sscanf(buffer, "%*s %*s %*s %*s %*s %s %s %s %s", X sixthword, seventhword, eighthword, ninthword); X X /* Not a from line if 6th word doesn't have colons for time field */ X if(strlen(sixthword) < 3) X return(FALSE); X if (sixthword[1] != ':' && sixthword[2] != ':') X return(FALSE); X X /* Not a from line if there is no seventh word */ X if(seventhword[0] == '\0') X return(FALSE); X X /* Not a from line if there is a ninthword */ X if (eighthword[0] != '\0') { X if(ninthword[0] != '\0') X return(FALSE); X } X X return(TRUE); X} SHAR_EOF chmod 0444 utils/readmsg.c || echo "restore of utils/readmsg.c fails" rm -f s2_seq_.tmp echo "You have unpacked the last part" exit 0 -- Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.