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 (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 : "", target_charset -> MIME_name ? target_charset -> 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: */