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 <hurtta+elm@posti.FMI.FI> (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 <errno.h>
#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:
 */


syntax highlighted by Code2HTML, v. 0.9.1