~sircmpwn/hare-message

8ca621f38f1901eed5deb925bfbe5dd51635543e — Drew DeVault 1 year, 4 months ago bcbe622
message: move header functions around
1 files changed, 56 insertions(+), 55 deletions(-)

M message/header.ha
M message/header.ha => message/header.ha +56 -55
@@ 9,61 9,6 @@ use strings;
use strio;
use types;

export def HEADER_BUCKETS: u64 = 16;

export type header_field = struct {
	raw: []u8,
	key: str,
	val: str,
};

// Initializes a new header field, duplicating the provided parameters.
fn new_header_field(key: str, val: str, raw: []u8) header_field = {
	return header_field {
		raw = alloc(raw...),
		key = canonical_mime_header_key(key),
		val = strings::dup(val),
	};
};

fn header_field_destroy(hf: *header_field) void = {
	free(hf.raw);
	free(hf.key);
	free(hf.val);
	free(hf);
};

// Returns the raw representation of this header field, including CRLF. The
// return value is borrowed from the header field.
fn header_field_raw(hf: *header_field) ([]u8 | errors::invalid) = {
	if (len(hf.raw) != 0) {
		return hf.raw;
	};

	const iter = strings::iter(hf.key);
	for (true) {
		const rn = match (strings::next(&iter)) {
		case let rn: rune =>
			yield rn;
		case void =>
			break;
		};

		if (!ascii::isprint(rn) || rn == ':') {
			return errors::invalid;
		};
	};

	if (strings::contains(hf.val, "\r\n")) {
		return errors::invalid;
	};

	let sink = bufio::dynamic(io::mode::WRITE);
	header_field_fmt(&sink, hf)!;
	hf.raw = bufio::buffer(&sink);
	return hf.raw;
};

export type header = struct {
	fields: []*header_field,
	map: [HEADER_BUCKETS][]header_map_key,


@@ 74,6 19,14 @@ export type header_map_key = struct {
	fields: []*header_field,
};

export def HEADER_BUCKETS: u64 = 16;

export type header_field = struct {
	raw: []u8,
	key: str,
	val: str,
};

// Creates a new message header. The representation is idempotent, such that
// whitespace and field ordering is preserved.
export fn new_header() header = {


@@ 384,6 337,54 @@ export fn write_header(sink: io::handle, head: *header) (size | io::error) = {
	assert(result == expect);
};

// Initializes a new header field, duplicating the provided parameters.
fn new_header_field(key: str, val: str, raw: []u8) header_field = {
	return header_field {
		raw = alloc(raw...),
		key = canonical_mime_header_key(key),
		val = strings::dup(val),
	};
};

fn header_field_destroy(hf: *header_field) void = {
	free(hf.raw);
	free(hf.key);
	free(hf.val);
	free(hf);
};

// Returns the raw representation of this header field, including CRLF. The
// return value is borrowed from the header field.
fn header_field_raw(hf: *header_field) ([]u8 | errors::invalid) = {
	if (len(hf.raw) != 0) {
		return hf.raw;
	};

	const iter = strings::iter(hf.key);
	for (true) {
		const rn = match (strings::next(&iter)) {
		case let rn: rune =>
			yield rn;
		case void =>
			break;
		};

		if (!ascii::isprint(rn) || rn == ':') {
			return errors::invalid;
		};
	};

	if (strings::contains(hf.val, "\r\n")) {
		return errors::invalid;
	};

	let sink = bufio::dynamic(io::mode::WRITE);
	header_field_fmt(&sink, hf)!;
	hf.raw = bufio::buffer(&sink);
	return hf.raw;
};


def PREFERRED_HEADER_LEN = 76z;
def MAX_HEADER_LEN = 998z;