14796Seric # include <ctype.h> 24684Seric # include <sysexits.h> 34865Seric # include "sendmail.h" 44684Seric 55182Seric # ifndef SMTP 6*10131Seric SCCSID(@(#)usersmtp.c 3.33 01/04/83 (no SMTP)); 75182Seric # else SMTP 84684Seric 9*10131Seric SCCSID(@(#)usersmtp.c 3.33 01/04/83); 105182Seric 119391Seric 129391Seric 134684Seric /* 149391Seric ** USERSMTP -- run SMTP protocol from the user end. 159391Seric ** 169391Seric ** This protocol is described in RFC821. 179391Seric */ 189391Seric 199391Seric #define REPLYTYPE(r) ((r) / 100) /* first digit of reply code */ 209391Seric #define REPLYCLASS(r) (((r) / 10) % 10) /* second digit of reply code */ 219391Seric #define SMTPCLOSING 421 /* "Service Shutting Down" */ 229391Seric 2310054Seric char SmtpReplyBuffer[MAXLINE]; /* buffer for replies */ 2410054Seric FILE *SmtpOut; /* output file */ 2510054Seric FILE *SmtpIn; /* input file */ 2610054Seric int SmtpPid; /* pid of mailer */ 2710054Seric bool SmtpClosing; /* set on a forced close */ 289391Seric /* 294865Seric ** SMTPINIT -- initialize SMTP. 304684Seric ** 314865Seric ** Opens the connection and sends the initial protocol. 324684Seric ** 334684Seric ** Parameters: 344865Seric ** m -- mailer to create connection to. 354865Seric ** pvp -- pointer to parameter vector to pass to 364865Seric ** the mailer. 374865Seric ** ctladdr -- controlling address for this mailer. 384684Seric ** 394684Seric ** Returns: 404865Seric ** appropriate exit status -- EX_OK on success. 414684Seric ** 424684Seric ** Side Effects: 434865Seric ** creates connection and sends initial protocol. 444684Seric */ 454684Seric 464865Seric smtpinit(m, pvp, ctladdr) 474865Seric struct mailer *m; 484865Seric char **pvp; 494865Seric ADDRESS *ctladdr; 504684Seric { 514865Seric register int r; 524865Seric char buf[MAXNAME]; 537685Seric extern char *canonname(); 544684Seric 554865Seric /* 564865Seric ** Open the connection to the mailer. 574865Seric */ 584684Seric 596051Seric SmtpIn = SmtpOut = NULL; 604865Seric SmtpPid = openmailer(m, pvp, ctladdr, TRUE, &SmtpOut, &SmtpIn); 616051Seric if (SmtpPid < 0) 626051Seric { 636051Seric # ifdef DEBUG 647677Seric if (tTd(18, 1)) 659391Seric printf("smtpinit: cannot open %s: stat %d errno %d\n", 669391Seric pvp[0], ExitStat, errno); 676051Seric # endif DEBUG 686051Seric return (ExitStat); 696051Seric } 704796Seric 714865Seric /* 724865Seric ** Get the greeting message. 734865Seric ** This should appear spontaneously. 744865Seric */ 754797Seric 764865Seric r = reply(); 778005Seric if (r < 0 || REPLYTYPE(r) != 2) 784865Seric return (EX_TEMPFAIL); 794684Seric 804865Seric /* 814976Seric ** Send the HELO command. 827963Seric ** My mother taught me to always introduce myself. 834976Seric */ 844976Seric 854976Seric smtpmessage("HELO %s", HostName); 864976Seric r = reply(); 878005Seric if (r < 0) 888005Seric return (EX_TEMPFAIL); 898005Seric else if (REPLYTYPE(r) == 5) 904976Seric return (EX_UNAVAILABLE); 917963Seric else if (REPLYTYPE(r) != 2) 924976Seric return (EX_TEMPFAIL); 934976Seric 944976Seric /* 959315Seric ** If this is expected to be another sendmail, send some internal 969315Seric ** commands. 979315Seric */ 989315Seric 999315Seric if (bitset(M_INTERNAL, m->m_flags)) 1009315Seric { 1019315Seric /* tell it to be verbose */ 1029315Seric smtpmessage("VERB"); 1039315Seric r = reply(); 1049315Seric if (r < 0) 1059315Seric return (EX_TEMPFAIL); 1069315Seric 1079315Seric /* tell it we will be sending one transaction only */ 1089315Seric smtpmessage("ONEX"); 1099315Seric r = reply(); 1109315Seric if (r < 0) 1119315Seric return (EX_TEMPFAIL); 1129315Seric } 1139315Seric 1149315Seric /* 1154865Seric ** Send the MAIL command. 1164865Seric ** Designates the sender. 1174865Seric */ 1184796Seric 1196980Seric expand("$g", buf, &buf[sizeof buf - 1], CurEnv); 1208436Seric if (CurEnv->e_from.q_mailer == LocalMailer || 1218436Seric !bitset(M_FULLSMTP, m->m_flags)) 1228436Seric { 1238436Seric smtpmessage("MAIL From:<%s>", canonname(buf, 1)); 1248436Seric } 1258436Seric else 1268436Seric { 1278436Seric smtpmessage("MAIL From:<@%s%c%s>", HostName, 1288436Seric buf[0] == '@' ? ',' : ':', canonname(buf, 1)); 1298436Seric } 1304865Seric r = reply(); 1318005Seric if (r < 0 || REPLYTYPE(r) == 4) 1324865Seric return (EX_TEMPFAIL); 1337963Seric else if (r == 250) 1347963Seric return (EX_OK); 1357963Seric else if (r == 552) 1367963Seric return (EX_UNAVAILABLE); 1377964Seric return (EX_PROTOCOL); 1384684Seric } 1394684Seric /* 1404976Seric ** SMTPRCPT -- designate recipient. 1414797Seric ** 1424797Seric ** Parameters: 1434865Seric ** to -- address of recipient. 1444797Seric ** 1454797Seric ** Returns: 1464865Seric ** exit status corresponding to recipient status. 1474797Seric ** 1484797Seric ** Side Effects: 1494865Seric ** Sends the mail via SMTP. 1504797Seric */ 1514797Seric 1524976Seric smtprcpt(to) 1534865Seric ADDRESS *to; 1544797Seric { 1554797Seric register int r; 1567685Seric extern char *canonname(); 1574797Seric 1588354Seric smtpmessage("RCPT To:<%s>", canonname(to->q_user, 2)); 1594865Seric 1604797Seric r = reply(); 1618005Seric if (r < 0 || REPLYTYPE(r) == 4) 1624865Seric return (EX_TEMPFAIL); 1637963Seric else if (REPLYTYPE(r) == 2) 1647963Seric return (EX_OK); 1657964Seric else if (r == 550 || r == 551 || r == 553) 1667964Seric return (EX_NOUSER); 1677964Seric else if (r == 552 || r == 554) 1687964Seric return (EX_UNAVAILABLE); 1697964Seric return (EX_PROTOCOL); 1704797Seric } 1714797Seric /* 1724865Seric ** SMTPFINISH -- finish up sending all the SMTP protocol. 1734684Seric ** 1744684Seric ** Parameters: 1754865Seric ** m -- mailer being sent to. 1766980Seric ** e -- the envelope for this message. 1774684Seric ** 1784684Seric ** Returns: 1794976Seric ** exit status corresponding to DATA command. 1804684Seric ** 1814684Seric ** Side Effects: 1824865Seric ** none. 1834684Seric */ 1844684Seric 1856980Seric smtpfinish(m, e) 1864865Seric struct mailer *m; 1876980Seric register ENVELOPE *e; 1884684Seric { 1894684Seric register int r; 1904684Seric 1914797Seric /* 1924797Seric ** Send the data. 1934797Seric ** Dot hiding is done here. 1944797Seric */ 1954797Seric 1964865Seric smtpmessage("DATA"); 1974796Seric r = reply(); 1988005Seric if (r < 0 || REPLYTYPE(r) == 4) 1994797Seric return (EX_TEMPFAIL); 2007963Seric else if (r == 554) 2017963Seric return (EX_UNAVAILABLE); 2027963Seric else if (r != 354) 2037964Seric return (EX_PROTOCOL); 20410067Seric (*e->e_puthdr)(SmtpOut, m, CurEnv, TRUE); 20510067Seric fprintf(SmtpOut, "\r\n"); 20610067Seric (*e->e_putbody)(SmtpOut, m, TRUE, CurEnv, TRUE); 2074865Seric smtpmessage("."); 2084796Seric r = reply(); 2098005Seric if (r < 0 || REPLYTYPE(r) == 4) 2104797Seric return (EX_TEMPFAIL); 2117963Seric else if (r == 250) 2127963Seric return (EX_OK); 2137963Seric else if (r == 552 || r == 554) 2147963Seric return (EX_UNAVAILABLE); 2157964Seric return (EX_PROTOCOL); 2164684Seric } 2174684Seric /* 2184865Seric ** SMTPQUIT -- close the SMTP connection. 2194865Seric ** 2204865Seric ** Parameters: 2214865Seric ** name -- name of mailer we are quitting. 2224865Seric ** 2234865Seric ** Returns: 2244865Seric ** none. 2254865Seric ** 2264865Seric ** Side Effects: 2274865Seric ** sends the final protocol and closes the connection. 2284865Seric */ 2294865Seric 2309391Seric smtpquit(name) 2314865Seric char *name; 2324865Seric { 2339391Seric int i; 2344865Seric 2359391Seric if (SmtpClosing) 2369391Seric { 2379391Seric SmtpClosing = FALSE; 2387229Seric return; 2399391Seric } 2409391Seric 2417229Seric smtpmessage("QUIT"); 2429391Seric i = reply(); 2439391Seric if (i != 221) 2449391Seric syserr("smtpquit %s: reply %d", name, i); 2457229Seric (void) fclose(SmtpIn); 2467229Seric (void) fclose(SmtpOut); 2477229Seric i = endmailer(SmtpPid, name); 2489391Seric if (i != EX_OK) 2499391Seric syserr("smtpquit %s: stat %d", name, i); 2504865Seric } 2514865Seric /* 2524684Seric ** REPLY -- read arpanet reply 2534684Seric ** 2544684Seric ** Parameters: 2554796Seric ** none. 2564684Seric ** 2574684Seric ** Returns: 2584684Seric ** reply code it reads. 2594684Seric ** 2604684Seric ** Side Effects: 2614684Seric ** flushes the mail file. 2624684Seric */ 2634684Seric 2644796Seric reply() 2654684Seric { 2664865Seric (void) fflush(SmtpOut); 2674684Seric 2687677Seric if (tTd(18, 1)) 2694796Seric printf("reply\n"); 2704796Seric 2717356Seric /* 2727356Seric ** Read the input line, being careful not to hang. 2737356Seric */ 2747356Seric 2754684Seric for (;;) 2764684Seric { 2774684Seric register int r; 2787356Seric register char *p; 2794684Seric 2807685Seric /* actually do the read */ 2819547Seric if (CurEnv->e_xfp != NULL) 2829547Seric (void) fflush(CurEnv->e_xfp); /* for debugging */ 2837356Seric 28410054Seric /* if we are in the process of closing just give the code */ 28510054Seric if (SmtpClosing) 28610054Seric return (SMTPCLOSING); 28710054Seric 28810054Seric /* get the line from the other side */ 28910054Seric p = sfgets(SmtpReplyBuffer, sizeof SmtpReplyBuffer, SmtpIn); 29010054Seric if (p == NULL) 291*10131Seric { 292*10131Seric syserr("reply: read error"); 29310054Seric return (-1); 294*10131Seric } 29510054Seric fixcrlf(SmtpReplyBuffer, TRUE); 29610054Seric 2977356Seric /* log the input in the transcript for future error returns */ 2987229Seric if (Verbose && !HoldErrs) 2999391Seric nmessage(Arpa_Info, "%s", SmtpReplyBuffer); 300*10131Seric else if (CurEnv->e_xfp != NULL) 3019547Seric fprintf(CurEnv->e_xfp, "%s\n", SmtpReplyBuffer); 3027356Seric 3037356Seric /* if continuation is required, we can go on */ 3049391Seric if (SmtpReplyBuffer[3] == '-' || !isdigit(SmtpReplyBuffer[0])) 3054684Seric continue; 3067356Seric 3077356Seric /* decode the reply code */ 3089391Seric r = atoi(SmtpReplyBuffer); 3097356Seric 3107356Seric /* extra semantics: 0xx codes are "informational" */ 3114684Seric if (r < 100) 3124684Seric continue; 3137356Seric 3149391Seric /* reply code 421 is "Service Shutting Down" */ 31510054Seric if (r == SMTPCLOSING) 3169391Seric { 31710054Seric /* send the quit protocol */ 3189391Seric smtpquit("SMTP Shutdown"); 3199391Seric SmtpClosing = TRUE; 3209391Seric } 3219391Seric 3224684Seric return (r); 3234684Seric } 3244684Seric } 3254796Seric /* 3264865Seric ** SMTPMESSAGE -- send message to server 3274796Seric ** 3284796Seric ** Parameters: 3294796Seric ** f -- format 3304796Seric ** a, b, c -- parameters 3314796Seric ** 3324796Seric ** Returns: 3334796Seric ** none. 3344796Seric ** 3354796Seric ** Side Effects: 3364865Seric ** writes message to SmtpOut. 3374796Seric */ 3384796Seric 3394865Seric /*VARARGS1*/ 3404865Seric smtpmessage(f, a, b, c) 3414796Seric char *f; 3424796Seric { 3434796Seric char buf[100]; 3444796Seric 3454865Seric (void) sprintf(buf, f, a, b, c); 3467677Seric if (tTd(18, 1) || (Verbose && !HoldErrs)) 3478237Seric nmessage(Arpa_Info, ">>> %s", buf); 348*10131Seric else if (CurEnv->e_xfp != NULL) 3499547Seric fprintf(CurEnv->e_xfp, ">>> %s\n", buf); 3509391Seric if (!SmtpClosing) 3519391Seric fprintf(SmtpOut, "%s\r\n", buf); 3524796Seric } 3535182Seric 3545182Seric # endif SMTP 355