/*
** mhfree.c -- routines to free the data structures used to
**          -- represent MIME messages
**
** This code is Copyright (c) 2002, by the authors of nmh.  See the
** COPYRIGHT file in the root directory of the nmh distribution for
** complete copyright information.
*/

#include <h/mh.h>
#include <h/utils.h>
#include <errno.h>
#include <h/mime.h>
#include <h/mhparse.h>
#include <unistd.h>

/* The list of top-level contents to display */
CT *cts = NULL;

/*
** prototypes
*/
void free_content(CT);
void free_header(CT);
void free_ctinfo(CT);
void free_encoding(CT, int);
void freects_done();

/*
** static prototypes
*/
static void free_text(CT);
static void free_multi(CT);
static void free_partial(CT);


/*
** Primary routine to free a MIME content structure
*/

void
free_content(CT ct)
{
	if (!ct)
		return;

	/*
	** free all the header fields
	*/
	free_header(ct);

	if (ct->c_partno)
		mh_free0(&(ct->c_partno));

	if (ct->c_vrsn)
		mh_free0(&(ct->c_vrsn));

	if (ct->c_ctline)
		mh_free0(&(ct->c_ctline));

	free_ctinfo(ct);

	/*
	** some of the content types have extra
	** parts which need to be freed.
	*/
	switch (ct->c_type) {
	case CT_MULTIPART:
		free_multi(ct);
		break;

	case CT_MESSAGE:
		if (ct->c_subtype == MESSAGE_PARTIAL) {
			free_partial(ct);
		}
		break;

	case CT_TEXT:
		free_text(ct);
		break;
	}

	if (ct->c_charset)
		mh_free0(&(ct->c_charset));
	if (ct->c_showproc)
		mh_free0(&(ct->c_showproc));
	if (ct->c_storeproc)
		mh_free0(&(ct->c_storeproc));

	if (ct->c_celine)
		mh_free0(&(ct->c_celine));

	/* free structures for content encodings */
	free_encoding(ct, 1);

	if (ct->c_id)
		mh_free0(&(ct->c_id));
	if (ct->c_descr)
		mh_free0(&(ct->c_descr));
	if (ct->c_dispo)
		mh_free0(&(ct->c_dispo));

	if (ct->c_file) {
		if (ct->c_unlink)
			unlink(ct->c_file);
		mh_free0(&(ct->c_file));
	}
	if (ct->c_fp)
		fclose(ct->c_fp);

	if (ct->c_storage)
		mh_free0(&(ct->c_storage));
	if (ct->c_folder)
		mh_free0(&(ct->c_folder));

	mh_free0(&ct);
}


/*
** Free the linked list of header fields
** for this content.
*/

void
free_header(CT ct)
{
	HF hp1, hp2;

	hp1 = ct->c_first_hf;
	while (hp1) {
		hp2 = hp1->next;

		mh_free0(&(hp1->name));
		mh_free0(&(hp1->value));
		mh_free0(&hp1);

		hp1 = hp2;
	}

	ct->c_first_hf = NULL;
	ct->c_last_hf  = NULL;
}


void
free_ctinfo(CT ct)
{
	char **ap;
	CI ci;

	ci = &ct->c_ctinfo;
	if (ci->ci_type) {
		mh_free0(&(ci->ci_type));
	}
	if (ci->ci_subtype) {
		mh_free0(&(ci->ci_subtype));
	}
	for (ap = ci->ci_attrs; *ap; ap++) {
		mh_free0(ap);
	}
	if (ci->ci_comment) {
		mh_free0(&(ci->ci_comment));
	}
	if (ci->ci_magic) {
		mh_free0(&(ci->ci_magic));
	}
}


static void
free_text(CT ct)
{
	struct text *t;

	if (!(t = (struct text *) ct->c_ctparams))
		return;

	mh_free0(&t);
}


static void
free_multi(CT ct)
{
	struct multipart *m;
	struct part *part, *next;

	if (!(m = (struct multipart *) ct->c_ctparams))
		return;

	if (m->mp_start)
		mh_free0(&(m->mp_start));
	if (m->mp_stop)
		mh_free0(&(m->mp_stop));

	for (part = m->mp_parts; part; part = next) {
		next = part->mp_next;
		free_content(part->mp_part);
		mh_free0(&part);
	}

	mh_free0(&m);
}


static void
free_partial(CT ct)
{
	struct partial *p;

	if (!(p = (struct partial *) ct->c_ctparams))
		return;

	if (p->pm_partid)
		mh_free0(&(p->pm_partid));

	mh_free0(&p);
}


/*
** Free data structures related to encoding/decoding
** Content-Transfer-Encodings.
*/

void
free_encoding(CT ct, int toplevel)
{
	CE ce;

	if (!(ce = ct->c_cefile))
		return;

	if (ce->ce_fp) {
		fclose(ce->ce_fp);
		ce->ce_fp = NULL;
	}

	if (ce->ce_file) {
		if (ce->ce_unlink)
			unlink(ce->ce_file);
		mh_free0(&(ce->ce_file));
	}

	if (toplevel) {
		mh_free0(&ce);
	} else {
		ct->c_ceopenfnx = NULL;
	}
}


void
freects_done()
{
	CT *ctp;

	if ((ctp = cts)) {
		for (; *ctp; ctp++){
			free_content(*ctp);
		}
	}
}
