syd@dsinc.UUCP (Syd Weinstein) (12/12/88)
---- Cut Here and unpack ---- #!/bin/sh # this is part 9 of a multipart archive # do not concatenate these parts, unpack them in order with /bin/sh # file src/alias.c continued # CurArch=9 if test ! -r s2_seq_.tmp then echo "Please unpack part 1 first!" exit 1; fi ( read Scheck if test "$Scheck" != $CurArch then echo "Please unpack part $Scheck next!" exit 1; else exit 0; fi ) < s2_seq_.tmp || exit 1 echo "x - Continuing file src/alias.c" sed 's/^X//' << 'SHAR_EOF' >> src/alias.c X Xunsigned long sleep(); X Xextern int errno; X Xextern int findnode_has_been_initialized; X Xread_alias_files() X{ X /** read the system and user alias files, if present. X Set the flags 'systemfiles' and 'userfiles' accordingly. X **/ X X char fname[SLEN]; X int hash; X X if ((hash = open(system_hash_file, O_RDONLY)) == -1) { X dprint(2, (debugfile, X "Warning: Can't read system hash file %s\n", system_hash_file)); X goto user; X } X X read(hash, (char *) system_hash_table, sizeof system_hash_table); X close(hash); X X /* and data file opened.. */ X X if ((system_data = open(system_data_file, O_RDONLY)) == -1) { X dprint(1, (debugfile, X "Warning: Can't read system data file %s\n", system_data_file)); X goto user; X } X X system_files++; /* got the system files! */ X Xuser: sprintf(fname, "%s/%s", home, ALIAS_HASH); X X if ((hash = open(fname, O_RDONLY)) == -1) { X dprint(2,(debugfile, "Warning: Can't read user hash file %s\n", X fname)); X return; X } X X read(hash, (char *) user_hash_table, sizeof user_hash_table); X close(hash); X X sprintf(fname, "%s/%s", home, ALIAS_DATA); X X if ((user_data = open(fname, O_RDONLY)) == -1) { X dprint(1, (debugfile, X "Warning: can't read user data file %s\n", fname)); X return; X } X X user_files++; /* got user files too! */ X} X Xint Xadd_alias() X{ X /** add an alias to the user alias text file. Return zero X if alias not added in actuality **/ X X char name[SLEN], *address, address1[LONG_STRING]; X char comment[SLEN]; X char *strcpy(); X X PutLine0(LINES-2,0,"Enter alias name: "); X CleartoEOLN(); X Raw(OFF); X gets(name); X Raw(ON); X if (strlen(name) == 0) X return(0); X if ((address = get_alias_address(name, 0, 0)) != NULL) { X dprint(3, (debugfile, X "Attempt to add a duplicate alias [%s] in add_alias\n", X address)); X if (address[0] == '!') { X address[0] = ' '; X error1("already a group with that name:%s", address); X } X else X error1("already an alias for that: %s", address); X return(0); X } X PutLine1(LINES-2,0,"Full name for %s: ", name); X CleartoEOLN(); X Raw(OFF); X gets(comment); X Raw(ON); X if (strlen(comment) == 0) strcpy(comment, name); X PutLine1(LINES-2,0,"Enter address for %s: ",name); X CleartoEOLN(); X Raw(OFF); X gets(address1); X Raw(ON); X if (strlen(address1) == 0) { X error("No address specified!"); X return(0); X } X add_to_alias_text(name, comment, address1); X return(1); X} X Xint Xadd_current_alias() X{ X /** alias the current message to the specified name and X add it to the alias text file, for processing as X the user leaves the program. Returns non-zero iff X alias actually added to file **/ X X char name[SLEN], address1[LONG_STRING], buffer[LONG_STRING], *address; X char comment[SLEN]; X X if (current == 0) { X dprint(4, (debugfile, X "Add current alias called without any current message!\n")); X error("No message to alias to!"); X return(0); X } X X PutLine0(LINES-2,0,"Current message address aliased to: "); X CleartoEOLN(); X Raw(OFF); X gets(name); X Raw(ON); X if (strlen(name) == 0) /* cancelled... */ X return(0); X if ((address = get_alias_address(name, 0, 0)) != NULL) { X dprint(3, (debugfile, X "Attempt to add a duplicate alias [%s] in add_current_alias\n", X address)); X if (address[1] == '!') { X address[0] = ' '; X error1("already a group with that name:%s", address); X } X else X error1("already an alias for that: %s", address); X return(0); X } X PutLine1(LINES-2,0,"Full name of %s: ", name); X CleartoEOLN(); X Raw(OFF); X gets(comment); X Raw(ON); X get_return(buffer); /* grab the return address of this message */ X strcpy(address1, strip_parens(buffer)); /* remove parens! */ X#ifdef OPTIMIZE_RETURN X optimize_return(address1); X#endif X PutLine3(LINES-2,0,"%s (%s) = %s", comment, name, address1); X CleartoEOLN(); X add_to_alias_text(name, comment, address1); X return(1); X} X Xadd_to_alias_text(name, comment, address) Xchar *name, *comment, *address; X{ X /** Add the data to the user alias text file. Return zero if we X succeeded, 1 if not **/ X X FILE *file; X char fname[SLEN]; X X sprintf(fname,"%s/%s", home, ALIAS_TEXT); X X if ((file = fopen(fname, "a")) == NULL) { X dprint(2, (debugfile, X "Failure attempting to add alias to file %s within %s", X fname, "add_to_alias_text")); X dprint(2, (debugfile, "** %s - %s **\n", error_name(errno), X error_description(errno))); X error1("couldn't open %s to add new alias!", fname); X return(1); X } X X fprintf(file,"%s = %s = %s\n", name, comment, address); X fclose(file); X X chown(fname, userid, groupid); X X return(0); X} X Xshow_alias_menu() X{ X MoveCursor(LINES-7,0); CleartoEOLN(); X MoveCursor(LINES-6,0); CleartoEOLN(); X MoveCursor(LINES-5,0); CleartoEOLN(); X X PutLine0(LINES-7,COLUMNS-45, "Alias commands"); X Centerline(LINES-5, X"A)lias current msg, Check a P)erson or S)ystem, M)ake new alias, or R)eturn" X ); X} X Xalias() X{ X /** work with alias commands... **/ X /** return non-0 if main part of screen overwritten, else 0 **/ X X char name[NLEN], *address, ch, buffer[SLEN]; X int newaliases = 0, redraw = 0; X X if (mini_menu) X show_alias_menu(); X X /** now let's ensure that we've initialized everything! **/ X X#ifndef DONT_TOUCH_ADDRESSES X X if (! findnode_has_been_initialized) { X if (! mail_only && warnings) X error("initializing internal tables..."); X#ifndef USE_DBM X get_connections(); X open_domain_file(); X#endif X init_findnode(); X clear_error(); X findnode_has_been_initialized = TRUE; X } X X#endif X X define_softkeys(ALIAS); X X while (1) { X prompt("Alias: "); X CleartoEOLN(); X ch = ReadCh(); X MoveCursor(LINES-1,0); CleartoEOS(); X X dprint(3, (debugfile, "\n-- Alias command: %c\n\n", ch)); X X switch (tolower(ch)) { X case '?': redraw += alias_help(); break; X X case 'a': newaliases += add_current_alias(); break; X case 'm': newaliases += add_alias(); break; X X case RETURN: X case LINE_FEED: X case 'q': X case 'x': X case 'r': if (newaliases) install_aliases(); X return(redraw); X case 'p': if (newaliases) X error("Warning: new aliases not installed yet!"); X PutLine0(LINES-2,0,"Check for person: "); X CleartoEOLN(); X Raw(OFF); X gets(name); X Raw(ON); X if ((address = get_alias_address(name, 0, 0))!=NULL) { X if (address[0] == '!') { X address[0] = ' '; X PutLine1(LINES-1,0,"Group alias:%-60.60s", address); X CleartoEOLN(); X } X else X PutLine1(LINES-1,0,"Aliased address: %-60.60s", X address); X } X else X error("not found"); X break; X X case 's': PutLine0(LINES-2,0,"Check for system: "); X CleartoEOS(); X Raw(OFF); X gets(name); X Raw(ON); X if (talk_to(name)) X#ifdef INTERNET_ADDRESS_FORMAT X PutLine1(LINES-1,0, X "You have a direct connection - the address is USER@%s", X name); X#else X PutLine1(LINES-1,0, X "You have a direct connection - the address is %s!USER", X name); X#endif X else { X sprintf(buffer, "USER@%s", name); X#ifdef DONT_TOUCH_ADDRESSES X address = buffer; X#else X address = expand_system(buffer, FALSE); X#endif X if (strlen(address) > strlen(name) + 7) X PutLine1(LINES-1,0,"Address is: %.65s", address); X else X error1("couldn't expand system '%s'", name); X } X break; X X case '@': PutLine0(LINES-2,0,"Fully expand alias: "); X CleartoEOS(); X Raw(OFF); X gets(name); X Raw(ON); X if ((address = get_alias_address(name, 1, 0)) != NULL) { X ClearScreen(); X PutLine1(3,0,"Aliased address:\n\r%s", address); X PutLine0(LINES-1,0,"Press <return> to continue: "); X (void) getchar(); X } X else X error("not found"); X if (mini_menu) show_alias_menu(); X break; X default : error("Invalid input!"); X } X } X} X Xinstall_aliases() X{ X /** run the 'newalias' program and install the newly X added aliases before going back to the main X program! X **/ X X X error("Adding new aliases..."); X sleep(2); X X if (system_call(newalias, SH) == 0) { X error("Re-reading the database in..."); X sleep(2); X read_alias_files(); X set_error("New aliases installed successfully"); X } X else X set_error("'newalias' failed. Please check alias_text"); X} X Xalias_help() X{ X /** help section for the alias menu... **/ X /** return non-0 if main part of screen overwritten, else 0 */ X X char ch; X int redraw=0; X X MoveCursor(LINES-3, 0); CleartoEOS(); X X if (! mini_menu) X lower_prompt("Key you want help for : "); X else { X Centerline(LINES-3, X"Enter key you want help for, '?' for list or '.' to leave help"); X lower_prompt("Key : "); X } X X while ((ch = ReadCh()) != '.') { X ch = tolower(ch); X switch(ch) { X case '?' : display_helpfile(ALIAS_HELP); X redraw++; X if (mini_menu) show_alias_menu(); X return(redraw); X case 'a': error( X"a = Add return address of current message to alias database"); break; X case 'm': error( X"m = Make new user alias, adding to alias database when done"); break; X X case RETURN: X case LINE_FEED: X case 'q': X case 'x': X case 'r': error("return from alias menu"); break; X X case 'p': error( X"p = check for a person in the alias database"); break; X X case 's': error( X"s = check for a system in the host routing/domain database"); break; X X default : error("That key isn't used in this section"); break; X } X if (! mini_menu) X lower_prompt("Key you want help for : "); X else X lower_prompt("Key : "); X } X return(redraw); X} SHAR_EOF echo "File src/alias.c is complete" chmod 0444 src/alias.c || echo "restore of src/alias.c fails" echo "x - extracting src/aliasdb.c (Text)" sed 's/^X//' << 'SHAR_EOF' > src/aliasdb.c && X Xstatic char rcsid[] = "@(#)$Id: aliasdb.c,v 2.1 88/07/21 09:57:50 edc Exp $"; X X/******************************************************************************* X * The Elm Mail System - $Revision: 2.1 $ $State: Exp $ X * X * Copyright (c) 1986 Dave Taylor X ******************************************************************************* X * Bug reports, patches, comments, suggetions should be sent to: X * X * Syd Weinstein, Elm Corrdinator X * syd@dsinc.UUCP dsinc!syd X * X ******************************************************************************* X * $Log: aliasdb.c,v $ X * Revision 2.1 88/07/21 09:57:50 edc X * checked in with -k by syd at 88.09.15.20.27.26. X * X * Revision 2.1 88/07/21 09:57:50 edc X * Final hacks and cleanup to the 2.1 alpha test release. X * X * Revision 2.0 88/06/27 17:24:47 edc X * The original 2.0 gamma sources as leaked from HP X * X * X * X ******************************************************************************/ X X/** Alias database files... X X**/ X X X#include "headers.h" X X#include <sys/types.h> X#include <sys/stat.h> X#include <errno.h> X Xextern int errno; X X#ifdef USE_DBM X# include <dbm.h> X#endif X X#define absolute(x) ((x) > 0 ? x : -(x)) X Xchar *shift_lower(), *find_path_to(), *strcat(), *strcpy(); Xunsigned long sleep(); X Xint findnode_has_been_initialized = FALSE; X Xfindnode(name, display_error) Xchar *name; Xint display_error; X{ X /** break 'name' into machine!user or user@machine and then X see if you can find 'machine' in the path database.. X If so, return name as the expanded address. If not, X return what was given to us! If display_error, then X do so... X **/ X X#ifndef DONT_TOUCH_ADDRESSES X X char old_name[SLEN]; X char address[SLEN]; X X if (strlen(name) == 0) X return; X X if (! findnode_has_been_initialized) { X if (! mail_only && warnings) X error("initializing internal tables..."); X#ifndef USE_DBM X get_connections(); X open_domain_file(); X#endif X init_findnode(); X clear_error(); X findnode_has_been_initialized = TRUE; X } X X strcpy(old_name, name); /* save what we were given */ X X if (expand_site(name, address) == -1) { X if (display_error && name[0] != '!') { X dprint(3, (debugfile, "Couldn't expand host %s in address.\n", X name)); X if (! check_only && warnings) { X if (mail_only) X printf("Warning: Couldn't expand system %s\n\r", name); X else { X error1("Couldn't expand system %s", name); X sleep(1); X } X } X } X strcpy(name, old_name); /* and restore... */ X } X else X strcpy(name, address); X#endif X return; X} X Xint Xexpand_site(cryptic, expanded) Xchar *cryptic, *expanded; X{ X X /** Given an address of the form 'xyz@site' or 'site!xyz' X return an address of the form <expanded address for site> X with 'xyz' embedded according to the path database entry. X Note that 'xyz' can be eiher a simple address (as in "joe") X or a complex address (as in "joe%xerox.parc@Xerox.ARPA")! X 0 = found, -1 return means unknown site code X X Modified to strip out parenthetical comments... X **/ X X#ifdef ACSNET X X strcpy(expanded, cryptic); /* fast and simple */ X return(0); X X#else X# ifdef USE_DBM X datum key, contents; X# endif X X char name[VERY_LONG_STRING], sitename[VERY_LONG_STRING], X temp[VERY_LONG_STRING], old_name[VERY_LONG_STRING], X comment[LONG_STRING]; X char *expand_domain(), *addr; X register int i = 0, j = 0, domain_name; X X strcpy(old_name, cryptic); /* remember what we were given */ X X /** break down **/ X X /** first, rip out the comment, if any **/ X X if ((i = chloc(cryptic, '(')) > -1) { X comment[j++] = ' '; /* leading space */ X for ( ;cryptic[i] != ')'; i++) X comment[j++] = cryptic[i]; X comment[j++] = ')'; X comment[j] = '\0'; X /* and remove this from cryptic string too... */ X if (cryptic[(j = chloc(cryptic,'('))-1] == ' ') X cryptic[j-1] = '\0'; X else X cryptic[j] = '\0'; X } X else X comment[0] = '\0'; X X i = j = 0; /* reset */ X X while (cryptic[i] != AT_SIGN && cryptic[i] != BANG && X cryptic[i] != '\0' && cryptic[i] != '(') X sitename[j++] = cryptic[i++]; X X sitename[j++] = '\0'; X X j = 0; X X if (cryptic[i] == '\0') return(-1); /* nothing to expand! */ X X domain_name = (cryptic[i] == AT_SIGN); X X i++; X X while (cryptic[i] != '\0' && cryptic[i] != '(' && X ! whitespace(cryptic[i])) X name[j++] = cryptic[i++]; X X name[j] = '\0'; X X if (domain_name) { X strcpy(temp, name); X strcpy(name, sitename); X strcpy(sitename, temp); X } X X dprint(5, (debugfile, "\nBroke address into '%s' @ '%s' '%s'\n\n", X name, sitename, comment)); X X#ifdef USE_DBM X X if (size_of_pathfd == 0) X return(-1); X X key.dptr = sitename; X key.dsize = strlen(sitename) + 1; X X contents = fetch(key); X X if (contents.dptr == 0) X return(-1); /* can't find it! */ X X sprintf(expanded, contents.dptr, name); X strcat(expanded, " "); /* add a single space... */ X strcat(expanded, comment); /* ...and add comment */ X return(0); X#endif X X#ifndef LOOK_CLOSE_AFTER_SEARCH X X if (talk_to(sitename)) { X strcpy(expanded, old_name); /* restore! */ X return(0); X } X#endif X X if ((addr = find_path_to(sitename, TRUE)) == NULL) { X X#ifdef LOOK_CLOSE_AFTER_SEARCH X X if (talk_to(sitename)) { X strcpy(expanded, old_name); /* restore! */ X return(0); X } X else X#endif X if ((addr = expand_domain(cryptic)) != NULL) { X strcpy(expanded, addr); /* into THIS buffer */ X strcat(expanded, comment); /* patch in comment */ X return(0); X } X else if (size_of_pathfd == 0) { /* no path database! */ X strcpy(expanded, old_name); /* restore! */ X return(0); X } X else { /* We just can't get there! */ X strcpy(expanded, old_name); /* restore! */ X return(-1); X } X } X else { /* search succeeded */ X sprintf(expanded, addr, name); X strcat(expanded, comment); /* add comment */ X return(0); X } X#endif X} X Xint Xbinary_search(name, address) Xchar *name, *address; X{ X /* binary search file for name. Return 0 if found, -1 if not */ X X char machine[40]; X register long first = 0, last, middle; X register int compare; X X address[0] = '\0'; X X last = size_of_pathfd; X X do { X X middle = (long) ((first+last) / 2); X X get_entry(machine, address, pathfd, middle); X X compare = strcmp(name, machine); X X if (compare < 0) X last = middle - 1; X else if (compare == 0) X return(0); X else /* greater */ X first = middle + 1; X } while (absolute(last) - absolute(first) > FIND_DELTA); X X return(-1); X} X Xget_entry(machine, address, fileid, offset) Xchar *machine, *address; XFILE *fileid; Xlong offset; X{ X /** get entry...return machine and address immediately X following given offset in fileid. **/ X X (void) fseek(fileid, offset, 0); X X /* read until we hit an end-of-line */ X X while (getc(fileid) != '\n') X ; X X fscanf(fileid, "%s\t%s", machine, address); X} X Xinit_findnode() X{ X /** Initialize the FILE and 'size_of_file' values for the X findnode procedure **/ X X struct stat buffer; X char *path_filename; X X#ifdef USE_DBM X char buf[BUFSIZ]; X X sprintf(buf,"%s.pag", pathfile); X path_filename = buf; X#else X path_filename = pathfile; X#endif X X if (stat(path_filename, &buffer) == -1) { X dprint(2, (debugfile, X "Warning: pathalias file \"%s\" wasn't found by %s\n", X path_filename, "init_findnode")); X size_of_pathfd = 0; X return; X } X X size_of_pathfd = (long) buffer.st_size; X X#ifdef USE_DBM X X if (dbminit(pathfile) != 0) { X dprint(2, (debugfile, X "Warning: couldn't initialize DBM database %s\n", X pathfile)); X dprint(2, (debugfile, "** %s - %s **\n\n", error_name(errno), X error_description(errno))); X size_of_pathfd = 0; /* error flag, in this case */ X return; X } X X return; X#else X X if ((pathfd = fopen(pathfile,"r")) == NULL) { X dprint(2, (debugfile, X "Warning: Can't read pathalias file \"%s\" within %s\n", X pathfile, "init_findnode")); X size_of_pathfd = 0; X } X else X dprint(3, (debugfile, "\nOpened '%s' as pathalias database.\n\n", X pathfile)); X#endif X} X Xchar *find_path_to(machine, printf_format) Xchar *machine; Xint printf_format; X{ X /** Returns either the path to the specified machine or NULL if X not found. If "printf_format" is TRUE, then it leaves the X '%s' intact, otherwise it assumes that the address is a uucp X address for the domain expansion program and removes the X last three characters of the expanded name ("!%s") since X they're redundant with the expansion! X **/ X X static char buffer[LONG_SLEN]; /* space for path */ X X if (size_of_pathfd > 0) X if (binary_search(machine, buffer) != -1) { /* found it! */ X if (! printf_format && strlen(buffer) > 3) X buffer[strlen(buffer)-3] = '\0'; X return( (char *) buffer); X } X X return(NULL); /* failed if it's here! */ X} SHAR_EOF chmod 0444 src/aliasdb.c || echo "restore of src/aliasdb.c fails" echo "x - extracting src/aliaslib.c (Text)" sed 's/^X//' << 'SHAR_EOF' > src/aliaslib.c && X Xstatic char rcsid[] = "@(#)$Id: aliaslib.c,v 2.1 88/07/21 09:57:53 edc Exp $"; X X/******************************************************************************* X * The Elm Mail System - $Revision: 2.1 $ $State: Exp $ X * X * Copyright (c) 1986 Dave Taylor X ******************************************************************************* X * Bug reports, patches, comments, suggetions should be sent to: X * X * Syd Weinstein, Elm Corrdinator X * syd@dsinc.UUCP dsinc!syd X * X ******************************************************************************* X * $Log: aliaslib.c,v $ X * Revision 2.1 88/07/21 09:57:53 edc X * checked in with -k by syd at 88.09.15.20.27.28. X * X * Revision 2.1 88/07/21 09:57:53 edc X * Final hacks and cleanup to the 2.1 alpha test release. X * X * Revision 2.0 88/06/27 17:24:47 edc X * The original 2.0 gamma sources as leaked from HP X * X * X * X ******************************************************************************/ X X/** Library of functions dealing with the alias system... X X **/ X X#include "headers.h" X Xchar *expand_group(), *get_alias_address(), *expand_system(); Xchar *get_token(), *strpbrk(); Xlong lseek(); X Xchar *get_alias_address(name, mailing, depth) Xchar *name; Xint mailing, depth; X{ X /** return the line from either datafile that corresponds X to the specified name. If 'mailing' specified, then X fully expand group names. Depth specifies the nesting X depth - the routine should always initially be called X with this equal 0. Returns NULL if not found **/ X X static char buffer[VERY_LONG_STRING]; X int loc; X X if (strlen(name) == 0) X return( (char *) NULL); X X if (! read_in_aliases) { X read_alias_files(); X read_in_aliases = TRUE; X } X X if (user_files) X if ((loc = find(name, user_hash_table, MAX_UALIASES)) >= 0) { X lseek(user_data, user_hash_table[loc].byte, 0L); X get_line(user_data, buffer); X if (buffer[0] == '!' && mailing) X return(expand_group(buffer, depth)); X else if (strpbrk(buffer,"!@:") != NULL) /* has a hostname */ X#ifdef DONT_TOUCH_ADDRESSES X return((char *) buffer); X#else X return(expand_system(buffer, TRUE)); X#endif X else X return((char *) buffer); X } X X if (system_files) X if ((loc = find(name, system_hash_table, MAX_SALIASES)) >= 0) { X lseek(system_data, system_hash_table[loc].byte, 0L); X get_line(system_data, buffer); X if (buffer[0] == '!' && mailing) X return(expand_group(buffer, depth)); X else if (strpbrk(buffer,"!@:") != NULL) /* has a hostname */ X#ifdef DONT_TOUCH_ADDRESSES X return((char *) buffer); X#else X return(expand_system(buffer, TRUE)); X#endif X else X return((char *) buffer); X } X X return( (char *) NULL); X} X Xchar *expand_system(buffer, show_errors) Xchar *buffer; Xint show_errors; X{ X /** This routine will check the first machine name in the given path X (if any) and expand it out if it is an alias...if not, it will X return what it was given. If show_errors is false, it won't X display errors encountered... X **/ X X dprint(6, (debugfile, "expand_system(%s, show-errors=%s)\n", buffer, X onoff(show_errors))); X findnode(buffer, show_errors); X X return( (char *) buffer); X} X Xchar *expand_group(members, depth) Xchar *members; Xint depth; X{ X /** Given a group of names separated by commas, this routine X will return a string that is the full addresses of each X member separated by spaces. Depth is an internal counter X that keeps track of the depth of nesting that the routine X is in...it's for the get_token routine! **/ X X static char buffer[VERY_LONG_STRING]; X char buf[LONG_STRING], *word, *address, *bufptr; X char *strcpy(); X X strcpy(buf, members); /* parameter safety! */ X if (depth == 0) buffer[0] = '\0'; /* nothing in yet! */ X bufptr = (char *) buf; /* grab the address */ X depth++; /* one deeper! */ X X while ((word = get_token(bufptr, "!, ", depth)) != NULL) { X if ((address = get_alias_address(word, 1, depth)) == NULL) { X if (! valid_name(word)) { X dprint(3, (debugfile, "Encountered illegal address %s in %s\n", X word, "expand_group")); X error1("%s is an illegal address!", word); X return( (char *) NULL); X } X else if (strcmp(buffer, word) != 0) X sprintf(buffer, "%s%s%s", buffer, X (strlen(buffer) > 0)? ", ":"", word); X } X else if (strcmp(buffer, address) != 0) X sprintf(buffer,"%s%s%s", buffer, X (strlen(buffer) > 0)? ", ":"", address); X X bufptr = NULL; X } X X return( (char *) buffer); X} X Xint Xfind(word, table, size) Xchar *word; Xstruct alias_rec table[]; Xint size; X{ X /** find word and return loc, or -1 **/ X register int loc; X X if (strlen(word) > 20) { X dprint(3, (debugfile, "Overly long alias name entered: %s\n", word)); X error1("Bad alias name: %s. Too long.\n", word); X return(-1); X } X X loc = hash_it(word, size); X X while (strcmp(word, table[loc].name) != 0) { X if (table[loc].name[0] == '\0') X return(-1); X loc = (loc + 1) % size; X } X X return(loc); X} X Xint Xhash_it(string, table_size) Xchar *string; Xint table_size; X{ X /** compute the hash function of the string, returning X it (mod table_size) **/ X X register int i, sum = 0; X X for (i=0; string[i] != '\0'; i++) X sum += (int) string[i]; X X return(sum % table_size); X} X Xget_line(fd, buffer) Xint fd; Xchar *buffer; X{ X /* Read from file fd. End read upon reading either X EOF or '\n' character (this is where it differs X from a straight 'read' command!) */ X X register int i= 0; X char ch; X X while (read(fd, &ch, 1) > 0) X if (ch == '\n' || ch == '\r') { X buffer[i] = 0; X return; X } X else X buffer[i++] = ch; X} SHAR_EOF chmod 0444 src/aliaslib.c || echo "restore of src/aliaslib.c fails" echo "x - extracting src/args.c (Text)" sed 's/^X//' << 'SHAR_EOF' > src/args.c && X Xstatic char rcsid[] = "@(#)$Id: args.c,v 2.1 88/09/15 20:27:30 syd Exp $"; X X/******************************************************************************* X * The Elm Mail System - $Revision: 2.1 $ $State: Exp $ X * X * Copyright (c) 1986 Dave Taylor X ******************************************************************************* X * Bug reports, patches, comments, suggetions should be sent to: X * X * Syd Weinstein, Elm Corrdinator X * syd@dsinc.UUCP dsinc!syd X * X ******************************************************************************* X * $Log: args.c,v $ X * Revision 2.1 88/09/15 20:27:30 syd X * checked in with -k by syd at 88.09.15.20.27.30. X * X * 88/09/01 Rob Bernardo <gatech!pbhyf.PacBell.COM!rob> X * 1. It allows the user to use the -z flags and -f [filename] flag X * 2. Puts elm in raw mode earlier on than before so that any commands X * X * 88/08/27 ssw X * add deluth patches X * X * Revision 2.1 88/07/21 09:57:55 edc X * Final hacks and cleanup to the 2.1 alpha test release. X * X * Revision 2.0 88/06/27 17:24:48 edc X * The original 2.0 gamma sources as leaked from HP X * X * X * X ******************************************************************************/ X X/** starting argument parsing routines for ELM system... X X**/ X X#include "headers.h" X X#define DONE 0 X#define ERROR -1 X Xextern char *optional_arg; /* optional argument as we go */ Xextern int opt_index; /* argnum + 1 when we leave */ X Xvoid exit(); /* just keeping lint happy.... */ X Xparse_arguments(argc, argv, to_whom) Xint argc; Xchar *argv[], *to_whom; X{ X /** Set flags according to what was given to program. If we are X fed a name or series of names, put them into the 'to_whom' buffer X and set "mail_only" to TRUE **/ X X register int c = 0; X char *strcpy(); X X infile[0] = '\0'; X to_whom[0] = '\0'; X batch_subject[0] = '\0'; X X while ((c = get_options(argc, argv, "?acd:f:hkKms:Vwz")) > 0) { X switch (c) { X case 'a' : arrow_cursor++; break; X case 'c' : check_only++; break; X case 'd' : debug = atoi(optional_arg); break; X case 'f' : strcpy(infile, optional_arg); X mbox_specified = 2; break; X case '?' : X case 'h' : args_help(); X case 'k' : hp_terminal++; break; X case 'K' : hp_terminal++; hp_softkeys++; break; X case 'm' : mini_menu = 0; break; X case 's' : strcpy(batch_subject, optional_arg); break; X case 'V' : sendmail_verbose++; break; X case 'w' : warnings = 0; break; X case 'z' : check_size++; break; X } X } X X if (c == ERROR) { X printf( X "Usage: %s [achkKmVwz] [-d level] [-f file] [-s subject] <names>\n\n", X argv[0]); X args_help(); X } X X#ifndef DEBUG X if (debug) X printf( X "Warning: system created without debugging enabled - request ignored\n"); X debug = 0; X#endif X X if (opt_index < argc) { X while (opt_index < argc) { X sprintf(to_whom, "%s%s%s", to_whom, X to_whom[0] != '\0'? " " : "", argv[opt_index]); X mail_only++; X opt_index++; X } X check_size = 0; /* NEVER do this if we're mailing!! */ X } X X if (strlen(batch_subject) > 0 && ! mail_only) X exit(printf( X "\n\rDon't understand specifying a subject and no-one to send to!\n\r")); X X if (!isatty(fileno(stdin)) && strlen(batch_subject) == 0 && !check_only) X strcpy(batch_subject, DEFAULT_BATCH_SUBJECT); X X} X Xargs_help() X{ X /** print out possible starting arguments... **/ X X printf("\nPossible Starting Arguments for ELM program:\n\n"); X printf("\targ\t\t\tMeaning\n"); X printf("\t -a \t\tArrow - use the arrow pointer regardless\n"); X printf("\t -c \t\tCheckalias - check the given aliases only\n"); X printf("\t -dn\t\tDebug - set debug level to 'n'\n"); X printf("\t -fx\t\tFile - read file 'x' rather than mailbox\n"); X printf("\t -h \t\tHelp - give this list of options\n"); X printf("\t -k \t\tKeypad - enable HP 2622 terminal keyboard\n"); X printf("\t -K \t\tKeypad&softkeys - enable use of softkeys + \"-k\"\n"); X printf("\t -m \t\tMenu - Turn off menu, using more of the screen\n"); X printf("\t -sx\t\tSubject 'x' - for batchmailing\n"); X printf("\t -V \t\tEnable sendmail voyeur mode.\n"); X printf("\t -w \t\tSupress warning messages...\n"); X printf("\t -z \t\tZero - don't enter Elm if no mail is pending\n"); X printf("\n"); X printf("\n"); X exit(1); X} SHAR_EOF chmod 0444 src/args.c || echo "restore of src/args.c fails" echo "x - extracting src/bouncebk.c (Text)" sed 's/^X//' << 'SHAR_EOF' > src/bouncebk.c && X Xstatic char rcsid[] = "@(#)$Id: bouncebk.c,v 2.1 88/07/21 09:57:57 edc Exp $"; X X/******************************************************************************* X * The Elm Mail System - $Revision: 2.1 $ $State: Exp $ X * X * Copyright (c) 1986 Dave Taylor X ******************************************************************************* X * Bug reports, patches, comments, suggetions should be sent to: X * X * Syd Weinstein, Elm Corrdinator X * syd@dsinc.UUCP dsinc!syd X * X ******************************************************************************* X * $Log: bouncebk.c,v $ X * Revision 2.1 88/07/21 09:57:57 edc X * checked in with -k by syd at 88.09.15.20.27.33. X * X * Revision 2.1 88/07/21 09:57:57 edc X * Final hacks and cleanup to the 2.1 alpha test release. X * X * Revision 2.0 88/06/27 17:24:49 edc X * The original 2.0 gamma sources as leaked from HP X * X * X * X ******************************************************************************/ X X/** This set of routines implement the bounceback feature of the mailer. X This feature allows mail greater than 'n' hops away (n specified by X the user) to have a 'cc' to the user through the remote machine. X X Due to the vagaries of the Internet addressing (uucp -> internet -> uucp) X this will NOT generate bounceback copies with mail to an internet host! X X**/ X X#include "headers.h" X Xchar *bounce_off_remote(), /* forward declaration */ X *strcat(), *strcpy(); X Xint Xuucp_hops(to) Xchar *to; X{ X /** Given the entire "To:" list, return the number of hops in the X first address (a hop = a '!') or ZERO iff the address is to a X non uucp address. X **/ X X register int hopcount = 0, index; X X for (index = 0; ! whitespace(to[index]) && to[index] != '\0'; index++) { X if (to[index] == '!') X hopcount++; X else if (to[index] == '@' || to[index] == '%' || to[index] == ':') X return(0); /* don't continue! */ X } X X return(hopcount); X} X Xchar *bounce_off_remote(to) Xchar *to; X{ X /** Return an address suitable for framing (no, that's not it...) X Er, suitable for including in a 'cc' line so that it ends up X with the bounceback address. The method is to take the first X address in the To: entry and break it into machines, then X build a message up from that. For example, consider the X following address: X a!b!c!d!e!joe X the bounceback address would be; X a!b!c!d!e!d!c!b!a!ourmachine!ourname X simple, eh? X **/ X X static char address[LONG_STRING]; /* BEEG address buffer! */ X X char host[MAX_HOPS][SHORT_SLEN]; /* for breaking up addr */ X register int hostcount = 0, hindex = 0, X index; X X for (index = 0; !whitespace(to[index]) && to[index] != '\0'; index++) { X if (to[index] == '!') { X host[hostcount][hindex] = '\0'; X hostcount++; X hindex = 0; X } X else X host[hostcount][hindex++] = to[index]; X } X X /* we have hostcount hosts... */ X X strcpy(address, host[0]); /* initialize it! */ X X for (index=1; index < hostcount; index++) { X strcat(address, "!"); X strcat(address, host[index]); X } X X /* and now the same thing backwards... */ X X for (index = hostcount -2; index > -1; index--) { X strcat(address, "!"); X strcat(address, host[index]); X } X X /* and finally, let's tack on our machine and login name */ X X strcat(address, "!"); X strcat(address, hostname); X strcat(address, "!"); X strcat(address, username); X X /* and we're done!! */ X X return( (char *) address ); X} SHAR_EOF chmod 0444 src/bouncebk.c || echo "restore of src/bouncebk.c fails" echo "x - extracting src/builtin.c (Text)" sed 's/^X//' << 'SHAR_EOF' > src/builtin.c && X Xstatic char rcsid[] = "@(#)$Id: builtin.c,v 2.1.1.2 88/09/23 syd Exp $"; X X/******************************************************************************* X * The Elm Mail System - $Revision: 2.1 $ $State: Exp $ X * X * Copyright (c) 1986 Dave Taylor X ******************************************************************************* X * Bug reports, patches, comments, suggetions should be sent to: X * X * Syd Weinstein, Elm Corrdinator X * syd@dsinc.UUCP dsinc!syd X * X ******************************************************************************* X * $Log: builtin.c,v $ X * Revision 2.1 88/09/15 20:27:35 syd X * checked in with -k by syd at 88.09.15.20.27.35. X * X * 88/08/27 ssw X * add deluth patches X * X * Revision 2.1 88/07/21 09:57:58 edc X * Final hacks and cleanup to the 2.1 alpha test release. X * X * Revision 2.0 88/06/27 17:24:50 edc X * The original 2.0 gamma sources as leaked from HP X * X * X * X ******************************************************************************/ X X/** This is the built-in pager for displaying messages while in the Elm X program. It's a bare-bones pager with precious few options. The idea X is that those systems that are sufficiently slow that using an external X pager such as 'more' is too slow, then they can use this! X X Added the following functionality; X X <number>s skip <number> lines X <number>f forward a page or <number> pages X /pattern skip forward to pattern X X [ not really - the pattern matching isn't REALLY implemented! X the moral of this story, of course, is that you shouldn't X read the source code to ascertain what functions a program has! ] X X [ oh - I almost forgot: *grin* ] X X Also added support for the "builtin+" pager (clears the screen for X each new page) including a two-line overlap for context... X X**/ X X#include "headers.h" X#include <ctype.h> X X#define BEEP 007 /* ASCII Bell character */ X X#ifdef BSD X# undef tolower X#endif X Xint lines_put_on_screen = 0, /* number of lines displayed per screen */ X lines_displayed = 0, /* Total number of lines displayed */ X total_lines_to_display, /* total number of lines in message */ X pages_displayed, /* for the nth page titles and all */ X lines_to_ignore = 0; /* for 'f' and 's' functions... */ X Xstart_builtin(lines_in_message) Xint lines_in_message; X{ X /** clears the screen and resets the internal counters... **/ X X dprint(8,(debugfile, X "displaying %d lines from message using internal pager\n", X lines_in_message)); X X lines_displayed = 0; X lines_put_on_screen = 0; X lines_to_ignore = 0; X pages_displayed = 1; X X total_lines_to_display = lines_in_message; X} X Xint Xdisplay_line(line) Xchar *line; X{ X /** Display the given line on the screen, taking into account such X dumbness as wraparound and such. If displaying this would put X us at the end of the screen, put out the "MORE" prompt and wait X for some input. Return non-zero if the user terminates the X paging (e.g. 'q' or 'i') or zero if we should continue...Also, X this will pass back the value of any character the user types in X at the prompt instead, if needed... (e.g. if it can't deal with X it at this point) X **/ X X register int lines_needed, okay_char, ch, len; X char pattern[SLEN], display_buffer[SLEN], *p, *pend; X char last_line[SLEN], line_before_that[SLEN]; X X if (lines_to_ignore != 0) { X if (--lines_to_ignore <= 0) { X putchar('\n'); X lines_to_ignore = 0; X } X return(0); X } X X lines_needed = (int) (printable_chars(line)/COLUMNS); /* wraparound */ X X /* the next few lines are from Greg Laskin and speed things up a lot! */ X X pend = line + strlen(line); X for (p = line; p < pend; ) X if (*p++ == '\n') lines_needed++; X X if (lines_needed + lines_put_on_screen > LINES-1) { X StartBold(); X if (user_level == 0) X sprintf(display_buffer, X" There are %d line%s left (%.2g%%) : press <space> for more, or 'q' to return ", X total_lines_to_display - lines_displayed, X plural(total_lines_to_display - lines_displayed), X 100.0*(1.0*lines_displayed) / (1.0*total_lines_to_display)); X else if (user_level == 1) X sprintf(display_buffer, X" %d line%s more (%.2g%%) : Press <space> for more, 'q' to return ", X total_lines_to_display - lines_displayed, X plural(total_lines_to_display - lines_displayed), X 100.0*(1.0*lines_displayed) / (1.0*total_lines_to_display)); X else X sprintf(display_buffer," %d line%s more (you've seen %.2g%%) ", X total_lines_to_display - lines_displayed, X plural(total_lines_to_display - lines_displayed), X 100.0*(1.0*lines_displayed) / (1.0*total_lines_to_display)); X X len = strlen(display_buffer); X Write_to_screen(display_buffer,0, "", "", ""); X X EndBold(); X okay_char = FALSE; X do { X ch = ReadCh(); X ch = tolower(ch); X switch (ch) { X case '\n' : X case '\r' : /* <return> pressed... */ X lines_put_on_screen -= lines_needed; X okay_char = TRUE; X break; X case ' ' : /* <space> pressed... */ X lines_put_on_screen = 0; X okay_char = TRUE; X break; X case '/' : putchar('/');fflush(stdout); X optionally_enter(pattern,-1,-1,FALSE); X CarriageReturn(); X CleartoEOLN(); X CarriageReturn(); X printf("...searching for pattern \"%s\"...", X pattern); X fflush(stdout); X break; X X case 'i' : X case 'q' : X case 'Q' : return(TRUE); /* get OUTTA here! */ X X default : dprint(2,(debugfile, X "builtin is outta here, returning '%c' [%d]\n", X ch, ch)); X return(ch); X } X } while (! okay_char); X X if (clear_pages && lines_put_on_screen == 0) { /* not for <ret> */ X ClearScreen(); X if (title_messages && filter) { X title_for_page(++pages_displayed); X display_line("\n"); /* blank line for fun */ X } X if (strlen(line_before_that) > 0) { X display_line(line_before_that); X display_line(last_line); X } X else if (strlen(last_line) > 0) X display_line(last_line); X } X else { X CarriageReturn(); /* back up to the beginning of line */ X CleartoEOLN(); X CarriageReturn(); X } X } X else if (lines_needed + lines_put_on_screen > LINES-5) { X strcpy(line_before_that, last_line); X strcpy(last_line, line); X } X X Write_to_screen("%s", 1, line); X X lines_put_on_screen += lines_needed; /* read from file */ X X return (FALSE); X} X Xtitle_for_page(page) Xint page; X{ X /** output a nice title for the second thru last pages of the message X we're currently reading... **/ X X char *p, title[SLEN], title2[SLEN], from_buffer[50], from_buffer2[50]; X register int padding, sl, mail_sent; X X strncpy(from_buffer, header_table[current-1].from, 50); X X tail_of(from_buffer, from_buffer2, TRUE); X X mail_sent = (strncmp(header_table[current-1].from, "To:", 3) == 0); X X sprintf(title, "%s #%d %s %s", X header_table[current-1].status&FORM_LETTER ? "Form" : "Message", X current, X mail_sent? "to" : "from", from_buffer2); X X padding = COLUMNS - (sl = strlen(title)) - X (page < 10 ? 7 : page < 100 ? 8 : 9); X X p = title + sl; X while (padding-- > 0) X *p++ = ' '; X *p = '\0'; X X sprintf(title2, " Page %d\n", page); X X strcat(title, title2); X X display_line(title); X} SHAR_EOF chmod 0444 src/builtin.c || echo "restore of src/builtin.c fails" echo "x - extracting src/calendar.c (Text)" sed 's/^X//' << 'SHAR_EOF' > src/calendar.c && X Xstatic char rcsid[] = "@(#)$Id: calendar.c,v 2.1 88/07/21 09:58:00 edc Exp $"; X X/******************************************************************************* X * The Elm Mail System - $Revision: 2.1 $ $State: Exp $ X * X * Copyright (c) 1986 Dave Taylor X ******************************************************************************* X * Bug reports, patches, comments, suggetions should be sent to: X * X * Syd Weinstein, Elm Corrdinator X * syd@dsinc.UUCP dsinc!syd X * X ******************************************************************************* X * $Log: calendar.c,v $ X * Revision 2.1 88/07/21 09:58:00 edc X * checked in with -k by syd at 88.09.15.20.27.38. X * X * Revision 2.1 88/07/21 09:58:00 edc X * Final hacks and cleanup to the 2.1 alpha test release. X * X * Revision 2.0 88/06/27 17:24:51 edc X * The original 2.0 gamma sources as leaked from HP X * X * X * X ******************************************************************************/ X X/** This routine implements a rather snazzy idea suggested by Warren X Carithers of the Rochester Institute of Technology that allows X mail to contain entries formatted in a manner that will allow direct X copying into a users calendar program. X X Never able to leave good-enough alone, I've extended this idea to a X further one - the knowledge of a different type of calendar program X too. Specifically, the current message can contain either of; X X -> Mon 04/21 1:00p meet with chairman candidate X X or X X - >April 21 X - X - 1:00 pm: Meet with Chairman Candidate X - X X The first type will have the leading '->' removed and all subsequent X white space, creating a simple one-line entry in the users calendar X file. The second type will remove the '-' and the leading white X spaces and leave everything else intact (that is, the file in the X second example would be appended with ">April 21" followed by a X blank line, the 1:00 pm meeting info, and another blank line. X X The file to include this in is either the default as defined in the X sysdefs.h file (see CALENDAR_FILE) or a filename contained in the X users ".elm/elmrc" file, "calendar= <filename>". X X**/ X X#include "headers.h" X X#ifdef ENABLE_CALENDAR /* if not defined, this will be an empty file */ X X#include <errno.h> X Xextern int errno; X Xchar *error_name(), *error_description(), *strcpy(); X Xscan_calendar() X{ X FILE *calendar; X int count; X X /* First step is to open the celendar file for appending... **/ X X if (can_open(calendar_file, "a") != 0) { X dprint(2, (debugfile, X "Error: wrong permissions to append to calendar %s\n", X calendar_file)); X dprint(2, (debugfile, "** %s - %s **\n", X error_name(errno), error_description(errno))); X error1("Not able to append to file %s!", calendar_file); X return; X } X X if ((calendar = fopen(calendar_file,"a")) == NULL) { X dprint(2, (debugfile, X "Error: couldn't append to calendar file %s (scan)\n", X calendar_file)); X dprint(2, (debugfile, "** %s - %s **\n", X error_name(errno), error_description(errno))); X error1("Couldn't append to file %s!", calendar_file); X return; X } X X count = extract_info(calendar); X X fclose(calendar); X X chown(calendar_file, userid, groupid); /* ensure owned by user */ X X if (count > 0) X error2("%d entr%s saved in calendar file", X count, count > 1 ? "ies" : "y"); X else X error("No calendar entries found in that message"); X X return; X} X Xint Xextract_info(save_to_fd) XFILE *save_to_fd; X{ X /** Save the relevant parts of the current message to the given X calendar file. The only parameter is an opened file X descriptor, positioned at the end of the existing file **/ X X register int entries = 0, ok = 1, lines, index, in_entry = FALSE; X char buffer[SLEN]; X X /** get to the first line of the message desired **/ X X if (fseek(mailfile, header_table[current-1].offset, 0) == -1) { X dprint(1,(debugfile, X "ERROR: Attempt to seek %d bytes into file failed (%s)", X header_table[current-1].offset, "extract_info")); X error1("ELM [seek] failed trying to read %d bytes into file", X header_table[current-1].offset); X return(0); X } X X /* how many lines in message? */ X X lines = header_table[current-1].lines; X X /* now while not EOF & still in message... scan it! */ X X while (ok && lines--) { X ok = (int) (fgets(buffer, LONG_SLEN, mailfile) != NULL); X X /* now let's see if it matches the basic pattern... */ X X if ((index = calendar_line(buffer)) > -1) { X X if (buffer[index] == '>') { /* single line entry */ X if (remove_through_ch(buffer, '>')) { X fprintf(save_to_fd,"%s", buffer); X entries++; X } X } X else { /* multi-line entry */ X fprintf(save_to_fd, "%s", (char *) (buffer + index + 1)); X in_entry = TRUE; X } X } X else if (in_entry) { X in_entry = FALSE; X entries++; X } X } X X dprint(4,(debugfile, X "Got %d calender entr%s.\n", entries, entries > 1? "ies":"y")); X X return(entries); X} X Xint Xcalendar_line(string) Xchar *string; X{ X /** Iff the input line is of the form; X X {white space} <one or more '-'> X X this routine will return the index of the NEXT character X after the dashed sequence...If this pattern doesn't occur, X or if any other problems are encountered, it'll return "-1" X **/ X X register int loc = 0; X X if (chloc(string,'-') == -1) /* no dash??? */ X return(-1); /* that was easy! */ X X /** skip leading white space... **/ X X while (whitespace(string[loc])) loc++; /* MUST have '-' too! */ X X if (string[loc] != '-') return(-1); /* nice try, sleazo! */ X X while (string[loc] == '-') loc++; X X if (loc >= strlen(string)) return(-1); /* Empty line... */ X X /* otherwise.... */ X X return(loc); X} X X Xint Xremove_through_ch(string, ch) Xchar *string; Xchar ch; X{ X /** removes all characters from zero to ch in the string, and X any 'white-space' following the 'n'th char... if it hits a X NULL string, it returns FALSE, otherwise it'll return TRUE! X **/ X X char buffer[SLEN]; X register int index = 0, i = 0; X X while (string[index] != ch && string[index] != '\0') X index++; X X if (index >= strlen(string)) X return(FALSE); /* crash! burn! */ X X index++; /* get past the 'ch' character... */ X X while (whitespace(string[index])) index++; X X while (index < strlen(string)) X buffer[i++] = string[index++]; X X buffer[i] = '\0'; X X strcpy(string, buffer); X X return(TRUE); X} X X#endif SHAR_EOF chmod 0444 src/calendar.c || echo "restore of src/calendar.c fails" echo "x - extracting src/conn_to.c (Text)" sed 's/^X//' << 'SHAR_EOF' > src/conn_to.c && X Xstatic char rcsid[] = "@(#)$Id: conn_to.c,v 2.1 88/07/21 09:58:03 edc Exp $"; X X/******************************************************************************* X * The Elm Mail System - $Revision: 2.1 $ $State: Exp $ X * X * Copyright (c) 1986 Dave Taylor X ******************************************************************************* X * Bug reports, patches, comments, suggetions should be sent to: X * X * Syd Weinstein, Elm Corrdinator X * syd@dsinc.UUCP dsinc!syd X * X ******************************************************************************* X * $Log: conn_to.c,v $ X * Revision 2.1 88/07/21 09:58:03 edc X * checked in with -k by syd at 88.09.15.20.27.40. X * X * Revision 2.1 88/07/21 09:58:03 edc X * Final hacks and cleanup to the 2.1 alpha test release. X * X * Revision 2.0 88/06/27 17:24:52 edc X * The original 2.0 gamma sources as leaked from HP X * X * X * X ******************************************************************************/ X X/** This contains the routine(s) needed to have the Elm mailer figure SHAR_EOF echo "End of part 9" echo "File src/conn_to.c is continued in part 10" echo "10" > s2_seq_.tmp exit 0 -- ===================================================================== Sydney S. Weinstein, CDP, CCP Elm Coordinator Datacomp Systems, Inc. Voice: (215) 947-9900 {allegra,bellcore,bpa,vu-vlsi}!dsinc!syd FAX: (215) 938-0235