14796Seric # include <ctype.h> 24684Seric # include <sysexits.h> 34865Seric # include "sendmail.h" 44684Seric 55182Seric # ifndef SMTP 6*9315Seric SCCSID(@(#)usersmtp.c 3.26 11/21/82 (no SMTP)); 75182Seric # else SMTP 84684Seric 9*9315Seric SCCSID(@(#)usersmtp.c 3.26 11/21/82); 105182Seric 114684Seric /* 124865Seric ** SMTPINIT -- initialize SMTP. 134684Seric ** 144865Seric ** Opens the connection and sends the initial protocol. 154684Seric ** 164684Seric ** Parameters: 174865Seric ** m -- mailer to create connection to. 184865Seric ** pvp -- pointer to parameter vector to pass to 194865Seric ** the mailer. 204865Seric ** ctladdr -- controlling address for this mailer. 214684Seric ** 224684Seric ** Returns: 234865Seric ** appropriate exit status -- EX_OK on success. 244684Seric ** 254684Seric ** Side Effects: 264865Seric ** creates connection and sends initial protocol. 274684Seric */ 284684Seric 294865Seric # define REPLYTYPE(r) ((r) / 100) 307963Seric # define REPLYCLASS(r) (((r) / 10) % 10) 314865Seric 324865Seric static FILE *SmtpOut; /* output file */ 334865Seric static FILE *SmtpIn; /* input file */ 344865Seric static int SmtpPid; /* pid of mailer */ 356051Seric static int SmtpErrstat; /* error status if open fails */ 364865Seric 374865Seric smtpinit(m, pvp, ctladdr) 384865Seric struct mailer *m; 394865Seric char **pvp; 404865Seric ADDRESS *ctladdr; 414684Seric { 424865Seric register int r; 434865Seric char buf[MAXNAME]; 447356Seric extern tick(); 457685Seric extern char *canonname(); 464684Seric 474865Seric /* 484865Seric ** Open the connection to the mailer. 494865Seric */ 504684Seric 516051Seric SmtpIn = SmtpOut = NULL; 524865Seric SmtpPid = openmailer(m, pvp, ctladdr, TRUE, &SmtpOut, &SmtpIn); 536051Seric if (SmtpPid < 0) 546051Seric { 556051Seric SmtpErrstat = ExitStat; 566051Seric # ifdef DEBUG 577677Seric if (tTd(18, 1)) 586051Seric printf("smtpinit: cannot open: Errstat %d errno %d\n", 596051Seric SmtpErrstat, errno); 606051Seric # endif DEBUG 616051Seric return (ExitStat); 626051Seric } 634796Seric 644865Seric /* 654865Seric ** Get the greeting message. 664865Seric ** This should appear spontaneously. 674865Seric */ 684797Seric 694865Seric r = reply(); 708005Seric if (r < 0 || REPLYTYPE(r) != 2) 714865Seric return (EX_TEMPFAIL); 724684Seric 734865Seric /* 744976Seric ** Send the HELO command. 757963Seric ** My mother taught me to always introduce myself. 764976Seric */ 774976Seric 784976Seric smtpmessage("HELO %s", HostName); 794976Seric r = reply(); 808005Seric if (r < 0) 818005Seric return (EX_TEMPFAIL); 828005Seric else if (REPLYTYPE(r) == 5) 834976Seric return (EX_UNAVAILABLE); 847963Seric else if (REPLYTYPE(r) != 2) 854976Seric return (EX_TEMPFAIL); 864976Seric 874976Seric /* 88*9315Seric ** If this is expected to be another sendmail, send some internal 89*9315Seric ** commands. 90*9315Seric */ 91*9315Seric 92*9315Seric if (bitset(M_INTERNAL, m->m_flags)) 93*9315Seric { 94*9315Seric /* tell it to be verbose */ 95*9315Seric smtpmessage("VERB"); 96*9315Seric r = reply(); 97*9315Seric if (r < 0) 98*9315Seric return (EX_TEMPFAIL); 99*9315Seric 100*9315Seric /* tell it we will be sending one transaction only */ 101*9315Seric smtpmessage("ONEX"); 102*9315Seric r = reply(); 103*9315Seric if (r < 0) 104*9315Seric return (EX_TEMPFAIL); 105*9315Seric } 106*9315Seric 107*9315Seric /* 1084865Seric ** Send the MAIL command. 1094865Seric ** Designates the sender. 1104865Seric */ 1114796Seric 1126980Seric expand("$g", buf, &buf[sizeof buf - 1], CurEnv); 1138436Seric if (CurEnv->e_from.q_mailer == LocalMailer || 1148436Seric !bitset(M_FULLSMTP, m->m_flags)) 1158436Seric { 1168436Seric smtpmessage("MAIL From:<%s>", canonname(buf, 1)); 1178436Seric } 1188436Seric else 1198436Seric { 1208436Seric smtpmessage("MAIL From:<@%s%c%s>", HostName, 1218436Seric buf[0] == '@' ? ',' : ':', canonname(buf, 1)); 1228436Seric } 1234865Seric r = reply(); 1248005Seric if (r < 0 || REPLYTYPE(r) == 4) 1254865Seric return (EX_TEMPFAIL); 1267963Seric else if (r == 250) 1277963Seric return (EX_OK); 1287963Seric else if (r == 552) 1297963Seric return (EX_UNAVAILABLE); 1307964Seric return (EX_PROTOCOL); 1314684Seric } 1324684Seric /* 1334976Seric ** SMTPRCPT -- designate recipient. 1344797Seric ** 1354797Seric ** Parameters: 1364865Seric ** to -- address of recipient. 1374797Seric ** 1384797Seric ** Returns: 1394865Seric ** exit status corresponding to recipient status. 1404797Seric ** 1414797Seric ** Side Effects: 1424865Seric ** Sends the mail via SMTP. 1434797Seric */ 1444797Seric 1454976Seric smtprcpt(to) 1464865Seric ADDRESS *to; 1474797Seric { 1484797Seric register int r; 1497685Seric extern char *canonname(); 1504797Seric 1516051Seric if (SmtpPid < 0) 1526051Seric return (SmtpErrstat); 1536051Seric 1548354Seric smtpmessage("RCPT To:<%s>", canonname(to->q_user, 2)); 1554865Seric 1564797Seric r = reply(); 1578005Seric if (r < 0 || REPLYTYPE(r) == 4) 1584865Seric return (EX_TEMPFAIL); 1597963Seric else if (REPLYTYPE(r) == 2) 1607963Seric return (EX_OK); 1617964Seric else if (r == 550 || r == 551 || r == 553) 1627964Seric return (EX_NOUSER); 1637964Seric else if (r == 552 || r == 554) 1647964Seric return (EX_UNAVAILABLE); 1657964Seric return (EX_PROTOCOL); 1664797Seric } 1674797Seric /* 1684865Seric ** SMTPFINISH -- finish up sending all the SMTP protocol. 1694684Seric ** 1704684Seric ** Parameters: 1714865Seric ** m -- mailer being sent to. 1726980Seric ** e -- the envelope for this message. 1734684Seric ** 1744684Seric ** Returns: 1754976Seric ** exit status corresponding to DATA command. 1764684Seric ** 1774684Seric ** Side Effects: 1784865Seric ** none. 1794684Seric */ 1804684Seric 1816980Seric smtpfinish(m, e) 1824865Seric struct mailer *m; 1836980Seric register ENVELOPE *e; 1844684Seric { 1854684Seric register int r; 1864684Seric 1876051Seric if (SmtpPid < 0) 1886051Seric return (SmtpErrstat); 1896051Seric 1904797Seric /* 1914797Seric ** Send the data. 1924797Seric ** Dot hiding is done here. 1934797Seric */ 1944797Seric 1954865Seric smtpmessage("DATA"); 1964796Seric r = reply(); 1978005Seric if (r < 0 || REPLYTYPE(r) == 4) 1984797Seric return (EX_TEMPFAIL); 1997963Seric else if (r == 554) 2007963Seric return (EX_UNAVAILABLE); 2017963Seric else if (r != 354) 2027964Seric return (EX_PROTOCOL); 2036980Seric (*e->e_puthdr)(SmtpOut, m, CurEnv); 2046980Seric fprintf(SmtpOut, "\n"); 2056980Seric (*e->e_putbody)(SmtpOut, m, TRUE); 2064865Seric smtpmessage("."); 2074796Seric r = reply(); 2088005Seric if (r < 0 || REPLYTYPE(r) == 4) 2094797Seric return (EX_TEMPFAIL); 2107963Seric else if (r == 250) 2117963Seric return (EX_OK); 2127963Seric else if (r == 552 || r == 554) 2137963Seric return (EX_UNAVAILABLE); 2147964Seric return (EX_PROTOCOL); 2154684Seric } 2164684Seric /* 2174865Seric ** SMTPQUIT -- close the SMTP connection. 2184865Seric ** 2194865Seric ** Parameters: 2204865Seric ** name -- name of mailer we are quitting. 2217229Seric ** showresp -- if set, give a response message. 2224865Seric ** 2234865Seric ** Returns: 2244865Seric ** none. 2254865Seric ** 2264865Seric ** Side Effects: 2274865Seric ** sends the final protocol and closes the connection. 2284865Seric */ 2294865Seric 2307229Seric smtpquit(name, showresp) 2314865Seric char *name; 2327229Seric bool showresp; 2334865Seric { 2344865Seric register int i; 2354865Seric 2366051Seric if (SmtpPid < 0) 2377229Seric return; 2387229Seric smtpmessage("QUIT"); 2397229Seric (void) reply(); 2407229Seric (void) fclose(SmtpIn); 2417229Seric (void) fclose(SmtpOut); 2427229Seric i = endmailer(SmtpPid, name); 2437229Seric if (showresp) 2447229Seric giveresponse(i, TRUE, LocalMailer); 2454865Seric } 2464865Seric /* 2474684Seric ** REPLY -- read arpanet reply 2484684Seric ** 2494684Seric ** Parameters: 2504796Seric ** none. 2514684Seric ** 2524684Seric ** Returns: 2534684Seric ** reply code it reads. 2544684Seric ** 2554684Seric ** Side Effects: 2564684Seric ** flushes the mail file. 2574684Seric */ 2584684Seric 2594796Seric reply() 2604684Seric { 2614865Seric (void) fflush(SmtpOut); 2624684Seric 2637677Seric if (tTd(18, 1)) 2644796Seric printf("reply\n"); 2654796Seric 2667356Seric /* 2677356Seric ** Read the input line, being careful not to hang. 2687356Seric */ 2697356Seric 2704684Seric for (;;) 2714684Seric { 2724684Seric char buf[MAXLINE]; 2734684Seric register int r; 2747356Seric register char *p; 2754684Seric 2767685Seric /* actually do the read */ 2777677Seric (void) fflush(Xscript); /* for debugging */ 2787685Seric p = sfgets(buf, sizeof buf, SmtpIn); 2797356Seric if (p == NULL) 2807356Seric return (-1); 2818237Seric fixcrlf(buf, TRUE); 2827356Seric 2837356Seric /* log the input in the transcript for future error returns */ 2847229Seric if (Verbose && !HoldErrs) 2858237Seric nmessage(Arpa_Info, "%s", buf); 2868237Seric fprintf(Xscript, "%s\n", buf); 2877356Seric 2887356Seric /* if continuation is required, we can go on */ 2894796Seric if (buf[3] == '-' || !isdigit(buf[0])) 2904684Seric continue; 2917356Seric 2927356Seric /* decode the reply code */ 2934684Seric r = atoi(buf); 2947356Seric 2957356Seric /* extra semantics: 0xx codes are "informational" */ 2964684Seric if (r < 100) 2974684Seric continue; 2987356Seric 2994684Seric return (r); 3004684Seric } 3014684Seric } 3024796Seric /* 3034865Seric ** SMTPMESSAGE -- send message to server 3044796Seric ** 3054796Seric ** Parameters: 3064796Seric ** f -- format 3074796Seric ** a, b, c -- parameters 3084796Seric ** 3094796Seric ** Returns: 3104796Seric ** none. 3114796Seric ** 3124796Seric ** Side Effects: 3134865Seric ** writes message to SmtpOut. 3144796Seric */ 3154796Seric 3164865Seric /*VARARGS1*/ 3174865Seric smtpmessage(f, a, b, c) 3184796Seric char *f; 3194796Seric { 3204796Seric char buf[100]; 3214796Seric 3224865Seric (void) sprintf(buf, f, a, b, c); 3237677Seric if (tTd(18, 1) || (Verbose && !HoldErrs)) 3248237Seric nmessage(Arpa_Info, ">>> %s", buf); 3258237Seric fprintf(Xscript, " >>> %s\n", buf); 3267229Seric fprintf(SmtpOut, "%s\r\n", buf); 3274796Seric } 3285182Seric 3295182Seric # endif SMTP 330