static char rcsid[] = "@(#)$Id: headers.c,v 1.37 2006/07/24 18:45:00 hurtta Exp $";

/******************************************************************************
 *  The Elm (ME+) Mail System  -  $Revision: 1.37 $   $State: Exp $
 *
 *  Author: Kari Hurtta <hurtta+elm@posti.FMI.FI> (was hurtta+elm@ozone.FMI.FI)
 *****************************************************************************/

#include "headers.h"
#include "hdr_imp.h"
#include "s_me.h"

DEBUG_VAR(Debug,__FILE__,"header");

static unsigned char * us_str P_((char *str));
static unsigned char * us_str(str)
     char *str;
{
    return (unsigned char *)str;
}


/* MIME header decode routines .........................................   */


static struct string * hdr_decode_from_text P_((header_list_ptr hdr,
						int demime,
						charset_t defcharset));
static struct string * hdr_decode_from_text(hdr,demime,defcharset)
     header_list_ptr hdr;
     int demime;
     charset_t defcharset;
{
    struct string * result = NULL;

    result = hdr_to_string(HDR_TEXT,hdr->body,defcharset,demime);

    return result;
}

static struct string * hdr_decode_from_raw P_((header_list_ptr hdr,
					       int demime, 
					       charset_t defcharset));

static struct string * hdr_decode_from_raw(hdr,demime,defcharset)
     header_list_ptr hdr;
     int demime;
     charset_t defcharset;
{
    struct string * result = NULL;

    result = new_string2(defcharset,us_str(hdr->body));

    return result;
}

static struct string * decode_comment P_((char * token,int demime, 
					  charset_t defcharset));

static struct string * decode_comment(token,demime,defcharset)
     char * token;
     int demime;
     charset_t defcharset;
{
    struct string *result = new_string(defcharset);
    struct string *newresult = NULL;
    struct string *R = NULL;

    int k,j=0;
    char buffer[1000];
    
    for (k = 1; (token[k] != ')' || token[k+1]) &&
	     j < sizeof buffer -1; k++)
	buffer[j++] = token[k];
    buffer[j] = '\0';
    
    R = hdr_to_string(HDR_COMMENT,buffer,defcharset,demime);
    
    /* HACK */
    add_streambyte_to_string(result,'(');
    add_streambyte_to_string(R,')');
    
    /* Now compine strings */
    newresult = cat_strings(result,R,1);
    free_string(&result);
    result = newresult;

    free_string(&R);
    return result;
}


static struct string * hdr_decode_from_comment P_((header_list_ptr hdr,
					       int demime, 
					       charset_t defcharset));

static struct string * hdr_decode_from_comment(hdr,demime,defcharset)
     header_list_ptr hdr;
     int demime;
     charset_t defcharset;
{
    struct string * result = new_string(defcharset);
    int i;

    char ** tokens = rfc822_tokenize(hdr->body);

    for (i = 0; tokens[i]; i++) {
	struct string * R = NULL, * newresult;

	if ('(' == tokens[i][0]) {
	    R = decode_comment(tokens[i],demime,defcharset);
	} else {
	    R = new_string2(defcharset,us_str(tokens[i]));
	}

	/* Now compine strings */
	newresult = cat_strings(result,R,1);
	free_string(&result);
	result = newresult;

	free_string(&R);
    }

    free_rfc822tokenized(tokens);

    return result;
}



static struct string * hdr_decode_from_phrase P_((header_list_ptr hdr,
						  int demime, 
						  charset_t defcharset));
