static char rcsid[] = "@(#)$Id: sb_file.c,v 1.12 2006/04/09 07:37:07 hurtta Exp $";

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

#include "headers.h"
#include "s_me.h"
#include "sb_imp.h"

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

DEBUG_VAR(Debug,__FILE__,"charset");

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

static int sb_init_file P_((struct stringbuffer *buffer));
static int sb_init_file(buffer)
     struct stringbuffer *buffer;
{
    static int count =  0;
    int i;
    char *tmp;

    tmp = give_dt_estr_as_str(&temp_dir_e,"tmpdir");
    if (!tmp)
	tmp = "/tmp/";
   
    buffer->p->a.file.offset_count = 0;
    buffer->p->a.file.offsets      = NULL;
    buffer->p->a.file.filename     = NULL;
    buffer->p->a.file.fh           = NULL;

    for (i = 0; i < 10; i++) {
	count++;

	buffer->p->a.file.filename = elm_message(FRM("%selmsb-%d-%d"),
						 tmp, getpid (),
						 count);

	buffer->p->a.file.fh = safeopen_rdwr(buffer->p->a.file.filename);
	if (!buffer->p->a.file.fh) {
	    int err = errno;
	    DPRINT(Debug,25,(&Debug,
			     "stringbuffer: safeopen_rdwr: %s: %s (errno %d)\n",
			     buffer->p->a.file.filename,
			     error_description(err),err));
	    free(buffer->p->a.file.filename);
	    buffer->p->a.file.filename = NULL;
	} else
	    break;
	
    } 
    if (!buffer->p->a.file.fh)
	return 0;

    unlink (buffer->p->a.file.filename);

    DPRINT(Debug,1,(&Debug,
		    "stringbuffer: using temp file (%s)\n",
		    buffer->p->a.file.filename));
    return 1;
}

static void sb_free_file P_((struct stringbuffer *buffer));
static void sb_free_file(buffer)
     struct stringbuffer *buffer;
{
    if (buffer->p->a.file.fh) {
	fclose(buffer->p->a.file.fh);
	buffer->p->a.file.fh = NULL;
    }

    if (buffer->p->a.file.filename) {
	free(buffer->p->a.file.filename);
	buffer->p->a.file.filename = NULL;
    }

    if (buffer->p->a.file.offsets) {
	free(buffer->p->a.file.offsets);
	buffer->p->a.file.offsets = NULL;
    }
    buffer->p->a.file.offset_count = 0;
}

static void sb_add_line_to_file P_((struct stringbuffer *buffer,
				   const struct string *string));
static void sb_add_line_to_file(buffer,string)
     struct stringbuffer *buffer;
     CONST struct string *string;
{
    int ptr = buffer->p->a.file.offset_count;

    if (fseek(buffer->p->a.file.fh,0,SEEK_END) != 0) {
	int err = errno;
	DPRINT(Debug,1,(&Debug,
			"stringbuffer: fseek (flush) failure: %s: %s (errno %d)\n",
			buffer->p->a.file.filename,
			error_description(err),err));
	
	return;
    }
    
    buffer->p->a.file.offsets = 
	safe_realloc(buffer->p->a.file.offsets,
		     (buffer->p->a.file.offset_count +1) *
		     sizeof (long));
    buffer->p->a.file.offsets[ptr] = ftell(buffer->p->a.file.fh);
    buffer->p->a.file.offset_count++;
    
    if (string->string_type-> MIME_name) {
	char * s = us2s(stream_from_string(string,0,NULL));
	int l1 = strlen(s);
	int l2 = strlen(string->string_type->MIME_name);
	fprintf(buffer->p->a.file.fh,"%d:%d:",l2,l1);
	/* Include ending \0 to string */
	fwrite(string->string_type-> MIME_name,1,l2+1,
	       buffer->p->a.file.fh);
	/* Include ending \0 to string */
	fwrite(s,1,l1+1,buffer->p->a.file.fh);
	free(s);
    } else { 
	/* No charset name available ... */
	struct string *str = convert_string(system_charset,string,0);
	char * s = us2s(stream_from_string(str,0,NULL));
	int l1 = strlen(s);
	fprintf(buffer->p->a.file.fh,":%d:",l1);
	fputc('\0',buffer->p->a.file.fh);  /* Terminaing \0 of null charset */
	/* Include ending \0 to string */
	fwrite(s,1,l1+1,buffer->p->a.file.fh);
	free(s);
	free_string(&str);
    }
}

