static char rcsid[] = "@(#)$Id: parse_util.c,v 1.29 2006/05/30 16:33:21 hurtta Exp $";


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

#include "def_melib.h"
#include "s_me.h"

DEBUG_VAR(Debug,__FILE__,"header");

static void header_panic P_((char *,int,char *, char *)); /* Prototype */
static void header_panic(f,ln,pr,ms) 
     char * f;
     int ln;
     char *pr;
     char *ms;
{
     panic("HEADER PANIC",f,ln,pr,ms,0);
}

long skip_envelope(hdr, fp)
     struct header_rec *hdr;
     FILE *fp;
{
  char buf[STRING];
  int tmp;
  int first_line = TRUE;

  long result = hdr->offset;

  if (0 !=  fseek(fp,hdr->offset,SEEK_SET)) {
    lib_error(CATGETS(elm_msg_cat, MeSet, MeFailedSeekEnvelope,
		      "Failed to seek beginning of mail envelope (%ld)"),
	      hdr->offset);
    DPRINT(Debug,7,(&Debug,
		    "skip_envelope=-1 (fseek error)\n"));

    return -1;
  }

  DPRINT(Debug,9,(&Debug,
		  "skip_envelope: scanning offset: %ld\n",
		  result));;

  while (0 < (tmp = mail_gets(buf,sizeof(buf),fp))) {
      DPRINT(Debug,15,(&Debug,		      
		      "skip_envelope: len=%d, got: %s\n",tmp,buf));
#ifdef MMDF
    if (0 == strcmp(buf,MSG_SEPARATOR))
      continue;
#endif
    if (0 == strncmp(buf,"From ",5)) {
      first_line = FALSE;
      continue;
    }
    if (!first_line && first_word_nc(buf, ">From"))
      continue;
    DPRINT(Debug,15,(&Debug,
		     "skip_envelope: got headers: %s\n",buf));
    break;
  }
  result = ftell(fp) - tmp;

  DPRINT(Debug,9,(&Debug,
		  "skip_envelope: beginning of headers=%ld\n",result));
  if (0 !=  fseek(fp,result,SEEK_SET)) {
      lib_error(CATGETS(elm_msg_cat, MeSet, MeFailedSeekHeaders,
			"Failed to seek beginning of mail headers (%ld)"),
		result);
      DPRINT(Debug,7,(&Debug,
		      "skip_envelope=-1 (fseek error)\n"));
    return -1;
  }

  DPRINT(Debug,9,(&Debug,
		  "skip_envelope=%ld\n",result));
  return result;
}

header_list_ptr file_read_headers(fp, flag) 
     FILE * fp;
     int flag;
{
    in_state_t state;
    
    header_list_ptr result;
    
    in_state_clear(&state,STATE_in_file);
    
    set_in_state_file(fp,&state);
    
    result = state_read_headers(&state, flag);
    
    in_state_destroy(&state);
    
    return result;
}

header_list_ptr state_read_headers(s, flag) 
     in_state_t * s;
     int flag;
{
    char buffer[32*1024+1];
    int size;

    header_list_ptr result = NULL, last = NULL;
    
    DPRINT(Debug,12,(&Debug,
		     "state_read_headers() --> START\n"));
    
    while ((size = state_read_hdr_line(s,buffer,sizeof buffer,
				       RHL_CHECK_HEADER|flag)) > 0) {
	char * k;
	if (1 == size && 0 == strcmp(buffer,"\n"))
	    break;
	k = strchr(buffer,':');
	if (!k)
	    break;
	*k = '\0';
	k++;

	while (whitespace(*k))
	    k++;

	update_header_list(&result,&last,buffer,k);
		
    }
    
    DPRINT(Debug,12,(&Debug,
		     "state_read_headers()=%p <-- END\n",result));
    return result;
}


void state_write_raw_header(dest_file,next)
     out_state_t   * dest_file;
     header_list_ptr next;
{
    char body[ 32 * 1024 + 1];  /* Allow 32 KB headers after
				   unfolding
				*/
    char * ptr;
    int first = 1;
    
    strfcpy(body,next->body, sizeof body);

    /* NOTE:  strtok skips empty fields
       therefore it does NOT return 
       ptr == body on first time when called
       if there was folding (ie nl) immediately
       after header name ....
       in other words if body[] starts with \n
    */
	
    for (ptr = strtok(body,"\n"); ptr; ptr = strtok(NULL,"\n")) { 

	state_add_prefix(dest_file);

	if (!first) { /* Do folding */

	    if (ptr <= body)
		panic("FILE PANIC",__FILE__,__LINE__,
		      "state_write_raw_header",
		      "ptr not advanced",0);
	    
	    --ptr;
	    if (*(ptr+1) == ' ')
		*ptr = ' ';
	    else
		*ptr = '\t';
	} else {
	    state_puts(give_header_name(next->header_name),dest_file);

	    state_puts(": ",dest_file);

	    first = 0;
	}

	state_puts(ptr,dest_file);		    
	/* 	state_nlputs or state_printf is needed for 
		EOLN_is_CRLF conversions 
	*/
	state_nlputs("\n",dest_file);
    }
}

int NULL_header_filter(hdr,flag)
     header_list_ptr hdr;
     int flag;
{
  if (hdr -> magic != HEADER_magic)
    header_panic(__FILE__,__LINE__,"NULL_header_filter","Bad magic number");

  flag++;      /* So that flag is used */
  return 1;
}


