static char rcsid[] = "@(#)$Id: charset.c,v 1.5 2006/08/02 08:46:02 hurtta Exp $";

/******************************************************************************
 *  The Elm (ME+) Mail System  -  $Revision: 1.5 $   $State: Exp $
 *
 *  Author: Kari Hurtta <hurtta+elm@posti.FMI.FI>
 *      or  Kari Hurtta <elm@elmme-mailer.org>
 *****************************************************************************/



#include "def_misc.h"

#include "s_me.h"
#include "cs_imp.h"

DEBUG_VAR(Debug,__FILE__,"charset");

static int name_ok P_((CONST char *name));
static int name_ok(name)
     CONST char *name;
{
    if ('\0' == *name)
	return 0;

    return strlen(name) == 
	strspn(name,
	       "ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789abcdefghijklmnopqrstuvwxyz");
}

static void dump_alias_info P_((FILE *f,struct charcode_info *info));
static void dump_alias_info(f,info)
     FILE *f;
     struct charcode_info *info;
{
    int i;
    for (i = 0; i < charset_alias_count; i++)
	if (info == charset_alias_list[i].set &&
	    charset_alias_list[i].name) {
	    if (name_ok(charset_alias_list[i].name))
		elm_fprintf(f,FRM(";alias=%s"),charset_alias_list[i].name);
	    else
		elm_fprintf(f,FRM(";alias=%Q"),charset_alias_list[i].name);
	}   
}

void dump_map_info(f,info)
     FILE *f;
     struct charcode_info *info;
{
   
    if (!info->MIME_name) {
	if (!info->codeset)
	    fputs("# <No MIME name> ",f);
    } else if (name_ok(info->MIME_name)) {
	fputs(info->MIME_name,f);
    } else {
	elm_fprintf(f,FRM("%Q"),info->MIME_name);
    }
    
    if (info->codeset) {
	elm_fprintf(f,FRM("%scodeset=%Q"),
		    info->MIME_name ? ";" : "",
		    info->codeset);
    } else if (0 != (info->flags & SET_nodata)) {
	fputs(";!",f);
	return;
    }

    if (&cs_unknown != info->charset_type)
	elm_fprintf(f,FRM(";type=%s"),info->charset_type->type_name);
    if (info->map_info && name_ok(info->map_info->map_name))
	elm_fprintf(f,FRM(";map=%s"),info->map_info->map_name);
    else if (info->map_info)
	elm_fprintf(f,FRM(";map=%Q"),info->map_info->map_name);

    if (info->subtype && 
	info->subtype->MIME_name &&
	name_ok(info->subtype->MIME_name))
	elm_fprintf(f,FRM(";MIME-subset=%s"),info->subtype->MIME_name);
    else if (info->subtype && 
	     info->subtype->MIME_name)
	elm_fprintf(f,FRM(";MIME-subset=%Q"),info->subtype->MIME_name);

    if (info->MIBenum) {
	fprintf(f,";MIBenum=%d",info->MIBenum);
    }

    if (info->iso2022_info)
	print_setlist(f,info->iso2022_info);

    if (0 != (info->flags & SET_havealias)) {
	dump_alias_info(f,info);
    }
}


void dump_by_MIBenum(FILE *f)
{
    int class;

    fprintf(f,"# Start of MIBenum listing -------------------------------\n");
    for (class = 0; class < MIBenum_CLASS_len; class++) {
	int j;
	fprintf(f,"# MIBenum %d-%d\n",
		class * MIBenum_class_divide ,
		class * MIBenum_class_divide + MIBenum_CLASS[class].MIBenum_array_len -1);

	for (j = 0; j < MIBenum_CLASS[class].MIBenum_array_len; j++) {

	    if (MIBenum_CLASS[class].MIBenum_array[j]) {
		fprintf(f,"-\t");
		dump_map_info(f,MIBenum_CLASS[class].MIBenum_array[j]);
		fputc('\n',f);
	    }
	}
    }
    fprintf(f,"# End of MIBenum listing ---------------------------------\n");
}

void dump_charset_map(f,map)
     FILE *f; 
     struct charset_map_item *map;
{
    int i;
    struct charset_map_item *ptr;

    for (ptr = map; ptr && ptr->charset; ptr++) {
	ptr->charset->flags &= ~SET_printed;
	DPRINT(Debug,25,(&Debug, 
			"dump_charset_map: map[%d] %p - '%s' - flags=%X\n",
			 ptr-map,ptr->charset,
			 ptr->charset->MIME_name ? ptr->charset->MIME_name :"<none>",
			 ptr->charset->flags));
    }
    
