home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Spezial / SPEZIAL2_97.zip / SPEZIAL2_97.iso / ANWEND / ONLINE / ELM23-2 / ELM23-2.ZIP / utils / answer.c next >
C/C++ Source or Header  |  1996-03-18  |  11KB  |  421 lines

  1.  
  2. static char rcsid[] = "@(#)$Id: answer.c,v 4.1 90/04/28 22:44:27 syd Exp $";
  3.  
  4. /*******************************************************************************
  5.  *  The Elm Mail System  -  $Revision: 4.1 $   $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:    answer.c,v $
  17.  * Revision 4.1  90/04/28  22:44:27  syd
  18.  * checkin of Elm 2.3 as of Release PL0
  19.  *
  20.  *
  21.  ******************************************************************************/
  22.  
  23. /** This program is a phone message transcription system, and
  24.     is designed for secretaries and the like, to allow them to
  25.     painlessly generate electronic mail instead of paper forms.
  26.  
  27.     Note: this program ONLY uses the local alias file, and does not
  28.       even read in the system alias file at all.
  29.  
  30. **/
  31.  
  32. #include <stdio.h>
  33. #include <fcntl.h>
  34. #include <ctype.h>
  35. #include <pwd.h>
  36.  
  37. #include "defs.h"            /* ELM system definitions      */
  38.  
  39. #define  ELM        "elm"        /* where the elm program lives */
  40.  
  41. static char ident[] = { WHAT_STRING };
  42.  
  43. struct alias_rec user_hash_table  [MAX_UALIASES];
  44.  
  45. int user_data;        /* fileno of user data file   */
  46.  
  47. char *expand_group(), *get_alias_address(), *get_token(), *strip_parens(),
  48.     *shift_lower();
  49.  
  50. main()
  51. {
  52.     FILE *fd;
  53.     char *address, buffer[LONG_STRING], tempfile[SLEN], *cp;
  54.     char  name[SLEN], user_name[SLEN];
  55.     int   msgnum = 0, eof;
  56.  
  57.         initpaths();
  58.     read_alias_files();
  59.  
  60.     while (1) {
  61.       if (msgnum > 9999) msgnum = 0;
  62.  
  63.       printf("\n-------------------------------------------------------------------------------\n");
  64.  
  65. prompt:   printf("\nMessage to: ");
  66.       if (fgets(user_name, SLEN, stdin) == NULL) {
  67.         putc('\n', stdout);
  68.         exit(0);
  69.       }
  70.       if(user_name[0] == '\0')
  71.         goto prompt;
  72.  
  73.       cp = &user_name[strlen(user_name)-1];
  74.       if(*cp == '\n') *cp = '\0';
  75.       if(user_name[0] == '\0')
  76.         goto prompt;
  77.  
  78.       if ((strcmp(user_name,"quit") == 0) ||
  79.           (strcmp(user_name,"exit") == 0) ||
  80.           (strcmp(user_name,"done") == 0) ||
  81.           (strcmp(user_name,"bye")  == 0))
  82.          exit(0);
  83.  
  84.       if (translate(user_name, name) == 0)
  85.         goto prompt;
  86.  
  87.       address = get_alias_address(name, 1, 0);
  88.  
  89.       printf("address '%s'\n", address);
  90.  
  91.       if (address == NULL || strlen(address) == 0) {
  92.         printf("Sorry, could not find '%s' [%s] in list!\n", user_name,
  93.            name);
  94.         goto prompt;
  95.       }
  96.  
  97.       sprintf(tempfile, "%s%d.ans", tempdir, msgnum++);
  98.  
  99.       if ((fd = fopen(tempfile,"w")) == NULL)
  100.         exit(printf("** Fatal Error: could not open %s to write\n",
  101.          tempfile));
  102.  
  103.  
  104.       printf("\nEnter message for %s ending with a blank line.\n\n",
  105.          user_name);
  106.  
  107.       fprintf(fd,"\n\n");
  108.  
  109.       do {
  110.        printf("> ");
  111.        if (! (eof = (fgets(buffer, SLEN, stdin) == NULL)))
  112.          fprintf(fd, "%s", buffer);
  113.       } while (! eof && strlen(buffer) > 1);
  114.  
  115.       fclose(fd);
  116.  
  117.       sprintf(buffer,
  118.          "%s -s \"While You Were Out\" %s <%s >nul",
  119.          ELM, strip_parens(address), tempfile);
  120.  
  121.       system(buffer);
  122.           unlink(tempfile);
  123.     }
  124. }
  125.  
  126. int
  127. translate(fullname, name)
  128. char *fullname, *name;
  129. {
  130.     /** translate fullname into name..
  131.            'first last'  translated to first_initial - underline - last
  132.            'initial last' translated to initial - underline - last
  133.         Return 0 if error.
  134.     **/
  135.     register int i, lastname = 0, len;
  136.  
  137.     for (i=0, len = strlen(fullname); i < len; i++) {
  138.  
  139.       if (isupper(fullname[i]))
  140.          fullname[i] = tolower(fullname[i]);
  141.  
  142.       if (fullname[i] == ' ')
  143.         if (lastname) {
  144.           printf(
  145.           "** Can't have more than 'FirstName LastName' as address!\n");
  146.           return(0);
  147.         }
  148.         else
  149.           lastname = i+1;
  150.  
  151.     }
  152.  
  153.     if (lastname)
  154.       sprintf(name, "%c_%s", fullname[0], (char *) fullname + lastname);
  155.     else
  156.       strcpy(name, fullname);
  157.  
  158.     return(1);
  159. }
  160.  
  161.  
  162. read_alias_files()
  163. {
  164.     /** read the user alias file **/
  165.  
  166.     char fname[SLEN];
  167.     int  hash;
  168.         char *getenv();
  169.         struct passwd *getpwuid();
  170.         struct passwd *pass;
  171.         char *homedir, *name;
  172.  
  173.     name = getenv("LOGNAME");
  174.     if((pass = getpwnam(name ? name : "unknown")) == NULL) {
  175.       printf("You have no password entry!\n");
  176.       exit(1);
  177.     }
  178.     homedir = pass->pw_dir;
  179.  
  180.     sprintf(fname,  "%s/%s", homedir, ALIAS_HASH);
  181.  
  182.     if ((hash = open(fname, O_RDONLY)) == -1)
  183.       exit(printf("** Fatal Error: Could not open %s!\n", fname));
  184.  
  185.     read(hash, user_hash_table, sizeof user_hash_table);
  186.     close(hash);
  187.  
  188.     sprintf(fname,  "%s/%s", homedir, ALIAS_DATA);
  189.  
  190.     if ((user_data = open(fname, O_RDONLY)) == -1)
  191.       return;
  192. }
  193.  
  194. char *get_alias_address(name, mailing, depth)
  195. char *name;
  196. int   mailing, depth;
  197. {
  198.     /** return the line from either datafile that corresponds
  199.         to the specified name.  If 'mailing' specified, then
  200.         fully expand group names.  Returns NULL if not found.
  201.         Depth is the nesting depth, and varies according to the
  202.         nesting level of the routine.  **/
  203.  
  204.     static char buffer[VERY_LONG_STRING];
  205.     int    loc;
  206.  
  207.     name = shift_lower(name);
  208.     if ((loc = find(name, user_hash_table, MAX_UALIASES)) >= 0) {
  209.       lseek(user_data, ntohl(user_hash_table[loc].byte), 0L);
  210.       get_line(user_data, buffer);
  211.       if (buffer[0] == '!' && mailing)
  212.         return( (char *) expand_group(buffer, depth));
  213.       else
  214.         return( (char *) buffer);
  215.     }
  216.  
  217.     return( (char *) NULL);
  218. }
  219.  
  220. char *expand_group(members, depth)
  221. char *members;
  222. int   depth;
  223. {
  224.     /** given a group of names separated by commas, this routine
  225.         will return a string that is the full addresses of each
  226.         member separated by spaces.  Depth is the current recursion
  227.         depth of the expansion (for the 'get_token' routine) **/
  228.  
  229.     static char   buffer[VERY_LONG_STRING];
  230.     char   buf[LONG_STRING], *word, *address, *bufptr;
  231.  
  232.     strcpy(buf, members);     /* parameter safety! */
  233.     buffer[0] = '\0';    /* nothing in yet!   */
  234.     bufptr = (char *) buf;    /* grab the address  */
  235.     depth++;        /* one more deeply into stack */
  236.  
  237.     while ((word = (char *) get_token(bufptr, "!, ", depth)) != NULL) {
  238.       if ((address = (char *) get_alias_address(word, 1, depth)) == NULL) {
  239.         fprintf(stderr, "Alias %s not found for group expansion!", word);
  240.         return( (char *) NULL);
  241.       }
  242.       else if (strcmp(buffer,address) != 0) {
  243.         sprintf(buffer,"%s %s", buffer, address);
  244.       }
  245.  
  246.       bufptr = NULL;
  247.     }
  248.  
  249.     return( (char *) buffer);
  250. }
  251.  
  252. int
  253. find(word, table, size)
  254. char *word;
  255. struct alias_rec table[];
  256. int size;
  257. {
  258.     /** find word and return loc, or -1 **/
  259.     register int loc;
  260.  
  261.     if (strlen(word) > 20)
  262.       exit(printf("Bad alias name: %s.  Too long.\n", word));
  263.  
  264.     loc = hash_it(word, size);
  265.  
  266.     while (strcmp(word, table[loc].name) != 0) {
  267.       if (table[loc].name[0] == '\0')
  268.         return(-1);
  269.       loc = (loc + 1) % size;
  270.     }
  271.  
  272.     return(loc);
  273. }
  274.  
  275. int
  276. hash_it(string, table_size)
  277. char *string;
  278. int   table_size;
  279. {
  280.     /** compute the hash function of the string, returning
  281.         it (mod table_size) **/
  282.  
  283.     register int i, sum = 0;
  284.  
  285.     for (i=0; string[i] != '\0'; i++)
  286.       sum += (int) string[i];
  287.  
  288.     return(sum % table_size);
  289. }
  290.  
  291. get_line(fd, buffer)
  292. int fd;
  293. char *buffer;
  294. {
  295.     /* read from file fd.  End read upon reading either
  296.        EOF or '\n' character (this is where it differs
  297.        from a straight 'read' command!) */
  298.  
  299.     register int i= 0;
  300.     char     ch;
  301.  
  302.     while (read(fd, &ch, 1) > 0)
  303.       if (ch == '\n' || ch == '\r') {
  304.         buffer[i] = 0;
  305.         return;
  306.       }
  307.       else
  308.         buffer[i++] = ch;
  309. }
  310.  
  311. print_long(buffer, init_len)
  312. char *buffer;
  313. int   init_len;
  314. {
  315.     /** print buffer out, 80 characters (or less) per line, for
  316.         as many lines as needed.  If 'init_len' is specified,
  317.         it is the length that the first line can be.
  318.     **/
  319.  
  320.     register int i, loc=0, space, length, len;
  321.  
  322.     /* In general, go to 80 characters beyond current character
  323.        being processed, and then work backwards until space found! */
  324.  
  325.     length = init_len;
  326.  
  327.     do {
  328.       if (strlen(buffer) > loc + length) {
  329.         space = loc + length;
  330.         while (buffer[space] != ' ' && space > loc + 50) space--;
  331.         for (i=loc;i <= space;i++)
  332.           putc(buffer[i], stdout);
  333.         putc('\n', stdout);
  334.         loc = space;
  335.       }
  336.       else {
  337.         for (i=loc, len = strlen(buffer);i < len;i++)
  338.           putc(buffer[i], stdout);
  339.         putc('\n', stdout);
  340.         loc = len;
  341.       }
  342.       length = 80;
  343.     } while (loc < strlen(buffer));
  344. }
  345.  
  346. /****
  347.      The following is a newly chopped version of the 'strtok' routine
  348.   that can work in a recursive way (up to 20 levels of recursion) by
  349.   changing the character buffer to an array of character buffers....
  350. ****/
  351.  
  352. #define MAX_RECURSION        20        /* up to 20 deep recursion */
  353.  
  354. #undef  NULL
  355. #define NULL            (char *) 0    /* for this routine only   */
  356.  
  357. extern char *strpbrk();
  358.  
  359. char *get_token(string, sepset, depth)
  360. char *string, *sepset;
  361. int  depth;
  362. {
  363.  
  364.     /** string is the string pointer to break up, sepstr are the
  365.         list of characters that can break the line up and depth
  366.         is the current nesting/recursion depth of the call **/
  367.  
  368.     register char    *p, *q, *r;
  369.     static char    *savept[MAX_RECURSION];
  370.  
  371.     /** is there space on the recursion stack? **/
  372.  
  373.     if (depth >= MAX_RECURSION) {
  374.      fprintf(stderr,"Error: Get_token calls nested greated than %d deep!\n",
  375.             MAX_RECURSION);
  376.      exit(1);
  377.     }
  378.  
  379.     /* set up the pointer for the first or subsequent call */
  380.     p = (string == NULL)? savept[depth]: string;
  381.  
  382.     if(p == 0)        /* return if no tokens remaining */
  383.         return(NULL);
  384.  
  385.     q = p + strspn(p, sepset);    /* skip leading separators */
  386.  
  387.     if (*q == '\0')        /* return if no tokens remaining */
  388.         return(NULL);
  389.  
  390.     if ((r = strpbrk(q, sepset)) == NULL)    /* move past token */
  391.         savept[depth] = 0;    /* indicate this is last token */
  392.     else {
  393.         *r = '\0';
  394.         savept[depth] = ++r;
  395.     }
  396.     return(q);
  397. }
  398.  
  399. char *strip_parens(string)
  400. char *string;
  401. {
  402.     /** Return string with all parenthesized information removed.
  403.         This is a non-destructive algorithm... **/
  404.  
  405.     static char  buffer[LONG_STRING];
  406.     register int depth = 0, buffer_index = 0;
  407.  
  408.     for (; *string; string++) {
  409.       if (*string == '(')
  410.         depth++;
  411.       else if (*string == ')')
  412.         depth--;
  413.       else if (depth == 0)
  414.         buffer[buffer_index++] = *string;
  415.     }
  416.  
  417.     buffer[buffer_index] = '\0';
  418.  
  419.     return( (char *) buffer);
  420. }
  421.