sources-request@mirror.UUCP (06/30/86)
Submitted by: Dave Taylor <pyramid!hplabs!hpldat!taylor> Mod.sources: Volume 6, Issue 33 Archive-name: elm/Part08 # Continuation of Shell Archive, created by hpldat!taylor # This is part 8 # 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 src ] then echo creating directory src mkdir src fi # ---------- file src/utils.c ---------- filename="src/utils.c" if [ -f $filename ] then echo File \"$filename\" already exists\! Skipping... filename=/dev/null # throw it away else echo extracting file src/utils.c... fi cat << 'END-OF-FILE' > $filename /** utils.c **/ /** Utility routines for ELM All routines herein: (C) Copyright 1985 Dave Taylor **/ #include "headers.h" #include <sys/types.h> #include <sys/stat.h> #include <ctype.h> #ifdef BSD #undef tolower #endif #include <signal.h> emergency_exit() { /** used in dramatic cases when we must leave without altering ANYTHING about the system... **/ dprint0(1, "\nERROR: Something dreadful is happening! Taking emergency exit!!\n\n"); dprint0(1," possibly leaving behind the following files;\n"); dprint2(1," The mailbox tempfile : %s%s\n", temp_mbox, username); dprint2(1," The mailbox lock file: %s%s.lock\n", mailhome, username); dprint2(1," The composition file : %s%d\n", temp_file, getpid()); dprint2(1," The header comp file : %s%d\n", temp_file, getpid()+1); dprint2(1," The readmsg data file: %s/%s\n", home, readmsg_file); Raw(OFF); if (cursor_control) transmit_functions(OFF); if (hp_terminal) softkeys_off(); if (cursor_control) MoveCursor(LINES, 0); PutLine0(LINES,0, "\nEmergency Exit taken! All temp files intact!\n\n"); exit(1); } leave(val) int val; /* not used, placeholder for signal catching! */ { char buffer[SLEN]; dprint0(2,"\nLeaving mailer normally (leave)\n"); Raw(OFF); if (cursor_control) transmit_functions(OFF); if (hp_terminal) softkeys_off(); sprintf(buffer,"%s%d",temp_file, getpid()); /* editor buffer */ (void) unlink(buffer); sprintf(buffer,"%s%d",temp_file, getpid()+1); /* editor buffer */ (void) unlink(buffer); sprintf(buffer,"%s%s",temp_mbox, username); /* temp mailbox */ (void) unlink(buffer); sprintf(buffer,"%s/%s", home, readmsg_file); /* readmsg temp */ (void) unlink(buffer); sprintf(buffer,"%s%s.lock",mailhome, username); /* lock file */ (void) unlink(buffer); if (! mail_only) { MoveCursor(LINES,0); Writechar('\n'); } exit(0); } leave_locked(val) int val; /* not used, placeholder for signal catching! */ { /** same as leave routine, but don't disturb lock file **/ char buffer[SLEN]; dprint0(3, "\nLeaving mailer due to presence of lock file (leave_locked)\n"); Raw(OFF); if (cursor_control) transmit_functions(OFF); if (hp_terminal) softkeys_off(); sprintf(buffer,"%s%d",temp_file, getpid()); /* editor buffer */ (void) unlink(buffer); sprintf(buffer,"%s%d",temp_file, getpid()+1); /* editor buffer */ (void) unlink(buffer); sprintf(buffer,"%s%s",temp_mbox, username); /* temp mailbox */ (void) unlink(buffer); MoveCursor(LINES,0); Writechar('\n'); exit(0); } int get_page(msg_pointer) int msg_pointer; { /** ensure that 'current' is on the displayed page, returning non-zero iff the page changed! **/ register int first_on_page, last_on_page; first_on_page = (header_page * headers_per_page) + 1; last_on_page = first_on_page + headers_per_page - 1; if (msg_pointer > last_on_page) { header_page = (int) (msg_pointer-1) / headers_per_page; return(1); } else if (msg_pointer < first_on_page) { header_page = (int) (msg_pointer-1) / headers_per_page; return(1); } else return(0); } int copy_to_self(buffer) char *buffer; { /** returns true iff buffer = 'Cc: username' where username is the account name of the person sending the message. Used for weeding out 'Cc:' lines from the messages if 'weed' is turned on. **/ /** note: tail_of() is located in file "strings.c" **/ char name[SLEN], buf[SLEN]; register int i=0, j=0; tail_of(header_table[current-1].from, name, FALSE); while (name[i] != '!' && i < strlen(name)) i++; if (name[i] == '!') { for (i++; i < strlen(name); i++) name[j++] = name[i]; name[j] = 0; } sprintf(buf, "Cc: %s\n", name); return( strcmp(buf, buffer) == 0 ); } END-OF-FILE if [ "$filename" != "/dev/null" ] then size=`wc -c < $filename` if [ $size != 3786 ] then echo $filename changed - should be 3786 bytes, not $size bytes fi chmod 644 $filename fi # ---------- file src/validname.c ---------- filename="src/validname.c" if [ -f $filename ] then echo File \"$filename\" already exists\! Skipping... filename=/dev/null # throw it away else echo extracting file src/validname.c... fi cat << 'END-OF-FILE' > $filename /** validname.c **/ /** This routine takes a single address, no machine hops or anything, and returns 1 if it's valid and 0 if not. The algorithm it uses is the same one that uux uses, namely: 1. Is there a file '/usr/mail/%s'? 2. Is there a password entry for %s? (C) Copyright 1986 Dave Taylor **/ #include <stdio.h> #include "defs.h" int valid_name(name) char *name; { /** does what it says above, boss! **/ #ifdef NOCHECK_VALIDNAME return(1); /* always say it's okay! */ #else char filebuf[SLEN]; sprintf(filebuf,"%s/%s", mailhome, name); if (access(filebuf, ACCESS_EXISTS) == 0) return(1); if (getpwnam(name) != NULL) return(1); return(0); #endif } END-OF-FILE if [ "$filename" != "/dev/null" ] then size=`wc -c < $filename` if [ $size != 706 ] then echo $filename changed - should be 706 bytes, not $size bytes fi chmod 644 $filename fi # ---------- file src/syscall.c ---------- filename="src/syscall.c" if [ -f $filename ] then echo File \"$filename\" already exists\! Skipping... filename=/dev/null # throw it away else echo extracting file src/syscall.c... fi cat << 'END-OF-FILE' > $filename /** syscall.c **/ /** These routines are used for user-level system calls, including the '!' command and the '|' commands... (C) Copyright 1986 Dave Taylor **/ #include "headers.h" #include <signal.h> char *argv_zero(); int subshell() { /** spawn a subshell with either the specified command returns non-zero if screen rewrite needed **/ char command[SLEN]; int ret; PutLine0(LINES-3,COLUMNS-40,"(use the shell name for a shell)"); PutLine0(LINES-2,0,"Shell Command: "); command[0] = '\0'; (void) optionally_enter(command, LINES-2, 15, FALSE); if (strlen(command) == 0) { MoveCursor(LINES-2,0); CleartoEOLN(); return(0); } MoveCursor(LINES,0); CleartoEOLN(); Raw(OFF); if (cursor_control) transmit_functions(OFF); ret = system_call(command, USER_SHELL); PutLine0(LINES, 0, "\n\nPress <return> to return to ELM: "); Raw(ON); (void) getchar(); if (cursor_control) transmit_functions(ON); if (ret != 0) error1("Return code was %d", ret); return(1); } system_call(string, shell_type) char *string; int shell_type; { /** execute 'string', setting uid to userid... **/ /** if shell-type is "SH" /bin/sh is used regardless of the users shell setting. Otherwise, "USER_SHELL" is sent **/ int status, pid, w; register int (*istat)(), (*qstat)(); dprint2(2,"System Call: %s\n\t%s\n", shell_type == SH? "/bin/sh" : shell, string); #ifdef NO_VM /* machine without virtual memory! */ if ((pid = fork()) == 0) { #else if ((pid = vfork()) == 0) { #endif setuid(userid); /* back to the normal user! */ setgid(groupid); /* and group id */ if (strlen(shell) > 0 && shell_type == USER_SHELL) { execl(shell, argv_zero(shell), "-c", string, 0); } else execl("/bin/sh", "sh", "-c", string, 0); _exit(127); } istat = signal(SIGINT, SIG_IGN); qstat = signal(SIGQUIT, SIG_IGN); while ((w = wait(&status)) != pid && w != -1) ; if (w == -1) status = -1; signal(SIGINT, istat); signal(SIGQUIT, qstat); return(status); } int do_pipe() { /** pipe the tagged messages to the specified sequence.. **/ char command[SLEN], buffer[LONG_SLEN], message_list[SLEN]; register int ret, tagged = 0, oldstat, i; message_list[0] = '\0'; /* NULL string to start... */ for (i=0; i < message_count; i++) if (ison(header_table[i].status, TAGGED)) { sprintf(message_list,"%s %d", message_list, header_table[i].index_number); tagged++; } if (tagged > 1) PutLine0(LINES-2,0,"Pipe tagged msgs to: "); else if (tagged) PutLine0(LINES-2,0,"Pipe tagged msg to : "); else { PutLine0(LINES-2,0,"Pipe current msg to: "); sprintf(message_list,"%d", header_table[current-1].index_number); } command[0] = '\0'; (void) optionally_enter(command, LINES-2, 21, FALSE); if (strlen(command) == 0) { MoveCursor(LINES-2,0); CleartoEOLN(); return(0); } MoveCursor(LINES,0); CleartoEOLN(); Raw(OFF); if (cursor_control) transmit_functions(OFF); sprintf(buffer, "%s -f %s -h %s | %s", readmsg, infile, message_list, command); ret = system_call(buffer, USER_SHELL); PutLine0(LINES, 0, "\n\nPress <return> to return to ELM: "); Raw(ON); (void) getchar(); if (cursor_control) transmit_functions(ON); if (ret != 0) error1("Return code was %d", ret); return(1); } printmsg() { /** Print current message or tagged messages using 'printout' variable. Error message iff printout not defined! **/ char buffer[LONG_SLEN], filename[SLEN], printbuffer[LONG_SLEN]; char message_list[SLEN]; register int retcode, tagged = 0, oldstat, i; if (strlen(printout) == 0) { error("Don't know how to print - option \"printmail\" undefined!"); return; } message_list[0] = '\0'; /* reset to null... */ for (i=0; i < message_count; i++) if (header_table[i].status & TAGGED) { sprintf(message_list, "%s %d", message_list, header_table[i].index_number); tagged++; } if (! tagged) sprintf(message_list," %d", header_table[current-1].index_number); sprintf(filename,"%s%d", temp_print, getpid()); if (in_string(printout, "%s")) sprintf(printbuffer, printout, filename); else sprintf(printbuffer, "%s %s", printout, filename); sprintf(buffer,"(%s -p -f %s%s > %s; %s 2>&1) > /dev/null", readmsg, infile, message_list, filename, printbuffer); dprint0(2,"Printing system call...\n"); Centerline(LINES, "queueing..."); if ((retcode = system_call(buffer, SH)) == 0) { sprintf(buffer, "Message%s queued up to print", plural(tagged)); Centerline(LINES, buffer); } else error1("Printout failed with return code %d", retcode); unlink(filename); /* remove da temp file! */ } END-OF-FILE if [ "$filename" != "/dev/null" ] then size=`wc -c < $filename` if [ $size != 4692 ] then echo $filename changed - should be 4692 bytes, not $size bytes fi chmod 644 $filename fi # ---------- file src/aliaslib.c ---------- filename="src/aliaslib.c" if [ -f $filename ] then echo File \"$filename\" already exists\! Skipping... filename=/dev/null # throw it away else echo extracting file src/aliaslib.c... fi cat << 'END-OF-FILE' > $filename /** aliaslib.c **/ /** Library of functions dealing with the alias system... (C) Copyright 1986 Dave Taylor **/ #include "headers.h" char *expand_group(), *get_alias_address(), *expand_system(); char *get_token(), *strpbrk(); char *get_alias_address(name, mailing, depth) char *name; int mailing, depth; { /** return the line from either datafile that corresponds to the specified name. If 'mailing' specified, then fully expand group names. Depth specifies the nesting depth - the routine should always initially be called with this equal 0. Returns NULL if not found **/ static char buffer[VERY_LONG_STRING]; int loc; if (strlen(name) == 0) return( (char *) NULL); if (user_files) if ((loc = find(name, user_hash_table, MAX_UALIASES)) >= 0) { lseek(user_data, user_hash_table[loc].byte, 0L); get_line(user_data, buffer); if (buffer[0] == '!' && mailing) return(expand_group(buffer, depth)); else if (strpbrk(buffer,"!@:") != NULL) /* has a hostname */ return(expand_system(buffer, TRUE)); else return((char *) buffer); } if (system_files) if ((loc = find(name, system_hash_table, MAX_SALIASES)) >= 0) { lseek(system_data, system_hash_table[loc].byte, 0L); get_line(system_data, buffer); if (buffer[0] == '!' && mailing) return(expand_group(buffer, depth)); else if (strpbrk(buffer,"!@:") != NULL) /* has a hostname */ return(expand_system(buffer, TRUE)); else return((char *) buffer); } return( (char *) NULL); } char *expand_system(buffer, show_errors) char *buffer; int show_errors; { /** This routine will check the first machine name in the given path (if any) and expand it out if it is an alias...if not, it will return what it was given. If show_errors is false, it won't display errors encountered... **/ dprint2(6, "expand_system(%s, show-errors=%s)\n", buffer, onoff(show_errors)); findnode(buffer, show_errors); return( (char *) buffer); } char *expand_group(members, depth) char *members; int depth; { /** Given a group of names separated by commas, this routine will return a string that is the full addresses of each member separated by spaces. Depth is an internal counter that keeps track of the depth of nesting that the routine is in...it's for the get_token routine! **/ static char buffer[VERY_LONG_STRING]; char buf[LONG_STRING], *word, *address, *bufptr; strcpy(buf, members); /* parameter safety! */ if (depth == 0) buffer[0] = '\0'; /* nothing in yet! */ bufptr = (char *) buf; /* grab the address */ depth++; /* one deeper! */ while ((word = get_token(bufptr, "!, ", depth)) != NULL) { if ((address = get_alias_address(word, 1, depth)) == NULL) { if (! valid_name(word)) { dprint2(3, "Encountered illegal address %s (%s)\n", word, "expand_group"); error1("%s is an illegal address!", word); return( (char *) NULL); } else if (strcmp(buffer, word) != 0) sprintf(buffer, "%s%s%s", buffer, (strlen(buffer) > 0)? ", ":"", word); } else if (strcmp(buffer, address) != 0) sprintf(buffer,"%s%s%s", buffer, (strlen(buffer) > 0)? ", ":"", address); bufptr = NULL; } return( (char *) buffer); } int find(word, table, size) char *word; struct alias_rec table[]; int size; { /** find word and return loc, or -1 **/ register int loc; if (strlen(word) > 20) { dprint2(3, "Too long alias name entered [%s] (%s)\n", word, "find"); error1("Bad alias name: %s. Too long.\n", word); return(-1); } loc = hash_it(word, size); while (strcmp(word, table[loc].name) != 0) { if (table[loc].name[0] == '\0') return(-1); loc = (loc + 1) % size; } return(loc); } int hash_it(string, table_size) char *string; int table_size; { /** 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); } get_line(fd, buffer) int fd; char *buffer; { /* read from file fd. End read upon reading either EOF or '\n' character (this is where it differs from a straight 'read' command!) */ register int i= 0; char ch; while (read(fd, &ch, 1) > 0) if (ch == '\n' || ch == '\r') { buffer[i] = 0; return; } else buffer[i++] = ch; } END-OF-FILE if [ "$filename" != "/dev/null" ] then size=`wc -c < $filename` if [ $size != 4476 ] then echo $filename changed - should be 4476 bytes, not $size bytes fi chmod 644 $filename fi # ---------- file src/domains.c ---------- filename="src/domains.c" if [ -f $filename ] then echo File \"$filename\" already exists\! Skipping... filename=/dev/null # throw it away else echo extracting file src/domains.c... fi cat << 'END-OF-FILE' > $filename /** domains.c **/ /** This file contains all the code dealing with the expansion of domain based addresses in Elm. It uses the file "domains" as defined in the sysdefs.h file. (C) Copyright 1986 Dave Taylor From a file format and idea in "uumail" - designed by Stan Barber. **/ #include <stdio.h> #include <ctype.h> #include "headers.h" /** define the various characters that we can encounter after a "%" sign in the template file... **/ #define USERNAME 'U' /* %U = the name of the remote user */ #define HOSTNAME 'N' /* %N = the remote machine name */ #define FULLNAME 'D' /* %D = %N + domain info given */ #define NPATH 'R' /* %R = path to %N from pathalias */ #define PPATH 'P' /* %P = path to 'P' from pathalias */ #define OBSOLETE 'S' /* %S = (used to be suffix string) */ /** and finally some characters that are allowed in user/machine names **/ #define okay_others(c) (c == '-' || c == '^' || c == '$' || c == '_') /** and some allowed ONLY in the username field **/ #define special_chars(c) (c == '%' || c == ':') char *find_path_to(), *expand_domain(), *match_and_expand_domain(); open_domain_file() { if ((domainfd = fopen(domains, "r")) == NULL) { dprint1(1, "Can't open file %s as domains file (open_domain_file)\n", domains); } else { dprint1(2, "\nOpened '%s' as the domain database. (open_domain_file)\n\n", domains); } /* if it fails it'll instantiate domainfd to NULL which is exactly what we want to have happen!! */ } char *expand_domain(buffer) char *buffer; { /** Expand the address 'buffer' based on the domain information, if any. Returns NULL if it can't expand it for any reason. **/ char name[2*NLEN], address[2*NLEN], domain[2*NLEN]; char *match_and_expand_domain(); if (domainfd == NULL) return(NULL); /* no file present! */ if (explode(buffer, name, address, domain)) return( match_and_expand_domain(domain, name, address) ); else { /* invalid format - not "user@host.domain" */ dprint1(3, "Invalid format for domain expansion: %s (expand_domain)\n", buffer); return(NULL); } } int explode(buffer, name, address, domain) char *buffer, *name, *address, *domain; { /** Break buffer, if in format name@machine.domain, into the component parts, otherwise return ZERO and don't worry about the values of the parameters! **/ register int i, j = 0; /** First get the name... **/ for (i=0; buffer[i] != '@'; i++) { if (! isalnum(buffer[i]) && ! okay_others(buffer[i]) && ! special_chars(buffer[i])) return(0); /* invalid character in string! */ name[i] = buffer[i]; } name[i++] = '\0'; /** now let's get the machinename **/ while (buffer[i] != '.') { if (! isalnum(buffer[i]) && ! okay_others(buffer[i])) return(0); /* invalid character in string! */ address[j++] = buffer[i++]; } address[j] = '\0'; j = 0; /** finally let's get the domain information (there better be some!) **/ while (buffer[i] != '\0') { if (! isalnum(buffer[i]) && ! okay_others(buffer[i]) && buffer[i] != '.') return(0); /* an you fail again, bozo! */ domain[j++] = toupper(buffer[i]); i++; } domain[j] = '\0'; return(j); /* if j == 0 there's no domain info! */ } char *match_and_expand_domain(domain, name, machine) char *domain, *name, *machine; { /** Given the domain, try to find it in the domain file and if found expand the entry and return the result as a character string... **/ static char address[SLEN]; char buffer[SLEN], domainbuff[NLEN]; char field1[2*NLEN], field2[2*NLEN], field3[2*NLEN]; char *path, *template, *expanded, *mydomain; int matched = 0, in_percent = 0; register int i, j = 0; address[j] = '\0'; domainbuff[0] = '\0'; mydomain = (char *) domainbuff; /* set up buffer etc */ do { rewind(domainfd); /* back to ground zero! */ if (strlen(mydomain) > 0) { /* already in a domain! */ mydomain++; /* skip leading '.' */ while (*mydomain != '.' && *mydomain != ',') mydomain++; /* next character */ if (*mydomain == ',') return (NULL); /* didn't find domain! */ } else sprintf(mydomain, "%s,", domain); /* match ENTIRELY! */ /* whip through file looking for the entry, please... */ while (fgets(buffer, SLEN, domainfd) != NULL) { if (buffer[0] == '#') /* skip comments */ continue; if (strncmp(buffer, mydomain, strlen(mydomain)) == 0) { /* match? */ matched++; /* Gotcha! Remember this momentous event! */ break; } } if (! matched) continue; /* Nothing. Not a sausage! Step through! */ /** We've matched the domain! **/ no_ret(buffer); (void) strtok(buffer, ","); /* skip the domain info */ strcpy(field1, strtok(NULL, ",")); /* fun */ strcpy(field2, strtok(NULL, ",")); /* stuff */ strcpy(field3, strtok(NULL, ",")); /* eh? */ path = (char *) NULL; /* now we merely need to figure out what permutation this is! */ if (field3 == NULL || strlen(field3) == 0) if (field2 == NULL || strlen(field2) == 0) template = (char *) field1; else { path = (char *) field1; template = (char *) field2; } else { dprint1(2,"Domain info for %s from file broken into THREE fields!!\n", domain); dprint3(2, "-> %s\n-> %s\n-> %s\n", field1, field2, field3); error1("Warning: domain %s uses a defunct field!!", domain); sleep(2); path = (char *) field1; template = (char *) field3; } if (strlen(path) > 0 && path[0] == '>') path++; /* skip the '>' character, okay? */ j = 0; /* address is zero, right now, right?? */ address[j] = '\0'; /* make sure string is too! */ for (i=0; i < strlen(template); i++) { if (template[i] == '%') { if (! in_percent) /* just hit a NEW percent! */ in_percent = 1; else { /* just another percent sign on the wall... */ address[j++] = '%'; address[j] = '\0'; /* ALWAYS NULL terminate */ in_percent = 0; } } else if (in_percent) { /* Hey! a real command string */ in_percent = 0; switch (template[i]) { case USERNAME: strcat(address, name); break; case HOSTNAME: strcat(address, machine); break; case FULLNAME: strcat(address, machine); strcat(address, domain); break; case NPATH : if ((expanded = find_path_to(machine, FALSE)) == NULL) { dprint2(3,"\nCouldn't expand system path '%s' (%s)\n\n", machine, "domains"); error1("Couldn't find a path to %s!", machine); sleep(2); return(NULL); /* failed!! */ } strcat(address, expanded); /* isn't this fun??? */ break; case PPATH : if ((expanded = find_path_to(path, FALSE)) == NULL) { dprint2(3,"\nCouldn't expand system path '%s' (%s)\n\n", path, "domains"); error1("I Couldn't find a path to %s!", path); sleep(2); return(NULL); /* failed!! */ } strcat(address, expanded); /* isn't this fun??? */ break; case OBSOLETE: /* fall through.. */ default : dprint2(1, "\nError: Bad sequence in template file for domain '%s': %%%c\n\n", domain, template[i]); } j = strlen(address); } else { address[j++] = template[i]; address[j] = '\0'; /* null terminate */ } } address[j] = '\0'; } while (strlen(address) < 1); return( (char *) address); } END-OF-FILE if [ "$filename" != "/dev/null" ] then size=`wc -c < $filename` if [ $size != 7635 ] then echo $filename changed - should be 7635 bytes, not $size bytes fi chmod 644 $filename fi # ---------- file src/fileio.c ---------- filename="src/fileio.c" if [ -f $filename ] then echo File \"$filename\" already exists\! Skipping... filename=/dev/null # throw it away else echo extracting file src/fileio.c... fi cat << 'END-OF-FILE' > $filename /** fileio.c **/ /** File I/O routines, including deletion from the mailbox! (C) Copyright 1986 Dave Taylor **/ #include "headers.h" #include <ctype.h> #ifdef BSD #undef tolower #endif copy_message(prefix, dest_file, remove_header, remote) char *prefix; FILE *dest_file; int remove_header, remote; { /** Copy current message to destination file, with optional 'prefix' as the prefix for each line. If remove_header is true, it will skip lines in the message until it finds the end of header line... then it will start copying into the file... If remote is true then it will append "remote from <hostname>" at the end of the very first line of the file (for remailing) **/ char buffer[LONG_SLEN]; register int ok = 1, lines, in_header = 1, first_line = TRUE; /** get to the first line of the message desired **/ if (fseek(mailfile, header_table[current-1].offset, 0) == -1) { dprint2(1,"ERROR: Attempt to seek %d bytes into file failed (%s)", header_table[current-1].offset, "copy_message"); error1("ELM [seek] failed trying to read %d bytes into file", header_table[current-1].offset); return; } /* how many lines in message? */ lines = header_table[current-1].lines; /* now while not EOF & still in message... copy it! */ while (ok && lines--) { ok = (int) (fgets(buffer, LONG_SLEN, mailfile) != NULL); if (strlen(buffer) < 2) in_header = 0; if (ok) if (! (remove_header && in_header)) if (first_line && remote) { no_ret(buffer); fprintf(dest_file, "%s%s remote from %s\n", prefix, buffer, hostname); first_line = FALSE; } else if (! in_header && first_word(buffer, "From ")) { dprint0(1,"\n*** Internal Problem...Tried to add the following;\n"); dprint1(1," '%s'\nto output file (copy_message) ***\n", buffer); } else fprintf(dest_file, "%s%s", prefix, buffer); } } END-OF-FILE if [ "$filename" != "/dev/null" ] then size=`wc -c < $filename` if [ $size != 1967 ] then echo $filename changed - should be 1967 bytes, not $size bytes fi chmod 644 $filename fi # ---------- file src/return_addr.c ---------- filename="src/return_addr.c" if [ -f $filename ] then echo File \"$filename\" already exists\! Skipping... filename=/dev/null # throw it away else echo extracting file src/return_addr.c... fi cat << 'END-OF-FILE' > $filename /** return_addr.c **/ /** This set of routines is used to generate real return addresses and also return addresses suitable for inclusion in a users alias files (ie optimized based on the pathalias database). Added: the ability to respond to messages that were originally sent by the user (That is, the "savemail" file format messages) by reading the return address, seeing the "To:" prefix and then calling the "get_existing_return()" routine. Currently this does NOT include any "Cc" lines in the message, just the "To:" line(s). Also added the PREFER_UUCP stuff for listing reasonable addresses and such...*sigh* These routines (C) Copyright 1986 Dave Taylor **/ #include "headers.h" #include <errno.h> #include <sys/types.h> #include <sys/stat.h> char *shift_lower(), *notes_machine(), *expand_address(); extern int errno; char *error_name(); optimize_return(address) char *address; { /** This routine tries to create an optimized address, that is, an address that has the minimal information needed to route a message to this person given the current path database... **/ #ifdef PREFER_UUCP /** first off, let's see if we need to strip off the localhost address crap... **/ /** if we have a uucp part (e.g.a!b) AND the bogus address...**/ if (chloc(address,'!') != -1 && in_string(address, BOGUS_INTERNET)) address[strlen(address)-strlen(BOGUS_INTERNET)] = '\0'; #endif /** next step is to figure out what sort of address we have... **/ if (chloc(address, '%') != -1) optimize_cmplx_arpa(address); else if (chloc(address, '@') != -1) optimize_arpa(address); else optimize_usenet(address); } optimize_cmplx_arpa(address) char *address; { /** Try to optimize a complex ARPA address. A Complex address is one that contains '%' (deferred '@'). For example: veeger!hpcnof!hplabs!joe%sytech@syte is a complex address (no kidding, right?). The algorithm for trying to resolve it is to move all the way to the right, then back up left until the first '!' then from there to the SECOND metacharacter on the right is the name@host address...(in this example, it would be "joe%sytech"). Check this in the routing table. If not present, keep backing out to the right until we find a host that is present, or we hit the '@' sign. Once we have a 'normal' ARPA address, hand it to optimize_arpa(). **/ char name[SHORT_SLEN], buffer[SLEN], junk[SLEN]; char host[SHORT_SLEN], old_host[SHORT_SLEN]; register int i, loc, nloc = 0, hloc = 0, passes = 1; /** first off, get the name%host... **/ for (loc = strlen(address)-1; address[loc] != '!' && loc > -1; loc--) ; while (address[loc] != '\0') { if (passes == 1) { loc++; while (address[loc] != '%' && address[loc] != '@') name[nloc++] = address[loc++]; } else { for (i=0; old_host[i] != '\0'; i++) name[nloc++] = old_host[i]; } loc++; while (address[loc] != '%' && address[loc] != '@') host[hloc++] = address[loc++]; host[hloc] = name[nloc] = '\0'; strcpy(old_host, host); remove_domains(host); sprintf(buffer, "%s@%s", name, shift_lower(host)); if (expand_site(buffer, junk) == 0) { strcpy(address, buffer); return; } else if (address[loc] == '@') { optimize_arpa(address); return; } else name[nloc++] = '%'; /* for next pass through */ } } optimize_arpa(address) char *address; { /** Get an arpa address and simplify it to the minimal route needed to get mail to this person... **/ char name[SHORT_SLEN], buffer[SLEN], junk[SLEN]; char host[SHORT_SLEN]; register int loc, nloc = 0, hloc = 0, at_sign = 0; for (loc = strlen(address)-1; address[loc] != '!' && loc > -1; loc--) { if (address[loc] == '@') at_sign++; /* remember this spot! */ else if (at_sign) name[nloc++] = address[loc]; else host[hloc++] = address[loc]; } name[nloc] = host[hloc] = '\0'; reverse(name); reverse(host); remove_domains(host); sprintf(buffer,"%s@%s", name, shift_lower(host)); if (expand_site(buffer, junk) == 0) { strcpy(address, buffer); return; } optimize_usenet(address); /* that didn't work... */ } optimize_usenet(address) char *address; { /** optimize the return address IFF it's a standard usenet address... **/ char name[SHORT_SLEN], new_address[SLEN], buffer[SLEN], junk[SLEN]; register int loc, nloc = 0, aloc = 0, passes = 1; for (loc = strlen(address)-1; address[loc] != '!' && loc > -1; loc--) name[nloc++] = address[loc]; name[nloc] = '\0'; reverse(name); new_address[0] = '\0'; /* got name, now get machine until we can get outta here */ while (loc > -1) { new_address[aloc++] = address[loc--]; /* the '!' char */ while (address[loc] != '!' && loc > -1) new_address[aloc++] = address[loc--]; new_address[aloc] = '\0'; strcpy(buffer, new_address); reverse(buffer); if (expand_site(buffer, junk) == 0) { if (passes == 1 && chloc(name, '@') == -1) { buffer[strlen(buffer) - 1] = '\0'; /* remove '!' */ sprintf(address, "%s@%s", name, buffer); } else sprintf(address, "%s%s", buffer, name); return; /* success! */ } passes++; } return; /* nothing to do! */ } get_return(buffer) char *buffer; { /** reads 'current' message again, building up the full return address including all machines that might have forwarded the message. **/ char buf[LONG_SLEN], name1[SLEN], name2[SLEN], lastname[SLEN]; char hold_return[LONG_SLEN], alt_name2[SLEN]; int ok = 1, lines; /** are we reading a notesfile file?? **/ if (notesfile) { strcpy(buf, header_table[current-1].from); if (chloc(buf, '!') == -1) sprintf(buf, "%s!%s", notes_machine(), header_table[current-1].from); strcpy(buffer, expand_system(buf, TRUE)); return; } /** get to the first line of the message desired **/ if (fseek(mailfile, header_table[current-1].offset, 0) == -1) { dprint3(1,"Error: seek %ld bytes into file hit errno %s (%s)", header_table[current-1].offset, error_name(errno), "get_return"); error2("couldn't seek %d bytes into file (%s)", header_table[current-1].offset, error_name(errno)); return; } /** okay! Now we're there! **/ lines = header_table[current-1].lines; buffer[0] = '\0'; while (ok && lines--) { ok = (int) (fgets(buf, LONG_SLEN, mailfile) != NULL); if (first_word(buf, "From ")) { sscanf(buf, "%*s %s", hold_return); } else if (first_word(buf, ">From")) { sscanf(buf,"%*s %s %*s %*s %*s %*s %*s %*s %*s %s %s", name1, name2, alt_name2); if (strcmp(name2, "from") == 0) strcpy(name2, alt_name2); add_site(buffer, name2, lastname); } #ifdef USE_EMBEDDED_ADDRESSES else if (first_word(buf, "From:")) { get_address_from("From:", buf, hold_return); } else if (first_word(buf, "Reply-To:")) { get_address_from("Reply-To:", buf, buffer); return; } #endif else if (strlen(buf) < 2) /* done with header */ lines = 0; /* let's get outta here! We're done!!! */ } if (buffer[0] == '\0') strcpy(buffer, hold_return); /* default address! */ else add_site(buffer, name1, lastname); /* get the user name too! */ if (first_word(buffer, "To:")) /* response to savecopy! */ get_existing_address(buffer); } get_existing_address(buffer) char *buffer; { /** This routine is called when the message being responded to has "To:xyz" as the return address, signifying that this message is an automatically saved copy of a message previously sent. The correct to address can be obtained fairly simply by reading the To: header from the message itself and (blindly) copying it to the given buffer. Note that this header can be either a normal "To:" line (Elm) or "Originally-To:" (previous versions e.g.Msg) **/ char mybuf[LONG_STRING]; register char ok = 1, in_to = 0; buffer[0] = '\0'; /** first off, let's get to the beginning of the message... **/ if (fseek(mailfile, header_table[current-1].offset, 0) == -1) { dprint3(1,"Error: seek %ld bytes into file hit errno %s (%s)", header_table[current-1].offset, error_name(errno), "get_existing_address"); error2("couldn't seek %d bytes into the file (%s)", header_table[current-1].offset, error_name(errno)); return; } /** okay! Now we're there! **/ while (ok) { ok = (int) (fgets(mybuf, LONG_STRING, mailfile) != NULL); no_ret(mybuf); /* remove return character */ if (first_word(mybuf, "To: ")) { in_to = TRUE; strcpy(buffer, (char *) mybuf + strlen("To: ")); } else if (first_word(mybuf, "Original-To:")) { in_to = TRUE; strcpy(buffer, (char *) mybuf + strlen("Original-To:")); } else if (in_to && whitespace(mybuf[0])) { strcat(buffer, " "); /* tag a space in */ strcat(buffer, (char *) mybuf + 1); /* skip 1 whitespace */ } else if (strlen(mybuf) < 2) return; /* we're done for! */ else in_to = 0; } } END-OF-FILE if [ "$filename" != "/dev/null" ] then size=`wc -c < $filename` if [ $size != 9321 ] then echo $filename changed - should be 9321 bytes, not $size bytes fi chmod 644 $filename fi # ---------- file src/addr_utils.c ---------- filename="src/addr_utils.c" if [ -f $filename ] then echo File \"$filename\" already exists\! Skipping... filename=/dev/null # throw it away else echo extracting file src/addr_utils.c... fi cat << 'END-OF-FILE' > $filename /** addr_utils.c **/ /** This file contains addressing utilities (C) Copyright 1986 Dave Taylor **/ #include "headers.h" #include <sys/types.h> #include <sys/stat.h> #include <ctype.h> #ifdef BSD #undef tolower #endif char *shift_lower(), *get_alias_address(), *get_token(), *strtok(); int talk_to(sitename) char *sitename; { /** If we talk to the specified site, return true, else we're going to have to expand this baby out, so return false! **/ struct lsys_rec *sysname; sysname = talk_to_sys; if (sysname == NULL) { dprint0(2, "Warning - talk_to_sys is currently set to NULL! (talk_to)\n"); return(0); } while (sysname != NULL) { if (strcmp(sysname->name, sitename) == 0) return(1); else sysname = sysname->next; } return(0); } remove_domains(host) char *host; { /** Remove all entries following the first '.' to ensure that entries like "MIT.ARPA" will match "MIT" in the database **/ register int loc = 0; while (host[loc] != '.' && host[loc] != '\0') loc++; if (host[loc] == '.') host[loc] = '\0'; } add_site(buffer, site, lastsite) char *buffer, *site, *lastsite; { /** add site to buffer, unless site is 'uucp', current machine, or site is the same as lastsite. If not, set lastsite to site. **/ char local_buffer[LONG_SLEN]; if (strcmp(site, "uucp") != 0) if (strcmp(site, lastsite) != 0) if (strcmp(site, hostname) != 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! */ } } #ifdef USE_EMBEDDED_ADDRESSES get_address_from(prefix, line, buffer) char *prefix, *line, *buffer; { /** This routine extracts the address from either a 'From:' line or a 'Reply-To:' line...the algorithm is quite simple, too: increment 'line' past header, then check last character of line. If it's a '>' then the address is contained within '<>' and if it's a ')' then the address is in the 'clear'... **/ register int i, j = 0; no_ret(line); line = (char *) (line + strlen(prefix) + 1); if (line[strlen(line)-1] == '>') { for (i=strlen(line)-2; i > -1 && line[i] != '<'; i--) buffer[j++] = line[i]; buffer[j] = 0; reverse(buffer); } else { /* either ')' or address in the clear... */ for (i=0; i < strlen(line) && line[i] != '('; i++) buffer[j++] = line[i]; if (buffer[j-1] == '(') j--; buffer[j] = 0; } } #endif translate_return(addr, ret_addr) char *addr, *ret_addr; { /** Return ret_addr to be the same as addr, but with the login of the person sending the message replaced by '%s' for future processing... Fixed to make "%xx" "%%xx" (dumb 'C' system!) **/ register int loc, loc2, index = 0; loc2 = chloc(addr,'@'); if ((loc = chloc(addr, '%')) < loc2) loc2 = loc; if (loc2 != -1) { /* ARPA address. */ /* algorithm is to get to '@' sign and move backwards until we've hit the beginning of the word or another metachar. */ for (loc = loc2 - 1; loc > -1 && addr[loc] != '!'; loc--) ; } else { /* usenet address */ /* simple algorithm - find last '!' */ loc2 = strlen(addr); /* need it anyway! */ for (loc = loc2; loc > -1 && addr[loc] != '!'; loc--) ; } /** now copy up to 'loc' into destination... **/ while (index <= loc) { ret_addr[index] = addr[index]; index++; } /** now append the '%s'... **/ ret_addr[index++] = '%'; ret_addr[index++] = 's'; /** and, finally, if anything left, add that **/ while (loc2 < strlen(addr)) { ret_addr[index++] = addr[loc2++]; if (addr[loc2-1] == '%') /* tweak for "printf" */ ret_addr[index++] = '%'; } ret_addr[index] = '\0'; } build_address(to, full_to) char *to, *full_to; { /** loop on all words in 'to' line...append to full_to as we go along, until done or length > len **/ register int i, changed = 0; char word[SLEN], *ptr, buffer[SLEN]; char new_to_list[LONG_SLEN]; new_to_list[0] = '\0'; i = get_word(to, 0, word); full_to[0] = '\0'; while (i > 0) { if (strpbrk(word,"!@:") != NULL) sprintf(full_to, "%s%s%s", full_to, full_to[0] != '\0'? ", " : "", expand_system(word, 1)); else if ((ptr = get_alias_address(word, 1, 0)) != NULL) sprintf(full_to, "%s%s%s", full_to, full_to[0] != '\0'? ", " : "", ptr); else if (strlen(word) > 0) { if (valid_name(word)) sprintf(full_to, "%s%s%s", full_to, full_to[0] != '\0'? ", " : "", word); else if (check_only) { printf("(alias \"%s\" is unknown)\n\r", word); changed++; } else if (! isatty(fileno(stdin)) ) { /* batch mode error! */ fprintf(stderr,"Cannot expand alias '%s'!\n\r", word); fprintf(stderr,"Use \"checkalias\" to find valid addresses!\n\r"); dprint1(1, "Can't expand alias %s - bailing out! (build_address)\n", word); emergency_exit(); } else { dprint1(2,"Entered unknown address %s (build_address)\n", word); sprintf(buffer, "'%s' is an unknown address. Replace with: ", word); word[0] = '\0'; if (! mail_only) PutLine0(LINES, 0, buffer); (void) optionally_enter(word, LINES, strlen(buffer), FALSE); if (strlen(word) > 0) { sprintf(new_to_list, "%s%s%s", new_to_list, strlen(new_to_list) > 0? " ":"", word); dprint1(3,"Replaced with %s (build_address)\n", word); } else dprint0(3,"Address removed from to list (build_address)\n"); if (mail_only) printf("\n\r"); changed++; clear_error(); continue; } } i = get_word(to, i, word); } if (changed) strcpy(to, new_to_list); } int real_from(buffer, entry) char *buffer; struct header_rec *entry; { /***** Returns true iff 's' has the seven 'from' fields, (or 8 - some machines include the TIME ZONE!!!) Initializing the date and from entries in the record and also the message received date/time. *****/ char junk[STRING], timebuff[STRING], holding_from[SLEN]; int eight_fields = 0; entry->year[0] = '\0'; junk[0] = '\0'; /* From <user> <day> <month> <day> <hr:min:sec> <year> */ sscanf(buffer, "%*s %*s %*s %*s %*s %s %*s %s", timebuff, junk); if (timebuff[1] != ':' && timebuff[2] != ':') { dprint1(3,"real_from returns FAIL [bad time field] on\n-> %s\n", buffer); return(FALSE); } if (junk[0] != '\0') { /* try for 8 field entry */ junk[0] = '\0'; sscanf(buffer, "%*s %*s %*s %*s %*s %s %*s %*s %s", timebuff, junk); if (junk[0] != '\0') { dprint1(3,"real_from returns FAIL [too many fields] on\n-> %s\n", buffer); return(FALSE); } eight_fields++; } /** now get the info out of the record! **/ if (eight_fields) sscanf(buffer, "%s %s %s %s %s %s %*s %s", junk, holding_from, entry->dayname, entry->month, entry->day, entry->time, entry->year); else sscanf(buffer, "%s %s %s %s %s %s %s", junk, holding_from, entry->dayname, entry->month, entry->day, entry->time, entry->year); strncpy(entry->from, holding_from, STRING); resolve_received(entry); return(entry->year[0] != '\0'); } forwarded(buffer, entry) char *buffer; struct header_rec *entry; { /** Change 'from' and date fields to reflect the ORIGINATOR of the message by iteratively parsing the >From fields... Modified to deal with headers that include the time zone of the originating machine... **/ char machine[SLEN], buff[SLEN], holding_from[SLEN]; machine[0] = '\0'; sscanf(buffer, "%*s %s %s %s %s %s %s %*s %*s %s", holding_from, entry->dayname, entry->month, entry->day, entry->time, entry->year, machine); if (isdigit(entry->month[0])) { /* try for veeger address */ sscanf(buffer, "%*s %s %s%*c %s %s %s %s %*s %*s %s", holding_from, entry->dayname, entry->day, entry->month, entry->year, entry->time, machine); } if (isalpha(entry->year[0])) { /* try for address including tz */ sscanf(buffer, "%*s %s %s %s %s %s %*s %s %*s %*s %s", holding_from, entry->dayname, entry->month, entry->day, entry->time, entry->year, machine); } if (machine[0] == '\0') sprintf(buff,"anonymous"); else sprintf(buff,"%s!%s", machine, holding_from); strncpy(entry->from, buff, STRING); } 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 <hplabs!dat> or From: hplabs!dat (Dave Taylor) Change 'newfrom' ONLY if sucessfully parsed this entry and the resulting name is non-null! Added: removes quotes if name is quoted (12/12) Added: only copies STRING characters... **/ 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 and quotes... */ while (whitespace(temp[0]) || quote(temp[0])) temp = (char *) (temp + 1); /* increment address! */ /* remove trailing spaces and quotes... */ i = strlen(temp) - 1; while (whitespace(temp[i]) || quote(temp[i])) temp[i--] = '\0'; /* if anything is left, let's change 'from' value! */ if (strlen(temp) > 0) strncpy(newfrom, temp, STRING); } } parse_arpa_date(string, entry) char *string; struct header_rec *entry; { /** Parse and figure out the given date format... return the entry fields changed iff it turns out we have a valid parse of the date! **/ char word[15][NLEN], buffer[SLEN], *bufptr; char *aword; int words = 0; strcpy(buffer, string); bufptr = (char *) buffer; /** break the line down into words... **/ while ((aword = strtok(bufptr," \t '\"-/(),.")) != NULL) { strcpy(word[words++], aword); bufptr = NULL; } if (words < 6) { /* strange format. We're outta here! */ dprint1(3,"parse_arpa_date failed [less than six fields] on\n-> %s\n", string); return; } /* There are now five possible combinations that we could have: Date: day_number month_name year_number time timezone Date: day_name day_number month_name year_number ... Date: day_name month_name day_number time year_number Date: day_name month_name day_number year_number time Date: day_number month_name year_number time timezone day_name Note that they are distinguishable by checking the first character of the second, third and fourth words... */ if (isdigit(word[1][0])) { /*** type one! ***/ if (! valid_date(word[1], word[2], word[3])) { dprint4(3,"parse_arpa_date failed [bad date: %s/%s/%s] on\n-> %s\n", word[1], word[2], word[3], string); return; /* strange date! */ } strncpy(entry->day, word[1], 3); strncpy(entry->month, word[2], 3); strncpy(entry->year, word[3], 4); strncpy(entry->time, word[4], 10); } else if (isdigit(word[2][0])) { /*** type two! ***/ if (! valid_date(word[2], word[3], word[4])) { dprint4(3,"parse_arpa_date failed [bad date: %s/%s/%s] on\n-> %s\n", word[2], word[3], word[4], string); return; /* strange date! */ } strncpy(entry->day, word[2], 3); strncpy(entry->month, word[3], 3); strncpy(entry->year, word[4], 4); strncpy(entry->time, word[5], 10); } else if (isdigit(word[3][0])) { if (word[4][1] == ':' || word[4][2] == ':') { /*** type three! ***/ if (! valid_date(word[3], word[2], word[5])) { dprint4(3, "parse_arpa_date failed [bad date: %s/%s/%s] on\n-> %s\n", word[3], word[2], word[5], string); return; /* strange date! */ } strncpy(entry->year, word[5], 4); strncpy(entry->time, word[4], 10); } else { /*** type four! ***/ if (! valid_date(word[3], word[2], word[4])) { dprint4(3,"parse_arpa_date failed [bad date: %s/%s/%s] on\n-> %s\n", word[3], word[2], word[4], string); return; /* strange date! */ } strncpy(entry->year, word[4], 4); strncpy(entry->time, word[5], 10); } strncpy(entry->day, word[3], 3); strncpy(entry->month, word[2], 3); } } fix_arpa_address(address) char *address; { /** Given a pure ARPA address, try to make it reasonable. This means that if you have something of the form a@b@b make it a@b. If you have something like a%b%c%b@x make it a%b@x... **/ register int host_count = 0, i; char hosts[MAX_HOPS][2*NLEN]; /* array of machine names */ char *host, *addrptr; /* break down into a list of machine names, checking as we go along */ addrptr = (char *) address; while ((host = get_token(addrptr, "%@", 2)) != NULL) { for (i = 0; i < host_count && ! equal(hosts[i], host); i++) ; if (i == host_count) { strcpy(hosts[host_count++], host); if (host_count == MAX_HOPS) { dprint0(2, "Can't build return address - hit MAX_HOPS (fix_arpa_address)\n"); error("Can't build return address - hit MAX_HOPS limit!"); return(1); } } else host_count = i + 1; addrptr = NULL; } /** rebuild the address.. **/ address[0] = '\0'; for (i = 0; i < host_count; i++) sprintf(address, "%s%s%s", address, address[0] == '\0'? "" : (i == host_count - 1 ? "@" : "%"), hosts[i]); return(0); } figure_out_addressee(buffer, mail_to) char *buffer; char *mail_to; { /** This routine steps through all the addresses in the "To:" list, initially setting it to the first entry (if mail_to is NULL) or, if the user is found (eg "alternatives") to the current "username". Modified to know how to read quoted names... **/ char *address, *bufptr, *strchr(); register int index = 0, index2 = 0; if (equal(mail_to, username)) return; /* can't be better! */ bufptr = (char *) buffer; /* use the string directly */ if (strchr(buffer,'"') != NULL) { /* we have a quoted string */ while (buffer[index] != '"') index++; index++; /* skip the leading quote */ while (buffer[index] != '"' && index < strlen(buffer)) mail_to[index2++] = buffer[index++]; mail_to[index2] = '\0'; } else while ((address = strtok(bufptr, " ,\t\n\r")) != NULL) { if (! okay_address(address, "don't match me!")) { strcpy(mail_to, username); /* it's to YOU! */ return; } else if (strlen(mail_to) == 0) /* it's SOMEthing! */ get_return_name(address, mail_to, FALSE); bufptr = (char *) NULL; /* set to null */ } return; } END-OF-FILE if [ "$filename" != "/dev/null" ] then size=`wc -c < $filename` if [ $size != 15408 ] then echo $filename changed - should be 15408 bytes, not $size bytes fi chmod 644 $filename fi # ---------- file src/input_utils.c ---------- filename="src/input_utils.c" if [ -f $filename ] then echo File \"$filename\" already exists\! Skipping... filename=/dev/null # throw it away else echo extracting file src/input_utils.c... fi cat << 'END-OF-FILE' > $filename /** input_utils.c **/ /** Mindless I/O routines for ELM (C) Copyright 1985 Dave Taylor **/ #include "headers.h" #include <errno.h> extern int errno; /* system error number */ int want_to(question, dflt, echo_answer) char *question, dflt; int echo_answer; { /** Ask 'question' at LINES-2, COLUMNS-40, returning the answer in lower case. If 'echo_answer', then echo answer. 'dflt' is the default answer if <return> is pressed. (Note: 'dflt' is also what will be returned if <return> is pressed!) **/ register char ch, cols; cols = (strlen(question) < 30)? COLUMNS-40 : COLUMNS-50; PutLine3(LINES-3, cols,"%s%c%c", question, dflt, BACKSPACE); fflush(stdout); fflush(stdin); ch = tolower(ReadCh()); if (echo_answer && ch > (char) ' ') { Writechar(ch); fflush(stdout); } return(ch == '\n' || ch == '\r' ? dflt : ch); } int read_number(ch, max) char ch; int max; { /** read a number, where 'ch' is the leading digit! If max < 10 then just return 'ch' **/ char buff[SHORT_SLEN]; int num; if (max < 10) return( (int) ch - '0' ); buff[0] = ch; buff[1] = '\0'; PutLine0(LINES-3, COLUMNS-40,"Set current message to :"); if (optionally_enter(buff, LINES-3, COLUMNS-15, TRUE) == -1) return(current); sscanf(buff,"%d", &num); return(num); } int optionally_enter(string, x, y, append_current) char *string; int x,y, append_current; { /** Display the string on the screen and if RETURN is pressed, return it. Otherwise, allow standard text input, including backspaces and such until RETURN is hit. If "append_current" is set, then leave the default string in place and edit AFTER it...assume 'x,y' is placing us at the beginning of the string... This routine returns zero unless INTERRUPT hit, then it returns -1 and must be treated accordingly. **/ char ch; register index = 0; PutLine1(x,y, "%s", string); CleartoEOLN(); if (! append_current) MoveCursor(x,y); if (cursor_control) transmit_functions(OFF); ch = getchar(); if (ch == '\n' || ch == '\r') { if (cursor_control) transmit_functions(ON); return(0); /* we're done. No change needed */ } CleartoEOLN(); index = (append_current? strlen(string) : 0); if (ch == kill_line) { if (! mail_only) MoveCursor(x,y); CleartoEOLN(); index = 0; } else if (ch != backspace) { Writechar(ch); string[index++] = ch; } else if (index > 0) { index--; Writechar(BACKSPACE); Writechar(' '); Writechar(BACKSPACE); fflush(stdout); } else { Writechar(' '); Writechar(BACKSPACE); fflush(stdout); } do { ch = getchar(); /* the following is converted from a case statement to allow the variable characters (backspace, kill_line and break) to be processed. Case statements in C require constants as labels, so it failed ... */ if (ch == backspace) { if (index > 0) { index--; Writechar(BACKSPACE); Writechar(' '); Writechar(BACKSPACE); fflush(stdout); } else { Writechar(' '); Writechar(BACKSPACE); fflush(stdout); } } else if (ch == '\n' || ch == '\r') { string[index] = '\0'; if (cursor_control) transmit_functions(ON); return(0); } else if (ch == kill_line) { if (mail_only) back_up(index+1); else MoveCursor(x,y); CleartoEOLN(); index = 0; } else if (ch == NULL) { if (cursor_control) transmit_functions(ON); fflush(stdin); /* remove extraneous chars, if any */ string[0] = '\0'; /* clean up string, and... */ return(-1); } else { /* default case */ string[index++] = ch; Writechar(ch); } } while (index < SLEN); string[index] = '\0'; if (cursor_control) transmit_functions(ON); return(0); } int pattern_enter(string, alt_string, x, y, alternate_prompt) char *string, *alt_string, *alternate_prompt; int x,y; { /** This function is functionally similar to the routine optionally-enter, but if the first character pressed is a '/' character, then the alternate prompt and string are used rather than the normal one. This routine returns 1 if alternate was used, 0 if not **/ char ch; register index = 0; PutLine1(x, y, "%s", string); CleartoEOLN(); MoveCursor(x,y); if (cursor_control) transmit_functions(OFF); ch = getchar(); if (ch == '\n' || ch == '\r') { if (cursor_control) transmit_functions(ON); return(0); /* we're done. No change needed */ } if (ch == '/') { PutLine1(x, 0, "%s", alternate_prompt); CleartoEOLN(); (void) optionally_enter(alt_string, x, strlen(alternate_prompt)+1, FALSE); return(1); } CleartoEOLN(); index = 0; if (ch == kill_line) { MoveCursor(x,y); CleartoEOLN(); index = 0; } else if (ch != backspace) { Writechar(ch); string[index++] = ch; } else if (index > 0) { index--; Writechar(BACKSPACE); Writechar(' '); Writechar(BACKSPACE); } else { Writechar(' '); Writechar(BACKSPACE); } do { fflush(stdout); ch = getchar(); /* the following is converted from a case statement to allow the variable characters (backspace, kill_line and break) to be processed. Case statements in C require constants as labels, so it failed ... */ if (ch == backspace) { if (index > 0) { index--; Writechar(BACKSPACE); Writechar(' '); Writechar(BACKSPACE); } else { Writechar(' '); Writechar(BACKSPACE); } } else if (ch == '\n' || ch == '\r') { string[index] = '\0'; if (cursor_control) transmit_functions(ON); return(0); } else if (ch == kill_line) { MoveCursor(x,y); CleartoEOLN(); index = 0; } else if (ch == NULL) { if (cursor_control) transmit_functions(ON); fflush(stdin); /* remove extraneous chars, if any */ string[0] = '\0'; /* clean up string, and... */ return(-1); } else { /* default case */ string[index++] = ch; Writechar(ch); } } while (index < SLEN); string[index] = '\0'; if (cursor_control) transmit_functions(ON); return(0); } back_up(spaces) int spaces; { /** this routine is to replace the goto x,y call for when sending mail without starting the entire "elm" system up... **/ while (spaces--) { Writechar(BACKSPACE); Writechar(' '); Writechar(BACKSPACE); } fflush(stdout); } int GetPrompt() { /** This routine does a read/timeout for a single character. The way that this is determined is that the routine to read a character is called, then the "errno" is checked against EINTR (interrupted call). If they match, this returns NO_OP_COMMAND otherwise it returns the normal command. **/ int ch; if (timeout > 0) { alarm(timeout); errno = 0; /* we actually have to do this. *sigh* */ ch = ReadCh(); if (errno == EINTR) ch = NO_OP_COMMAND; alarm(0); } else ch = ReadCh(); return(ch); } END-OF-FILE if [ "$filename" != "/dev/null" ] then size=`wc -c < $filename` if [ $size != 7235 ] then echo $filename changed - should be 7235 bytes, not $size bytes fi chmod 644 $filename fi echo end of this archive file.... exit 0