    for (ptr = map; ptr && ptr->charset; ptr++) {

	if (!ptr->match && 
	    0 != (ptr->charset->flags & SET_printed) &&
	    2 == ptr->is_def)
	    continue;   /* Several aliases lines? */
	if (!ptr->match &&
	    0 == (ptr->charset->flags & SET_valid)) {
	    fputc('#',f);  /* Ignored charset */
	}

	if (ptr->match) 
	    fputs(ptr->match,f);
	else
	    fputc('-',f);

	fputc('\t',f);

	if (0 != (ptr->charset->flags & SET_printed) &&
	    2 == ptr->is_def) {
	    /* Several aliases lines? */
	    goto noalias;
	}

	if (0 ==  (ptr->charset->flags & SET_valid)) {
	    /* Ignored charset? */
	    if (ptr->match)
		goto noalias;
	}

	switch(ptr->is_def) {

	case 0:  /* Simple mapping */
	noalias:
	    if (!ptr->charset->MIME_name) {
		if (ptr->charset->codeset)
		    elm_fprintf(f,FRM("codeset=%Q"),
			    ptr->charset->codeset);
		else
		    fputs("(unsupported)",f);
	    } else if (name_ok(ptr->charset->MIME_name)) {
		fputs(ptr->charset->MIME_name,f);
	    } else {
		elm_fprintf(f,FRM("%Q"),ptr->charset->MIME_name);
	    }
	    break;

	case 1:  /* Redefination */
	    dump_map_info(f,ptr->charset);
	    ptr->charset->flags |= SET_printed;
	    break;

	case 2:  /* alias */

	    if (!ptr->charset->MIME_name) {
		if (ptr->charset->codeset)
		    elm_fprintf(f,FRM("codeset=%Q"),
				ptr->charset->codeset);
		else
		    fputs("# <No MIME name> ",f);
	    } else if (name_ok(ptr->charset->MIME_name)) {
		fputs(ptr->charset->MIME_name,f);
	    } else {
		elm_fprintf(f,FRM("%Q"),ptr->charset->MIME_name);
	    }
	    
	    dump_alias_info(f,ptr->charset);
	    ptr->charset->flags |= SET_printed;
	    break;
	}
	
	fputc('\n',f);
	DPRINT(Debug,25,(&Debug,
			 "dump_charset_map: map[%d] %p - '%s' - flags=%X\n",
			 ptr-map,ptr->charset,
			 ptr->charset->MIME_name ? ptr->charset->MIME_name :"<none>",
			 ptr->charset->flags));
	
    }
}


void free_charset_map(map)
     struct charset_map_item **map;
{
    struct charset_map_item *ptr;

    for (ptr = *map; ptr && ptr->charset; ptr++) {
	if (ptr->match) {
	    free(ptr->match);
	    ptr->match = NULL;
	}
    }

    free(*map);
    *map = NULL;

}

static int match_item P_((struct charset_map_item *a, 
			  struct charset_map_item *b));
static int match_item(a,b)
     struct charset_map_item *a;
     struct charset_map_item*b;
{
    if (a->is_def != b->is_def)
	return 0;
    
    if (a->match && b->match) {

	/* if this is locale -> charset mapping then match item
	   is only required for match 
	*/

	if (0 != strcmp(a->match,b->match))
	    return 0;
	else if (0 == a->is_def)
	    return 1;
	
    } else {
	if (a->match || b->match)
	    return 0;
    }

    if (a->charset == b->charset)
	return 1;

    if (a->charset->MIME_name && b->charset->MIME_name) {
	if (0 == strcmp(a->charset->MIME_name,b->charset->MIME_name))
	    return 1;
	else
	    return 0;
    } else {
	if (a->charset->MIME_name || b->charset->MIME_name)
	    return 0;
    }

    if (a->charset->codeset && b->charset->codeset &&
	0 == strcmp(a->charset->codeset,b->charset->codeset))
	return 1;
    
    return 0;    
}

void change_charset_map(map,new)
     struct charset_map_item **map;
     struct charset_map_item *new;
{
    int count = 0;

    struct charset_map_item *ptr;

    for (ptr = *map; ptr && ptr->charset; ptr++)
	count++;

    for (ptr = new; ptr && ptr->charset; ptr++)
	count++;

    if (!count)
	return;

    if (!*map) {
	*map = safe_malloc((count+1) * sizeof ((*map)[0]));
	(*map)->charset   = NULL;
	
    } else
	*map = safe_realloc(*map, (count+1) * sizeof ((*map)[0]));

    for (ptr = new; ptr && ptr->charset; ptr++) {
	struct charset_map_item *ptr2;

	for (ptr2 = *map; ptr2->charset; ptr2++) {
	    if (match_item(ptr,ptr2)) {
		goto set_it;
	    }
	}

	if (ptr2 > (*map) + count)
	    panic("CHARSET PANIC",__FILE__,__LINE__,"change_charset_map",
		  "Overflow",0);

	ptr2->match     = NULL;
	if (ptr->match)
	    ptr2->match = safe_strdup(ptr->match);
	ptr2->is_def     = ptr->is_def;
 
	(ptr2+1)->match   = NULL;
	(ptr2+1)->charset = NULL;
	
    set_it:
	(ptr2)->charset = ptr->charset;
    }

}



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


syntax highlighted by Code2HTML, v. 0.9.1