static struct string * hdr_decode_from_phrase(hdr,demime,defcharset)
     header_list_ptr hdr;
     int demime;
     charset_t defcharset;
{
    struct string * result = new_string(defcharset);
    int i;

    char ** tokens = rfc822_tokenize(hdr->body);

    for (i = 0; tokens[i]; i++) {
	struct string * R = NULL, * newresult;
	
	if ('\n' == tokens[i][0] &&
	    !tokens[i+1])
	    break;

	if (whitespace(tokens[i][0]) || '\n' == tokens[i][0]) {
	    R = new_string(defcharset);
	    add_ascii_to_string(R,us_str(tokens[i]));

	} else if ('(' == tokens[i][0]) {
	    R = decode_comment(tokens[i],demime,defcharset);

	} else if ('<' == tokens[i][0]) {
	    int j;
	    
	    /* Add mising space wetween phrase and < > */
	    if (i > 0)
		add_ascii_to_string(result,us_str(" ")); 

	    R = new_string(defcharset);
	    add_ascii_to_string(R,us_str(tokens[i]));
	    

	    for (j = i+1; tokens[j] && tokens[j][0] != '>'; j++) {
		
		if ('(' == tokens[i][0]) {
		    struct string * R1 = decode_comment(tokens[j],
							demime,defcharset);
		    
		    /* Now combine strings */
		    newresult = cat_strings(result,R1,1);
		    free_string(&R);
		    R = newresult;
		    
		} else
		    add_ascii_to_string(R,us_str(tokens[j]));
		i = j;
	    }
	    
	    if (tokens[j]) {
		add_ascii_to_string(R,us_str(tokens[j]));
		i = j;
	    }
	} else {
	    char * buffer = NULL;
	    int j;
	    int ph = give_dt_enumerate_as_int(&phrase_display_mode);


	    for (j = i; tokens[j]; j++) {
		if ('(' == tokens[j][0]) 
		    break;
		else if ('<' == tokens[j][0]) 
		    break;
		else if ('\n' == tokens[j][0] && !tokens[j+1])
		    break;

		i = j;

		buffer = strmcat(buffer,tokens[j]);	
	    }

	    R = hdr_to_string(HDR_PHRASE,buffer,defcharset,demime);	    

	    switch (ph) {
	    case 0: 
		break;
	    default:
		/* We do not (backslash) quote displayed (only) text */
		
		add_ascii_to_string(result,us_str("\""));
		add_ascii_to_string(R,us_str("\""));
		break;
	    }

	    free(buffer);
	}

	/* Now combine strings */
	newresult = cat_strings(result,R,1);
	free_string(&result);
	result = newresult;

	free_string(&R);
    }

    free_rfc822tokenized(tokens);

    return result;
}


static struct string * hdr_decode_from_addr P_((header_list_ptr hdr,
					       int demime, 
					       charset_t defcharset));
