static char rcsid[] = "@(#)$Id: charset.c,v 1.92 2006/06/28 19:21:09 hurtta Exp $";
/******************************************************************************
* The Elm (ME+) Mail System - $Revision: 1.92 $ $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"
#ifdef USE_DLOPEN
#include "shared_imp.h"
#endif
#include <errno.h>
#ifndef ANSI_C
extern int errno;
#endif
DEBUG_VAR(Debug,__FILE__,"charset");
struct charset_type * cs_first_type = &cs_unknown;
/* ---------------------------------------------------------------------- */
static struct extra_sets {
struct charcode_info set;
struct extra_sets * next;
} * extra_sets = NULL, * extra_sets_tail = NULL;
static int extra_sets_count = 0;
union compare_info {
CONST char *name;
struct charcode_info * part;
};
typedef int compare_set P_((struct charcode_info *set,
union compare_info data));
static struct charcode_info * find_set P_(( compare_set *func,
union compare_info data ));
static struct charcode_info * find_set(func,data)
compare_set *func;
union compare_info data;
{
int i;
struct extra_sets *walk;
#define TEST(ITEM) \
if (0 != (ITEM.flags & SET_valid) && func(&(ITEM),data)) { \
DPRINT(Debug,9,(&Debug,"find_set: found=%p (%s)\n",&(ITEM),\
ITEM.MIME_name ? ITEM.MIME_name : "<no MIME name>")); \
return &(ITEM); }
#define SCAN(SET) \
for (i = 0; SET[i].charset_type; i++) {\
DPRINT(Debug,72,(&Debug,"find_set: (scan#%d) %p -- flags=%d\n",\
i,&(SET[i]),SET[i].flags)); \
TEST(SET[i]); }
DPRINT(Debug,70,(&Debug,
"find_set: precompiled_sets\n"));
SCAN(precompiled_sets);
DPRINT(Debug,70,(&Debug, "find_set: extra_sets\n"));
for (walk = extra_sets; walk; walk = walk -> next) {
DPRINT(Debug,72,(&Debug, "find_set: (walk) %p -- flags=%d\n",
&(walk->set),walk->set.flags));
TEST(walk->set);
}
DPRINT(Debug,40,(&Debug, "find_set: NOT FOUND\n"));
return NULL;
}
#undef SCAN
#undef SET
/*
Assigned MIB enum Numbers
-------------------------
0-2 Reserved
3-999 Set By Standards Organizations
1000-1999 Unicode / 10646
2000-2999 Vendor
Divide array to 3 classes so memory usage is better ...
*/
struct MIBenum_class MIBenum_CLASS[] = {
{ NULL, 0 } /* 0 - 999 */,
{ NULL, 0 } /* 1000 - 1999 */,
{ NULL, 0 } /* 2000 - 2999 */,
};
CONST int MIBenum_CLASS_len =
sizeof (MIBenum_CLASS) / sizeof (MIBenum_CLASS[0]);
static int array_initialized = 0;
static int add_MIBenum P_((struct charcode_info *ptr));
static int add_MIBenum(ptr)
struct charcode_info *ptr;
{
CONST int MIBenum = ptr->MIBenum;
int MIBenum_class;
int val;
if (MIBenum <= 0)
return 0;
MIBenum_class = MIBenum / MIBenum_class_divide;
val = MIBenum % MIBenum_class_divide;
if (MIBenum_class >= MIBenum_CLASS_len)
return 0;
if (MIBenum_CLASS[MIBenum_class].MIBenum_array_len <= val) {
int X = val+1;
int i;
if (X < 100) X = 100;
MIBenum_CLASS[MIBenum_class].MIBenum_array =
safe_realloc (MIBenum_CLASS[MIBenum_class].MIBenum_array,
X * sizeof (MIBenum_CLASS[MIBenum_class].MIBenum_array[0]));
for (i = MIBenum_CLASS[MIBenum_class].MIBenum_array_len; i < X; i++)
MIBenum_CLASS[MIBenum_class].MIBenum_array[i] = NULL;
MIBenum_CLASS[MIBenum_class].MIBenum_array_len = X;
}
if (MIBenum_CLASS[MIBenum_class].MIBenum_array[val] &&
MIBenum_CLASS[MIBenum_class].MIBenum_array[val] != ptr &&
MIBenum_CLASS[MIBenum_class].MIBenum_array[val] -> flags & SET_valid)
return 0;
if (MIBenum_CLASS[MIBenum_class].MIBenum_array[val])
MIBenum_CLASS[MIBenum_class].MIBenum_array[val] -> MIBenum = 0;
MIBenum_CLASS[MIBenum_class].MIBenum_array[val] = ptr;
return 1;
}
static void add_builtin_sets P_((void));
static void add_builtin_sets(void)
{
int i;
for (i = 0; precompiled_sets[i].charset_type; i++) {
if (precompiled_sets[i].MIBenum) {
DPRINT(Debug,49,(&Debug,"(#%d) Setting MIBEnum for %s (%d)\n",
i,
precompiled_sets[i].MIME_name ?
precompiled_sets[i].MIME_name :
"<no MIME name>",
precompiled_sets[i].MIBenum));
if (!add_MIBenum(& (precompiled_sets[i]))) {
panic("CHARSET PANIC",__FILE__,__LINE__,"add_builtin_set",
"Duplicate or bad MIBenum on builtin set",0);
}
}
}
array_initialized++;
}
static struct charcode_info * add_set P_((struct charcode_info s));
static struct charcode_info * add_set(s)
struct charcode_info s;
{
struct extra_sets *tmp = safe_malloc( sizeof (struct extra_sets));
if (CS_charset_magic != s.magic)
panic("STRING PANIC",__FILE__,__LINE__,"add_set",
"Bad magic number",0);
tmp->set = s;
tmp->next = NULL;
if (!array_initialized)
add_builtin_sets();
if (extra_sets_tail)
extra_sets_tail->next = tmp;
extra_sets_tail = tmp;
if (!extra_sets)
extra_sets = tmp;
extra_sets_count++;
if (tmp->set.MIME_name) {
DPRINT(Debug,1,(&Debug,
"charset: Adding charset %s (type %s)\n",
tmp->set.MIME_name,
tmp->set.charset_type->type_name));
}
if (tmp->set.MIBenum && !add_MIBenum(& (tmp->set))) {
lib_error(CATGETS(elm_msg_cat, MeSet,
MeDuplicateMibEnum,
"Charset %s have duplicate or bad MIBenum %d"),
tmp->set.MIME_name ? tmp->set.MIME_name : "<no MIME name>",
tmp->set.MIBenum);
tmp->set.MIBenum = 0; /* Discard MIBEnum */
}
return &(tmp->set);
}
#if defined(WCHAR) && defined(__STDC_ISO_10646__)
void change_system_charset_1 P_((void));
void change_system_charset()
{
char ** cs;
int i;
if (system_charset->charset_type == &cs_unknown) {
DPRINT(Debug,9,(&Debug,"change_system_charset: System charset is already type unknown\n"));
return;
}
if (!system_charset->MIME_name) {
DPRINT(Debug,9,(&Debug,"change_system_charset: System charset have no MIME name\n"));
return;
}
cs = give_dt_path_as_elems(&locale_charsets,"locale-charsets");
if (!cs) {
DPRINT(Debug,9,(&Debug,
"change_system_charset: No change: locale-charsets list empty\n"));
return;
}
for (i = 0; cs[i]; i++) {
if (0 == istrcmp(cs[i],system_charset->MIME_name)) {
DPRINT(Debug,9,(&Debug,
"change_system_charset: Found system charset %s from list, item #%d\n",
system_charset->MIME_name,i));
break;
}
}
if (!cs[i]) {
DPRINT(Debug,9,(&Debug,
"change_system_charset: No change\n"));
return;
}
change_system_charset_1();
}
void change_system_charset_1() {
struct charcode_info new_vals;
charset_t x;
new_vals = *system_charset;
new_vals.charset_type = &cs_unknown;
new_vals.map_info = NULL;
new_vals.flags |= SET_nodata;
system_charset->flags &= ~SET_valid;
x = add_set(new_vals);
DPRINT(Debug,9,(&Debug,
"change_system_charset_1: Changed system charset %s (type %s) to type unknown\n",
system_charset->MIME_name,
system_charset->charset_type->type_name));
system_charset = x;
}
#endif
static int same_name P_((struct charcode_info *set, union compare_info data));
static int same_name (set,data)
struct charcode_info *set;
union compare_info data;
{
DPRINT(Debug,71,(&Debug,
"same_name -- set=%p (MIME_name=%s,codeset=%s,data.name=%s)\n",
set,
set->MIME_name ? set->MIME_name : "<NULL>",
set->codeset ? set->codeset : "<NULL>",
data.name));
if (set->codeset &&
0 == istrcmp(data.name,set->codeset))
return 1;
if (!set->MIME_name)
return 0;
return 0 == istrcmp(data.name,set->MIME_name);
}
struct charset_alias * charset_alias_list = NULL;
int charset_alias_count = 0;
static int locate_charset_alias P_((const char * name));
static int locate_charset_alias(name)
CONST char * name;
{
int i;
for (i = 0; i < charset_alias_count; i++)
if (0 == istrcmp(charset_alias_list[i].name,name))
return i;
return -1;
}
static int add_charset_alias P_((const char * name, charset_t set));
static int add_charset_alias(name,set)
CONST char * name;
charset_t set;
{
charset_alias_list = safe_realloc(charset_alias_list,
(charset_alias_count +1) *
sizeof (struct charset_alias));
charset_alias_list[charset_alias_count].name = safe_strdup(name);
charset_alias_list[charset_alias_count].set = set;
return charset_alias_count++;
}
charset_t codeset_name_to_charset (name)
CONST char *name;
{
charset_t ret;
union compare_info D;
D.name = name;
ret = find_set(same_name,D);
return ret;
}
charset_t MIME_name_to_charset (name,flag)
CONST char *name;
int flag;
{
int create = flag & CHARSET_create;
CONST int noautodef = flag & CHARSET_noautodef;
int i;
charset_t ret;
struct charcode_info new;
int do_ascii = 0;
int do_cs = 0;
struct charset_type * cs_type = NULL;
struct map_info * cs_map = NULL;
uint16 MIBenum = 0;
union compare_info D;
D.name = name;
ret = find_set(same_name,D);
if (!ret && 0 == istrcmp(name,"US-ASCII")) {
DPRINT(Debug,7,(&Debug,
"MIME_name_to_charset: US-ASCII not found -- using builting constant...\n"));
ret = ASCII_SET;
}
if (!ret && 0 == istrcmp(name,"UTF-8")) {
DPRINT(Debug,7,(&Debug,
"MIME_name_to_charset: UTF-8 not found -- using builting constant...\n"));
ret = UTF8_ENCODING; /* This is NOT from precompiled_sets[..] */
}
if (ret && &cs_unknown == ret->charset_type &&
0 == (charset_properties(ret) & CS_mapping)) {
DPRINT(Debug,9,(&Debug, "MIME_name_to_charset(%s), found=%p as unknown\n",
name,ret));
#ifdef USE_DLOPEN
if (!noautodef &&
cs_auto_charset(name,&cs_type,&cs_map)) {
DPRINT(Debug,9,(&Debug,
"MIME_name_to_charset: Using autocreate instead... (MIBenum=%d)\n",
(int) ret->MIBenum));
do_cs = 1;
create = 1;
ret-> flags &= ~SET_valid; /* Invalidate result so that
autocreated set is found instead
*/
MIBenum = ret->MIBenum;
goto create_new;
}
#endif
}
if (ret) {
DPRINT(Debug,9,(&Debug, "MIME_name_to_charset(%s), found=%p",
name,ret));
found_it:
if (ret->codeset) {
DPRINT(Debug,9,(&Debug, ", codeset=%s",ret->codeset));
}
DPRINT(Debug,9,(&Debug, "\n",ret->codeset));
if (!ret->MIME_name && create) {
CONST char * X = ret->codeset ? ret->codeset : name; /* Should be unnecessary */
DPRINT(Debug,1,(&Debug,"*** No MIME name for charset %s, using %s as MIME name\n",
name,X));
ret->MIME_name = safe_strdup(X);
}
if (!ret->MIME_name) {
DPRINT(Debug,1,(&Debug,"*** No MIME name for charset %s (codeset %s)\n",
name,ret->codeset ? ret->codeset : "<?>"));
lib_error(CATGETS(elm_msg_cat, MeSet,
MeNoMIMEname,
"Charset %s exists, but that is not suitable name for MIME use"),
name);
return NULL;
}
/* Initialize associated map if not done already ... */
if (ret->map_info && !ret->map_info->map_initialized)
ret->map_info->map_init_it(ret->map_info);
return ret;
}
/* Check aliases ... */
if (0 <= (i = locate_charset_alias(name)) &&
(ret = charset_alias_list[i].set) &&
ret->MIME_name &&
/* Ignore aliases which point invalidated charsets.
These charsets may me invalidated by setting
explicit compatcharsets on user's elmrc
*/
(0 != (ret-> flags & SET_valid))) {
DPRINT(Debug,9,(&Debug,
"MIME_name_to_charset(%s), found=%p (alias of %s)",
name,ret,
ret->MIME_name ? ret->MIME_name : "<no MIME name>"));
goto found_it;
}
if (!ret && 0 == strincmp(name,"ISO-8859-",9) &&
0 < (i = atoi(name+9))) {
DPRINT(Debug,7,(&Debug, "MIME_name_to_charset: ISO-8859-X charset, "));
if (noautodef) {
DPRINT(Debug,7,(&Debug, "CHARSET_noautodef set\n"));
} else if (auto_iso_8859) {
do_ascii = 1;
create = 1;
DPRINT(Debug,7,(&Debug, " autocreating (as subtype of builtin ASCII constant)\n"));
} else {
DPRINT(Debug,7,(&Debug, "auto-iso-8859 is not set.\n"));
}
}
#ifdef USE_DLOPEN
if (!ret && !noautodef &&
cs_auto_charset(name,&cs_type,&cs_map)) {
do_cs = 1;
create = 1;
DPRINT(Debug,7,(&Debug,
"MIME_name_to_charset: %s charset, autocreating\n",
name));
}
#endif
if (!create) {
DPRINT(Debug,12,(&Debug,"MIME_name_to_charset(%s), not found\n",
name));
return NULL;
}
#ifdef USE_DLOPEN
create_new:
#endif
new.magic = CS_charset_magic;
new.flags = SET_nodata|SET_valid;
new.map_info = NULL;
new.MIME_name = safe_strdup(name);
if (do_cs) {
new.map_info = cs_map;
new.charset_type = cs_type;
new.subtype = NULL;
} else if (do_ascii) {
new.charset_type = &cs_ascii;
new.subtype = ASCII_SET;
} else {
new.charset_type = &cs_unknown;
new.subtype = NULL;
}
new.iso2022_info = NULL;
new.MIBenum = MIBenum;
new.codeset = NULL;
ret = add_set(new);
DPRINT(Debug,12,(&Debug,"MIME_name_to_charset(%s), adding=%p\n",
name,ret));
return ret;
}
char * dequote_opt(source,len)
CONST char *source;
int len;
{
int size = len + 1;
int ptr = 0;
char * store = safe_malloc(size);
CONST char *p;
int q = 0;
for (p = source; p - source < len && ptr < size-1; p++) {
switch(*p) {
case '"':
q = !q;
break;
case '\\':
if (q) {
p++;
if (*p != '\0')
store[ptr++] = *p;
else {
lib_error(CATGETS(elm_msg_cat, MeSet,
MeTrailingBackslash,
"Trailing backslash (\\): %.20s..."),
source);
}
break;
}
/* FALLTHRU */
default:
if (q || *p != ' ')
store[ptr++] = *p;
break;
}
}
store[ptr] = '\0';
if (q)
lib_error(CATGETS(elm_msg_cat, MeSet,
MeUnbalancedQuote,
"Unbalanced quote (\"): %.20s..."),
source);
DPRINT(Debug,20,(&Debug,
"dequote_opt(%.*s (len=%d))=%s\n",
len,source,len,store));
return store;
}
/* 0 == nothinh load, 1 == defination, 2 == alias only */
int load_charset_map_info(buffer,data)
charset_t *buffer;
CONST char *data;
{
char * temp = safe_strdup(data);
char *c;
char *store,*opt;
struct charcode_info new_vals;
int reallocation_needed = 0;
char ** alias_vector = NULL;
int alias_count = 0;
struct setlist new_setlist;
int setcount = 0;
int define_as_codeset = 0;
int ret = 0;
iso2022_clear_setlist(&new_setlist);
if (0 == strncmp(data,"codeset=",8)) {
store = NULL;
*buffer = NULL;
reallocation_needed = 0; /* codeset= code will set this */
new_vals.magic = CS_charset_magic;
new_vals.charset_type = &cs_unknown;
new_vals.map_info = NULL;
new_vals.flags = SET_valid;
new_vals.MIME_name = NULL;
new_vals.subtype = NULL;
new_vals.iso2022_info = NULL;
new_vals.MIBenum = 0;
new_vals.codeset = NULL;
define_as_codeset = 1;
c = temp;
goto codeset_hook;
}
c = qstrpbrk(temp,";");
if (!c) {
*buffer = NULL;
DPRINT(Debug,7,(&Debug,
"load_charset_map_info(\"%s\") = 0 (FAIL)\n",
data));
free(temp);
return 0;
}
store = dequote_opt(temp,c - temp);
DPRINT(Debug,11,(&Debug,
"load_charset_map_info: charset=%s\n",
store));
DPRINT(Debug,11,(&Debug,
"load_charset_map_info: info=%s\n", c));
*buffer = MIME_name_to_charset(store,0);
if (!*buffer) {
reallocation_needed = 1;
new_vals.magic = CS_charset_magic;
new_vals.charset_type = &cs_unknown;
new_vals.map_info = NULL;
new_vals.flags = SET_valid;
new_vals.MIME_name = safe_strdup(store);
new_vals.subtype = NULL;
new_vals.iso2022_info = NULL;
new_vals.MIBenum = 0;
new_vals.codeset = NULL;
} else
new_vals = **buffer;
c++;
if ('\0' == *c || 0 == strcmp(c,"!")) {
DPRINT(Debug,9,(&Debug,"charset: %s: no data\n",store));
new_vals.flags |= SET_nodata;
} else {
int i;
char * WALK;
if (0 <= (i = locate_charset_alias(store)) &&
charset_alias_list[i].set == *buffer) {
DPRINT(Debug,1,(&Debug,
"DANGER: Defining charset %s which is also alias of %s\n",
store,
charset_alias_list[i].set->MIME_name ?
charset_alias_list[i].set->MIME_name :
"<no MIME name>"));
alias_vector = safe_realloc(alias_vector,
(alias_count+1) *
sizeof (char *));
alias_vector[alias_count++] = safe_strdup(store);
lib_error(CATGETS(elm_msg_cat, MeSet,
MeTryingCharsetAlias,
"Trying redefine alias %s as charset"),
store);
}
codeset_hook:
WALK = NULL;
for (opt = mime_parse_content_opts(c, &WALK);
opt;
opt = mime_parse_content_opts(NULL, &WALK)) {
char * q = strchr(opt,'=');
DPRINT(Debug,20,(&Debug, "mime_parse_content_opts gives: %s\n",
opt));
if (q) {
char *val;
*q++ = '\0';
val = dequote_opt(q,strlen(q));
if (0 == strcmp(opt,"codeset")) {
charset_t X = codeset_name_to_charset(val);
if (X && X != *buffer && !define_as_codeset) {
lib_error(CATGETS(elm_msg_cat, MeSet,
MeCodesetRedefined,
"Codeset %s redefined -- invalidating old charset %s"),
X->codeset ? X->codeset : val,
X->MIME_name ? X->MIME_name : val);
X -> flags &= ~SET_valid;
}
if (define_as_codeset) {
*buffer = X;
if (X) {
new_vals = *X;
free(val); val = NULL;
} else {
reallocation_needed = 1;
new_vals.codeset = val; val = NULL;
}
define_as_codeset = 0;
} else {
reallocation_needed = 1;
new_vals.codeset = val; val = NULL;
}
} else if (0 == strcmp(opt,"MIBenum")) {
new_vals.MIBenum = atoi(val);
if (new_vals.MIBenum < 1) {
lib_error(CATGETS(elm_msg_cat, MeSet,
MeBadMIBenum,
"Bad MIBenum %s"),
val);
new_vals.MIBenum = 0;
}
free(val); val = NULL;
} else if (0 == strcmp(opt,"MIME-subset")) {
reallocation_needed = 1;
new_vals.flags &= ~SET_nodata;
new_vals.subtype = MIME_name_to_charset(val,0);
if (!new_vals.subtype) {
lib_error(CATGETS(elm_msg_cat, MeSet,
MeUnknownMIMEsubset,
"Unknown MIME-subset %s"),
val);
}
if (0 == istrcmp(val,"US-ASCII") &&
&cs_unknown == new_vals.charset_type)
new_vals.charset_type = &cs_ascii;
if (0 == istrcmp(val,"INVARIANT") &&
&cs_unknown == new_vals.charset_type)
new_vals.charset_type = &cs_iso646;
free(val); val = NULL;
} else if (0 == strcmp(opt,"map")) {
struct map_info * r;
if (new_vals.charset_type == &cs_unknown) {
lib_error(CATGETS(elm_msg_cat, MeSet,
MeCharsetTypeBeforeMap,
"Charset type must be given before map -parameter"));
}
r = new_vals.charset_type->find_map_type(val);
if (!r) {
lib_error(CATGETS(elm_msg_cat, MeSet,
MeUnknownMap,
"No map %s on charset type %s"),
val,new_vals.charset_type->type_name);
} else {
reallocation_needed = 1;
new_vals.flags &= ~SET_nodata;
new_vals.map_info = r;
}
free(val); /* ?? */ val = NULL;
} else if (0 == strcmp(opt,"type")) {
struct charset_type * walk;
for (walk = cs_first_type; walk; walk = walk -> next_type)
if (0 == strcmp(val,walk->type_name))
break;
#ifdef USE_DLOPEN
if (!walk)
walk = find_shared_CS_type(val);
#endif
if (!walk) {
lib_error(CATGETS(elm_msg_cat, MeSet,
MeUnknownCharsetType,
"Unknown charset type %s"),
val);
walk = &cs_unknown;
}
reallocation_needed = 1;
new_vals.flags &= ~SET_nodata;
new_vals.charset_type = walk;
free(val); val = NULL;
} else if (0 == strcmp(opt,"alias")) {
if (new_vals.codeset &&
0 == istrcmp(new_vals.codeset,val)) {
DPRINT(Debug,1,(&Debug,
"charset: Ignoring alias=\"%s\" for codeset=\"%s\"\n",
val,new_vals.codeset));
free(val); val = NULL;
} else if (new_vals.MIME_name &&
0 == istrcmp(new_vals.MIME_name,val)) {
DPRINT(Debug,1,(&Debug,
"charset: Ignoring alias=\"%s\" for charset %s\n",
val,new_vals.MIME_name));
free(val); val = NULL;
} else {
int i = locate_charset_alias(val);
charset_t p1;
if (i < 0 &&
(p1 = codeset_name_to_charset(val))) {
lib_error(CATGETS(elm_msg_cat, MeSet,
MeTryingAliasCodeset,
"Trying redefine codeset %s as alias"),
p1->codeset ? p1->codeset :
p1->MIME_name ? p1->MIME_name :
val);
free(val); val = NULL;
} else {
alias_vector = safe_realloc(alias_vector,
(alias_count+1) *
sizeof (char *));
alias_vector[alias_count++] = val; val = NULL;
}
}
} else if (parse_iso2022_specification(opt,val,
&setcount,
&new_setlist)) {
/* none */
free(val); /* ?? */ val = NULL;
} else {
lib_error(CATGETS(elm_msg_cat, MeSet,
MeUnsupportedCharsetOption,
"Unsupported charset option %s (value %.20s...)"),
opt,val);
free(val); val = NULL;
}
} else {
lib_error(CATGETS(elm_msg_cat, MeSet,
MeUnsupportedCharsetOptionNoValue,
"Unsupported charset option %s (no value)"),
opt);
}
}
}
if (setcount > 0) {
if (new_vals.iso2022_info)
iso2022_merge_old_info(&new_setlist,setcount,new_vals.iso2022_info);
if (new_vals.charset_type->cs_iso2022_info_set_it(&new_vals,&new_setlist,
setcount)) {
reallocation_needed = 1;
new_vals.flags &= ~SET_nodata;
} else
goto iso2022_fail; /* Discard bank defination */
/* TODO: Other processing? */
}
iso2022_fail:
if (reallocation_needed) {
/* Reset incompatble map types ... */
if (new_vals.map_info &&
new_vals.map_info->map_type != new_vals.charset_type) {
DPRINT(Debug,1,(&Debug,
"charset: Resetting incompatible map %s (type %s) from charset %s (type %s)\n",
new_vals.map_info->map_name,
new_vals.map_info->map_type->type_name,
new_vals.MIME_name ?
new_vals.MIME_name : "<no MIME name>",
new_vals.charset_type->type_name));
new_vals.map_info = NULL;
}
if (!new_vals.map_info && &cs_onebyte == new_vals.charset_type) {
lib_error(CATGETS(elm_msg_cat, MeSet, MeNeedsMapParamater,
"Charset type %s requires map parameter"),
new_vals.charset_type->type_name);
if (new_vals.subtype == ASCII_SET) {
DPRINT(Debug,1,(&Debug,
"charset: Charset %s: setting type to %s instead of %s\n",
(*buffer)->MIME_name ?
(*buffer)->MIME_name : "<no MIME name>",
cs_ascii.type_name,
new_vals.charset_type->type_name));
new_vals.charset_type = &cs_ascii;
}
if (new_vals.subtype == INVARIANT_SET) {
DPRINT(Debug,1,(&Debug,
"charset: Charset %s: setting type to %s instead of %s\n",
(*buffer)->MIME_name ?
(*buffer)->MIME_name : "<no MIME name>",
cs_iso646.type_name,
new_vals.charset_type->type_name));
new_vals.charset_type = &cs_iso646;
}
}
if (*buffer) {
(*buffer) -> flags &= ~SET_valid;
DPRINT(Debug,1,(&Debug,
"charset: Invalidating charset %s (and regenerating)\n",
(*buffer)->MIME_name ?
(*buffer)->MIME_name : "<no MIME name>"));
}
*buffer = add_set(new_vals);
DPRINT(Debug,9,(&Debug,
"charset: Adding "));
if ((*buffer)->MIME_name) {
DPRINT(Debug,9,(&Debug,
"charset %s ",
(*buffer)->MIME_name));
}
if ((*buffer)->codeset) {
DPRINT(Debug,9,(&Debug,
"codeset %s ",
(*buffer)->codeset));
}
DPRINT(Debug,9,(&Debug,
"(type %s) = %p\n",
(*buffer)->charset_type->type_name,
*buffer));
}
if (alias_vector) {
int i;
for (i = 0; i < alias_count; i++) {
int j = locate_charset_alias(alias_vector[i]);
if (j < 0)
j = add_charset_alias(alias_vector[i],*buffer);
/* In case of we redefine alias ... */
/* This is BUGGY on case of multiple aliases */
charset_alias_list[j].set->flags &= ~SET_havealias;
(*buffer) -> flags |= SET_havealias;
DPRINT(Debug,9,(&Debug,
"load_charset_map_info: Setting %s as alias of %s\n",
charset_alias_list[j].name,
(*buffer)->MIME_name ?
(*buffer)->MIME_name : "<no MIME name>"));
charset_alias_list[j].set = *buffer;
free(alias_vector[i]);
alias_vector[i] = NULL;
}
free(alias_vector);
ret = 2;
}
if (reallocation_needed)
ret = 1;
DPRINT(Debug,9,(&Debug,
"load_charset_map_info(\"%s\") = %d (SUCCEED)\n",
data,ret));
free(temp);
if (store)
free(store);
return ret;
}
int charset_superset_of(charset,subset)
charset_t charset,subset;
{
int res = 0;
int loop = 0;
charset_t p;
DPRINT(Debug,6,(&Debug,
"charset_superset_of(%p (%s),%p (%s))\n",
charset,
charset->MIME_name ? charset->MIME_name :"<no MIME name>",
subset,subset->MIME_name ? subset->MIME_name :"<no MIME name>"));
for (p = charset; p; p = p->subtype) {
DPRINT(Debug,6,(&Debug, " subset: %p (%s)\n",
p,
p->MIME_name ? p->MIME_name :"<no MIME name>"));
if (p == subset) {
DPRINT(Debug,6,(&Debug, " subset found\n"));
res = 1;
}
if (p->subtype == charset) {
DPRINT(Debug,6,(&Debug, " loop found\n"));
lib_error(CATGETS(elm_msg_cat, MeSet, MeCharsetSubsetLoop,
"Charset subset defination loop detected for %s"),
charset->MIME_name ? charset->MIME_name : "<no MIME name>");
break;
}
if (loop++ > 20) {
/* Catch other loop which do not go tgrough original set */
lib_error(CATGETS(elm_msg_cat, MeSet, MeCharsetSubsetLoop,
"Charset subset defination loop detected for %s"),
p->MIME_name ? p->MIME_name : "<no MIME name>");
break;
}
}
DPRINT(Debug,6,(&Debug,
"charset_superset_of=%d\n",
res));
return res;
}
int charset_ok_p(ptr)
charset_t ptr;
{
int r;
charset_t ascii_ptr = MIME_name_to_charset("US-ASCII",0);
if (!ascii_ptr)
panic("CHARSET PANIC",__FILE__,__LINE__,"charset_ok_p",
"US-ASCII not found",0);
r = charset_superset_of(ptr,ascii_ptr);
if (r && &cs_ascii != ptr->charset_type) {
DPRINT(Debug,6,(&Debug,
"charset_ok_p: charset %p (%s) is superset of ascii %p (%s) but is not type cs_ascii (type = %p)\n",
ptr,
ptr->MIME_name ? ptr->MIME_name :"<no MIME name>",
ascii_ptr,
ascii_ptr->MIME_name ? ascii_ptr->MIME_name :"<no MIME name>",
ptr->charset_type));
}
if (!r && &cs_ascii == ptr->charset_type) { /* Hack !! */
DPRINT(Debug,6,(&Debug,
"charset_ok_p: charset %p (%s) is not superset of ascii %p (%s) but is type cs_ascii (type = %p), returning OK\n",
ptr,
ptr->MIME_name ? ptr->MIME_name :"<no MIME name>",
ascii_ptr,
ascii_ptr->MIME_name ? ascii_ptr->MIME_name :"<no MIME name>"));
r = 1;
}
return r;
}
struct charset_map_item * load_charset_map(filename,errors)
CONST char *filename;
int *errors;
{
struct charset_map_item *result;
int result_len = 0;
FILE * f;
int max_result = 0;
int c,l1;
char buf[LONG_STRING];
int err = can_open(filename,"r");
if (!array_initialized)
add_builtin_sets();
if(err) {
DPRINT(Debug,2,(&Debug,
"load_charset_map: %s: %s (can_open)\n",
filename,error_description(err)));
return NULL;
}
f = fopen(filename,"r");
if (!f) {
int err = errno;
DPRINT(Debug,2,(&Debug,
"load_charset_map: %s: %s\n",
filename,error_description(err)));
return NULL;
}
while(EOF != (c = fgetc(f)))
if ('\n' == c)
max_result++;
DPRINT(Debug,11,(&Debug,
"load_charset_map: %s, max_result=%d\n",
filename,max_result));
if (!max_result) {
fclose(f);
return NULL;
}
rewind(f);
result = safe_malloc((max_result +1) * sizeof (struct charset_map_item));
while (result_len < max_result &&
(l1 = mail_gets(buf,sizeof buf, f)) > 0) {
char * c = buf,*c1;
if ('\n' == buf[l1 -1])
buf[l1 - 1] = '\0';
else {
lib_error(CATGETS(elm_msg_cat, MeSet, MeTooLongLine,
"%.30s: Too long line: %.30s..."),
filename,buf);
(*errors) ++;
break;
}
l1--;
while (l1-- > 0 && whitespace(buf[l1]))
buf[l1] = '\0';
c = buf;
while (*c && whitespace (*c)) /* skip leading whitespace */
c++;
if ('#' == *c)
continue;
if (!*c)
continue;
c1 = strpbrk(c," \t");
if (!c1) {
lib_error(CATGETS(elm_msg_cat, MeSet, MeBadLine,
"%.30s: Bad line: %.30s..."),
filename,buf);
(*errors) ++;
break;
}
*c1 = '\0';
c1++;
while (*c1 && whitespace (*c1)) /* skip leading whitespace */
c1++;
if (!*c1) {
lib_error(CATGETS(elm_msg_cat, MeSet, MeBadLine,
"%.30s: Bad line: %.30s..."),
filename,buf);
(*errors) ++;
break;
}
result[result_len].match = NULL;
result[result_len].charset = NULL;
result[result_len].is_def = 0;
if (0 == strcmp(c,"-")) {
result[result_len].match = NULL;
result[result_len].is_def =
load_charset_map_info(&result[result_len].charset,c1);
if (!result[result_len].is_def) {
lib_error(CATGETS(elm_msg_cat, MeSet, MeNotCharsetDeclaration,
"%.30s: Not charset declaration: %.30s..."),
filename,c1);
(*errors) ++;
break;
}
} else {
result[result_len].match = safe_strdup(c);
if (0 == strcmp(c1,"(unsupported)")) {
/* Adding nameless unsupported charset */
struct charcode_info new;
charset_t ret;
new.magic = CS_charset_magic;
new.flags = 0;
new.map_info = NULL;
new.MIME_name = NULL;
new.charset_type = &cs_unknown;
new.subtype = NULL;
new.iso2022_info = NULL;
new.MIBenum = 0;
new.codeset = NULL;
ret = add_set(new);
DPRINT(Debug,11,(&Debug,"Adding (unsupported) =%p\n",
ret));
result[result_len].charset = ret;
} else {
result[result_len].is_def =
load_charset_map_info(&result[result_len].charset,c1);
if (! result[result_len].is_def &&
! result[result_len].charset)
result[result_len].charset =
MIME_name_to_charset(c1,CHARSET_create);
}
}
DPRINT(Debug,11,(&Debug,"Added map[%d] %-15s %-15s (flags %X)\n",
result_len,
result[result_len].match ?
result[result_len].match : "- (define)",
result[result_len].charset->MIME_name ?
result[result_len].charset->MIME_name :
"(unsupported -- no MIME name)",
result[result_len].charset->flags));
result_len++;
}
result[result_len].match = NULL;
result[result_len].charset = NULL;
fclose(f);
DPRINT(Debug,11,(&Debug,"load_charset_map: %s, result_len=%d\n",
filename,result_len));
return result;
}
/*
* Local Variables:
* mode:c
* c-basic-offset:4
* buffer-file-coding-system: iso-8859-1
* End:
*/
syntax highlighted by Code2HTML, v. 0.9.1