static int sb_linecount_file P_((const struct stringbuffer *ptr));
static int sb_linecount_file(ptr)
     CONST struct stringbuffer *ptr;
{
    return ptr->p->a.file.offset_count;
}

static struct string *sb_get_line_from_file P_((const struct 
					       stringbuffer *buffer,
					       int ptr));
static struct string *sb_get_line_from_file(buffer,ptr)
     CONST struct stringbuffer *buffer;
     int ptr;
{
    int setlen = 0;
    int strlen = 0;
    char * bigs = NULL;
    charset_t sn = system_charset;
    struct string * res = NULL;
    int c;

    if (ptr < 0 || ptr >= buffer->p->a.file.offset_count)
	panic("STRINGBUFFER PANIC",__FILE__,__LINE__,"sb_get_line_from_file",
	      "Bad index",0);

    if (0 != fseek(buffer->p->a.file.fh,buffer->p->a.file.offsets[ptr],
		   SEEK_SET)) {
	int err = errno;
         DPRINT(Debug,1,(&Debug,
			 "stringbuffer: fseek (flush) failure: %s: %s (errno %d)\n",
			 buffer->p->a.file.filename,
			 error_description(err),err));
	panic("STRINGBUFFER PANIC",__FILE__,__LINE__,"sb_get_line_from_file",
	      "Failed to flush or seek file",0);
    }

    c = fgetc(buffer->p->a.file.fh);
    while (c >= '0' && c <= '9') {
	setlen = setlen * 10 + c - '0';
	c = fgetc(buffer->p->a.file.fh);
    }
    if (':' != c) {
	panic("STRINGBUFFER PANIC",__FILE__,__LINE__,"sb_get_line_from_file",
	      "Bad data read from file",0);
    }
    c = fgetc(buffer->p->a.file.fh);
    while (c >= '0' && c <= '9') {
	strlen = strlen * 10 + c - '0';
	c = fgetc(buffer->p->a.file.fh);
    }
    if (':' != c) {
	panic("STRINGBUFFER PANIC",__FILE__,__LINE__,"sb_get_line_from_file",
	      "Bad data read from file",0);
    }

    bigs = safe_malloc(setlen+1+strlen+1);
    
    if (fread(bigs,1,setlen+1+strlen+1,buffer->p->a.file.fh) !=
	setlen+1+strlen+1) {
	panic("STRINGBUFFER PANIC",__FILE__,__LINE__,"sb_get_line_from_file",
	      "Read error or short data read from file",0);
    }
    if (bigs[setlen] != '\0' ||
	bigs[setlen+1+strlen] != '\0') {
	panic("STRINGBUFFER PANIC",__FILE__,__LINE__,"sb_get_line_from_file",
	      "Bad data read from file",0);
    }

    if (setlen != 0) {
	sn = MIME_name_to_charset(bigs,0);
	if (!sn) { 
	    DPRINT(Debug,1,(&Debug,
			    "stringbuffer: Charset '%s' is not knows (impossible?)\n",
			    bigs));
	    panic("STRINGBUFFER PANIC",__FILE__,__LINE__,
		  "sb_get_line_from_file",
		  "Bad charset read from file",0);
	}
    }
    res = new_string2(sn,s2us(&(bigs[setlen+1])));

    free(bigs);
    return res;
}

struct sb_type   sb_in_file = {
    sb_init_file,
    sb_free_file,
    sb_add_line_to_file,
    sb_linecount_file,
    sb_get_line_from_file
};

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



syntax highlighted by Code2HTML, v. 0.9.1