static struct string * hdr_decode_from_addr(hdr,demime,defcharset)
     header_list_ptr hdr;
     int demime;
     charset_t defcharset;
{
    struct string * result = new_string(defcharset);

    char ** tokens = rfc822_tokenize(hdr->body);
    int tokcount = 0;
    int ptr = 0;
    int bracket = 0;
    int lastptr = 0;

    while(tokens[tokcount])
	tokcount++;

    /* Remove LF from end of header */
    if (tokcount > 0 &&
	   '\n' == tokens[tokcount-1][0])
	tokcount--;
    
    /* Walk through addressess ... */

    for (ptr = 0; ptr < tokcount; ptr = lastptr) {
	
	char **scanned = NULL;
	struct string *comments = NULL;
	struct string *newresult = NULL;
	char tok = '\0';

	look_special_tokens(tokens,":<>,;",ptr,&lastptr,demime,
			    defcharset,&comments,&scanned);


	if (lastptr < tokcount) {
	    tok = tokens[lastptr][0];
	    DPRINT(Debug,25,(&Debug, 
			     "hdr_decode_from_addr: [%d] token=%c (%s)\n",
			     lastptr,tok,tokens[lastptr]));
	} else {
	    tok = '\0';
	    DPRINT(Debug,25,(&Debug,
			     "hdr_decode_from_addr: [%d] token=EOS\n",
			     lastptr));
	}

	if (ptr < lastptr) {
	    struct string *R = NULL;

	    if (bracket <= 0 && 
		( ':' == tok ||
		  '<' == tok)) {

		int ph = give_dt_enumerate_as_int(&phrase_display_mode);

		DPRINT(Debug,25,(&Debug, 
			   "hdr_decode_from_addr: Adding phrase\n"));

		R = scanned_to_phrase(scanned,
				      demime,
				      defcharset);		

		switch (ph) {
		case 0: 
		    break;
		default:
		    /* We do not (backslash) quote displayed (only) text */
		    
		    add_ascii_to_string(result,us_str("\""));
		    add_ascii_to_string(R,us_str("\""));
		    break;
		}

	    } else {
		int z;

		DPRINT(Debug,25,(&Debug, 
			   "hdr_decode_from_addr: Adding address\n"));

		R = new_string(defcharset);
		
		for (z = 0; scanned[z]; z++) {
		    if ('\n' == scanned[z][0] && !scanned[z+1]) {
			/* HACK: Ignore */
			DPRINT(Debug,25,(&Debug, 
				   "hdr_decode_from_addr: Ignoring ending LF\n"));
		    } else
			add_ascii_to_string(R,us_str(scanned[z]));
		}
	    }


	    /* Now compine strings */
	    newresult = cat_strings(result,R,1);
	    free_string(&result);
	    result = newresult;
	    
	    free_string(&R);
	} else {
	    DPRINT(Debug,25,(&Debug, 			     
			     "hdr_decode_from_addr: (empty) \n"));
	}


	if (comments) {
	    DPRINT(Debug,25,(&Debug,
			     "hdr_decode_from_addr: Adding comments\n"));
	    
	    add_ascii_to_string(result,us_str(" ("));

	    /* Now compine strings */
	    newresult = cat_strings(result,comments,1);
	    free_string(&result);
	    result = newresult;

	    add_ascii_to_string(result,us_str(")"));
	}
	
	if (lastptr < tokcount) {
	    switch (tok) {
	    case '<':
		bracket++;

		if (ptr < lastptr)
		    add_ascii_to_string(result,us_str(" ")); 


		DPRINT(Debug,25,(&Debug,
				 "hdr_decode_from_addr: bracket=%d\n",
				 bracket));
		
		break;
	    case '>':
		bracket--;
		DPRINT(Debug,25,(&Debug,
				 "hdr_decode_from_addr: bracket=%d\n",
				 bracket));
		break;
	    }
	    DPRINT(Debug,25,(&Debug,
			     "hdr_decode_from_addr: Adding token %s\n",
			     tokens[lastptr]));
	    add_ascii_to_string(result,us_str(tokens[lastptr]));
	    lastptr++;

	    switch (tok) {
	    case ':':
	    case ',':
		if (bracket <= 0)
		    add_ascii_to_string(result,us_str(" "));
		break;
	    }
	}
	
	if (comments)
	    free_string(&comments);
	if (scanned)
	    free_rfc822tokenized(scanned);
    }

    free_rfc822tokenized(tokens);

    return result;
}

#ifdef ANSI_C
static hdr_add_to_mailing_hdr no_add_to_mail_hdr;
#endif
static int no_add_to_mail_hdr(headers,X,value,demime,defcharset,replace)
     struct mailing_headers * headers;
     header_ptr X;
     CONST char *value;
     int demime;
     charset_t defcharset;
     int replace;
{
    return 0;
}

/* ------------------------------------------------------------------------ */

