static char rcsid[] = "@(#)$Id: terminal.c,v 1.51 2006/04/09 07:37:07 hurtta Exp $"; /****************************************************************************** * The Elm (ME+) Mail System - $Revision: 1.51 $ $State: Exp $ * * Author: Kari Hurtta (was hurtta+elm@ozone.FMI.FI) *****************************************************************************/ #include "headers.h" #include "s_me.h" #include "cs_imp.h" #include "cs_terminal.h" DEBUG_VAR(Debug,__FILE__,"charset"); #include #ifndef ANSI_C extern int errno; #endif static char * sStr P_((unsigned char *p)); static char * sStr (p) unsigned char *p; { return (char *)p; } int match_charset_name(cs1,cs2) charset_t cs1; charset_t cs2; { if (cs1 == cs2) return 1; if (!cs1 || !cs2) return 0; if (cs1->MIME_name && cs2->MIME_name && 0 == istrcmp(cs1->MIME_name,cs2->MIME_name)) { SIGDPRINT(Debug,9,(&Debug, "** Matched charset by name %s (%p) == %s (%p)\n", cs1->MIME_name,cs1, cs2->MIME_name,cs2)); return 1; } return 0; } void debug_display_settings(p,sig,stream) struct display_settings *p; int sig; int stream; { int i; int corrupted = 0; if (stream) { SIGDPRINT(Debug,8,(&Debug, "Stream sets: (%d sets)\n", p->set_count)); } else { SIGDPRINT(Debug,8,(&Debug, "Terminal sets: (%d sets)\n", p->set_count)); } for (i = 0; i < p->set_count; i++) { if (i >= sizeof (p->sets) / sizeof (p->sets[0])) { corrupted++; break; } SIGDPRINT(Debug,8,(&Debug," set [%d]: bank=",i)); switch(p->sets[i].bank) { case bank_unspecified: SIGDPRINT(Debug,8,(&Debug, "(none)")); break; default: SIGDPRINT(Debug,8,(&Debug, "G%d ", p->sets[i].bank)); break; } SIGDPRINT(Debug,8,(&Debug," type=")); switch(p->sets[i].type) { case iso2022_other: SIGDPRINT(Debug,8,(&Debug,"other")); break; case iso2022_94: SIGDPRINT(Debug,8,(&Debug,"94 ")); break; case iso2022_96: SIGDPRINT(Debug,8,(&Debug,"96 ")); break; case iso2022_94x94: SIGDPRINT(Debug,8,(&Debug,"94x94")); break; case iso2022_96x96: SIGDPRINT(Debug,8,(&Debug,"96x96")); break; default: SIGDPRINT(Debug,8,(&Debug,"?????")); corrupted++; break; } { int k; SIGDPRINT(Debug,8,(&Debug," bytes=")); for (k = 0; k < sizeof p->sets[i].bytes && p->sets[i].bytes[k]; k++) { int val = (unsigned char) p->sets[i].bytes[k]; if (k > 0) { SIGDPRINT(Debug,8,(&Debug," ")); } SIGDPRINT(Debug,8,(&Debug,"%d/%d",val/16,val%16)); } } SIGDPRINT(Debug,8,(&Debug," width=%d\n",p->width[i])); } for (i = 0; i < 4; i++) { SIGDPRINT(Debug,8,(&Debug," bank G%d=",i));; switch(p->bank[i]) { case -1: SIGDPRINT(Debug,8,(&Debug,"(none)")); break; default: SIGDPRINT(Debug,9,(&Debug,"set %d",p->bank[i])); if (p->bank[i] < 0 || p->bank[i] >= p->set_count) { corrupted++; SIGDPRINT(Debug,8,(&Debug," ????")); } break; } SIGDPRINT(Debug,8,(&Debug,"\n")); } SIGDPRINT(Debug,8,(&Debug," left="));; switch(p->current_L) { case bank_unspecified: SIGDPRINT(Debug,8,(&Debug,"(none)")); break; default: SIGDPRINT(Debug,8,(&Debug,"G%d ", p->current_L)); break; } SIGDPRINT(Debug,8,(&Debug,"\n")); SIGDPRINT(Debug,8,(&Debug," right="));; switch(p->current_R) { case bank_unspecified: SIGDPRINT(Debug,8,(&Debug,"(none)")); break; default: SIGDPRINT(Debug,8,(&Debug,"G%d ", p->current_R)); break; } SIGDPRINT(Debug,8,(&Debug,"\n")); if (corrupted) { if (stream) panic("STRING PANIC",__FILE__,__LINE__, "debug_display_settings", #ifdef DEBUG Debug.active >= 8 ? "Corrupted stream sets information -- see debugfile" : #endif "Corrupted stream sets information",sig); else panic("STRING PANIC",__FILE__,__LINE__, "debug_display_settings", #ifdef DEBUG Debug.active >= 8 ? "Corrupted terminal sets information -- see debugfile" : #endif "Corrupted terminal sets information",sig); } } static void debug_charset_sets P_((struct setlist *p)); static void debug_charset_sets(p) struct setlist *p; { int i; DPRINT(Debug,8,(&Debug,"(output) charset sets: \n")); for (i = 0; i < sizeof (p->sets) / sizeof (p->sets[0]) && p->sets[i]; i++) { char *s; DPRINT(Debug,8,(&Debug," set [%d]: bank=",i)); switch(p->sets[i]->bank) { case bank_unspecified: DPRINT(Debug,8,(&Debug,"(none)")); break; default: DPRINT(Debug,8,(&Debug,"G%d ", p->sets[i]->bank)); break; } DPRINT(Debug,8,(&Debug," type=")); switch(p->sets[i]->type) { case iso2022_other: DPRINT(Debug,8,(&Debug,"other")); break; case iso2022_94: DPRINT(Debug,8,(&Debug,"94 ")); break; case iso2022_96: DPRINT(Debug,8,(&Debug,"96 ")); break; case iso2022_94x94: DPRINT(Debug,8,(&Debug,"94x94")); break; case iso2022_96x96: DPRINT(Debug,8,(&Debug,"96x96")); break; default: DPRINT(Debug,8,(&Debug,"?????")); break; } s = iso2022_codestr(p->sets[i]->bytes, sizeof p->sets[i]->bytes); DPRINT(Debug,8,(&Debug," bytes=%s\n",s)); free(s); } DPRINT(Debug,8,(&Debug," left=")); switch(p->initial_L) { case bank_unspecified: DPRINT(Debug,8,(&Debug,"(none)")); break; default: DPRINT(Debug,8,(&Debug,"G%d ", p->initial_L)); break; } DPRINT(Debug,8,(&Debug," rigth=")); switch(p->initial_R) { case bank_unspecified: DPRINT(Debug,8,(&Debug,"(none)")); break; default: DPRINT(Debug,8,(&Debug,"G%d ", p->initial_R)); break; } DPRINT(Debug,8,(&Debug,"\n")); for (i = 0; i < sizeof (p->initial_bank) / sizeof (p->initial_bank[0]); i++) { DPRINT(Debug,8,(&Debug," initial bank G%d=",i)); if (-1 == p->initial_bank[i]) { DPRINT(Debug,8,(&Debug,"(none)\n")); } else { DPRINT(Debug,8,(&Debug,"set %d",p->initial_bank[i])); if (p->initial_bank[i] < 0 || p->initial_bank[i] >= sizeof (p->sets) / sizeof (p->sets[0]) || !p->sets[p->initial_bank[i]]) { DPRINT(Debug,8,(&Debug," ?????")); } DPRINT(Debug,8,(&Debug,"\n")); } } } void reset_display_settings(p) struct display_settings *p; { int i; /* defined in hdrs/defs.h */ bzero((void *)p,sizeof (struct display_settings)); p->magic = DISPLAY_STATE_magic; p->set_count = 0; p->bank[0] = -1; p->bank[1] = -1; p->bank[2] = -1; p->bank[3] = -1; p->current_L = bank_unspecified; p->current_R = bank_unspecified; if (sizeof (p->width) / sizeof (p->width[0]) != sizeof (p->sets) / sizeof (p->sets[0])) panic("STRING PANIC",__FILE__,__LINE__, "reset_display_settings", "width and sets array do not have save number of elemens",0); for (i = 0; i < sizeof (p->width) / sizeof (p->width[0]); i++) p->width[i] = -1; #ifdef WCHAR p->wcwidth = 0; #endif } void free_terminal_info(p) struct display_settings **p; { if (*p) { if (DISPLAY_STATE_magic != (*p)->magic) panic("STRING PANIC",__FILE__,__LINE__, "free_terminal_info", "Bad magic number",0); (*p)->magic = 0; /* Not valid */ free(*p); *p = NULL; } } /* May be called from signal handler -- on that situation use buffer specified as argument -- otherwise result is malloced */ char * iso2022_change_helper_1(terminal_info,ID,setnum,buffer,size) screen_info_p terminal_info; struct iso2022_setid ID; int setnum; char * buffer; int size; { char * ret = NULL; int maybe_signal = buffer != NULL; if (maybe_signal) { SIGDPRINT(Debug,9,(&Debug, "iso2022_change_helper_1: buffer=%p size=%d\n", buffer,size)); } if (ID.bank != bank_unspecified) { if (-1 == terminal_info->bank[ID.bank]) { terminal_info->bank[ID.bank] = setnum; if (maybe_signal) { if (!ret) ret = iso2022_setid_stream(ID,buffer,size); else { char buffer1[128]; char *c = iso2022_setid_stream(ID,buffer1,sizeof buffer1); ret = strfcat(buffer,c,size); } } else { char *c = iso2022_setid_stream(ID,NULL,0); ret = strmcat(ret,c); free(c); } } else if (terminal_info->bank[ID.bank] != setnum) { SIGDPRINT(Debug,4,(&Debug, "terminal_switch_to [iso2022_change_helper_1]: Several assignments for bank G%d\n", ID.bank)); SIGDPRINT(Debug,8,(&Debug, " Assigned to set %d -- another candinate set %d\n", terminal_info->bank[ID.bank],setnum)); } /* Initial bank settinsg do not set left and right so set them here if them are not set ion iso2022_info */ if (terminal_info->bank[ID.bank] == setnum) { if (terminal_info->current_L == bank_unspecified && ID.bank == bank_G0) { terminal_info->current_L = bank_G0; if (maybe_signal) { if (!ret) ret = lock_shift(0,terminal_info->current_L,buffer, size); else { char buffer1[10]; char * c = lock_shift(0,terminal_info->current_L, buffer1,sizeof buffer1); ret = strfcat(buffer,c,size); } } else { char *c = lock_shift(0,terminal_info->current_L,NULL,0); ret = strmcat(ret,c); free(c); } } if (/* For ISO-8859-* charsets */ terminal_info->current_R == bank_unspecified && ID.type == iso2022_96 || /* For EUC-* charsets */ terminal_info->current_R == bank_unspecified && ID.type == iso2022_94x94 && ID.bank == bank_G1 ) { terminal_info->current_R = ID.bank; if (maybe_signal) { if (!ret) ret = lock_shift(1,terminal_info->current_R, buffer,size); else { char buffer1[10]; char *c = lock_shift(1,terminal_info->current_R, buffer1,sizeof buffer1); ret = strfcpy(buffer,c,size); } } else { char *c = lock_shift(1,terminal_info->current_R,NULL,0); ret = strmcat(ret,c); free(c); } } } } else if (ID.type == iso2022_other) { ret = iso2022_setid_stream(ID,buffer,size); } if (maybe_signal && ret && ret != buffer) panic("STRING PANIC",__FILE__,__LINE__, "iso2022_change_helper_1","buffer != ret when called from signal",1); return ret; } /* Result is MALLOCed */ char * terminal_charset_post_init(terminal_info,iso2022_info) screen_info_p terminal_info; struct setlist * iso2022_info; { char * ret = NULL; int max,k; int i; /* FIXME: Usage of this function on string.c unclear!!! */ static screen_info_p LAST_COMPLAIN = NULL; static struct setlist * LAST_COMPLAIN_b = NULL; if (DISPLAY_STATE_magic != terminal_info->magic) panic("STRING PANIC",__FILE__,__LINE__, "terminal_charset_post_init", "Bad terminal_info (bad magic)",0); /* Only check that terminal_info includes same sets (on beginning of list) than iso2022_info */ for (max = 0; max < sizeof (iso2022_info->sets) / sizeof (iso2022_info->sets[0]) && iso2022_info->sets[max]; max++) { if (max >= terminal_info->set_count || terminal_info->sets[max].type != iso2022_info->sets[max]->type || 0 != strncmp(sStr(terminal_info->sets[max].bytes), sStr(iso2022_info->sets[max]->bytes), sizeof (terminal_info->sets[max].bytes)) || (bank_unspecified != iso2022_info->sets[max]->bank && terminal_info->sets[max].bank != iso2022_info->sets[max]->bank)) { if (LAST_COMPLAIN != terminal_info || LAST_COMPLAIN_b != iso2022_info) { LAST_COMPLAIN = terminal_info; LAST_COMPLAIN_b = iso2022_info; DPRINT(Debug,8,(&Debug, "terminal_charset_post_init: Output charset not current terminal charset\n")); DPRINT(Debug,8,(&Debug, " (perhaps subset) -- can't really post init terminal charset\n")); if (max >= terminal_info->set_count) { DPRINT(Debug,8,(&Debug, " Only %d sets on terminal... \n", terminal_info->set_count)); } else { DPRINT(Debug,8,(&Debug, " [%d] -- bank G%d on terminal set not match to output charset\n", max, terminal_info->sets[max].bank)); } debug_display_settings(terminal_info,0,0); debug_charset_sets(iso2022_info); } return NULL; } } LAST_COMPLAIN = NULL; LAST_COMPLAIN_b = NULL; if (terminal_info->set_count > 0 && terminal_info->sets[0].type == iso2022_other) { if (same_setid(terminal_info->sets[0], *(iso2022_info->sets[0]))) { DPRINT(Debug,8,(&Debug, "terminal_charset_post_init: Terminal was on no ISO2022 mode ... NO change\n")); return NULL; } else { char *c; DPRINT(Debug,8,(&Debug, "terminal_charset_post_init: Terminal was on no ISO2022 mode ... returning to ISO2022\n")); c = iso2022_setid_stream(return_to_iso2022,NULL,0); ret = strmcat(ret,c); free(c); reset_display_settings(terminal_info); } } /* Remove assignments which does not belong to iso2022_info */ for (k = 0; k < 4; k++) { if (terminal_info->bank[k] >= max) { if (k == terminal_info->current_L) terminal_info->current_L = bank_unspecified; if (k == terminal_info->current_R) terminal_info->current_R = bank_unspecified; terminal_info->bank[k] = -1; } } if (bank_unspecified != iso2022_info->initial_L && terminal_info->current_L != iso2022_info->initial_L) { char *c = lock_shift(0,terminal_info->current_L,NULL,0); ret = strmcat(ret,c); free(c); } if (bank_unspecified != iso2022_info->initial_R && terminal_info->current_R != iso2022_info->initial_R) { char *c = lock_shift(1,terminal_info->current_R,NULL,0); ret = strmcat(ret,c); free(c); } for (i = 0; i < sizeof (iso2022_info->initial_bank) / sizeof (iso2022_info->initial_bank[0]); i++) { int x = iso2022_info->initial_bank[i]; if (-1 != x) { struct iso2022_setid ID; if (x < 0 || x >= sizeof (iso2022_info->sets) / sizeof (iso2022_info->sets[0]) || ! iso2022_info->sets[x]) panic("STRING PANIC",__FILE__,__LINE__, "terminal_charset_post_init", "Bad initial_bank (set)", 0); ID = * (iso2022_info->sets[x]); if (ID.bank != i) panic("STRING PANIC",__FILE__,__LINE__, "terminal_charset_post_init", "Bad initial_bank (bank number)", 0); set_initial_bank(&ret,ID,terminal_info,NULL,0,0); } } for (k = 0; k < max; k++) { char * c; struct iso2022_setid ID = terminal_info->sets[k]; c=iso2022_change_helper_1(terminal_info,ID,k,NULL,0); if (c) { ret = strmcat(ret,c); free(c); } } if (ret) debug_display_settings(terminal_info,0,0); return ret; } screen_info_p create_terminal_info(void) { screen_info_p terminal_info; terminal_info = safe_malloc(sizeof (struct display_settings)); reset_display_settings(terminal_info); return terminal_info; } void iso2022_setid_select_bank (ID,terminal_info) struct iso2022_setid *ID; screen_info_p terminal_info; { if (ID->bank == bank_unspecified) { switch(ID->type) { case iso2022_94: ID->bank = bank_G0; break; case iso2022_94x94: ID->bank = bank_G1; break; /* We use bank G2 to compatible of VT3xx terminals */ case iso2022_96: case iso2022_96x96: /* not perhaps exists */ if (-1 == terminal_info->bank[bank_G2]) ID->bank = bank_G2; else ID->bank = bank_G3; } } } int iso2022_give_setpos(ID,output_state) struct iso2022_setid *ID; screen_info_p output_state; { int setpos = -1; int i; iso2022_setid_select_bank (ID,output_state); for (i = 0; i < output_state->set_count; i++) { if (same_setid(output_state->sets[i],*ID)) setpos = i; } return setpos; } /* Return setnumber from terminal info */ int set_initial_bank(ret,ID,terminal_info,buffer,size,maybe_signal) char **ret; struct iso2022_setid ID; screen_info_p terminal_info; char * buffer; int size; int maybe_signal; { int setpos = -1; if (ID.bank < 0 || ID.bank >= ISO2022_BANK_NUM) panic("STRING PANIC",__FILE__,__LINE__, "set_initial_bank", "Bad bank",maybe_signal); setpos = iso2022_give_setpos(&ID,terminal_info); if (-1 == setpos) { if (terminal_info->set_count < sizeof (terminal_info->sets) / sizeof (terminal_info->sets[0])) { setpos = terminal_info->set_count++; } else { setpos = ID.bank; DPRINT(Debug,7,(&Debug, "set_initial_bank: Too many sets on output state, replacing set %d\n", setpos)); } terminal_info->sets[setpos] = ID; terminal_info->width[setpos] = -1; /* Initially no width */ } terminal_info->bank[ID.bank] = setpos; if (maybe_signal) { if (!*ret) *ret = iso2022_setid_stream(ID,buffer,size); else { char buffer1[128]; char *c = iso2022_setid_stream(ID,buffer1,sizeof buffer1); *ret = strfcat(buffer,c,size); } } else { char *c = iso2022_setid_stream(ID,NULL,0); *ret = strmcat(*ret,c); free(c); } return setpos; } /* * Local Variables: * mode:c * c-basic-offset:4 * buffer-file-coding-system: iso-8859-1 * End: */