home *** CD-ROM | disk | FTP | other *** search
/ Tutto per Internet / Internet.iso / soft95 / News / souper95 / smtp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-02-13  |  7.1 KB  |  335 lines

  1. /* $Id$
  2.  *
  3.  * Send mail reply packet using SMTP directly
  4.  */
  5. #include <ctype.h>
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <sys/types.h>
  10. #include <sys/socket.h>
  11. #include <netinet/in.h>
  12. #include <netdb.h>
  13. #ifdef __WIN32__
  14. #include <winsock.h>
  15. #else
  16. #include <unistd.h>
  17. #endif
  18. #include "socket.h"
  19. #include "souper.h"
  20.  
  21. extern char *mailGateway;
  22.  
  23. /* Close SMTP connection and socket */
  24.  
  25. void
  26. smtpClose (int socket)
  27. {
  28.     SockPuts(socket, "QUIT");
  29.     SockClose(socket);
  30. }
  31.  
  32. /* Get a response from the SMTP server and test it
  33. */
  34. static int
  35. getSmtpReply (int socket, char *response)
  36. {
  37.     char buf[BUFSIZ];
  38.  
  39.     do {
  40.     SockGets(socket, buf, BUFSIZ);
  41.     } while (buf[3] == '-');        /* wait until not a continuation */
  42.  
  43.     if (strncmp(buf, response, 3) != 0) {
  44.     fprintf(stderr, "Expecting SMTP %s reply, got %s\n", response, buf);
  45.     }
  46.     return (buf[0] == *response);    /* only first digit really matters */
  47. }
  48.  
  49. /* Open socket and intialize connection to SMTP server. */
  50.  
  51. #ifdef DEBUG
  52. int
  53. smtpConnect (void)
  54. {
  55.     return 1;
  56. }
  57. #else
  58. int
  59. smtpConnect (void)
  60. {
  61.     struct servent *sp;
  62.     int    socket;
  63.     struct sockaddr_in local;
  64.     int addrLen;
  65.     struct hostent *hp;
  66.  
  67.     if ((sp = getservbyname("smtp", "tcp")) == NULL) {
  68.     fprintf(stderr, "smtp/tcp: Unknown service.\n");
  69.     return -1;
  70.     }
  71.  
  72.     if ((socket = Socket(mailGateway, ntohs(sp->s_port))) < 0) {
  73.     fprintf(stderr, "Cannot connect to mail server %s\n", mailGateway);
  74.     return -1;
  75.     }
  76.  
  77.     if (!getSmtpReply(socket, "220")) {
  78.     printf("Disconnecting from %s\n", mailGateway);
  79.     smtpClose(socket);
  80.     return -1;
  81.     }
  82.  
  83.     addrLen = sizeof(local);
  84.     getsockname(socket, (struct sockaddr *)&local, &addrLen);
  85.     hp = gethostbyaddr((const char *)&local.sin_addr, sizeof(local.sin_addr),
  86.     AF_INET);
  87.     if (!hp) {
  88.     printf("Cannot get name for this host's IP address %s\n",
  89.         inet_ntoa(local.sin_addr));
  90.     smtpClose(socket);
  91.     return -1;
  92.     }
  93.     SockPrintf(socket, "HELO %s\r\n", hp->h_name);
  94.     if (!getSmtpReply(socket, "250")) {
  95.     printf("Disconnecting from %s\n", mailGateway);
  96.     smtpClose(socket);
  97.     return -1;
  98.     }
  99.     return socket;
  100. }
  101. #endif
  102.  
  103. /* Extract mail address from the string.
  104.  * Return a pointer to a static buffer containing the address or
  105.  * NULL on an error.
  106.  */
  107. static const char *
  108. extractAddress (const char *src)
  109. {
  110.     static char buf[BUFSIZ];
  111.     char ch, *put;
  112.     const char *get;
  113.     char gotAddress;
  114.  
  115.     gotAddress = 0;
  116.     put = buf;
  117.     if ((get = strchr(src, '<')) != 0) {
  118.     char ch = *++get;
  119.     while (ch != '>' && ch != '\0') {
  120.         *put++ = ch;
  121.         ch = *++get;
  122.     }
  123.     gotAddress = 1;
  124.     } else {
  125.     get = src;
  126.     ch = *get++;
  127.  
  128.     /* Skip leading whitespace. */
  129.     while (ch != '\0' && isspace(ch))
  130.         ch = *get++;
  131.  
  132.     while (ch != '\0') {
  133.         if (isspace(ch)) {
  134.         ch = *get++;
  135.  
  136.         } else if (ch == '(') {
  137.         /* Skip comment. */
  138.         int nest = 1;
  139.         while (nest > 0 && ch != '\0') {
  140.             ch = *get++;
  141.  
  142.             if (ch == '(')
  143.             ++nest;
  144.             else if (ch == ')')
  145.             --nest;
  146.         }
  147.  
  148.         if (ch == ')') {
  149.             ch = *get++;
  150.         }
  151.  
  152.         } else if (ch == '"') {
  153.         /* Copy quoted string. */
  154.         do {
  155.             *put++ = ch;
  156.             ch = *get++;
  157.         } while (ch != '"' && ch != '\0');
  158.  
  159.         if (ch == '"') {
  160.             *put++ = ch;
  161.             ch = *get++;
  162.         }
  163.  
  164.         } else {
  165.         /* Copy address. */
  166.         while (ch != '\0' && ch != '(' && !isspace(ch)) {
  167.             *put++ = ch;
  168.             ch = *get++;
  169.         }
  170.         gotAddress = 1;
  171.         }
  172.     }
  173.     }
  174.  
  175.     if (gotAddress) {
  176.     *put = '\0';
  177.     return buf;
  178.     } else {
  179.     return NULL;
  180.     }
  181. }
  182.  
  183. /* Search for ',' separating addresses.
  184. */
  185. static char *
  186. findAddressSep (char *src)
  187. {
  188.     char ch, matchCh;
  189.  
  190.     ch = *src; 
  191.     while (ch != '\0' && ch != ',') {
  192.         if (ch == '"') {
  193.             matchCh = '"';
  194.         } else if (ch == '(') {
  195.             matchCh = ')';
  196.         } else if (ch == '<') {
  197.             matchCh = '>';
  198.         } else {
  199.             matchCh = '\0';
  200.         }
  201.  
  202.         if (matchCh) {
  203.             do {
  204.                 ch = *(++src);
  205.             } while (ch != '\0' && ch != matchCh);
  206.  
  207.             if (ch == '\0')
  208.                 break;
  209.         }
  210.         ch = *(++src);
  211.     }
  212.  
  213.     return src;
  214. }
  215.     
  216. /* Send RCPT command.
  217. */
  218. static void
  219. sendSmtpRcpt (int socket, const char *buf)
  220. {
  221.     printf("%s: mailing to %s\n", progname, buf);
  222.     SockPrintf(socket, "RCPT TO:<%s>\r\n", buf);
  223.     getSmtpReply(socket, "250");
  224. }
  225.  
  226. /* Send an RCPT command for each address in the address list.
  227. */
  228. static void
  229. putAddresses (int socket, char *addresses)
  230. {
  231.     char *srcEnd, *startAddr, *endAddr, saveCh;
  232.     const char *addr;
  233.     
  234.     srcEnd = strchr(addresses, '\0');
  235.     startAddr = addresses;
  236.  
  237.     while (startAddr < srcEnd) {
  238.     endAddr = findAddressSep(startAddr);
  239.     saveCh = *endAddr;
  240.     *endAddr = '\0';
  241.     addr = extractAddress(startAddr);
  242.     if (addr) {
  243.         sendSmtpRcpt(socket, addr);
  244.     }
  245.     *endAddr = saveCh;
  246.     startAddr = endAddr + 1;
  247.     }
  248. }
  249.  
  250. /* Send message to SMTP server.  Return TRUE if successful.
  251.  */
  252. int
  253. smtpMail (int socket, FILE *fd, size_t bytes)
  254. {
  255.     const char *addr;
  256.     char buf[BUFSIZ], *addrs, ch;
  257.     char *from, *resentTo, *s;
  258.     char more;
  259.     long offset;
  260.     size_t count;
  261.  
  262.     /* Look for From header and send MAIL command to SMTP server. */
  263.     from = getHeader(fd, "From");
  264.     if (from == NULL || (addr = extractAddress(from)) == NULL) {
  265.     puts("No address in From header");
  266.     return 0;
  267.     }
  268.     printf("%s: mailing from %s\n", progname, addr);
  269.     SockPrintf(socket, "MAIL FROM:<%s>\r\n", addr);
  270.     free(from);
  271.     if (!getSmtpReply(socket, "250")) {
  272.     return 0;
  273.     }
  274.  
  275.     offset = ftell(fd);
  276.     if ((resentTo = getHeader(fd, "Resent-To")) != NULL) {
  277.     /* Send to address on Resent-To header. */
  278.     putAddresses(socket, resentTo);
  279.     free(resentTo);
  280.     } else {
  281.     /* Send to addresses on To, Cc and Bcc headers. */
  282.     more = fgets(buf, sizeof(buf), fd) != 0;
  283.     while (more) {
  284.         if (buf[0] == '\n')
  285.         break;
  286.  
  287.         if (isHeader(buf, "To", 2) || isHeader(buf, "Cc", 2)
  288.          || isHeader(buf, "Bcc", 3))
  289.         {
  290.         addrs = buf;
  291.         while (*addrs != '\0' && !isspace(*addrs)) {
  292.             ++addrs;
  293.         }
  294.         putAddresses(socket, addrs);
  295.  
  296.         /* Read next line and check if it is a continuation line. */
  297.         while ((more = fgets(buf, sizeof(buf), fd) != 0) != 0) {
  298.             ch = buf[0];
  299.             if (ch == '\n' || (ch != ' ' && ch != '\t'))
  300.             break;
  301.             putAddresses(socket, buf);
  302.         }
  303.  
  304.         continue;
  305.         }
  306.     
  307.         more = fgets(buf, sizeof(buf), fd) != 0;
  308.     }
  309.     }
  310.  
  311.     /* Send the DATA command and the mail message line by line. */
  312.     SockPuts(socket, "DATA");
  313.     if (!getSmtpReply(socket, "354")) {
  314.     return 0;
  315.     }
  316.  
  317.     fseek(fd, offset, SEEK_SET);
  318.     count = bytes;
  319.     while (fgets(buf, sizeof(buf), fd) && count > 0) {
  320.     count -= strlen(buf);
  321.     if ((s = strchr(buf, '\n')) != NULL)
  322.         *s = '\0';
  323.     if (buf[0] == '.') {
  324.         SockWrite(socket, buf, 1);    /* write an extra . */
  325.     }
  326.     SockPrintf(socket, "%s\r\n", buf);
  327.     }
  328.     fseek(fd, offset+bytes, SEEK_SET);
  329.  
  330.     SockPuts(socket, ".");
  331.     getSmtpReply(socket, "250");
  332.  
  333.     return 1;
  334. }
  335.