static struct header_info header_types[] = {
    /* From STD 11 (RFC 822): */
    { "Subject",         hdr_decode_from_text, add_subject_hdr },
    { "Comments",        hdr_decode_from_text, no_add_to_mail_hdr },
    { "Return-path",     hdr_decode_from_comment, add_env_from_hdr },
    { "Received",        hdr_decode_from_comment, no_add_to_mail_hdr },
    { "Reply-To",        hdr_decode_from_addr, add_replyto_hdr },  
    { "From",            hdr_decode_from_addr, add_from_hdr },    
    { "Sender",          hdr_decode_from_addr, no_add_to_mail_hdr },    
    { "Resent-Reply-To", hdr_decode_from_addr, no_add_to_mail_hdr },
    { "Resent-From",     hdr_decode_from_addr, no_add_to_mail_hdr },
    { "Resent-Sender",   hdr_decode_from_addr, no_add_to_mail_hdr },
    { "Date",            hdr_decode_from_comment, no_add_to_mail_hdr },
    { "Resent-Date",     hdr_decode_from_comment, no_add_to_mail_hdr },
    { "To",              hdr_decode_from_addr, add_to_hdr }, 
    { "Resent-To",       hdr_decode_from_addr, no_add_to_mail_hdr }, 
    { "cc",              hdr_decode_from_addr, add_cc_hdr }, 
    { "Resent-cc",       hdr_decode_from_addr, no_add_to_mail_hdr }, 
    { "bcc",             hdr_decode_from_addr, add_bcc_hdr }, 
    { "Resent-bcc",      hdr_decode_from_addr, no_add_to_mail_hdr }, 
    { "Message-ID",      hdr_decode_from_comment, no_add_to_mail_hdr },
    { "Resent-Message-ID",  hdr_decode_from_comment, no_add_to_mail_hdr },
    { "In-Reply-To",   hdr_decode_from_phrase, no_add_to_mail_hdr },
    { "References",    hdr_decode_from_phrase, no_add_to_mail_hdr }, 
    { "Keywords",      hdr_decode_from_phrase, no_add_to_mail_hdr },  
    { "Encrypted",     hdr_decode_from_comment, no_add_to_mail_hdr },   

    /* From MIME (RFC 1521) */
    { "MIME-Version",  hdr_decode_from_comment, no_add_to_mail_hdr }, 
    { "Content-Type",  hdr_decode_from_comment, no_add_to_mail_hdr },  
    { "Content-Transfer-Encoding",  hdr_decode_from_comment, 
      no_add_to_mail_hdr },
    { "Content-ID",    hdr_decode_from_comment, no_add_to_mail_hdr },  
    { "Content-Description",       hdr_decode_from_text, no_add_to_mail_hdr },
    /* From RFC 1806 */
    { "Content-Disposition",       hdr_decode_from_comment, no_add_to_mail_hdr },
    /* From RFC 1864 */
    { "Content-MD5",               hdr_decode_from_raw, no_add_to_mail_hdr },

    /* From RFC 2919 */
    { "List-Id",                hdr_decode_from_phrase, no_add_to_mail_hdr }, 

    /* From RFC 2369 */
    { "List-Help",           hdr_decode_from_comment, no_add_to_mail_hdr },  
    { "List-Subscribe",      hdr_decode_from_comment, no_add_to_mail_hdr },  
    { "List-Unsubscribe",    hdr_decode_from_comment, no_add_to_mail_hdr },  
    { "List-Post",           hdr_decode_from_comment, no_add_to_mail_hdr },  
    { "List-Owner",          hdr_decode_from_comment, no_add_to_mail_hdr },  
    { "List-Archive",        hdr_decode_from_comment, no_add_to_mail_hdr },  
    
    /* mailbox format */
    { "Content-Length",            hdr_decode_from_raw, no_add_to_mail_hdr },
    { "Status",                    hdr_decode_from_raw, no_add_to_mail_hdr },

    /* Sendmail */
    { "Full-Name",                 hdr_decode_from_text, no_add_to_mail_hdr },
    { "Return-Receipt-To",         hdr_decode_from_addr, no_add_to_mail_hdr }, 
    { "Auto-Submitted",            hdr_decode_from_comment, 
      no_add_to_mail_hdr },
    { "Precedence",                hdr_decode_from_raw, no_add_to_mail_hdr },
    

    /* IDA Sendmail */
    { "X-Charset",                 hdr_decode_from_raw, no_add_to_mail_hdr },
    { "X-Char-Esc",                hdr_decode_from_raw, no_add_to_mail_hdr },
    
    /* Unknown source */
    { "Action",                    hdr_decode_from_raw, no_add_to_mail_hdr },
    { "Priority",             hdr_decode_from_comment, no_add_to_mail_hdr },
    { "Expires",              hdr_decode_from_comment, no_add_to_mail_hdr },
    { "Importance",           hdr_decode_from_comment, no_add_to_mail_hdr },
    { "Sensitivity",          hdr_decode_from_comment, no_add_to_mail_hdr },

