<commit_before>/* Copyright (c) 2009 Dovecot authors, see the included COPYING file */

#include "lib.h"
#include "str.h"
#include "base64.h"
#include "message-header-encode.h"

#define MIME_WRAPPER_LEN (strlen("=?utf-8?q?""?="))
#define MIME_MAX_LINE_LEN 76

#define IS_LWSP(c) \
	((c) == ' ' || (c) == '\t' || (c) == '\n')

static bool input_idx_need_encoding(const unsigned char *input, unsigned int i)
{
	if ((input[i] & 0x80) != 0)
		return TRUE;

	if (input[i] == '=' && input[i+1] == '?' &&
	    (i == 0 || IS_LWSP(input[i-1])))
		return TRUE;
	return FALSE;
}

static unsigned int str_last_line_len(string_t *str)
{
	const unsigned char *data = str_data(str);
	unsigned int i = str_len(str);

	while (i > 0 && data[i-1] != '\n')
		i--;
	return str_len(str) - i;
}

void message_header_encode_q(const unsigned char *input, unsigned int len,
			     string_t *output)
{
	unsigned int i, line_len, line_len_left;

	line_len = str_last_line_len(output);
	if (line_len >= MIME_MAX_LINE_LEN - MIME_WRAPPER_LEN - 3) {
		str_append(output, "\n\t");
		line_len = 1;
	}

	str_append(output, "=?utf-8?q?");
	line_len_left = MIME_MAX_LINE_LEN - MIME_WRAPPER_LEN - line_len;
	for (i = 0; i < len; i++) {
		if (line_len_left < 3) {
			/* if we're not at the beginning of a character,
			   go backwards until we are */
			while ((input[i] & 0xc0) == 0x80) {
				str_truncate(output, str_len(output)-3);
				i--;
			}
			str_append(output, "?=\n\t=?utf-8?q?");
			line_len_left = MIME_MAX_LINE_LEN -
				MIME_WRAPPER_LEN - 1;
		}
		switch (input[i]) {
		case ' ':
			str_append_c(output, '_');
			break;
		case '=':
		case '?':
		case '_':
			str_printfa(output, "=%2X", input[i]);
			break;
		default:
			if (input[i] < 32 || (input[i] & 0x80) != 0) {
				line_len_left -= 2;
				str_printfa(output, "=%2X", input[i]);
			} else {
				str_append_c(output, input[i]);
			}
			break;
		}
		line_len_left--;
	}
	str_append(output, "?=");
}

void message_header_encode_b(const unsigned char *input, unsigned int len,
			     string_t *output)
{
	unsigned int line_len, line_len_left, max;

	line_len = str_last_line_len(output);
	if (line_len >= MIME_MAX_LINE_LEN - MIME_WRAPPER_LEN) {
		str_append(output, "\n\t");
		line_len = 1;
	}

	for (;;) {
		line_len_left = MIME_MAX_LINE_LEN - MIME_WRAPPER_LEN - line_len;
		max = MAX_BASE64_DECODED_SIZE(line_len_left);
		do {<commit_msg>message_header_encode(): Line lengths weren't calculated properly with some characters.<commit_after>/* Copyright (c) 2009 Dovecot authors, see the included COPYING file */

#include "lib.h"
#include "str.h"
#include "base64.h"
#include "message-header-encode.h"

#define MIME_WRAPPER_LEN (strlen("=?utf-8?q?""?="))
#define MIME_MAX_LINE_LEN 76

#define IS_LWSP(c) \
	((c) == ' ' || (c) == '\t' || (c) == '\n')

static bool input_idx_need_encoding(const unsigned char *input, unsigned int i)
{
	if ((input[i] & 0x80) != 0)
		return TRUE;

	if (input[i] == '=' && input[i+1] == '?' &&
	    (i == 0 || IS_LWSP(input[i-1])))
		return TRUE;
	return FALSE;
}

static unsigned int str_last_line_len(string_t *str)
{
	const unsigned char *data = str_data(str);
	unsigned int i = str_len(str);

	while (i > 0 && data[i-1] != '\n')
		i--;
	return str_len(str) - i;
}

void message_header_encode_q(const unsigned char *input, unsigned int len,
			     string_t *output)
{
	unsigned int i, line_len, line_len_left;

	line_len = str_last_line_len(output);
	if (line_len >= MIME_MAX_LINE_LEN - MIME_WRAPPER_LEN - 3) {
		str_append(output, "\n\t");
		line_len = 1;
	}

	str_append(output, "=?utf-8?q?");
	line_len_left = MIME_MAX_LINE_LEN - MIME_WRAPPER_LEN - line_len;
	for (i = 0; i < len; i++) {
		if (line_len_left < 3) {
			/* if we're not at the beginning of a character,
			   go backwards until we are */
			while ((input[i] & 0xc0) == 0x80) {
				str_truncate(output, str_len(output)-3);
				i--;
			}
			str_append(output, "?=\n\t=?utf-8?q?");
			line_len_left = MIME_MAX_LINE_LEN -
				MIME_WRAPPER_LEN - 1;
		}
		switch (input[i]) {
		case ' ':
			str_append_c(output, '_');
			break;
		case '=':
		case '?':
		case '_':
			line_len_left -= 2;
			str_printfa(output, "=%2X", input[i]);
			break;
		default:
			if (input[i] < 32 || (input[i] & 0x80) != 0) {
				line_len_left -= 2;
				str_printfa(output, "=%2X", input[i]);
			} else {
				str_append_c(output, input[i]);
			}
			break;
		}
		line_len_left--;
	}
	str_append(output, "?=");
}

void message_header_encode_b(const unsigned char *input, unsigned int len,
			     string_t *output)
{
	unsigned int line_len, line_len_left, max;

	line_len = str_last_line_len(output);
	if (line_len >= MIME_MAX_LINE_LEN - MIME_WRAPPER_LEN) {
		str_append(output, "\n\t");
		line_len = 1;
	}

	for (;;) {
		line_len_left = MIME_MAX_LINE_LEN - MIME_WRAPPER_LEN - line_len;
		max = MAX_BASE64_DECODED_SIZE(line_len_left);
		do {
{'fraction_non_alphanumeric': 0.16821657367224632, 'fraction_numerical': 0.017978921264724116, 'mean_word_length': 3.69447138700291, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1868193', 'n_tokens_mistral': 2233, 'n_tokens_neox': 2002, 'n_words': 432}