view src/header.c @ 22:7c1635972aa7

small cleanups
author meillo@marmaro.de
date Fri, 05 Dec 2008 11:26:24 +0100
parents f671821d8222
children 3708b655a371
line wrap: on
line source

/*  MasqMail
    Copyright (C) 2000 Oliver Kurth

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "masqmail.h"

header_name header_names[] = {
	{"From", HEAD_FROM,},
	{"Sender", HEAD_SENDER,},
	{"To", HEAD_TO,},
	{"Cc", HEAD_CC,},
	{"Bcc", HEAD_BCC,},
	{"Date", HEAD_DATE,},
	{"Message-Id", HEAD_MESSAGE_ID,},
	{"Reply-To", HEAD_REPLY_TO,},
	{"Subject", HEAD_SUBJECT,},
	{"Return-Path", HEAD_RETURN_PATH,},
	{"Envelope-To", HEAD_ENVELOPE_TO,},
	{"Received", HEAD_RECEIVED},
};

/* this was borrowed from exim and slightly changed */
gchar*
rec_timestamp()
{
	static gchar buf[64];
	int len;

	time_t now = time(NULL);
	struct tm *t = localtime(&now);

	int diff_hour, diff_min;
	struct tm local;
	struct tm *gmt;

	memcpy(&local, t, sizeof(struct tm));
	gmt = gmtime(&now);
	diff_min = 60 * (local.tm_hour - gmt->tm_hour) + local.tm_min - gmt->tm_min;
	if (local.tm_year != gmt->tm_year)
		diff_min += (local.tm_year > gmt->tm_year) ? 1440 : -1440;
	else if (local.tm_yday != gmt->tm_yday)
		diff_min += (local.tm_yday > gmt->tm_yday) ? 1440 : -1440;
	diff_hour = diff_min / 60;
	diff_min = abs(diff_min - diff_hour * 60);

	len = strftime(buf, sizeof(buf), "%a, ", &local);
	g_snprintf(buf + len, sizeof(buf) - len, "%02d ", local.tm_mday);
	len += strlen(buf + len);
	len += strftime(buf + len, sizeof(buf) - len, "%b %Y %H:%M:%S", &local);
	g_snprintf(buf + len, sizeof(buf) - len, " %+03d%02d", diff_hour, diff_min);

	return buf;
}

/* finds list of headers matching id
   if id == HEAD_UNKNOWN and header == NULL finds all unknown headers
   else finds all headers matching header
*/
GList*
find_header(GList * hdr_list, header_id id, gchar * hdr_str)
{
	GList *found_list = NULL;
	GList *node;

	if ((id != HEAD_UNKNOWN) || (hdr_str == NULL)) {
		foreach(hdr_list, node) {
			header *hdr = (header *) (node->data);
			if (hdr->id == id)
				found_list = g_list_append(found_list, hdr);
		}
	} else {
		foreach(hdr_list, node) {
			header *hdr = (header *) (node->data);
			gchar buf[64], *q = buf, *p = hdr->header;

			while (*p != ':' && q < buf + 63 && *p)
				*(q++) = *(p++);
			*q = '\0';

			if (strcasecmp(buf, hdr_str) == 0)
				found_list = g_list_append(found_list, hdr);
		}
	}
	return found_list;
}

void
header_unfold(header * hdr)
{
	gchar *tmp_hdr = g_malloc(strlen(hdr->header));
	gchar *p = hdr->header, *q = tmp_hdr;
	gboolean flag = FALSE;

	while (*p) {
		if (*p != '\n')
			*(q++) = *p;
		else
			flag = TRUE;
		p++;
	}
	*(q++) = '\n';

	if (flag) {
		gchar *new_hdr;

		g_free(hdr->header);
		new_hdr = g_strdup(tmp_hdr);
		g_free(tmp_hdr);
		hdr->value = new_hdr + (hdr->value - hdr->header);
		hdr->header = new_hdr;
	}
}

#define MAX_HDR_LEN 72
void
header_fold(header * hdr)
{
	gint len = strlen(hdr->header);
	gchar *p, *q;
	/* size is probably overestimated, but so we are on the safe side */
	gchar *tmp_hdr = g_malloc(len + 2 * len / MAX_HDR_LEN);

	p = hdr->header;
	q = tmp_hdr;

	if (p[len - 1] == '\n')
		p[len - 1] = '\0';

	while (*p) {
		gint i, l;
		gchar *pp;

		/* look forward and find potential break points */
		i = 0;
		l = -1;
		pp = p;
		while (*pp && (i < MAX_HDR_LEN)) {
			if ((*pp == ' ') || (*pp == '\t'))
				l = i;
			pp++;
			i++;
		}
		if (!*pp)
			l = pp - p;  /* take rest, if EOS found */

		if (l == -1) {
			/* no potential break point was found within MAX_HDR_LEN so advance further until the next */
			while (*pp && *pp != ' ' && *pp != '\t') {
				pp++;
				i++;
			}
			l = i;
		}

		/* copy */
		i = 0;
		while (i < l) {
			*(q++) = *(p++);
			i++;
		}
		*(q++) = '\n';
		*(q++) = *(p++);  /* this is either space, tab or 0 */
	}
	{
		gchar *new_hdr;

		g_free(hdr->header);
		new_hdr = g_strdup(tmp_hdr);
		g_free(tmp_hdr);
		hdr->value = new_hdr + (hdr->value - hdr->header);
		hdr->header = new_hdr;
	}
}

header*
create_header(header_id id, gchar * fmt, ...)
{
	gchar *p;
	header *hdr;
	va_list args;
	va_start(args, fmt);

	if ((hdr = g_malloc(sizeof(header)))) {

		hdr->id = id;
		hdr->header = g_strdup_vprintf(fmt, args);
		hdr->value = NULL;

		p = hdr->header;
		while (*p && *p != ':')
			p++;
		if (*p)
			hdr->value = p + 1;
	}

	va_end(args);
	return hdr;
}

void
destroy_header(header * hdr)
{
	if (hdr) {
		if (hdr->header)
			g_free(hdr->header);
		g_free(hdr);
	}
}

header*
copy_header(header * hdr)
{
	header *new_hdr = NULL;

	if (hdr) {
		if ((new_hdr = g_malloc(sizeof(header)))) {
			new_hdr->id = hdr->id;
			new_hdr->header = g_strdup(hdr->header);
			new_hdr->value = new_hdr->header + (hdr->value - hdr->header);
		}
	}
	return new_hdr;
}

header*
get_header(gchar * line)
{
	gchar *p = line;
	gchar buf[64], *q = buf;
	gint i;
	header *hdr;

	while (*p && (*p != ':') && (q < buf + 63))
		*(q++) = *(p++);
	*q = '\0';

	if (*p != ':')
		return NULL;

	hdr = g_malloc(sizeof(header));

	hdr->value = NULL;
	p++;

	while (*p && (*p == ' ' || *p == '\t'))
		p++;
	hdr->value = p;

	for (i = 0; i < HEAD_NUM_IDS; i++) {
		if (strcasecmp(header_names[i].header, buf) == 0)
			break;
	}
	hdr->id = (header_id) i;
	hdr->header = g_strdup(line);
	hdr->value = hdr->header + (hdr->value - line);

	DEBUG(4) debugf("header: %d = %s", hdr->id, hdr->header);

	return hdr;
}