    /* Our non-standard headers */
    { "X-ELM-OSV",                 hdr_decode_from_comment, no_add_to_mail_hdr },
    { "X-Mailer",                  hdr_decode_from_text, no_add_to_mail_hdr },
    { "Content-Name",              hdr_decode_from_text, no_add_to_mail_hdr },
  
    /* Tailer */
    { NULL, hdr_decode_from_raw, no_add_to_mail_hdr }
};


static struct header_info * malloc_header_info P_((const char *name));
static struct header_info * malloc_header_info(name)
     CONST char *name;
{
    struct header_info *ret = safe_malloc(sizeof (*ret));

    bzero((void *)ret, sizeof(*ret));

    ret->header = safe_strdup(name);
    
    if (strincmp(name,"X-",2) == 0) {
	/* Default for user defined headers */
	ret->hdr_decode_from_it =
	    hdr_decode_from_text;
	ret->hdr_add_to_it = add_user_hdr;

    } else {
	/* We don't know it, right? */
	ret->hdr_decode_from_it = hdr_decode_from_raw;
	ret->hdr_add_to_it = no_add_to_mail_hdr;
    }	

    return ret;
}

#define HDR_SCAN_magic		0xFC06

static struct header_scan_list {
    unsigned short            magic;      /* HDR_SCAN_magic */

    struct header_info      * hdr;
    struct header_scan_list * smaller;
    struct header_scan_list * bigger;
} * find_header_1 P_((struct header_scan_list **root,
		      const char *name, int create_flag,
		      struct header_info *init));




static struct header_scan_list * find_header_1(root,name,create_flag,init)
     struct header_scan_list **root;
     const char *name; 
     int create_flag;
     struct header_info *init;
{
    struct header_scan_list *ptr = *root;
    int r;

    if (!ptr) {
	if (!create_flag)
	    return NULL;

	ptr = safe_malloc(sizeof(*ptr));

	bzero((void *)ptr, sizeof(*ptr));

	ptr->magic   = HDR_SCAN_magic;
	if (init)
	    ptr->hdr = init;
	else
	    ptr->hdr     = malloc_header_info(name);
	ptr->smaller = NULL;
	ptr->bigger  = NULL;

	*root = ptr;
	return ptr;
    }
    
    if (ptr->magic  != HDR_SCAN_magic)
	panic("MBX VIEW PANIC",__FILE__,__LINE__,"find_header_1",
	      "Bad magic number",0);

    
    r = istrcmp(name,ptr->hdr->header);
    
    if (0 == r) {

	return ptr;
    } else if (0 < r) {

	return find_header_1(& (ptr->bigger), name, create_flag,
			     init);
    } else {
	
	return find_header_1(& (ptr->smaller), name, create_flag,
			     init);
    }
}

header_ptr find_header(name, create_flag) 
     CONST char *name;
     int create_flag;
{

    static struct header_scan_list * root = NULL;

    struct header_scan_list * tmp;

    if (! root) {
	int i;
	
	for (i = 0; header_types[i].header; i++) {

	    if (! find_header_1(&root, header_types[i].header,
				1, & (header_types[i])))
		panic("MBX VIEW PANIC",__FILE__,__LINE__,"find_header",
		      "Init failure",0);
	    
	    
	}
    }

    tmp = find_header_1(&root, name, create_flag, NULL);

    if (tmp) {
	return tmp->hdr;
    }
  
    return NULL;
}

header_list_ptr locate_header(h,n)
     header_list_ptr h;
     header_ptr n;           /* NOTE: n may be also NULL */
{
    header_list_ptr walk;

    for (walk = h; 
	 walk != NULL; 
	 walk = walk -> next_other_header) {
	if (walk -> magic != HEADER_magic)
	    panic("HEADERS PANIC",__FILE__,__LINE__,"locate_header",
		  "Bad magic number",0);
	if (n == walk -> header_name)
	    return walk;
    }
    return NULL;
}

