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 | |
e1f691b3 | 13 | static char sccsid[] = "@(#)srvrsmtp.c 8.61 (Berkeley) %G% (with SMTP)"; |
bee79b64 | 14 | #else |
e1f691b3 | 15 | static char sccsid[] = "@(#)srvrsmtp.c 8.61 (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"); |
80662ec6 | 586 | e->e_flags |= EF_CLRQUEUE; |
e6f08ab1 EA |
587 | if (InChild) |
588 | finis(); | |
3b87200d EA |
589 | |
590 | /* clean up a bit */ | |
591 | gotmail = FALSE; | |
592 | dropenvelope(e); | |
fda58daa | 593 | CurEnv = e = newenvelope(e, CurEnv); |
e6f08ab1 | 594 | break; |
6b861048 EA |
595 | |
596 | case CMDVRFY: /* vrfy -- verify address */ | |
8f48def8 EA |
597 | case CMDEXPN: /* expn -- expand address */ |
598 | vrfy = c->cmdcode == CMDVRFY; | |
599 | if (bitset(vrfy ? PRIV_NOVRFY : PRIV_NOEXPN, | |
600 | PrivacyFlags)) | |
1c7897ef | 601 | { |
efae59f3 | 602 | if (vrfy) |
cb282b01 | 603 | message("252 Cannot VRFY user; try RCPT to attempt delivery (or try finger)"); |
efae59f3 | 604 | else |
c5b74eae | 605 | message("502 Sorry, we do not allow this operation"); |
c9af7ef4 EA |
606 | #ifdef LOG |
607 | if (LogLevel > 5) | |
608 | syslog(LOG_INFO, "%s: %s [rejected]", | |
609 | CurSmtpClient, inp); | |
610 | #endif | |
1c7897ef EA |
611 | break; |
612 | } | |
613 | else if (!gothello && | |
8f48def8 EA |
614 | bitset(vrfy ? PRIV_NEEDVRFYHELO : PRIV_NEEDEXPNHELO, |
615 | PrivacyFlags)) | |
1c7897ef | 616 | { |
b6edea3d | 617 | message("503 I demand that you introduce yourself first"); |
1c7897ef EA |
618 | break; |
619 | } | |
8f48def8 | 620 | if (runinchild(vrfy ? "SMTP-VRFY" : "SMTP-EXPN", e) > 0) |
e6f08ab1 | 621 | break; |
01e8020e | 622 | #ifdef LOG |
68f7099c | 623 | if (LogLevel > 5) |
c9af7ef4 | 624 | syslog(LOG_INFO, "%s: %s", CurSmtpClient, inp); |
01e8020e | 625 | #endif |
abae7b2d | 626 | paddrtree(a); |
6b861048 EA |
627 | break; |
628 | ||
629 | case CMDHELP: /* help -- give user info */ | |
34d37b7d | 630 | help(p); |
6b861048 EA |
631 | break; |
632 | ||
633 | case CMDNOOP: /* noop -- do nothing */ | |
422d9f83 | 634 | message("250 OK"); |
6b861048 EA |
635 | break; |
636 | ||
637 | case CMDQUIT: /* quit -- leave mail */ | |
b6edea3d | 638 | message("221 %s closing connection", MyHostName); |
251126e0 | 639 | |
f6603f3b | 640 | doquit: |
251126e0 | 641 | /* avoid future 050 messages */ |
33cbaada | 642 | disconnect(1, e); |
251126e0 | 643 | |
e6f08ab1 EA |
644 | if (InChild) |
645 | ExitStat = EX_QUIT; | |
6b861048 EA |
646 | finis(); |
647 | ||
e8ad767d | 648 | case CMDVERB: /* set verbose mode */ |
de975e1b EA |
649 | if (bitset(PRIV_NOEXPN, PrivacyFlags)) |
650 | { | |
651 | /* this would give out the same info */ | |
652 | message("502 Verbose unavailable"); | |
653 | break; | |
654 | } | |
e8ad767d | 655 | Verbose = TRUE; |
8c8e8e94 | 656 | e->e_sendmode = SM_DELIVER; |
de975e1b | 657 | message("250 Verbose mode"); |
e8ad767d EA |
658 | break; |
659 | ||
8fe4fb9b | 660 | case CMDONEX: /* doing one transaction only */ |
7338e3d4 | 661 | OneXact = TRUE; |
de975e1b | 662 | message("250 Only one transaction"); |
8fe4fb9b EA |
663 | break; |
664 | ||
ab4889ea | 665 | # ifdef SMTPDEBUG |
e6f08ab1 | 666 | case CMDDBGQSHOW: /* show queues */ |
2654b031 | 667 | printf("Send Queue="); |
a4076aed | 668 | printaddr(e->e_sendqueue, TRUE); |
d4f42161 | 669 | break; |
09eb49d8 EA |
670 | |
671 | case CMDDBGDEBUG: /* set debug mode */ | |
9678c96d EA |
672 | tTsetup(tTdvect, sizeof tTdvect, "0-99.1"); |
673 | tTflag(p); | |
b6edea3d | 674 | message("200 Debug set"); |
09eb49d8 EA |
675 | break; |
676 | ||
ab4889ea | 677 | # else /* not SMTPDEBUG */ |
ab4889ea MK |
678 | case CMDDBGQSHOW: /* show queues */ |
679 | case CMDDBGDEBUG: /* set debug mode */ | |
3e8f46ad EA |
680 | # endif /* SMTPDEBUG */ |
681 | case CMDLOGBOGUS: /* bogus command */ | |
2e15a2d8 | 682 | # ifdef LOG |
5973222c | 683 | if (LogLevel > 0) |
3e8f46ad | 684 | syslog(LOG_CRIT, |
68f7099c | 685 | "\"%s\" command from %s (%s)", |
7c8c5b90 | 686 | c->cmdname, peerhostname, |
3341995c | 687 | anynet_ntoa(&RealHostAddr)); |
2e15a2d8 | 688 | # endif |
ab4889ea | 689 | /* FALL THROUGH */ |
d4f42161 | 690 | |
6b861048 | 691 | case CMDERROR: /* unknown command */ |
f6603f3b EA |
692 | if (++badcommands > MAXBADCOMMANDS) |
693 | { | |
694 | message("421 %s Too many bad commands; closing connection", | |
695 | MyHostName); | |
696 | goto doquit; | |
697 | } | |
698 | ||
b6edea3d | 699 | message("500 Command unrecognized"); |
6b861048 EA |
700 | break; |
701 | ||
702 | default: | |
ab4889ea | 703 | errno = 0; |
b6edea3d | 704 | syserr("500 smtp: unknown code %d", c->cmdcode); |
6b861048 EA |
705 | break; |
706 | } | |
707 | } | |
708 | } | |
709 | \f/* | |
710 | ** SKIPWORD -- skip a fixed word. | |
711 | ** | |
712 | ** Parameters: | |
713 | ** p -- place to start looking. | |
714 | ** w -- word to skip. | |
715 | ** | |
716 | ** Returns: | |
717 | ** p following w. | |
718 | ** NULL on error. | |
719 | ** | |
720 | ** Side Effects: | |
721 | ** clobbers the p data area. | |
722 | */ | |
723 | ||
724 | static char * | |
725 | skipword(p, w) | |
726 | register char *p; | |
727 | char *w; | |
728 | { | |
729 | register char *q; | |
7c8c5b90 | 730 | char *firstp = p; |
6b861048 EA |
731 | |
732 | /* find beginning of word */ | |
2bee003d | 733 | while (isascii(*p) && isspace(*p)) |
6b861048 EA |
734 | p++; |
735 | q = p; | |
736 | ||
737 | /* find end of word */ | |
2bee003d | 738 | while (*p != '\0' && *p != ':' && !(isascii(*p) && isspace(*p))) |
6b861048 | 739 | p++; |
2bee003d | 740 | while (isascii(*p) && isspace(*p)) |
6b861048 EA |
741 | *p++ = '\0'; |
742 | if (*p != ':') | |
743 | { | |
744 | syntax: | |
7c8c5b90 EA |
745 | message("501 Syntax error in parameters scanning \"%s\"", |
746 | firstp); | |
6b861048 EA |
747 | Errors++; |
748 | return (NULL); | |
749 | } | |
750 | *p++ = '\0'; | |
2bee003d | 751 | while (isascii(*p) && isspace(*p)) |
6b861048 EA |
752 | p++; |
753 | ||
20f20f1e EA |
754 | if (*p == '\0') |
755 | goto syntax; | |
756 | ||
6b861048 | 757 | /* see if the input word matches desired word */ |
ed73ef1d | 758 | if (strcasecmp(q, w)) |
6b861048 EA |
759 | goto syntax; |
760 | ||
761 | return (p); | |
762 | } | |
34d37b7d | 763 | \f/* |
c7a0eaaf EA |
764 | ** MAIL_ESMTP_ARGS -- process ESMTP arguments from MAIL line |
765 | ** | |
766 | ** Parameters: | |
767 | ** kp -- the parameter key. | |
768 | ** vp -- the value of that parameter. | |
769 | ** e -- the envelope. | |
770 | ** | |
771 | ** Returns: | |
772 | ** none. | |
773 | */ | |
774 | ||
775 | mail_esmtp_args(kp, vp, e) | |
776 | char *kp; | |
777 | char *vp; | |
778 | ENVELOPE *e; | |
779 | { | |
780 | if (strcasecmp(kp, "size") == 0) | |
781 | { | |
782 | if (vp == NULL) | |
783 | { | |
784 | usrerr("501 SIZE requires a value"); | |
785 | /* NOTREACHED */ | |
786 | } | |
787 | # ifdef __STDC__ | |
81e7e79e | 788 | e->e_msgsize = strtoul(vp, (char **) NULL, 10); |
c7a0eaaf | 789 | # else |
81e7e79e | 790 | e->e_msgsize = strtol(vp, (char **) NULL, 10); |
c7a0eaaf EA |
791 | # endif |
792 | } | |
793 | else if (strcasecmp(kp, "body") == 0) | |
794 | { | |
795 | if (vp == NULL) | |
796 | { | |
797 | usrerr("501 BODY requires a value"); | |
798 | /* NOTREACHED */ | |
799 | } | |
800 | if (strcasecmp(vp, "8bitmime") == 0) | |
801 | { | |
802 | SevenBitInput = FALSE; | |
803 | } | |
804 | else if (strcasecmp(vp, "7bit") == 0) | |
805 | { | |
806 | SevenBitInput = TRUE; | |
807 | } | |
808 | else | |
809 | { | |
810 | usrerr("501 Unknown BODY type %s", | |
811 | vp); | |
812 | /* NOTREACHED */ | |
813 | } | |
814 | e->e_bodytype = newstr(vp); | |
815 | } | |
816 | else if (strcasecmp(kp, "envid") == 0) | |
817 | { | |
818 | if (vp == NULL) | |
819 | { | |
820 | usrerr("501 ENVID requires a value"); | |
821 | /* NOTREACHED */ | |
822 | } | |
8b6906e3 EA |
823 | if (!xtextok(vp)) |
824 | { | |
825 | usrerr("501 Syntax error in ENVID parameter value"); | |
826 | /* NOTREACHED */ | |
827 | } | |
828 | if (e->e_envid != NULL) | |
829 | { | |
830 | usrerr("501 Duplicate ENVID parameter"); | |
831 | /* NOTREACHED */ | |
832 | } | |
c7a0eaaf EA |
833 | e->e_envid = newstr(vp); |
834 | } | |
835 | else if (strcasecmp(kp, "ret") == 0) | |
836 | { | |
837 | if (vp == NULL) | |
838 | { | |
839 | usrerr("501 RET requires a value"); | |
840 | /* NOTREACHED */ | |
841 | } | |
8b6906e3 EA |
842 | if (bitset(EF_RET_PARAM, e->e_flags)) |
843 | { | |
844 | usrerr("501 Duplicate RET parameter"); | |
845 | /* NOTREACHED */ | |
846 | } | |
c7a0eaaf EA |
847 | e->e_flags |= EF_RET_PARAM; |
848 | if (strcasecmp(vp, "hdrs") == 0) | |
849 | e->e_flags |= EF_NO_BODY_RETN; | |
850 | else if (strcasecmp(vp, "full") != 0) | |
851 | { | |
852 | usrerr("501 Bad argument \"%s\" to RET", vp); | |
853 | /* NOTREACHED */ | |
854 | } | |
855 | } | |
856 | else | |
857 | { | |
858 | usrerr("501 %s parameter unrecognized", kp); | |
859 | /* NOTREACHED */ | |
860 | } | |
861 | } | |
862 | \f/* | |
82e3dc75 EA |
863 | ** RCPT_ESMTP_ARGS -- process ESMTP arguments from RCPT line |
864 | ** | |
865 | ** Parameters: | |
866 | ** a -- the address corresponding to the To: parameter. | |
867 | ** kp -- the parameter key. | |
868 | ** vp -- the value of that parameter. | |
869 | ** e -- the envelope. | |
870 | ** | |
871 | ** Returns: | |
872 | ** none. | |
873 | */ | |
874 | ||
875 | rcpt_esmtp_args(a, kp, vp, e) | |
876 | ADDRESS *a; | |
877 | char *kp; | |
878 | char *vp; | |
879 | ENVELOPE *e; | |
880 | { | |
881 | if (strcasecmp(kp, "notify") == 0) | |
882 | { | |
883 | char *p; | |
884 | ||
885 | if (vp == NULL) | |
886 | { | |
887 | usrerr("501 NOTIFY requires a value"); | |
888 | /* NOTREACHED */ | |
889 | } | |
890 | a->q_flags &= ~(QPINGONSUCCESS|QPINGONFAILURE|QPINGONDELAY); | |
e1f691b3 | 891 | a->q_flags |= QHASNOTIFY; |
82e3dc75 EA |
892 | if (strcasecmp(vp, "never") == 0) |
893 | return; | |
894 | for (p = vp; p != NULL; vp = p) | |
895 | { | |
896 | p = strchr(p, ','); | |
897 | if (p != NULL) | |
898 | *p++ = '\0'; | |
899 | if (strcasecmp(vp, "success") == 0) | |
900 | a->q_flags |= QPINGONSUCCESS; | |
901 | else if (strcasecmp(vp, "failure") == 0) | |
902 | a->q_flags |= QPINGONFAILURE; | |
903 | else if (strcasecmp(vp, "delay") == 0) | |
904 | a->q_flags |= QPINGONDELAY; | |
905 | else | |
906 | { | |
907 | usrerr("501 Bad argument \"%s\" to NOTIFY", | |
908 | vp); | |
909 | /* NOTREACHED */ | |
910 | } | |
911 | } | |
912 | } | |
82e3dc75 EA |
913 | else if (strcasecmp(kp, "orcpt") == 0) |
914 | { | |
915 | if (vp == NULL) | |
916 | { | |
917 | usrerr("501 ORCPT requires a value"); | |
918 | /* NOTREACHED */ | |
919 | } | |
8b6906e3 EA |
920 | if (!xtextok(vp)) |
921 | { | |
922 | usrerr("501 Syntax error in ORCPT parameter value"); | |
923 | /* NOTREACHED */ | |
924 | } | |
925 | if (a->q_orcpt != NULL) | |
926 | { | |
927 | usrerr("501 Duplicate ORCPT parameter"); | |
928 | /* NOTREACHED */ | |
929 | } | |
82e3dc75 EA |
930 | a->q_orcpt = newstr(vp); |
931 | } | |
932 | else | |
933 | { | |
934 | usrerr("501 %s parameter unrecognized", kp); | |
935 | /* NOTREACHED */ | |
936 | } | |
937 | } | |
938 | \f/* | |
b6edea3d EA |
939 | ** PRINTVRFYADDR -- print an entry in the verify queue |
940 | ** | |
941 | ** Parameters: | |
942 | ** a -- the address to print | |
943 | ** last -- set if this is the last one. | |
944 | ** | |
945 | ** Returns: | |
946 | ** none. | |
947 | ** | |
948 | ** Side Effects: | |
949 | ** Prints the appropriate 250 codes. | |
950 | */ | |
951 | ||
952 | printvrfyaddr(a, last) | |
953 | register ADDRESS *a; | |
954 | bool last; | |
955 | { | |
956 | char fmtbuf[20]; | |
957 | ||
958 | strcpy(fmtbuf, "250"); | |
959 | fmtbuf[3] = last ? ' ' : '-'; | |
960 | ||
ac820be5 EA |
961 | if (a->q_fullname == NULL) |
962 | { | |
963 | if (strchr(a->q_user, '@') == NULL) | |
964 | strcpy(&fmtbuf[4], "<%s@%s>"); | |
965 | else | |
966 | strcpy(&fmtbuf[4], "<%s>"); | |
967 | message(fmtbuf, a->q_user, MyHostName); | |
968 | } | |
b6edea3d EA |
969 | else |
970 | { | |
ac820be5 EA |
971 | if (strchr(a->q_user, '@') == NULL) |
972 | strcpy(&fmtbuf[4], "%s <%s@%s>"); | |
973 | else | |
974 | strcpy(&fmtbuf[4], "%s <%s>"); | |
975 | message(fmtbuf, a->q_fullname, a->q_user, MyHostName); | |
b6edea3d | 976 | } |
b6edea3d EA |
977 | } |
978 | \f/* | |
34d37b7d EA |
979 | ** HELP -- implement the HELP command. |
980 | ** | |
981 | ** Parameters: | |
982 | ** topic -- the topic we want help for. | |
983 | ** | |
984 | ** Returns: | |
985 | ** none. | |
986 | ** | |
987 | ** Side Effects: | |
988 | ** outputs the help file to message output. | |
989 | */ | |
990 | ||
991 | help(topic) | |
992 | char *topic; | |
993 | { | |
994 | register FILE *hf; | |
995 | int len; | |
996 | char buf[MAXLINE]; | |
997 | bool noinfo; | |
998 | ||
c1e24818 | 999 | if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL) |
34d37b7d EA |
1000 | { |
1001 | /* no help */ | |
1b932f66 | 1002 | errno = 0; |
b6edea3d | 1003 | message("502 HELP not implemented"); |
34d37b7d EA |
1004 | return; |
1005 | } | |
1006 | ||
e97afd4a EA |
1007 | if (topic == NULL || *topic == '\0') |
1008 | topic = "smtp"; | |
1009 | else | |
1010 | makelower(topic); | |
1011 | ||
34d37b7d | 1012 | len = strlen(topic); |
34d37b7d EA |
1013 | noinfo = TRUE; |
1014 | ||
1015 | while (fgets(buf, sizeof buf, hf) != NULL) | |
1016 | { | |
1017 | if (strncmp(buf, topic, len) == 0) | |
1018 | { | |
1019 | register char *p; | |
1020 | ||
f3d8f6d6 | 1021 | p = strchr(buf, '\t'); |
34d37b7d EA |
1022 | if (p == NULL) |
1023 | p = buf; | |
1024 | else | |
1025 | p++; | |
1026 | fixcrlf(p, TRUE); | |
b6edea3d | 1027 | message("214-%s", p); |
34d37b7d EA |
1028 | noinfo = FALSE; |
1029 | } | |
1030 | } | |
1031 | ||
1032 | if (noinfo) | |
b6edea3d | 1033 | message("504 HELP topic unknown"); |
34d37b7d | 1034 | else |
b6edea3d | 1035 | message("214 End of HELP info"); |
ed45aae1 | 1036 | (void) fclose(hf); |
34d37b7d | 1037 | } |
abae7b2d | 1038 | \f/* |
e6f08ab1 EA |
1039 | ** RUNINCHILD -- return twice -- once in the child, then in the parent again |
1040 | ** | |
1041 | ** Parameters: | |
1042 | ** label -- a string used in error messages | |
1043 | ** | |
1044 | ** Returns: | |
1045 | ** zero in the child | |
1046 | ** one in the parent | |
1047 | ** | |
1048 | ** Side Effects: | |
1049 | ** none. | |
1050 | */ | |
1051 | ||
a4076aed | 1052 | runinchild(label, e) |
e6f08ab1 | 1053 | char *label; |
a4076aed | 1054 | register ENVELOPE *e; |
e6f08ab1 EA |
1055 | { |
1056 | int childpid; | |
1057 | ||
c1a66acf | 1058 | if (!OneXact) |
e6f08ab1 | 1059 | { |
c1a66acf EA |
1060 | childpid = dofork(); |
1061 | if (childpid < 0) | |
1062 | { | |
1063 | syserr("%s: cannot fork", label); | |
1064 | return (1); | |
1065 | } | |
1066 | if (childpid > 0) | |
1067 | { | |
1068 | auto int st; | |
e6f08ab1 | 1069 | |
c1a66acf | 1070 | /* parent -- wait for child to complete */ |
8e948497 | 1071 | setproctitle("server %s child wait", CurHostName); |
c1a66acf EA |
1072 | st = waitfor(childpid); |
1073 | if (st == -1) | |
1074 | syserr("%s: lost child", label); | |
39824631 EA |
1075 | else if (!WIFEXITED(st)) |
1076 | syserr("%s: died on signal %d", | |
1077 | label, st & 0177); | |
e6f08ab1 | 1078 | |
c1a66acf | 1079 | /* if we exited on a QUIT command, complete the process */ |
33cbaada EA |
1080 | if (WEXITSTATUS(st) == EX_QUIT) |
1081 | { | |
1082 | disconnect(1, e); | |
c1a66acf | 1083 | finis(); |
33cbaada | 1084 | } |
e6f08ab1 | 1085 | |
c1a66acf EA |
1086 | return (1); |
1087 | } | |
1088 | else | |
1089 | { | |
1090 | /* child */ | |
1091 | InChild = TRUE; | |
57c97d4a | 1092 | QuickAbort = FALSE; |
a4076aed | 1093 | clearenvelope(e, FALSE); |
c1a66acf | 1094 | } |
e6f08ab1 | 1095 | } |
55f0da62 | 1096 | |
c1a66acf | 1097 | /* open alias database */ |
36b09297 | 1098 | initmaps(FALSE, e); |
c1a66acf EA |
1099 | |
1100 | return (0); | |
e6f08ab1 EA |
1101 | } |
1102 | \f/* | |
abae7b2d EA |
1103 | ** PADDRTREE -- print address tree |
1104 | ** | |
1105 | ** Used by VRFY and EXPD to dump the tree of addresses produced. | |
1106 | ** | |
1107 | ** Parameters: | |
1108 | ** a -- address of root. | |
1109 | ** | |
1110 | ** Returns: | |
1111 | ** none. | |
1112 | ** | |
1113 | ** Side Effects: | |
1114 | ** prints the tree in a nice order. | |
1115 | */ | |
1116 | ||
1117 | paddrtree(a) | |
1118 | register ADDRESS *a; | |
1119 | { | |
1120 | static ADDRESS *prev; | |
1121 | static int lev; | |
1122 | ||
1123 | if (a == NULL) | |
1124 | return; | |
1125 | lev++; | |
1126 | if (!bitset(QDONTSEND, a->q_flags)) | |
1127 | { | |
1128 | if (prev != NULL) | |
1129 | { | |
1130 | if (prev->q_fullname != NULL) | |
1131 | message("250-", "%s <%s>", prev->q_fullname, prev->q_paddr); | |
1132 | else | |
1133 | message("250-", "<%s>", prev->q_paddr); | |
1134 | } | |
1135 | prev = a; | |
1136 | } | |
1137 | paddrtree(a->q_child); | |
1138 | paddrtree(a->q_sibling); | |
1139 | if (--lev <= 0) | |
1140 | { | |
1141 | if (prev != NULL) | |
1142 | { | |
1143 | /* last one */ | |
1144 | if (prev->q_fullname != NULL) | |
1145 | message("250", "%s <%s>", prev->q_fullname, prev->q_paddr); | |
1146 | else | |
1147 | message("250", "<%s>", prev->q_paddr); | |
1148 | prev = NULL; | |
1149 | } | |
1150 | else | |
1151 | message("550", "User unknown"); | |
1152 | } | |
1153 | } | |
884a20cb | 1154 | |
f3d8f6d6 | 1155 | # endif /* SMTP */ |