Commit | Line | Data |
---|---|---|
b2a81223 | 1 | /* |
dc45ba8c | 2 | * Copyright (c) 1983 Eric P. Allman |
24634489 KB |
3 | * Copyright (c) 1988, 1993 |
4 | * The Regents of the University of California. All rights reserved. | |
bee79b64 | 5 | * |
417f7a11 | 6 | * %sccs.include.redist.c% |
bee79b64 KB |
7 | */ |
8 | ||
9 | # include "sendmail.h" | |
b2a81223 | 10 | |
bee79b64 KB |
11 | #ifndef lint |
12 | #ifdef SMTP | |
66d16835 | 13 | static char sccsid[] = "@(#)srvrsmtp.c 8.62 (Berkeley) %G% (with SMTP)"; |
bee79b64 | 14 | #else |
66d16835 | 15 | static char sccsid[] = "@(#)srvrsmtp.c 8.62 (Berkeley) %G% (without SMTP)"; |
bee79b64 KB |
16 | #endif |
17 | #endif /* not lint */ | |
b2a81223 | 18 | |
e6f08ab1 | 19 | # include <errno.h> |
6b861048 | 20 | |
bee79b64 | 21 | # ifdef SMTP |
d727056e | 22 | |
6b861048 EA |
23 | /* |
24 | ** SMTP -- run the SMTP protocol. | |
25 | ** | |
26 | ** Parameters: | |
27 | ** none. | |
28 | ** | |
29 | ** Returns: | |
30 | ** never. | |
31 | ** | |
32 | ** Side Effects: | |
33 | ** Reads commands from the input channel and processes | |
34 | ** them. | |
35 | */ | |
36 | ||
37 | struct cmd | |
38 | { | |
39 | char *cmdname; /* command name */ | |
40 | int cmdcode; /* internal code, see below */ | |
41 | }; | |
42 | ||
43 | /* values for cmdcode */ | |
44 | # define CMDERROR 0 /* bad command */ | |
45 | # define CMDMAIL 1 /* mail -- designate sender */ | |
4a4ebe09 | 46 | # define CMDRCPT 2 /* rcpt -- designate recipient */ |
6b861048 | 47 | # define CMDDATA 3 /* data -- send message text */ |
7d7fdf93 | 48 | # define CMDHOPS 4 /* hops -- specify hop count */ |
e6f08ab1 EA |
49 | # define CMDRSET 4 /* rset -- reset state */ |
50 | # define CMDVRFY 5 /* vrfy -- verify address */ | |
8f48def8 | 51 | # define CMDEXPN 6 /* expn -- expand address */ |
e6f08ab1 EA |
52 | # define CMDNOOP 7 /* noop -- do nothing */ |
53 | # define CMDQUIT 8 /* quit -- close connection and die */ | |
54 | # define CMDHELO 9 /* helo -- be polite */ | |
8f48def8 | 55 | # define CMDHELP 10 /* help -- give usage info */ |
34f2d20e | 56 | # define CMDEHLO 11 /* ehlo -- extended helo (RFC 1425) */ |
8f48def8 EA |
57 | /* non-standard commands */ |
58 | # define CMDONEX 16 /* onex -- sending one transaction only */ | |
59 | # define CMDVERB 17 /* verb -- go into verbose mode */ | |
3e8f46ad EA |
60 | /* use this to catch and log "door handle" attempts on your system */ |
61 | # define CMDLOGBOGUS 23 /* bogus command that should be logged */ | |
ab4889ea | 62 | /* debugging-only commands, only enabled if SMTPDEBUG is defined */ |
8f48def8 EA |
63 | # define CMDDBGQSHOW 24 /* showq -- show send queue */ |
64 | # define CMDDBGDEBUG 25 /* debug -- set debug mode */ | |
6b861048 EA |
65 | |
66 | static struct cmd CmdTab[] = | |
67 | { | |
68 | "mail", CMDMAIL, | |
4a4ebe09 | 69 | "rcpt", CMDRCPT, |
6b861048 | 70 | "data", CMDDATA, |
6b861048 EA |
71 | "rset", CMDRSET, |
72 | "vrfy", CMDVRFY, | |
8f48def8 | 73 | "expn", CMDEXPN, |
633a2e02 | 74 | "expn", CMDVRFY, |
6b861048 EA |
75 | "help", CMDHELP, |
76 | "noop", CMDNOOP, | |
77 | "quit", CMDQUIT, | |
4a4ebe09 | 78 | "helo", CMDHELO, |
34f2d20e | 79 | "ehlo", CMDEHLO, |
e8ad767d | 80 | "verb", CMDVERB, |
8fe4fb9b | 81 | "onex", CMDONEX, |
7d7fdf93 | 82 | "hops", CMDHOPS, |
ab4889ea MK |
83 | /* |
84 | * remaining commands are here only | |
85 | * to trap and log attempts to use them | |
86 | */ | |
e6f08ab1 | 87 | "showq", CMDDBGQSHOW, |
ad20d67b | 88 | "debug", CMDDBGDEBUG, |
3e8f46ad | 89 | "wiz", CMDLOGBOGUS, |
6b861048 EA |
90 | NULL, CMDERROR, |
91 | }; | |
92 | ||
7338e3d4 | 93 | bool OneXact = FALSE; /* one xaction only this run */ |
c9af7ef4 | 94 | char *CurSmtpClient; /* who's at the other end of channel */ |
1972fb40 | 95 | |
e6cb9fc4 | 96 | static char *skipword(); |
90f34501 EA |
97 | extern char RealUserName[]; |
98 | ||
e6cb9fc4 | 99 | |
f6603f3b EA |
100 | #define MAXBADCOMMANDS 25 /* maximum number of bad commands */ |
101 | ||
a4076aed EA |
102 | smtp(e) |
103 | register ENVELOPE *e; | |
6b861048 | 104 | { |
6b861048 | 105 | register char *p; |
e8ad767d | 106 | register struct cmd *c; |
6b861048 | 107 | char *cmd; |
abae7b2d EA |
108 | extern ADDRESS *sendto(); |
109 | ADDRESS *a; | |
6b861048 | 110 | |
abae7b2d | 111 | hasmail = FALSE; |
20219e3f | 112 | if (fileno(OutChannel) != fileno(stdout)) |
1f1cc003 EA |
113 | { |
114 | /* arrange for debugging output to go to remote host */ | |
20219e3f | 115 | (void) dup2(fileno(OutChannel), fileno(stdout)); |
1f1cc003 | 116 | } |
a4076aed | 117 | settime(e); |
7c8c5b90 EA |
118 | peerhostname = RealHostName; |
119 | if (peerhostname == NULL) | |
120 | peerhostname = "localhost"; | |
121 | CurHostName = peerhostname; | |
c9af7ef4 EA |
122 | CurSmtpClient = macvalue('_', e); |
123 | if (CurSmtpClient == NULL) | |
389c0d5e | 124 | CurSmtpClient = CurHostName; |
c9af7ef4 EA |
125 | |
126 | setproctitle("server %s startup", CurSmtpClient); | |
832e8a27 | 127 | expand("\201e", inp, sizeof inp, e); |
53ae7b6c EA |
128 | if (BrokenSmtpPeers) |
129 | { | |
5f0e0cf2 EA |
130 | p = strchr(inp, '\n'); |
131 | if (p != NULL) | |
132 | *p = '\0'; | |
53ae7b6c EA |
133 | message("220 %s", inp); |
134 | } | |
135 | else | |
136 | { | |
fb617949 EA |
137 | char *q = inp; |
138 | ||
139 | while (q != NULL) | |
140 | { | |
5f0e0cf2 | 141 | p = strchr(q, '\n'); |
fb617949 EA |
142 | if (p != NULL) |
143 | *p++ = '\0'; | |
5f0e0cf2 EA |
144 | message("220-%s", q); |
145 | q = p; | |
fb617949 | 146 | } |
53ae7b6c EA |
147 | message("220 ESMTP spoken here"); |
148 | } | |
6fd6d536 | 149 | protocol = NULL; |
37444fe1 | 150 | sendinghost = macvalue('s', e); |
1c7897ef | 151 | gothello = FALSE; |
6fd6d536 | 152 | gotmail = FALSE; |
6b861048 EA |
153 | for (;;) |
154 | { | |
d344c0b7 | 155 | /* arrange for backout */ |
c583011b | 156 | if (setjmp(TopFrame) > 0) |
b8bf5eba | 157 | { |
c583011b EA |
158 | /* if() nesting is necessary for Cray UNICOS */ |
159 | if (InChild) | |
160 | { | |
161 | QuickAbort = FALSE; | |
162 | SuprErrs = TRUE; | |
163 | finis(); | |
164 | } | |
b8bf5eba | 165 | } |
d344c0b7 EA |
166 | QuickAbort = FALSE; |
167 | HoldErrs = FALSE; | |
f61c3c40 | 168 | LogUsrErrs = FALSE; |
4b72e6db | 169 | e->e_flags &= ~(EF_VRFYONLY|EF_GLOBALERRS); |
d344c0b7 | 170 | |
37eaaadb | 171 | /* setup for the read */ |
a4076aed | 172 | e->e_to = NULL; |
34d37b7d | 173 | Errors = 0; |
09eb49d8 | 174 | (void) fflush(stdout); |
37eaaadb | 175 | |
37eaaadb | 176 | /* read the input line */ |
8e948497 EA |
177 | SmtpPhase = "server cmd read"; |
178 | setproctitle("server %s cmd read", CurHostName); | |
179 | p = sfgets(inp, sizeof inp, InChannel, TimeOuts.to_nextcommand, | |
180 | SmtpPhase); | |
37eaaadb | 181 | |
2439b900 | 182 | /* handle errors */ |
37eaaadb | 183 | if (p == NULL) |
6b861048 EA |
184 | { |
185 | /* end of file, just die */ | |
33cbaada | 186 | disconnect(1, e); |
b6edea3d | 187 | message("421 %s Lost input channel from %s", |
c9af7ef4 | 188 | MyHostName, CurSmtpClient); |
6d6f9196 | 189 | #ifdef LOG |
4b72e6db | 190 | if (LogLevel > (gotmail ? 1 : 19)) |
6d6f9196 | 191 | syslog(LOG_NOTICE, "lost input channel from %s", |
c9af7ef4 | 192 | CurSmtpClient); |
6d6f9196 | 193 | #endif |
074b0256 EA |
194 | if (InChild) |
195 | ExitStat = EX_QUIT; | |
6b861048 EA |
196 | finis(); |
197 | } | |
198 | ||
199 | /* clean up end of line */ | |
2768afe3 | 200 | fixcrlf(inp, TRUE); |
6b861048 | 201 | |
49086753 | 202 | /* echo command to transcript */ |
a4076aed EA |
203 | if (e->e_xfp != NULL) |
204 | fprintf(e->e_xfp, "<<< %s\n", inp); | |
49086753 | 205 | |
ade7da2a | 206 | if (e->e_id == NULL) |
e42c7981 | 207 | setproctitle("%s: %.80s", CurSmtpClient, inp); |
ade7da2a | 208 | else |
e42c7981 | 209 | setproctitle("%s %s: %.80s", e->e_id, CurSmtpClient, inp); |
ade7da2a | 210 | |
6b861048 | 211 | /* break off command */ |
2bee003d | 212 | for (p = inp; isascii(*p) && isspace(*p); p++) |
6b861048 | 213 | continue; |
f43b04ce | 214 | cmd = cmdbuf; |
2bee003d EA |
215 | while (*p != '\0' && |
216 | !(isascii(*p) && isspace(*p)) && | |
217 | cmd < &cmdbuf[sizeof cmdbuf - 2]) | |
a0225d08 EA |
218 | *cmd++ = *p++; |
219 | *cmd = '\0'; | |
6b861048 | 220 | |
a1a07282 | 221 | /* throw away leading whitespace */ |
2bee003d | 222 | while (isascii(*p) && isspace(*p)) |
a1a07282 EA |
223 | p++; |
224 | ||
6b861048 EA |
225 | /* decode command */ |
226 | for (c = CmdTab; c->cmdname != NULL; c++) | |
227 | { | |
ed73ef1d | 228 | if (!strcasecmp(c->cmdname, cmdbuf)) |
6b861048 EA |
229 | break; |
230 | } | |
231 | ||
5ae51cd5 EA |
232 | /* reset errors */ |
233 | errno = 0; | |
234 | ||
6b861048 EA |
235 | /* process command */ |
236 | switch (c->cmdcode) | |
237 | { | |
4a4ebe09 | 238 | case CMDHELO: /* hello -- introduce yourself */ |
34f2d20e EA |
239 | case CMDEHLO: /* extended hello */ |
240 | if (c->cmdcode == CMDEHLO) | |
241 | { | |
242 | protocol = "ESMTP"; | |
8e948497 | 243 | SmtpPhase = "server EHLO"; |
34f2d20e EA |
244 | } |
245 | else | |
246 | { | |
247 | protocol = "SMTP"; | |
8e948497 | 248 | SmtpPhase = "server HELO"; |
34f2d20e | 249 | } |
825424db EA |
250 | |
251 | /* check for valid domain name (re 1123 5.2.5) */ | |
252 | if (*p == '\0') | |
253 | { | |
254 | message("501 %s requires domain address", | |
255 | cmdbuf); | |
256 | break; | |
257 | } | |
258 | else | |
259 | { | |
260 | register char *q; | |
261 | ||
262 | for (q = p; *q != '\0'; q++) | |
263 | { | |
264 | if (!isascii(*q)) | |
265 | break; | |
266 | if (isalnum(*q)) | |
267 | continue; | |
268 | if (strchr("[].-_#", *q) == NULL) | |
269 | break; | |
270 | } | |
271 | if (*q != '\0') | |
272 | { | |
273 | message("501 Invalid domain name"); | |
274 | break; | |
275 | } | |
276 | } | |
277 | ||
37444fe1 | 278 | sendinghost = newstr(p); |
abae7b2d | 279 | message("250", "%s Hello %s, pleased to meet you", HostName, p); |
4a4ebe09 EA |
280 | break; |
281 | ||
6b861048 | 282 | case CMDMAIL: /* mail -- designate sender */ |
8e948497 | 283 | SmtpPhase = "server MAIL"; |
2e3062fe | 284 | |
8fe4fb9b | 285 | /* check for validity of this command */ |
94bc039a | 286 | if (!gothello) |
1c7897ef | 287 | { |
a9bac7a9 | 288 | /* set sending host to our known value */ |
37444fe1 | 289 | if (sendinghost == NULL) |
7c8c5b90 | 290 | sendinghost = peerhostname; |
a9bac7a9 | 291 | |
94bc039a | 292 | if (bitset(PRIV_NEEDMAILHELO, PrivacyFlags)) |
f967c46a | 293 | { |
94bc039a | 294 | message("503 Polite people say HELO first"); |
f967c46a EA |
295 | break; |
296 | } | |
1c7897ef | 297 | } |
3b87200d | 298 | if (gotmail) |
2768afe3 | 299 | { |
b6edea3d | 300 | message("503 Sender already specified"); |
4b72e6db EA |
301 | if (InChild) |
302 | finis(); | |
2768afe3 EA |
303 | break; |
304 | } | |
e6f08ab1 EA |
305 | if (InChild) |
306 | { | |
ab4889ea | 307 | errno = 0; |
b6edea3d | 308 | syserr("503 Nested MAIL command: MAIL %s", p); |
074b0256 | 309 | finis(); |
e6f08ab1 EA |
310 | } |
311 | ||
312 | /* fork a subprocess to process this command */ | |
a4076aed | 313 | if (runinchild("SMTP-MAIL", e) > 0) |
e6f08ab1 | 314 | break; |
8e5c6745 EA |
315 | if (!gothello) |
316 | { | |
317 | auth_warning(e, | |
7c8c5b90 EA |
318 | "Host %s didn't use HELO protocol", |
319 | peerhostname); | |
8e5c6745 | 320 | } |
3bb5d0e6 | 321 | #ifdef PICKY_HELO_CHECK |
7c8c5b90 EA |
322 | if (strcasecmp(sendinghost, peerhostname) != 0 && |
323 | (strcasecmp(peerhostname, "localhost") != 0 || | |
2d5db20a EA |
324 | strcasecmp(sendinghost, MyHostName) != 0)) |
325 | { | |
326 | auth_warning(e, "Host %s claimed to be %s", | |
7c8c5b90 | 327 | peerhostname, sendinghost); |
2d5db20a | 328 | } |
3bb5d0e6 | 329 | #endif |
2d5db20a | 330 | |
34f2d20e EA |
331 | if (protocol == NULL) |
332 | protocol = "SMTP"; | |
333 | define('r', protocol, e); | |
37444fe1 | 334 | define('s', sendinghost, e); |
a4076aed | 335 | initsys(e); |
fba945cd | 336 | nrcpts = 0; |
3dd1581c | 337 | e->e_flags |= EF_LOGSENDER|EF_CLRQUEUE; |
e42c7981 | 338 | setproctitle("%s %s: %.80s", e->e_id, CurSmtpClient, inp); |
e6f08ab1 EA |
339 | |
340 | /* child -- go do the processing */ | |
6b861048 EA |
341 | p = skipword(p, "from"); |
342 | if (p == NULL) | |
343 | break; | |
aa102c71 | 344 | if (setjmp(TopFrame) > 0) |
182c060a EA |
345 | { |
346 | /* this failed -- undo work */ | |
347 | if (InChild) | |
b8bf5eba EA |
348 | { |
349 | QuickAbort = FALSE; | |
350 | SuprErrs = TRUE; | |
fd57f063 | 351 | e->e_flags &= ~EF_FATALERRS; |
182c060a | 352 | finis(); |
b8bf5eba | 353 | } |
aa102c71 | 354 | break; |
182c060a | 355 | } |
aa102c71 | 356 | QuickAbort = TRUE; |
9e2cf26f EA |
357 | |
358 | /* must parse sender first */ | |
359 | delimptr = NULL; | |
4a2da288 | 360 | setsender(p, e, &delimptr, FALSE); |
9e2cf26f EA |
361 | p = delimptr; |
362 | if (p != NULL && *p != '\0') | |
363 | *p++ = '\0'; | |
364 | ||
90f34501 EA |
365 | /* check for possible spoofing */ |
366 | if (RealUid != 0 && OpMode == MD_SMTP && | |
2bade550 EA |
367 | !bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags) && |
368 | strcmp(e->e_from.q_user, RealUserName) != 0) | |
90f34501 EA |
369 | { |
370 | auth_warning(e, "%s owned process doing -bs", | |
371 | RealUserName); | |
372 | } | |
373 | ||
9e2cf26f | 374 | /* now parse ESMTP arguments */ |
81e7e79e | 375 | e->e_msgsize = 0; |
24e2a159 | 376 | while (p != NULL && *p != '\0') |
9e2cf26f EA |
377 | { |
378 | char *kp; | |
89346287 | 379 | char *vp = NULL; |
9e2cf26f EA |
380 | |
381 | /* locate the beginning of the keyword */ | |
382 | while (isascii(*p) && isspace(*p)) | |
383 | p++; | |
384 | if (*p == '\0') | |
385 | break; | |
386 | kp = p; | |
387 | ||
388 | /* skip to the value portion */ | |
389 | while (isascii(*p) && isalnum(*p) || *p == '-') | |
390 | p++; | |
391 | if (*p == '=') | |
392 | { | |
393 | *p++ = '\0'; | |
394 | vp = p; | |
395 | ||
396 | /* skip to the end of the value */ | |
397 | while (*p != '\0' && *p != ' ' && | |
398 | !(isascii(*p) && iscntrl(*p)) && | |
399 | *p != '=') | |
400 | p++; | |
401 | } | |
402 | ||
403 | if (*p != '\0') | |
404 | *p++ = '\0'; | |
405 | ||
406 | if (tTd(19, 1)) | |
24e2a159 | 407 | printf("MAIL: got arg %s=\"%s\"\n", kp, |
9e2cf26f EA |
408 | vp == NULL ? "<null>" : vp); |
409 | ||
c7a0eaaf | 410 | mail_esmtp_args(kp, vp, e); |
9e2cf26f | 411 | } |
346fe280 | 412 | |
81e7e79e | 413 | if (MaxMessageSize > 0 && e->e_msgsize > MaxMessageSize) |
346fe280 EA |
414 | { |
415 | usrerr("552 Message size exceeds fixed maximum message size (%ld)", | |
416 | MaxMessageSize); | |
417 | /* NOTREACHED */ | |
418 | } | |
9e2cf26f | 419 | |
81e7e79e | 420 | if (!enoughspace(e->e_msgsize)) |
9e2cf26f EA |
421 | { |
422 | message("452 Insufficient disk space; try again later"); | |
423 | break; | |
424 | } | |
b6edea3d | 425 | message("250 Sender ok"); |
182c060a | 426 | gotmail = TRUE; |
506a2500 EA |
427 | |
428 | /* optimize: non-interactive, don't expand aliases */ | |
28a8a6ef | 429 | if (e->e_sendmode != SM_DELIVER) |
506a2500 EA |
430 | e->e_flags |= EF_VRFYONLY; |
431 | ||
6b861048 EA |
432 | break; |
433 | ||
4a4ebe09 | 434 | case CMDRCPT: /* rcpt -- designate recipient */ |
d7f41a7b EA |
435 | if (!gotmail) |
436 | { | |
437 | usrerr("503 Need MAIL before RCPT"); | |
438 | break; | |
439 | } | |
8e948497 | 440 | SmtpPhase = "server RCPT"; |
d344c0b7 | 441 | if (setjmp(TopFrame) > 0) |
9bfb75c1 | 442 | { |
a4076aed | 443 | e->e_flags &= ~EF_FATALERRS; |
d344c0b7 | 444 | break; |
9bfb75c1 | 445 | } |
d344c0b7 | 446 | QuickAbort = TRUE; |
f61c3c40 | 447 | LogUsrErrs = TRUE; |
6b861048 EA |
448 | p = skipword(p, "to"); |
449 | if (p == NULL) | |
450 | break; | |
abae7b2d EA |
451 | a = sendto(p, 1, (ADDRESS *) NULL, 0); |
452 | # ifdef DEBUG | |
453 | if (Debug > 1) | |
454 | printaddr(a, TRUE); | |
455 | # endif DEBUG | |
d344c0b7 EA |
456 | if (Errors != 0) |
457 | break; | |
458 | ||
459 | /* no errors during parsing, but might be a duplicate */ | |
a4076aed | 460 | e->e_to = p; |
d344c0b7 | 461 | if (!bitset(QBADADDR, a->q_flags)) |
fba945cd | 462 | { |
fe3849ea EA |
463 | message("250 Recipient ok%s", |
464 | bitset(QQUEUEUP, a->q_flags) ? | |
465 | " (will queue)" : ""); | |
fba945cd EA |
466 | nrcpts++; |
467 | } | |
d344c0b7 | 468 | else |
6b861048 | 469 | { |
d344c0b7 | 470 | /* punt -- should keep message in ADDRESS.... */ |
b6edea3d | 471 | message("550 Addressee unknown"); |
6b861048 | 472 | } |
a4076aed | 473 | e->e_to = NULL; |
6b861048 EA |
474 | break; |
475 | ||
476 | case CMDDATA: /* data -- text of mail */ | |
8e948497 | 477 | SmtpPhase = "server DATA"; |
3b87200d | 478 | if (!gotmail) |
4a4ebe09 | 479 | { |
b6edea3d | 480 | message("503 Need MAIL command"); |
4a4ebe09 EA |
481 | break; |
482 | } | |
fe3849ea | 483 | else if (nrcpts <= 0) |
6b861048 | 484 | { |
b6edea3d | 485 | message("503 Need RCPT (recipient)"); |
4a4ebe09 | 486 | break; |
6b861048 | 487 | } |
4a4ebe09 | 488 | |
959cf51d | 489 | /* check to see if we need to re-expand aliases */ |
fd57f063 EA |
490 | /* also reset QBADADDR on already-diagnosted addrs */ |
491 | doublequeue = FALSE; | |
959cf51d EA |
492 | for (a = e->e_sendqueue; a != NULL; a = a->q_next) |
493 | { | |
494 | if (bitset(QVERIFIED, a->q_flags)) | |
fd57f063 EA |
495 | { |
496 | /* need to re-expand aliases */ | |
497 | doublequeue = TRUE; | |
498 | } | |
499 | if (bitset(QBADADDR, a->q_flags)) | |
500 | { | |
501 | /* make this "go away" */ | |
502 | a->q_flags |= QDONTSEND; | |
503 | a->q_flags &= ~QBADADDR; | |
504 | } | |
959cf51d EA |
505 | } |
506 | ||
4a4ebe09 | 507 | /* collect the text of the message */ |
2e3062fe | 508 | SmtpPhase = "collect"; |
c23930c0 | 509 | collect(InChannel, TRUE, doublequeue, NULL, e); |
4f8e0a23 EA |
510 | if (Errors != 0) |
511 | goto abortmessage; | |
439fd0d9 | 512 | |
3dd1581c EA |
513 | /* make sure we actually do delivery */ |
514 | e->e_flags &= ~EF_CLRQUEUE; | |
515 | ||
439fd0d9 | 516 | /* from now on, we have to operate silently */ |
4f8e0a23 | 517 | HoldErrs = TRUE; |
439fd0d9 | 518 | e->e_errormode = EM_MAIL; |
4a4ebe09 | 519 | |
8eedb496 EA |
520 | /* |
521 | ** Arrange to send to everyone. | |
522 | ** If sending to multiple people, mail back | |
523 | ** errors rather than reporting directly. | |
524 | ** In any case, don't mail back errors for | |
525 | ** anything that has happened up to | |
526 | ** now (the other end will do this). | |
bcf74f25 EA |
527 | ** Truncate our transcript -- the mail has gotten |
528 | ** to us successfully, and if we have | |
529 | ** to mail this back, it will be easier | |
530 | ** on the reader. | |
8eedb496 EA |
531 | ** Then send to everyone. |
532 | ** Finally give a reply code. If an error has | |
533 | ** already been given, don't mail a | |
534 | ** message back. | |
e6f08ab1 | 535 | ** We goose error returns by clearing error bit. |
8eedb496 EA |
536 | */ |
537 | ||
2e3062fe | 538 | SmtpPhase = "delivery"; |
a4076aed | 539 | e->e_xfp = freopen(queuename(e, 'x'), "w", e->e_xfp); |
4aed8f3a | 540 | id = e->e_id; |
4a4ebe09 | 541 | |
439fd0d9 | 542 | if (doublequeue) |
2f6a8a78 | 543 | { |
439fd0d9 EA |
544 | /* make sure it is in the queue */ |
545 | queueup(e, TRUE, FALSE); | |
96a1575a EA |
546 | if (e->e_sendmode == SM_QUEUE) |
547 | e->e_flags |= EF_KEEPQUEUE; | |
2f6a8a78 EA |
548 | } |
549 | else | |
a891bb7e | 550 | { |
439fd0d9 EA |
551 | /* send to all recipients */ |
552 | sendall(e, SM_DEFAULT); | |
553 | } | |
554 | e->e_to = NULL; | |
fba945cd | 555 | |
439fd0d9 EA |
556 | /* issue success message */ |
557 | message("250 %s Message accepted for delivery", id); | |
d0268270 | 558 | |
439fd0d9 EA |
559 | /* if we just queued, poke it */ |
560 | if (doublequeue && e->e_sendmode != SM_QUEUE) | |
561 | { | |
562 | extern pid_t dowork(); | |
563 | ||
564 | unlockqueue(e); | |
565 | (void) dowork(id, TRUE, TRUE, e); | |
a891bb7e EA |
566 | } |
567 | ||
6366413a EA |
568 | /* now make it really happen */ |
569 | if (!Verbose && e->e_sendmode != SM_QUEUE) | |
570 | dowork(id, TRUE, e); | |
571 | ||
fba945cd | 572 | abortmessage: |
e6f08ab1 EA |
573 | /* if in a child, pop back to our parent */ |
574 | if (InChild) | |
575 | finis(); | |
2e3062fe EA |
576 | |
577 | /* clean up a bit */ | |
3b87200d | 578 | gotmail = FALSE; |
a4076aed | 579 | dropenvelope(e); |
fda58daa | 580 | CurEnv = e = newenvelope(e, CurEnv); |
a4076aed | 581 | e->e_flags = BlankEnvelope.e_flags; |
6b861048 EA |
582 | break; |
583 | ||
584 | case CMDRSET: /* rset -- reset state */ | |
b6edea3d | 585 | message("250 Reset state"); |
66d16835 EA |
586 | |
587 | /* arrange to ignore any current send list */ | |
588 | e->e_sendqueue = NULL; | |
80662ec6 | 589 | e->e_flags |= EF_CLRQUEUE; |
e6f08ab1 EA |
590 | if (InChild) |
591 | finis(); | |
3b87200d EA |
592 | |
593 | /* clean up a bit */ | |
594 | gotmail = FALSE; | |
595 | dropenvelope(e); | |
fda58daa | 596 | CurEnv = e = newenvelope(e, CurEnv); |
e6f08ab1 | 597 | break; |
6b861048 EA |
598 | |
599 | case CMDVRFY: /* vrfy -- verify address */ | |
8f48def8 EA |
600 | case CMDEXPN: /* expn -- expand address */ |
601 | vrfy = c->cmdcode == CMDVRFY; | |
602 | if (bitset(vrfy ? PRIV_NOVRFY : PRIV_NOEXPN, | |
603 | PrivacyFlags)) | |
1c7897ef | 604 | { |
efae59f3 | 605 | if (vrfy) |
cb282b01 | 606 | message("252 Cannot VRFY user; try RCPT to attempt delivery (or try finger)"); |
efae59f3 | 607 | else |
c5b74eae | 608 | message("502 Sorry, we do not allow this operation"); |
c9af7ef4 EA |
609 | #ifdef LOG |
610 | if (LogLevel > 5) | |
611 | syslog(LOG_INFO, "%s: %s [rejected]", | |
612 | CurSmtpClient, inp); | |
613 | #endif | |
1c7897ef EA |
614 | break; |
615 | } | |
616 | else if (!gothello && | |
8f48def8 EA |
617 | bitset(vrfy ? PRIV_NEEDVRFYHELO : PRIV_NEEDEXPNHELO, |
618 | PrivacyFlags)) | |
1c7897ef | 619 | { |
b6edea3d | 620 | message("503 I demand that you introduce yourself first"); |
1c7897ef EA |
621 | break; |
622 | } | |
8f48def8 | 623 | if (runinchild(vrfy ? "SMTP-VRFY" : "SMTP-EXPN", e) > 0) |
e6f08ab1 | 624 | break; |
01e8020e | 625 | #ifdef LOG |
68f7099c | 626 | if (LogLevel > 5) |
c9af7ef4 | 627 | syslog(LOG_INFO, "%s: %s", CurSmtpClient, inp); |
01e8020e | 628 | #endif |
abae7b2d | 629 | paddrtree(a); |
6b861048 EA |
630 | break; |
631 | ||
632 | case CMDHELP: /* help -- give user info */ | |
34d37b7d | 633 | help(p); |
6b861048 EA |
634 | break; |
635 | ||
636 | case CMDNOOP: /* noop -- do nothing */ | |
422d9f83 | 637 | message("250 OK"); |
6b861048 EA |
638 | break; |
639 | ||
640 | case CMDQUIT: /* quit -- leave mail */ | |
b6edea3d | 641 | message("221 %s closing connection", MyHostName); |
251126e0 | 642 | |
f6603f3b | 643 | doquit: |
66d16835 EA |
644 | /* arrange to ignore any current send list */ |
645 | e->e_sendqueue = NULL; | |
646 | ||
251126e0 | 647 | /* avoid future 050 messages */ |
33cbaada | 648 | disconnect(1, e); |
251126e0 | 649 | |
e6f08ab1 EA |
650 | if (InChild) |
651 | ExitStat = EX_QUIT; | |
6b861048 EA |
652 | finis(); |
653 | ||
e8ad767d | 654 | case CMDVERB: /* set verbose mode */ |
de975e1b EA |
655 | if (bitset(PRIV_NOEXPN, PrivacyFlags)) |
656 | { | |
657 | /* this would give out the same info */ | |
658 | message("502 Verbose unavailable"); | |
659 | break; | |
660 | } | |
e8ad767d | 661 | Verbose = TRUE; |
8c8e8e94 | 662 | e->e_sendmode = SM_DELIVER; |
de975e1b | 663 | message("250 Verbose mode"); |
e8ad767d EA |
664 | break; |
665 | ||
8fe4fb9b | 666 | case CMDONEX: /* doing one transaction only */ |
7338e3d4 | 667 | OneXact = TRUE; |
de975e1b | 668 | message("250 Only one transaction"); |
8fe4fb9b EA |
669 | break; |
670 | ||
ab4889ea | 671 | # ifdef SMTPDEBUG |
e6f08ab1 | 672 | case CMDDBGQSHOW: /* show queues */ |
2654b031 | 673 | printf("Send Queue="); |
a4076aed | 674 | printaddr(e->e_sendqueue, TRUE); |
d4f42161 | 675 | break; |
09eb49d8 EA |
676 | |
677 | case CMDDBGDEBUG: /* set debug mode */ | |
9678c96d EA |
678 | tTsetup(tTdvect, sizeof tTdvect, "0-99.1"); |
679 | tTflag(p); | |
b6edea3d | 680 | message("200 Debug set"); |
09eb49d8 EA |
681 | break; |
682 | ||
ab4889ea | 683 | # else /* not SMTPDEBUG */ |
ab4889ea MK |
684 | case CMDDBGQSHOW: /* show queues */ |
685 | case CMDDBGDEBUG: /* set debug mode */ | |
3e8f46ad EA |
686 | # endif /* SMTPDEBUG */ |
687 | case CMDLOGBOGUS: /* bogus command */ | |
2e15a2d8 | 688 | # ifdef LOG |
5973222c | 689 | if (LogLevel > 0) |
3e8f46ad | 690 | syslog(LOG_CRIT, |
68f7099c | 691 | "\"%s\" command from %s (%s)", |
7c8c5b90 | 692 | c->cmdname, peerhostname, |
3341995c | 693 | anynet_ntoa(&RealHostAddr)); |
2e15a2d8 | 694 | # endif |
ab4889ea | 695 | /* FALL THROUGH */ |
d4f42161 | 696 | |
6b861048 | 697 | case CMDERROR: /* unknown command */ |
f6603f3b EA |
698 | if (++badcommands > MAXBADCOMMANDS) |
699 | { | |
700 | message("421 %s Too many bad commands; closing connection", | |
701 | MyHostName); | |
702 | goto doquit; | |
703 | } | |
704 | ||
b6edea3d | 705 | message("500 Command unrecognized"); |
6b861048 EA |
706 | break; |
707 | ||
708 | default: | |
ab4889ea | 709 | errno = 0; |
b6edea3d | 710 | syserr("500 smtp: unknown code %d", c->cmdcode); |
6b861048 EA |
711 | break; |
712 | } | |
713 | } | |
714 | } | |
715 | \f/* | |
716 | ** SKIPWORD -- skip a fixed word. | |
717 | ** | |
718 | ** Parameters: | |
719 | ** p -- place to start looking. | |
720 | ** w -- word to skip. | |
721 | ** | |
722 | ** Returns: | |
723 | ** p following w. | |
724 | ** NULL on error. | |
725 | ** | |
726 | ** Side Effects: | |
727 | ** clobbers the p data area. | |
728 | */ | |
729 | ||
730 | static char * | |
731 | skipword(p, w) | |
732 | register char *p; | |
733 | char *w; | |
734 | { | |
735 | register char *q; | |
7c8c5b90 | 736 | char *firstp = p; |
6b861048 EA |
737 | |
738 | /* find beginning of word */ | |
2bee003d | 739 | while (isascii(*p) && isspace(*p)) |
6b861048 EA |
740 | p++; |
741 | q = p; | |
742 | ||
743 | /* find end of word */ | |
2bee003d | 744 | while (*p != '\0' && *p != ':' && !(isascii(*p) && isspace(*p))) |
6b861048 | 745 | p++; |
2bee003d | 746 | while (isascii(*p) && isspace(*p)) |
6b861048 EA |
747 | *p++ = '\0'; |
748 | if (*p != ':') | |
749 | { | |
750 | syntax: | |
7c8c5b90 EA |
751 | message("501 Syntax error in parameters scanning \"%s\"", |
752 | firstp); | |
6b861048 EA |
753 | Errors++; |
754 | return (NULL); | |
755 | } | |
756 | *p++ = '\0'; | |
2bee003d | 757 | while (isascii(*p) && isspace(*p)) |
6b861048 EA |
758 | p++; |
759 | ||
20f20f1e EA |
760 | if (*p == '\0') |
761 | goto syntax; | |
762 | ||
6b861048 | 763 | /* see if the input word matches desired word */ |
ed73ef1d | 764 | if (strcasecmp(q, w)) |
6b861048 EA |
765 | goto syntax; |
766 | ||
767 | return (p); | |
768 | } | |
34d37b7d | 769 | \f/* |
c7a0eaaf EA |
770 | ** MAIL_ESMTP_ARGS -- process ESMTP arguments from MAIL line |
771 | ** | |
772 | ** Parameters: | |
773 | ** kp -- the parameter key. | |
774 | ** vp -- the value of that parameter. | |
775 | ** e -- the envelope. | |
776 | ** | |
777 | ** Returns: | |
778 | ** none. | |
779 | */ | |
780 | ||
781 | mail_esmtp_args(kp, vp, e) | |
782 | char *kp; | |
783 | char *vp; | |
784 | ENVELOPE *e; | |
785 | { | |
786 | if (strcasecmp(kp, "size") == 0) | |
787 | { | |
788 | if (vp == NULL) | |
789 | { | |
790 | usrerr("501 SIZE requires a value"); | |
791 | /* NOTREACHED */ | |
792 | } | |
793 | # ifdef __STDC__ | |
81e7e79e | 794 | e->e_msgsize = strtoul(vp, (char **) NULL, 10); |
c7a0eaaf | 795 | # else |
81e7e79e | 796 | e->e_msgsize = strtol(vp, (char **) NULL, 10); |
c7a0eaaf EA |
797 | # endif |
798 | } | |
799 | else if (strcasecmp(kp, "body") == 0) | |
800 | { | |
801 | if (vp == NULL) | |
802 | { | |
803 | usrerr("501 BODY requires a value"); | |
804 | /* NOTREACHED */ | |
805 | } | |
806 | if (strcasecmp(vp, "8bitmime") == 0) | |
807 | { | |
808 | SevenBitInput = FALSE; | |
809 | } | |
810 | else if (strcasecmp(vp, "7bit") == 0) | |
811 | { | |
812 | SevenBitInput = TRUE; | |
813 | } | |
814 | else | |
815 | { | |
816 | usrerr("501 Unknown BODY type %s", | |
817 | vp); | |
818 | /* NOTREACHED */ | |
819 | } | |
820 | e->e_bodytype = newstr(vp); | |
821 | } | |
822 | else if (strcasecmp(kp, "envid") == 0) | |
823 | { | |
824 | if (vp == NULL) | |
825 | { | |
826 | usrerr("501 ENVID requires a value"); | |
827 | /* NOTREACHED */ | |
828 | } | |
8b6906e3 EA |
829 | if (!xtextok(vp)) |
830 | { | |
831 | usrerr("501 Syntax error in ENVID parameter value"); | |
832 | /* NOTREACHED */ | |
833 | } | |
834 | if (e->e_envid != NULL) | |
835 | { | |
836 | usrerr("501 Duplicate ENVID parameter"); | |
837 | /* NOTREACHED */ | |
838 | } | |
c7a0eaaf EA |
839 | e->e_envid = newstr(vp); |
840 | } | |
841 | else if (strcasecmp(kp, "ret") == 0) | |
842 | { | |
843 | if (vp == NULL) | |
844 | { | |
845 | usrerr("501 RET requires a value"); | |
846 | /* NOTREACHED */ | |
847 | } | |
8b6906e3 EA |
848 | if (bitset(EF_RET_PARAM, e->e_flags)) |
849 | { | |
850 | usrerr("501 Duplicate RET parameter"); | |
851 | /* NOTREACHED */ | |
852 | } | |
c7a0eaaf EA |
853 | e->e_flags |= EF_RET_PARAM; |
854 | if (strcasecmp(vp, "hdrs") == 0) | |
855 | e->e_flags |= EF_NO_BODY_RETN; | |
856 | else if (strcasecmp(vp, "full") != 0) | |
857 | { | |
858 | usrerr("501 Bad argument \"%s\" to RET", vp); | |
859 | /* NOTREACHED */ | |
860 | } | |
861 | } | |
862 | else | |
863 | { | |
864 | usrerr("501 %s parameter unrecognized", kp); | |
865 | /* NOTREACHED */ | |
866 | } | |
867 | } | |
868 | \f/* | |
82e3dc75 EA |
869 | ** RCPT_ESMTP_ARGS -- process ESMTP arguments from RCPT line |
870 | ** | |
871 | ** Parameters: | |
872 | ** a -- the address corresponding to the To: parameter. | |
873 | ** kp -- the parameter key. | |
874 | ** vp -- the value of that parameter. | |
875 | ** e -- the envelope. | |
876 | ** | |
877 | ** Returns: | |
878 | ** none. | |
879 | */ | |
880 | ||
881 | rcpt_esmtp_args(a, kp, vp, e) | |
882 | ADDRESS *a; | |
883 | char *kp; | |
884 | char *vp; | |
885 | ENVELOPE *e; | |
886 | { | |
887 | if (strcasecmp(kp, "notify") == 0) | |
888 | { | |
889 | char *p; | |
890 | ||
891 | if (vp == NULL) | |
892 | { | |
893 | usrerr("501 NOTIFY requires a value"); | |
894 | /* NOTREACHED */ | |
895 | } | |
896 | a->q_flags &= ~(QPINGONSUCCESS|QPINGONFAILURE|QPINGONDELAY); | |
e1f691b3 | 897 | a->q_flags |= QHASNOTIFY; |
82e3dc75 EA |
898 | if (strcasecmp(vp, "never") == 0) |
899 | return; | |
900 | for (p = vp; p != NULL; vp = p) | |
901 | { | |
902 | p = strchr(p, ','); | |
903 | if (p != NULL) | |
904 | *p++ = '\0'; | |
905 | if (strcasecmp(vp, "success") == 0) | |
906 | a->q_flags |= QPINGONSUCCESS; | |
907 | else if (strcasecmp(vp, "failure") == 0) | |
908 | a->q_flags |= QPINGONFAILURE; | |
909 | else if (strcasecmp(vp, "delay") == 0) | |
910 | a->q_flags |= QPINGONDELAY; | |
911 | else | |
912 | { | |
913 | usrerr("501 Bad argument \"%s\" to NOTIFY", | |
914 | vp); | |
915 | /* NOTREACHED */ | |
916 | } | |
917 | } | |
918 | } | |
82e3dc75 EA |
919 | else if (strcasecmp(kp, "orcpt") == 0) |
920 | { | |
921 | if (vp == NULL) | |
922 | { | |
923 | usrerr("501 ORCPT requires a value"); | |
924 | /* NOTREACHED */ | |
925 | } | |
8b6906e3 EA |
926 | if (!xtextok(vp)) |
927 | { | |
928 | usrerr("501 Syntax error in ORCPT parameter value"); | |
929 | /* NOTREACHED */ | |
930 | } | |
931 | if (a->q_orcpt != NULL) | |
932 | { | |
933 | usrerr("501 Duplicate ORCPT parameter"); | |
934 | /* NOTREACHED */ | |
935 | } | |
82e3dc75 EA |
936 | a->q_orcpt = newstr(vp); |
937 | } | |
938 | else | |
939 | { | |
940 | usrerr("501 %s parameter unrecognized", kp); | |
941 | /* NOTREACHED */ | |
942 | } | |
943 | } | |
944 | \f/* | |
b6edea3d EA |
945 | ** PRINTVRFYADDR -- print an entry in the verify queue |
946 | ** | |
947 | ** Parameters: | |
948 | ** a -- the address to print | |
949 | ** last -- set if this is the last one. | |
950 | ** | |
951 | ** Returns: | |
952 | ** none. | |
953 | ** | |
954 | ** Side Effects: | |
955 | ** Prints the appropriate 250 codes. | |
956 | */ | |
957 | ||
958 | printvrfyaddr(a, last) | |
959 | register ADDRESS *a; | |
960 | bool last; | |
961 | { | |
962 | char fmtbuf[20]; | |
963 | ||
964 | strcpy(fmtbuf, "250"); | |
965 | fmtbuf[3] = last ? ' ' : '-'; | |
966 | ||
ac820be5 EA |
967 | if (a->q_fullname == NULL) |
968 | { | |
969 | if (strchr(a->q_user, '@') == NULL) | |
970 | strcpy(&fmtbuf[4], "<%s@%s>"); | |
971 | else | |
972 | strcpy(&fmtbuf[4], "<%s>"); | |
973 | message(fmtbuf, a->q_user, MyHostName); | |
974 | } | |
b6edea3d EA |
975 | else |
976 | { | |
ac820be5 EA |
977 | if (strchr(a->q_user, '@') == NULL) |
978 | strcpy(&fmtbuf[4], "%s <%s@%s>"); | |
979 | else | |
980 | strcpy(&fmtbuf[4], "%s <%s>"); | |
981 | message(fmtbuf, a->q_fullname, a->q_user, MyHostName); | |
b6edea3d | 982 | } |
b6edea3d EA |
983 | } |
984 | \f/* | |
34d37b7d EA |
985 | ** HELP -- implement the HELP command. |
986 | ** | |
987 | ** Parameters: | |
988 | ** topic -- the topic we want help for. | |
989 | ** | |
990 | ** Returns: | |
991 | ** none. | |
992 | ** | |
993 | ** Side Effects: | |
994 | ** outputs the help file to message output. | |
995 | */ | |
996 | ||
997 | help(topic) | |
998 | char *topic; | |
999 | { | |
1000 | register FILE *hf; | |
1001 | int len; | |
1002 | char buf[MAXLINE]; | |
1003 | bool noinfo; | |
1004 | ||
c1e24818 | 1005 | if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL) |
34d37b7d EA |
1006 | { |
1007 | /* no help */ | |
1b932f66 | 1008 | errno = 0; |
b6edea3d | 1009 | message("502 HELP not implemented"); |
34d37b7d EA |
1010 | return; |
1011 | } | |
1012 | ||
e97afd4a EA |
1013 | if (topic == NULL || *topic == '\0') |
1014 | topic = "smtp"; | |
1015 | else | |
1016 | makelower(topic); | |
1017 | ||
34d37b7d | 1018 | len = strlen(topic); |
34d37b7d EA |
1019 | noinfo = TRUE; |
1020 | ||
1021 | while (fgets(buf, sizeof buf, hf) != NULL) | |
1022 | { | |
1023 | if (strncmp(buf, topic, len) == 0) | |
1024 | { | |
1025 | register char *p; | |
1026 | ||
f3d8f6d6 | 1027 | p = strchr(buf, '\t'); |
34d37b7d EA |
1028 | if (p == NULL) |
1029 | p = buf; | |
1030 | else | |
1031 | p++; | |
1032 | fixcrlf(p, TRUE); | |
b6edea3d | 1033 | message("214-%s", p); |
34d37b7d EA |
1034 | noinfo = FALSE; |
1035 | } | |
1036 | } | |
1037 | ||
1038 | if (noinfo) | |
b6edea3d | 1039 | message("504 HELP topic unknown"); |
34d37b7d | 1040 | else |
b6edea3d | 1041 | message("214 End of HELP info"); |
ed45aae1 | 1042 | (void) fclose(hf); |
34d37b7d | 1043 | } |
abae7b2d | 1044 | \f/* |
e6f08ab1 EA |
1045 | ** RUNINCHILD -- return twice -- once in the child, then in the parent again |
1046 | ** | |
1047 | ** Parameters: | |
1048 | ** label -- a string used in error messages | |
1049 | ** | |
1050 | ** Returns: | |
1051 | ** zero in the child | |
1052 | ** one in the parent | |
1053 | ** | |
1054 | ** Side Effects: | |
1055 | ** none. | |
1056 | */ | |
1057 | ||
a4076aed | 1058 | runinchild(label, e) |
e6f08ab1 | 1059 | char *label; |
a4076aed | 1060 | register ENVELOPE *e; |
e6f08ab1 EA |
1061 | { |
1062 | int childpid; | |
1063 | ||
c1a66acf | 1064 | if (!OneXact) |
e6f08ab1 | 1065 | { |
c1a66acf EA |
1066 | childpid = dofork(); |
1067 | if (childpid < 0) | |
1068 | { | |
1069 | syserr("%s: cannot fork", label); | |
1070 | return (1); | |
1071 | } | |
1072 | if (childpid > 0) | |
1073 | { | |
1074 | auto int st; | |
e6f08ab1 | 1075 | |
c1a66acf | 1076 | /* parent -- wait for child to complete */ |
8e948497 | 1077 | setproctitle("server %s child wait", CurHostName); |
c1a66acf EA |
1078 | st = waitfor(childpid); |
1079 | if (st == -1) | |
1080 | syserr("%s: lost child", label); | |
39824631 EA |
1081 | else if (!WIFEXITED(st)) |
1082 | syserr("%s: died on signal %d", | |
1083 | label, st & 0177); | |
e6f08ab1 | 1084 | |
c1a66acf | 1085 | /* if we exited on a QUIT command, complete the process */ |
33cbaada EA |
1086 | if (WEXITSTATUS(st) == EX_QUIT) |
1087 | { | |
1088 | disconnect(1, e); | |
c1a66acf | 1089 | finis(); |
33cbaada | 1090 | } |
e6f08ab1 | 1091 | |
c1a66acf EA |
1092 | return (1); |
1093 | } | |
1094 | else | |
1095 | { | |
1096 | /* child */ | |
1097 | InChild = TRUE; | |
57c97d4a | 1098 | QuickAbort = FALSE; |
a4076aed | 1099 | clearenvelope(e, FALSE); |
c1a66acf | 1100 | } |
e6f08ab1 | 1101 | } |
55f0da62 | 1102 | |
c1a66acf | 1103 | /* open alias database */ |
36b09297 | 1104 | initmaps(FALSE, e); |
c1a66acf EA |
1105 | |
1106 | return (0); | |
e6f08ab1 EA |
1107 | } |
1108 | \f/* | |
abae7b2d EA |
1109 | ** PADDRTREE -- print address tree |
1110 | ** | |
1111 | ** Used by VRFY and EXPD to dump the tree of addresses produced. | |
1112 | ** | |
1113 | ** Parameters: | |
1114 | ** a -- address of root. | |
1115 | ** | |
1116 | ** Returns: | |
1117 | ** none. | |
1118 | ** | |
1119 | ** Side Effects: | |
1120 | ** prints the tree in a nice order. | |
1121 | */ | |
1122 | ||
1123 | paddrtree(a) | |
1124 | register ADDRESS *a; | |
1125 | { | |
1126 | static ADDRESS *prev; | |
1127 | static int lev; | |
1128 | ||
1129 | if (a == NULL) | |
1130 | return; | |
1131 | lev++; | |
1132 | if (!bitset(QDONTSEND, a->q_flags)) | |
1133 | { | |
1134 | if (prev != NULL) | |
1135 | { | |
1136 | if (prev->q_fullname != NULL) | |
1137 | message("250-", "%s <%s>", prev->q_fullname, prev->q_paddr); | |
1138 | else | |
1139 | message("250-", "<%s>", prev->q_paddr); | |
1140 | } | |
1141 | prev = a; | |
1142 | } | |
1143 | paddrtree(a->q_child); | |
1144 | paddrtree(a->q_sibling); | |
1145 | if (--lev <= 0) | |
1146 | { | |
1147 | if (prev != NULL) | |
1148 | { | |
1149 | /* last one */ | |
1150 | if (prev->q_fullname != NULL) | |
1151 | message("250", "%s <%s>", prev->q_fullname, prev->q_paddr); | |
1152 | else | |
1153 | message("250", "<%s>", prev->q_paddr); | |
1154 | prev = NULL; | |
1155 | } | |
1156 | else | |
1157 | message("550", "User unknown"); | |
1158 | } | |
1159 | } | |
884a20cb | 1160 | |
f3d8f6d6 | 1161 | # endif /* SMTP */ |