void update_header_list(list,last1, name, value)
     header_list_ptr *list;
     header_list_ptr *last1;
     CONST char * name;
     CONST char * value;
{
    header_list_ptr result = *list, last = *last1;
    header_list_ptr item, last_this = NULL, walk;

    if (result && !last) {
	last = result;

	DPRINT(Debug,9,(&Debug, 
			"update_header_list: Moving 'last' to end of list ... \n"));

	while (last -> next_header)
	    last = last -> next_header;

    }

    item = (struct header_list *) safe_malloc(sizeof (struct header_list));
    item -> header_name = find_header(name,1);
	
    item -> next_header       = NULL;
    item -> next_this_header  = NULL;
    item -> next_other_header = NULL;
    item -> body              = safe_strdup(value);
    item -> magic             = HEADER_magic;
	
    for (walk = result; 
	 walk != NULL; 
	 last_this = walk, walk = walk -> next_other_header) {
	if (walk -> magic != HEADER_magic)
	    panic("HEADERS PANIC",__FILE__,__LINE__,"update_header_list",
		  "Bad magic number",0);
	if (item -> header_name == walk -> header_name)
	    break;
    }
	
    if (!walk) {
	DPRINT(Debug,9,(&Debug,
			"update_header_list: name='%s': (%p) Not in chain!\n",
			item -> header_name->header,
			item -> header_name));
    }

    if (walk) {  
	while (walk->next_this_header != NULL) {
	    if (walk -> magic != HEADER_magic)
		panic("HEADERS PANIC",__FILE__,__LINE__,"update_header_list",
		      "Bad magic number",0);
	    walk = walk->next_this_header;
	}
	    
	walk->next_this_header = item;
	
	DPRINT(Debug,9,(&Debug,
			"update_header_list: name='%s' -- append next_this_header (%s)\n",
			item->header_name->header,
			walk->header_name->header));
	    	
    } else if (last_this) {
	last_this -> next_other_header = item;
	DPRINT(Debug,9,(&Debug,
			"update_header_list: name='%s' -- append next_other_header (%s)\n",
			item->header_name->header,
			last_this->header_name->header));
    }
    
    if (last) {
	last -> next_header  = item;
	
	DPRINT(Debug,9,(&Debug,
			"update_header_list: name='%s' -- append next_header (%s)\n",
			item->header_name->header,
			last->header_name->header));
	
    } else  {
	result               = item;
	DPRINT(Debug,9,(&Debug,
			"update_header_list: name='%s' -- head of next_header\n",
			item->header_name->header));
    }
    last = item;
    
    *list  = result;
    *last1 = last;
}

void delete_headers(hdr)
     header_list_ptr *hdr;
{
    header_list_ptr next = *hdr;
  
    while(next) {
	if (next -> magic != HEADER_magic)
	    panic("HEADERS PANIC",__FILE__,__LINE__,"delete_headers",
		  "Bad magic number",0);
	
	(*hdr)  = next;
	next = next -> next_header;
	
	if((*hdr) -> body) {
	    free((*hdr) -> body);
	    (*hdr) -> body = NULL;
	}
	(*hdr) -> next_header       = NULL;
	(*hdr) -> next_this_header  = NULL;
	(*hdr) -> next_other_header = NULL;
	(*hdr) -> magic             = 0;
	free((void *)(*hdr));
    }
    (*hdr)  = next;
}




/* Returns ponter to static storage */
CONST char * give_header_name(X)
     header_ptr X;
{
    return X->header;
}

int is_mailing_header(X)
     header_ptr X;
{
    return X->hdr_add_to_it != no_add_to_mail_hdr;
}

struct string * give_decoded_header(hdr,demime,defcharset)
     header_list_ptr hdr;
     int demime;
     charset_t defcharset;
{
    struct string * result = NULL;

    if (hdr -> magic != HEADER_magic)
	panic("HEADERS PANIC",__FILE__,__LINE__,"give_decoded_header",
	      "Bad magic number",0);

    result = hdr->header_name->hdr_decode_from_it(hdr,demime,defcharset);

    return result;
}


