diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2008-01-12 15:07:46 +0000 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2008-01-12 15:07:46 +0000 |
commit | b23b5cad0cff93314190431693106e3f29ba29da (patch) | |
tree | 980f694f3105a81f4985cee3c675338f2fb8a9eb | |
parent | f3fe35899c9749e4eb8000ccebb8e1348def28d6 (diff) | |
download | mailfromd-b23b5cad0cff93314190431693106e3f29ba29da.tar.gz mailfromd-b23b5cad0cff93314190431693106e3f29ba29da.tar.bz2 |
* src/prog.c (instr_header): Improve trace output.
* pmult/pmult.c: Implement recipient and header modifications.
* configure.ac: Link libmta/libcstrr.a (for pmult).
* TODO: Update.
* gacopyz/server.c (gacopyz_srv_send_command): Do not bail out on
message modification responses.
* gacopyz/gacopyz.c (gacopyz_header_command): Improve trace output.
git-svn-id: file:///svnroot/mailfromd/branches/gmach@1557 7a8a7f39-df28-0410-adc6-e0d955640f24
-rw-r--r-- | ChangeLog | 11 | ||||
-rw-r--r-- | TODO | 2 | ||||
-rw-r--r-- | configure.ac | 1 | ||||
-rw-r--r-- | gacopyz/gacopyz.c | 2 | ||||
-rw-r--r-- | gacopyz/server.c | 13 | ||||
-rw-r--r-- | pmult/pmult.c | 306 | ||||
-rw-r--r-- | src/prog.c | 2 |
7 files changed, 323 insertions, 14 deletions
@@ -1,8 +1,17 @@ 2008-01-12 Sergey Poznyakoff <gray@gnu.org.ua> + * src/prog.c (instr_header): Improve trace output. + * pmult/pmult.c: Implement recipient and header modifications. + * configure.ac: Link libmta/libcstrr.a (for pmult). + * TODO: Update. + + * gacopyz/server.c (gacopyz_srv_send_command): Do not bail out on + message modification responses. + * gacopyz/gacopyz.c (gacopyz_header_command): Improve trace output. + * src/gram.y (DELETE string): Initialize hdr.value. * src/drivers.c (code_type_header): Value can be NULL. - + * pmult/pmult.c: Implement most of the SMTP functionality. * src/mailfromd.h, lib/libmf.h (dict_init, dict_install) @@ -2,6 +2,8 @@ Mailfromd TODO list. * Language: +** Clarify the `delete' semantics. + ** Implement \U, \L, \E and other GNU extensions to the replacement strings. ** Various items by Jan (ref <Pine.LNX.4.58.0610112345080.2162@cedric.unob.cz>) diff --git a/configure.ac b/configure.ac index 25a9cb66..f0c3da18 100644 --- a/configure.ac +++ b/configure.ac @@ -549,6 +549,7 @@ if test "$enable_pmilter" = yes; then libmta/librcbcomm.a\ libmta/librcb.a\ libmta/libmtar.a\ + libmta/libcstrr.a\ libcheck/libcheck.a\ librepl/libreplr.a" diff --git a/gacopyz/gacopyz.c b/gacopyz/gacopyz.c index f20a506f..4e28161b 100644 --- a/gacopyz/gacopyz.c +++ b/gacopyz/gacopyz.c @@ -1587,7 +1587,7 @@ gacopyz_header_command(SMFICTX *ctx, unsigned char cmd, memcpy(cptr, headerv, lenv); cptr += lenv; - TRACE(ctx, cmd, bufsize, buf); + TRACE(ctx, cmd, sizeof hptr->buf + bufsize, buf); hptr->hdr.cmd = cmd; hptr->hdr.size = htonl(bufsize + 1); diff --git a/gacopyz/server.c b/gacopyz/server.c index 36868b7f..554b3398 100644 --- a/gacopyz/server.c +++ b/gacopyz/server.c @@ -1031,6 +1031,19 @@ gacopyz_srv_send_command(gacopyz_srv_t srv, unsigned char cmd, srv->state = srv_msgproc; break; + case SMFIR_ADDRCPT: + case SMFIR_DELRCPT: + case SMFIR_REPLBODY: + case SMFIR_CHGHEADER: + case SMFIR_ADDHEADER: + case SMFIR_INSHEADER: + srv->resp_ptr = srv->buf; + srv->resp_size = size; + gacopyz_io_log(&srv->iod, SMI_LOG_DEBUG, + "action=%s, unhandled response=%c", + cp->action, rcmd); + break; + default: gacopyz_io_log(&srv->iod, SMI_LOG_ERR, "action=%s, bogus response=%c", diff --git a/pmult/pmult.c b/pmult/pmult.c index 3f804a54..4b80295c 100644 --- a/pmult/pmult.c +++ b/pmult/pmult.c @@ -85,12 +85,24 @@ struct pmult_client /* List of configured clients: */ mu_list_t /* of struct pmult_client */ client_list; +enum pmult_msg_state + { + pmult_msg_state_initial, + pmult_msg_state_headers, + pmult_msg_state_cr1, + pmult_msg_state_crlf1, + pmult_msg_state_cr2, + pmult_msg_state_body + }; + struct pmult_priv_data { mu_debug_t debug; mu_list_t /* of gacopyz_srv_t */ srvlist; unsigned nrcpt; unsigned nbadrcpts; + mu_stream_t hdrstream; + enum pmult_msg_state state; }; @@ -532,24 +544,47 @@ while (0) #define MSG_REJECT "550 5.7.1 Command rejected\r\n" #define MSG_SHUTDOWN "421 4.7.0 pmult closing connection\r\n" +const char * +hdrcommname (int rc) +{ + switch (rc) + { + case SMFIR_CHGHEADER: + return "chgheader"; + + case SMFIR_ADDHEADER: + return "addheader"; + + case SMFIR_INSHEADER: + return "insheader"; + } + return "unknown"; +} + static int pmult_std_reply (struct pmult_priv_data *p, pmse_ctx_P pmse_ctx, gacopyz_srv_t gsrv, int rc, const char *ident, const char *arg) { + char *buf; + char *cp; + size_t size; + + if (!arg) + arg = ""; + switch (rc) { + case SMFIR_CONTINUE: + break; + case SMFIR_REPLYCODE: - { - char *msg; - size_t size; - gacopyz_srv_reply (gsrv, &msg, &size); - MU_DEBUG3 (p->debug, MU_DEBUG_TRACE2, - "%s=%s, reply=%s", - ident, arg, msg); - SM_VERBOSE (sm_pmfi_setreply (pmse_ctx, msg)); - return (msg[0] == '4') ? SMTP_R_TEMP : SMTP_R_PERM; - } + gacopyz_srv_reply (gsrv, &buf, &size); + MU_DEBUG3 (p->debug, MU_DEBUG_TRACE2, + "%s=%s, reply=%s", + ident, arg, buf); + SM_VERBOSE (sm_pmfi_setreply (pmse_ctx, buf)); + return (buf[0] == '4') ? SMTP_R_TEMP : SMTP_R_PERM; case SMFIR_REJECT: MU_DEBUG3 (p->debug, MU_DEBUG_TRACE2, @@ -577,11 +612,96 @@ pmult_std_reply (struct pmult_priv_data *p, pmse_ctx_P pmse_ctx, ident, arg, MSG_SHUTDOWN); SM_VERBOSE (sm_pmfi_setreply (pmse_ctx, MSG_SHUTDOWN)); return SMTP_R_SSD; + + case SMFIR_ADDRCPT: + gacopyz_srv_reply (gsrv, &buf, &size); + MU_DEBUG3 (p->debug, MU_DEBUG_TRACE2, + "%s=%s, addrcpt=%s", + ident, arg, buf); + /* FIXME-MF: Not implemented in mailfromd */ + SM_VERBOSE (sm_pmfi_rcpt_add (pmse_ctx, buf, NULL)); + break; + + case SMFIR_DELRCPT: + gacopyz_srv_reply (gsrv, &buf, &size); + MU_DEBUG3 (p->debug, MU_DEBUG_TRACE2, + "%s=%s, delrcpt=%s", + ident, arg, buf); + /* FIXME-MF: Not implemented in mailfromd */ + /* FIXME: Index is always 0 */ + SM_VERBOSE (sm_pmfi_rcpt_del (pmse_ctx, buf, 0)); + break; + + case SMFIR_CHGHEADER: + case SMFIR_ADDHEADER: + case SMFIR_INSHEADER: + { + char *header; + uint type; + uint32_t idx = 0; + + gacopyz_srv_reply (gsrv, &buf, &size); + if (rc != SMFIR_ADDHEADER) + { + idx = ntohl (*(uint32_t*)buf); + buf += sizeof (uint32_t); + } + cp = memchr (buf, 0, size); + if (!cp) + { + mu_diag_output (MU_DIAG_NOTICE, "Malformed CHGHEADER command"); + break; + } + cp++; + MU_DEBUG6 (p->debug, MU_DEBUG_TRACE2, + "%s=%s, %s=%u '%s','%s'\n", + ident, arg, hdrcommname (rc), idx, buf, cp); + + header = malloc (size + 5); + if (!header) + { + mu_error ("%s", mu_strerror (ENOMEM)); + return SMTP_R_ACCEPT; + } + strcpy (header, buf); + strcat (header, ": "); + strcat (header, cp); + strcat (header, "\r\n"); + + switch (rc) + { + case SMFIR_CHGHEADER: + /* FIXME: REMOVE does not work unless full header contents is + supplied. */ + type = (*cp == 0) ? SM_HDRMOD_T_REMOVE : SM_HDRMOD_T_REPLACE; + break; + + case SMFIR_ADDHEADER: + type = SM_HDRMOD_T_APPEND; + break; + + case SMFIR_INSHEADER: + type = SM_HDRMOD_T_INSERT; + } + SM_VERBOSE (sm_pmfi_hdr_mod (pmse_ctx, type, idx, header)); + free (header); + } + break; + + case SMFIR_REPLBODY: + /* FIXME */ + + default: + if (isascii (rc) && isprint (rc)) + mu_diag_output (MU_DIAG_WARNING, _("Unsupported reply code: %c (%d)"), + rc, rc); + else + mu_diag_output (MU_DIAG_WARNING, _("Unsupported reply code: (%d)"), + rc); } return SMTP_R_CONT; } - typedef sfsistat_T (*pmult_runfun_t) (pmse_ctx_P, gacopyz_srv_t, void *); static sfsistat_T @@ -631,6 +751,7 @@ pmult_free (struct pmult_priv_data *p) mu_list_destroy (&p->srvlist); unprotect (); + mu_stream_destroy (&p->hdrstream, NULL); mu_debug_destroy (&p->debug, NULL); free (p); } @@ -1078,6 +1199,148 @@ rf_body (pmse_ctx_P pmse_ctx, gacopyz_srv_t gsrv, void *data) return status == SMTP_R_CONT ? SMTP_R_OK : status; } +static int +collect_headers (struct pmult_priv_data *p, unsigned char *buf, size_t len, + size_t *poff) +{ + int rc; + size_t off = 0; + + if (p->state == pmult_msg_state_initial) + { + mu_memory_stream_create (&p->hdrstream, NULL, MU_STREAM_NO_CHECK); + p->state = pmult_msg_state_headers; + } + + for (;;) + { + if (p->state == pmult_msg_state_headers) + { + for (; off < len; off++) + if (buf[off] == '\r') + { + off++; + p->state = pmult_msg_state_cr1; + break; + } + } + + if (off == len) + break; + + if (p->state == pmult_msg_state_cr1 && buf[off] == '\n') + { + p->state = pmult_msg_state_crlf1; + off++; + } + + if (off == len) + break; + + if (p->state == pmult_msg_state_crlf1) + { + if (buf[off] == '\r') + { + p->state = pmult_msg_state_cr2; + off++; + } + else + p->state = pmult_msg_state_headers; + } + + if (off == len) + break; + + if (p->state == pmult_msg_state_cr2 && buf[off] == '\n') + { + p->state = pmult_msg_state_body; + off++; + break; + } + } + + rc = mu_stream_sequential_write (p->hdrstream, buf, off); + if (rc) + { + mu_error ("mu_stream_sequential_write: %s", mu_strerror (rc)); + return 1; + } + *poff = off; + return 0; +} + +struct header +{ + const char *name; + const char *value; +}; + +static sfsistat_T +rf_header (pmse_ctx_P pmse_ctx, gacopyz_srv_t gsrv, void *data) +{ + struct pmult_priv_data *p = sm_pmfi_get_ctx_se (pmse_ctx); + struct header *hp = data; + int rc = gacopyz_srv_header (gsrv, (char*)hp->name, (char*)hp->value); + pmult_std_reply (p, pmse_ctx, gsrv, rc, "header", NULL); + /* FIXME: do I need to analyze its return? */ + return SMTP_R_OK; +} + +static sfsistat_T +rf_eoh (pmse_ctx_P pmse_ctx, gacopyz_srv_t gsrv, void *data) +{ + struct pmult_priv_data *p = sm_pmfi_get_ctx_se (pmse_ctx); + int rc = gacopyz_srv_eoh (gsrv); + pmult_std_reply (p, pmse_ctx, gsrv, rc, "eoh", NULL); + /* FIXME: do I need to analyze its return? */ + return SMTP_R_OK; +} + +static int +process_headers (pmse_ctx_P pmse_ctx, struct pmult_priv_data *p) +{ + mu_header_t hdr; + mu_off_t size; + size_t count, i; + int rc; + mu_transport_t tbuf; + + /* FIXME-MU: This could be largely simplified if mu_header_t had + a _set_stream method. */ + rc = mu_stream_size (p->hdrstream, &size); + if (rc) + { + mu_error (_("Cannot get the size of the header stream: %s"), + mu_strerror (rc)); + return 1; + } + mu_stream_get_transport (p->hdrstream, &tbuf); + rc = mu_header_create (&hdr, (char*) tbuf, size, NULL); + if (rc) + { + mu_error (_("Cannot create header: %s"), mu_strerror (rc)); + return 1; + } + + /* FIXME-MU: mu_header_get_iterator would be in place here. */ + mu_header_get_field_count (hdr, &count); + for (i = 1; i <= count; i++) + { + struct header h; + if (mu_header_sget_field_name (hdr, i, &h.name) + || mu_header_sget_field_value (hdr, i, &h.value)) + continue; + pmult_runlist (p, rf_header, pmse_ctx, &h, NULL); + } + pmult_runlist (p, rf_eoh, pmse_ctx, NULL, NULL); + + mu_header_destroy (&hdr, mu_header_get_owner (hdr)); + return 0; +} + +#define EOM_MARK "\r\n.\r\n" +#define EOM_MARK_LEN (sizeof (EOM_MARK) - 1) + static sfsistat_T pmult_msg (pmse_ctx_P pmse_ctx, unsigned char *buf, size_t len) { @@ -1093,6 +1356,27 @@ pmult_msg (pmse_ctx_P pmse_ctx, unsigned char *buf, size_t len) MU_DEBUG1 (p->debug, MU_DEBUG_TRACE1, "BODY %lu\n", (unsigned long) len); } + + if (p->state != pmult_msg_state_body) + { + size_t off; + int rc = collect_headers (p, buf, len, &off); + if (rc) + return SMTP_R_ACCEPT; /* Better safe than sorry. */ + if (p->state != pmult_msg_state_body) + return SMTP_R_OK; /* See comment to rf_body */ + if (process_headers (pmse_ctx, p)) + return SMTP_R_ACCEPT; + len -= off; + buf += off; + } + + /* FIXME: This is not enough, the marker can be split between two + successive calls. */ + if (len >= EOM_MARK_LEN + && memcmp (buf + len - EOM_MARK_LEN, EOM_MARK, EOM_MARK_LEN) == 0) + len -= 3; + bc.ident = "body"; bc.srvfun = gacopyz_srv_body; bc.size = len; @@ -1359,7 +1359,7 @@ instr_header(eval_environ_t env) adjust_stack(env, 1); if (PROG_TRACE_ENGINE) - prog_trace(env, "HEADER %d %s %s", + prog_trace(env, "HEADER %d '%s' '%s'", hdr->opcode, hdr->name, hdr->value); trace("%s%s:%lu: %s %s %s", |