home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume3 / sm-smtp / smtp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-02-03  |  4.9 KB  |  236 lines

  1. /*
  2.  * smtp -- client, send mail to remote smtp server
  3.  * Set up for 4.2BSD networking system.
  4.  * Adapted for System V by jv@mh.nl.
  5.  * TODO:
  6.  *    better mapping of error numbers.
  7.  *    allow multiple recipients (maybe)
  8.  *     send stuff from cmds.h instead of hard-coded here
  9.  */
  10.  
  11. #define    USAGE "usage: %s [-h helohost] targethost sender recipient\n"
  12.  
  13. #include "smtp.h"
  14. #include <sys/uio.h>        /* needed for socket.h */
  15. #include <sys/socket.h>
  16. #include <netinet/in.h>
  17. #include <netdb.h>
  18.  
  19.  
  20. #ifndef SERVNAME
  21. #define SERVNAME "smtp"            /* service we wanna talk to */
  22. #endif
  23.  
  24. char *progname;
  25. int debug = 0;
  26. extern char hostname[];
  27. extern char hostdomain[];
  28. char *sendhost = hostdomain;
  29. FILE *sfi, *sfo;
  30. char *host = "None";
  31. char *strcat(), *strcpy();
  32. static char *makedomain();
  33.  
  34. #ifdef HOOTING
  35. extern int hooting;    /* in netio */
  36. #endif
  37.  
  38. /*
  39.  * main - parse arguments and handle options
  40.  */
  41. main(argc, argv)
  42. int argc;
  43. char *argv[];
  44. {
  45.     register int c;
  46.     int errflg = 0;
  47.     extern int optind;
  48.     extern char *optarg;
  49.     char *sender, *recip;
  50.  
  51.     progname = argv[0];
  52.     getmynames ();
  53.  
  54.     while ((c = getopt(argc, argv, "dh:")) != EOF)
  55.         switch (c) {
  56.         case 'd':
  57.             ++debug;
  58.             break;
  59.         case 'h':        /* alternate sending host */
  60.             sendhost = optarg;
  61.             break;
  62.         case '?':
  63.         default:
  64.             errflg++;
  65.             break;
  66.         }
  67.     if (errflg || (argc - optind) < 3) {
  68.         (void) fprintf(stderr, USAGE, progname);
  69.         bomb(E_USAGE);
  70.     }
  71.     host = argv[optind++];
  72.     sender = makedomain(argv[optind++], sendhost);
  73.     recip  = makedomain(argv[optind++], host);
  74.  
  75.     setup();        /* open connection */
  76.  
  77.  
  78. #ifdef HOOTING
  79.     hooting = 1;
  80. #endif
  81.     /* hold the conversation */
  82.  
  83.     converse(sender, recip, sfi, sfo, stdin);
  84.     (void) sleep(5);    /* drain? */
  85.  
  86.     if (sfo!=NULL)
  87.         (void) fclose(sfo);
  88.     if (sfi!=NULL)
  89.         (void) fclose(sfi);
  90.  
  91.     return 0;
  92. }
  93.  
  94. /*
  95.  * setup -- setup tcp/ip connection to/from server
  96.  */
  97. setup()
  98. {
  99.     struct hostent *hp;
  100.     struct servent *sp;
  101.     struct sockaddr_in sin;
  102.     int s;
  103.     extern int errno;
  104.  
  105.     (void) bzero((char *)&sin, sizeof(sin));
  106.  
  107.     if ((hp = gethostbyname(host)) == (struct hostent *) NULL) {
  108.         (void) fprintf(stderr, "unknown host (%s).\n", host);
  109.         bomb(E_NOHOST);
  110.     }
  111.  
  112.     (void) bcopy(hp->h_addr, &sin.sin_addr, hp->h_length);
  113.  
  114.     if ((sp = getservbyname (SERVNAME, "tcp")) == NULL) {
  115.         (void)fprintf(stderr,"unknown service TCP/%s\n", SERVNAME);
  116.         bomb(E_OSFILE);
  117.     }
  118.     sin.sin_port = sp->s_port;
  119.     sin.sin_family = hp->h_addrtype;
  120.  
  121.     if ((s = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
  122.         perror("setup - socket");
  123.         bomb(E_CANTOPEN);
  124.     }
  125.  
  126.     if (connect(s, (struct sockaddr *) &sin, sizeof (sin)) < 0) {
  127.         perror("setup - connect");
  128.         /*
  129.          * check for conditions that (we think) are temporary;
  130.          * try them later; bomb utterly on all others.
  131.          */
  132.         if (errno == ETIMEDOUT || errno == ECONNREFUSED || 
  133.             errno == EHOSTDOWN || errno == EHOSTUNREACH)
  134.             bomb(E_TEMPFAIL);
  135.         else
  136.             bomb(E_CANTOPEN);
  137.     }
  138.  
  139.     if (((sfi = fdopen(s, "r")) == (FILE *) NULL) ||
  140.         ((sfo = fdopen(s, "w")) == (FILE *) NULL)) {
  141.         perror("setup - fdopen");
  142.         bomb(E_CANTOPEN);
  143.     }
  144. /*    setbuf(sfi, (char *) 0);*/
  145. }
  146.  
  147. /*
  148.  * bomb(code) - exit program, map smtp error code into mailsystem code
  149.  * Codes with E_ are defined in miscerrs.h.
  150.  * Codes with EX_ are from <sysexits.h>
  151.  * Lines with FOO are placeholders until we decrypt more appropriate codes.
  152.  */
  153. bomb(code)
  154. int code;
  155. {
  156.     if (sfi != NULL)
  157.         (void) fclose(sfi);
  158.     if (sfo != NULL)
  159.         (void) fclose(sfo);
  160.  
  161. #ifdef    EX_OK
  162.     switch(code) {
  163.     case 451:            /* host not responding */
  164.         code = EX_UNAVAILABLE;    /* service unavailable */
  165.         break;
  166.     case 550:
  167.         code = EX_NOUSER;    /* addressee unknown */
  168.         break;
  169.     case 501:            /* syntax error in address */
  170.     case 554:            /* */
  171.         code = EX_DATAERR;    /* data format error */
  172.         break;
  173.     case E_IOERR:
  174.         code = EX_IOERR;    /* input/output error */
  175.         break;
  176.     case E_NOHOST:
  177.         code = EX_NOHOST;    /* host name unknown */
  178.         break;
  179.     case E_OSFILE:            /* no "smtp" -> /etc/services f'd */
  180.         code = EX_OSFILE;    /* critical OS file missing */
  181.         break;
  182.     case E_USAGE:
  183.         code = EX_USAGE;    /* command line usage error */
  184.         break;
  185.     case E_TEMPFAIL:
  186.         code = EX_TEMPFAIL;    /* temp failure; user can retry */
  187.         break;
  188. #if 0
  189.     case FOO:
  190.         code = EX_OSERR;    /* system error (e.g., can't fork) */
  191.         break;
  192.     case FOO:
  193.         code = EX_NOINPUT;    /* cannot open input */
  194.         break;
  195.     case FOO:
  196.         code = EX_CANTCREAT;    /* can't create (user) output file */
  197.         break;
  198.     case FOO:
  199.         code = EX_PROTOCOL;    /* remote error in protocol */
  200.         break;
  201.     case FOO:
  202.         code = EX_NOPERM;    /* permission denied */
  203.         break;
  204. #endif    /* NOTDEF */
  205.     default:            /* can't happen? */
  206.         code = EX_SOFTWARE;    /* internal software error */
  207.         break;
  208.     }
  209.  
  210. #else    /* has no sysexits */
  211.     code = 1;
  212. #endif
  213.  
  214.     (void) exit (code);
  215. }
  216.  
  217. static char *
  218. makedomain(addr, domain)
  219. char *addr, *domain;
  220. {
  221.     char *rval;
  222.     extern char *index(), *malloc();
  223.  
  224.     if (index(addr, '@') != 0)
  225.         return addr;
  226.  
  227.     if ((rval = malloc(strlen(addr) + strlen(domain) + 2)) == 0)
  228. #ifdef EX_SOFTWARE
  229.         bomb(EX_SOFTWARE);    /* can't happen! */
  230. #else
  231.         bomb (3);
  232. #endif
  233.     sprintf(rval, "%s@%s", addr, domain);
  234.     return rval;
  235. }
  236.