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


/******************************************************************************
 *  The Elm (ME+) Mail System  -  $Revision: 1.3 $   $State: Exp $
 *
 *  Author: Kari Hurtta <hurtta+elm@posti.FMI.FI>
 *      or  Kari Hurtta <elm@elmme-mailer.org>
 ******************************************************************************
 * Some minor part of code based on code utils/readmsg.c
 * That code was following copyright:
 *
 *  The Elm Mail System 
 *
 *			Copyright (c) 1988-1992 USENET Community Trust
 *			Copyright (c) 1986,1987 Dave Taylor
 *****************************************************************************/

#include "def_readmsg.h"

DEBUG_VAR(Debug,__FILE__,"readmsg");

#include <errno.h>
#ifndef ANSI_C
extern int errno;
#endif

static struct folder_state fstate;	/* information from external state file	*/

static int have_fstate_called = 0;

int have_fstate()
{
     zero_ldstate(&fstate);

     have_fstate_called = 1;

     if (load_folder_state_file(&fstate) != 0)
       return -1;

     return fstate.storage != NULL;
}


#if ANSI_C
#define S_(x) static x;
#else
#define S_(x)
#endif

struct fstate_data {

    FILE ** fp_vec;
    int     fp_vec_len;

    struct msgdata {
	int fpnum;  	
	long offset; 	
	long content_len;

	struct header_rec *entry;
    } * messages;
    int messages_len;
};


S_(init_folder_handler_f init_fstate_handler)
static void init_fstate_handler P_((struct folder_handler *H));
static void init_fstate_handler(H)
     struct folder_handler *H;
{
    H->d.fstate = safe_malloc(sizeof (* H->d.fstate));

     /* bzero is defined hdrs/defs.h */
    bzero((void *)H->d.fstate,sizeof (* H->d.fstate));

    H->d.fstate->fp_vec     = NULL;
    H->d.fstate->fp_vec_len = 0;

    H->d.fstate->messages     = NULL;
    H->d.fstate->messages_len = 0;
}



S_(free_folder_handler_f free_fstate_handler)
static void free_fstate_handler P_((struct folder_handler *H));
static void free_fstate_handler(H)
     struct folder_handler *H;
{
    
    if (H->d.fstate->fp_vec) {
	int i;

	for ( i = 0; i < H->d.fstate->fp_vec_len; i++) {
	    if (H->d.fstate->fp_vec[i]) {

		fclose(H->d.fstate->fp_vec[i]);
		H->d.fstate->fp_vec[i] = NULL;

	    }	    
	}

	free(H->d.fstate->fp_vec);
	H->d.fstate->fp_vec = NULL;
    }
    H->d.fstate->fp_vec_len = 0;

    if (H->d.fstate->messages) {
	int i;

	for (i = 0; i < H->d.fstate->messages_len; i++) {
	    if (H->d.fstate->messages[i].entry) 
		free_header_helper(& (H->d.fstate->messages[i].entry));	   
	}

	free(H->d.fstate->messages);
	H->d.fstate->messages = NULL;

    }
    H->d.fstate->messages_len = 0;

    free(H->d.fstate);
    H->d.fstate = NULL;
}

