Commit | Line | Data |
---|---|---|
b2a81223 | 1 | /* |
dc45ba8c | 2 | * Copyright (c) 1983 Eric P. Allman |
bee79b64 KB |
3 | * Copyright (c) 1988 Regents of the University of California. |
4 | * All rights reserved. | |
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 | |
b5958391 | 13 | static char sccsid[] = "@(#)srvrsmtp.c 5.34 (Berkeley) %G% (with SMTP)"; |
bee79b64 | 14 | #else |
b5958391 | 15 | static char sccsid[] = "@(#)srvrsmtp.c 5.34 (Berkeley) %G% (without SMTP)"; |
bee79b64 KB |
16 | #endif |
17 | #endif /* not lint */ | |
b2a81223 | 18 | |
e6f08ab1 | 19 | # include <errno.h> |
671d4b5c | 20 | # include <signal.h> |
6b861048 | 21 | |
bee79b64 | 22 | # ifdef SMTP |
d727056e | 23 | |
6b861048 EA |
24 | /* |
25 | ** SMTP -- run the SMTP protocol. | |
26 | ** | |
27 | ** Parameters: | |
28 | ** none. | |
29 | ** | |
30 | ** Returns: | |
31 | ** never. | |
32 | ** | |
33 | ** Side Effects: | |
34 | ** Reads commands from the input channel and processes | |
35 | ** them. | |
36 | */ | |
37 | ||
38 | struct cmd | |
39 | { | |
40 | char *cmdname; /* command name */ | |
41 | int cmdcode; /* internal code, see below */ | |
42 | }; | |
43 | ||
44 | /* values for cmdcode */ | |
45 | # define CMDERROR 0 /* bad command */ | |
46 | # define CMDMAIL 1 /* mail -- designate sender */ | |
4a4ebe09 | 47 | # define CMDRCPT 2 /* rcpt -- designate recipient */ |
6b861048 | 48 | # define CMDDATA 3 /* data -- send message text */ |
7d7fdf93 | 49 | # define CMDHOPS 4 /* hops -- specify hop count */ |
e6f08ab1 EA |
50 | # define CMDRSET 4 /* rset -- reset state */ |
51 | # define CMDVRFY 5 /* vrfy -- verify address */ | |
52 | # define CMDHELP 6 /* help -- give usage info */ | |
53 | # define CMDNOOP 7 /* noop -- do nothing */ | |
54 | # define CMDQUIT 8 /* quit -- close connection and die */ | |
55 | # define CMDHELO 9 /* helo -- be polite */ | |
ab4889ea MK |
56 | # define CMDONEX 10 /* onex -- sending one transaction only */ |
57 | # define CMDVERB 11 /* verb -- go into verbose mode */ | |
58 | /* debugging-only commands, only enabled if SMTPDEBUG is defined */ | |
59 | # define CMDDBGQSHOW 12 /* showq -- show send queue */ | |
60 | # define CMDDBGDEBUG 13 /* debug -- set debug mode */ | |
6b861048 EA |
61 | |
62 | static struct cmd CmdTab[] = | |
63 | { | |
64 | "mail", CMDMAIL, | |
4a4ebe09 | 65 | "rcpt", CMDRCPT, |
6b861048 | 66 | "data", CMDDATA, |
6b861048 EA |
67 | "rset", CMDRSET, |
68 | "vrfy", CMDVRFY, | |
abae7b2d | 69 | "expn", CMDVRFY, |
633a2e02 | 70 | "expn", CMDVRFY, |
6b861048 EA |
71 | "help", CMDHELP, |
72 | "noop", CMDNOOP, | |
73 | "quit", CMDQUIT, | |
4a4ebe09 | 74 | "helo", CMDHELO, |
e8ad767d | 75 | "verb", CMDVERB, |
8fe4fb9b | 76 | "onex", CMDONEX, |
7d7fdf93 | 77 | "hops", CMDHOPS, |
ab4889ea MK |
78 | /* |
79 | * remaining commands are here only | |
80 | * to trap and log attempts to use them | |
81 | */ | |
e6f08ab1 | 82 | "showq", CMDDBGQSHOW, |
ad20d67b | 83 | "debug", CMDDBGDEBUG, |
6b861048 EA |
84 | NULL, CMDERROR, |
85 | }; | |
86 | ||
e6f08ab1 | 87 | bool InChild = FALSE; /* true if running in a subprocess */ |
7338e3d4 | 88 | bool OneXact = FALSE; /* one xaction only this run */ |
1972fb40 | 89 | |
e6f08ab1 | 90 | #define EX_QUIT 22 /* special code for QUIT command */ |
e8ad767d | 91 | |
6b861048 EA |
92 | smtp() |
93 | { | |
6b861048 | 94 | register char *p; |
e8ad767d | 95 | register struct cmd *c; |
6b861048 | 96 | char *cmd; |
0df908a9 | 97 | static char *skipword(); |
6b861048 | 98 | bool hasmail; /* mail command received */ |
abae7b2d EA |
99 | extern ADDRESS *sendto(); |
100 | ADDRESS *a; | |
6b861048 | 101 | |
abae7b2d | 102 | hasmail = FALSE; |
1f1cc003 EA |
103 | if (OutChannel != stdout) |
104 | { | |
105 | /* arrange for debugging output to go to remote host */ | |
106 | (void) close(1); | |
107 | (void) dup(fileno(OutChannel)); | |
108 | } | |
1b932f66 | 109 | settime(); |
356262e6 | 110 | if (RealHostName != NULL) |
57c97d4a EA |
111 | { |
112 | CurHostName = RealHostName; | |
113 | setproctitle("srvrsmtp %s", CurHostName); | |
114 | } | |
115 | else | |
116 | { | |
117 | /* this must be us!! */ | |
118 | CurHostName = MyHostName; | |
119 | } | |
a73ae8ac | 120 | expand("\001e", inp, &inp[sizeof inp], CurEnv); |
378e8da7 | 121 | message("220", inp); |
2e3062fe | 122 | SmtpPhase = "startup"; |
7564b51f | 123 | sendinghost = NULL; |
6b861048 EA |
124 | for (;;) |
125 | { | |
d344c0b7 EA |
126 | /* arrange for backout */ |
127 | if (setjmp(TopFrame) > 0 && InChild) | |
128 | finis(); | |
129 | QuickAbort = FALSE; | |
130 | HoldErrs = FALSE; | |
f61c3c40 | 131 | LogUsrErrs = FALSE; |
d344c0b7 | 132 | |
37eaaadb | 133 | /* setup for the read */ |
2654b031 | 134 | CurEnv->e_to = NULL; |
34d37b7d | 135 | Errors = 0; |
09eb49d8 | 136 | (void) fflush(stdout); |
37eaaadb | 137 | |
37eaaadb | 138 | /* read the input line */ |
2439b900 | 139 | p = sfgets(inp, sizeof inp, InChannel); |
37eaaadb | 140 | |
2439b900 | 141 | /* handle errors */ |
37eaaadb | 142 | if (p == NULL) |
6b861048 EA |
143 | { |
144 | /* end of file, just die */ | |
ab4889ea | 145 | message("421", "%s Lost input channel from %s", |
57c97d4a | 146 | MyHostName, CurHostName); |
6b861048 EA |
147 | finis(); |
148 | } | |
149 | ||
150 | /* clean up end of line */ | |
2768afe3 | 151 | fixcrlf(inp, TRUE); |
6b861048 | 152 | |
49086753 | 153 | /* echo command to transcript */ |
912acb74 EA |
154 | if (CurEnv->e_xfp != NULL) |
155 | fprintf(CurEnv->e_xfp, "<<< %s\n", inp); | |
49086753 | 156 | |
6b861048 EA |
157 | /* break off command */ |
158 | for (p = inp; isspace(*p); p++) | |
159 | continue; | |
160 | cmd = p; | |
a0225d08 EA |
161 | for (cmd = cmdbuf; *p != '\0' && !isspace(*p); ) |
162 | *cmd++ = *p++; | |
163 | *cmd = '\0'; | |
6b861048 | 164 | |
a1a07282 EA |
165 | /* throw away leading whitespace */ |
166 | while (isspace(*p)) | |
167 | p++; | |
168 | ||
6b861048 EA |
169 | /* decode command */ |
170 | for (c = CmdTab; c->cmdname != NULL; c++) | |
171 | { | |
ed73ef1d | 172 | if (!strcasecmp(c->cmdname, cmdbuf)) |
6b861048 EA |
173 | break; |
174 | } | |
175 | ||
5ae51cd5 EA |
176 | /* reset errors */ |
177 | errno = 0; | |
178 | ||
6b861048 EA |
179 | /* process command */ |
180 | switch (c->cmdcode) | |
181 | { | |
4a4ebe09 | 182 | case CMDHELO: /* hello -- introduce yourself */ |
2e3062fe | 183 | SmtpPhase = "HELO"; |
57c97d4a | 184 | setproctitle("%s: %s", CurHostName, inp); |
ed73ef1d | 185 | if (!strcasecmp(p, MyHostName)) |
f7e74083 | 186 | { |
ab4889ea MK |
187 | /* |
188 | * didn't know about alias, | |
189 | * or connected to an echo server | |
190 | */ | |
af80352d EA |
191 | message("553", "%s config error: mail loops back to myself", |
192 | MyHostName); | |
f7e74083 EA |
193 | break; |
194 | } | |
ed73ef1d | 195 | if (RealHostName != NULL && strcasecmp(p, RealHostName)) |
1972fb40 | 196 | { |
a0225d08 | 197 | char hostbuf[MAXNAME]; |
1972fb40 | 198 | |
a0225d08 | 199 | (void) sprintf(hostbuf, "%s (%s)", p, RealHostName); |
7564b51f | 200 | sendinghost = newstr(hostbuf); |
1972fb40 EA |
201 | } |
202 | else | |
7564b51f | 203 | sendinghost = newstr(p); |
abae7b2d | 204 | message("250", "%s Hello %s, pleased to meet you", HostName, p); |
4a4ebe09 EA |
205 | break; |
206 | ||
6b861048 | 207 | case CMDMAIL: /* mail -- designate sender */ |
2e3062fe EA |
208 | SmtpPhase = "MAIL"; |
209 | ||
0c6a0070 EA |
210 | /* force a sending host even if no HELO given */ |
211 | if (RealHostName != NULL && macvalue('s', CurEnv) == NULL) | |
7564b51f | 212 | sendinghost = RealHostName; |
0c6a0070 | 213 | |
8fe4fb9b | 214 | /* check for validity of this command */ |
2768afe3 EA |
215 | if (hasmail) |
216 | { | |
217 | message("503", "Sender already specified"); | |
218 | break; | |
219 | } | |
e6f08ab1 EA |
220 | if (InChild) |
221 | { | |
ab4889ea | 222 | errno = 0; |
e6f08ab1 EA |
223 | syserr("Nested MAIL command"); |
224 | exit(0); | |
225 | } | |
226 | ||
227 | /* fork a subprocess to process this command */ | |
228 | if (runinchild("SMTP-MAIL") > 0) | |
229 | break; | |
7564b51f | 230 | define('s', sendinghost, CurEnv); |
dfff22e9 | 231 | define('r', "SMTP", CurEnv); |
e6f08ab1 | 232 | initsys(); |
4d344ce6 | 233 | setproctitle("%s %s: %s", CurEnv->e_id, |
57c97d4a | 234 | CurHostName, inp); |
e6f08ab1 EA |
235 | |
236 | /* child -- go do the processing */ | |
6b861048 EA |
237 | p = skipword(p, "from"); |
238 | if (p == NULL) | |
239 | break; | |
b5958391 | 240 | setsender(p, CurEnv); |
34d37b7d | 241 | if (Errors == 0) |
6b861048 EA |
242 | { |
243 | message("250", "Sender ok"); | |
244 | hasmail = TRUE; | |
245 | } | |
e6f08ab1 EA |
246 | else if (InChild) |
247 | finis(); | |
6b861048 EA |
248 | break; |
249 | ||
4a4ebe09 | 250 | case CMDRCPT: /* rcpt -- designate recipient */ |
2e3062fe | 251 | SmtpPhase = "RCPT"; |
4d344ce6 | 252 | setproctitle("%s %s: %s", CurEnv->e_id, |
57c97d4a | 253 | CurHostName, inp); |
d344c0b7 | 254 | if (setjmp(TopFrame) > 0) |
9bfb75c1 EA |
255 | { |
256 | CurEnv->e_flags &= ~EF_FATALERRS; | |
d344c0b7 | 257 | break; |
9bfb75c1 | 258 | } |
d344c0b7 | 259 | QuickAbort = TRUE; |
f61c3c40 | 260 | LogUsrErrs = TRUE; |
6b861048 EA |
261 | p = skipword(p, "to"); |
262 | if (p == NULL) | |
263 | break; | |
abae7b2d EA |
264 | a = sendto(p, 1, (ADDRESS *) NULL, 0); |
265 | # ifdef DEBUG | |
266 | if (Debug > 1) | |
267 | printaddr(a, TRUE); | |
268 | # endif DEBUG | |
d344c0b7 EA |
269 | if (Errors != 0) |
270 | break; | |
271 | ||
272 | /* no errors during parsing, but might be a duplicate */ | |
273 | CurEnv->e_to = p; | |
274 | if (!bitset(QBADADDR, a->q_flags)) | |
275 | message("250", "Recipient ok"); | |
276 | else | |
6b861048 | 277 | { |
d344c0b7 EA |
278 | /* punt -- should keep message in ADDRESS.... */ |
279 | message("550", "Addressee unknown"); | |
6b861048 | 280 | } |
d344c0b7 | 281 | CurEnv->e_to = NULL; |
6b861048 EA |
282 | break; |
283 | ||
284 | case CMDDATA: /* data -- text of mail */ | |
2e3062fe | 285 | SmtpPhase = "DATA"; |
6b861048 | 286 | if (!hasmail) |
4a4ebe09 | 287 | { |
6b861048 | 288 | message("503", "Need MAIL command"); |
4a4ebe09 EA |
289 | break; |
290 | } | |
2e3062fe | 291 | else if (CurEnv->e_nrcpts <= 0) |
6b861048 | 292 | { |
4a4ebe09 EA |
293 | message("503", "Need RCPT (recipient)"); |
294 | break; | |
6b861048 | 295 | } |
4a4ebe09 EA |
296 | |
297 | /* collect the text of the message */ | |
2e3062fe | 298 | SmtpPhase = "collect"; |
4d344ce6 | 299 | setproctitle("%s %s: %s", CurEnv->e_id, |
57c97d4a | 300 | CurHostName, inp); |
4a4ebe09 EA |
301 | collect(TRUE); |
302 | if (Errors != 0) | |
303 | break; | |
304 | ||
8eedb496 EA |
305 | /* |
306 | ** Arrange to send to everyone. | |
307 | ** If sending to multiple people, mail back | |
308 | ** errors rather than reporting directly. | |
309 | ** In any case, don't mail back errors for | |
310 | ** anything that has happened up to | |
311 | ** now (the other end will do this). | |
bcf74f25 EA |
312 | ** Truncate our transcript -- the mail has gotten |
313 | ** to us successfully, and if we have | |
314 | ** to mail this back, it will be easier | |
315 | ** on the reader. | |
8eedb496 EA |
316 | ** Then send to everyone. |
317 | ** Finally give a reply code. If an error has | |
318 | ** already been given, don't mail a | |
319 | ** message back. | |
e6f08ab1 | 320 | ** We goose error returns by clearing error bit. |
8eedb496 EA |
321 | */ |
322 | ||
2e3062fe EA |
323 | SmtpPhase = "delivery"; |
324 | if (CurEnv->e_nrcpts != 1) | |
7338e3d4 EA |
325 | { |
326 | HoldErrs = TRUE; | |
83f674d8 | 327 | ErrorMode = EM_MAIL; |
7338e3d4 | 328 | } |
e6f08ab1 | 329 | CurEnv->e_flags &= ~EF_FATALERRS; |
bcf74f25 | 330 | CurEnv->e_xfp = freopen(queuename(CurEnv, 'x'), "w", CurEnv->e_xfp); |
4a4ebe09 EA |
331 | |
332 | /* send to all recipients */ | |
f7e74083 | 333 | sendall(CurEnv, SM_DEFAULT); |
2654b031 | 334 | CurEnv->e_to = NULL; |
4a4ebe09 | 335 | |
666b39ad EA |
336 | /* save statistics */ |
337 | markstats(CurEnv, (ADDRESS *) NULL); | |
338 | ||
8eedb496 EA |
339 | /* issue success if appropriate and reset */ |
340 | if (Errors == 0 || HoldErrs) | |
75f95954 | 341 | message("250", "Ok"); |
8eedb496 | 342 | else |
e6f08ab1 EA |
343 | CurEnv->e_flags &= ~EF_FATALERRS; |
344 | ||
345 | /* if in a child, pop back to our parent */ | |
346 | if (InChild) | |
347 | finis(); | |
2e3062fe EA |
348 | |
349 | /* clean up a bit */ | |
350 | hasmail = 0; | |
2e3062fe EA |
351 | dropenvelope(CurEnv); |
352 | CurEnv = newenvelope(CurEnv); | |
353 | CurEnv->e_flags = BlankEnvelope.e_flags; | |
6b861048 EA |
354 | break; |
355 | ||
356 | case CMDRSET: /* rset -- reset state */ | |
357 | message("250", "Reset state"); | |
e6f08ab1 EA |
358 | if (InChild) |
359 | finis(); | |
360 | break; | |
6b861048 EA |
361 | |
362 | case CMDVRFY: /* vrfy -- verify address */ | |
e6f08ab1 EA |
363 | if (runinchild("SMTP-VRFY") > 0) |
364 | break; | |
57c97d4a | 365 | setproctitle("%s: %s", CurHostName, inp); |
abae7b2d | 366 | paddrtree(a); |
6b861048 EA |
367 | break; |
368 | ||
369 | case CMDHELP: /* help -- give user info */ | |
34d37b7d | 370 | help(p); |
6b861048 EA |
371 | break; |
372 | ||
373 | case CMDNOOP: /* noop -- do nothing */ | |
374 | message("200", "OK"); | |
375 | break; | |
376 | ||
377 | case CMDQUIT: /* quit -- leave mail */ | |
57c97d4a | 378 | message("221", "%s closing connection", MyHostName); |
e6f08ab1 EA |
379 | if (InChild) |
380 | ExitStat = EX_QUIT; | |
6b861048 EA |
381 | finis(); |
382 | ||
e8ad767d EA |
383 | case CMDVERB: /* set verbose mode */ |
384 | Verbose = TRUE; | |
28852808 | 385 | SendMode = SM_DELIVER; |
e8ad767d EA |
386 | message("200", "Verbose mode"); |
387 | break; | |
388 | ||
8fe4fb9b | 389 | case CMDONEX: /* doing one transaction only */ |
7338e3d4 | 390 | OneXact = TRUE; |
8fe4fb9b EA |
391 | message("200", "Only one transaction"); |
392 | break; | |
393 | ||
ab4889ea | 394 | # ifdef SMTPDEBUG |
e6f08ab1 | 395 | case CMDDBGQSHOW: /* show queues */ |
2654b031 EA |
396 | printf("Send Queue="); |
397 | printaddr(CurEnv->e_sendqueue, TRUE); | |
d4f42161 | 398 | break; |
09eb49d8 EA |
399 | |
400 | case CMDDBGDEBUG: /* set debug mode */ | |
9678c96d EA |
401 | tTsetup(tTdvect, sizeof tTdvect, "0-99.1"); |
402 | tTflag(p); | |
403 | message("200", "Debug set"); | |
09eb49d8 EA |
404 | break; |
405 | ||
ab4889ea MK |
406 | # else /* not SMTPDEBUG */ |
407 | ||
408 | case CMDDBGQSHOW: /* show queues */ | |
409 | case CMDDBGDEBUG: /* set debug mode */ | |
2e15a2d8 MK |
410 | # ifdef LOG |
411 | if (RealHostName != NULL && LogLevel > 0) | |
ab4889ea MK |
412 | syslog(LOG_NOTICE, |
413 | "\"%s\" command from %s (%s)\n", | |
414 | c->cmdname, RealHostName, | |
415 | inet_ntoa(RealHostAddr.sin_addr)); | |
2e15a2d8 | 416 | # endif |
ab4889ea MK |
417 | /* FALL THROUGH */ |
418 | # endif /* SMTPDEBUG */ | |
d4f42161 | 419 | |
6b861048 EA |
420 | case CMDERROR: /* unknown command */ |
421 | message("500", "Command unrecognized"); | |
422 | break; | |
423 | ||
424 | default: | |
ab4889ea | 425 | errno = 0; |
6b861048 EA |
426 | syserr("smtp: unknown code %d", c->cmdcode); |
427 | break; | |
428 | } | |
429 | } | |
430 | } | |
431 | \f/* | |
432 | ** SKIPWORD -- skip a fixed word. | |
433 | ** | |
434 | ** Parameters: | |
435 | ** p -- place to start looking. | |
436 | ** w -- word to skip. | |
437 | ** | |
438 | ** Returns: | |
439 | ** p following w. | |
440 | ** NULL on error. | |
441 | ** | |
442 | ** Side Effects: | |
443 | ** clobbers the p data area. | |
444 | */ | |
445 | ||
446 | static char * | |
447 | skipword(p, w) | |
448 | register char *p; | |
449 | char *w; | |
450 | { | |
451 | register char *q; | |
6b861048 EA |
452 | |
453 | /* find beginning of word */ | |
454 | while (isspace(*p)) | |
455 | p++; | |
456 | q = p; | |
457 | ||
458 | /* find end of word */ | |
459 | while (*p != '\0' && *p != ':' && !isspace(*p)) | |
460 | p++; | |
461 | while (isspace(*p)) | |
462 | *p++ = '\0'; | |
463 | if (*p != ':') | |
464 | { | |
465 | syntax: | |
466 | message("501", "Syntax error"); | |
467 | Errors++; | |
468 | return (NULL); | |
469 | } | |
470 | *p++ = '\0'; | |
471 | while (isspace(*p)) | |
472 | p++; | |
473 | ||
474 | /* see if the input word matches desired word */ | |
ed73ef1d | 475 | if (strcasecmp(q, w)) |
6b861048 EA |
476 | goto syntax; |
477 | ||
478 | return (p); | |
479 | } | |
34d37b7d EA |
480 | \f/* |
481 | ** HELP -- implement the HELP command. | |
482 | ** | |
483 | ** Parameters: | |
484 | ** topic -- the topic we want help for. | |
485 | ** | |
486 | ** Returns: | |
487 | ** none. | |
488 | ** | |
489 | ** Side Effects: | |
490 | ** outputs the help file to message output. | |
491 | */ | |
492 | ||
493 | help(topic) | |
494 | char *topic; | |
495 | { | |
496 | register FILE *hf; | |
497 | int len; | |
498 | char buf[MAXLINE]; | |
499 | bool noinfo; | |
500 | ||
c1e24818 | 501 | if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL) |
34d37b7d EA |
502 | { |
503 | /* no help */ | |
1b932f66 | 504 | errno = 0; |
34d37b7d EA |
505 | message("502", "HELP not implemented"); |
506 | return; | |
507 | } | |
508 | ||
e97afd4a EA |
509 | if (topic == NULL || *topic == '\0') |
510 | topic = "smtp"; | |
511 | else | |
512 | makelower(topic); | |
513 | ||
34d37b7d | 514 | len = strlen(topic); |
34d37b7d EA |
515 | noinfo = TRUE; |
516 | ||
517 | while (fgets(buf, sizeof buf, hf) != NULL) | |
518 | { | |
519 | if (strncmp(buf, topic, len) == 0) | |
520 | { | |
521 | register char *p; | |
522 | ||
523 | p = index(buf, '\t'); | |
524 | if (p == NULL) | |
525 | p = buf; | |
526 | else | |
527 | p++; | |
528 | fixcrlf(p, TRUE); | |
529 | message("214-", p); | |
530 | noinfo = FALSE; | |
531 | } | |
532 | } | |
533 | ||
534 | if (noinfo) | |
535 | message("504", "HELP topic unknown"); | |
536 | else | |
537 | message("214", "End of HELP info"); | |
ed45aae1 | 538 | (void) fclose(hf); |
34d37b7d | 539 | } |
abae7b2d | 540 | \f/* |
e6f08ab1 EA |
541 | ** RUNINCHILD -- return twice -- once in the child, then in the parent again |
542 | ** | |
543 | ** Parameters: | |
544 | ** label -- a string used in error messages | |
545 | ** | |
546 | ** Returns: | |
547 | ** zero in the child | |
548 | ** one in the parent | |
549 | ** | |
550 | ** Side Effects: | |
551 | ** none. | |
552 | */ | |
553 | ||
554 | runinchild(label) | |
555 | char *label; | |
556 | { | |
557 | int childpid; | |
558 | ||
c1a66acf | 559 | if (!OneXact) |
e6f08ab1 | 560 | { |
c1a66acf EA |
561 | childpid = dofork(); |
562 | if (childpid < 0) | |
563 | { | |
564 | syserr("%s: cannot fork", label); | |
565 | return (1); | |
566 | } | |
567 | if (childpid > 0) | |
568 | { | |
569 | auto int st; | |
e6f08ab1 | 570 | |
c1a66acf EA |
571 | /* parent -- wait for child to complete */ |
572 | st = waitfor(childpid); | |
573 | if (st == -1) | |
574 | syserr("%s: lost child", label); | |
e6f08ab1 | 575 | |
c1a66acf EA |
576 | /* if we exited on a QUIT command, complete the process */ |
577 | if (st == (EX_QUIT << 8)) | |
578 | finis(); | |
e6f08ab1 | 579 | |
c1a66acf EA |
580 | return (1); |
581 | } | |
582 | else | |
583 | { | |
584 | /* child */ | |
585 | InChild = TRUE; | |
57c97d4a | 586 | QuickAbort = FALSE; |
66ba9834 | 587 | clearenvelope(CurEnv, FALSE); |
c1a66acf | 588 | } |
e6f08ab1 | 589 | } |
55f0da62 | 590 | |
c1a66acf EA |
591 | /* open alias database */ |
592 | initaliases(AliasFile, FALSE); | |
593 | ||
594 | return (0); | |
e6f08ab1 EA |
595 | } |
596 | \f/* | |
abae7b2d EA |
597 | ** PADDRTREE -- print address tree |
598 | ** | |
599 | ** Used by VRFY and EXPD to dump the tree of addresses produced. | |
600 | ** | |
601 | ** Parameters: | |
602 | ** a -- address of root. | |
603 | ** | |
604 | ** Returns: | |
605 | ** none. | |
606 | ** | |
607 | ** Side Effects: | |
608 | ** prints the tree in a nice order. | |
609 | */ | |
610 | ||
611 | paddrtree(a) | |
612 | register ADDRESS *a; | |
613 | { | |
614 | static ADDRESS *prev; | |
615 | static int lev; | |
616 | ||
617 | if (a == NULL) | |
618 | return; | |
619 | lev++; | |
620 | if (!bitset(QDONTSEND, a->q_flags)) | |
621 | { | |
622 | if (prev != NULL) | |
623 | { | |
624 | if (prev->q_fullname != NULL) | |
625 | message("250-", "%s <%s>", prev->q_fullname, prev->q_paddr); | |
626 | else | |
627 | message("250-", "<%s>", prev->q_paddr); | |
628 | } | |
629 | prev = a; | |
630 | } | |
631 | paddrtree(a->q_child); | |
632 | paddrtree(a->q_sibling); | |
633 | if (--lev <= 0) | |
634 | { | |
635 | if (prev != NULL) | |
636 | { | |
637 | /* last one */ | |
638 | if (prev->q_fullname != NULL) | |
639 | message("250", "%s <%s>", prev->q_fullname, prev->q_paddr); | |
640 | else | |
641 | message("250", "<%s>", prev->q_paddr); | |
642 | prev = NULL; | |
643 | } | |
644 | else | |
645 | message("550", "User unknown"); | |
646 | } | |
647 | } | |
884a20cb EA |
648 | |
649 | # endif SMTP |