#include <sys_defs.h>
#include <msg.h>
#include <mymalloc.h>
#include <vstring.h>
#include <vstream.h>
#include <split_at.h>
#include <mime_state.h>
#include <rec_type.h>
#include <smtpd_binary.h>
#include <string.h>
struct binary_context {
VSTREAM *output;
void *output_context;
int (*output_rec)(VSTREAM *stream, int rec_type, const char *data,
ssize_t len);
MIME_STATE *mime_state;
};
static void binary_head_out(void *context, int header_class_unused,
const HEADER_OPTS *header_info_unused,
VSTRING *buf, off_t offset_unused)
{
struct binary_context *bcp = context;
char *start, *line, *next_line;
for (line = start = vstring_str(buf); line; line = next_line) {
next_line = split_at(line, '\n');
bcp->output_rec(bcp->output, REC_TYPE_NORM, line,
next_line ? next_line - line - 1 : strlen(line));
}
}
static void binary_body_out(void *context, int rec_type,
const char *buf, ssize_t len, off_t offset_unused)
{
struct binary_context *bcp = context;
bcp->output_rec(bcp->output, rec_type, buf, len);
}
void *binary_filter_create(void)
{
struct binary_context *bcp;
bcp = (struct binary_context *) mymalloc(sizeof *bcp);
bcp->output = NULL;
bcp->output_context = NULL;
bcp->output_rec = NULL;
bcp->mime_state = mime_state_alloc(MIME_OPT_DOWNGRADE_BASE64,
binary_head_out, NULL,
binary_body_out, NULL,
NULL, bcp);
return bcp;
}
void binary_filter_start(void *context, VSTREAM *output,
int (*output_rec)(VSTREAM *stream, int rec_type,
const char *data, ssize_t len))
{
struct binary_context *bcp = context;
if (bcp->output == NULL)
bcp->output = output;
else if (bcp->output != output)
msg_panic("binary_filter_start: output mismatch");
vstream_control(output,
VSTREAM_CTL_CONTEXT_GET, &bcp->output_context,
VSTREAM_CTL_CONTEXT, bcp,
VSTREAM_CTL_END);
bcp->output_rec = output_rec;
}
int binary_filter_rec_put(VSTREAM *stream, int rec_type, const char *data,
ssize_t len)
{
struct binary_context *bcp = NULL;
int err;
vstream_control(stream,
VSTREAM_CTL_CONTEXT_GET, &bcp,
VSTREAM_CTL_END);
if (bcp == NULL || bcp->output != stream)
msg_panic("binary_filter_rec_put: output mismatch");
vstream_control(stream,
VSTREAM_CTL_CONTEXT, bcp->output_context,
VSTREAM_CTL_END);
err = mime_state_update(bcp->mime_state, rec_type, data, len);
vstream_control(stream,
VSTREAM_CTL_CONTEXT, bcp,
VSTREAM_CTL_END);
return err ? REC_TYPE_ERROR : rec_type;
}
int binary_filter_flush(void *context, VSTREAM *stream)
{
struct binary_context *bcp = NULL;
int err;
vstream_control(stream,
VSTREAM_CTL_CONTEXT_GET, &bcp,
VSTREAM_CTL_END);
if (bcp == NULL || bcp->output != stream)
msg_panic("binary_filter_rec_put: output mismatch");
vstream_control(stream,
VSTREAM_CTL_CONTEXT, bcp->output_context,
VSTREAM_CTL_END);
err = mime_state_flush(bcp->mime_state);
vstream_control(stream,
VSTREAM_CTL_CONTEXT, bcp,
VSTREAM_CTL_END);
return err ? REC_TYPE_ERROR : 0;
}
void binary_filter_stop(void *context, VSTREAM *stream)
{
struct binary_context *bcp = NULL;
vstream_control(stream,
VSTREAM_CTL_CONTEXT_GET, &bcp,
VSTREAM_CTL_END);
if (bcp != context || bcp->output != stream)
msg_panic("binary_filter_deinit: output mismatch");
vstream_control(stream,
VSTREAM_CTL_CONTEXT, bcp->output_context,
VSTREAM_CTL_END);
}
void binary_filter_destroy(void *context)
{
struct binary_context *bcp = context;
mime_state_free(bcp->mime_state);
myfree((char *) bcp);
}