int add_to_mailing_header(headers,X,value,demime,defcharset,replace)
     struct mailing_headers * headers;
     header_ptr X;
     CONST char *value;
     int demime;
     charset_t defcharset;
     int replace;
{
    int ret;

    if (headers->magic   != MAIL_HDR_magic) 
    	panic("HEADERS PANIC",__FILE__,__LINE__,"add_to_mailing_header",
	      "Bad magic number",0);

    ret = X->hdr_add_to_it(headers,X,value,demime,defcharset,replace);

    return ret;
}

int read_header_line (fp, buf, size,flag) 
     FILE *fp;
     char *buf;
     int size;
     int flag;
{
  in_state_t state;
  int result;

  in_state_clear(&state,STATE_in_file);

  set_in_state_file(fp,&state);

  result = state_read_hdr_line(&state,buf,size,flag);

  in_state_destroy(&state);

  return result;
}

int state_read_hdr_line (s, buf, size,flag) 
     in_state_t *s;
     char *buf;
     int size;
     int flag;
{
  /* Read and unfold header line -- stores maximum size-1 bytes to buffer
   * (plus \0). Also handle case when headers are eneded either CR LF or LF.
   * Returns number of bytes stored. Always _read_ end of header
   * (even when buffer fills). Returns 0 when reads empty line (only CR LF).
   * That indicates end of headers.
   *
   * If flag & 1 (RHL_MARK_FOLDING) then folding is marked with '\n' 
   * (instead of ' ' and buffer ended with '\n' before '\0'
   * If flag & 2 (RHL_CHECK_HEADER) then check that this was header line...
   */

    int len = 0,c;
    int col_seen = 0;
    long pos = -1;
    
    DPRINT(Debug,12,(&Debug,		    
		     "state_read_hdr_line: size=%d, flag=%d\n",size,flag));
    size--; /* Place for \0 */

    if ( (!in_state_seekable(s) ||
	  (pos = in_state_ftell(s)) < 0) && 
	 (flag & RHL_CHECK_HEADER)) {
	DPRINT(Debug,5,(&Debug,
			"state_read_hdr_line=0; not seekable or ftell failed!"));
	buf[0] = '\0';
	return 0;
    }

#define PUTC(c) { if (len < size) buf[len++] = (c); }
  
  while (EOF != (c = state_getc(s))) {
    if ('\r' == c) {                /* Is this CR LF sequence ? */
      if (EOF == (c = state_getc(s)))
	break;
      if (c != '\n') 
	PUTC('\r');
    }
    if (c == '\n') {                /* Read CR LF or LF, check folding */
      if (!col_seen && len > 0 && (flag & RHL_CHECK_HEADER)) {
      bad_header_line:
	  DPRINT(Debug,12,(&Debug,
			   "state_read_hdr_line: Not ':' seen. Not a header line!\n"));
	if (0 != in_state_fseek(s,pos)) {
	    DPRINT(Debug,5,(&Debug,
			    "read_header_line: seek failed!\n"));
	}
	len = 0;
      }
      if (len == 0)
	break;                      /* End of headers ! */
      if (EOF == (c = state_getc(s)))
	break;
      if (c != ' ' && c != '\t') {   /* Not a continuation line */
	state_ungetc(c,s);
	break;
      }
      /* CRLF LWSP sequence should be replaced with ' ' */
      c = ' ';
      if (flag & RHL_MARK_FOLDING)
	c = '\n';
    }
    /* Space before ':' ? */
    if ((' ' == c || '\t' == c) && !col_seen && (flag & RHL_CHECK_HEADER)) {
      /* Skip to next ':' */
      while (' ' == c || '\t' == c)
	c = state_getc(s);
      if (':' != c) 
	goto bad_header_line;
    }
    if (':' == c)
      col_seen = 1;
    PUTC(c);
  }

  if (flag & RHL_MARK_FOLDING) {
    PUTC('\n');
  }

#undef PUTC
  buf[len] = 0;

  DPRINT(Debug,12,(&Debug,
		   "state_read_hdr_line: len=%d, buf=%s\n",len,buf));

  return len;
}

/*
 * Local Variables:
 *  mode:c
 *  c-basic-offset:4
 *  buffer-file-coding-system: iso-8859-1
 * End:
 */



syntax highlighted by Code2HTML, v. 0.9.1