diff options
Diffstat (limited to '')
-rw-r--r-- | src/milter/test-milter.c | 839 |
1 files changed, 839 insertions, 0 deletions
diff --git a/src/milter/test-milter.c b/src/milter/test-milter.c new file mode 100644 index 0000000..ac0d8e5 --- /dev/null +++ b/src/milter/test-milter.c @@ -0,0 +1,839 @@ +/*++ +/* NAME +/* test-milter 1 +/* SUMMARY +/* Simple test mail filter program. +/* SYNOPSIS +/* .fi +/* \fBtest-milter\fR [\fIoptions\fR] -p \fBinet:\fIport\fB@\fIhost\fR +/* +/* \fBtest-milter\fR [\fIoptions\fR] -p \fBunix:\fIpathname\fR +/* DESCRIPTION +/* \fBtest-milter\fR is a Milter (mail filter) application that +/* exercises selected features. +/* +/* Note: this is an unsupported test program. No attempt is made +/* to maintain compatibility between successive versions. +/* +/* Arguments (multiple alternatives are separated by "\fB|\fR"): +/* .IP "\fB-a accept|tempfail|reject|discard|skip|\fIddd x.y.z text\fR" +/* Specifies a non-default reply for the MTA command specified +/* with \fB-c\fR. The default is \fBtempfail\fR. +/* .IP "\fB-A address\fR" +/* Add the specified recipient address (specify ESMTP parameters +/* separated by space). Multiple -A options are supported. +/* .IP "\fB-b pathname\fR" +/* Replace the message body by the content of the specified file. +/* .IP "\fB-c connect|helo|mail|rcpt|data|header|eoh|body|eom|unknown|close|abort\fR" +/* When to send the non-default reply specified with \fB-a\fR. +/* The default protocol stage is \fBconnect\fR. +/* .IP "\fB-C\fI count\fR" +/* Terminate after \fIcount\fR connections. +/* .IP "\fB-d\fI level\fR" +/* Enable libmilter debugging at the specified level. +/* .IP "\fB-D\fI address\fR" +/* Delete the specified recipient address. Multiple -D options +/* are supported. +/* .IP "\fB-f \fIsender\fR" +/* Replace the sender by the specified address. +/* .IP "\fB-h \fI'index header-label header-value'\fR" +/* Replace the message header at the specified position. +/* .IP "\fB-i \fI'index header-label header-value'\fR" +/* Insert header at specified position. +/* .IP "\fB-l\fR" +/* Header values include leading space. Specify this option +/* before \fB-i\fR or \fB-h\fR. +/* .IP "\fB-m connect|helo|mail|rcpt|data|eoh|eom\fR" +/* The protocol stage that receives the list of macros specified +/* with \fB-M\fR. The default protocol stage is \fBconnect\fR. +/* .IP "\fB-M \fIset_macro_list\fR" +/* A non-default list of macros that the MTA should send at +/* the protocol stage specified with \fB-m\fR. +/* .IP "\fB-n connect|helo|mail|rcpt|data|header|eoh|body|eom|unknown\fR" +/* The event that the MTA should not send. +/* .IP "\fB-N connect|helo|mail|rcpt|data|header|eoh|body|eom|unknown\fR" +/* The event for which the filter will not reply. +/* .IP "\fB-p inet:\fIport\fB@\fIhost\fB|unix:\fIpathname\fR" +/* The mail filter listen endpoint. +/* .IP "\fB-r\fR" +/* Request rejected recipients from the MTA. +/* .IP "\fB-v\fR" +/* Make the program more verbose. +/* LICENSE +/* .ad +/* .fi +/* The Secure Mailer license must be distributed with this software. +/* AUTHOR(S) +/* Wietse Venema +/* IBM T.J. Watson Research +/* P.O. Box 704 +/* Yorktown Heights, NY 10598, USA +/* +/* Wietse Venema +/* Google, Inc. +/* 111 8th Avenue +/* New York, NY 10011, USA +/*--*/ + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <sys/un.h> +#include <arpa/inet.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> + +#include "libmilter/mfapi.h" +#include "libmilter/mfdef.h" + +static int conn_count; +static int verbose; + +static int test_connect_reply = SMFIS_CONTINUE; +static int test_helo_reply = SMFIS_CONTINUE; +static int test_mail_reply = SMFIS_CONTINUE; +static int test_rcpt_reply = SMFIS_CONTINUE; + +#if SMFI_VERSION > 3 +static int test_data_reply = SMFIS_CONTINUE; + +#endif +static int test_header_reply = SMFIS_CONTINUE; +static int test_eoh_reply = SMFIS_CONTINUE; +static int test_body_reply = SMFIS_CONTINUE; +static int test_eom_reply = SMFIS_CONTINUE; + +#if SMFI_VERSION > 2 +static int test_unknown_reply = SMFIS_CONTINUE; + +#endif +static int test_close_reply = SMFIS_CONTINUE; +static int test_abort_reply = SMFIS_CONTINUE; + +struct command_map { + const char *name; + int *reply; +}; + +static const struct command_map command_map[] = { + "connect", &test_connect_reply, + "helo", &test_helo_reply, + "mail", &test_mail_reply, + "rcpt", &test_rcpt_reply, + "header", &test_header_reply, + "eoh", &test_eoh_reply, + "body", &test_body_reply, + "eom", &test_eom_reply, + "abort", &test_abort_reply, + "close", &test_close_reply, +#if SMFI_VERSION > 2 + "unknown", &test_unknown_reply, +#endif +#if SMFI_VERSION > 3 + "data", &test_data_reply, +#endif + 0, 0, +}; + +static char *reply_code; +static char *reply_dsn; +static char *reply_message; + +#ifdef SMFIR_CHGFROM +static char *chg_from; + +#endif + +#ifdef SMFIR_INSHEADER +static char *ins_hdr; +static int ins_idx; +static char *ins_val; + +#endif + +#ifdef SMFIR_CHGHEADER +static char *chg_hdr; +static int chg_idx; +static char *chg_val; + +#endif + +#ifdef SMFIR_REPLBODY +static char *body_file; + +#endif + +#define MAX_RCPT 10 +int add_rcpt_count = 0; +char *add_rcpt[MAX_RCPT]; +int del_rcpt_count = 0; +char *del_rcpt[MAX_RCPT]; + +static const char *macro_names[] = { + "_", + "i", + "j", + "v", + "{auth_authen}", + "{auth_author}", + "{auth_type}", + "{cert_issuer}", + "{cert_subject}", + "{cipher}", + "{cipher_bits}", + "{client_addr}", + "{client_connections}", + "{client_name}", + "{client_port}", + "{client_ptr}", + "{client_resolve}", + "{daemon_addr}", + "{daemon_name}", + "{daemon_port}", + "{if_addr}", + "{if_name}", + "{mail_addr}", + "{mail_host}", + "{mail_mailer}", + "{rcpt_addr}", + "{rcpt_host}", + "{rcpt_mailer}", + "{tls_version}", + 0, +}; + +static int test_reply(SMFICTX *ctx, int code) +{ + const char **cpp; + const char *symval; + + for (cpp = macro_names; *cpp; cpp++) + if ((symval = smfi_getsymval(ctx, (char *) *cpp)) != 0) + printf("macro: %s=\"%s\"\n", *cpp, symval); + (void) fflush(stdout); /* In case output redirected. */ + + if (code == SMFIR_REPLYCODE) { + if (smfi_setmlreply(ctx, reply_code, reply_dsn, reply_message, reply_message, (char *) 0) == MI_FAILURE) + fprintf(stderr, "smfi_setmlreply failed\n"); + printf("test_reply %s\n", reply_code); + return (reply_code[0] == '4' ? SMFIS_TEMPFAIL : SMFIS_REJECT); + } else { + printf("test_reply %d\n\n", code); + return (code); + } +} + +static sfsistat test_connect(SMFICTX *ctx, char *name, struct sockaddr * sa) +{ + const char *print_addr; + char buf[BUFSIZ]; + + printf("test_connect %s ", name); + switch (sa->sa_family) { + case AF_INET: + { + struct sockaddr_in *sin = (struct sockaddr_in *) sa; + + print_addr = inet_ntop(AF_INET, &sin->sin_addr, buf, sizeof(buf)); + if (print_addr == 0) + print_addr = strerror(errno); + printf("AF_INET (%s:%d)\n", print_addr, ntohs(sin->sin_port)); + } + break; +#ifdef HAS_IPV6 + case AF_INET6: + { + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sa; + + print_addr = inet_ntop(AF_INET, &sin6->sin6_addr, buf, sizeof(buf)); + if (print_addr == 0) + print_addr = strerror(errno); + printf("AF_INET6 (%s:%d)\n", print_addr, ntohs(sin6->sin6_port)); + } + break; +#endif + case AF_UNIX: + { +#undef sun + struct sockaddr_un *sun = (struct sockaddr_un *) sa; + + printf("AF_UNIX (%s)\n", sun->sun_path); + } + break; + default: + printf(" [unknown address family]\n"); + break; + } + return (test_reply(ctx, test_connect_reply)); +} + +static sfsistat test_helo(SMFICTX *ctx, char *arg) +{ + printf("test_helo \"%s\"\n", arg ? arg : "NULL"); + return (test_reply(ctx, test_helo_reply)); +} + +static sfsistat test_mail(SMFICTX *ctx, char **argv) +{ + char **cpp; + + printf("test_mail"); + for (cpp = argv; *cpp; cpp++) + printf(" \"%s\"", *cpp); + printf("\n"); + return (test_reply(ctx, test_mail_reply)); +} + +static sfsistat test_rcpt(SMFICTX *ctx, char **argv) +{ + char **cpp; + + printf("test_rcpt"); + for (cpp = argv; *cpp; cpp++) + printf(" \"%s\"", *cpp); + printf("\n"); + return (test_reply(ctx, test_rcpt_reply)); +} + + +sfsistat test_header(SMFICTX *ctx, char *name, char *value) +{ + printf("test_header \"%s\" \"%s\"\n", name, value); + return (test_reply(ctx, test_header_reply)); +} + +static sfsistat test_eoh(SMFICTX *ctx) +{ + printf("test_eoh\n"); + return (test_reply(ctx, test_eoh_reply)); +} + +static sfsistat test_body(SMFICTX *ctx, unsigned char *data, size_t data_len) +{ + if (verbose == 0) + printf("test_body %ld bytes\n", (long) data_len); + else + printf("%.*s", (int) data_len, data); + return (test_reply(ctx, test_body_reply)); +} + +static sfsistat test_eom(SMFICTX *ctx) +{ + printf("test_eom\n"); +#ifdef SMFIR_REPLBODY + if (body_file) { + char buf[BUFSIZ + 2]; + FILE *fp; + size_t len; + int count; + + if ((fp = fopen(body_file, "r")) == 0) { + perror(body_file); + } else { + printf("replace body with content of %s\n", body_file); + for (count = 0; fgets(buf, BUFSIZ, fp) != 0; count++) { + len = strcspn(buf, "\n"); + buf[len + 0] = '\r'; + buf[len + 1] = '\n'; + if (smfi_replacebody(ctx, buf, len + 2) == MI_FAILURE) { + fprintf(stderr, "body replace failure\n"); + exit(1); + } + if (verbose) + printf("%.*s\n", (int) len, buf); + } + if (count == 0) + perror("fgets"); + (void) fclose(fp); + } + } +#endif +#ifdef SMFIR_CHGFROM + if (chg_from != 0 && smfi_chgfrom(ctx, chg_from, "whatever") == MI_FAILURE) + fprintf(stderr, "smfi_chgfrom failed\n"); +#endif +#ifdef SMFIR_INSHEADER + if (ins_hdr && smfi_insheader(ctx, ins_idx, ins_hdr, ins_val) == MI_FAILURE) + fprintf(stderr, "smfi_insheader failed\n"); +#endif +#ifdef SMFIR_CHGHEADER + if (chg_hdr && smfi_chgheader(ctx, chg_hdr, chg_idx, chg_val) == MI_FAILURE) + fprintf(stderr, "smfi_chgheader failed\n"); +#endif + { + int count; + char *args; + + for (count = 0; count < add_rcpt_count; count++) { + if ((args = strchr(add_rcpt[count], ' ')) != 0) { + *args++ = 0; + if (smfi_addrcpt_par(ctx, add_rcpt[count], args) == MI_FAILURE) + fprintf(stderr, "smfi_addrcpt_par `%s' `%s' failed\n", + add_rcpt[count], args); + } else { + if (smfi_addrcpt(ctx, add_rcpt[count]) == MI_FAILURE) + fprintf(stderr, "smfi_addrcpt `%s' failed\n", + add_rcpt[count]); + } + } + + for (count = 0; count < del_rcpt_count; count++) + if (smfi_delrcpt(ctx, del_rcpt[count]) == MI_FAILURE) + fprintf(stderr, "smfi_delrcpt `%s' failed\n", del_rcpt[count]); + } + return (test_reply(ctx, test_eom_reply)); +} + +static sfsistat test_abort(SMFICTX *ctx) +{ + printf("test_abort\n"); + return (test_reply(ctx, test_abort_reply)); +} + +static sfsistat test_close(SMFICTX *ctx) +{ + printf("test_close\n"); + if (verbose) + printf("conn_count %d\n", conn_count); + if (conn_count > 0 && --conn_count == 0) + exit(0); + return (test_reply(ctx, test_close_reply)); +} + +#if SMFI_VERSION > 3 + +static sfsistat test_data(SMFICTX *ctx) +{ + printf("test_data\n"); + return (test_reply(ctx, test_data_reply)); +} + +#endif + +#if SMFI_VERSION > 2 + +static sfsistat test_unknown(SMFICTX *ctx, const char *what) +{ + printf("test_unknown %s\n", what); + return (test_reply(ctx, test_unknown_reply)); +} + +#endif + +#if SMFI_VERSION > 5 + +static sfsistat test_negotiate(SMFICTX *, unsigned long, unsigned long, + unsigned long, unsigned long, + unsigned long *, unsigned long *, + unsigned long *, unsigned long *); + +#endif + +#ifndef SMFIF_CHGFROM +#define SMFIF_CHGFROM 0 +#endif +#ifndef SMFIP_HDR_LEADSPC +#define SMFIP_HDR_LEADSPC 0 +#define misc_mask 0 +#endif + +static struct smfiDesc smfilter = +{ + "test-milter", + SMFI_VERSION, + SMFIF_ADDRCPT | SMFIF_DELRCPT | SMFIF_ADDHDRS | SMFIF_CHGHDRS | SMFIF_CHGBODY | SMFIF_CHGFROM, + test_connect, + test_helo, + test_mail, + test_rcpt, + test_header, + test_eoh, + test_body, + test_eom, + test_abort, + test_close, +#if SMFI_VERSION > 2 + test_unknown, +#endif +#if SMFI_VERSION > 3 + test_data, +#endif +#if SMFI_VERSION > 5 + test_negotiate, +#endif +}; + +#if SMFI_VERSION > 5 + +static const char *macro_states[] = { + "connect", /* SMFIM_CONNECT */ + "helo", /* SMFIM_HELO */ + "mail", /* SMFIM_ENVFROM */ + "rcpt", /* SMFIM_ENVRCPT */ + "data", /* SMFIM_DATA */ + "eom", /* SMFIM_EOM < SMFIM_EOH */ + "eoh", /* SMFIM_EOH > SMFIM_EOM */ + 0, +}; + +static int set_macro_state; +static char *set_macro_list; + +typedef sfsistat (*FILTER_ACTION) (); + +struct noproto_map { + const char *name; + int send_mask; + int reply_mask; + int *reply; + FILTER_ACTION *action; +}; + +static const struct noproto_map noproto_map[] = { + "connect", SMFIP_NOCONNECT, SMFIP_NR_CONN, &test_connect_reply, &smfilter.xxfi_connect, + "helo", SMFIP_NOHELO, SMFIP_NR_HELO, &test_helo_reply, &smfilter.xxfi_helo, + "mail", SMFIP_NOMAIL, SMFIP_NR_MAIL, &test_mail_reply, &smfilter.xxfi_envfrom, + "rcpt", SMFIP_NORCPT, SMFIP_NR_RCPT, &test_rcpt_reply, &smfilter.xxfi_envrcpt, + "data", SMFIP_NODATA, SMFIP_NR_DATA, &test_data_reply, &smfilter.xxfi_data, + "header", SMFIP_NOHDRS, SMFIP_NR_HDR, &test_header_reply, &smfilter.xxfi_header, + "eoh", SMFIP_NOEOH, SMFIP_NR_EOH, &test_eoh_reply, &smfilter.xxfi_eoh, + "body", SMFIP_NOBODY, SMFIP_NR_BODY, &test_body_reply, &smfilter.xxfi_body, + "unknown", SMFIP_NOUNKNOWN, SMFIP_NR_UNKN, &test_connect_reply, &smfilter.xxfi_unknown, + 0, +}; + +static int nosend_mask; +static int noreply_mask; +static int misc_mask; + +static sfsistat test_negotiate(SMFICTX *ctx, + unsigned long f0, + unsigned long f1, + unsigned long f2, + unsigned long f3, + unsigned long *pf0, + unsigned long *pf1, + unsigned long *pf2, + unsigned long *pf3) +{ + if (set_macro_list) { + if (verbose) + printf("set symbol list %s to \"%s\"\n", + macro_states[set_macro_state], set_macro_list); + smfi_setsymlist(ctx, set_macro_state, set_macro_list); + } + if (verbose) + printf("negotiate f0=%lx *pf0 = %lx f1=%lx *pf1=%lx nosend=%lx noreply=%lx misc=%lx\n", + f0, *pf0, f1, *pf1, (long) nosend_mask, (long) noreply_mask, (long) misc_mask); + *pf0 = f0; + *pf1 = f1 & (nosend_mask | noreply_mask | misc_mask); + return (SMFIS_CONTINUE); +} + +#endif + +static void parse_hdr_info(const char *optarg, int *idx, + char **hdr, char **value) +{ + int len; + + len = strlen(optarg) + 1; + if ((*hdr = malloc(len)) == 0 || (*value = malloc(len)) == 0) { + fprintf(stderr, "out of memory\n"); + exit(1); + } + if ((misc_mask & SMFIP_HDR_LEADSPC) == 0 ? + sscanf(optarg, "%d %s %[^\n]", idx, *hdr, *value) != 3 : + sscanf(optarg, "%d %[^ ]%[^\n]", idx, *hdr, *value) != 3) { + fprintf(stderr, "bad header info: %s\n", optarg); + exit(1); + } +} + +int main(int argc, char **argv) +{ + char *action = 0; + char *command = 0; + const struct command_map *cp; + int ch; + int code; + const char **cpp; + char *set_macro_state_arg = 0; + char *nosend = 0; + char *noreply = 0; + const struct noproto_map *np; + + while ((ch = getopt(argc, argv, "a:A:b:c:C:d:D:f:h:i:lm:M:n:N:p:rv")) > 0) { + switch (ch) { + case 'a': + action = optarg; + break; + case 'A': + if (add_rcpt_count >= MAX_RCPT) { + fprintf(stderr, "too many -A options\n"); + exit(1); + } + add_rcpt[add_rcpt_count++] = optarg; + break; + case 'b': +#ifdef SMFIR_REPLBODY + if (body_file) { + fprintf(stderr, "too many -b options\n"); + exit(1); + } + body_file = optarg; +#else + fprintf(stderr, "no libmilter support to replace body\n"); +#endif + break; + case 'c': + command = optarg; + break; + case 'd': + if (smfi_setdbg(atoi(optarg)) == MI_FAILURE) { + fprintf(stderr, "smfi_setdbg failed\n"); + exit(1); + } + break; + case 'D': + if (del_rcpt_count >= MAX_RCPT) { + fprintf(stderr, "too many -D options\n"); + exit(1); + } + del_rcpt[del_rcpt_count++] = optarg; + break; + case 'f': +#ifdef SMFIR_CHGFROM + if (chg_from) { + fprintf(stderr, "too many -f options\n"); + exit(1); + } + chg_from = optarg; +#else + fprintf(stderr, "no libmilter support to change sender\n"); + exit(1); +#endif + break; + case 'h': +#ifdef SMFIR_CHGHEADER + if (chg_hdr) { + fprintf(stderr, "too many -h options\n"); + exit(1); + } + parse_hdr_info(optarg, &chg_idx, &chg_hdr, &chg_val); +#else + fprintf(stderr, "no libmilter support to change header\n"); + exit(1); +#endif + break; + case 'i': +#ifdef SMFIR_INSHEADER + if (ins_hdr) { + fprintf(stderr, "too many -i options\n"); + exit(1); + } + parse_hdr_info(optarg, &ins_idx, &ins_hdr, &ins_val); +#else + fprintf(stderr, "no libmilter support to insert header\n"); + exit(1); +#endif + break; + case 'l': +#if SMFI_VERSION > 5 + if (ins_hdr || chg_hdr) { + fprintf(stderr, "specify -l before -i or -r\n"); + exit(1); + } + misc_mask |= SMFIP_HDR_LEADSPC; +#else + fprintf(stderr, "no libmilter support for leading space\n"); + exit(1); +#endif + break; + case 'm': +#if SMFI_VERSION > 5 + if (set_macro_state_arg) { + fprintf(stderr, "too many -m options\n"); + exit(1); + } + set_macro_state_arg = optarg; +#else + fprintf(stderr, "no libmilter support to specify macro list\n"); + exit(1); +#endif + break; + case 'M': +#if SMFI_VERSION > 5 + if (set_macro_list) { + fprintf(stderr, "too many -M options\n"); + exit(1); + } + set_macro_list = optarg; +#else + fprintf(stderr, "no libmilter support to specify macro list\n"); +#endif + break; + case 'n': +#if SMFI_VERSION > 5 + if (nosend) { + fprintf(stderr, "too many -n options\n"); + exit(1); + } + nosend = optarg; +#else + fprintf(stderr, "no libmilter support for negotiate callback\n"); +#endif + break; + case 'N': +#if SMFI_VERSION > 5 + if (noreply) { + fprintf(stderr, "too many -n options\n"); + exit(1); + } + noreply = optarg; +#else + fprintf(stderr, "no libmilter support for negotiate callback\n"); +#endif + break; + case 'p': + if (smfi_setconn(optarg) == MI_FAILURE) { + fprintf(stderr, "smfi_setconn failed\n"); + exit(1); + } + break; + case 'r': +#ifdef SMFIP_RCPT_REJ + misc_mask |= SMFIP_RCPT_REJ; +#else + fprintf(stderr, "no libmilter support for rejected recipients\n"); +#endif + break; + case 'v': + verbose++; + break; + case 'C': + conn_count = atoi(optarg); + break; + default: + fprintf(stderr, + "usage: %s [-dv] \n" + "\t[-a action] non-default action\n" + "\t[-b body_text] replace body\n" + "\t[-c command] non-default action trigger\n" + "\t[-h 'index label value'] replace header\n" + "\t[-i 'index label value'] insert header\n" + "\t[-m macro_state] non-default macro state\n" + "\t[-M macro_list] non-default macro list\n" + "\t[-n events] don't receive these events\n" + "\t[-N events] don't reply to these events\n" + "\t-p port milter application\n" + "\t-r request rejected recipients\n" + "\t[-C conn_count] when to exit\n", + argv[0]); + exit(1); + } + } + if (command) { + for (cp = command_map; /* see below */ ; cp++) { + if (cp->name == 0) { + fprintf(stderr, "bad -c argument: %s\n", command); + exit(1); + } + if (strcmp(command, cp->name) == 0) + break; + } + } + if (action) { + if (command == 0) + cp = command_map; + if (strcmp(action, "tempfail") == 0) { + cp->reply[0] = SMFIS_TEMPFAIL; + } else if (strcmp(action, "reject") == 0) { + cp->reply[0] = SMFIS_REJECT; + } else if (strcmp(action, "accept") == 0) { + cp->reply[0] = SMFIS_ACCEPT; + } else if (strcmp(action, "discard") == 0) { + cp->reply[0] = SMFIS_DISCARD; +#ifdef SMFIS_SKIP + } else if (strcmp(action, "skip") == 0) { + cp->reply[0] = SMFIS_SKIP; +#endif + } else if ((code = atoi(action)) >= 400 + && code <= 599 + && action[3] == ' ') { + cp->reply[0] = SMFIR_REPLYCODE; + reply_code = action; + reply_dsn = action + 3; + if (*reply_dsn != 0) { + *reply_dsn++ = 0; + reply_dsn += strspn(reply_dsn, " "); + } + if (*reply_dsn == 0) { + reply_dsn = reply_message = 0; + } else { + reply_message = reply_dsn + strcspn(reply_dsn, " "); + if (*reply_message != 0) { + *reply_message++ = 0; + reply_message += strspn(reply_message, " "); + } + if (*reply_message == 0) + reply_message = 0; + } + } else { + fprintf(stderr, "bad -a argument: %s\n", action); + exit(1); + } + if (verbose) { + printf("command %s action %d\n", cp->name, cp->reply[0]); + if (reply_code) + printf("reply code %s dsn %s message %s\n", + reply_code, reply_dsn ? reply_dsn : "(null)", + reply_message ? reply_message : "(null)"); + } + } +#if SMFI_VERSION > 5 + if (set_macro_state_arg) { + for (cpp = macro_states; /* see below */ ; cpp++) { + if (*cpp == 0) { + fprintf(stderr, "bad -m argument: %s\n", set_macro_state_arg); + exit(1); + } + if (strcmp(set_macro_state_arg, *cpp) == 0) + break; + } + set_macro_state = cpp - macro_states; + } + if (nosend) { + for (np = noproto_map; /* see below */ ; np++) { + if (np->name == 0) { + fprintf(stderr, "bad -n argument: %s\n", nosend); + exit(1); + } + if (strcmp(nosend, np->name) == 0) + break; + } + nosend_mask = np->send_mask; + np->action[0] = 0; + } + if (noreply) { + for (np = noproto_map; /* see below */ ; np++) { + if (np->name == 0) { + fprintf(stderr, "bad -N argument: %s\n", noreply); + exit(1); + } + if (strcmp(noreply, np->name) == 0) + break; + } + noreply_mask = np->reply_mask; + *np->reply = SMFIS_NOREPLY; + } +#endif + if (smfi_register(smfilter) == MI_FAILURE) { + fprintf(stderr, "smfi_register failed\n"); + exit(1); + } + return (smfi_main()); +} |