home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume9 / elm2 / patch02 / reply.c
C/C++ Source or Header  |  1987-04-30  |  14KB  |  490 lines

  1. /**        reply.c        **/
  2.  
  3. /*** routine allows replying to the sender of the current message 
  4.  
  5.      (C) Copyright 1985, Dave Taylor
  6. ***/
  7.  
  8. #include "headers.h"
  9. #include <errno.h>
  10.  
  11. #ifndef BSD
  12. #  include <sys/types.h>
  13. #  include <sys/utsname.h>
  14. #endif
  15.  
  16. /** Note that this routine generates automatic header information
  17.     for the subject and (obviously) to lines, but that these can
  18.     be altered while in the editor composing the reply message! 
  19. **/
  20.  
  21. char *strip_parens(), *get_token();
  22.  
  23. extern int errno;
  24.  
  25. char *error_name(), *strcat(), *strcpy();
  26.  
  27. int
  28. reply()
  29. {
  30.     /** Reply to the current message.  Returns non-zero iff
  31.         the screen has to be rewritten. **/
  32.  
  33.     char return_address[LONG_SLEN], subject[SLEN];
  34.     int  return_value, form_letter;
  35.  
  36.     form_letter = (header_table[current-1].status & FORM_LETTER);
  37.  
  38.     get_return(return_address);
  39.  
  40.     if (first_word(header_table[current-1].from, "To:")) {
  41.       strcpy(subject, header_table[current-1].subject);
  42.       if (form_letter)
  43.         return_value = mail_filled_in_form(return_address, subject);
  44.       else
  45.         return_value = send(return_address, subject, TRUE, NO);
  46.     }
  47.     else if (header_table[current-1].subject[0] != '\0') {
  48.       if ((strncmp("Re:", header_table[current-1].subject, 3) == 0) ||
  49.           (strncmp("RE:", header_table[current-1].subject, 3) == 0) ||
  50.           (strncmp("re:", header_table[current-1].subject, 3) == 0)) 
  51.         strcpy(subject, header_table[current-1].subject);
  52.       else {
  53.         strcpy(subject,"Re: ");
  54.         strcat(subject,header_table[current-1].subject); 
  55.       }
  56.       if (form_letter)
  57.         return_value = mail_filled_in_form(return_address, subject);
  58.       else
  59.         return_value = send(return_address, subject, TRUE, NO);
  60.     }
  61.     else
  62.       if (form_letter)
  63.         return_value = mail_filled_in_form(return_address, 
  64.                         "Filled in Form");
  65.       else
  66.         return_value = send(return_address, "Re: your mail", TRUE, NO);
  67.  
  68.     return(return_value);
  69. }
  70.  
  71. int
  72. reply_to_everyone()
  73. {
  74.     /** Reply to everyone who received the current message.  
  75.         This includes other people in the 'To:' line and people
  76.         in the 'Cc:' line too.  Returns non-zero iff the screen 
  77.             has to be rewritten. **/
  78.  
  79.     char return_address[LONG_SLEN], subject[SLEN];
  80.     char full_address[VERY_LONG_STRING];
  81.     int  return_value;
  82.  
  83.     get_return(return_address);
  84.  
  85.     strcpy(full_address, return_address);    /* sender gets copy */
  86.     
  87.     get_and_expand_everyone(return_address, full_address);
  88.  
  89.     if (header_table[current-1].subject[0] != '\0') {
  90.       if ((strncmp("Re:", header_table[current-1].subject, 3) == 0) ||
  91.           (strncmp("RE:", header_table[current-1].subject, 3) == 0) ||
  92.           (strncmp("re:", header_table[current-1].subject, 3) == 0)) 
  93.         strcpy(subject, header_table[current-1].subject);
  94.       else {
  95.         strcpy(subject,"Re: ");
  96.         strcat(subject,header_table[current-1].subject); 
  97.       }
  98.       return_value = send(full_address, subject, TRUE, NO);
  99.     }
  100.     else
  101.       return_value = send(full_address, "Re: your mail", TRUE, NO);
  102.  
  103.     return(return_value);
  104.  
  105. }
  106.  
  107. int
  108. forward()
  109. {
  110.     /** Forward the current message.  What this actually does is
  111.         to set auto_copy to true, then call 'send' to get the 
  112.         address and route the mail. 
  113.     **/
  114.  
  115.     char subject[SLEN], address[VERY_LONG_STRING];
  116.     int  original_cc, results, edit_msg = FALSE;
  117.  
  118.     original_cc = auto_copy;
  119.     address[0] = '\0';
  120.  
  121.     if (header_table[current-1].status & FORM_LETTER)
  122.       PutLine0(LINES-3,COLUMNS-40,"<no editing allowed>");
  123.     else {
  124.       edit_msg = (want_to("Edit outgoing message (y/n) ? ",'y',FALSE)!='n');
  125.       Write_to_screen("%s", 1, edit_msg? "Yes" : "No");
  126.     }
  127.  
  128.     auto_cc = TRUE;            /* we want a copy */
  129.  
  130.     if (strlen(header_table[current-1].subject) > 0) {
  131.       strcpy(subject,header_table[current-1].subject); 
  132.       results = send(address, subject, edit_msg,
  133.         header_table[current-1].status & FORM_LETTER? 
  134.         PREFORMATTED : allow_forms);
  135.     }
  136.     else
  137.       results = send(address, "Forwarded Mail...", edit_msg, 
  138.         header_table[current-1].status & FORM_LETTER? 
  139.         PREFORMATTED : allow_forms);
  140.     
  141.     auto_copy = original_cc;
  142.  
  143.     return(results);
  144. }
  145.  
  146. get_and_expand_everyone(return_address, full_address)
  147. char *return_address, *full_address;
  148. {
  149.     /** Read the current message, extracting addresses from the 'To:'
  150.         and 'Cc:' lines.   As each address is taken, ensure that it
  151.         isn't to the author of the message NOR to us.  If neither,
  152.         prepend with current return address and append to the 
  153.         'full_address' string.
  154.     **/
  155.  
  156.     char ret_address[LONG_SLEN], buf[LONG_SLEN], new_address[LONG_SLEN],
  157.      address[LONG_SLEN], comment[LONG_SLEN];
  158.     int  in_message = 1, first_pass = 0, index;
  159.  
  160.     /** First off, get to the first line of the message desired **/
  161.  
  162.     if (fseek(mailfile, header_table[current-1].offset, 0) == -1) {
  163.     dprint3(1,"Error: seek %ld resulted in errno %s (%s)\n", 
  164.          header_table[current-1].offset, error_name(errno), 
  165.          "get_and_expand_everyone");
  166.     error2("ELM [seek] couldn't read %d bytes into file (%s)",
  167.            header_table[current-1].offset, error_name(errno));
  168.     return;
  169.     }
  170.  
  171.     /** okay!  Now we're there!  **/
  172.  
  173.     /** let's fix the ret_address to reflect the return address of this
  174.     message with '%s' instead of the persons login name... **/
  175.  
  176.     translate_return(return_address, ret_address);
  177.  
  178.     /** now let's parse the actual message! **/
  179.  
  180.     while (in_message) {
  181.       in_message = (int) (fgets(buf, LONG_SLEN, mailfile) != NULL);
  182.       if (first_word(buf, "From ") && first_pass++ != 0) 
  183.     in_message = FALSE;
  184.       else if (first_word(buf, "To:") || first_word(buf, "Cc:") ||
  185.            first_word(buf, "CC:") || first_word(buf, "cc:")) {
  186.     do {
  187.       no_ret(buf);
  188.  
  189.       /** we have a buffer with a list of addresses, each of either the
  190.           form "address (name)" or "name <address>".  Our mission, should
  191.           we decide not to be too lazy, is to break it into the two parts.
  192.       **/
  193.           
  194.       if (!whitespace(buf[0]))
  195.         index = chloc(buf, ':')+1;        /* skip header field */
  196.       else
  197.         index = 0;                /* skip whitespace   */
  198.  
  199.       while (break_down_tolist(buf, &index, address, comment)) {
  200.  
  201.         if (okay_address(address, return_address)) {
  202.           sprintf(new_address, ret_address, address);
  203.           optimize_and_add(new_address, full_address);
  204.         }
  205.       }
  206.  
  207.           in_message = (int) (fgets(buf, LONG_SLEN, mailfile) != NULL);
  208.  
  209.       if (in_message) dprint1(1,"> %s", buf);
  210.     
  211.     } while (in_message && whitespace(buf[0]));
  212.  
  213.       }
  214.       else if (strlen(buf) < 2)    /* done with header */
  215.      in_message = FALSE;
  216.     }
  217. }
  218.  
  219. int
  220. okay_address(address, return_address)
  221. char *address, *return_address;
  222. {
  223.     /** This routine checks to ensure that the address we just got
  224.         from the "To:" or "Cc:" line isn't us AND isn't the person    
  225.         who sent the message.  Returns true iff neither is the case **/
  226.  
  227.     char our_address[SLEN];
  228.     struct addr_rec  *alternatives;
  229.  
  230.     if (in_string(address, return_address))
  231.       return(FALSE);
  232.  
  233.     sprintf(our_address, "%s!%s", hostname, username);
  234.  
  235.     if (in_string(address, our_address))
  236.       return(FALSE);
  237.  
  238.     sprintf(our_address, "%s@%s", username, hostname);
  239.       
  240.     if (in_string(address, our_address))
  241.       return(FALSE);
  242.  
  243.     alternatives = alternative_addresses;
  244.  
  245.     while (alternatives != NULL) {
  246.       if (in_string(address, alternatives->address))
  247.         return(FALSE);
  248.       alternatives = alternatives->next;
  249.     }
  250.  
  251.     return(TRUE);
  252. }
  253.         
  254. optimize_and_add(new_address, full_address)
  255. char *new_address, *full_address;
  256. {
  257.     /** This routine will add the new address to the list of addresses
  258.         in the full address buffer IFF it doesn't already occur.  It
  259.         will also try to fix dumb hops if possible, specifically hops
  260.         of the form ...a!b...!a... and hops of the form a@b@b etc 
  261.     **/
  262.  
  263.     register int len, host_count = 0, i;
  264.     char     hosts[MAX_HOPS][SLEN];    /* array of machine names */
  265.     char     *host, *addrptr;
  266.  
  267.     if (in_string(full_address, new_address))
  268.       return(1);    /* duplicate address */
  269.  
  270.     /** optimize **/
  271.     /*  break down into a list of machine names, checking as we go along */
  272.     
  273.     addrptr = (char *) new_address;
  274.  
  275.     while ((host = get_token(addrptr, "!", 1)) != NULL) {
  276.       for (i = 0; i < host_count && ! equal(hosts[i], host); i++)
  277.           ;
  278.  
  279.       if (i == host_count) {
  280.         strcpy(hosts[host_count++], host);
  281.         if (host_count == MAX_HOPS) {
  282.            dprint1(2,
  283.               "Error: hit max_hops limit trying to build return address (%s)\n",
  284.               "optimize_and_add");
  285.            error("Can't build return address - hit MAX_HOPS limit!");
  286.            return(1);
  287.         }
  288.       }
  289.       else 
  290.         host_count = i + 1;
  291.       addrptr = NULL;
  292.     }
  293.  
  294.     /** fix the ARPA addresses, if needed **/
  295.     
  296.     if (chloc(hosts[host_count-1], '@') > -1)
  297.       fix_arpa_address(hosts[host_count-1]);
  298.       
  299.     /** rebuild the address.. **/
  300.  
  301.     new_address[0] = '\0';
  302.  
  303.     for (i = 0; i < host_count; i++)
  304.       sprintf(new_address, "%s%s%s", new_address, 
  305.               new_address[0] == '\0'? "" : "!",
  306.               hosts[i]);
  307.  
  308.     if (full_address[0] == '\0')
  309.       strcpy(full_address, new_address);
  310.     else {
  311.       len = strlen(full_address);
  312.       full_address[len  ] = ',';
  313.       full_address[len+1] = ' ';
  314.       full_address[len+2] = '\0';
  315.       strcat(full_address, new_address);
  316.     }
  317.  
  318.     return(0);
  319. }
  320.  
  321. get_return_name(address, name, shift_lower)
  322. char *address, *name;
  323. int   shift_lower;
  324. {
  325.     /** Given the address (either a single address or a combined list 
  326.         of addresses) extract the login name of the first person on
  327.         the list and return it as 'name'.  Modified to stop at
  328.         any non-alphanumeric character. **/
  329.  
  330.     /** An important note to remember is that it isn't vital that this
  331.         always returns just the login name, but rather that it always
  332.         returns the SAME name.  If the persons' login happens to be,
  333.         for example, joe.richards, then it's arguable if the name 
  334.         should be joe, or the full login.  It's really immaterial, as
  335.         indicated before, so long as we ALWAYS return the same name! **/
  336.  
  337.     /** Another note: modified to return the argument as all lowercase
  338.         always, unless shift_lower is FALSE... **/
  339.  
  340.     char single_address[LONG_SLEN];
  341.     register int i, loc, index = 0;
  342.  
  343.     dprint2(6,"get_return_name called with (%s, <>, shift=%s)\n", 
  344.            address, onoff(shift_lower));
  345.  
  346.     /* First step - copy address up to a comma, space, or EOLN */
  347.  
  348.     for (i=0; address[i] != ',' && ! whitespace(address[i]) && 
  349.          address[i] != '\0'; i++)
  350.       single_address[i] = address[i];
  351.     single_address[i] = '\0';
  352.  
  353.     /* Now is it an ARPA address?? */
  354.  
  355.     if ((loc = chloc(single_address, '@')) != -1) {      /* Yes */
  356.  
  357.       /* At this point the algorithm is to keep shifting our copy 
  358.          window left until we hit a '!'.  The login name is then
  359.              located between the '!' and the first metacharacter to 
  360.          it's right (ie '%', ':' or '@'). */
  361.  
  362.       for (i=loc; single_address[i] != '!' && i > -1; i--)
  363.           if (single_address[i] == '%' || 
  364.               single_address[i] == ':' ||
  365.               single_address[i] == '.' ||    /* no domains */
  366.           single_address[i] == '@') loc = i-1;
  367.     
  368.       if (i < 0 || single_address[i] == '!') i++;
  369.  
  370.       for (index = 0; index < loc - i + 1; index++)
  371.         if (shift_lower)
  372.           name[index] = tolower(single_address[index+i]);
  373.         else
  374.           name[index] = single_address[index+i];
  375.       name[index] = '\0';
  376.     }
  377.     else {    /* easier - standard USENET address */
  378.  
  379.       /* This really is easier - we just cruise left from the end of
  380.          the string until we hit either a '!' or the beginning of the
  381.              line.  No sweat. */
  382.  
  383.       loc = strlen(single_address)-1;     /* last char */
  384.  
  385.       for (i = loc; single_address[i] != '!' && single_address[i] != '.' 
  386.            && i > -1; i--)
  387.          if (shift_lower)
  388.            name[index++] = tolower(single_address[i]);
  389.          else
  390.            name[index++] = single_address[i];
  391.       name[index] = '\0';
  392.       reverse(name);
  393.     }
  394. }
  395.  
  396. int
  397. break_down_tolist(buf, index, address, comment)
  398. char *buf, *address, *comment;
  399. int  *index;
  400. {
  401.     /** This routine steps through "buf" and extracts a single address
  402.         entry.  This entry can be of any of the following forms;
  403.  
  404.         address (name)
  405.         name <address>
  406.         address
  407.     
  408.         Once it's extracted a single entry, it will then return it as
  409.         two tokens, with 'name' (e.g. comment) surrounded by parens.
  410.         Returns ZERO if done with the string...
  411.     **/
  412.  
  413.     char buffer[LONG_STRING];
  414.     register int i, loc = 0;
  415.  
  416.     if (*index > strlen(buf)) return(FALSE);
  417.  
  418.     while (whitespace(buf[*index])) (*index)++;
  419.  
  420.     if (*index > strlen(buf)) return(FALSE);
  421.  
  422.     /** Now we're pointing at the first character of the token! **/
  423.  
  424.     while (buf[*index] != ',' && buf[*index] != '\0')
  425.       buffer[loc++] = buf[(*index)++];
  426.  
  427.     (*index)++;
  428.  
  429.     while (whitespace(buffer[loc])) loc--;    /* remove trailing whitespace */
  430.  
  431.     buffer[loc] = '\0';
  432.  
  433.     if (strlen(buffer) == 0) return(FALSE);
  434.  
  435.     dprint1(5, "\n* got \"%s\"\n", buffer);
  436.  
  437.     if (buffer[loc-1] == ')') {    /*   address (name)  format */
  438.       for (loc = 0;buffer[loc] != '(' && loc < strlen(buffer); loc++)
  439.         /* get to the opening comment character... */ ;
  440.  
  441.       loc--;    /* back up to just before the paren */
  442.       while (whitespace(buffer[loc])) loc--;    /* back up */
  443.  
  444.       /** get the address field... **/
  445.  
  446.       for (i=0; i <= loc; i++)
  447.         address[i] = buffer[i];
  448.       address[i] = '\0';
  449.  
  450.       /** now get the comment field, en toto! **/
  451.  
  452.       loc = 0;
  453.  
  454.       for (i = chloc(buffer, '('); i < strlen(buffer); i++)
  455.         comment[loc++] = buffer[i];
  456.       comment[loc] = '\0';
  457.     }
  458.     else if (buffer[loc-1] == '>') {    /*   name <address>  format */
  459.       dprint0(7, "\tcomment <address>\n");
  460.       for (loc = 0;buffer[loc] != '<' && loc < strlen(buffer); loc++)
  461.         /* get to the opening comment character... */ ;
  462.       while (whitespace(buffer[loc])) loc--;    /* back up */
  463.  
  464.       /** get the comment field... **/
  465.  
  466.       comment[0] = '(';
  467.       for (i=1; i < loc; i++)
  468.         comment[i] = buffer[i-1];
  469.       comment[i++] = ')';
  470.       comment[i] = '\0';
  471.  
  472.       /** now get the address field, en toto! **/
  473.  
  474.       loc = 0;
  475.  
  476.       for (i = chloc(buffer,'<') + 1; i < strlen(buffer) - 1; i++)
  477.         address[loc++] = buffer[i];
  478.     
  479.       address[loc] = '\0';
  480.     }
  481.     else {
  482.       strcpy(address, buffer);
  483.       comment[0] = '\0';
  484.     }
  485.  
  486.     dprint2(5,"-- returning '%s' '%s'\n", address, comment);
  487.  
  488.     return(TRUE);
  489. }
  490.