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