Path: seismo!harvard!talcott!panda!sources-request From: sources-request@panda.UUCP Newsgroups: mod.sources Subject: Msg Shar.part.3 Message-ID: <1461@panda.UUCP> Date: 2 Mar 86 13:36:49 GMT Sender: jpn@panda.UUCP Organization: Hewlett-Packard, Colorado Networks Division Lines: 2671 Approved: jpn@panda.UUCP Mod.sources: Volume 4, Issue 7 Submitted by: decvax!hplabs!hpcnou!dat (Dave Taylor) # Msg Shar part 3 of 7 # Shell Archive created by hpcnou!dat at Wed Feb 26 15:56:06 1986 # 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 # This archive contains; # src/addr_utils.c src/alias.c src/aliasdb.c src/aliaslib.c # src/args.c src/curses.c src/date.c src/delete.c # src/encode.c src/file.c if [ ! -d src ] then echo creating directory src mkdir src fi # ---------- file src/addr_utils.c ---------- if [ -f src/addr_utils.c ] then echo File 'src/addr_utils.c' already exists\! exit 1 fi echo extracting file src/addr_utils.c... cat << 'END-OF-FILE' > src/addr_utils.c /** addr_utils.c **/ /** This file contains addressing utilities (C) Copyright 1986 Dave Taylor **/ #include "headers.h" #include #include #include #ifdef BSD #undef tolower #endif char *shift_lower(), *get_alias_address(), *get_token(); 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; dprint1("talk-to(sitename='%s')\n", sitename); sysname = talk_to_sys; if (sysname == NULL) { dprint0("\tWarning: talk_to_sys is currently set to NULL!\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; dprint1("remove_domains(host='%s')\n", host); 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]; dprint3("add_site(buffer='%s', site='%s', lastsite='%s')\n", buffer, site, lastsite); 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); dprint2("get_address_from(prefix='%s', line='%s', )\n", prefix, 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; dprint1("translate_return(addr='%s', )\n", addr); 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'; dprint1("\treturning address: '%s'\n", ret_addr); } 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]; dprint1("build_address(to='%s', )\n", to); 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"); leave(1); } else { dprint1("-- Unknown address '%s'\n", buffer); sprintf(buffer, "'%s' is an unknown address. Replace with: ", word); word[0] = '\0'; if (mail_only) printf("%s", buffer); else PutLine(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); 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[SLEN], timebuff[SLEN]; int eight_fields = 0; dprint1("real_from(buffer='%s', )\n", buffer); entry->year[0] = '\0'; junk[0] = '\0'; /* From */ sscanf(buffer, "%*s %*s %*s %*s %*s %s %*s %s", timebuff, junk); if (timebuff[1] != ':' && timebuff[2] != ':') 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') 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, entry->from, entry->dayname, entry->month, entry->day, entry->time, entry->year); else sscanf(buffer, "%s %s %s %s %s %s %s", junk, entry->from, entry->dayname, entry->month, entry->day, entry->time, entry->year); 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]; dprint1("forwarded(buffer='%s', )\n", buffer); machine[0] = '\0'; sscanf(buffer, "%*s %s %s %s %s %s %s %*s %*s %s", entry->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", entry->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", entry->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, entry->from); strncpy(entry->from, buff, SLEN); } 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 or From: hpcnou!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) **/ char temp_buffer[SLEN], *temp; register int i, j = 0; dprint1("parse_arpa_from(buffer='%s', )\n", buffer); 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) strcpy(newfrom, temp); } } 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, *strtok(); int words = 0; dprint1("parse_arpa_date(string='%s', )\n", string); 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! */ 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])) 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])) 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])) return; strncpy(entry->year, word[5], 4); strncpy(entry->time, word[4], 10); } else { /*** type four! ***/ if (! valid_date(word[3], word[2], word[4])) return; 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; dprint1("fix_arpa_address(%s)\n", address); /* 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) { 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]); dprint1("\tmodified to address '%s'\n", address); return(0); } END-OF-FILE size=`wc -c < src/addr_utils.c` if [ $size != 13730 ] then echo Warning: src/addr_utils.c changed - should be 13730 bytes, not $size bytes fi chmod 644 src/addr_utils.c # ---------- file src/alias.c ---------- if [ -f src/alias.c ] then echo File 'src/alias.c' already exists\! exit 1 fi echo extracting file src/alias.c... cat << 'END-OF-FILE' > src/alias.c /** alias.c **/ /** This file contains alias stuff (C) Copyright 1986 Dave Taylor **/ #include "headers.h" char *expand_group(), *get_alias_address(), *expand_system(), *get_token(); read_alias_files() { /** read the system and user alias files, if present. Set the flags 'systemfiles' and 'userfiles' accordingly. **/ char fname[SLEN]; int hash; dprint0("read_alias_files()\n"); if ((hash = open(system_hash_file, O_RDONLY)) == -1) goto user; read(hash, system_hash_table, sizeof system_hash_table); close(hash); /* and data file opened.. */ if ((system_data = open(system_data_file, O_RDONLY)) == -1) goto user; system_files++; /* got the system files! */ user: sprintf(fname, "%s/.alias_hash", home); if ((hash = open(fname, O_RDONLY)) == -1) return; read(hash, user_hash_table, sizeof user_hash_table); close(hash); sprintf(fname, "%s/.alias_data", home); if ((user_data = open(fname, O_RDONLY)) == -1) return; user_files++; /* got user files too! */ } int add_alias() { /** add an alias to the user alias text file. Return zero if alias not added in actuality **/ char name[SLEN], *address, address1[LONG_STRING]; char comment[SLEN]; dprint0("add_alias()\n"); PutLine(LINES-2,0,"Enter alias name: "); CleartoEOLN(); Raw(OFF); gets(name, 20); Raw(ON); if ((address = (char *) get_alias_address(name, 0, 0)) != NULL) { if (address[0] == '!') { address[0] = ' '; error1("already a group with that name:%s", address); } else error1("already an alias for that: %s", address); return(0); } PutLine(LINES-2,0,"Full name for %s: ", name); CleartoEOLN(); Raw(OFF); gets(comment,SLEN); Raw(ON); PutLine(LINES-2,0,"Enter address for %s: ",name); CleartoEOLN(); Raw(OFF); gets(address1,LONG_SLEN); Raw(ON); add_to_alias_text(name, comment, address1); return(1); } int add_current_alias() { /** alias the current message to the specified name and add it to the alias text file, for processing as the user leaves the program. Returns non-zero iff alias actually added to file **/ char name[SLEN], address1[LONG_STRING], *address; char comment[SLEN]; dprint0("add_current_alias()\n"); if (current == 0) { error("No message to alias to!"); return(0); } PutLine(LINES-2,0,"Current message address aliased to: "); CleartoEOLN(); Raw(OFF); gets(name, 20); Raw(ON); if ((address = (char *) get_alias_address(name, 0, 0)) != NULL) { if (address[1] == '!') { address[0] = ' '; error1("already a group with that name:%s", address); } else error1("already an alias for that: %s", address); return(0); } PutLine(LINES-2,0,"Full name of %s: ", name); CleartoEOLN(); Raw(OFF); gets(comment, 40); Raw(ON); get_return(address1); /* grab the return address of this message */ optimize_return(address1); PutLine(LINES-2,0,"%s (%s) = %s", comment, name, address1); CleartoEOLN(); add_to_alias_text(name, comment, address1); return(1); } add_to_alias_text(name, comment, address) char *name, *comment, *address; { /** add the data to the user alias text file... **/ FILE *file; char fname[SLEN]; dprint3("add_to_alias_text(name='%s', comment='%s', address='%s')\n", name, comment, address); sprintf(fname,"%s/.alias_text", home); if ((file = fopen(fname, "a")) == NULL) return(error1("couldn't open %s to add new alias!", fname)); fprintf(file,"%s : %s : %s\n", name, comment, address); fclose(file); chown(fname, userid, getgid()); return(0); } show_alias_menu() { MoveCursor(LINES-7,0); CleartoEOLN(); MoveCursor(LINES-6,0); CleartoEOLN(); MoveCursor(LINES-5,0); CleartoEOLN(); PutLine(LINES-7,COLUMNS-45, "Alias commands"); Centerline(LINES-5, "A)lias current msg, Check a P)erson or S)ystem, M)ake new alias, or R)eturn" ); } alias() { /** work with alias commands... **/ char name[NLEN], *address, ch, buffer[SLEN]; int newaliases = 0; dprint0("alias()\n"); if (mini_menu) show_alias_menu(); define_softkeys(ALIAS); while (1) { PutLine(LINES-3,0,"Alias: "); CleartoEOLN(); ch = ReadCh(); MoveCursor(LINES-1,0); CleartoEOLN(); switch (tolower(ch)) { case 'a': newaliases += add_current_alias(); break; case 'm': newaliases += add_alias(); break; case RETURN: case 'q': case 'x': case 'r': if (newaliases) install_aliases(); return; case 'p': if (newaliases) error("Warning: new aliases not installed yet!"); PutLine(LINES-2,0,"Check for person: "); CleartoEOLN(); Raw(OFF); gets(name,NLEN); Raw(ON); if ((address = get_alias_address(name, 0, 0))!=NULL) { if (address[0] == '!') { address[0] = ' '; PutLine(LINES-1,0,"Group alias:%-65.65s", address); CleartoEOLN(); } else PutLine(LINES-1,0,"Aliased addresss: %-65.65s", address); } else error("not found"); break; case 's': PutLine(LINES-2,0,"Check for system: "); CleartoEOS(); Raw(OFF); gets(name,NLEN); Raw(ON); sprintf(buffer, "(user)@%s", name); address = (char *) expand_system(buffer, 0, FALSE); if (strlen(address) > strlen(name) + 7) PutLine(LINES-1,0,"Address is: %.65s", address); else error1("couldn't expand system '%s'", name); break; case '@': PutLine(LINES-2,0,"Fully expand alias: "); CleartoEOS(); Raw(OFF); gets(name,NLEN); Raw(ON); if ((address = get_alias_address(name, 1, 0)) != NULL) { ClearScreen(); PutLine(3,0,"Aliased address:\n\r%s", address); PutLine(LINES-1,0,"Press to continue: "); (void) getchar(); } else error("not found"); break; default : error("Invalid input!"); } } } install_aliases() { /** run the 'newalias' program and install the newly added aliases before going back to the main program! **/ dprint0("install_aliases()\n"); error("Adding new aliases..."); if (system_call(newalias, SH) == 0) { error("Re-reading the database in..."); read_alias_files(); set_error("New aliases installed successfully"); } else set_error("'newalias' failed. Please check alias_text"); } END-OF-FILE size=`wc -c < src/alias.c` if [ $size != 6455 ] then echo Warning: src/alias.c changed - should be 6455 bytes, not $size bytes fi chmod 644 src/alias.c # ---------- file src/aliasdb.c ---------- if [ -f src/aliasdb.c ] then echo File 'src/aliasdb.c' already exists\! exit 1 fi echo extracting file src/aliasdb.c... cat << 'END-OF-FILE' > src/aliasdb.c /** aliasdb.c **/ /** Alias database files... (C) Copyright 1986 Dave Taylor **/ #include "headers.h" #include #include char *shift_lower(); findnode(name, display_error) char *name; int display_error; { /** break 'name' into machine!user or user@machine and then see if you can find 'machine' in the path database.. If so, return name as the expanded address. If not, return what was given to us! If display_error, then do so... **/ char address[SLEN]; dprint2("findnode(name='%s', display_error=%s)\n", name, display_error? "ON" : "OFF"); if (strlen(name) == 0) return; if (expand_site(name, address) == -1) { if (display_error && name[0] != '!') { error1("Warning: couldn't expand %s...", name); sleep(1); } } else strcpy(name, address); return; } int expand_site(cryptic, expanded) char *cryptic, *expanded; { /** Given an address of the form 'xyz@site' or 'site!xyz' return an address of the form with 'xyz' embedded according to the path database entry. Note that 'xyz' can be eiher a simple address (as in "joe") or a complex address (as in "joe%xerox.parc@Xerox.ARPA")! 0 = found, -1 return means unknown site code **/ char name[VERY_LONG_STRING], sitename[VERY_LONG_STRING], address[VERY_LONG_STRING], temp[VERY_LONG_STRING]; register int i = 0, j = 0, domain_name; dprint1("expand_site(cryptic='%s', )\n", cryptic); /** break down **/ while (cryptic[i] != '@' && cryptic[i] != '!' && cryptic[i] != '\0') sitename[j++] = cryptic[i++]; sitename[j++] = '\0'; j = 0; if (cryptic[i] == '\0') return(-1); /* nothing to expand! */ domain_name = (cryptic[i] == '@'); i++; while (cryptic[i] != '\0') name[j++] = cryptic[i++]; name[j] = '\0'; if (domain_name) { strcpy(temp, name); strcpy(name, sitename); strcpy(sitename, temp); } if (talk_to(sitename)) { sprintf(expanded,"%s!%s", sitename, name); return(0); } if (size_of_pathfd > 0) { if (binary_search(sitename, address) == -1) return(-1); } else { sprintf(expanded,"%s!%s", sitename, name); return(0); } /* otherwise... */ sprintf(expanded, address, name); return(0); } int binary_search(name, address) char *name, *address; { /* binary search file for name. Return 0 if found, -1 if not */ char machine[20]; register long first = 0, last, middle; register int compare; dprint1("binary_search(name='%s',
)\n", name); address[0] = '\0'; last = size_of_pathfd; do { middle = (long) ((first+last) / 2); get_entry(machine, address, pathfd, middle); compare = strcmp(name, machine); if (compare < 0) last = middle - 1; else if (compare == 0) return(0); else /* greater */ first = middle + 1; } while (abs(last) - abs(first) > FIND_DELTA); return(-1); } get_entry(machine, address, fileid, offset) char *machine, *address; FILE *fileid; long offset; { /** get entry...return machine and address immediately following given offset in fileid. **/ fseek(fileid, offset, 0L); /* read until we hit an end-of-line */ while (getc(fileid) != '\n') ; fscanf(fileid, "%s\t%s", machine, address); } init_findnode() { /** Initialize the FILE and 'size_of_file' values for the findnode procedure **/ struct stat buffer; dprint0("init_findnode()\n"); if (stat(pathfile, &buffer) == -1) { dprint1("\tWarning: No pathalias file '%s' found!\n", pathfile); size_of_pathfd = 0; return; } size_of_pathfd = buffer.st_size; if ((pathfd = fopen(pathfile,"r")) == NULL) { dprint1("\tFound pathalias file '%s' but couldn't open to read\n", pathfile); size_of_pathfd = 0; } else dprint1("\tOpened file '%s' as path alias database\n", pathfile); } END-OF-FILE size=`wc -c < src/aliasdb.c` if [ $size != 3888 ] then echo Warning: src/aliasdb.c changed - should be 3888 bytes, not $size bytes fi chmod 644 src/aliasdb.c # ---------- file src/aliaslib.c ---------- if [ -f src/aliaslib.c ] then echo File 'src/aliaslib.c' already exists\! exit 1 fi echo extracting file src/aliaslib.c... cat << 'END-OF-FILE' > src/aliaslib.c /** 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(); 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; dprint3("get_alias_address(name='%s', mailing=%s, depth=%d)\n", name, mailing? "ON" : "OFF", depth); 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( (char *) expand_group(buffer, depth)); else return( (char *) expand_system(buffer, depth, TRUE)); } 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( (char *) expand_group(buffer, depth)); else return( (char *) expand_system(buffer, depth, TRUE)); } return( (char *) NULL); } char *expand_system(buffer, depth, show_errors) char *buffer; int depth, 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("expand_system(buffer='%s', show_errors=%s)\n", buffer, show_errors? "ON" : "OFF"); 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; dprint2("expand_group(members='%s', depth=%d)\n", members, depth); strcpy(buf, members); /* parameter safety! */ 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)) { 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) exit(printf("Bad alias name: %s. Too long.\n", word)); 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 size=`wc -c < src/aliaslib.c` if [ $size != 4347 ] then echo Warning: src/aliaslib.c changed - should be 4347 bytes, not $size bytes fi chmod 644 src/aliaslib.c # ---------- file src/args.c ---------- if [ -f src/args.c ] then echo File 'src/args.c' already exists\! exit 1 fi echo extracting file src/args.c... cat << 'END-OF-FILE' > src/args.c /** args.c **/ /** starting argument parsing routines for MSG system... (C) Copyright 1986 Dave Taylor **/ #include "headers.h" #define DONE 0 #define ERROR -1 char *optional_arg; /* optional argument as we go */ int opt_index; /* argnum + 1 when we leave */ parse_arguments(argc, argv, to_whom) int argc; char *argv[], *to_whom; { /** set flags according to what was given to program. If we are fed a name or series of names, put them into the 'to_whom' buffer and set "mail_only" to TRUE **/ register char c = 0; infile[0] = '\0'; to_whom[0] = '\0'; batch_subject[0] = '\0'; while ((c = get_options(argc, argv, "?cdf:hkmsS:z")) > 0) { switch (c) { case 'c' : check_only++; break; case 'd' : debug++; break; case 'f' : strcpy(infile, optional_arg); mbox_specified = 2; break; case '?' : case 'h' : args_help(); case 'k' : hp_terminal++; break; case 'm' : mini_menu = 0; break; case 's' : hp_softkeys++; break; case 'S' : strcpy(batch_subject, optional_arg); break; case 'z' : check_mailfile_size(); break; } } if (c == ERROR) { printf("Usage: msg [cdhkmsz] [-f file] [-S subject] \n\n"); args_help(); } if (opt_index < argc) while (opt_index < argc) { sprintf(to_whom, "%s%s%s", to_whom, to_whom[0] != '\0'? " " : "", argv[opt_index]); mail_only++; opt_index++; } if (strlen(batch_subject) > 0 && ! mail_only) exit(printf( "\n\rDon't understand specifying a subject and no-one to send to!\n\r")); if (! isatty(fileno(stdin)) && strlen(batch_subject) == 0) strcpy(batch_subject, DEFAULT_BATCH_SUBJECT); } args_help() { /** print out possible starting arguments... **/ printf("\nPossible Starting Arguments for MSG program:\n\n"); printf("\targ\t\t\tMeaning\n"); printf("\t -c \t\tCheckalias - check the given aliases only\n"); printf("\t -d \t\tDebug - turn on debug mode (output to file)\n"); printf("\t -f \t\tFile - read file (specified) rather than mailbox\n"); printf("\t -h \t\tHelp - give this list of options\n"); printf("\t -k \t\tKeypad - force knowledge of HP terminal keyboard\n"); printf("\t -m \t\tMenu - Turn off menu, using more of the screen\n"); printf("\t -s \t\tSoftkeys - enable use of softkeys\n"); printf("\t -z \t\tZero - don't enter MSG if no mail is pending\n"); printf("\n"); printf("\t -S \t\tSubject - for batchmailing, combined with address\n"); printf("\n"); exit(1); } int _indx = 1, _argnum = 1; int get_options(argc, argv, options) int argc; char *argv[], *options; { /** Returns the character argument next, and optionally instantiates "argument" to the argument associated with the particular option **/ char *word, *strchr(); if (_indx >= strlen(argv[_argnum])) { _argnum++; _indx = 1; /* zeroeth char is '-' */ } if (_argnum >= argc) { opt_index = argc; return(DONE); } if (argv[_argnum][0] != '-') { opt_index = _argnum; return(DONE); } word = strchr(options, argv[_argnum][_indx++]); if (strlen(word) == 0) return(ERROR); if (word[1] == ':') { /** Two possibilities - either tailing end of this argument or the next argument in the list **/ if (_indx < strlen(argv[_argnum])) { /* first possibility */ optional_arg = (char *) (argv[_argnum] + _indx); _argnum++; _indx = 1; } else { /* second choice */ if (++_argnum >= argc) return(ERROR); /* no argument!! */ optional_arg = (char *) argv[_argnum++]; _indx = 1; } } return((int) word[0]); } END-OF-FILE size=`wc -c < src/args.c` if [ $size != 3662 ] then echo Warning: src/args.c changed - should be 3662 bytes, not $size bytes fi chmod 644 src/args.c # ---------- file src/curses.c ---------- if [ -f src/curses.c ] then echo File 'src/curses.c' already exists\! exit 1 fi echo extracting file src/curses.c... cat << 'END-OF-FILE' > src/curses.c /** curses.c **/ /** This library gives programs the ability to easily access the termcap information and write screen oriented and raw input programs. The routines can be called as needed, except that to use the cursor / screen routines there must be a call to InitScreen() first. The 'Raw' input routine can be used independently, however. Modified 2/86 to work (hopefully) on Berkeley systems. If there are any problems with BSD Unix, please report them to the author at hpcnoe!dat@HPLABS (fixed, if possible!) (C) Copyright 1985 Dave Taylor, HP Colorado Networks **/ #include #ifdef RAWMODE # ifdef BSD # include # else # include # endif #endif #include #ifdef BSD #undef tolower #endif #include "curses.h" #ifdef BSD # include "/usr/include/curses.h" /* don't ask! */ #endif #ifdef RAWMODE # define TTYIN 0 #endif extern int debug; #ifdef RAWMODE # ifndef BSD struct termio _raw_tty, _original_tty; # endif static int _inraw = 0; /* are we IN rawmode? */ #endif static int _intransmit; /* are we transmitting keys? */ static char *_clearscreen, *_moveto, *_up, *_down, *_right, *_left, *_setbold, *_clearbold, *_setunderline, *_clearunderline, *_sethalfbright, *_clearhalfbright, *_setinverse, *_clearinverse, *_cleartoeoln, *_cleartoeos, *_transmit_on, *_transmit_off; static int _lines, _columns; static char _terminal[1024]; /* Storage for terminal entry */ static char _capabilities[256]; /* String for cursor motion */ static char *ptr = _capabilities; /* for buffering */ int outchar(); /* char output for tputs */ InitScreen() { /* Set up all this fun stuff: returns zero if all okay, or; -1 indicating no terminal name associated with this shell, -2..-n No termcap for this terminal type known */ int tgetent(), /* get termcap entry */ error; char *tgetstr(), /* Get termcap capability */ termname[40]; if (strcpy(termname, getenv("TERM")) == NULL) return(-1); if ((error = tgetent(_terminal, termname)) != 1) return(error-2); /* load in all those pesky values */ _clearscreen = tgetstr("cl", &ptr); _moveto = tgetstr("cm", &ptr); _up = tgetstr("up", &ptr); _down = tgetstr("do", &ptr); _right = tgetstr("nd", &ptr); _left = tgetstr("bs", &ptr); _setbold = tgetstr("so", &ptr); _clearbold = tgetstr("se", &ptr); _setunderline = tgetstr("us", &ptr); _clearunderline = tgetstr("ue", &ptr); _setinverse = tgetstr("so", &ptr); _clearinverse = tgetstr("se", &ptr); _sethalfbright = tgetstr("hs", &ptr); _clearhalfbright = tgetstr("he", &ptr); _cleartoeoln = tgetstr("ce", &ptr); _cleartoeos = tgetstr("cd", &ptr); _lines = tgetnum("li"); _columns = tgetnum("co"); _transmit_on = tgetstr("ks", &ptr); _transmit_off = tgetstr("ke", &ptr); if (!_left) { _left = ptr; *ptr++ = '\b'; *ptr++ = '\0'; } #ifdef BSD initscr(); /* initalize curses too! */ #endif return(0); } char *return_value_of(termcap_label) char *termcap_label; { /** this will return the string kept by termcap for the specified capability **/ char *tgetstr(); /* Get termcap capability */ return( (char *) tgetstr(termcap_label, &ptr)); } transmit_functions(newstate) int newstate; { /** turn function key transmission to ON | OFF **/ if (newstate != _intransmit) { _intransmit = ! _intransmit; if (newstate == ON) tputs(_transmit_on, 1, outchar); else tputs(_transmit_off, 1, outchar); fflush(stdout); /* clear the output buffer */ } } /****** now into the 'meat' of the routines...the cursor stuff ******/ ScreenSize(lines, columns) int *lines, *columns; { /** returns the number of lines and columns on the display. **/ *lines = _lines - 1; /* assume index from zero */ *columns = _columns; } ClearScreen() { /* clear the screen: returns -1 if not capable */ if (!_clearscreen) return(-1); tputs(_clearscreen, 1, outchar); fflush(stdout); /* clear the output buffer */ return(0); } MoveCursor(row, col) int row, col; { /** move cursor to the specified row column on the screen. 0,0 is the top left! **/ char *tgoto(); char *stuff; if (!_moveto) return(-1); stuff = (char *) tgoto(_moveto, col, row); tputs(stuff, 1, outchar); fflush(stdout); return(0); } CursorUp() { /** move the cursor up one line **/ if (!_up) return(-1); tputs(_up, 1, outchar); fflush(stdout); return(0); } CursorDown() { /** move the cursor down one line **/ if (!_down) return(-1); tputs(_down, 1, outchar); fflush(stdout); return(0); } CursorLeft() { /** move the cursor one character to the left **/ if (!_left) return(-1); tputs(_left, 1, outchar); fflush(stdout); return(0); } CursorRight() { /** move the cursor one character to the right (nondestructive) **/ if (!_right) return(-1); tputs(_right, 1, outchar); fflush(stdout); return(0); } StartBold() { /** start boldface/standout mode **/ if (!_setbold) return(-1); tputs(_setbold, 1, outchar); fflush(stdout); return(0); } EndBold() { /** compliment of startbold **/ if (!_clearbold) return(-1); tputs(_clearbold, 1, outchar); fflush(stdout); return(0); } StartUnderline() { /** start underline mode **/ if (!_setunderline) return(-1); tputs(_setunderline, 1, outchar); fflush(stdout); return(0); } EndUnderline() { /** the compliment of start underline mode **/ if (!_clearunderline) return(-1); tputs(_clearunderline, 1, outchar); fflush(stdout); return(0); } StartHalfbright() { /** start half intensity mode **/ if (!_sethalfbright) return(-1); tputs(_sethalfbright, 1, outchar); fflush(stdout); return(0); } EndHalfbright() { /** compliment of starthalfbright **/ if (!_clearhalfbright) return(-1); tputs(_clearhalfbright, 1, outchar); fflush(stdout); return(0); } StartInverse() { /** set inverse video mode **/ if (!_setinverse) return(-1); tputs(_setinverse, 1, outchar); fflush(stdout); return(0); } EndInverse() { /** compliment of startinverse **/ if (!_clearinverse) return(-1); tputs(_clearinverse, 1, outchar); fflush(stdout); return(0); } PutLine(x, y, line, args) int x,y; char *line; int args; { /** write line at location x,y **/ MoveCursor(x,y); _doprnt(line, &args, stdout); fflush(stdout); /* ensure it actually gets out! */ } CleartoEOLN() { /** clear to end of line **/ if (!_cleartoeoln) return(-1); tputs(_cleartoeoln, 1, outchar); fflush(stdout); /* clear the output buffer */ return(0); } CleartoEOS() { /** clear to end of screen **/ if (!_cleartoeos) return(-1); tputs(_cleartoeos, 1, outchar); fflush(stdout); /* clear the output buffer */ return(0); } #ifdef RAWMODE Raw(state) int state; { /** state is either ON or OFF, as indicated by call **/ if (state == OFF && _inraw) { #ifdef BSD echo(); nocrmode(); #else (void) ioctl(TTYIN, TCSETAW, &_original_tty); #endif _inraw = 0; } else if (state == ON && ! _inraw) { #ifdef BSD noecho(); crmode(); #else (void) ioctl(TTYIN, TCGETA, &_original_tty); /** current setting **/ (void) ioctl(TTYIN, TCGETA, &_raw_tty); /** again! **/ _raw_tty.c_iflag &= ~(INLCR | ICRNL |BRKINT); _raw_tty.c_iflag |= IXON; _raw_tty.c_oflag |= OPOST; _raw_tty.c_oflag &= ~(OLCUC | ONLCR | OCRNL | ONOCR | ONLRET); _raw_tty.c_lflag &= ~(ICANON | ECHO); _raw_tty.c_cc[VMIN] = '\01'; _raw_tty.c_cc[VTIME] = '\0'; (void) ioctl(TTYIN, TCSETAW, &_raw_tty); #endif _inraw = 1; } } int ReadCh() { /** read a character with Raw mode set! **/ register int result; char ch; result = read(0, &ch, 1); return(result == 0? EOF : ch); } #endif outchar(c) char c; { /** output the given character. From tputs... **/ /** Note: this CANNOT be a macro! **/ putc(c, stdout); } END-OF-FILE size=`wc -c < src/curses.c` if [ $size != 8965 ] then echo Warning: src/curses.c changed - should be 8965 bytes, not $size bytes fi chmod 644 src/curses.c # ---------- file src/date.c ---------- if [ -f src/date.c ] then echo File 'src/date.c' already exists\! exit 1 fi echo extracting file src/date.c... cat << 'END-OF-FILE' > src/date.c /** date.c **/ /** return the current date and time in a readable format! **/ /** also returns an ARPA RFC-822 format date... **/ /** (C) Copyright 1985, Dave Taylor **/ #include "headers.h" #ifdef BSD # include #else # include #endif #include #ifdef BSD #undef toupper #endif #define MONTHS_IN_YEAR 11 /* 0-11 equals 12 months! */ #define FEB 1 /* 0 = January */ #define DAYS_IN_LEAP_FEB 29 /* leap year only */ #define ampm(n) (n > 12? n - 12 : n) #define am_or_pm(n) (n > 11? (n > 23? "am" : "pm") : "am") #define leapyear(year) ((year % 4 == 0) && (year % 100 != 0)) char *dayname[] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "" }; char *monname[] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", ""}; char *arpa_dayname[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "" }; char *arpa_monname[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", ""}; int days_in_month[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, -1}; #ifdef BSD char *tzname(); #else extern char *tzname[]; #endif char *get_date() { /** return the date in the format exemplified by; Thursday, April 18th 1985 at 8:35 pm **/ static char buffer[SLEN]; /* static character buffer */ struct tm *the_time, /* Time structure, see CTIME(3C) */ *localtime(); char *suffix(); /* digit suffix for date */ long junk; /* time in seconds.... */ dprint0("get_date()\n"); junk = time(0); /* this must be here for it to work! */ the_time = localtime(&junk); sprintf(buffer, "%s, %s %d%s %d at %d:%02d %s", dayname[the_time->tm_wday], /* weekday */ monname[the_time->tm_mon], /* month */ the_time->tm_mday, /* day */ suffix(the_time->tm_mday), /* suffix */ the_time->tm_year + 1900, /* year */ ampm(the_time->tm_hour), /* hour */ the_time->tm_min, /* minute */ ((the_time->tm_hour == 12 || the_time->tm_hour == 24) && the_time->tm_min == 0) ? (the_time->tm_hour == 12? "noon" : "midnight") : am_or_pm(the_time->tm_hour)); /* am | pm */ return( (char *) buffer); } char *suffix(day) int day; { /** this routine returns the suffix appropriate for the specified number to make it an ordinal number. ie, if given '1' it would return 'st', and '2' => 'nd' **/ static char buffer[10]; register int digit; digit = day % 10; if (digit == 0 || digit > 3) strcpy(buffer,"th"); else if (digit == 1) strcpy(buffer,"st"); else if (digit == 2) strcpy(buffer, "nd"); else strcpy(buffer, "rd"); return( (char *) buffer); } char *get_arpa_date() { /** returns an ARPA standard date. The format for the date according to DARPA document RFC-822 is exemplified by; Mon, 12 Aug 85 6:29:08 MST **/ static char buffer[SLEN]; /* static character buffer */ struct tm *the_time, /* Time structure, see CTIME(3C) */ *localtime(); long junk; /* time in seconds.... */ dprint0("get_arpa_date()\n"); junk = time(0); /* this must be here for it to work! */ the_time = localtime(&junk); sprintf(buffer, "%s, %d %s %d %d:%02d:%02d %s", arpa_dayname[the_time->tm_wday], the_time->tm_mday % 32, arpa_monname[the_time->tm_mon], the_time->tm_year % 100, the_time->tm_hour % 24, the_time->tm_min % 61, the_time->tm_sec % 61, #ifdef BSD tzname()); #else tzname[the_time->tm_isdst]); #endif return( (char *) buffer); } char *full_month(month) char *month; { /** Given a three letter month abbreviation, return the full name of the month. If can't figure it out, just return the given argument. **/ char name[4]; register int i; /** ensure name in correct case... **/ strncpy(name, shift_lower(month), 3); name[0] = toupper(name[0]); /** now simply step through arpa_monname table to find a match **/ for (i=0; i < 12; i++) if (strncmp(name, arpa_monname[i], 3) == 0) return((char *) monname[i]); return( (char *) month); } days_ahead(days, buffer) int days; char *buffer; { /** return in buffer the date (Day, Mon Day, Year) of the date 'days' days after today. **/ struct tm *the_time, /* Time structure, see CTIME(3C) */ *localtime(); long junk; /* time in seconds.... */ dprint1("days_ahead(days=%d)\n", days); junk = time(0); /* this must be here for it to work! */ the_time = localtime(&junk); /* increment the day of the week */ the_time->tm_wday = (the_time->tm_wday + days) % 7; /* the day of the month... */ the_time->tm_mday += days; if (the_time->tm_mday > days_in_month[the_time->tm_mon]) { if (the_time->tm_mon == FEB && leapyear(the_time->tm_year)) { if (the_time->tm_mday > DAYS_IN_LEAP_FEB) { the_time->tm_mday -= days_in_month[the_time->tm_mon]; the_time->tm_mon += 1; } } else { the_time->tm_mday -= days_in_month[the_time->tm_mon]; the_time->tm_mon += 1; } } /* check the month of the year */ if (the_time->tm_mon > MONTHS_IN_YEAR) { the_time->tm_mon -= MONTHS_IN_YEAR; the_time->tm_year += 1; } /* now, finally, build the actual date string */ sprintf(buffer, "%s, %d %s %d", arpa_dayname[the_time->tm_wday], the_time->tm_mday % 32, arpa_monname[the_time->tm_mon], the_time->tm_year % 100); } int valid_date(day, mon, year) char *day, *mon, *year; { /** validate the given date - returns TRUE iff the date handed is reasonable and valid. **/ register int daynum, yearnum; dprint3("valid_date(day='%s', month='%s', year='%s')\n", day, mon, year); daynum = atoi(day); yearnum = atoi(year); if (daynum < 1 || daynum > 31) return(0); if (yearnum < 1 || (yearnum > 100 && yearnum < 1900) || yearnum > 2000) return(0); return(1); } fix_date(entry) struct header_rec *entry; { /** This routine will 'fix' the date entry for the specified message. This consists of 1) adjusting the year to 0-99 and 2) altering time from HH:MM:SS to HH:MM am|pm **/ dprint3("fix_date(month='%s', day='%s', year='%s')\n", entry->month, entry->day, entry->year); if (atoi(entry->year) > 99) sprintf(entry->year,"%d", atoi(entry->year) - 1900); fix_time(entry->time); } fix_time(timestring) char *timestring; { /** Timestring in format HH:MM:SS (24 hour time). This routine will fix it to display as: HH:MM [am|pm] **/ int hour, minute; dprint1("fix_time(string='%s')\n", timestring); sscanf(timestring, "%d:%d", &hour, &minute); if (hour < 1 || hour == 24) sprintf(timestring, "12:%2d (midnight)", minute); else if (hour < 12) sprintf(timestring, "%d:%2.2d am", hour, minute); else if (hour == 12) sprintf(timestring, "%d:%2.2d (noon)", hour, minute); else if (hour < 24) sprintf(timestring, "%d:%2.2d pm", hour-12, minute); } #ifdef BSD char *tzname() { /** Return the name of the timezone (three letters) by plowing about in the various time structures on the Berkeley systems. This is a pretty grungy routine, actually! **/ struct timeval *current_time; struct timezone *time_zone; char *timezone(); gettimeofday(current_time, time_zone); return (timezone(time_zone->tz_minuteswest, time_zone->tz_dsttime)); } #endif END-OF-FILE size=`wc -c < src/date.c` if [ $size != 7441 ] then echo Warning: src/date.c changed - should be 7441 bytes, not $size bytes fi chmod 644 src/date.c # ---------- file src/delete.c ---------- if [ -f src/delete.c ] then echo File 'src/delete.c' already exists\! exit 1 fi echo extracting file src/delete.c... cat << 'END-OF-FILE' > src/delete.c /** delete.c **/ /** Delete or undelete files: just set flag in header record! (C) Copyright 1985 Dave Taylor **/ #include "headers.h" delete(real_del) int real_del; { /** Delete current message. If real-del is false, then we're actually requested to toggle the state of the current message... **/ dprint1("delete(real_del=%s)\n", real_del? "ON" : "OFF"); if (real_del) header_table[current-1].delete = 1; else header_table[current-1].delete = ! header_table[current-1].delete; show_msg_status(current-1); } undelete() { /** clear the deleted message flag **/ dprint0("undelete()\n"); header_table[current-1].delete = 0; show_msg_status(current-1); } show_delete_flags() { /** display page of headers (10) if present. First check to ensure that header_page is in bounds, fixing silently if not **/ register int first = 0, last = 0, line = 4; dprint0("show_delete_flags()\n"); (void) fix_header_page(); /** compute last header to display **/ first = header_page*headers_per_page; last = first + (headers_per_page - 1); if (last > message_count) last = message_count; /** okay, now let's show the stuff **/ while (first <= last) { MoveCursor(line++,7); if (header_table[first].delete) putchar('*'); else putchar(' '); first++; } } show_msg_status(msg) int msg; { /** show the status of the current message only. **/ register int line; dprint1("show_msg_status(msg=%d)\n", msg); line = (msg % headers_per_page) + 4; MoveCursor(line,7); putchar( header_table[msg].delete? '*' : ' '); } END-OF-FILE size=`wc -c < src/delete.c` if [ $size != 1591 ] then echo Warning: src/delete.c changed - should be 1591 bytes, not $size bytes fi chmod 644 src/delete.c # ---------- file src/encode.c ---------- if [ -f src/encode.c ] then echo File 'src/encode.c' already exists\! exit 1 fi echo extracting file src/encode.c... cat << 'END-OF-FILE' > src/encode.c /** encode.c **/ /** This is a heavily mangled version of the 'cypher' program written by person or persons unknown. (C) Copyright 1986, Dave Taylor **/ #include #include "curses.h" #include "headers.h" #define RS 94 #define RN 4 #define RMASK 0x7fff /* use only 15 bits */ static char r[RS][RN]; /* rotors */ static char ir[RS][RN]; /* inverse rotors */ static char h[RS]; /* half rotor */ static char s[RS]; /* shuffle vector */ static int p[RN]; /* rotor indices */ static char the_key[SLEN]; /* unencrypted key */ static char *encrypted_key; /* encrypted key */ getkey(send) int send; { /** this routine prompts for and returns an encode/decode key for use in the rest of the program. If send == 1 then need to mess with rawmode. **/ char buffer[NLEN]; int gotkey = 0; dprint1("getkey(send=%s)\n", send? "ON" : "OFF"); ClearLine(21); if (send) Raw(OFF); while ( !gotkey ) { MoveCursor(LINES-1,0); ClearLine(LINES-1); if (send) strcpy( buffer, getpass( "Enter encryption key: ")); else strcpy( buffer, getpass( "Enter decryption key: ")); MoveCursor(LINES-1,0); if ( strcmp( buffer, getpass( "Please enter it again: "))) { error("Your keys were not the same!"); sleep(1); clear_error(); continue; } strcpy(the_key, buffer); /* save unencrypted key */ makekey( buffer ); gotkey = 1; } if (send) Raw(ON); setup(); /** initialize the rotors etc. **/ ClearLine(LINES-1); clear_error(); } get_key_no_prompt() { /** This performs the same action as get_key, but assumes that the current value of 'the_key' is acceptable. This is used when a message is encrypted twice... **/ char buffer[SLEN]; dprint0("get_key_no_prompt()\n"); strcpy(buffer, the_key); makekey( buffer ); setup(); } encode(line) char *line; { /** encrypt or decrypt the specified line. Uses the previously entered key... **/ register int i, index, j, ph = 0; dprint1("encode(line='%s')\n", line); for (index=0; index < strlen(line); index++) { i = (int) line[index]; if ( (i >= ' ') && (i < '~') ) { i -= ' '; for ( j = 0; j < RN; j++ ) /* rotor forwards */ i = r[(i+p[j])%RS][j]; i = ((h[(i+ph)%RS])-ph+RS)%RS; /* half rotor */ for ( j-- ; j >= 0; j-- ) /* rotor backwards */ i = (ir[i][j]+RS-p[j])%RS; j = 0; /* rotate rotors */ p[0]++; while ( p[j] == RS ) { p[j] = 0; j++; if ( j == RN ) break; p[j]++; } if ( ++ph == RS ) ph = 0; i += ' '; } line[index] = (char) i; /* replace with altered one */ } } makekey( rkey) char *rkey; { /** encrypt the key using the system routine 'crypt' **/ char key[8], salt[2], *crypt(); dprint1("makekey(rkey='%s')\n", rkey); strncpy( key, rkey, 8); salt[0] = key[0]; salt[1] = key[1]; encrypted_key = crypt( key, salt); } /* * shuffle rotors. * shuffle each of the rotors indiscriminately. shuffle the half-rotor * using a special obvious and not very tricky algorithm which is not as * sophisticated as the one in crypt(1) and Oh God, I'm so depressed. * After all this is done build the inverses of the rotors. */ setup() { register long i, j, k, temp; long seed; dprint0("setup()\n"); for ( j = 0; j < RN; j++ ) { p[j] = 0; for ( i = 0; i < RS; i++ ) r[i][j] = i; } seed = 123; for ( i = 0; i < 13; i++) /* now personalize the seed */ seed = (seed*encrypted_key[i] + i) & RMASK; for ( i = 0; i < RS; i++ ) /* initialize shuffle vector */ h[i] = s[i] = i; for ( i = 0; i < RS; i++) { /* shuffle the vector */ seed = (5 * seed + encrypted_key[i%13]) & RMASK;; k = ((seed % 65521) & RMASK) % RS; temp = s[k]; s[k] = s[i]; s[i] = temp; } for ( i = 0; i < RS; i += 2 ) { /* scramble the half-rotor */ temp = h[s[i]]; /* swap rotor elements ONCE */ h[s[i]] = h[s[i+1]]; h[s[i+1]] = temp; } for ( j = 0; j < RN; j++) { /* select a rotor */ for ( i = 0; i < RS; i++) { /* shuffle the vector */ seed = (5 * seed + encrypted_key[i%13]) & RMASK;; k = ((seed % 65521) & RMASK) % RS; temp = r[i][j]; r[i][j] = r[k][j]; r[k][j] = temp; } for ( i = 0; i < RS; i++) /* create inverse rotors */ ir[r[i][j]][j] = i; } } END-OF-FILE size=`wc -c < src/encode.c` if [ $size != 4349 ] then echo Warning: src/encode.c changed - should be 4349 bytes, not $size bytes fi chmod 644 src/encode.c # ---------- file src/file.c ---------- if [ -f src/file.c ] then echo File 'src/file.c' already exists\! exit 1 fi echo extracting file src/file.c... cat << 'END-OF-FILE' > src/file.c /** file.c **/ /** File I/O routines, including deletion from the mailbox! (C) Copyright 1986, Dave Taylor **/ #include "headers.h" #include #ifdef BSD #undef tolower #endif int save() { /** save current message in file. Append if possible! Returns zero iff no file specified (cancelled command) **/ char filename[SLEN], address[LONG_SLEN], buffer[SLEN]; FILE *save_file; dprint0("save()\n"); MoveCursor(LINES-2,0); printf("File current message in: "); if (save_by_name) { /** build default filename to save to **/ get_return(address); get_return_name(address, buffer); sprintf(filename, "=/%s", buffer); } else filename[0] = '\0'; optionally_enter(filename, LINES-2, 25, FALSE); MoveCursor(LINES-1,0); if (strlen(filename) == 0) /** means 'cancel', right? **/ return(0); if (! expand_filename(filename)) return(0); /* failed expanding name! */ if ((save_file = fopen(filename,"a")) == NULL) { error1("Couldn't append to file %s!", filename); return(0); } copy_message("", save_file, FALSE); fclose(save_file); chown(filename, getuid(), getgid()); /* owned by user */ error1("Message saved in file %s", filename); return(1); } int expand_filename(filename) char *filename; { /* expands '~' and '=' to specified file names, also will try to expand shell variables if encountered.. */ char buffer[SLEN], varname[SLEN], env_value[SLEN]; register int i = 1, index = 0; dprint1("expand_filename(filename='%s')\n", filename); /** new stuff - make sure no illegal char as last **/ if (lastch(filename) == '\n' || lastch(filename) == '\r') lastch(filename) = '\0'; if (filename[0] == '~') { sprintf(buffer, "%s%s%s", home, (filename[1] != '/' && lastch(folders) != '/')? "/" : "", (char *) filename + 1); strcpy(filename, buffer); } else if (filename[0] == '=') { if (strlen(folders) == 0) { error("MAILDIR not defined. Can't expand '='"); return(0); } sprintf(buffer, "%s%s%s", folders, (filename[1] != '/' && lastch(folders) != '/')? "/" : "", (char *) filename + 1); strcpy(filename, buffer); } else if (filename[0] == '$') { /* env variable! */ while (isalnum(filename[i])) varname[index++] = filename[i++]; varname[index] = '\0'; strcpy(env_value, getenv(varname)); if (strlen(env_value) == 0) { error1("Don't know what the value of $%s is!", varname); return(0); } sprintf(buffer, "%s%s%s", env_value, (filename[i] != '/' && lastch(env_value) != '/')? "/" : "", (char *) filename + i); strcpy(filename, buffer); } return(1); } END-OF-FILE size=`wc -c < src/file.c` if [ $size != 2644 ] then echo Warning: src/file.c changed - should be 2644 bytes, not $size bytes fi chmod 644 src/file.c echo done exit 0