home *** CD-ROM | disk | FTP | other *** search
/ vsiftp.vmssoftware.com / VSIPUBLIC@vsiftp.vmssoftware.com.tar / FREEWARE / FREEWARE40.ZIP / pine / c-client / smtp.c < prev    next >
C/C++ Source or Header  |  1994-01-19  |  9KB  |  289 lines

  1. /*
  2.  * Program:    Simple Mail Transfer Protocol (SMTP) routines
  3.  *
  4.  * Author:    Mark Crispin
  5.  *        Networks and Distributed Computing
  6.  *        Computing & Communications
  7.  *        University of Washington
  8.  *        Administration Building, AG-44
  9.  *        Seattle, WA  98195
  10.  *        Internet: MRC@CAC.Washington.EDU
  11.  *
  12.  * Date:    27 July 1988
  13.  * Last Edited:    18 March 1993
  14.  *
  15.  * Sponsorship:    The original version of this work was developed in the
  16.  *        Symbolic Systems Resources Group of the Knowledge Systems
  17.  *        Laboratory at Stanford University in 1987-88, and was funded
  18.  *        by the Biomedical Research Technology Program of the National
  19.  *        Institutes of Health under grant number RR-00785.
  20.  *
  21.  * Original version Copyright 1988 by The Leland Stanford Junior University.
  22.  * Copyright 1993 by the University of Washington.
  23.  *
  24.  *  Permission to use, copy, modify, and distribute this software and its
  25.  * documentation for any purpose and without fee is hereby granted, provided
  26.  * that the above copyright notices appear in all copies and that both the
  27.  * above copyright notices and this permission notice appear in supporting
  28.  * documentation, and that the name of the University of Washington or The
  29.  * Leland Stanford Junior University not be used in advertising or publicity
  30.  * pertaining to distribution of the software without specific, written prior
  31.  * permission.  This software is made available "as is", and
  32.  * THE UNIVERSITY OF WASHINGTON AND THE LELAND STANFORD JUNIOR UNIVERSITY
  33.  * DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD TO THIS SOFTWARE,
  34.  * INCLUDING WITHOUT LIMITATION ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
  35.  * FITNESS FOR A PARTICULAR PURPOSE, AND IN NO EVENT SHALL THE UNIVERSITY OF
  36.  * WASHINGTON OR THE LELAND STANFORD JUNIOR UNIVERSITY BE LIABLE FOR ANY
  37.  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
  38.  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
  39.  * CONTRACT, TORT (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF
  40.  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  41.  *
  42.  */
  43.  
  44. #include <ctype.h>
  45. #include <stdio.h>
  46. /* VMS - The following two lines were transposed */
  47. #include "osdep.h"
  48. #include "mail.h"
  49. #include "smtp.h"
  50. #include "rfc822.h"
  51. #include "misc.h"
  52.  
  53. /* Mail Transfer Protocol open connection
  54.  * Accepts: service host list
  55.  *        initial debugging flag
  56.  * Returns: T on success, NIL on failure
  57.  */
  58.  
  59. SMTPSTREAM *smtp_open (hostlist,debug)
  60.     char **hostlist;
  61.     long debug;
  62. {
  63.   SMTPSTREAM *stream = NIL;
  64.   void *tcpstream;
  65.   char tmp[MAILTMPLEN];
  66.   if (!(hostlist && *hostlist)) mm_log ("Missing MTP service host",ERROR);
  67.   else do {            /* try to open connection */
  68.     if (tcpstream = tcp_open (*hostlist,SMTPTCPPORT)) {
  69.                 /* default local host */
  70.       if (!lhostn) lhostn = cpystr (tcp_localhost (tcpstream));
  71.       stream = (SMTPSTREAM *) fs_get (sizeof (SMTPSTREAM));
  72.       stream->tcpstream = tcpstream;
  73.       stream->debug = debug;
  74.       stream->reply = NIL;
  75.                 /* get SMTP greeting */
  76.       if (smtp_reply (stream) == SMTPGREET &&
  77.       ((smtp_send (stream,"HELO",tcp_localhost (tcpstream)) == SMTPOK) ||
  78.        ((!strcmp ("localhost",lcase (strcpy (tmp,*hostlist)))) &&
  79.         (smtp_send (stream,"HELO","localhost") == SMTPOK))))
  80.     return stream;        /* success return */
  81.       smtp_close (stream);    /* otherwise punt stream */
  82.     }
  83.   } while (*++hostlist);    /* try next server */
  84.   return NIL;
  85. }
  86.  
  87.  
  88. /* Mail Transfer Protocol close connection
  89.  * Accepts: stream
  90.  */
  91.  
  92. void smtp_close (stream)
  93.     SMTPSTREAM *stream;
  94. {
  95.   if (stream) {            /* send "QUIT" */
  96.     smtp_send (stream,"QUIT",NIL);
  97.                 /* close TCP connection */
  98.     tcp_close (stream->tcpstream);
  99.     if (stream->reply) fs_give ((void **) &stream->reply);
  100.     fs_give ((void **) &stream);/* flush the stream */
  101.   }
  102. }
  103.  
  104. /* Mail Transfer Protocol deliver mail
  105.  * Accepts: stream
  106.  *        delivery option (MAIL, SEND, SAML, SOML)
  107.  *        message envelope
  108.  *        message body
  109.  * Returns: T on success, NIL on failure
  110.  */
  111.  
  112. long smtp_mail (stream,type,env,body)
  113.     SMTPSTREAM *stream;
  114.     char *type;
  115.     ENVELOPE *env;
  116.     BODY *body;
  117. {
  118.   char tmp[8*MAILTMPLEN];
  119.   long error = NIL;
  120.   if (!(env->to || env->cc || env->bcc)) {
  121.                   /* no recipients in request */
  122.     smtp_fake (stream,SMTPHARDERROR,"No recipients specified");
  123.     return NIL;
  124.   }
  125.                   /* make sure stream is in good shape */
  126.   smtp_send (stream,"RSET",NIL);
  127.   strcpy (tmp,"FROM:<");    /* compose "MAIL FROM:<return-path>" */
  128.   rfc822_address (tmp,env->return_path);
  129.   strcat (tmp,">");
  130.                 /* send "MAIL FROM" command */
  131.   if (!(smtp_send (stream,type,tmp) == SMTPOK)) return NIL;
  132.                 /* negotiate the recipients */
  133.   if (env->to) smtp_rcpt (stream,env->to,&error);
  134.   if (env->cc) smtp_rcpt (stream,env->cc,&error);
  135.   if (env->bcc) smtp_rcpt (stream,env->bcc,&error);
  136.   if (error) {            /* any recipients failed? */
  137.                       /* reset the stream */
  138.     smtp_send (stream,"RSET",NIL);
  139.     smtp_fake (stream,SMTPHARDERROR,"One or more recipients failed");
  140.     return NIL;
  141.   }
  142.                 /* negotiate data command */
  143.   if (!(smtp_send (stream,"DATA",NIL) == SMTPREADY)) return NIL;
  144.                 /* set up error in case failure */
  145.   smtp_fake (stream,SMTPSOFTFATAL,"SMTP connection went away!");
  146.                 /* output data, return success status */
  147.   return rfc822_output (tmp,env,body,smtp_soutr,stream->tcpstream) &&
  148.     (smtp_send (stream,".",NIL) == SMTPOK);
  149. }
  150.  
  151. /* Mail Transfer Protocol turn on debugging telemetry
  152.  * Accepts: stream
  153.  */
  154.  
  155. void smtp_debug (stream)
  156.     SMTPSTREAM *stream;
  157. {
  158.   stream->debug = T;        /* turn on protocol telemetry */
  159. }
  160.  
  161.  
  162. /* Mail Transfer Protocol turn off debugging telemetry
  163.  * Accepts: stream
  164.  */
  165.  
  166. void smtp_nodebug (stream)
  167.     SMTPSTREAM *stream;
  168. {
  169.   stream->debug = NIL;        /* turn off protocol telemetry */
  170. }
  171.  
  172. /* Internal routines */
  173.  
  174.  
  175. /* Simple Mail Transfer Protocol send recipient
  176.  * Accepts: SMTP stream
  177.  *        address list
  178.  *        pointer to error flag
  179.  */
  180.  
  181. void smtp_rcpt (stream,adr,error)
  182.     SMTPSTREAM *stream;
  183.     ADDRESS *adr;
  184.     long *error;
  185. {
  186.   char tmp[MAILTMPLEN];
  187.   while (adr) {
  188.                 /* clear any former error */
  189.     if (adr->error) fs_give ((void **) &adr->error);
  190.     if (adr->host) {        /* ignore group syntax */
  191.       strcpy (tmp,"TO:<");    /* compose "RCPT TO:<return-path>" */
  192.       rfc822_address (tmp,adr);
  193.       strcat (tmp,">");
  194.                 /* send "RCPT TO" command */
  195.       if (!(smtp_send (stream,"RCPT",tmp) == SMTPOK)) {
  196.     *error = T;        /* note that an error occurred */
  197.     adr->error = cpystr (stream->reply);
  198.       }
  199.     }
  200.     adr = adr->next;        /* do any subsequent recipients */
  201.   }
  202. }
  203.  
  204.  
  205. /* Simple Mail Transfer Protocol send command
  206.  * Accepts: SMTP stream
  207.  *        text
  208.  * Returns: reply code
  209.  */
  210.  
  211. long smtp_send (stream,command,args)
  212.     SMTPSTREAM *stream;
  213.     char *command;
  214.     char *args;
  215. {
  216.   char tmp[MAILTMPLEN];
  217.                 /* build the complete command */
  218.   if (args) sprintf (tmp,"%s %s",command,args);
  219.   else strcpy (tmp,command);
  220.   if (stream->debug) mm_dlog (tmp);
  221.   strcat (tmp,"\015\012");
  222.                 /* send the command */
  223.   return tcp_soutr (stream->tcpstream,tmp) ? smtp_reply (stream) :
  224.     smtp_fake (stream,SMTPSOFTFATAL,"SMTP connection went away!");
  225. }
  226.  
  227. /* Simple Mail Transfer Protocol get reply
  228.  * Accepts: SMTP stream
  229.  * Returns: reply code
  230.  */
  231.  
  232. long smtp_reply (stream)
  233.     SMTPSTREAM *stream;
  234. {
  235.                 /* flush old reply */
  236.   if (stream->reply) fs_give ((void **) &stream->reply);
  237.                   /* get reply */
  238.   if (!(stream->reply = tcp_getline (stream->tcpstream)))
  239.     return smtp_fake (stream,SMTPSOFTFATAL,"SMTP connection went away!");
  240.   if (stream->debug) mm_dlog (stream->reply);
  241.                 /* handle continuation by recursion */
  242.   return (stream->reply[3]=='-') ? smtp_reply (stream) : atoi (stream->reply);
  243. }
  244.  
  245.  
  246. /* Simple Mail Transfer Protocol set fake error
  247.  * Accepts: SMTP stream
  248.  *        SMTP error code
  249.  *        error text
  250.  * Returns: error code
  251.  */
  252.  
  253. long smtp_fake (stream,code,text)
  254.     SMTPSTREAM *stream;
  255.     long code;
  256.     char *text;
  257. {
  258.                 /* flush any old reply */
  259.   if (stream->reply ) fs_give ((void **) &stream->reply);
  260.                   /* set up pseudo-reply string */
  261.   stream->reply = (char *) fs_get (20+strlen (text));
  262.   sprintf (stream->reply,"%ld %s",code,text);
  263.   return code;            /* return error code */
  264. }
  265.  
  266. /* Simple Mail Transfer Protocol filter mail
  267.  * Accepts: stream
  268.  *        string
  269.  * Returns: T on success, NIL on failure
  270.  */
  271.  
  272. long smtp_soutr (stream,s)
  273.     void *stream;
  274.     char *s;
  275. {
  276.   char c,*t;
  277.                 /* find lines beginning with a "." */
  278.   while (t = strstr (s,"\015\012.")) {
  279.     c = *(t += 3);        /* remember next character after "." */
  280.     *t = '\0';            /* tie off string */
  281.                 /* output prefix */
  282.     if (!tcp_soutr (stream,s)) return NIL;
  283.     *t = c;            /* restore delimiter */
  284.     s = t - 1;            /* push pointer up to the "." */
  285.   }
  286.                 /* output remainder of text */
  287.   return *s ? tcp_soutr (stream,s) : T;
  288. }
  289.