home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Spezial / SPEZIAL2_97.zip / SPEZIAL2_97.iso / ANWEND / ONLINE / ELM23-2 / ELM23-2.ZIP / src / reply.c < prev    next >
C/C++ Source or Header  |  1994-11-05  |  17KB  |  562 lines

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