/*
  $NiH: mime.c,v 1.17 2002/04/16 22:46:07 wiz Exp $

  mime.c -- MIME header parsing
  Copyright (C) 2002 Dieter Baron and Thomas Klausner

  This file is part of cg, a program to assemble and decode binary Usenet
  postings.  The authors can be contacted at <nih@giga.or.at>

  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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "mime.h"

void _mime_lws(char **s);
symbol _mime_token(char **s);
char * _mime_value(char **s);

#define MIME_MAX 14

char *mime_string[MIME_MAX] = {
    "message/partial",
    "message/multipart",
    "multipart/mixed",
    "7bit",
    "8bit",
    "base64",
    "quoted-printable",
    "x-uuencode",
    "filename",
    "name",
    "boundary",
    "id",
    "number",
    "total"
};

symbol mime_sym[MIME_MAX];



void
mime_init(void)
{
    int i;

    for (i=0; i<MIME_MAX; i++)
	mime_sym[i] = intern(mime_string[i]);
}



void
mime_free(struct mime_hdr *m)
{
    int i;

    if (m == NULL)
	return;

    for (i=0; m->option[i].name; i++)
	free(m->option[i].value);

    free(m->option);
    free(m);
}



struct mime_hdr *
mime_parse(char *h)
{
    struct mime_hdr *m;
    struct mime_opt o[256];
    int i;

    if ((m=(struct mime_hdr *)malloc(sizeof(struct mime_hdr))) == NULL)
	return NULL;

    if ((m->type=_mime_token(&h)) == NULL) {
	free(m);
	return NULL;
    }

    i = 0;

    _mime_lws(&h);
    while (*h == ';') {
	h++;

	if ((o[i].name=_mime_token(&h)) == NULL) {
	    break;
	}
	_mime_lws(&h);
	if (*h == '=') {
	    h++;
	    o[i].value = _mime_value(&h);
	}
	else
	    o[i].value = NULL;

        i++;
	/* XXX: handle buffer overrun */
    }

    o[i].name = o[i].value = NULL;
    i++;

    if ((m->option=(struct mime_opt *)malloc(sizeof(struct mime_opt)*i))
	== NULL) {
	free(m);
	while (i)
	    free(o[--i].value);
	return NULL;
    }
    memcpy(m->option, o, sizeof(struct mime_opt)*i);

    return m;
}



symbol
_mime_token(char **s)
{
    symbol m;
    char c, *p;

    _mime_lws(s);
    p = *s+strcspn(*s, " \t()<>@,;:\\\"[]?=");
    c = *p;
    *p = '\0';
    if (strlen(*s) > 0)
	m = intern_lower(*s);
    else
	m = 0;
    *p = c;
    *s = p;
    return m;
}



void
_mime_lws(char **s)
{
    /* XXX: handle () comments */

    *s += strspn(*s, " \t");
}



char *
_mime_value(char **s)
{
    static char b[8192];
    char *p, *r, c;
    int i;

    i=0;
    _mime_lws(s);

    if (**s == '"') {
	/* quoted string */
	p = *s;
	for (;;) {
	    switch (*(++p)) {
	    case '"':
		p++;
		/* fallthrough */
	    case '\0':
		b[i++]='\0';
		*s = p;
		return strdup(b);
	    case '\\':
		if (*p == '\0') {
		    b[i++]='\0';
		    *s = p;
		    return strdup(b);
		}
		else
		    b[i++]=*(++p);
		break;
	    default:
		b[i++]=*p;
		break;
	    }
	}
    }
    else {
	/* token */
	p = *s+strcspn(*s, " \t()<>@,;:\\\"[]?=");
	c = *p;
	*p = '\0';
	if (strlen(*s) > 0)
	    r = strdup(*s);
	else
	    r = NULL;
	*p = c;
	*s = p;
	return r;
    }
}



char *
mime_option_get(struct mime_hdr *m, symbol name)
{
    int i;

    for (i=0; m->option[i].name; i++)
	if (m->option[i].name == name)
	    return m->option[i].value;

    return NULL;
}


syntax highlighted by Code2HTML, v. 0.9.1