78 #include <sys/types.h>
79 #include <sys/socket.h>
80 #include <netinet/in.h>
82 #include <arpa/inet.h>
89 #include "libmilter/mfapi.h"
90 #include "libmilter/mfdef.h"
92 static int conn_count;
95 static int test_connect_reply = SMFIS_CONTINUE;
96 static int test_helo_reply = SMFIS_CONTINUE;
97 static int test_mail_reply = SMFIS_CONTINUE;
98 static int test_rcpt_reply = SMFIS_CONTINUE;
101 static int test_data_reply = SMFIS_CONTINUE;
104 static int test_header_reply = SMFIS_CONTINUE;
105 static int test_eoh_reply = SMFIS_CONTINUE;
106 static int test_body_reply = SMFIS_CONTINUE;
107 static int test_eom_reply = SMFIS_CONTINUE;
110 static int test_unknown_reply = SMFIS_CONTINUE;
113 static int test_close_reply = SMFIS_CONTINUE;
114 static int test_abort_reply = SMFIS_CONTINUE;
122 "connect", &test_connect_reply,
123 "helo", &test_helo_reply,
124 "mail", &test_mail_reply,
125 "rcpt", &test_rcpt_reply,
126 "header", &test_header_reply,
127 "eoh", &test_eoh_reply,
128 "body", &test_body_reply,
129 "eom", &test_eom_reply,
130 "abort", &test_abort_reply,
131 "close", &test_close_reply,
133 "unknown", &test_unknown_reply,
136 "data", &test_data_reply,
141 static char *reply_code;
142 static char *reply_dsn;
143 static char *reply_message;
146 static char *chg_from;
150 #ifdef SMFIR_INSHEADER
151 static char *ins_hdr;
153 static char *ins_val;
157 #ifdef SMFIR_CHGHEADER
158 static char *chg_hdr;
160 static char *chg_val;
164 #ifdef SMFIR_REPLBODY
165 static char *body_file;
175 static const char *macro_names[] = {
188 "{client_connections}",
208 static int test_reply(SMFICTX *ctx,
int code)
213 for (cpp = macro_names; *cpp; cpp++)
214 if ((symval = smfi_getsymval(ctx, (
char *) *cpp)) != 0)
215 printf(
"macro: %s=\"%s\"\n", *cpp, symval);
216 (void) fflush(stdout);
219 if (smfi_setmlreply(ctx, reply_code, reply_dsn, reply_message, reply_message, (
char *) 0) == MI_FAILURE)
220 fprintf(stderr,
"smfi_setmlreply failed\n");
221 printf(
"test_reply %s\n", reply_code);
222 return (reply_code[0] ==
'4' ? SMFIS_TEMPFAIL : SMFIS_REJECT);
224 printf(
"test_reply %d\n\n", code);
229 static sfsistat test_connect(SMFICTX *ctx,
char *
name,
struct sockaddr * sa)
231 const char *print_addr;
234 printf(
"test_connect %s ", name);
235 switch (sa->sa_family) {
238 struct sockaddr_in *sin = (
struct sockaddr_in *) sa;
240 print_addr =
inet_ntop(AF_INET, &sin->sin_addr, buf,
sizeof(buf));
242 print_addr = strerror(errno);
243 printf(
"AF_INET (%s:%d)\n", print_addr, ntohs(sin->sin_port));
249 struct sockaddr_in6 *sin6 = (
struct sockaddr_in6 *) sa;
251 print_addr =
inet_ntop(AF_INET, &sin6->sin6_addr, buf,
sizeof(buf));
253 print_addr = strerror(errno);
254 printf(
"AF_INET6 (%s:%d)\n", print_addr, ntohs(sin6->sin6_port));
261 struct sockaddr_un *sun = (
struct sockaddr_un *) sa;
263 printf(
"AF_UNIX (%s)\n", sun->sun_path);
267 printf(
" [unknown address family]\n");
270 return (test_reply(ctx, test_connect_reply));
273 static sfsistat test_helo(SMFICTX *ctx,
char *arg)
275 printf(
"test_helo \"%s\"\n", arg ? arg :
"NULL");
276 return (test_reply(ctx, test_helo_reply));
279 static sfsistat test_mail(SMFICTX *ctx,
char **argv)
284 for (cpp = argv; *cpp; cpp++)
285 printf(
" \"%s\"", *cpp);
287 return (test_reply(ctx, test_mail_reply));
290 static sfsistat test_rcpt(SMFICTX *ctx,
char **argv)
295 for (cpp = argv; *cpp; cpp++)
296 printf(
" \"%s\"", *cpp);
298 return (test_reply(ctx, test_rcpt_reply));
304 printf(
"test_header \"%s\" \"%s\"\n", name, value);
305 return (test_reply(ctx, test_header_reply));
308 static sfsistat test_eoh(SMFICTX *ctx)
310 printf(
"test_eoh\n");
311 return (test_reply(ctx, test_eoh_reply));
314 static sfsistat test_body(SMFICTX *ctx,
unsigned char *data,
size_t data_len)
317 printf(
"test_body %ld bytes\n", (
long) data_len);
319 printf(
"%.*s", (
int) data_len, data);
320 return (test_reply(ctx, test_body_reply));
323 static sfsistat test_eom(SMFICTX *ctx)
325 printf(
"test_eom\n");
326 #ifdef SMFIR_REPLBODY
328 char buf[BUFSIZ + 2];
333 if ((fp = fopen(body_file,
"r")) == 0) {
336 printf(
"replace body with content of %s\n", body_file);
337 for (count = 0; fgets(buf, BUFSIZ, fp) != 0; count++) {
338 len = strcspn(buf,
"\n");
341 if (smfi_replacebody(ctx, buf, len + 2) == MI_FAILURE) {
342 fprintf(stderr,
"body replace failure\n");
346 printf(
"%.*s\n", (
int) len, buf);
355 if (chg_from != 0 && smfi_chgfrom(ctx, chg_from,
"whatever") == MI_FAILURE)
356 fprintf(stderr,
"smfi_chgfrom failed\n");
358 #ifdef SMFIR_INSHEADER
359 if (ins_hdr && smfi_insheader(ctx, ins_idx, ins_hdr, ins_val) == MI_FAILURE)
360 fprintf(stderr,
"smfi_insheader failed\n");
362 #ifdef SMFIR_CHGHEADER
363 if (chg_hdr && smfi_chgheader(ctx, chg_hdr, chg_idx, chg_val) == MI_FAILURE)
364 fprintf(stderr,
"smfi_chgheader failed\n");
371 if ((args = strchr(
add_rcpt[count],
' ')) != 0) {
373 if (smfi_addrcpt_par(ctx,
add_rcpt[count], args) == MI_FAILURE)
374 fprintf(stderr,
"smfi_addrcpt_par `%s' `%s' failed\n",
377 if (smfi_addrcpt(ctx,
add_rcpt[count]) == MI_FAILURE)
378 fprintf(stderr,
"smfi_addrcpt `%s' failed\n",
384 if (smfi_delrcpt(ctx,
del_rcpt[count]) == MI_FAILURE)
385 fprintf(stderr,
"smfi_delrcpt `%s' failed\n",
del_rcpt[count]);
387 return (test_reply(ctx, test_eom_reply));
390 static sfsistat test_abort(SMFICTX *ctx)
392 printf(
"test_abort\n");
393 return (test_reply(ctx, test_abort_reply));
396 static sfsistat test_close(SMFICTX *ctx)
398 printf(
"test_close\n");
400 printf(
"conn_count %d\n", conn_count);
401 if (conn_count > 0 && --conn_count == 0)
403 return (test_reply(ctx, test_close_reply));
408 static sfsistat test_data(SMFICTX *ctx)
410 printf(
"test_data\n");
411 return (test_reply(ctx, test_data_reply));
418 static sfsistat test_unknown(SMFICTX *ctx,
const char *what)
420 printf(
"test_unknown %s\n", what);
421 return (test_reply(ctx, test_unknown_reply));
428 static sfsistat test_negotiate(SMFICTX *,
unsigned long,
unsigned long,
429 unsigned long,
unsigned long,
430 unsigned long *,
unsigned long *,
431 unsigned long *,
unsigned long *);
435 #ifndef SMFIF_CHGFROM
436 #define SMFIF_CHGFROM 0
438 #ifndef SMFIP_HDR_LEADSPC
439 #define SMFIP_HDR_LEADSPC 0
443 static struct smfiDesc smfilter =
471 static const char *macro_states[] = {
482 static int set_macro_state;
483 static char *set_macro_list;
485 typedef sfsistat (*FILTER_ACTION) ();
492 FILTER_ACTION *action;
495 static const struct noproto_map noproto_map[] = {
508 static int nosend_mask;
509 static int noreply_mask;
512 static sfsistat test_negotiate(SMFICTX *ctx,
522 if (set_macro_list) {
524 printf(
"set symbol list %s to \"%s\"\n",
525 macro_states[set_macro_state], set_macro_list);
526 smfi_setsymlist(ctx, set_macro_state, set_macro_list);
529 printf(
"negotiate f0=%lx *pf0 = %lx f1=%lx *pf1=%lx nosend=%lx noreply=%lx misc=%lx\n",
530 f0, *pf0, f1, *pf1, (
long) nosend_mask, (
long) noreply_mask, (
long) misc_mask);
532 *pf1 = f1 & (nosend_mask | noreply_mask |
misc_mask);
533 return (SMFIS_CONTINUE);
538 static void parse_hdr_info(
const char *optarg,
int *idx,
539 char **hdr,
char **value)
543 len = strlen(optarg) + 1;
544 if ((*hdr = malloc(len)) == 0 || (*value = malloc(len)) == 0) {
545 fprintf(stderr,
"out of memory\n");
549 sscanf(optarg,
"%d %s %[^\n]", idx, *hdr, *value) != 3 :
550 sscanf(optarg,
"%d %[^ ]%[^\n]", idx, *hdr, *value) != 3) {
551 fprintf(stderr,
"bad header info: %s\n", optarg);
556 int main(
int argc,
char **argv)
560 const struct command_map *cp;
564 char *set_macro_state_arg = 0;
567 const struct noproto_map *np;
569 while ((ch = getopt(argc, argv,
"a:A:b:c:C:d:D:f:h:i:lm:M:n:N:p:rv")) > 0) {
576 fprintf(stderr,
"too many -A options\n");
579 add_rcpt[add_rcpt_count++] = optarg;
582 #ifdef SMFIR_REPLBODY
584 fprintf(stderr,
"too many -b options\n");
589 fprintf(stderr,
"no libmilter support to replace body\n");
596 if (smfi_setdbg(atoi(optarg)) == MI_FAILURE) {
597 fprintf(stderr,
"smfi_setdbg failed\n");
603 fprintf(stderr,
"too many -D options\n");
606 del_rcpt[del_rcpt_count++] = optarg;
611 fprintf(stderr,
"too many -f options\n");
616 fprintf(stderr,
"no libmilter support to change sender\n");
621 #ifdef SMFIR_CHGHEADER
623 fprintf(stderr,
"too many -h options\n");
626 parse_hdr_info(optarg, &chg_idx, &chg_hdr, &chg_val);
628 fprintf(stderr,
"no libmilter support to change header\n");
633 #ifdef SMFIR_INSHEADER
635 fprintf(stderr,
"too many -i options\n");
638 parse_hdr_info(optarg, &ins_idx, &ins_hdr, &ins_val);
640 fprintf(stderr,
"no libmilter support to insert header\n");
646 if (ins_hdr || chg_hdr) {
647 fprintf(stderr,
"specify -l before -i or -r\n");
652 fprintf(stderr,
"no libmilter support for leading space\n");
658 if (set_macro_state_arg) {
659 fprintf(stderr,
"too many -m options\n");
662 set_macro_state_arg = optarg;
664 fprintf(stderr,
"no libmilter support to specify macro list\n");
670 if (set_macro_list) {
671 fprintf(stderr,
"too many -M options\n");
674 set_macro_list = optarg;
676 fprintf(stderr,
"no libmilter support to specify macro list\n");
682 fprintf(stderr,
"too many -n options\n");
687 fprintf(stderr,
"no libmilter support for negotiate callback\n");
693 fprintf(stderr,
"too many -n options\n");
698 fprintf(stderr,
"no libmilter support for negotiate callback\n");
702 if (smfi_setconn(optarg) == MI_FAILURE) {
703 fprintf(stderr,
"smfi_setconn failed\n");
708 #ifdef SMFIP_RCPT_REJ
711 fprintf(stderr,
"no libmilter support for rejected recipients\n");
718 conn_count = atoi(optarg);
723 "\t[-a action] non-default action\n"
724 "\t[-b body_text] replace body\n"
725 "\t[-c command] non-default action trigger\n"
726 "\t[-h 'index label value'] replace header\n"
727 "\t[-i 'index label value'] insert header\n"
728 "\t[-m macro_state] non-default macro state\n"
729 "\t[-M macro_list] non-default macro list\n"
730 "\t[-n events] don't receive these events\n"
731 "\t[-N events] don't reply to these events\n"
732 "\t-p port milter application\n"
733 "\t-r request rejected recipients\n"
734 "\t[-C conn_count] when to exit\n",
740 for (cp = command_map; ; cp++) {
742 fprintf(stderr,
"bad -c argument: %s\n", command);
745 if (strcmp(command, cp->
name) == 0)
752 if (strcmp(action,
"tempfail") == 0) {
753 cp->
reply[0] = SMFIS_TEMPFAIL;
754 }
else if (strcmp(action,
"reject") == 0) {
755 cp->
reply[0] = SMFIS_REJECT;
756 }
else if (strcmp(action,
"accept") == 0) {
757 cp->
reply[0] = SMFIS_ACCEPT;
758 }
else if (strcmp(action,
"discard") == 0) {
759 cp->
reply[0] = SMFIS_DISCARD;
761 }
else if (strcmp(action,
"skip") == 0) {
762 cp->
reply[0] = SMFIS_SKIP;
764 }
else if ((code = atoi(action)) >= 400
766 && action[3] ==
' ') {
769 reply_dsn = action + 3;
770 if (*reply_dsn != 0) {
772 reply_dsn += strspn(reply_dsn,
" ");
774 if (*reply_dsn == 0) {
775 reply_dsn = reply_message = 0;
777 reply_message = reply_dsn + strcspn(reply_dsn,
" ");
778 if (*reply_message != 0) {
779 *reply_message++ = 0;
780 reply_message += strspn(reply_message,
" ");
782 if (*reply_message == 0)
786 fprintf(stderr,
"bad -a argument: %s\n", action);
790 printf(
"command %s action %d\n", cp->
name, cp->
reply[0]);
792 printf(
"reply code %s dsn %s message %s\n",
793 reply_code, reply_dsn ? reply_dsn :
"(null)",
794 reply_message ? reply_message :
"(null)");
798 if (set_macro_state_arg) {
799 for (cpp = macro_states; ; cpp++) {
801 fprintf(stderr,
"bad -m argument: %s\n", set_macro_state_arg);
804 if (strcmp(set_macro_state_arg, *cpp) == 0)
807 set_macro_state = cpp - macro_states;
810 for (np = noproto_map; ; np++) {
812 fprintf(stderr,
"bad -n argument: %s\n", nosend);
815 if (strcmp(nosend, np->name) == 0)
818 nosend_mask = np->send_mask;
822 for (np = noproto_map; ; np++) {
824 fprintf(stderr,
"bad -N argument: %s\n", noreply);
827 if (strcmp(noreply, np->name) == 0)
830 noreply_mask = np->reply_mask;
831 *np->reply = SMFIS_NOREPLY;
834 if (smfi_register(smfilter) == MI_FAILURE) {
835 fprintf(stderr,
"smfi_register failed\n");
838 return (smfi_main());
sfsistat test_header(SMFICTX *ctx, char *name, char *value)
int main(int argc, char **argv)
char * del_rcpt[MAX_RCPT]
char * add_rcpt[MAX_RCPT]
const char * inet_ntop(int af, const void *src, char *dst, SOCKADDR_SIZE size)
#define SMFIP_HDR_LEADSPC