static void parser_helper1 P_((struct msgdata *X, FILE *F));
static void parser_helper1(X, F)
     struct msgdata *X;
     FILE *F;
{
    long content_start;

    struct header_rec * entry = X->entry;
    header_list_ptr hdrs      = file_read_headers(F,0);

    read_folder_headers_helper(entry,hdrs);
    mime_parse_helper(entry,hdrs);

    content_start = ftell(F);

    start_body_helper(entry,content_start,hdrs);

    delete_headers(&hdrs);
}

				 
long separator_helper(entry,errret,print_separator,env_buffer,F)
     struct header_rec * entry; 
     enum message_error *errret;
     int print_separator;
     char **env_buffer;
     FILE * F;
{
    char buf[LONG_STRING];
    int buf_len;
    int first_line = 0;
    long ZZ;

    while (0 < (buf_len = mail_gets(buf,sizeof(buf),F))) {
      DPRINT(Debug,15,(&Debug,		      
		       "separator_helper: len=%d, got: %s\n",
		       buf_len,buf));
#ifdef MMDF
      if (0 == strcmp(buf,MSG_SEPARATOR)) {
	  
	  first_line = 0;

	  if (print_separator)
	      fputs(buf,stdout);
	  continue;
      }
#endif

      if (0 == strncmp(buf,"From ",5)) {
	  first_line = 0;

	  if (! real_from(buf, entry)) {
	      *errret = error_start;
	      return -1;
	  }
	      
	  if (print_separator)
	      fputs(buf,stdout);

	  if (env_buffer)
	      *env_buffer = strmcat(*env_buffer,buf);

	  continue;
      }

      if (!first_line && first_word_nc(buf, ">From")) {
	  if (print_separator)
	      fputs(buf,stdout);

	  if (env_buffer)
	      *env_buffer = strmcat(*env_buffer,buf);
	  continue;
      }
      
      break;
    }

    if (first_line) {
	*errret = error_start;
	return -1;	
    }

    ZZ = ftell(F) - buf_len;


    return ZZ;
}



S_(give_message_from_folder_f give_message_from_fstate)
static FILE * give_message_from_fstate P_((struct folder_handler *folder,
					   int idx,
					   long *content_length,
					   enum message_error *errret,
					   int print_separator,
					   char **env_buffer,
					   struct header_rec **entryret));

static FILE * give_message_from_fstate(folder,idx,content_length,
				       errret,print_separator,env_buffer,
				       entryret) 
     struct folder_handler *folder;
     int idx;
     long *content_length;
     enum message_error *errret;
     int print_separator;
     char **env_buffer;
     struct header_rec **entryret;
{
    FILE *ret;
    struct fstate_data   * fst = folder->d.fstate;
    long offset;
    int need_parse = 0;
    long ZZ;

    if (idx < 0  || idx >= folder->num_messages ||
	idx >= fst->messages_len) 
	panic("READMSG PANIC",__FILE__,__LINE__,"give_message_from_fstate",
	      "Bad index",0);

    *errret = error_none;

    offset = fst->messages[idx].offset;
    if (-1 == offset)
	return NULL;
    if (-1 == fst->messages[idx].fpnum)
	return NULL;

    if (fst->messages[idx].fpnum < 0 ||	
	fst->messages[idx].fpnum >= fst->fp_vec_len)
	panic("READMSG PANIC",__FILE__,__LINE__,"give_message_from_fstate",
	      "Bad fpnum",0);

    ret = fst->fp_vec[fst->messages[idx].fpnum];
    if (!ret)
	return NULL;

    if (fseek(ret, offset, SEEK_SET) == -1) {
	int err = errno;
	DPRINT(Debug,1,(&Debug, 
			
			"give_message_from_fstate: Couldn't seek folder to offset %ld Errno %s (%s)\n",
			offset, 
			error_description(err)));

	*errret = error_seek;
	return NULL;
    }

    *content_length = fst->messages[idx].content_len;

    if (! fst->messages[idx].entry) {

	fst->messages[idx].entry = malloc_header_helper();
	need_parse = 1;

	fst->messages[idx].entry->offset         = offset;
	fst->messages[idx].entry->header_charset = display_charset;
	fst->messages[idx].entry->content_length = 
	    fst->messages[idx].content_len;

	    DPRINT(Debug,10,(&Debug, 
			     "-- content_len=%ld\n",
			     fst->messages[idx].content_len));
	
    }

    ZZ = separator_helper(need_parse ? fst->messages[idx].entry : NULL,
			  errret,
			  print_separator,env_buffer,ret);
    if (-1 == ZZ)
	return NULL;

    DPRINT(Debug,9,(&Debug,
		    "give_message_from_fstate: beginning of headers=%ld\n",ZZ));

    if (fseek(ret, ZZ, SEEK_SET) == -1) {
	int err = errno;
	DPRINT(Debug,1,(&Debug, 
			
			"give_message_from_fstate: Couldn't seek folder to offset %ld Errno %s (%s)\n",
			ZZ, 
			error_description(err)));

	*errret = error_seek;
	return NULL;
    }

