|
|
1.1 root 1: # include <ctype.h>
2: # include <sysexits.h>
3: # include "sendmail.h"
4:
5: # ifndef SMTP
6: SCCSID(@(#)usersmtp.c 4.4 9/7/83 (no SMTP));
7: # else SMTP
8:
9: SCCSID(@(#)usersmtp.c 4.4 9/7/83);
10:
11:
12:
13: /*
14: ** USERSMTP -- run SMTP protocol from the user end.
15: **
16: ** This protocol is described in RFC821.
17: */
18:
19: #define REPLYTYPE(r) ((r) / 100) /* first digit of reply code */
20: #define REPLYCLASS(r) (((r) / 10) % 10) /* second digit of reply code */
21: #define SMTPCLOSING 421 /* "Service Shutting Down" */
22:
23: char SmtpMsgBuffer[MAXLINE]; /* buffer for commands */
24: char SmtpReplyBuffer[MAXLINE]; /* buffer for replies */
25: FILE *SmtpOut; /* output file */
26: FILE *SmtpIn; /* input file */
27: int SmtpPid; /* pid of mailer */
28:
29: /* following represents the state of the SMTP connection */
30: int SmtpState; /* connection state, see below */
31:
32: #define SMTP_CLOSED 0 /* connection is closed */
33: #define SMTP_OPEN 1 /* connection is open for business */
34: #define SMTP_SSD 2 /* service shutting down */
35: /*
36: ** SMTPINIT -- initialize SMTP.
37: **
38: ** Opens the connection and sends the initial protocol.
39: **
40: ** Parameters:
41: ** m -- mailer to create connection to.
42: ** pvp -- pointer to parameter vector to pass to
43: ** the mailer.
44: **
45: ** Returns:
46: ** appropriate exit status -- EX_OK on success.
47: ** If not EX_OK, it should close the connection.
48: **
49: ** Side Effects:
50: ** creates connection and sends initial protocol.
51: */
52:
53: jmp_buf CtxGreeting;
54:
55: smtpinit(m, pvp)
56: struct mailer *m;
57: char **pvp;
58: {
59: register int r;
60: EVENT *gte;
61: char buf[MAXNAME];
62: extern greettimeout();
63:
64: /*
65: ** Open the connection to the mailer.
66: */
67:
68: #ifdef DEBUG
69: if (SmtpState == SMTP_OPEN)
70: syserr("smtpinit: already open");
71: #endif DEBUG
72:
73: SmtpIn = SmtpOut = NULL;
74: SmtpState = SMTP_CLOSED;
75: SmtpPid = openmailer(m, pvp, (ADDRESS *) NULL, TRUE, &SmtpOut, &SmtpIn);
76: if (SmtpPid < 0)
77: {
78: # ifdef DEBUG
79: if (tTd(18, 1))
80: printf("smtpinit: cannot open %s: stat %d errno %d\n",
81: pvp[0], ExitStat, errno);
82: # endif DEBUG
83: return (ExitStat);
84: }
85: SmtpState = SMTP_OPEN;
86:
87: /*
88: ** Get the greeting message.
89: ** This should appear spontaneously. Give it five minutes to
90: ** happen.
91: */
92:
93: if (setjmp(CtxGreeting) != 0)
94: goto tempfail;
95: gte = setevent(300, greettimeout, 0);
96: r = reply(m);
97: clrevent(gte);
98: if (r < 0 || REPLYTYPE(r) != 2)
99: goto tempfail;
100:
101: /*
102: ** Send the HELO command.
103: ** My mother taught me to always introduce myself.
104: */
105:
106: smtpmessage("HELO %s", m, HostName);
107: r = reply(m);
108: if (r < 0)
109: goto tempfail;
110: else if (REPLYTYPE(r) == 5)
111: goto unavailable;
112: else if (REPLYTYPE(r) != 2)
113: goto tempfail;
114:
115: /*
116: ** If this is expected to be another sendmail, send some internal
117: ** commands.
118: */
119:
120: if (bitnset(M_INTERNAL, m->m_flags))
121: {
122: /* tell it to be verbose */
123: smtpmessage("VERB", m);
124: r = reply(m);
125: if (r < 0)
126: goto tempfail;
127:
128: /* tell it we will be sending one transaction only */
129: smtpmessage("ONEX", m);
130: r = reply(m);
131: if (r < 0)
132: goto tempfail;
133: }
134:
135: /*
136: ** Send the MAIL command.
137: ** Designates the sender.
138: */
139:
140: expand("$g", buf, &buf[sizeof buf - 1], CurEnv);
141: if (CurEnv->e_from.q_mailer == LocalMailer ||
142: !bitnset(M_FROMPATH, m->m_flags))
143: {
144: smtpmessage("MAIL From:<%s>", m, buf);
145: }
146: else
147: {
148: smtpmessage("MAIL From:<@%s%c%s>", m, HostName,
149: buf[0] == '@' ? ',' : ':', buf);
150: }
151: r = reply(m);
152: if (r < 0 || REPLYTYPE(r) == 4)
153: goto tempfail;
154: else if (r == 250)
155: return (EX_OK);
156: else if (r == 552)
157: goto unavailable;
158:
159: /* protocol error -- close up */
160: smtpquit(m);
161: return (EX_PROTOCOL);
162:
163: /* signal a temporary failure */
164: tempfail:
165: smtpquit(m);
166: return (EX_TEMPFAIL);
167:
168: /* signal service unavailable */
169: unavailable:
170: smtpquit(m);
171: return (EX_UNAVAILABLE);
172: }
173:
174:
175: static
176: greettimeout()
177: {
178: /* timeout reading the greeting message */
179: longjmp(CtxGreeting, 1);
180: }
181: /*
182: ** SMTPRCPT -- designate recipient.
183: **
184: ** Parameters:
185: ** to -- address of recipient.
186: ** m -- the mailer we are sending to.
187: **
188: ** Returns:
189: ** exit status corresponding to recipient status.
190: **
191: ** Side Effects:
192: ** Sends the mail via SMTP.
193: */
194:
195: smtprcpt(to, m)
196: ADDRESS *to;
197: register MAILER *m;
198: {
199: register int r;
200: extern char *remotename();
201:
202: smtpmessage("RCPT To:<%s>", m, remotename(to->q_user, m, FALSE, TRUE));
203:
204: r = reply(m);
205: if (r < 0 || REPLYTYPE(r) == 4)
206: return (EX_TEMPFAIL);
207: else if (REPLYTYPE(r) == 2)
208: return (EX_OK);
209: else if (r == 550 || r == 551 || r == 553)
210: return (EX_NOUSER);
211: else if (r == 552 || r == 554)
212: return (EX_UNAVAILABLE);
213: return (EX_PROTOCOL);
214: }
215: /*
216: ** SMTPDATA -- send the data and clean up the transaction.
217: **
218: ** Parameters:
219: ** m -- mailer being sent to.
220: ** e -- the envelope for this message.
221: **
222: ** Returns:
223: ** exit status corresponding to DATA command.
224: **
225: ** Side Effects:
226: ** none.
227: */
228:
229: smtpdata(m, e)
230: struct mailer *m;
231: register ENVELOPE *e;
232: {
233: register int r;
234:
235: /*
236: ** Send the data.
237: ** First send the command and check that it is ok.
238: ** Then send the data.
239: ** Follow it up with a dot to terminate.
240: ** Finally get the results of the transaction.
241: */
242:
243: /* send the command and check ok to proceed */
244: smtpmessage("DATA", m);
245: r = reply(m);
246: if (r < 0 || REPLYTYPE(r) == 4)
247: return (EX_TEMPFAIL);
248: else if (r == 554)
249: return (EX_UNAVAILABLE);
250: else if (r != 354)
251: return (EX_PROTOCOL);
252:
253: /* now output the actual message */
254: (*e->e_puthdr)(SmtpOut, m, CurEnv);
255: putline("\n", SmtpOut, m);
256: (*e->e_putbody)(SmtpOut, m, CurEnv);
257:
258: /* terminate the message */
259: fprintf(SmtpOut, ".%s", m->m_eol);
260: if (Verbose && !HoldErrs)
261: nmessage(Arpa_Info, ">>> .");
262:
263: /* check for the results of the transaction */
264: r = reply(m);
265: if (r < 0 || REPLYTYPE(r) == 4)
266: return (EX_TEMPFAIL);
267: else if (r == 250)
268: return (EX_OK);
269: else if (r == 552 || r == 554)
270: return (EX_UNAVAILABLE);
271: return (EX_PROTOCOL);
272: }
273: /*
274: ** SMTPQUIT -- close the SMTP connection.
275: **
276: ** Parameters:
277: ** name -- name of mailer we are quitting.
278: **
279: ** Returns:
280: ** none.
281: **
282: ** Side Effects:
283: ** sends the final protocol and closes the connection.
284: */
285:
286: smtpquit(name, m)
287: char *name;
288: register MAILER *m;
289: {
290: int i;
291:
292: /* if the connection is already closed, don't bother */
293: if (SmtpIn == NULL)
294: return;
295:
296: /* send the quit message if not a forced quit */
297: if (SmtpState == SMTP_OPEN || SmtpState == SMTP_SSD)
298: {
299: smtpmessage("QUIT", m);
300: (void) reply(m);
301: if (SmtpState == SMTP_CLOSED)
302: return;
303: }
304:
305: /* now actually close the connection */
306: (void) fclose(SmtpIn);
307: (void) fclose(SmtpOut);
308: SmtpIn = SmtpOut = NULL;
309: SmtpState = SMTP_CLOSED;
310:
311: /* and pick up the zombie */
312: i = endmailer(SmtpPid, name);
313: if (i != EX_OK)
314: syserr("smtpquit %s: stat %d", name, i);
315: }
316: /*
317: ** REPLY -- read arpanet reply
318: **
319: ** Parameters:
320: ** m -- the mailer we are reading the reply from.
321: **
322: ** Returns:
323: ** reply code it reads.
324: **
325: ** Side Effects:
326: ** flushes the mail file.
327: */
328:
329: reply(m)
330: MAILER *m;
331: {
332: (void) fflush(SmtpOut);
333:
334: if (tTd(18, 1))
335: printf("reply\n");
336:
337: /*
338: ** Read the input line, being careful not to hang.
339: */
340:
341: for (;;)
342: {
343: register int r;
344: register char *p;
345:
346: /* actually do the read */
347: if (CurEnv->e_xfp != NULL)
348: (void) fflush(CurEnv->e_xfp); /* for debugging */
349:
350: /* if we are in the process of closing just give the code */
351: if (SmtpState == SMTP_CLOSED)
352: return (SMTPCLOSING);
353:
354: /* get the line from the other side */
355: p = sfgets(SmtpReplyBuffer, sizeof SmtpReplyBuffer, SmtpIn);
356: if (p == NULL)
357: {
358: extern char MsgBuf[]; /* err.c */
359: extern char Arpa_TSyserr[]; /* conf.c */
360:
361: message(Arpa_TSyserr, "reply: read error");
362: # ifdef DEBUG
363: /* if debugging, pause so we can see state */
364: if (tTd(18, 100))
365: pause();
366: # endif DEBUG
367: # ifdef LOG
368: syslog(LOG_ERR, "%s", &MsgBuf[4]);
369: # endif LOG
370: SmtpState = SMTP_CLOSED;
371: smtpquit("reply error", m);
372: return (-1);
373: }
374: fixcrlf(SmtpReplyBuffer, TRUE);
375:
376: if (CurEnv->e_xfp != NULL && index("45", SmtpReplyBuffer[0]) != NULL)
377: {
378: /* serious error -- log the previous command */
379: if (SmtpMsgBuffer[0] != '\0')
380: fprintf(CurEnv->e_xfp, ">>> %s\n", SmtpMsgBuffer);
381: SmtpMsgBuffer[0] = '\0';
382:
383: /* now log the message as from the other side */
384: fprintf(CurEnv->e_xfp, "<<< %s\n", SmtpReplyBuffer);
385: }
386:
387: /* display the input for verbose mode */
388: if (Verbose && !HoldErrs)
389: nmessage(Arpa_Info, "%s", SmtpReplyBuffer);
390:
391: /* if continuation is required, we can go on */
392: if (SmtpReplyBuffer[3] == '-' || !isdigit(SmtpReplyBuffer[0]))
393: continue;
394:
395: /* decode the reply code */
396: r = atoi(SmtpReplyBuffer);
397:
398: /* extra semantics: 0xx codes are "informational" */
399: if (r < 100)
400: continue;
401:
402: /* reply code 421 is "Service Shutting Down" */
403: if (r == SMTPCLOSING && SmtpState != SMTP_SSD)
404: {
405: /* send the quit protocol */
406: SmtpState = SMTP_SSD;
407: smtpquit("SMTP Shutdown", m);
408: }
409:
410: return (r);
411: }
412: }
413: /*
414: ** SMTPMESSAGE -- send message to server
415: **
416: ** Parameters:
417: ** f -- format
418: ** m -- the mailer to control formatting.
419: ** a, b, c -- parameters
420: **
421: ** Returns:
422: ** none.
423: **
424: ** Side Effects:
425: ** writes message to SmtpOut.
426: */
427:
428: /*VARARGS1*/
429: smtpmessage(f, m, a, b, c)
430: char *f;
431: MAILER *m;
432: {
433: (void) sprintf(SmtpMsgBuffer, f, a, b, c);
434: if (tTd(18, 1) || (Verbose && !HoldErrs))
435: nmessage(Arpa_Info, ">>> %s", SmtpMsgBuffer);
436: if (SmtpOut != NULL)
437: fprintf(SmtpOut, "%s%s", SmtpMsgBuffer, m->m_eol);
438: }
439:
440: # endif SMTP
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.