static char rcsid[] = "@(#)$Id: elmstringconvert.c,v 1.12 2006/04/09 07:37:30 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 "elmutil.h"
#include "s_me.h"
#include "s_elm.h"
#include "cs_imp.h"

DEBUG_VAR(Debug,__FILE__,"util");

extern char *optarg;		
extern int   optind;		

static charset_t  source_charset = NULL;
static charset_t  target_charset = NULL;

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

static int copy_between_fds P_((FILE *infd,FILE *fd,const char *name));
static int copy_between_fds(infd,fd,name)
     FILE *infd; 
     FILE *fd; 
     const char *name;
{
    char buffer[1024 * 1024 +1];    /* 1 MB */
    int line_len;
    int count = 0;
    int errcount = 0;


    while (0 < (line_len = 
		mail_gets(buffer, sizeof buffer -1, infd))) {
	int l;

	struct string * in_str  = new_string(source_charset);
	struct string * out_str = NULL;

	char * res;
	int reslen;
	int written;
	int errors = 0;
	
	if ('\n' == buffer[line_len-1])
	    count++;
	else {
	    DPRINT(Debug,7,(&Debug,
			    "Too long line (read %d bytes)\n",
			    line_len));

	    lib_error(CATGETS(elm_msg_cat, MeSet, MeLineTooLongOnFile,
			      "Warning: Line %d too long on file %s: %.50s..."),
		      count+1,name,buffer);
	}

	l = add_streambytes_to_string(in_str,line_len,s2us(buffer),&errors);
	
	if (l < line_len) {
	    DPRINT(Debug,7,(&Debug,
			    "Feeding of line failed (handled %d bytes from %d)\n",
			    l,line_len));
	    lib_error(CATGETS(elm_msg_cat, MeSet, MeLineBadDataOnFile,
			      "Warning: Bad data on line %d on file %s: %.50s..."),
		      count,name,buffer);
	    errcount++;
	}
	if (errors) {
	    DPRINT(Debug,7,(&Debug,
			    "Feeding of line failed: %d errors\n",
			    errors));
	    errcount += errors;
	}
	out_str = convert_string(target_charset,in_str,0);

	bytestream_from_string(out_str,&res,&reslen);

	written = 0;
	while (written < reslen) {
	    int X = fwrite(res + written, 1, reslen - written,fd);

	    if (X < 1) {
		errcount++;
		break;
	    }
	    written += X;
	}

	free_string(&in_str);
	free_string(&out_str);
    }

    
    if (errcount)
	return 0;
    return 1;
}

static int copy_to_fd P_((FILE *fd,int argc,char *argv[]));
static int copy_to_fd(fd,argc,argv)
     FILE *fd; 
     int argc;
     char *argv[];
{
    if (optind < argc) {
	int errcount = 0;

	for (;optind < argc; optind++) {
	    FILE * X;
	    if (0 != access(argv[optind],READ_ACCESS)) {
		int errcode = errno;
		lib_error(CATGETS(elm_msg_cat, MeSet, MeFileNotReadable,
				  "File %.50s is not readable: %s"),
			  argv[optind], error_description(errcode));
		errcount++;
		continue;
	    }

	    X = fopen(argv[optind],"r");
	    if (!X) {
		int errcode = errno;
		lib_error(CATGETS(elm_msg_cat, MeSet, MeFileNotReadable,
				  "File %.50s is not readable: %s"),
			  argv[optind], error_description(errcode));
		errcount++;
		continue;
	    }
	    
	    if (!copy_between_fds(X,fd,argv[optind]))
		errcount++;
	    
	    if (ferror(X)) {
		lib_error(CATGETS(elm_msg_cat, ElmSet, ElmErrorReading,
				  "Error reading from %.50s"),
			  argv[optind]);
		errcount++;
	    }
	    fclose(X);
	}

	if (errcount) {
	    return 0;
	}
    } else {
	return copy_between_fds(stdin,fd,"(stdin)");
    }
    return 1;
}

