home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Spezial / SPEZIAL2_97.zip / SPEZIAL2_97.iso / ANWEND / ONLINE / ELM23-2 / ELM23-2.ZIP / utils / newalias.c < prev    next >
C/C++ Source or Header  |  1992-03-29  |  18KB  |  662 lines

  1.  
  2. static char rcsid[] = "@(#)$Id: newalias.c,v 4.1.1.4 91/01/07 20:34:11 syd Exp $";
  3.  
  4. /*******************************************************************************
  5.  *  The Elm Mail System  -  $Revision: 4.1.1.4 $   $State: Exp $
  6.  *
  7.  *             Copyright (c) 1986, 1987 Dave Taylor
  8.  *             Copyright (c) 1988, 1989, 1990 USENET Community Trust
  9.  *******************************************************************************
  10.  * Bug reports, patches, comments, suggestions should be sent to:
  11.  *
  12.  *    Syd Weinstein, Elm Coordinator
  13.  *    elm@DSI.COM            dsinc!elm
  14.  *
  15.  *******************************************************************************
  16.  * $Log:    newalias.c,v $
  17.  * Revision 4.1.1.4  91/01/07  20:34:11  syd
  18.  * Fix missed j=0 assign in newalias
  19.  * From: Shawn Shealy  <shawn@Columbia.NCR.COM>
  20.  *
  21.  * Revision 4.1.1.3  90/12/06  10:23:22  syd
  22.  * Prevent newalias from trying to process lines without two = signs
  23.  * From: Syd via report from integow!ronald
  24.  *
  25.  * Revision 4.1.1.2  90/08/02  21:57:58  syd
  26.  * The newly introduced function 'stricmp' has a name conflict with a libc
  27.  * function under SunOS 4.1.  Changed name to istrcmp.
  28.  * From: scs@lokkur.dexter.mi.us (Steve Simmons)
  29.  *
  30.  * Revision 4.1.1.1  90/06/05  21:11:20  syd
  31.  * alias command in ELM2.3 fails because of the wrong sized aliases.hash
  32.  * newalias did not truncate existing file (aliases.hash)
  33.  * From: Toshinori Maeno <tmaeno@cc.titech.ac.jp>
  34.  *
  35.  * Revision 4.1  90/04/28  22:44:46  syd
  36.  * checkin of Elm 2.3 as of Release PL0
  37.  *
  38.  *
  39.  ******************************************************************************/
  40.  
  41. /** Install a new set of aliases for the 'Elm' mailer.
  42.  
  43.     If invoked with a specific filename, it assumes that
  44.   it is working with an individual users alias tables, and
  45.   generates the .alias.hash and .alias.data files in their
  46.   home directory.
  47.     If, however, it is invoked with no arguments, then
  48.   it assumes that the user is updating the system alias
  49.   file and uses the defaults for everything.
  50.  
  51.   The format for the input file is;
  52.     alias1, alias2, ... = username = address
  53. or  alias1, alias2, ... = groupname= member, member, member, ...
  54.                                      member, member, member, ...
  55.  
  56. **/
  57.  
  58. #include <stdio.h>
  59. #include "defs.h"
  60. #include <ctype.h>
  61. #include <pwd.h>
  62.  
  63. #ifdef BSD
  64. #  include <sys/file.h>
  65. #  undef tolower
  66. #  undef toupper
  67. #else
  68. #  include <fcntl.h>
  69. #endif
  70.  
  71. static char ident[] = { WHAT_STRING };
  72.  
  73. #define group(string)        (strpbrk(string,", ") != NULL)
  74.  
  75. struct alias_rec
  76. shash_table[MAX_SALIASES];    /* the actual hash table     */
  77.  
  78. struct alias_rec
  79. uhash_table[MAX_UALIASES];    /* the actual hash table     */
  80.  
  81. int  hash_table_loaded=0;    /* is system table actually loaded? */
  82.  
  83. int  buff_loaded;        /* for file input overlap... */
  84. int  error= 0;            /* if errors, don't save!    */
  85. int  is_system=0;        /* system file updating?     */
  86. int  count=0;            /* how many aliases so far?  */
  87. long offset = 0L;        /* data file line offset!    */
  88.  
  89. struct passwd *getpwuid();
  90. struct passwd *pass;
  91. char home[SLEN];        /* the users home directory  */
  92.  
  93. main(argc, argv)
  94. int argc;
  95. char *argv[];
  96. {
  97.     FILE *in, *data;
  98.     char inputname[SLEN], hashname[SLEN], dataname[SLEN];
  99.     char buffer[LONG_STRING];
  100.     int  a, hash, count = 0, owner;
  101.  
  102.         initpaths();
  103.  
  104.     for (a = 1; a < argc; ++a) {
  105.       if (strcmp(argv[a], "-g") == 0)
  106.         is_system = 1;
  107.       else {
  108.         printf("\nUsage: %s [-g]\n", argv[0]);
  109.         exit(1);
  110.       }
  111.     }
  112.  
  113.     if (is_system) {   /* update system aliases */
  114.       printf("\nUpdating the system alias file...\n");
  115.  
  116.       sprintf(inputname, "%s/%s", elmhome, system_text_file);
  117.       sprintf(hashname, "%s/%s", elmhome, system_hash_file);
  118.       sprintf(dataname, "%s/%s", elmhome, system_data_file);
  119.  
  120.       init_table(shash_table, MAX_SALIASES);
  121.     }
  122.     else
  123.       printf("\nUpdating your personal alias file...\n");
  124.  
  125.     if (! is_system) {
  126.       if((pass = getpwuid(getuid())) == NULL) {
  127.         printf("You have no password entry!\n");
  128.         exit(1);
  129.       }
  130.       strcpy(home, pass->pw_dir);
  131.  
  132.       sprintf(inputname, "%s/%s", home, ALIAS_TEXT);
  133.       sprintf(hashname, "%s/%s", home, ALIAS_HASH);
  134.       sprintf(dataname, "%s/%s", home, ALIAS_DATA);
  135.  
  136.       init_table(uhash_table, MAX_UALIASES);
  137.  
  138.       read_in_system(shash_table, sizeof shash_table);
  139.     }
  140.  
  141.     if ((in = fopen(inputname,"r")) == NULL) {
  142.       /** let's see if they have the files in the old place... **/
  143.       sprintf(buffer, "%s/.alias_text", home);
  144.       if (access(buffer, ACCESS_EXISTS) != -1) {
  145.         update_alias_file_locations();
  146.         in = fopen(inputname, "r");
  147.       }
  148.       else {
  149.         printf("Couldn't open %s for input!\n", inputname);
  150.         exit(1);
  151.       }
  152.     }
  153.  
  154.     if ((hash = open(hashname, O_WRONLY  | O_BINARY | O_TRUNC | O_CREAT, 0644)) == -1) {
  155.       printf("Couldn't open %s for output!\n", hashname);
  156.       exit(1);
  157.     }
  158.  
  159.     if ((data = fopen(dataname,"wb")) == NULL) {
  160.       printf("Couldn't open %s for output!\n", dataname);
  161.       exit(1);
  162.     }
  163.  
  164.     buff_loaded = 0;     /* file buffer empty right now! */
  165.  
  166.     while (get_alias(in, buffer) != -1) {
  167.       if (is_system)
  168.         put_alias(data, buffer, shash_table, MAX_SALIASES);
  169.       else
  170.         put_alias(data, buffer, uhash_table, MAX_UALIASES);
  171.       count++;
  172.     }
  173.  
  174.     if (error) {
  175.       printf("\n** Not saving tables!  Please fix and re-run %s!\n",
  176.          argv[0]);
  177.       exit(1);
  178.     }
  179.     else {
  180.       if (is_system)
  181.         write(hash, shash_table, sizeof shash_table);
  182.       else
  183.         write(hash, uhash_table, sizeof uhash_table);
  184.  
  185.       close(hash);
  186.       fclose(data);
  187.       fclose(in);
  188.  
  189.       printf("Processed %d aliases\n", count);
  190.       exit(0);
  191.     }
  192. }
  193.  
  194. int
  195. get_alias(file, buffer)
  196. FILE *file;
  197. char *buffer;
  198. {
  199.     /* load buffer with the next complete alias from the file.
  200.        (this can include reading in multiple lines and appending
  201.        them all together!)  Returns EOF after last entry in file.
  202.  
  203.     Lines that start with '#' are assumed to be comments and are
  204.      ignored.  White space as the first field of a line is taken
  205.     to indicate that this line is a continuation of the previous. */
  206.  
  207.     static char mybuffer[SLEN];
  208.     int    done = 0, first_read = 1;
  209.  
  210.     /** get the first line of the entry... **/
  211.  
  212.     buffer[0] = '\0';            /* zero out line */
  213.  
  214.     do {
  215.       if (get_line(file, mybuffer, first_read) == -1)
  216.         return(-1);
  217.       first_read = 0;
  218.       if (mybuffer[0] != '#')
  219.         strcpy(buffer, mybuffer);
  220.     } while (strlen(buffer) == 0);
  221.  
  222.     /** now read in the rest (if there is any!) **/
  223.  
  224.     do {
  225.       if (get_line(file, mybuffer, first_read) == -1) {
  226.         buff_loaded = 0;    /* force a read next pass! */
  227.         return(0);    /* okay. let's just hand 'buffer' back! */
  228.       }
  229.       done = (! whitespace(mybuffer[0]));
  230.       if (! done)
  231.         strcat(buffer, mybuffer);
  232.       done = (done && mybuffer[0] != '#');
  233.     } while (! done);
  234.  
  235.     return(0);    /* no sweat! */
  236. }
  237.  
  238. put_alias(data, buffer, table, size)
  239. FILE *data;
  240. char *buffer;
  241. struct alias_rec table[];
  242. int  size;
  243. {
  244.     /** break buffer down into three pieces: aliases, comment, and address.
  245.         Make the appropriate entries in the table (size)
  246.     **/
  247.  
  248.     char aliases[LONG_STRING], address[LONG_STRING];
  249.     char comment[LONG_STRING], c;
  250.     int  first, last, i, j;
  251.  
  252.     /* check for two = signs */
  253.     for (i = 0, j = 0; buffer[i]; i++)
  254.         if (buffer[i] == '=')
  255.         j++;
  256.  
  257.     if (j < 2) {
  258.         printf("Error - alias data line is not in proper format:\n'%s'\n", buffer);
  259.         error++;
  260.         return;
  261.     }
  262.  
  263.     remove_all(' ', TAB, buffer);
  264.  
  265.     for (i=0; buffer[i] != '=' && i < LONG_STRING; i++)
  266.       aliases[i] = buffer[i];
  267.     aliases[i] = '\0';
  268.  
  269.     for (i=strlen(buffer)-1, j = 0; buffer[i] != '=' && i > 0; i--)
  270.       address[j++] = buffer[i];
  271.     address[j] = '\0';
  272.  
  273.     comment[0] = '\0';    /* default to nothing at all... */
  274.  
  275.     if ((first=strlen(aliases)+1) < (last=(strlen(buffer) - j))) {
  276.       extract_comment(comment, buffer, first, last);
  277.     }
  278.  
  279.     reverse(address);
  280.  
  281.     add_to_table(data, aliases, comment, address, table, size);
  282. }
  283.  
  284. int
  285. get_line(file, buffer, first_line)
  286. FILE *file;
  287. char *buffer;
  288. int  first_line;
  289. {
  290.     /** read line from file.  If first_line and buff_loaded,
  291.         then just return! **/
  292.  
  293.     int stat, len;
  294.  
  295.     if (first_line && buff_loaded) {
  296.       buff_loaded = 1;
  297.       return(0);
  298.     }
  299.  
  300.     buff_loaded = 1;    /* we're going to get SOMETHING in the buffer */
  301.  
  302.     stat = fgets(buffer, SLEN, file) == NULL ? -1 : 0;
  303.  
  304.     if (stat != -1) {
  305.       len = strlen(buffer);
  306.       if (len > 0) {
  307.         if (buffer[len - 1] != '\n') {
  308.           printf("Line too long, split using continuation line format (starting line\nwith whitespace):\n%s\n\n", buffer);
  309.           exit(1);
  310.         }
  311.       }
  312.       no_ret(buffer);
  313.     }
  314.  
  315.     return(stat);
  316. }
  317.  
  318. reverse(string)
  319. char *string;
  320. {
  321.     /** reverse the order of the characters in string...
  322.         uses a bubble-sort type of algorithm!                 **/
  323.  
  324.     register int f, l;
  325.     char     c;
  326.  
  327.     f = 0;
  328.     l = strlen(string) - 1;
  329.  
  330.     while (f < l) {
  331.       c = string[f];
  332.        string[f] = string[l];
  333.       string[l] = c;
  334.       f++;
  335.       l--;
  336.     }
  337. }
  338.  
  339. add_to_table(data, aliases, comment, address, table, size)
  340. FILE *data;
  341. char *aliases, *comment, *address;
  342. struct alias_rec table[];
  343. int  size;
  344. {
  345.     /** add address + comment to datafile, incrementing offset count
  346.         (bytes), then for each alias in the aliases string, add to the
  347.         hash table, with the associated pointer value! **/
  348.  
  349.     static char buf[SLEN], *word, *s;
  350.     long additive = 1L;
  351.  
  352.     word = buf;    /* use the allocated space! */
  353.  
  354.     for ( s = aliases ; *s != '\0' && (ok_alias_char(*s)||*s==',') ; ++s ) ;
  355.     if ( *s != '\0' ) {
  356.       printf("Error - character '%c' in alias '%s' is not supported.\n",
  357.         *s, aliases);
  358.       error++;
  359.       return;
  360.     }
  361.  
  362.     if (group(address)) {
  363.       check_group(address, aliases);
  364.       if (error) return;    /* don't do work if we aren't to save it! */
  365.       fprintf(data, "!%s\n", address);
  366.       additive = 2L;
  367.     }
  368.     else {
  369.       if (error) return;    /* don't do work if we aren't to save it! */
  370.       if (strlen(comment) > 0) {
  371.         fprintf(data, "%s (%s)\n", address, comment);
  372.         additive = (long) (strlen(comment) + 4);
  373.       }
  374.       else
  375.         fprintf(data, "%s\n", address, comment);
  376.     }
  377.  
  378.     while ((word = (char *) strtok(aliases,", ")) != NULL) {
  379.       add_to_hash_table(word, offset, table, size);
  380.       aliases = NULL;    /* let's get ALL entries via 'strtok' */
  381.       count++;
  382.     }
  383.  
  384.     if ( is_system ? count > MAX_SALIASES-35 : count > MAX_UALIASES-21) {
  385.       printf("** Too many aliases in file! **\n");
  386.       error++;
  387.     }
  388.  
  389.     offset = (offset + (long) strlen(address) + additive);
  390. }
  391.  
  392. remove_all(c1, c2, string)
  393. char c1, c2, *string;
  394. {
  395.     /* Remove all occurances of character 'c1' or 'c2' from the string.
  396.        Hacked (literally) to NOT remove ANY characters from within the
  397.        equals fields.  This will only be used if the line contains TWO
  398.        equalss (and comments with equalss in them are the kiss of death!)
  399.      */
  400.  
  401.     char buffer[LONG_STRING];
  402.     register int i = 0, j = 0, first_equals = -1, last_equals = -1;
  403.  
  404.     for (i = 0; string[i] != '\0' && i < LONG_STRING; i++) {
  405.       if (string[i] != c1 && string[i] != c2)
  406.         buffer[j++] = string[i];
  407.  
  408.       if (first_equals == -1 && string[i] == '=') {
  409.         first_equals = i;
  410.         for (last_equals=strlen(string);string[last_equals] != '=';
  411.         last_equals--) ;
  412.       }
  413.       else if (i > first_equals && i < last_equals)
  414.        if (string[i] == c1 || string[i] == c2)
  415.          buffer[j++] = string[i];
  416.     }
  417.  
  418.     buffer[j] = '\0';
  419.     strcpy(string, buffer);
  420. }
  421.  
  422. add_to_hash_table(word, offset, table, size)
  423. char *word;
  424. long  offset;
  425. struct alias_rec table[];
  426. int   size;
  427. {
  428.     /** add word and offset to current hash table. **/
  429.     register int loc;
  430.  
  431.     if (strlen(word) > 20) {
  432.       printf("Bad alias name: %s.  Too long.\n", word);
  433.       exit(1);
  434.     }
  435.  
  436.     loc = hash_it(word, size);
  437.  
  438.     while (table[loc].name[0] != '\0' && istrcmp(table[loc].name,word) != 0)
  439.       loc = (loc + 1) % size;
  440.  
  441.     if (table[loc].name[0] == '\0') {
  442.       strcpy(table[loc].name, word);
  443.       table[loc].byte = htonl(offset);
  444.     }
  445.     else
  446.       printf("** Duplicate alias '%s' in file.  Multiples ignored.\n",
  447.              word);
  448. }
  449.  
  450. int
  451. istrcmp(s1,s2)
  452. register char *s1, *s2;
  453. {
  454.     /* case insensitive comparison */
  455.     register int d;
  456.     for (;;) {
  457.       d = ( isupper(*s1) ? tolower(*s1) : *s1 )
  458.           - ( isupper(*s2) ? tolower(*s2) : *s2 ) ;
  459.       if ( d != 0 || *s1 == '\0' || *s2 == '\0' )
  460.         return d;
  461.       ++s1;
  462.       ++s2;
  463.     }
  464.     /*NOTREACHED*/
  465. }
  466.  
  467. int
  468. hash_it(string, table_size)
  469. register char *string;
  470. int   table_size;
  471. {
  472.     /** compute the hash function of the string, returning
  473.         it (mod table_size) **/
  474.  
  475.     register int sum = 0;
  476.     for ( ; *string != '\0' ; ++string )
  477.       sum += (int) ( isupper(*string) ? tolower(*string) : *string );
  478.     return(sum % table_size);
  479. }
  480.  
  481.  
  482. init_table(table, size)
  483. struct alias_rec table[];
  484. int size;
  485. {
  486.     /** initialize hash table! **/
  487.  
  488.     register int i;
  489.  
  490.     for (i=0; i < size; i++)
  491.       table[i].name[0] = '\0';
  492. }
  493.  
  494. read_in_system(table, size)
  495. struct alias_rec table[];
  496. int size;
  497. {
  498.     /** read in the system hash table...to check for group aliases
  499.         from the user alias file (to ensure that there are no names
  500.         in the user group files that are not purely contained within
  501.         either alias table) **/
  502.  
  503.     int  fd;
  504.     char fname[SLEN];
  505.  
  506.     sprintf(fname, "%s/%s", mailhome, ALIAS_HASH);
  507.  
  508.     if ((fd = open(fname, O_RDONLY)) == -1)
  509.       return;    /* no sweat: flag 'hash_table_loaded' not set! */
  510.  
  511.     (void) read(fd, table, size);
  512.     close(fd);
  513.     hash_table_loaded++;
  514. }
  515.  
  516. check_group(names, groupname)
  517. char *names, *groupname;
  518. {
  519.     /** one by one make sure each name in the group is defined
  520.         in either the system alias file or the user alias file.
  521.         This search is linearly dependent, so all group aliases
  522.         in the source file should appear LAST, after all the user
  523.         aliases! **/
  524.  
  525.     char *word, *bufptr, buffer[LONG_STRING];
  526.     int aliased;
  527.  
  528.     strcpy(buffer, names);
  529.     bufptr = (char *) buffer;
  530.     names[0] = '\0';
  531.  
  532.     while ((word = (char *) strtok(bufptr,", ")) != NULL) {
  533.       if (! (aliased = can_find(word)))
  534.         if (! valid_name(word)) {
  535.           error++;
  536.           printf("** Alias %s in group %s is bad!\n", word, groupname);
  537.         }
  538.       bufptr = NULL;
  539.       if (names[0])
  540.         strcat(names, ", ");
  541.       strcat(names, word);
  542.     }
  543. }
  544.  
  545. int
  546. can_find(name)
  547. char *name;
  548. {
  549.     /** find name in either hash table...use 'is_system' variable to
  550.         determine if we should look in both or just system....    **/
  551.  
  552.     register int loc;
  553.  
  554.     if (strlen(name) > 20) {
  555.       error++;
  556.       printf("** Bad alias name: %s.  Too long.\n", name);
  557.       return(1);    /* fake out: don't want 2 error messages! */
  558.     }
  559.  
  560.     /** system alias table... **/
  561.     if (hash_table_loaded || is_system) {
  562.       loc = hash_it(name, MAX_SALIASES);
  563.  
  564.       while (istrcmp(name, shash_table[loc].name) != 0 &&
  565.                  shash_table[loc].name[0] != '\0')
  566.         loc = (loc + 1) % MAX_SALIASES;
  567.  
  568.       if (istrcmp(name, shash_table[loc].name) == 0)
  569.         return(1);    /* found it! */
  570.     }
  571.  
  572.     if (! is_system) {    /* okay! Let's check the user alias file! */
  573.       loc = hash_it(name, MAX_UALIASES);
  574.  
  575.       while (istrcmp(name, uhash_table[loc].name) != 0 &&
  576.                  uhash_table[loc].name[0] != '\0')
  577.         loc = (loc + 1) % MAX_UALIASES;
  578.  
  579.       if (istrcmp(name, uhash_table[loc].name) == 0)
  580.         return(1);    /* found it! */
  581.     }
  582.  
  583.     return(0);
  584. }
  585.  
  586. extract_comment(comment, buffer, first, last)
  587. char *comment, *buffer;
  588. int first, last;
  589. {
  590.     /** Buffer contains a comment, located between the first and last
  591.         values.  Copy that into 'comment', but remove leading and
  592.         trailing white space.  Note also that it doesn't copy past
  593.         a comma, so `unpublishable' comments can be of the form;
  594.         dave: Dave Taylor, HP Labs : taylor@hplabs
  595.         and the output will be "taylor@hplabs (Dave Taylor)".
  596.     **/
  597.  
  598.     register int loc = 0;
  599.  
  600.     /** first off, skip the LEADING white space... **/
  601.  
  602.     while (whitespace(buffer[first])) first++;
  603.  
  604.     /** now let's backup the 'last' value until we hit a non-whitespace **/
  605.  
  606.     last -= 2;    /* starts at ch AFTER equals.. */
  607.     while (whitespace(buffer[last])) last--;
  608.  
  609.     /** now a final check to make sure we're still talking about a
  610.         reasonable string (rather than a "joe :: joe@dec" type string) **/
  611.  
  612.     if (first < last) {
  613.       /* one more check - let's find the comma, if present... */
  614.       for (loc=first; loc < last; loc++)
  615.         if (buffer[loc] == ',') {
  616.           last = loc-1;
  617.           break;
  618.       }
  619.       loc = 0;
  620.       while (first <= last)
  621.         comment[loc++] = buffer[first++];
  622.       comment[loc] = '\0';
  623.     }
  624. }
  625.  
  626. update_alias_file_locations()
  627. {
  628.     /** a short-term routine to ensure that the data files are
  629.         moved into the correct directory... **/
  630.  
  631.     char source[SLEN], dest[SLEN];
  632.  
  633.     /** first let's create the directory if it ain't there... **/
  634.  
  635.     sprintf(source, "%s/.elm", home);
  636.  
  637.     /** Some systems don't have a mkdir call - how inconvienient! **/
  638. #ifdef MKDIR
  639.     (void) mkdir(source, 0700);
  640. #else
  641.     system("mkdir $HOME/.elm");
  642.     system("chmod 700 $HOME/.elm");
  643. #endif /* MKDIR */
  644.  
  645.     /** now *link* the files... **/
  646.  
  647.     sprintf(source, "%s/.alias_text", home);
  648.     sprintf(dest,   "%s/%s",          home, ALIAS_TEXT);
  649.     link(source, dest);
  650.  
  651.     sprintf(source, "%s/.alias_hash", home);
  652.     sprintf(dest,   "%s/%s",          home, ALIAS_HASH);
  653.     link(source, dest);
  654.  
  655.     sprintf(source, "%s/.alias_data", home);
  656.     sprintf(dest,   "%s/%s",          home, ALIAS_DATA);
  657.     link(source, dest);
  658.  
  659.     printf("\n*** Moved all data files into %s/.elm directory ***\n\n",
  660.         home);
  661. }
  662.