14796Seric # include <ctype.h> 24684Seric # include <sysexits.h> 34865Seric # include "sendmail.h" 44684Seric 55182Seric # ifndef SMTP 6*9341Seric SCCSID(@(#)usersmtp.c 3.27 11/24/82 (no SMTP)); 75182Seric # else SMTP 84684Seric 9*9341Seric SCCSID(@(#)usersmtp.c 3.27 11/24/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 /* 889315Seric ** If this is expected to be another sendmail, send some internal 899315Seric ** commands. 909315Seric */ 919315Seric 929315Seric if (bitset(M_INTERNAL, m->m_flags)) 939315Seric { 949315Seric /* tell it to be verbose */ 959315Seric smtpmessage("VERB"); 969315Seric r = reply(); 979315Seric if (r < 0) 989315Seric return (EX_TEMPFAIL); 999315Seric 1009315Seric /* tell it we will be sending one transaction only */ 1019315Seric smtpmessage("ONEX"); 1029315Seric r = reply(); 1039315Seric if (r < 0) 1049315Seric return (EX_TEMPFAIL); 1059315Seric } 1069315Seric 1079315Seric /* 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 */ 277*9341Seric if (Xscript != NULL) 278*9341Seric (void) fflush(Xscript); /* for debugging */ 2797685Seric p = sfgets(buf, sizeof buf, SmtpIn); 2807356Seric if (p == NULL) 2817356Seric return (-1); 2828237Seric fixcrlf(buf, TRUE); 2837356Seric 2847356Seric /* log the input in the transcript for future error returns */ 2857229Seric if (Verbose && !HoldErrs) 2868237Seric nmessage(Arpa_Info, "%s", buf); 287*9341Seric if (Xscript != NULL) 288*9341Seric fprintf(Xscript, "%s\n", buf); 2897356Seric 2907356Seric /* if continuation is required, we can go on */ 2914796Seric if (buf[3] == '-' || !isdigit(buf[0])) 2924684Seric continue; 2937356Seric 2947356Seric /* decode the reply code */ 2954684Seric r = atoi(buf); 2967356Seric 2977356Seric /* extra semantics: 0xx codes are "informational" */ 2984684Seric if (r < 100) 2994684Seric continue; 3007356Seric 3014684Seric return (r); 3024684Seric } 3034684Seric } 3044796Seric /* 3054865Seric ** SMTPMESSAGE -- send message to server 3064796Seric ** 3074796Seric ** Parameters: 3084796Seric ** f -- format 3094796Seric ** a, b, c -- parameters 3104796Seric ** 3114796Seric ** Returns: 3124796Seric ** none. 3134796Seric ** 3144796Seric ** Side Effects: 3154865Seric ** writes message to SmtpOut. 3164796Seric */ 3174796Seric 3184865Seric /*VARARGS1*/ 3194865Seric smtpmessage(f, a, b, c) 3204796Seric char *f; 3214796Seric { 3224796Seric char buf[100]; 3234796Seric 3244865Seric (void) sprintf(buf, f, a, b, c); 3257677Seric if (tTd(18, 1) || (Verbose && !HoldErrs)) 3268237Seric nmessage(Arpa_Info, ">>> %s", buf); 327*9341Seric if (Xscript != NULL) 328*9341Seric fprintf(Xscript, ">>> %s\n", buf); 3297229Seric fprintf(SmtpOut, "%s\r\n", buf); 3304796Seric } 3315182Seric 3325182Seric # endif SMTP 333