/* Copyright (c) 2003-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "sort.h"
#include "message-parser.h"
#include "istream-private.h"
#include "istream-header-filter.h"
struct header_filter_istream {
const char **headers;
unsigned int headers_count;
void *context;
};
{
(struct header_filter_istream *)stream;
}
static ssize_t
{
const unsigned char *data;
return -1;
}
if (pos <= body_highwater_size) {
(mstream->end_body_with_lf &&
if (ret <= 0) {
/* add missing trailing LF to body */
}
return ret;
}
}
return ret;
}
{
}
{
return FALSE;
}
{
else
}
{
return ret;
}
{
int hdr_ret;
NULL, 0);
}
/* remove skipped data from hdr_buf */
if (mstream->header_read) {
/* we want to return mixed headers and body */
}
}
i_assert(max_buffer_size > 0);
return -2;
}
&hdr)) > 0) {
bool matched;
if (mstream->eoh_not_matched)
}
if (matched) {
continue;
}
continue;
}
/* Header line continued - use only the first line's
matched-result. Otherwise multiline headers might
end up being only partially picked, which wouldn't
be very good. However, allow callbacks to modify
the headers in any way they want. */
} else if (mstream->headers_count == 0) {
} else {
bsearch_strcasecmp) != NULL;
}
/* nothing gets excluded */
/* first time in this line or we have actually modified
the header so we always want to call the callbacks */
if (matched != orig_matched &&
}
/* second time in this line. was it excluded by the
callback the first time? */
if (match_line_changed(mstream))
}
/* ignore */
} else {
}
if (!hdr->no_newline)
/* we need more */
} else {
if (mstream->skip_count > 0) {
mstream->skip_count = 0;
}
break;
}
}
break;
}
}
if (hdr_ret < 0) {
return -1;
}
if (!mstream->last_added_newline)
if (mstream->eoh_not_matched)
.name = "",
};
}
if (matched) {
} else {
}
}
}
/* don't copy eof here because we're only returning headers here.
the body will be returned in separate read() call. */
if (hdr_ret == 0) {
/* need more data to finish parsing headers. we may have some
data already available though. */
return ret;
}
/* finished */
mstream->callbacks_called) &&
/* check if the callback added more headers.
this is allowed only if EOH wasn't added yet. */
else {
}
}
}
if (ret == 0) {
/* we're at the end of headers. */
}
return ret;
}
static ssize_t
{
const unsigned char *data;
bool last_lf;
else if (size > 0)
else
/* missing LF, need to add it */
} else {
}
return ret;
}
{
(struct header_filter_istream *)stream;
if (mstream->last_lf_added) {
return -1;
}
if (!mstream->header_read ||
return read_header(mstream);
return -1;
}
if (mstream->end_body_with_lf)
return ret;
}
static void
{
}
{
if (mstream->header_read)
return 0;
/* need to re-parse headers */
}
while (!mstream->header_read &&
}
}
static void
{
}
{
(struct header_filter_istream *)stream;
/* just reset the input buffer */
return;
}
/* if last_lf_added=TRUE, we're currently at EOF. So reset it only if
we're seeking backwards, otherwise we would just add a duplicate */
if (v_offset == 0) {
/* seeking to beginning of headers. */
stream_reset_to(mstream, 0);
return;
}
/* if we haven't parsed the whole header yet, we don't know if we
want to seek inside header or body. so make sure we've parsed the
header. */
if (skip_header(mstream) < 0)
return;
/* seek into headers. we'll have to re-parse them, use
skip_count to set the wanted position */
} else {
/* body */
}
}
static void ATTR_NORETURN
{
i_panic("istream-header-filter sync() not implemented");
}
static int
{
(struct header_filter_istream *)stream;
return -1;
}
return 0;
/* fix the filtered header size */
if (skip_header(mstream) < 0)
return -1;
/* no body */
} else if (!mstream->end_body_with_lf) {
/* no last-LF */
} else if (mstream->last_lf_added) {
/* yes, we have added LF */
/* no, we didn't need to add LF */
} else {
/* check if we need to add LF */
return -1;
}
if (ret > 0)
}
return 0;
}
struct istream *
enum header_filter_flags flags,
const char *const *headers,
unsigned int headers_count,
{
unsigned int i, j;
int ret;
"header filter stream", 4096);
for (i = j = 0; i < headers_count; i++) {
ret = j == 0 ? -1 :
if (ret == 0) {
/* drop duplicate */
continue;
}
}
mstream->headers_count = j;
if ((flags & HEADER_FILTER_CRLF_PRESERVE) != 0)
else if ((flags & HEADER_FILTER_NO_CR) != 0)
else
(flags & HEADER_FILTER_END_BODY_WITH_LF) != 0;
}
{
}