Esempio n. 1
0
static void test_quoted_printable_decode(void)
{
	static struct test_quoted_printable_decode_data data[] = {
		{ "foo  \r\nbar=", "foo\r\nbar", 1, 0 },
		{ "foo\t=\nbar", "foo\tbar", 0, 0 },
		{ "foo = \n=01", "foo \001", 0, 0 },
		{ "foo =\t\r\nbar", "foo bar", 0, 0 },
		{ "foo =\r\n=01", "foo \001", 0, 0 },
		{ "foo  \nbar=", "foo\nbar", 1, 0 },
		{ "=0A=0D  ", "\n\r", 2, 0 },
		{ "foo_bar", "foo_bar", 0, 0 },
		{ "foo=", "foo", 1, 0 },
		{ "foo=  ", "foo", 3, 0 },
		{ "foo=A", "foo", 2, 0 },
		{ "foo=Ax", "foo=Ax", 0, -1 },
		{ "foo=Ax=xy", "foo=Ax=xy", 0, -1 }
	};
	buffer_t *buf;
	unsigned int i, start, end, len;
	size_t src_pos;
	int ret;

	test_begin("quoted printable decode");
	buf = buffer_create_dynamic(pool_datastack_create(), 128);
	for (i = 0; i < N_ELEMENTS(data); i++) {
		len = strlen(data[i].input);
		ret = quoted_printable_decode((const void *)data[i].input, len,
					      &src_pos, buf);
		test_assert(ret == data[i].ret);
		test_assert(src_pos + data[i].end_skip == len);
		test_assert(strcmp(data[i].output, str_c(buf)) == 0);

		buffer_set_used_size(buf, 0);
		for (start = 0, end = 1; end <= len; ) {
			quoted_printable_decode(CONST_PTR_OFFSET(data[i].input, start),
						end - start, &src_pos, buf);
			src_pos += start;
			start = src_pos;
			if (src_pos <= end)
				end++;
			else
				end = src_pos + 1;
		}
		test_assert(src_pos + data[i].end_skip == len);
		test_assert(strcmp(data[i].output, str_c(buf)) == 0);
		buffer_set_used_size(buf, 0);
	}
	test_end();
}
static int
i_stream_qp_try_decode_input(struct qp_decoder_istream *bstream, bool eof)
{
    struct istream_private *stream = &bstream->istream;
    const unsigned char *data;
    size_t size, avail, buffer_avail, pos;
    buffer_t buf;
    int ret;

    data = i_stream_get_data(stream->parent, &size);
    if (size == 0)
        return 0;

    /* normally the decoded quoted-printable content can't be larger than
       the encoded content, but because we always use CRLFs, it may use
       twice as much space by only converting LFs to CRLFs. */
    i_stream_try_alloc(stream, size, &avail);
    buffer_avail = stream->buffer_size - stream->pos;

    if (size > buffer_avail/2) {
        /* can't fit everything to destination buffer.
           write as much as we can. */
        size = buffer_avail/2;
        if (size == 0)
            return -2;
    }

    buffer_create_from_data(&buf, stream->w_buffer + stream->pos,
                            buffer_avail);
    ret = !eof ? quoted_printable_decode(data, size, &pos, &buf) :
          quoted_printable_decode_final(data, size, &pos, &buf);
    if (ret < 0) {
        io_stream_set_error(&stream->iostream,
                            "Invalid quoted-printable data: 0x%s",
                            binary_to_hex(data+pos, I_MAX(size-pos, 8)));
        stream->istream.stream_errno = EINVAL;
        return -1;
    }

    stream->pos += buf.used;
    i_stream_skip(stream->parent, pos);
    return pos > 0 ? 1 : 0;
}
Esempio n. 3
0
static int
i_stream_qp_try_decode_input(struct qp_decoder_istream *bstream, bool eof)
{
	struct istream_private *stream = &bstream->istream;
	const unsigned char *data;
	size_t size, avail, buffer_avail, pos;
	buffer_t buf;
	int ret;

	data = i_stream_get_data(stream->parent, &size);
	if (size == 0)
		return 0;

	/* the decoded quoted-printable content can never be larger than the
	   encoded content. at worst they are equal. */
	i_stream_try_alloc(stream, size, &avail);
	buffer_avail = stream->buffer_size - stream->pos;

	if (size > buffer_avail) {
		/* can't fit everything to destination buffer.
		   write as much as we can. */
		size = buffer_avail;
		if (size == 0)
			return -2;
	}

	buffer_create_from_data(&buf, stream->w_buffer + stream->pos,
				buffer_avail);
	ret = !eof ? quoted_printable_decode(data, size, &pos, &buf) :
		quoted_printable_decode_final(data, size, &pos, &buf);
	if (ret < 0) {
		stream->istream.stream_errno = EINVAL;
		return -1;
	}

	stream->pos += buf.used;
	i_stream_skip(stream->parent, pos);
	return pos > 0 ? 1 : 0;
}
Esempio n. 4
0
static bool message_decode_body(struct message_decoder_context *ctx,
				struct message_block *input,
				struct message_block *output)
{
	const unsigned char *data = NULL;
	size_t pos = 0, size = 0;
	int ret;