int main P_((int argc, char *argv[]));
int main(argc, argv)
     int argc;
     char *argv[];
{
    int err = 0;
    int c;
    int global = 0;
    char *targetfile = NULL;

#if DEBUG
    init_debugfile("ELMSTRINGCONVERT");
#endif
    locale_init();
    user_init();
    init_defaults();
    
    while ((c = getopt(argc, argv, "Gd:w:S:T:")) != EOF) {
	charset_t wanted_charset;

	switch(c) {
	case 'S':
	    wanted_charset = MIME_name_to_charset(optarg,0);
	    if (!wanted_charset) {
		lib_error(CATGETS(elm_msg_cat, MeSet, MeArgsCharsetSUnknown,
				  "Charset %s given with -S flag is unknown."),
			  optarg);
		err = 1;
		goto fail;	       
	    }
	    if (! wanted_charset->map_info) {
		lib_error(CATGETS(elm_msg_cat, MeSet, MeArgsCharsetSNeedsMap,
				  "Warning: Charset %s given on -S flag needs map defination (on %s file)"),
			  optarg,
			  global ? system_mime_charsets : USER_MIME_CHARSETS);
	    }
	    source_charset = wanted_charset;

	    break;
	case 'T':
	    wanted_charset = MIME_name_to_charset(optarg,0);
	    if (!wanted_charset) {
		lib_error(CATGETS(elm_msg_cat, MeSet, MeArgsCharsetTUnknown,
				  "Charset %s given with -T flag is unknown."),
			  optarg);
		err = 1;
		goto fail;	       
	    }
	    if (! wanted_charset->map_info) {
		lib_error(CATGETS(elm_msg_cat, MeSet, MeArgsCharsetTNeedsMap,
				  "Warning: Charset %s given on -T flag needs map defination (on %s file)"),
			  optarg,
			  global ? system_mime_charsets : USER_MIME_CHARSETS);
	    }
	    target_charset = wanted_charset;

	    break;
	case 'G':
	    global++;
	    break;
	case 'd':
#if DEBUG
	    set_debugging(optarg);	 
#else
	    lib_error(CATGETS(elm_msg_cat, ElmSet, ElmArgsIngoringDebug,
			      "Warning: system created without debugging enabled - request ignored\n"));
#endif
	    break;
	case 'w' : 
	    targetfile = optarg;
	    if (0 != access(targetfile,WRITE_ACCESS)) {
		int errcode = errno;
		
		if (errcode != ENOENT) {
		    lib_error(CATGETS(elm_msg_cat, MeSet, MeFileNotWriteable,
				      "File %.50s is not writeable: %s"),
			      targetfile, error_description(errcode));
		    err++;
		    goto fail;
		}
	    }
	    break;
	case '?':
	    err = 1;
	    goto fail;
	}
    }
    
    
    elm_sfprintf(version_buff, sizeof version_buff,
		 FRM("%s PL%s"), VERSION, PATCHLEVEL);
    
#ifdef DEBUG
    { 
	int d = panic_dprint("\n\
======================================================\n\
Debug output of the ELMSTRINGCONVERT program (version %s).\n",
			     version_buff);

	if (d >= 50) {
#if 0	
	    panic_dprint("WARNING: Edit manually out sensitive information from that file!\n");
	    
	    lower_prompt("WARNING: Debug file may include passwords -- edit it!");
	    sleep(5+sleepmsg);	    
#endif
	}
    }
#endif
    

    if (!global)
	read_rc_file(0);
    else
	post_init_check(0);

    if (!source_charset)
	source_charset = system_charset;

    if (!target_charset)
	target_charset = system_charset;

    if (source_charset != target_charset && 
	(!(CS_mapping & charset_properties(source_charset)) ||
	 !(CS_mapping & charset_properties(target_charset)))) {
	lib_error(CATGETS(elm_msg_cat, ElmSet, ElmCantConvertCharset,
			  "Can't convert text from charset %s to charset %s"),
		  source_charset -> MIME_name ? 
		  source_charset -> MIME_name : "<no MIME name>",
		  target_charset -> MIME_name ? 
		  target_charset -> MIME_name : "<no MIME name>");
	err = 1;
	goto fail;
    }
    	      
    if (targetfile) {
	char * tmp = elm_message(FRM("%s.N"),targetfile);
	int errcode = can_open(tmp,"w");
	FILE *f;
	
	if (errcode) {
	    lib_error(CATGETS(elm_msg_cat, MeSet, MeFileNotWriteable,
			      "File %.50s is not writeable: %s"),
		      tmp, error_description(errcode));
	  
	    err++;
	    free(tmp);
	    goto fail;
	}
	f = fopen(tmp,"w");
	if (!f) {
	    int errcode = errno;
	    lib_error(CATGETS(elm_msg_cat, MeSet, MeFileNotWriteable,
			      "File %.50s is not writeable: %s"),
		      tmp, error_description(errcode));
	    
	    err++;
	    free(tmp);
	    goto fail;
	}

	if (!copy_to_fd(f,argc,argv)) {
	    fclose(f);
	    unlink(tmp);

	    err++;
	    free(tmp);
	    goto fail;
	}

	if (EOF == fclose(f)) {
	    int errcode = errno;
	    lib_error(CATGETS(elm_msg_cat, MeSet, MeFileNotWriteable,
			      "File %.50s is not writeable: %s"),
		      tmp, error_description(errcode));
	    
	    unlink(tmp);

	    err++;
	    free(tmp);
	    goto fail;
	}
	if (0 != rename(tmp,targetfile)) {
	    int errcode = errno;
	    lib_error(CATGETS(elm_msg_cat, MeSet, MeFileNotRenamed,
			      "Failed to rename temporary file to %.50s: %.30s"),
		      targetfile, error_description(errcode));
	    
	    err++;
	    free(tmp);
	    goto fail;
	}
	free(tmp);
    }    
    else {

	if (!copy_to_fd(stdout,argc,argv))
	    err = 1;

    }

 fail:
    if (err)
	lib_error(CATGETS(elm_msg_cat, MeSet, MeProgFailed,
			  "%s failed; exit code=%d"),
		  argv[0],err);
    
    return err;
}

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


syntax highlighted by Code2HTML, v. 0.9.1