    if (need_parse) {
	
	fst->messages[idx].entry->mime_rec.begin_offset = ZZ;

	parser_helper1(& (fst->messages[idx]),ret);

	if (fseek(ret, ZZ, SEEK_SET) == -1) {
	    int err = errno;
	    DPRINT(Debug,1,(&Debug, 
			    
			    "give_message_from_fstate: Couldn't seek folder to offset %ld Errno %s (%s)\n",
			    ZZ, 
			    error_description(err)));
	    
	    *errret = error_seek;
	    return NULL;
	}
    }

    if (entryret)
	*entryret = fst->messages[idx].entry;


    return ret;
}


S_(parse_folder_handler_f parse_folder_fstate)
static int parse_folder_fstate P_((struct folder_handler *H));
static int parse_folder_fstate(H)
     struct folder_handler *H;
{
    return 1;
}


static struct folder_routines FSTATE = {
    FOLDER_ROUTINES_magic,

    init_fstate_handler,
    free_fstate_handler,
    give_message_from_fstate,
    parse_folder_fstate
};


struct folder_handler * open_fstate()
{
    struct folder_handler *ret = NULL;
    FILE **fp_vec              = NULL;
    int i;

    if (! have_fstate_called) {
	if (have_fstate() < 1)
	    return NULL;
    }

    if (fstate.storage_len < 1)
	return NULL;

    fp_vec = safe_malloc ( fstate.storage_len * sizeof (fp_vec[0]));

    /* We ignores unopenable storages now */
    for (i = 0; i < fstate.storage_len; i++) {
	fp_vec[i] = NULL;
	
	if (fstate.storage[i].folder_name)
	    fp_vec[i] = fopen(fstate.storage[i].folder_name,"r");
    }
    
    ret = malloc_folder_handler(&FSTATE);

    ret->d.fstate->fp_vec     = fp_vec;
    ret->d.fstate->fp_vec_len = fstate.storage_len;

    ret->num_messages         = fstate.view_len;

    if (fstate.view_len > 0) {
	ret->d.fstate->messages = 
	    safe_malloc(fstate.view_len *
			sizeof ( ret->d.fstate->messages[0]));
	ret->d.fstate->messages_len = fstate.view_len;
			
	for (i = 0; i < fstate.view_len; i++) {
	    int mbx = fstate.view[i].mailbox_number;
	    int idx = fstate.view[i].index;

	    ret->d.fstate->messages[i].fpnum = -1;    /* Invalid */   
	    ret->d.fstate->messages[i].offset = 0L;
	    ret->d.fstate->messages[i].content_len = 0L;
	    ret->d.fstate->messages[i].entry  = NULL;

	    if (mbx >= 0 && mbx < fstate.storage_len &&
		idx >= 0 && idx < fstate.storage[mbx].num_mssgs &&
		fstate.storage[mbx].mssgs[idx].idx >= 0) {

		ret->d.fstate->messages[i].fpnum = mbx;
		ret->d.fstate->messages[i].offset = 
		    fstate.storage[mbx].mssgs[idx].idx;		
		ret->d.fstate->messages[i].content_len = 
		    fstate.storage[mbx].mssgs[idx].cl;
	    }
	}
    }

    return ret;
}

int process_fstate_print(hdr_display_level, do_page_breaks, do_raw_output)
     enum hdr_disp_level hdr_display_level;
     int do_page_breaks;
     int do_raw_output;
{
    struct folder_handler  * folder = open_fstate();
    int i;
    int ret = 1;

    if (! folder) 
	return 0;

    /* num_sel numbers are starting from 1 ... */

    for (i = 0 ; i < fstate.num_sel ; i++) {

	if (!print_number_message(folder,fstate.sel_list[i],
				  hdr_display_level,
				  do_page_breaks,
				  do_raw_output))
	    ret = 0;
    }

    free_folder_handler(&folder);

    return ret;
}


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


syntax highlighted by Code2HTML, v. 0.9.1