view f-demime/header.c @ 2:1857d0d5a7bd

f-demime: fix parsing of Content-* headers
author Mychaela Falconia <falcon@freecalypso.org>
date Sat, 06 May 2023 06:33:26 +0000
parents 7e0d08176f32
children 612c4d0df768
line wrap: on
line source

/*
 * This module implements initial processing (pass-through and collection)
 * of message and body part headers.
 */

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include "defs.h"

extern enum msg_hdr_state hdr_state;
extern char cont_type_buf[HDR_BUF_SIZE], cont_te_buf[HDR_BUF_SIZE];
extern int got_cont_type, got_cont_te;

static void
error(line, msg)
	char *line, *msg;
{
	if (got_cont_type) {
		fputs(cont_type_buf, stdout);
		got_cont_type = 0;
	}
	if (got_cont_te) {
		fputs(cont_te_buf, stdout);
		got_cont_te = 0;
	}
	printf("X-Fdemime-Error: %s\n", msg);
	puts(line);
	hdr_state = HDR_STATE_ERROR;
}

static void
error_ct_cont(hdr_name)
	char *hdr_name;
{
	printf("X-Fdemime-Error: %s header is too long\n", hdr_name);
}

static void
cont_line(line)
	char *line;
{
	unsigned prev_len;

	switch (hdr_state) {
	case HDR_STATE_BEGIN:
		error(line, "continuation line at the beginning of header");
		return;
	case HDR_STATE_GOTSOME:
		puts(line);
		return;
	case HDR_STATE_CONT_TYPE:
		prev_len = strlen(cont_type_buf);
		if (prev_len + strlen(line) + 2 > HDR_BUF_SIZE) {
			error_ct_cont("Content-Type");
			fputs(cont_type_buf, stdout);
			puts(line);
			hdr_state = HDR_STATE_ERROR;
			got_cont_type = 0;
			return;
		}
		sprintf(cont_type_buf + prev_len, "%s\n", line);
		return;
	case HDR_STATE_CONT_TE:
		prev_len = strlen(cont_te_buf);
		if (prev_len + strlen(line) + 2 > HDR_BUF_SIZE) {
			error_ct_cont("Content-Transfer-Encoding");
			fputs(cont_te_buf, stdout);
			puts(line);
			hdr_state = HDR_STATE_ERROR;
			got_cont_te = 0;
			return;
		}
		sprintf(cont_te_buf + prev_len, "%s\n", line);
		return;
	default:
		fprintf(stderr,
			"f-demime internal error: bad state in cont_line()\n");
		abort();
	}
}

void
header_input_line(line)
	char *line;
{
	char *cp, savech;
	enum msg_hdr_state newhdr;

	if (!line[0]) {
		process_header_end();
		return;
	}
	if (hdr_state == HDR_STATE_ERROR) {
		puts(line);
		return;
	}
	if (line[0] == ' ' || line[0] == '\t') {
		cont_line(line);
		return;
	}
	cp = index(line, ':');
	if (!cp) {
		error(line, "header line has no colon");
		return;
	}
	if (cp == line) {
		error(line, "null header field name");
		return;
	}
	while (cp[-1] == ' ' || cp[-1] == '\t')
		cp--;
	savech = *cp;
	*cp = '\0';
	if (!strcasecmp(line, "Content-Type"))
		newhdr = HDR_STATE_CONT_TYPE;
	else if (!strcasecmp(line, "Content-Transfer-Encoding"))
		newhdr = HDR_STATE_CONT_TE;
	else
		newhdr = HDR_STATE_GOTSOME;
	*cp = savech;
	switch (newhdr) {
	case HDR_STATE_CONT_TYPE:
		if (got_cont_type) {
			error(line, "duplicate Content-Type");
			return;
		}
		sprintf(cont_type_buf, "%s\n", line);
		got_cont_type = 1;
		break;
	case HDR_STATE_CONT_TE:
		if (got_cont_te) {
			error(line, "duplicate Content-Transfer-Encoding");
			return;
		}
		sprintf(cont_te_buf, "%s\n", line);
		got_cont_te = 1;
		break;
	default:
		puts(line);
	}
	hdr_state = newhdr;
}