Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / external / ibm-public / postfix / dist / src / milter / test-milter.c
blob534ea3757550350378a8419e7b926d06d7c41cb7
1 /* $NetBSD$ */
3 /*++
4 /* NAME
5 /* test-milter 1
6 /* SUMMARY
7 /* Simple test mail filter program.
8 /* SYNOPSIS
9 /* .fi
10 /* \fBtest-milter\fR [\fIoptions\fR] -p \fBinet:\fIport\fB@\fIhost\fR
12 /* \fBtest-milter\fR [\fIoptions\fR] -p \fBunix:\fIpathname\fR
13 /* DESCRIPTION
14 /* \fBtest-milter\fR is a Milter (mail filter) application that
15 /* exercises selected features.
17 /* Note: this is an unsupported test program. No attempt is made
18 /* to maintain compatibility between successive versions.
20 /* Arguments (multiple alternatives are separated by "\fB|\fR"):
21 /* .IP "\fB-a accept|tempfail|reject|discard|skip|\fIddd x.y.z text\fR"
22 /* Specifies a non-default reply for the MTA command specified
23 /* with \fB-c\fR. The default is \fBtempfail\fR.
24 /* .IP "\fB-A address\fR"
25 /* Add the specified recipient address. Multiple -A options
26 /* are supported.
27 /* .IP "\fB-b pathname
28 /* Replace the message body by the content of the specified file.
29 /* .IP "\fB-c connect|helo|mail|rcpt|data|header|eoh|body|eom|unknown|close|abort\fR"
30 /* When to send the non-default reply specified with \fB-a\fR.
31 /* The default protocol stage is \fBconnect\fR.
32 /* .IP "\fB-C\fI count\fR"
33 /* Terminate after \fIcount\fR connections.
34 /* .IP "\fB-d\fI level\fR"
35 /* Enable libmilter debugging at the specified level.
36 /* .IP "\fB-f \fIsender\fR
37 /* Replace the sender by the specified address.
38 /* .IP "\fB-h \fI'index header-label header-value'\fR"
39 /* Replace the message header at the specified position.
40 /* .IP "\fB-i \fI'index header-label header-value'\fR"
41 /* Insert header at specified position.
42 /* .IP "\fB-l\fR"
43 /* Header values include leading space. Specify this option
44 /* before \fB-i\fR or \fB-r\fR.
45 /* .IP "\fB-m connect|helo|mail|rcpt|data|eoh|eom\fR"
46 /* The protocol stage that receives the list of macros specified
47 /* with \fB-M\fR. The default protocol stage is \fBconnect\fR.
48 /* .IP "\fB-M \fIset_macro_list\fR"
49 /* A non-default list of macros that the MTA should send at
50 /* the protocol stage specified with \fB-m\fR.
51 /* .IP "\fB-n connect|helo|mail|rcpt|data|header|eoh|body|eom|unknown\fR"
52 /* The event that the MTA should not send.
53 /* .IP "\fB-N connect|helo|mail|rcpt|data|header|eoh|body|eom|unknown\fR"
54 /* The event for which the filter will not reply.
55 /* .IP "\fB-p inet:\fIport\fB@\fIhost\fB|unix:\fIpathname\fR"
56 /* The mail filter listen endpoint.
57 /* .IP "\fB-r\fR"
58 /* Request rejected recipients from the MTA.
59 /* .IP "\fB-v\fR"
60 /* Make the program more verbose.
61 /* LICENSE
62 /* .ad
63 /* .fi
64 /* The Secure Mailer license must be distributed with this software.
65 /* AUTHOR(S)
66 /* Wietse Venema
67 /* IBM T.J. Watson Research
68 /* P.O. Box 704
69 /* Yorktown Heights, NY 10598, USA
70 /*--*/
72 #include <sys/types.h>
73 #include <sys/socket.h>
74 #include <netinet/in.h>
75 #include <sys/un.h>
76 #include <arpa/inet.h>
77 #include <errno.h>
78 #include <stdio.h>
79 #include <stdlib.h>
80 #include <unistd.h>
81 #include <string.h>
83 #include "libmilter/mfapi.h"
84 #include "libmilter/mfdef.h"
86 static int conn_count;
87 static int verbose;
89 static int test_connect_reply = SMFIS_CONTINUE;
90 static int test_helo_reply = SMFIS_CONTINUE;
91 static int test_mail_reply = SMFIS_CONTINUE;
92 static int test_rcpt_reply = SMFIS_CONTINUE;
94 #if SMFI_VERSION > 3
95 static int test_data_reply = SMFIS_CONTINUE;
97 #endif
98 static int test_header_reply = SMFIS_CONTINUE;
99 static int test_eoh_reply = SMFIS_CONTINUE;
100 static int test_body_reply = SMFIS_CONTINUE;
101 static int test_eom_reply = SMFIS_CONTINUE;
103 #if SMFI_VERSION > 2
104 static int test_unknown_reply = SMFIS_CONTINUE;
106 #endif
107 static int test_close_reply = SMFIS_CONTINUE;
108 static int test_abort_reply = SMFIS_CONTINUE;
110 struct command_map {
111 const char *name;
112 int *reply;
115 static const struct command_map command_map[] = {
116 "connect", &test_connect_reply,
117 "helo", &test_helo_reply,
118 "mail", &test_mail_reply,
119 "rcpt", &test_rcpt_reply,
120 "header", &test_header_reply,
121 "eoh", &test_eoh_reply,
122 "body", &test_body_reply,
123 "eom", &test_eom_reply,
124 "abort", &test_abort_reply,
125 "close", &test_close_reply,
126 #if SMFI_VERSION > 2
127 "unknown", &test_unknown_reply,
128 #endif
129 #if SMFI_VERSION > 3
130 "data", &test_data_reply,
131 #endif
132 0, 0,
135 static char *reply_code;
136 static char *reply_dsn;
137 static char *reply_message;
139 #ifdef SMFIR_CHGFROM
140 static char *chg_from;
142 #endif
144 #ifdef SMFIR_INSHEADER
145 static char *ins_hdr;
146 static int ins_idx;
147 static char *ins_val;
149 #endif
151 #ifdef SMFIR_CHGHEADER
152 static char *chg_hdr;
153 static int chg_idx;
154 static char *chg_val;
156 #endif
158 #ifdef SMFIR_REPLBODY
159 static char *body_file;
161 #endif
163 #define MAX_RCPT 10
164 int rcpt_count = 0;
165 char *rcpt_addr[MAX_RCPT];
167 static const char *macro_names[] = {
168 "_",
169 "i",
170 "j",
171 "v",
172 "{auth_authen}",
173 "{auth_author}",
174 "{auth_type}",
175 "{cert_issuer}",
176 "{cert_subject}",
177 "{cipher}",
178 "{cipher_bits}",
179 "{client_addr}",
180 "{client_connections}",
181 "{client_name}",
182 "{client_port}",
183 "{client_ptr}",
184 "{client_resolve}",
185 "{daemon_name}",
186 "{if_addr}",
187 "{if_name}",
188 "{mail_addr}",
189 "{mail_host}",
190 "{mail_mailer}",
191 "{rcpt_addr}",
192 "{rcpt_host}",
193 "{rcpt_mailer}",
194 "{tls_version}",
198 static int test_reply(SMFICTX *ctx, int code)
200 const char **cpp;
201 const char *symval;
203 for (cpp = macro_names; *cpp; cpp++)
204 if ((symval = smfi_getsymval(ctx, (char *) *cpp)) != 0)
205 printf("macro: %s=\"%s\"\n", *cpp, symval);
206 (void) fflush(stdout); /* In case output redirected. */
208 if (code == SMFIR_REPLYCODE) {
209 if (smfi_setmlreply(ctx, reply_code, reply_dsn, reply_message, reply_message, (char *) 0) == MI_FAILURE)
210 fprintf(stderr, "smfi_setmlreply failed\n");
211 printf("test_reply %s\n", reply_code);
212 return (reply_code[0] == '4' ? SMFIS_TEMPFAIL : SMFIS_REJECT);
213 } else {
214 printf("test_reply %d\n", code);
215 return (code);
219 static sfsistat test_connect(SMFICTX *ctx, char *name, struct sockaddr * sa)
221 const char *print_addr;
222 char buf[BUFSIZ];
224 printf("test_connect %s ", name);
225 switch (sa->sa_family) {
226 case AF_INET:
228 struct sockaddr_in *sin = (struct sockaddr_in *) sa;
230 print_addr = inet_ntop(AF_INET, &sin->sin_addr, buf, sizeof(buf));
231 if (print_addr == 0)
232 print_addr = strerror(errno);
233 printf("AF_INET (%s:%d)\n", print_addr, ntohs(sin->sin_port));
235 break;
236 #ifdef HAS_IPV6
237 case AF_INET6:
239 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sa;
241 print_addr = inet_ntop(AF_INET, &sin6->sin6_addr, buf, sizeof(buf));
242 if (print_addr == 0)
243 print_addr = strerror(errno);
244 printf("AF_INET6 (%s:%d)\n", print_addr, ntohs(sin6->sin6_port));
246 break;
247 #endif
248 case AF_UNIX:
250 #undef sun
251 struct sockaddr_un *sun = (struct sockaddr_un *) sa;
253 printf("AF_UNIX (%s)\n", sun->sun_path);
255 break;
256 default:
257 printf(" [unknown address family]\n");
258 break;
260 return (test_reply(ctx, test_connect_reply));
263 static sfsistat test_helo(SMFICTX *ctx, char *arg)
265 printf("test_helo \"%s\"\n", arg ? arg : "NULL");
266 return (test_reply(ctx, test_helo_reply));
269 static sfsistat test_mail(SMFICTX *ctx, char **argv)
271 char **cpp;
273 printf("test_mail");
274 for (cpp = argv; *cpp; cpp++)
275 printf(" \"%s\"", *cpp);
276 printf("\n");
277 return (test_reply(ctx, test_mail_reply));
280 static sfsistat test_rcpt(SMFICTX *ctx, char **argv)
282 char **cpp;
284 printf("test_rcpt");
285 for (cpp = argv; *cpp; cpp++)
286 printf(" \"%s\"", *cpp);
287 printf("\n");
288 return (test_reply(ctx, test_rcpt_reply));
292 sfsistat test_header(SMFICTX *ctx, char *name, char *value)
294 printf("test_header \"%s\" \"%s\"\n", name, value);
295 return (test_reply(ctx, test_header_reply));
298 static sfsistat test_eoh(SMFICTX *ctx)
300 printf("test_eoh\n");
301 return (test_reply(ctx, test_eoh_reply));
304 static sfsistat test_body(SMFICTX *ctx, unsigned char *data, size_t data_len)
306 if (verbose == 0)
307 printf("test_body %ld bytes\n", (long) data_len);
308 else
309 printf("%.*s", (int) data_len, data);
310 return (test_reply(ctx, test_body_reply));
313 static sfsistat test_eom(SMFICTX *ctx)
315 printf("test_eom\n");
316 #ifdef SMFIR_REPLBODY
317 if (body_file) {
318 char buf[BUFSIZ + 2];
319 FILE *fp;
320 size_t len;
321 int count;
323 if ((fp = fopen(body_file, "r")) == 0) {
324 perror(body_file);
325 } else {
326 printf("replace body with content of %s\n", body_file);
327 for (count = 0; fgets(buf, BUFSIZ, fp) != 0; count++) {
328 len = strcspn(buf, "\n");
329 buf[len + 0] = '\r';
330 buf[len + 1] = '\n';
331 if (smfi_replacebody(ctx, buf, len + 2) == MI_FAILURE) {
332 fprintf(stderr, "body replace failure\n");
333 exit(1);
335 if (verbose)
336 printf("%.*s\n", (int) len, buf);
338 if (count == 0)
339 perror("fgets");
340 (void) fclose(fp);
343 #endif
344 #ifdef SMFIR_CHGFROM
345 if (chg_from != 0 && smfi_chgfrom(ctx, chg_from, "whatever") == MI_FAILURE)
346 fprintf(stderr, "smfi_chgfrom failed\n");
347 else
348 printf("smfi_chgfrom OK\n");
349 #endif
350 #ifdef SMFIR_INSHEADER
351 if (ins_hdr && smfi_insheader(ctx, ins_idx, ins_hdr, ins_val) == MI_FAILURE)
352 fprintf(stderr, "smfi_insheader failed\n");
353 #endif
354 #ifdef SMFIR_CHGHEADER
355 if (chg_hdr && smfi_chgheader(ctx, chg_hdr, chg_idx, chg_val) == MI_FAILURE)
356 fprintf(stderr, "smfi_chgheader failed\n");
357 #endif
359 int count;
361 for (count = 0; count < rcpt_count; count++)
362 if (smfi_addrcpt(ctx, rcpt_addr[count]) == MI_FAILURE)
363 fprintf(stderr, "smfi_addrcpt `%s' failed\n", rcpt_addr[count]);
365 return (test_reply(ctx, test_eom_reply));
368 static sfsistat test_abort(SMFICTX *ctx)
370 printf("test_abort\n");
371 return (test_reply(ctx, test_abort_reply));
374 static sfsistat test_close(SMFICTX *ctx)
376 printf("test_close\n");
377 if (verbose)
378 printf("conn_count %d\n", conn_count);
379 if (conn_count > 0 && --conn_count == 0)
380 exit(0);
381 return (test_reply(ctx, test_close_reply));
384 #if SMFI_VERSION > 3
386 static sfsistat test_data(SMFICTX *ctx)
388 printf("test_data\n");
389 return (test_reply(ctx, test_data_reply));
392 #endif
394 #if SMFI_VERSION > 2
396 static sfsistat test_unknown(SMFICTX *ctx, const char *what)
398 printf("test_unknown %s\n", what);
399 return (test_reply(ctx, test_unknown_reply));
402 #endif
404 static sfsistat test_negotiate(SMFICTX *, unsigned long, unsigned long,
405 unsigned long, unsigned long,
406 unsigned long *, unsigned long *,
407 unsigned long *, unsigned long *);
409 static struct smfiDesc smfilter =
411 "test-milter",
412 SMFI_VERSION,
413 SMFIF_ADDRCPT | SMFIF_DELRCPT | SMFIF_ADDHDRS | SMFIF_CHGHDRS | SMFIF_CHGBODY | SMFIF_CHGFROM,
414 test_connect,
415 test_helo,
416 test_mail,
417 test_rcpt,
418 test_header,
419 test_eoh,
420 test_body,
421 test_eom,
422 test_abort,
423 test_close,
424 #if SMFI_VERSION > 2
425 test_unknown,
426 #endif
427 #if SMFI_VERSION > 3
428 test_data,
429 #endif
430 #if SMFI_VERSION > 5
431 test_negotiate,
432 #endif
435 #if SMFI_VERSION > 5
437 static const char *macro_states[] = {
438 "connect", /* SMFIM_CONNECT */
439 "helo", /* SMFIM_HELO */
440 "mail", /* SMFIM_ENVFROM */
441 "rcpt", /* SMFIM_ENVRCPT */
442 "data", /* SMFIM_DATA */
443 "eom", /* SMFIM_EOM < SMFIM_EOH */
444 "eoh", /* SMFIM_EOH > SMFIM_EOM */
448 static int set_macro_state;
449 static char *set_macro_list;
451 typedef sfsistat (*FILTER_ACTION) ();
453 struct noproto_map {
454 const char *name;
455 int send_mask;
456 int reply_mask;
457 int *reply;
458 FILTER_ACTION *action;
461 static const struct noproto_map noproto_map[] = {
462 "connect", SMFIP_NOCONNECT, SMFIP_NR_CONN, &test_connect_reply, &smfilter.xxfi_connect,
463 "helo", SMFIP_NOHELO, SMFIP_NR_HELO, &test_helo_reply, &smfilter.xxfi_helo,
464 "mail", SMFIP_NOMAIL, SMFIP_NR_MAIL, &test_mail_reply, &smfilter.xxfi_envfrom,
465 "rcpt", SMFIP_NORCPT, SMFIP_NR_RCPT, &test_rcpt_reply, &smfilter.xxfi_envrcpt,
466 "data", SMFIP_NODATA, SMFIP_NR_DATA, &test_data_reply, &smfilter.xxfi_data,
467 "header", SMFIP_NOHDRS, SMFIP_NR_HDR, &test_header_reply, &smfilter.xxfi_header,
468 "eoh", SMFIP_NOEOH, SMFIP_NR_EOH, &test_eoh_reply, &smfilter.xxfi_eoh,
469 "body", SMFIP_NOBODY, SMFIP_NR_BODY, &test_body_reply, &smfilter.xxfi_body,
470 "unknown", SMFIP_NOUNKNOWN, SMFIP_NR_UNKN, &test_connect_reply, &smfilter.xxfi_unknown,
474 static int nosend_mask;
475 static int noreply_mask;
476 static int misc_mask;
478 static sfsistat test_negotiate(SMFICTX *ctx,
479 unsigned long f0,
480 unsigned long f1,
481 unsigned long f2,
482 unsigned long f3,
483 unsigned long *pf0,
484 unsigned long *pf1,
485 unsigned long *pf2,
486 unsigned long *pf3)
488 if (set_macro_list) {
489 if (verbose)
490 printf("set symbol list %s to \"%s\"\n",
491 macro_states[set_macro_state], set_macro_list);
492 smfi_setsymlist(ctx, set_macro_state, set_macro_list);
494 if (verbose)
495 printf("negotiate f0=%lx *pf0 = %lx f1=%lx *pf1=%lx nosend=%lx noreply=%lx misc=%lx\n",
496 f0, *pf0, f1, *pf1, (long) nosend_mask, (long) noreply_mask, (long) misc_mask);
497 *pf0 = f0;
498 *pf1 = f1 & (nosend_mask | noreply_mask | misc_mask);
499 return (SMFIS_CONTINUE);
502 #endif
504 static void parse_hdr_info(const char *optarg, int *idx,
505 char **hdr, char **value)
507 int len;
509 len = strlen(optarg) + 1;
510 if ((*hdr = malloc(len)) == 0 || (*value = malloc(len)) == 0) {
511 fprintf(stderr, "out of memory\n");
512 exit(1);
514 if ((misc_mask & SMFIP_HDR_LEADSPC) == 0 ?
515 sscanf(optarg, "%d %s %[^\n]", idx, *hdr, *value) != 3 :
516 sscanf(optarg, "%d %[^ ]%[^\n]", idx, *hdr, *value) != 3) {
517 fprintf(stderr, "bad header info: %s\n", optarg);
518 exit(1);
522 int main(int argc, char **argv)
524 char *action = 0;
525 char *command = 0;
526 const struct command_map *cp;
527 int ch;
528 int code;
529 const char **cpp;
530 char *set_macro_state_arg = 0;
531 char *nosend = 0;
532 char *noreply = 0;
533 const struct noproto_map *np;
535 while ((ch = getopt(argc, argv, "a:A:b:c:C:d:f:h:i:lm:M:n:N:p:rv")) > 0) {
536 switch (ch) {
537 case 'a':
538 action = optarg;
539 break;
540 case 'A':
541 if (rcpt_count >= MAX_RCPT) {
542 fprintf(stderr, "too many -A options\n");
543 exit(1);
545 rcpt_addr[rcpt_count++] = optarg;
546 break;
547 case 'b':
548 #ifdef SMFIR_REPLBODY
549 if (body_file) {
550 fprintf(stderr, "too many -b options\n");
551 exit(1);
553 body_file = optarg;
554 #else
555 fprintf(stderr, "no libmilter support to replace body\n");
556 #endif
557 break;
558 case 'c':
559 command = optarg;
560 break;
561 case 'd':
562 if (smfi_setdbg(atoi(optarg)) == MI_FAILURE) {
563 fprintf(stderr, "smfi_setdbg failed\n");
564 exit(1);
566 break;
567 case 'f':
568 #ifdef SMFIR_CHGFROM
569 if (chg_from) {
570 fprintf(stderr, "too many -f options\n");
571 exit(1);
573 chg_from = optarg;
574 #else
575 fprintf(stderr, "no libmilter support to change sender\n");
576 exit(1);
577 #endif
578 break;
579 case 'h':
580 #ifdef SMFIR_CHGHEADER
581 if (chg_hdr) {
582 fprintf(stderr, "too many -h options\n");
583 exit(1);
585 parse_hdr_info(optarg, &chg_idx, &chg_hdr, &chg_val);
586 #else
587 fprintf(stderr, "no libmilter support to change header\n");
588 exit(1);
589 #endif
590 break;
591 case 'i':
592 #ifdef SMFIR_INSHEADER
593 if (ins_hdr) {
594 fprintf(stderr, "too many -i options\n");
595 exit(1);
597 parse_hdr_info(optarg, &ins_idx, &ins_hdr, &ins_val);
598 #else
599 fprintf(stderr, "no libmilter support to insert header\n");
600 exit(1);
601 #endif
602 break;
603 case 'l':
604 #if SMFI_VERSION > 5
605 if (ins_hdr || chg_hdr) {
606 fprintf(stderr, "specify -l before -i or -r\n");
607 exit(1);
609 misc_mask |= SMFIP_HDR_LEADSPC;
610 #else
611 fprintf(stderr, "no libmilter support for leading space\n");
612 exit(1);
613 #endif
614 break;
615 case 'm':
616 #if SMFI_VERSION > 5
617 if (set_macro_state_arg) {
618 fprintf(stderr, "too many -m options\n");
619 exit(1);
621 set_macro_state_arg = optarg;
622 #else
623 fprintf(stderr, "no libmilter support to specify macro list\n");
624 exit(1);
625 #endif
626 break;
627 case 'M':
628 #if SMFI_VERSION > 5
629 if (set_macro_list) {
630 fprintf(stderr, "too many -M options\n");
631 exit(1);
633 set_macro_list = optarg;
634 #else
635 fprintf(stderr, "no libmilter support to specify macro list\n");
636 #endif
637 break;
638 case 'n':
639 #if SMFI_VERSION > 5
640 if (nosend) {
641 fprintf(stderr, "too many -n options\n");
642 exit(1);
644 nosend = optarg;
645 #else
646 fprintf(stderr, "no libmilter support for negotiate callback\n");
647 #endif
648 break;
649 case 'N':
650 #if SMFI_VERSION > 5
651 if (noreply) {
652 fprintf(stderr, "too many -n options\n");
653 exit(1);
655 noreply = optarg;
656 #else
657 fprintf(stderr, "no libmilter support for negotiate callback\n");
658 #endif
659 break;
660 case 'p':
661 if (smfi_setconn(optarg) == MI_FAILURE) {
662 fprintf(stderr, "smfi_setconn failed\n");
663 exit(1);
665 break;
666 case 'r':
667 #ifdef SMFIP_RCPT_REJ
668 misc_mask |= SMFIP_RCPT_REJ;
669 #else
670 fprintf(stderr, "no libmilter support for rejected recipients\n");
671 #endif
672 break;
673 case 'v':
674 verbose++;
675 break;
676 case 'C':
677 conn_count = atoi(optarg);
678 break;
679 default:
680 fprintf(stderr,
681 "usage: %s [-dv] \n"
682 "\t[-a action] non-default action\n"
683 "\t[-b body_text] replace body\n",
684 "\t[-c command] non-default action trigger\n"
685 "\t[-h 'index label value'] replace header\n"
686 "\t[-i 'index label value'] insert header\n"
687 "\t[-m macro_state] non-default macro state\n"
688 "\t[-M macro_list] non-default macro list\n"
689 "\t[-n events] don't receive these events\n"
690 "\t[-N events] don't reply to these events\n"
691 "\t-p port milter application\n"
692 "\t-r request rejected recipients\n"
693 "\t[-C conn_count] when to exit\n",
694 argv[0]);
695 exit(1);
698 if (command) {
699 for (cp = command_map; /* see below */ ; cp++) {
700 if (cp->name == 0) {
701 fprintf(stderr, "bad -c argument: %s\n", command);
702 exit(1);
704 if (strcmp(command, cp->name) == 0)
705 break;
708 if (action) {
709 if (command == 0)
710 cp = command_map;
711 if (strcmp(action, "tempfail") == 0) {
712 cp->reply[0] = SMFIS_TEMPFAIL;
713 } else if (strcmp(action, "reject") == 0) {
714 cp->reply[0] = SMFIS_REJECT;
715 } else if (strcmp(action, "accept") == 0) {
716 cp->reply[0] = SMFIS_ACCEPT;
717 } else if (strcmp(action, "discard") == 0) {
718 cp->reply[0] = SMFIS_DISCARD;
719 #ifdef SMFIS_SKIP
720 } else if (strcmp(action, "skip") == 0) {
721 cp->reply[0] = SMFIS_SKIP;
722 #endif
723 } else if ((code = atoi(action)) >= 400
724 && code <= 599
725 && action[3] == ' ') {
726 cp->reply[0] = SMFIR_REPLYCODE;
727 reply_code = action;
728 reply_dsn = action + 3;
729 if (*reply_dsn != 0) {
730 *reply_dsn++ = 0;
731 reply_dsn += strspn(reply_dsn, " ");
733 if (*reply_dsn == 0) {
734 reply_dsn = reply_message = 0;
735 } else {
736 reply_message = reply_dsn + strcspn(reply_dsn, " ");
737 if (*reply_message != 0) {
738 *reply_message++ = 0;
739 reply_message += strspn(reply_message, " ");
741 if (*reply_message == 0)
742 reply_message = 0;
744 } else {
745 fprintf(stderr, "bad -a argument: %s\n", action);
746 exit(1);
748 if (verbose) {
749 printf("command %s action %d\n", cp->name, cp->reply[0]);
750 if (reply_code)
751 printf("reply code %s dsn %s message %s\n",
752 reply_code, reply_dsn ? reply_dsn : "(null)",
753 reply_message ? reply_message : "(null)");
756 #if SMFI_VERSION > 5
757 if (set_macro_state_arg) {
758 for (cpp = macro_states; /* see below */ ; cpp++) {
759 if (*cpp == 0) {
760 fprintf(stderr, "bad -m argument: %s\n", set_macro_state_arg);
761 exit(1);
763 if (strcmp(set_macro_state_arg, *cpp) == 0)
764 break;
766 set_macro_state = cpp - macro_states;
768 if (nosend) {
769 for (np = noproto_map; /* see below */ ; np++) {
770 if (np->name == 0) {
771 fprintf(stderr, "bad -n argument: %s\n", nosend);
772 exit(1);
774 if (strcmp(nosend, np->name) == 0)
775 break;
777 nosend_mask = np->send_mask;
778 np->action[0] = 0;
780 if (noreply) {
781 for (np = noproto_map; /* see below */ ; np++) {
782 if (np->name == 0) {
783 fprintf(stderr, "bad -N argument: %s\n", noreply);
784 exit(1);
786 if (strcmp(noreply, np->name) == 0)
787 break;
789 noreply_mask = np->reply_mask;
790 *np->reply = SMFIS_NOREPLY;
792 #endif
793 if (smfi_register(smfilter) == MI_FAILURE) {
794 fprintf(stderr, "smfi_register failed\n");
795 exit(1);
797 return (smfi_main());