14796Seric # include <ctype.h> 24684Seric # include <sysexits.h> 34865Seric # include "sendmail.h" 44684Seric 55182Seric # ifndef SMTP 6*10308Seric SCCSID(@(#)usersmtp.c 3.38 01/15/83 (no SMTP)); 75182Seric # else SMTP 84684Seric 9*10308Seric SCCSID(@(#)usersmtp.c 3.38 01/15/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. 374684Seric ** 384684Seric ** Returns: 394865Seric ** appropriate exit status -- EX_OK on success. 404684Seric ** 414684Seric ** Side Effects: 424865Seric ** creates connection and sends initial protocol. 434684Seric */ 444684Seric 4510175Seric smtpinit(m, pvp) 464865Seric struct mailer *m; 474865Seric char **pvp; 484684Seric { 494865Seric register int r; 504865Seric char buf[MAXNAME]; 514684Seric 524865Seric /* 534865Seric ** Open the connection to the mailer. 544865Seric */ 554684Seric 566051Seric SmtpIn = SmtpOut = NULL; 5710148Seric SmtpClosing = FALSE; 5810175Seric SmtpPid = openmailer(m, pvp, (ADDRESS *) NULL, TRUE, &SmtpOut, &SmtpIn); 596051Seric if (SmtpPid < 0) 606051Seric { 616051Seric # ifdef DEBUG 627677Seric if (tTd(18, 1)) 639391Seric printf("smtpinit: cannot open %s: stat %d errno %d\n", 649391Seric pvp[0], ExitStat, errno); 656051Seric # endif DEBUG 666051Seric return (ExitStat); 676051Seric } 684796Seric 694865Seric /* 704865Seric ** Get the greeting message. 714865Seric ** This should appear spontaneously. 724865Seric */ 734797Seric 7410175Seric r = reply(m); 758005Seric if (r < 0 || REPLYTYPE(r) != 2) 764865Seric return (EX_TEMPFAIL); 774684Seric 784865Seric /* 794976Seric ** Send the HELO command. 807963Seric ** My mother taught me to always introduce myself. 814976Seric */ 824976Seric 8310175Seric smtpmessage("HELO %s", m, HostName); 8410175Seric r = reply(m); 858005Seric if (r < 0) 868005Seric return (EX_TEMPFAIL); 878005Seric else if (REPLYTYPE(r) == 5) 884976Seric return (EX_UNAVAILABLE); 897963Seric else if (REPLYTYPE(r) != 2) 904976Seric return (EX_TEMPFAIL); 914976Seric 924976Seric /* 939315Seric ** If this is expected to be another sendmail, send some internal 949315Seric ** commands. 959315Seric */ 969315Seric 979315Seric if (bitset(M_INTERNAL, m->m_flags)) 989315Seric { 999315Seric /* tell it to be verbose */ 10010175Seric smtpmessage("VERB", m); 10110175Seric r = reply(m); 1029315Seric if (r < 0) 1039315Seric return (EX_TEMPFAIL); 1049315Seric 1059315Seric /* tell it we will be sending one transaction only */ 10610175Seric smtpmessage("ONEX", m); 10710175Seric r = reply(m); 1089315Seric if (r < 0) 1099315Seric return (EX_TEMPFAIL); 1109315Seric } 1119315Seric 1129315Seric /* 1134865Seric ** Send the MAIL command. 1144865Seric ** Designates the sender. 1154865Seric */ 1164796Seric 1176980Seric expand("$g", buf, &buf[sizeof buf - 1], CurEnv); 1188436Seric if (CurEnv->e_from.q_mailer == LocalMailer || 11910175Seric !bitset(M_FROMPATH, m->m_flags)) 1208436Seric { 121*10308Seric smtpmessage("MAIL From:<%s>", m, buf); 1228436Seric } 1238436Seric else 1248436Seric { 12510175Seric smtpmessage("MAIL From:<@%s%c%s>", m, HostName, 126*10308Seric buf[0] == '@' ? ',' : ':', buf); 1278436Seric } 12810175Seric r = reply(m); 1298005Seric if (r < 0 || REPLYTYPE(r) == 4) 1304865Seric return (EX_TEMPFAIL); 1317963Seric else if (r == 250) 1327963Seric return (EX_OK); 1337963Seric else if (r == 552) 1347963Seric return (EX_UNAVAILABLE); 1357964Seric return (EX_PROTOCOL); 1364684Seric } 1374684Seric /* 1384976Seric ** SMTPRCPT -- designate recipient. 1394797Seric ** 1404797Seric ** Parameters: 1414865Seric ** to -- address of recipient. 14210175Seric ** m -- the mailer we are sending to. 1434797Seric ** 1444797Seric ** Returns: 1454865Seric ** exit status corresponding to recipient status. 1464797Seric ** 1474797Seric ** Side Effects: 1484865Seric ** Sends the mail via SMTP. 1494797Seric */ 1504797Seric 15110175Seric smtprcpt(to, m) 1524865Seric ADDRESS *to; 15310175Seric register MAILER *m; 1544797Seric { 1554797Seric register int r; 156*10308Seric extern char *remotename(); 1574797Seric 158*10308Seric smtpmessage("RCPT To:<%s>", m, remotename(to->q_user, m, FALSE, TRUE)); 1594865Seric 16010175Seric r = reply(m); 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 /* 17210175Seric ** SMTPDATA -- send the data and clean up the transaction. 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 18510175Seric smtpdata(m, e) 1864865Seric struct mailer *m; 1876980Seric register ENVELOPE *e; 1884684Seric { 1894684Seric register int r; 1904684Seric 1914797Seric /* 1924797Seric ** Send the data. 19310175Seric ** First send the command and check that it is ok. 19410175Seric ** Then send the data. 19510175Seric ** Follow it up with a dot to terminate. 19610175Seric ** Finally get the results of the transaction. 1974797Seric */ 1984797Seric 19910175Seric /* send the command and check ok to proceed */ 20010175Seric smtpmessage("DATA", m); 20110175Seric r = reply(m); 2028005Seric if (r < 0 || REPLYTYPE(r) == 4) 2034797Seric return (EX_TEMPFAIL); 2047963Seric else if (r == 554) 2057963Seric return (EX_UNAVAILABLE); 2067963Seric else if (r != 354) 2077964Seric return (EX_PROTOCOL); 20810175Seric 20910175Seric /* now output the actual message */ 21010175Seric (*e->e_puthdr)(SmtpOut, m, CurEnv); 21110175Seric putline("\n", SmtpOut, m); 21210175Seric (*e->e_putbody)(SmtpOut, m, CurEnv); 21310175Seric 21410175Seric /* terminate the message */ 21510215Seric fprintf(SmtpOut, ".%s", crlf(m)); 21610215Seric if (Verbose && !HoldErrs) 21710215Seric nmessage(Arpa_Info, ">>> ."); 21810175Seric 21910175Seric /* check for the results of the transaction */ 22010175Seric r = reply(m); 2218005Seric if (r < 0 || REPLYTYPE(r) == 4) 2224797Seric return (EX_TEMPFAIL); 2237963Seric else if (r == 250) 2247963Seric return (EX_OK); 2257963Seric else if (r == 552 || r == 554) 2267963Seric return (EX_UNAVAILABLE); 2277964Seric return (EX_PROTOCOL); 2284684Seric } 2294684Seric /* 2304865Seric ** SMTPQUIT -- close the SMTP connection. 2314865Seric ** 2324865Seric ** Parameters: 2334865Seric ** name -- name of mailer we are quitting. 2344865Seric ** 2354865Seric ** Returns: 2364865Seric ** none. 2374865Seric ** 2384865Seric ** Side Effects: 2394865Seric ** sends the final protocol and closes the connection. 2404865Seric */ 2414865Seric 24210175Seric smtpquit(name, m) 2434865Seric char *name; 24410175Seric register MAILER *m; 2454865Seric { 2469391Seric int i; 2474865Seric 24810148Seric /* if the connection is already closed, don't bother */ 24910148Seric if (SmtpIn == NULL) 25010148Seric return; 25110148Seric 25210148Seric /* send the quit message if not a forced quit */ 25310148Seric if (!SmtpClosing) 2549391Seric { 25510175Seric smtpmessage("QUIT", m); 25610175Seric (void) reply(m); 25710159Seric if (SmtpClosing) 25810159Seric return; 2599391Seric } 2609391Seric 26110148Seric /* now actually close the connection */ 2627229Seric (void) fclose(SmtpIn); 2637229Seric (void) fclose(SmtpOut); 26410148Seric SmtpIn = SmtpOut = NULL; 26510148Seric 26610148Seric /* and pick up the zombie */ 2677229Seric i = endmailer(SmtpPid, name); 2689391Seric if (i != EX_OK) 2699391Seric syserr("smtpquit %s: stat %d", name, i); 2704865Seric } 2714865Seric /* 2724684Seric ** REPLY -- read arpanet reply 2734684Seric ** 2744684Seric ** Parameters: 27510175Seric ** m -- the mailer we are reading the reply from. 2764684Seric ** 2774684Seric ** Returns: 2784684Seric ** reply code it reads. 2794684Seric ** 2804684Seric ** Side Effects: 2814684Seric ** flushes the mail file. 2824684Seric */ 2834684Seric 28410175Seric reply(m) 2854684Seric { 2864865Seric (void) fflush(SmtpOut); 2874684Seric 2887677Seric if (tTd(18, 1)) 2894796Seric printf("reply\n"); 2904796Seric 2917356Seric /* 2927356Seric ** Read the input line, being careful not to hang. 2937356Seric */ 2947356Seric 2954684Seric for (;;) 2964684Seric { 2974684Seric register int r; 2987356Seric register char *p; 2994684Seric 3007685Seric /* actually do the read */ 3019547Seric if (CurEnv->e_xfp != NULL) 3029547Seric (void) fflush(CurEnv->e_xfp); /* for debugging */ 3037356Seric 30410054Seric /* if we are in the process of closing just give the code */ 30510054Seric if (SmtpClosing) 30610054Seric return (SMTPCLOSING); 30710054Seric 30810054Seric /* get the line from the other side */ 30910054Seric p = sfgets(SmtpReplyBuffer, sizeof SmtpReplyBuffer, SmtpIn); 31010054Seric if (p == NULL) 31110131Seric { 31210148Seric extern char MsgBuf[]; /* err.c */ 31310148Seric extern char Arpa_TSyserr[]; /* conf.c */ 31410148Seric 31510148Seric message(Arpa_TSyserr, "reply: read error"); 31610148Seric # ifdef LOG 31710148Seric syslog(LOG_ERR, "%s", &MsgBuf[4]); 31810148Seric # endif LOG 31910148Seric SmtpClosing = TRUE; 32010175Seric smtpquit("reply error", m); 32110054Seric return (-1); 32210131Seric } 32310054Seric fixcrlf(SmtpReplyBuffer, TRUE); 32410054Seric 3257356Seric /* log the input in the transcript for future error returns */ 3267229Seric if (Verbose && !HoldErrs) 3279391Seric nmessage(Arpa_Info, "%s", SmtpReplyBuffer); 32810131Seric else if (CurEnv->e_xfp != NULL) 3299547Seric fprintf(CurEnv->e_xfp, "%s\n", SmtpReplyBuffer); 3307356Seric 3317356Seric /* if continuation is required, we can go on */ 3329391Seric if (SmtpReplyBuffer[3] == '-' || !isdigit(SmtpReplyBuffer[0])) 3334684Seric continue; 3347356Seric 3357356Seric /* decode the reply code */ 3369391Seric r = atoi(SmtpReplyBuffer); 3377356Seric 3387356Seric /* extra semantics: 0xx codes are "informational" */ 3394684Seric if (r < 100) 3404684Seric continue; 3417356Seric 3429391Seric /* reply code 421 is "Service Shutting Down" */ 34310054Seric if (r == SMTPCLOSING) 3449391Seric { 34510054Seric /* send the quit protocol */ 34610175Seric smtpquit("SMTP Shutdown", m); 3479391Seric SmtpClosing = TRUE; 3489391Seric } 3499391Seric 3504684Seric return (r); 3514684Seric } 3524684Seric } 3534796Seric /* 3544865Seric ** SMTPMESSAGE -- send message to server 3554796Seric ** 3564796Seric ** Parameters: 3574796Seric ** f -- format 35810175Seric ** m -- the mailer to control formatting. 3594796Seric ** a, b, c -- parameters 3604796Seric ** 3614796Seric ** Returns: 3624796Seric ** none. 3634796Seric ** 3644796Seric ** Side Effects: 3654865Seric ** writes message to SmtpOut. 3664796Seric */ 3674796Seric 3684865Seric /*VARARGS1*/ 36910175Seric smtpmessage(f, m, a, b, c) 3704796Seric char *f; 37110175Seric MAILER *m; 3724796Seric { 3734796Seric char buf[100]; 3744796Seric 3754865Seric (void) sprintf(buf, f, a, b, c); 3767677Seric if (tTd(18, 1) || (Verbose && !HoldErrs)) 3778237Seric nmessage(Arpa_Info, ">>> %s", buf); 37810131Seric else if (CurEnv->e_xfp != NULL) 3799547Seric fprintf(CurEnv->e_xfp, ">>> %s\n", buf); 3809391Seric if (!SmtpClosing) 38110215Seric fprintf(SmtpOut, "%s%s", buf, crlf(m)); 3824796Seric } 3835182Seric 3845182Seric # endif SMTP 385