/*
 * Copyright (c) 1986, 1987, 1988 by The Trustees of Columbia University
 * in the City of New York.  Permission is granted to any individual or
 * institution to use, copy, or redistribute this software so long as it
 * is not sold for profit, provided this copyright notice is retained.
 */

#ifndef lint
static char *rcsid = "$Header: parsemsg.c,v 1.11 88/06/07 20:27:04 howie Exp $";
#endif

#include "mm.h"
#include "parse.h"
#include "cmds.h"
#include "message.h"

extern msgvec *cf;

keywrd header_keys[] = {
    { "to", 0, TO },
    { "cc", 0, CC },
    { "bcc", 0, BCC },
    { "from", 0, FROM },
    { "date", 0, DATE },
    { "subject", 0, SUBJECT },
    { "reply-to", 0, REPLY_TO },
    { "in-reply-to", 0, IN_REPLY_TO },
    { "resent-to", 0, RESENT_TO },
    { "resent-date", 0, RESENT_DATE },
    { "resent-from", 0, RESENT_FROM },
    { "sender", 0, SENDER },
    { "references", 0, REFERENCES },
    { "comments", 0, COMMENTS },
    { "message-id", 0, MESSAGE_ID },
    { "keywords", 0, KEYWORDS },
    { "encrypted", 0, ENCRYPTED },
    { "received", 0, RECEIVED },
};

static keytab header_tab = { (sizeof(header_keys)/ sizeof(keywrd)),
				 header_keys };

static brktab hdrbrk = {		/* break table for remote user name */
    {					/* letters only in first position */
      0xff, 0xff, 0xff, 0xff, 0xf7, 0xfa, 0x00, 0x3f,
      0x80, 0x00, 0x00, 0x16, 0x80, 0x00, 0x00, 0x1f
    },
    {					/* letters, digits and hyphens here */
      0xff, 0xff, 0xff, 0xff, 0xb2, 0xe8, 0x00, 0x3f,
      0x80, 0x00, 0x00, 0x16, 0x80, 0x00, 0x00, 0x1f
    }					/* (also +%_.!) */
};

static fdb header_fdb = { _CMKEY, 0, nil, (pdat) &header_tab,"header field, ",
			  NULL, &hdrbrk};
static fdb other = { _CMFLD, FLD_EMPTY, NULL, NULL, NULL, NULL, &hdrbrk };
static fdb colon = { _CMTOK, 0, nil, (pdat) ":" };
static fdb text = { _CMTXT };

/*
 * take a 'text' mail message, and convert it to internal format.
 * parse out all of the headers, etc.
 */
static mail_msg mesg;

mail_msg *
parse_msg(msg)
message *msg;
{
    char *s = msg->text, *next_header();
    char *s1, *realloc(), *malloc();
    char *save;
    char *linebeg;
    char c;
    int next;
    int retval;
    pval pv;
    fdb *used;
    int parselen;
    headers *h, *new_header();
    int len;
    keylist match_keylist();

    bzero (&mesg, sizeof (mail_msg));
    while(s1 = next_header(&s,&next)) {
	int l;
	stripspaces(s1);
	l = strlen(s1);
	s1 = realloc(s1, strlen(s1) + 2);
	s1[l] = '\0';
	strcat(s1, "\n");
	retval = match(s1, strlen(s1), fdbchn(&header_fdb,
				     &other,
				     NULL), &pv, &used, &parselen);
	if (retval == CMxOK) {
	    char *name = malloc(parselen+1);
	    strncpy(name,s1,parselen);
	    name[parselen] = '\0';
	    s1 += parselen;
	    if (used == &header_fdb) {
		int which = pv._pvkey;
		if (match(s1, strlen(s1), fdbchn(&colon, nil),
			  &pv, &used, &parselen) == CMxOK) {
		    h = new_header(which, name, HEAD_KNOWN, &mesg);
		    free(name);
		    s1 += parselen;
		}
		else {
		    free(name);
		    break;
		}
		switch(which) {
		case TO:
		case CC:
		case BCC:
		case RESENT_TO:
		    h->address = (addresslist *) malloc(sizeof(addresslist));
		    h->address->first = h->address->last = NULL;
		    match_addresses(h->address, &s1, strlen(s1));
		    break;
		case KEYWORDS:
		    h->keys = match_keylist(s1);
		    if (!(mode& MM_SEND)) {
			keylist k = h->keys, add_keyword();
			while(k && *k) {
			    cf->keywords = add_keyword(*k, cf->keywords);
			    k++;
			}
		    }
		    break;
		case FROM:
		case DATE:
		case SUBJECT:
		case REPLY_TO:
		case IN_REPLY_TO:
		case RESENT_DATE:
		case RESENT_FROM:
		case SENDER:
		case REFERENCES:
		case COMMENTS:
		case MESSAGE_ID:
		case ENCRYPTED:
		case RECEIVED:
		    skip_spaces(&s1);
		    retval = match(s1, strlen(s1), fdbchn(&text,nil), &pv,
				   &used, &parselen);
		    h->string = malloc(parselen+1);
		    strncpy(h->string,s1,parselen);
		    h->string[parselen] = '\0';
		    s1 += parselen;
		    break;
		}
	    }
	    else {
		if (match(s1, strlen(s1), fdbchn(&colon, nil),
			  &pv, &used, &parselen) == CMxOK) {
		    h = new_header(USER_HEADERS, name, HEAD_UNKNOWN,
				   &mesg);
		    free(name);
		    s1 += parselen;
		    skip_spaces(&s1);
		    retval = match(s1, strlen(s1), fdbchn(&text,nil), &pv,
				   &used, &parselen);
		    h->string = malloc(parselen+1);
		    strncpy(h->string,s1,parselen);
		    h->string[parselen] = '\0';
		    s1 += parselen;
		}
		else {
		    free(name);
		    break;
		}
	    }
	}
	else {				/* no CR between headers and body */
	    c = *(s-1); *(s-1) = '\0';	/* remember... */
	    linebeg = rindex (msg->text,'\n'); /* line beg is beg. of body */
	    *(s-1) = c;			/* put that back! */
	    if (linebeg != 0)
		s = linebeg;		/* otherwise, bad s is better than 0 */
	    break;
	}
	if (!next) break;
    }
    len = msg->size - (s - msg->text);
    mesg.body = malloc(len+1);
    strncpy(mesg.body,s,len);
    mesg.body[len] = '\0';
    return(&mesg);
}

