aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2009-05-07 15:17:34 +0300
committerSergey Poznyakoff <gray@gnu.org.ua>2009-05-07 15:17:34 +0300
commit05a8bb0ca988f41f016420ffc7dde427e423c187 (patch)
treefff58297f073bec8148c2d5468a45d592eab0379
parent9f8f65324491b4186f4fd3c2580a8e0b14a248d9 (diff)
downloadmailfromd-05a8bb0ca988f41f016420ffc7dde427e423c187.tar.gz
mailfromd-05a8bb0ca988f41f016420ffc7dde427e423c187.tar.bz2
Implement v6 negotiation on the server side.
* gacopyz/stagenames.c: New file. * gacopyz/Makefile.am (libgacopyz_a_SOURCES): Add stagenames.c. * gacopyz/gacopyz.c (gacopyz_context_loop): Free req_macros. (gacopyz_addrcpt_par): rename to gacopyz_add_rcpt_par. * gacopyz/gacopyz.h (SM_LM_VRS_MAJOR, SM_LM_VRS_MAJOR) (SM_LM_VRS_PLVL, GACOPYZ_SM_MKVER): New macros. (macro_index): Rename to gacopyz_stage. All uses updated. (smfi_version): New proto. (gacopyz_addrcpt_par): rename to gacopyz_add_rcpt_par. (gacopyz_stage_name): New declaration. (gacopyz_srv_get_required_macros): New proto. (gacopyz_srv_set_version, gacopyz_srv_set_protocol) (gacopyz_srv_set_actions): 2nd argument is unsigned long. * gacopyz/server.c (struct gacopyz_srv): New member req_macros. (gacopyz_srv_get_required_macros): New function. (gacopyz_srv_destroy): Free req_macros. (gacopyz_srv_negotiate): Read macros. * mfd/gram.y (milter_state_name): Removed. Use gacopyz_stage_name instead. * mtasim/mtasim.c: New options: --gacopyz-log, --milter-proto, --milter-acts. * doc/mtasim.texi, doc/mailfromd.texi: Update.
-rw-r--r--doc/mailfromd.texi8
-rw-r--r--doc/mtasim.texi33
-rw-r--r--gacopyz/Makefile.am1
-rw-r--r--gacopyz/context.c4
-rw-r--r--gacopyz/gacopyz.c71
-rw-r--r--gacopyz/gacopyz.h58
-rw-r--r--gacopyz/gacopyz_priv.h4
-rw-r--r--gacopyz/server.c121
-rw-r--r--gacopyz/smfi.c17
-rw-r--r--gacopyz/stagenames.c27
-rw-r--r--mfd/engine.c4
-rw-r--r--mfd/gram.y44
-rw-r--r--mfd/mailfromd.h2
-rw-r--r--mtasim/mtasim.c111
14 files changed, 383 insertions, 122 deletions
diff --git a/doc/mailfromd.texi b/doc/mailfromd.texi
index 3f8f893b..fd270c1a 100644
--- a/doc/mailfromd.texi
+++ b/doc/mailfromd.texi
@@ -12295,6 +12295,7 @@ Overrides @code{#pragma option stack-trace}, which you are advised to
use instead (@pxref{pragma stack-trace}). @xref{tracing runtime
errors}, for more information on this feature.
+@anchor{gacopyz-log option}
@opsummary{gacopyz-log}
@item --gacopyz-log=@var{level}
Set desired logging level for @command{gacopyz} library
@@ -12326,7 +12327,10 @@ Apr 28 09:00:11 host mailfromd[9411]: finishing
This level can be useful for debugging your scripts.
@item debug
-Log debugging information. This level prints huge amounts of
+Log debugging information.
+
+@item proto
+Log Milter protocol interactions. This level prints huge amounts of
information, in particular it displays dumps of each Milter packet
sent and received.
@@ -12339,7 +12343,7 @@ other, it is seldom practical. Therefore, the option
log levels @samp{warn}, @samp{err} and @samp{fatal}. It is the
default. If you need to trace each subprocess startup and shutdown,
set @option{--gacopyz-log=info}. Setting the logging level to
-@samp{debug} can be needed only for @command{Gacopyz} developers, to
+@samp{proto} can be needed only for @command{Gacopyz} developers, to
debug the protocol.
@xref{Testing Filter Scripts}.
diff --git a/doc/mtasim.texi b/doc/mtasim.texi
index a8849fea..513d045d 100644
--- a/doc/mtasim.texi
+++ b/doc/mtasim.texi
@@ -454,6 +454,14 @@ cases.
Define Sendmail macro @var{macro} to the given @var{value}. It is
similar to the @code{\D} administrative command (@pxref{D command})
+@mtasimopt{gacopyz-log, summary}
+@item --gacopyz-log=@var{level}
+Set desired logging level for @command{gacopyz} library
+(@pxref{Gacopyz}). @xref{gacopyz-log option}, for a detailed
+description of @var{level}. Notice, that unless this option is used,
+the @option{--verbose} (@option{-v}) command line option implies
+@option{--gacopyz-log=debug}.
+
@mtasimopt{group, summary}
@mtindex g, -g, @command{mtasim} option, summary
@item --group=@var{name}
@@ -476,11 +484,29 @@ privileges.
Display a short help summary
@mtasimopt{milter-version, summary}
-@item --milter-version=@var{number}
- Force using the given Milter protocol version number. This option
+@item --milter-version=@var{version}
+ Force using the given Milter protocol version number. The
+@var{version} argument is either a numeric version (e.g. @samp{2}), or
+a version string in form @samp{@var{major}.@var{minor}[.@var{patch}]},
+where square brackets indicate optional part. The default is
+@samp{1.0.0}. If @var{version} is any of @samp{2}, @samp{3} or
+@samp{1.0.0}, the default protocol capabilities and actions for that
+version are set automatically. This option
is intended for development and testing of the Gacopyz library
(@pxref{Gacopyz}).
+@mtasimopt{milter-proto, summary}
+@item --milter-proto=@var{bitmask}
+Set Milter protocol capabilities. See @file{gacopyz/gacopyz.h} for
+the meaning of various bits in the @var{bitmask}. Look for the C
+macros with the prefix @samp{SMFIP_}.
+
+@mtasimopt{milter-actions, summary}
+@item --milter-actions=@var{bitmask}
+Set Milter actions. See @file{gacopyz/gacopyz.h} for
+the meaning of various bits in the @var{bitmask}. Look for the C
+macros with the prefix @samp{SMFIF_}.
+
@mtasimopt{no-interactive, summary}
@item --no-interactive
Not-interactive mode (disable readline). @xref{Command Line Editing, ,
@@ -520,7 +546,8 @@ is the default mode for @command{mtasim}. @xref{interactive mode}.
@mtindex v, -v, @command{mtasim} option, summary
@item --verbose
@itemx -v
- Increase verbosity level.
+ Increase verbosity level. Implies @option{--gacopyz-log=debug},
+unless that option is used explicitly.
@item --version
@itemx -V
diff --git a/gacopyz/Makefile.am b/gacopyz/Makefile.am
index 7d8c012b..d658b3e7 100644
--- a/gacopyz/Makefile.am
+++ b/gacopyz/Makefile.am
@@ -27,6 +27,7 @@ libgacopyz_a_SOURCES = \
mfapi.h\
proc.c\
server.c\
+ stagenames.c\
trans.h
EXTRA_DIST=trans.tab trans.awk
diff --git a/gacopyz/context.c b/gacopyz/context.c
index 41d64c44..12094fdf 100644
--- a/gacopyz/context.c
+++ b/gacopyz/context.c
@@ -1,5 +1,5 @@
/* This file is part of gacopyz.
- Copyright (C) 2006, 2007 Sergey Poznyakoff
+ Copyright (C) 2006, 2007, 2009 Sergey Poznyakoff
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -50,7 +50,7 @@ gacopyz_getsymval(SMFICTX *ctx, const char *name)
if (name[len-1] == '}')
len--;
- for (i = maci_max - 1; i >= 0; i--) {
+ for (i = gacopyz_stage_max - 1; i >= 0; i--) {
if (ctx->macros[i].argv) {
char **p;
diff --git a/gacopyz/gacopyz.c b/gacopyz/gacopyz.c
index f29681be..e26f7e2e 100644
--- a/gacopyz/gacopyz.c
+++ b/gacopyz/gacopyz.c
@@ -764,7 +764,7 @@ make_optneg_buf(SMFICTX *ctx, gacopyz_uint32_t *vbuf,
size_t bufsize = 0;
int i;
- for (i = 0; i < maci_max; i++) {
+ for (i = 0; i < gacopyz_stage_max; i++) {
if (ctx->req_macros[i])
bufsize += strlen(ctx->req_macros[i]) + 1 +
sizeof(gacopyz_uint32_t);
@@ -789,7 +789,7 @@ make_optneg_buf(SMFICTX *ctx, gacopyz_uint32_t *vbuf,
*pbuf = buf;
buf += OPTLEN;
- for (i = 0; i < maci_max; i++) {
+ for (i = 0; i < gacopyz_stage_max; i++) {
if (ctx->req_macros[i]) {
gacopyz_uint32_t v;
size_t len;
@@ -901,7 +901,7 @@ macro_assoc_free(macro_assoc_t *p)
static void
clear_macros(SMFICTX *ctx, int i)
{
- for (; i < maci_max; i++)
+ for (; i < gacopyz_stage_max; i++)
macro_assoc_free(&ctx->macros[i]);
}
@@ -962,7 +962,7 @@ shan_abort(SMFICTX *ctx, union state_arg *arg, unsigned char *cmd)
static state_ret_type
shan_macro(SMFICTX *ctx, union state_arg *arg, unsigned char *cmd)
{
- enum macro_index ind;
+ enum gacopyz_stage ind;
char **p;
if (!arg->argv.v)
@@ -970,31 +970,31 @@ shan_macro(SMFICTX *ctx, union state_arg *arg, unsigned char *cmd)
switch (arg->argv.cmd) {
case SMFIC_CONNECT:
- ind = maci_conn;
+ ind = gacopyz_stage_conn;
break;
case SMFIC_HELO:
- ind = maci_helo;
+ ind = gacopyz_stage_helo;
break;
case SMFIC_MAIL:
- ind = maci_mail;
+ ind = gacopyz_stage_mail;
break;
case SMFIC_RCPT:
- ind = maci_rcpt;
+ ind = gacopyz_stage_rcpt;
break;
case SMFIC_DATA:
- ind = maci_data;
+ ind = gacopyz_stage_data;
break;
case SMFIC_BODYEOB:
- ind = maci_eom;
+ ind = gacopyz_stage_eom;
break;
case SMFIC_EOH:
- ind = maci_eoh;
+ ind = gacopyz_stage_eoh;
break;
default:
@@ -1346,33 +1346,33 @@ shan_unkn(SMFICTX *ctx, union state_arg *arg, unsigned char *cmd)
static struct state_disp disp[] = {
{ SMFIC_ABORT, "abort",
- arg_no_args, shan_abort, st_abrt, CT_CNT, maci_none },
+ arg_no_args, shan_abort, st_abrt, CT_CNT, gacopyz_stage_none },
{ SMFIC_MACRO, "macro",
- arg_argvc, shan_macro, st_none, CT_CNT, maci_none },
+ arg_argvc, shan_macro, st_none, CT_CNT, gacopyz_stage_none },
{ SMFIC_BODY, "body",
- arg_one_string, shan_body, st_body, CT_CNT, maci_none },
+ arg_one_string, shan_body, st_body, CT_CNT, gacopyz_stage_none },
{ SMFIC_CONNECT, "connect",
- arg_two_strings, shan_connect, st_conn, CT_CLR, maci_conn },
+ arg_two_strings, shan_connect, st_conn, CT_CLR, gacopyz_stage_conn },
{ SMFIC_BODYEOB, "endm",
- arg_one_string, shan_endm, st_endm, CT_CNT, maci_eom },
+ arg_one_string, shan_endm, st_endm, CT_CNT, gacopyz_stage_eom },
{ SMFIC_HELO, "helo",
- arg_one_string, shan_helo, st_helo, CT_CLR, maci_helo },
+ arg_one_string, shan_helo, st_helo, CT_CLR, gacopyz_stage_helo },
{ SMFIC_HEADER, "header",
- arg_two_strings, shan_header, st_hdrs, CT_CNT, maci_none },
+ arg_two_strings, shan_header, st_hdrs, CT_CNT, gacopyz_stage_none },
{ SMFIC_MAIL, "mail",
- arg_argv, shan_mail, st_mail, CT_CLR, maci_mail },
+ arg_argv, shan_mail, st_mail, CT_CLR, gacopyz_stage_mail },
{ SMFIC_OPTNEG, "optneg",
- arg_ints, shan_optneg, st_opts, CT_CNT, maci_none },
+ arg_ints, shan_optneg, st_opts, CT_CNT, gacopyz_stage_none },
{ SMFIC_EOH, "eoh",
- arg_no_args, shan_eoh, st_eohs, CT_CNT, maci_none },
+ arg_no_args, shan_eoh, st_eohs, CT_CNT, gacopyz_stage_none },
{ SMFIC_QUIT, "quit",
- arg_no_args, shan_quit, st_quit, CT_END, maci_none },
+ arg_no_args, shan_quit, st_quit, CT_END, gacopyz_stage_none },
{ SMFIC_DATA, "data",
- arg_no_args, shan_data, st_data, CT_CNT, maci_none },
+ arg_no_args, shan_data, st_data, CT_CNT, gacopyz_stage_none },
{ SMFIC_RCPT, "rcpt",
- arg_argv, shan_rcpt, st_rcpt, CT_IGN|CT_CLR, maci_rcpt },
+ arg_argv, shan_rcpt, st_rcpt, CT_IGN|CT_CLR, gacopyz_stage_rcpt },
{ SMFIC_UNKNOWN, "unknown",
- arg_one_string, shan_unkn, st_unkn, CT_IGN|CT_CLR, maci_none }
+ arg_one_string, shan_unkn, st_unkn, CT_IGN|CT_CLR, gacopyz_stage_none }
};
struct state_disp *
@@ -1488,6 +1488,17 @@ report_command(enum state state, enum state next_state,
gacopyz_logdump(SMI_LOG_WARN, _("buffer"), buffer, size);
}
+static int
+ctx_free(SMFICTX *ctx)
+{
+ int i;
+
+ free(ctx->reply);
+ clear_macros(&ctx, 0);
+ for (i = 0; i < gacopyz_stage_max; i++)
+ free(ctx->req_macros[i]);
+}
+
int
gacopyz_context_loop(int fd, struct smfiDesc *desc)
{
@@ -1648,9 +1659,9 @@ gacopyz_context_loop(int fd, struct smfiDesc *desc)
free(buffer);
if (desc->xxfi_close)
desc->xxfi_close(&ctx);
- free(ctx.reply);
- clear_macros(&ctx, 0);
+ ctx_free(&ctx);
+
if (desc->xxfi_finish)
desc->xxfi_finish();
@@ -2026,7 +2037,7 @@ gacopyz_quarantine(SMFICTX *ctx, const char *reason)
}
int
-gacopyz_addrcpt_par(SMFICTX *ctx, const char *rcpt, const char *args)
+gacopyz_add_rcpt_par(SMFICTX *ctx, const char *rcpt, const char *args)
{
if (!rcpt || !*rcpt)
return MI_FAILURE;
@@ -2046,9 +2057,9 @@ gacopyz_chgfrom(SMFICTX *ctx, const char *from, const char *args)
}
int
-gacopyz_setsymlist(SMFICTX *ctx, enum macro_index ind, const char *macros)
+gacopyz_setsymlist(SMFICTX *ctx, enum gacopyz_stage ind, const char *macros)
{
- if (ind < 0 || ind >= maci_max)
+ if (ind < 0 || ind >= gacopyz_stage_max)
return MI_FAILURE;
if (ctx->req_macros[ind])
free(ctx->req_macros[ind]);
diff --git a/gacopyz/gacopyz.h b/gacopyz/gacopyz.h
index f0b5bff2..f7d547a7 100644
--- a/gacopyz/gacopyz.h
+++ b/gacopyz/gacopyz.h
@@ -48,6 +48,13 @@ extern "C" {
/* Implementation version number */
#define SMFI_VERSION 0x01000000
+#define SM_LM_VRS_MAJOR(v) (((v) & 0x7f000000) >> 24)
+#define SM_LM_VRS_MINOR(v) (((v) & 0x007fff00) >> 8)
+#define SM_LM_VRS_PLVL(v) ((v) & 0x0000007f)
+
+#define GACOPYZ_SM_MKVER(maj,min,pat) \
+ ((((maj) & 0x7f)<<24) | (((min) & 0x7ffff) << 8) | ((pat) & 0x7f))
+
/* Milter protocol version */
#define SMFI_PROT_VERSION 6
@@ -199,26 +206,26 @@ typedef union {
struct sockaddr_un sunix;
} milter_sockaddr_t;
-enum macro_index {
- maci_conn,
- maci_helo,
- maci_mail,
- maci_rcpt,
- maci_data,
- maci_eom,
- maci_eoh,
+enum gacopyz_stage {
+ gacopyz_stage_conn,
+ gacopyz_stage_helo,
+ gacopyz_stage_mail,
+ gacopyz_stage_rcpt,
+ gacopyz_stage_data,
+ gacopyz_stage_eom,
+ gacopyz_stage_eoh,
- maci_max,
- maci_none = maci_max
+ gacopyz_stage_max,
+ gacopyz_stage_none = gacopyz_stage_max
};
-#define SMFIM_CONNECT maci_conn
-#define SMFIM_HELO maci_helo
-#define SMFIM_ENVFROM maci_mail
-#define SMFIM_ENVRCPT maci_rcpt
-#define SMFIM_DATA maci_data
-#define SMFIM_EOM maci_eom
-#define SMFIM_EOH maci_eoh
+#define SMFIM_CONNECT gacopyz_stage_conn
+#define SMFIM_HELO gacopyz_stage_helo
+#define SMFIM_ENVFROM gacopyz_stage_mail
+#define SMFIM_ENVRCPT gacopyz_stage_rcpt
+#define SMFIM_DATA gacopyz_stage_data
+#define SMFIM_EOM gacopyz_stage_eom
+#define SMFIM_EOH gacopyz_stage_eoh
#define _SOCK_ADDR milter_sockaddr_t
#define smfiDesc gacopyz_milter_descr
@@ -275,6 +282,7 @@ struct gacopyz_milter_descr
};
/* Standard API calls */
+extern int smfi_version (unsigned int *, unsigned int *, unsigned int *);
extern int smfi_opensocket (int);
extern int smfi_register (struct smfiDesc);
extern int smfi_main (void);
@@ -365,15 +373,17 @@ int gacopyz_replace_body(SMFICTX *ctx, const unsigned char *bodyp,
size_t bodylen);
int gacopyz_progress(SMFICTX *ctx);
int gacopyz_quarantine(SMFICTX *ctx, const char *reason);
-int gacopyz_addrcpt_par(SMFICTX *ctx, const char *rcpt, const char *args);
+int gacopyz_add_rcpt_par(SMFICTX *ctx, const char *rcpt, const char *args);
int gacopyz_chgfrom(SMFICTX *ctx, const char *from, const char *args);
-int gacopyz_setsymlist(SMFICTX *ctx, enum macro_index ind, const char *macros);
+int gacopyz_setsymlist(SMFICTX *ctx, enum gacopyz_stage ind, const char *macros);
int gacopyz_setpriv (SMFICTX *ctx, void *data);
void *gacopyz_getpriv (SMFICTX *ctx);
/* Logging (extensions) */
+extern const char *gacopyz_stage_name[gacopyz_stage_max];
+
#define GACOPYZ_VBUFSIZE 69
size_t gacopyz_format_vbuf(char vbuf[GACOPYZ_VBUFSIZE], const char *buf,
size_t size);
@@ -411,6 +421,10 @@ void gacopyz_srv_iterate_macros (gacopyz_srv_t srv,
void *data),
void *data);
void gacopyz_srv_count_macros (gacopyz_srv_t srv, size_t *count);
+
+const char **gacopyz_srv_get_required_macros(gacopyz_srv_t srv,
+ enum gacopyz_stage stage);
+
int gacopyz_srv_connect (gacopyz_srv_t srv);
int gacopyz_srv_init(gacopyz_srv_t srv);
int gacopyz_srv_negotiate(gacopyz_srv_t srv);
@@ -440,9 +454,9 @@ void gacopyz_srv_set_callback(gacopyz_srv_t srv,
void gacopyz_srv_set_callback_data(gacopyz_srv_t, void *);
int gacopyz_srv_set_source(gacopyz_srv_t srv, unsigned long addr);
-int gacopyz_srv_set_version(gacopyz_srv_t srv, int version);
-int gacopyz_srv_set_protocol(gacopyz_srv_t srv, int proto);
-int gacopyz_srv_set_actions(gacopyz_srv_t srv, int acts);
+int gacopyz_srv_set_version(gacopyz_srv_t srv, unsigned long version);
+int gacopyz_srv_set_protocol(gacopyz_srv_t srv, unsigned long proto);
+int gacopyz_srv_set_actions(gacopyz_srv_t srv, unsigned long acts);
#define GACOPYZ_WRITE_TIMEOUT 10
#define GACOPYZ_READ_TIMEOUT 10
diff --git a/gacopyz/gacopyz_priv.h b/gacopyz/gacopyz_priv.h
index 76be1611..d7e1ffe9 100644
--- a/gacopyz/gacopyz_priv.h
+++ b/gacopyz/gacopyz_priv.h
@@ -34,8 +34,8 @@ struct smfi_str {
unsigned long mta_pflags; /* pflags supported by MTA */
unsigned long aflags; /* milter action flags (from xxfi_flags) */
int nmacros; /* Number of entries in macros */
- macro_assoc_t macros[maci_max]; /* Macro tables */
- char *req_macros[maci_max]; /* Required macros */
+ macro_assoc_t macros[gacopyz_stage_max]; /* Macro tables */
+ char *req_macros[gacopyz_stage_max]; /* Required macros */
char *reply; /* reply code */
void *privdata; /* private data */
};
diff --git a/gacopyz/server.c b/gacopyz/server.c
index a61836e8..e7cfa643 100644
--- a/gacopyz/server.c
+++ b/gacopyz/server.c
@@ -1,5 +1,5 @@
/* This file is part of gacopyz.
- Copyright (C) 2007, 2008 Sergey Poznyakoff
+ Copyright (C) 2007, 2008, 2009 Sergey Poznyakoff
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -49,6 +49,7 @@ struct gacopyz_srv {
unsigned long version;
unsigned long acts;
unsigned long proto;
+ char **req_macros[gacopyz_stage_max]; /* Required macros */
int (*cb_reply) (gacopyz_srv_t srv, int cmd, int rcmd, void *data);
void *cb_data;
@@ -279,6 +280,13 @@ gacopyz_srv_count_macros(gacopyz_srv_t srv, size_t *count)
}
+const char **
+gacopyz_srv_get_required_macros(gacopyz_srv_t srv, enum gacopyz_stage stage)
+{
+ return (const char **) srv->req_macros[stage];
+}
+
+
struct timeval default_gacopyz_timeout[GACOPYZ_TO_COUNT] = {
{ GACOPYZ_WRITE_TIMEOUT, 0 },
@@ -612,7 +620,7 @@ gacopyz_srv_set_source(gacopyz_srv_t srv, unsigned long addr)
}
int
-gacopyz_srv_set_version(gacopyz_srv_t srv, int version)
+gacopyz_srv_set_version(gacopyz_srv_t srv, unsigned long version)
{
GACOPYZ_ASSERT(srv);
@@ -621,7 +629,7 @@ gacopyz_srv_set_version(gacopyz_srv_t srv, int version)
}
int
-gacopyz_srv_set_protocol(gacopyz_srv_t srv, int proto)
+gacopyz_srv_set_protocol(gacopyz_srv_t srv, unsigned long proto)
{
GACOPYZ_ASSERT(srv);
@@ -630,7 +638,7 @@ gacopyz_srv_set_protocol(gacopyz_srv_t srv, int proto)
}
int
-gacopyz_srv_set_actions(gacopyz_srv_t srv, int acts)
+gacopyz_srv_set_actions(gacopyz_srv_t srv, unsigned long acts)
{
GACOPYZ_ASSERT(srv);
@@ -638,15 +646,24 @@ gacopyz_srv_set_actions(gacopyz_srv_t srv, int acts)
return MI_SUCCESS;
}
-
void
gacopyz_srv_destroy(gacopyz_srv_t *p)
{
+ int i;
+
gacopyz_srv_t srv = *p;
gacopyz_srv_clear_macros(srv);
free(srv->portspec);
free(srv->id);
free(srv->def);
+ for (i = 0; i < gacopyz_stage_max; i++)
+ if (srv->req_macros[i]) {
+ int j;
+
+ for (j = 0; srv->req_macros[i][j]; j++)
+ free(srv->req_macros[i][j]);
+ free(srv->req_macros[i]);
+ }
free(srv->buf);
free(srv);
*p = 0;
@@ -860,6 +877,94 @@ gacopyz_srv_connect(gacopyz_srv_t srv)
return MI_SUCCESS;
}
+#define ISWS(c) ((c) == ' ' || (c) == '\t')
+
+static void
+parse_macros(gacopyz_srv_t srv, enum gacopyz_stage stage, char *buf)
+{
+ char *p;
+ char **argv;
+ size_t count;
+
+ count = 0;
+ for (p = buf; *p;) {
+ while (*p && ISWS(*p))
+ p++;
+ if (*p) {
+ count++;
+ while (*p && !ISWS(*p))
+ p++;
+ }
+ }
+ if (count == 0)
+ return;
+ GACOPYZ_ALLOC(srv, argv = calloc(count + 1, sizeof(argv[0])));
+ count = 0;
+ for (p = buf; *p;) {
+ while (*p && ISWS(*p))
+ p++;
+ if (*p) {
+ size_t i;
+ char *str = p;
+
+ for (i = 0; *p && !ISWS(*p); p++, i++)
+ ;
+ if (i > 0) {
+ char *newstr;
+
+ if (*str == '{' && str[i-1] == '}') {
+ str++;
+ i -= 2;
+ }
+ GACOPYZ_ALLOC(srv, newstr = malloc(i + 1));
+ memcpy(newstr, str, i);
+ newstr[i] = 0;
+ argv[count++] = newstr;
+ }
+ }
+ }
+ argv[count] = NULL;
+ srv->req_macros[stage] = argv;
+}
+
+
+static void
+read_macros(gacopyz_srv_t srv)
+{
+ char *buf = srv->buf + 3 * sizeof(gacopyz_uint32_t);
+ size_t size = srv->bufsize - 3 * sizeof(gacopyz_uint32_t);
+
+ while (size > sizeof(gacopyz_uint32_t)) {
+ gacopyz_uint32_t v;
+ unsigned n;
+ size_t len;
+
+ memcpy (&v, buf, sizeof(gacopyz_uint32_t));
+ n = ntohl(v);
+ if (n >= gacopyz_stage_max) {
+ gacopyz_io_log(&srv->iod, SMI_LOG_ERR,
+ _("received invalid stage number"));
+ break;
+ }
+ buf += sizeof(gacopyz_uint32_t);
+ size -= sizeof(gacopyz_uint32_t);
+ if (size == 0)
+ break;
+ len = strlen(buf) + 1;
+ if (len > size) {
+ gacopyz_io_log(&srv->iod, SMI_LOG_ERR,
+ _("invalid macro list"));
+ break;
+ }
+ gacopyz_io_log(&srv->iod, SMI_LOG_DEBUG,
+ _("macros for stage \"%s\" (%d): %s"),
+ gacopyz_stage_name[n], n, buf);
+ parse_macros(srv, n, buf);
+ buf += len;
+ size -= len;
+ }
+}
+
int
gacopyz_srv_negotiate(gacopyz_srv_t srv)
{
@@ -927,6 +1032,10 @@ gacopyz_srv_negotiate(gacopyz_srv_t srv)
return MI_FAILURE;
}
+ if (milter_version > 3
+ && srv->bufsize > 3 * sizeof(gacopyz_uint32_t))
+ read_macros(srv);
+
srv->version = milter_version;
srv->acts = milter_acts;
srv->proto = milter_proto;
@@ -1209,8 +1318,6 @@ gacopyz_srv_conn(gacopyz_srv_t srv, const char *hostname, struct sockaddr *sa)
int
gacopyz_srv_helo(gacopyz_srv_t srv, const char *domain)
{
- int rc;
-
GACOPYZ_ASSERT(srv);
if (srv->state == srv_msgproc)
gacopyz_srv_abort(srv);
diff --git a/gacopyz/smfi.c b/gacopyz/smfi.c
index 721b3460..4f8628d4 100644
--- a/gacopyz/smfi.c
+++ b/gacopyz/smfi.c
@@ -197,7 +197,7 @@ smfi_quarantine(SMFICTX *ctx, char *reason)
int
smfi_addrcpt_par(SMFICTX *ctx, char *rcpt, char *args)
{
- return gacopyz_addrcpt_par(ctx, rcpt, args);
+ return gacopyz_add_rcpt_par(ctx, rcpt, args);
}
int
@@ -209,12 +209,23 @@ smfi_chgfrom(SMFICTX *ctx, char *from, char *args)
int
smfi_setsymlist(SMFICTX *ctx, int n, char *macros)
{
- if (n < 0 || n >= maci_max)
+ if (n < 0 || n >= gacopyz_stage_max)
return MI_FAILURE;
if (!macros || !*macros || ctx->req_macros[n])
return MI_FAILURE;
return gacopyz_setsymlist(ctx, n, macros);
}
-
+int
+smfi_version(unsigned int *maj, unsigned int *min, unsigned int *pat)
+{
+ if (maj)
+ *maj = SM_LM_VRS_MAJOR(SMFI_VERSION);
+ if (min)
+ *min = SM_LM_VRS_MINOR(SMFI_VERSION);
+ if (pat)
+ *pat = SM_LM_VRS_MINOR(SMFI_VERSION);
+ return MI_SUCCESS;
+}
+
diff --git a/gacopyz/stagenames.c b/gacopyz/stagenames.c
new file mode 100644
index 00000000..0be67617
--- /dev/null
+++ b/gacopyz/stagenames.c
@@ -0,0 +1,27 @@
+/* This file is part of gacopyz.
+ Copyright (C) 2009 Sergey Poznyakoff
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <gacopyz_priv.h>
+
+const char *gacopyz_stage_name[gacopyz_stage_max] = {
+ "connect",
+ "helo",
+ "envfrom",
+ "envrcpt",
+ "data",
+ "eom",
+ "eoh"
+};
diff --git a/mfd/engine.c b/mfd/engine.c
index 2ddfd5f9..a9b42b29 100644
--- a/mfd/engine.c
+++ b/mfd/engine.c
@@ -1358,13 +1358,13 @@ mlfi_negotiate(SMFICTX *ctx,
unsigned long *unused4,
unsigned long *unused5)
{
- enum macro_index i;
+ enum gacopyz_stage i;
debug4(70, "Negotiate: mta_actions=%#lx, mta_capa=%#lx, "
"filter_actions=%#lx, filter_capa=%#lx",
mta_actions, mta_capa, *filter_actions, *filter_capa);
- for (i = 0; i < maci_max; i++) {
+ for (i = 0; i < gacopyz_stage_max; i++) {
char *str = get_stage_macro_string(i);
gacopyz_setsymlist(ctx, i, str);
free(str);
diff --git a/mfd/gram.y b/mfd/gram.y
index 0b278972..15a7f069 100644
--- a/mfd/gram.y
+++ b/mfd/gram.y
@@ -2412,49 +2412,39 @@ print_xref()
}
-static mu_list_t smtp_macro_list[maci_max];
+static mu_list_t smtp_macro_list[gacopyz_stage_max];
-static enum macro_index
-smtp_to_milter_state(enum smtp_state tag)
+static enum gacopyz_stage
+smtp_to_gacopyz_stage(enum smtp_state tag)
{
switch (tag) {
case smtp_state_connect:
- return maci_conn;
+ return gacopyz_stage_conn;
case smtp_state_helo:
- return maci_helo;
+ return gacopyz_stage_helo;
case smtp_state_envfrom:
- return maci_mail;
+ return gacopyz_stage_mail;
case smtp_state_envrcpt:
- return maci_rcpt;
+ return gacopyz_stage_rcpt;
case smtp_state_data:
case smtp_state_header:
case smtp_state_body:
- return maci_data;
+ return gacopyz_stage_data;
case smtp_state_eoh:
- return maci_eoh;
+ return gacopyz_stage_eoh;
case smtp_state_eom:
- return maci_eom;
+ return gacopyz_stage_eom;
default:
break;
}
- return maci_none;
+ return gacopyz_stage_none;
}
-static const char *milter_state_name[maci_max] = {
- "connect",
- "helo",
- "envfrom",
- "envrcpt",
- "data",
- "eom",
- "eoh"
-};
-
void
register_macro(enum smtp_state state, const char *macro)
{
- enum macro_index ind = smtp_to_milter_state(state);
- if (ind == maci_none)
+ enum gacopyz_stage ind = smtp_to_gacopyz_stage(state);
+ if (ind == gacopyz_stage_none)
return;
if (!smtp_macro_list[ind]) {
mu_list_create(&smtp_macro_list[ind]);
@@ -2481,12 +2471,12 @@ print_macro(void *item, void *data)
void
print_used_macros()
{
- enum macro_index i;
+ enum gacopyz_stage i;
- for (i = 0; i < maci_max; i++) {
+ for (i = 0; i < gacopyz_stage_max; i++) {
if (smtp_macro_list[i]) {
int n = 1;
- printf("%s", milter_state_name[i]);
+ printf("%s", gacopyz_stage_name[i]);
mu_list_do(smtp_macro_list[i], print_macro, &n);
printf("\n");
}
@@ -2521,7 +2511,7 @@ concat_macro(void *item, void *data)
}
char *
-get_stage_macro_string(enum macro_index i)
+get_stage_macro_string(enum gacopyz_stage i)
{
struct macro_acc acc;
size_t size;
diff --git a/mfd/mailfromd.h b/mfd/mailfromd.h
index 47360b8d..a45bf346 100644
--- a/mfd/mailfromd.h
+++ b/mfd/mailfromd.h
@@ -732,7 +732,7 @@ char *mf_strdup(const char *str);
void regex_push(void);
void regex_pop(void);
-char *get_stage_macro_string(enum macro_index i);
+char *get_stage_macro_string(enum gacopyz_stage i);
/* Data types and declarations for handling compiled configuration code */
diff --git a/mtasim/mtasim.c b/mtasim/mtasim.c
index 5c79ff7f..f9a85f53 100644
--- a/mtasim/mtasim.c
+++ b/mtasim/mtasim.c
@@ -102,7 +102,10 @@ int define_macro (char *arg);
/* Milter-related options */
char *milter_port;
size_t max_body_chunk = 65535;
-int milter_version_option = 0;
+unsigned long milter_version_option = 0;
+unsigned long milter_proto_option = 0;
+unsigned long milter_acts_option = 0;
+int gacopyz_log_mask;
struct timeval milter_timeouts[GACOPYZ_TO_COUNT] = {
{ GACOPYZ_WRITE_TIMEOUT, 0 },
{ GACOPYZ_READ_TIMEOUT, 0 },
@@ -268,6 +271,7 @@ static char doc[] = N_("mtasim -- MTA simulator for mailfromd");
enum {
OPTION_STDIO = 128,
+ OPTION_GACOPYZ_LOG,
OPTION_DAEMON,
OPTION_TLS_CERT,
OPTION_TLS_CA,
@@ -275,6 +279,8 @@ enum {
OPTION_TRACE_FILE,
OPTION_BODY_CHUNK,
OPTION_MILTER_VERSION,
+ OPTION_MILTER_PROTO,
+ OPTION_MILTER_ACTS,
OPTION_NO_INTERACTIVE,
OPTION_PROMPT,
OPTION_STATEDIR
@@ -322,8 +328,12 @@ static struct argp_option options[] = {
{ "body-chunk", OPTION_BODY_CHUNK, N_("NUMBER"), 0,
N_("Set the body chunk for xxfi_body calls"),
GRP+1 },
- { "milter-version", OPTION_MILTER_VERSION, N_("NUMBER"), 0,
+ { "milter-version", OPTION_MILTER_VERSION, N_("VER"), 0,
N_("Force using the given Milter protocol version number"), GRP+1 },
+ { "milter-actions", OPTION_MILTER_ACTS, N_("BITMASK"), 0,
+ N_("Force the given Milter actions"), GRP+1 },
+ { "milter-proto", OPTION_MILTER_PROTO, N_("BITMASK"), 0,
+ N_("Set Milter protocol capabilities"), GRP+1 },
#undef GRP
#define GRP 20
@@ -343,6 +353,8 @@ static struct argp_option options[] = {
{ "verbose", 'v', NULL, 0,
N_("Increase verbosity level"),
GRP+1 },
+ { "gacopyz-log", OPTION_GACOPYZ_LOG, N_("LEVEL"), 0,
+ N_("Set Gacopyz log level"), GRP+1 },
#undef GRP
#define GRP 40
@@ -369,6 +381,31 @@ char *trace_name = NULL;
int append;
int statedir_option;
+static unsigned long
+parse_version (char *arg, struct argp_state *state)
+{
+ char *p;
+ unsigned long maj, min, pat;
+
+ maj = strtoul (arg, &p, 0);
+ if (*p == 0)
+ return maj;
+ else if (*p == '.')
+ {
+ min = strtoul (p + 1, &p, 0);
+ if (*p == '.')
+ {
+ pat = strtoul (p + 1, &p, 0);
+ if (*p == 0)
+ return GACOPYZ_SM_MKVER (maj, min, pat);
+ }
+ else if (*p == 0)
+ return GACOPYZ_SM_MKVER (maj, min, 0);
+ }
+ argp_error (state, _("invalid version syntax (near %s)"), p);
+ return 0;
+}
+
static error_t
parse_opt (int key, char *arg, struct argp_state *state)
{
@@ -392,11 +429,19 @@ parse_opt (int key, char *arg, struct argp_state *state)
break;
default:
- mu_error (_("unsupported mode"));
- exit (EX_USAGE);