void state_write_header(s,next,demime,defcharset)
     out_state_t   * s;
     header_list_ptr next;
     int             demime;
     charset_t          defcharset;
{
    struct string *buffer = NULL;
    int X,L1;
    charset_t Y;
    int j;

    DPRINT(Debug,13,(&Debug,
		     "state_write_header: Writing header '%s': demime=%d defcharset=%s (charset filter=%s)",
		     give_header_name(next->header_name),
		     demime,
		     defcharset && defcharset -> MIME_name ?
		     defcharset -> MIME_name : "<not set>",
		     s -> filter && s -> filter -> MIME_name ?
		     s -> filter -> MIME_name : "<not set>"));

    buffer = give_decoded_header(next,demime,defcharset);
    
    DPRINT(Debug,13,(&Debug, " (header data charset=%s)\n",
		     buffer -> string_type -> MIME_name ?
		     buffer -> string_type -> MIME_name :
		     "<not set>"));

    /* Use current header charset as filter .... */
    Y = s->filter;

    for (j = 0; s->display_charset[j]; j++) {

	DPRINT(Debug,13,(&Debug,
			 "   output charset [%d]: %s\n",
			 j,
			 s -> display_charset[j] -> MIME_name ?
			 s -> display_charset[j] -> MIME_name :
			 "<no MIME name>"));

	if (match_charset_name(s->display_charset[j], buffer->string_type)) {
	    s->filter = buffer->string_type;

	    DPRINT(Debug,13,(&Debug,
			     "state_write_header: Setting charset filter to %s\n",
			     s -> filter -> MIME_name ?
			     s -> filter -> MIME_name : "<no MIME name>"));
	}
    }

    state_add_prefix(s);
    state_puts(give_header_name(next->header_name),s);
    state_puts(": ",s);
    
    L1 = string_len(buffer);
    
    for (X = 0; X < L1; ) {
	int len = 0;
	uint16 ch = 0;
	struct string * data;
	int oldX = X;
	
	while (X + len < L1) {
	    ch = give_unicode_from_string(buffer,X+len);
	    
	    if (0x000C   /* FF */ == ch ||
		0x000B   /* VT */ == ch ||
		0x000A   /* LF */ == ch)
		break;
	    len++;		  
	} 
	
	/* clip_from_string updates X */
	data = clip_from_string(buffer,&X,len);
	
	if (oldX > 0) {
	    /* folding ...*/
	    state_add_prefix(s);
	    state_putc('\t',s);
	}
	
	state_printf(s,FRM("%S"),data);
	state_putc('\n',s);
	X++;
	
	free_string(&data);
    }
    
    if (0 == X) {
	/* No newline printed so print it now ... 

	   state_nlputs or state_printf is needed for EOLN_is_CRLF
	   conversions 
	*/	
	state_nlputs("\n",s);
    }
    free_string(&buffer);

    s->filter = Y;
}

void state_write_headers(s,hdr,filter,flag,demime,defcharset) 
     out_state_t      * s;
     header_list_ptr    hdr;
     header_filter    * filter;
     int                flag;
     int                demime;
     charset_t          defcharset;
{
    header_list_ptr next = hdr;
    int ret;

    DPRINT(Debug,10,(&Debug,
		     "state_write_headers: Writing headers: demime=%d defcharset=%s (charset filter=%s output charset=%s)\n",
		     demime,
		     defcharset && defcharset -> MIME_name ?
		     defcharset -> MIME_name : "<not set>",
		     s -> filter && s -> filter -> MIME_name ?
		     s -> filter -> MIME_name : "<not set>",
		     s -> display_charset[0] && 
		     s -> display_charset[0] -> MIME_name ?
		     s -> display_charset[0] -> MIME_name :
		     "<not set>"));

    
    for (next = hdr; next; next = next -> next_header) {
	
	if (next -> magic != HEADER_magic)
	    header_panic(__FILE__,__LINE__,"state_write_headers",
			 "Bad magic number");
	
	if (! (ret = filter(next,flag))) {
	    DPRINT(Debug,12,(&Debug,
			     "state_write_headers: header='%s', {filter}=%d FILTERED\n",
			     give_header_name(next->header_name), ret));
	    continue;
	} else {
	    DPRINT(Debug,12,(&Debug,
			     "state_write_headers: header='%s', {filter}=%d PASSED\n",
			     give_header_name(next->header_name), ret));
	}
	
	state_write_header(s,next,demime,defcharset);
    }
}

void state_write_raw_headers(s,hdr,filter,flag) 
     out_state_t      * s;
     header_list_ptr    hdr;
     header_filter    * filter;
     int                flag;
{
    header_list_ptr next = hdr;
    int ret;

    DPRINT(Debug,10,(&Debug,
		     "state_write_raw_headers: Writing headers: (charset filter=%s output charset=%s)\n",
		     s -> filter && s -> filter -> MIME_name ?
		     s -> filter -> MIME_name : "<not set>",
		     s -> display_charset[0] && 
		     s -> display_charset[0] -> MIME_name ?
		     s -> display_charset[0] -> MIME_name :
		     "<not set>"));

    
    for (next = hdr; next; next = next -> next_header) {
	
	if (next -> magic != HEADER_magic)
	    header_panic(__FILE__,__LINE__,"state_write_raw_headers",
			 "Bad magic number");
	
	if (! (ret = filter(next,flag))) {
	    DPRINT(Debug,12,(&Debug,
			     "state_write_raw_headers: header='%s', {filter}=%d FILTERED\n",
			     give_header_name(next->header_name), ret));
	    continue;
	} else {
	    DPRINT(Debug,12,(&Debug,
			     "state_write_raw_headers: header='%s', {filter}=%d PASSED\n",
			     give_header_name(next->header_name), ret));
	}
	
	state_write_raw_header(s,next);
    }
}



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


syntax highlighted by Code2HTML, v. 0.9.1