	if (ctx->encoding_buf->used != 0) {
		/* @UNSAFE */
		buffer_append(ctx->encoding_buf, input->data, input->size);
	}

	switch (ctx->message_cte) {
	case MESSAGE_CTE_UNKNOWN:
		/* just skip this body */
		return FALSE;

	case MESSAGE_CTE_78BIT:
	case MESSAGE_CTE_BINARY:
		data = input->data;
		size = pos = input->size;
		break;
	case MESSAGE_CTE_QP:
		buffer_set_used_size(ctx->buf, 0);
		if (ctx->encoding_buf->used != 0) {
			(void)quoted_printable_decode(ctx->encoding_buf->data,
						      ctx->encoding_buf->used,
						      &pos, ctx->buf);
		} else {
			(void)quoted_printable_decode(input->data, input->size,
						      &pos, ctx->buf);
		}
		data = ctx->buf->data;
		size = ctx->buf->used;
		break;
	case MESSAGE_CTE_BASE64:
		buffer_set_used_size(ctx->buf, 0);
		if (ctx->encoding_buf->used != 0) {
			ret = base64_decode(ctx->encoding_buf->data,
					    ctx->encoding_buf->used,
					    &pos, ctx->buf);
		} else {
			ret = base64_decode(input->data, input->size,
					    &pos, ctx->buf);
		}
		if (ret < 0) {
			/* corrupted base64 data, don't bother with
			   the rest of it */
			return FALSE;
		}
		if (ret == 0) {
			/* end of base64 input */
			pos = input->size;
			buffer_set_used_size(ctx->encoding_buf, 0);
		}
		data = ctx->buf->data;
		size = ctx->buf->used;
		break;
	}

	if (ctx->encoding_buf->used != 0)
		buffer_delete(ctx->encoding_buf, 0, pos);
	else if (pos != input->size) {
		buffer_append(ctx->encoding_buf,
			      input->data + pos, input->size - pos);
	}

	if (ctx->binary_input) {
		output->data = data;
		output->size = size;
	} else if (ctx->charset_utf8 || ctx->charset_trans == NULL) {
		/* handle unknown charsets the same as UTF-8. it might find
		   usable ASCII text. */
		buffer_set_used_size(ctx->buf2, 0);
		if (ctx->normalizer != NULL) {
			(void)ctx->normalizer(data, size, ctx->buf2);
			output->data = ctx->buf2->data;
			output->size = ctx->buf2->used;
		} else if (uni_utf8_get_valid_data(data, size, ctx->buf2)) {
			output->data = data;
			output->size = size;
		} else {
			output->data = ctx->buf2->data;
			output->size = ctx->buf2->used;
		}
	} else {
		buffer_set_used_size(ctx->buf2, 0);
		if (ctx->translation_size != 0)
			translation_buf_decode(ctx, &data, &size);

		pos = size;
		(void)charset_to_utf8(ctx->charset_trans,
				      data, &pos, ctx->buf2);
		if (pos != size) {
			ctx->translation_size = size - pos;
			i_assert(ctx->translation_size <=
				 sizeof(ctx->translation_buf));
			memcpy(ctx->translation_buf, data + pos,
			       ctx->translation_size);
		}
		output->data = ctx->buf2->data;
		output->size = ctx->buf2->used;
	}

	output->hdr = NULL;
	return TRUE;
}