/** * Initialize iconv conversion descriptors. * * This is called the first time it is needed, and also called again * every time the configuration is reloaded, because the charset or * codepage might have changed. **/ void init_iconv(void) { int c1; for (c1=0;c1<NUM_CHARSETS;c1++) { const char *name = charset_name((charset_t)c1); conv_handles[c1][CH_UCS2] = atalk_iconv_open( charset_name(CH_UCS2), name); if (conv_handles[c1][CH_UCS2] == (atalk_iconv_t)-1) { LOG(log_error, logtype_default, "Required conversion from %s to %s not supported", name, charset_name(CH_UCS2)); conv_handles[c1][CH_UCS2] = NULL; } if (c1 != CH_UCS2) { /* avoid lost memory, make valgrind happy */ conv_handles[CH_UCS2][c1] = atalk_iconv_open( name, charset_name(CH_UCS2)); if (conv_handles[CH_UCS2][c1] == (atalk_iconv_t)-1) { LOG(log_error, logtype_default, "Required conversion from %s to %s not supported", charset_name(CH_UCS2), name); conv_handles[CH_UCS2][c1] = NULL; } } charsets[c1] = get_charset_functions (c1); } }
/* * FIXME the size is a mess we really need a malloc/free logic *`dest size must be dest_len +2 */ size_t convert_charset ( charset_t from_set, charset_t to_set, charset_t cap_charset, const char *src, size_t src_len, char *dest, size_t dest_len, uint16_t *flags) { size_t i_len, o_len; ucs2_t *u; ucs2_t buffer[MAXPATHLEN +2]; ucs2_t buffer2[MAXPATHLEN +2]; lazy_initialize_conv(); /* convert from_set to UCS2 */ if ((size_t)(-1) == ( o_len = pull_charset_flags( from_set, to_set, cap_charset, src, src_len, (char *) buffer, sizeof(buffer) -2, flags)) ) { LOG(log_error, logtype_default, "Conversion failed ( %s to CH_UCS2 )", charset_name(from_set)); return (size_t) -1; } if ( o_len == 0) return o_len; /* Do pre/decomposition */ i_len = sizeof(buffer2) -2; u = buffer2; if (CHECK_FLAGS(flags, CONV_DECOMPOSE) || (charsets[to_set] && (charsets[to_set]->flags & CHARSET_DECOMPOSED)) ) { if ( (size_t)-1 == (i_len = decompose_w(buffer, o_len, u, &i_len)) ) return (size_t)(-1); } else if (CHECK_FLAGS(flags, CONV_PRECOMPOSE) || !charsets[from_set] || (charsets[from_set]->flags & CHARSET_DECOMPOSED)) { if ( (size_t)-1 == (i_len = precompose_w(buffer, o_len, u, &i_len)) ) return (size_t)(-1); } else { u = buffer; i_len = o_len; } /* null terminate */ u[i_len] = 0; u[i_len +1] = 0; /* Do case conversions */ if (CHECK_FLAGS(flags, CONV_TOUPPER)) { strupper_w(u); } else if (CHECK_FLAGS(flags, CONV_TOLOWER)) { strlower_w(u); } /* Convert UCS2 to to_set */ if ((size_t)(-1) == ( o_len = push_charset_flags( to_set, cap_charset, (char *)u, i_len, dest, dest_len, flags )) ) { LOG(log_error, logtype_default, "Conversion failed (CH_UCS2 to %s):%s", charset_name(to_set), strerror(errno)); return (size_t) -1; } /* null terminate */ dest[o_len] = 0; dest[o_len +1] = 0; return o_len; }
charset_t add_charset(const char* name) { static charset_t max_charset_t = NUM_CHARSETS-1; charset_t cur_charset_t = max_charset_t+1; unsigned int c1; lazy_initialize_conv(); for (c1=0; c1<=max_charset_t;c1++) { if ( strcasecmp(name, charset_name(c1)) == 0) return (c1); } if ( cur_charset_t >= MAX_CHARSETS ) { LOG (log_debug, logtype_default, "Adding charset %s failed, too many charsets (max. %u allowed)", name, MAX_CHARSETS); return (charset_t) -1; } /* First try to setup the required conversions */ conv_handles[cur_charset_t][CH_UCS2] = atalk_iconv_open( charset_name(CH_UCS2), name); if (conv_handles[cur_charset_t][CH_UCS2] == (atalk_iconv_t)-1) { LOG(log_error, logtype_default, "Required conversion from %s to %s not supported", name, charset_name(CH_UCS2)); conv_handles[cur_charset_t][CH_UCS2] = NULL; return (charset_t) -1; } conv_handles[CH_UCS2][cur_charset_t] = atalk_iconv_open( name, charset_name(CH_UCS2)); if (conv_handles[CH_UCS2][cur_charset_t] == (atalk_iconv_t)-1) { LOG(log_error, logtype_default, "Required conversion from %s to %s not supported", charset_name(CH_UCS2), name); conv_handles[CH_UCS2][cur_charset_t] = NULL; return (charset_t) -1; } /* register the new charset_t name */ charset_names[cur_charset_t] = strdup(name); charsets[cur_charset_t] = get_charset_functions (cur_charset_t); max_charset_t++; #ifdef DEBUG LOG(log_debug9, logtype_default, "Added charset %s with handle %u", name, cur_charset_t); #endif return (cur_charset_t); }
static struct charset_functions* get_charset_functions (charset_t ch) { if (charsets[ch] != NULL) return charsets[ch]; charsets[ch] = find_charset_functions(charset_name(ch)); return charsets[ch]; }
size_t convert_string_allocate(charset_t from, charset_t to, void const *src, size_t srclen, char ** dest) { size_t i_len, o_len; ucs2_t *u; ucs2_t buffer[MAXPATHLEN]; ucs2_t buffer2[MAXPATHLEN]; *dest = NULL; /* convert from_set to UCS2 */ if ((size_t)(-1) == ( o_len = convert_string_internal( from, CH_UCS2, src, srclen, buffer, sizeof(buffer))) ) { LOG(log_error, logtype_default, "Conversion failed ( %s to CH_UCS2 )", charset_name(from)); return (size_t) -1; } /* Do pre/decomposition */ i_len = sizeof(buffer2); u = buffer2; if (charsets[to] && (charsets[to]->flags & CHARSET_DECOMPOSED) ) { if ( (size_t)-1 == (i_len = decompose_w(buffer, o_len, u, &i_len)) ) return (size_t)-1; } else if ( !charsets[from] || (charsets[from]->flags & CHARSET_DECOMPOSED) ) { if ( (size_t)-1 == (i_len = precompose_w(buffer, o_len, u, &i_len)) ) return (size_t)-1; } else { u = buffer; i_len = o_len; } /* Convert UCS2 to to_set */ if ((size_t)-1 == ( o_len = convert_string_allocate_internal( CH_UCS2, to, (char*)u, i_len, dest)) ) LOG(log_error, logtype_default, "Conversion failed (CH_UCS2 to %s):%s", charset_name(to), strerror(errno)); return o_len; }
/** * Initialize iconv conversion descriptors. * * This is called the first time it is needed, and also called again * every time the configuration is reloaded, because the charset or * codepage might have changed. **/ void init_iconv(void) { int c1, c2; BOOL did_reload = False; /* so that charset_name() works we need to get the UNIX<->UCS2 going first */ if (!conv_handles[CH_UNIX][CH_UTF16LE]) conv_handles[CH_UNIX][CH_UTF16LE] = smb_iconv_open(charset_name(CH_UTF16LE), "ASCII"); if (!conv_handles[CH_UTF16LE][CH_UNIX]) conv_handles[CH_UTF16LE][CH_UNIX] = smb_iconv_open("ASCII", charset_name(CH_UTF16LE)); for (c1=0;c1<NUM_CHARSETS;c1++) { for (c2=0;c2<NUM_CHARSETS;c2++) { const char *n1 = charset_name((charset_t)c1); const char *n2 = charset_name((charset_t)c2); if (conv_handles[c1][c2] && strcmp(n1, conv_handles[c1][c2]->from_name) == 0 && strcmp(n2, conv_handles[c1][c2]->to_name) == 0) continue; did_reload = True; if (conv_handles[c1][c2]) smb_iconv_close(conv_handles[c1][c2]); conv_handles[c1][c2] = smb_iconv_open(n2,n1); if (conv_handles[c1][c2] == (smb_iconv_t)-1) { DEBUG(0,("init_iconv: Conversion from %s to %s not supported\n", charset_name((charset_t)c1), charset_name((charset_t)c2))); if (c1 != CH_UTF16LE && c1 != CH_UTF16BE) { n1 = "ASCII"; } if (c2 != CH_UTF16LE && c2 != CH_UTF16BE) { n2 = "ASCII"; } DEBUG(0,("init_iconv: Attempting to replace with conversion from %s to %s\n", n1, n2 )); conv_handles[c1][c2] = smb_iconv_open(n2,n1); if (!conv_handles[c1][c2]) { DEBUG(0,("init_iconv: Conversion from %s to %s failed", n1, n2)); smb_panic("init_iconv: conv_handle initialization failed."); } } } } if (did_reload) { /* XXX: Does this really get called every time the dos * codepage changes? */ /* XXX: Is the did_reload test too strict? */ conv_silent = True; init_doschar_table(); init_valid_table(); conv_silent = False; } }
static size_t convert_string_internal(charset_t from, charset_t to, void const *src, size_t srclen, void *dest, size_t destlen, BOOL allow_bad_conv) { size_t i_len, o_len; size_t retval; const char* inbuf = (const char*)src; char* outbuf = (char*)dest; smb_iconv_t descriptor; lazy_initialize_conv(); descriptor = conv_handles[from][to]; if (srclen == (size_t)-1) { if (from == CH_UTF16LE || from == CH_UTF16BE) { srclen = (strlen_w((const smb_ucs2_t *)src)+1) * 2; } else { srclen = strlen((const char *)src)+1; } } if (descriptor == (smb_iconv_t)-1 || descriptor == (smb_iconv_t)0) { if (!conv_silent) DEBUG(0,("convert_string_internal: Conversion not supported.\n")); return (size_t)-1; } i_len=srclen; o_len=destlen; again: retval = smb_iconv(descriptor, &inbuf, &i_len, &outbuf, &o_len); if(retval==(size_t)-1) { const char *reason="unknown error"; switch(errno) { case EINVAL: reason="Incomplete multibyte sequence"; if (!conv_silent) DEBUG(3,("convert_string_internal: Conversion error: %s(%s)\n",reason,inbuf)); if (allow_bad_conv) goto use_as_is; break; case E2BIG: reason="No more room"; if (!conv_silent) { if (from == CH_UNIX) { DEBUG(3,("E2BIG: convert_string(%s,%s): srclen=%u destlen=%u - '%s'\n", charset_name(from), charset_name(to), (unsigned int)srclen, (unsigned int)destlen, (const char *)src)); } else { DEBUG(3,("E2BIG: convert_string(%s,%s): srclen=%u destlen=%u\n", charset_name(from), charset_name(to), (unsigned int)srclen, (unsigned int)destlen)); } } break; case EILSEQ: reason="Illegal multibyte sequence"; if (!conv_silent) DEBUG(3,("convert_string_internal: Conversion error: %s(%s)\n",reason,inbuf)); if (allow_bad_conv) goto use_as_is; break; default: if (!conv_silent) DEBUG(0,("convert_string_internal: Conversion error: %s(%s)\n",reason,inbuf)); break; } /* smb_panic(reason); */ } return destlen-o_len; use_as_is: /* * Conversion not supported. This is actually an error, but there are so * many misconfigured iconv systems and smb.conf's out there we can't just * fail. Do a very bad conversion instead.... JRA. */ { if (o_len == 0 || i_len == 0) return destlen - o_len; if (((from == CH_UTF16LE)||(from == CH_UTF16BE)) && ((to != CH_UTF16LE)||(to != CH_UTF16BE))) { /* Can't convert from utf16 any endian to multibyte. Replace with the default fail char. */ if (i_len < 2) return destlen - o_len; if (i_len >= 2) { *outbuf = lp_failed_convert_char(); outbuf++; o_len--; inbuf += 2; i_len -= 2; } if (o_len == 0 || i_len == 0) return destlen - o_len; /* Keep trying with the next char... */ goto again; } else if (from != CH_UTF16LE && from != CH_UTF16BE && to == CH_UTF16LE) { /* Can't convert to UTF16LE - just widen by adding the default fail char then zero. */ if (o_len < 2) return destlen - o_len; outbuf[0] = lp_failed_convert_char(); outbuf[1] = '\0'; inbuf++; i_len--; outbuf += 2; o_len -= 2; if (o_len == 0 || i_len == 0) return destlen - o_len; /* Keep trying with the next char... */ goto again; } else if (from != CH_UTF16LE && from != CH_UTF16BE && to != CH_UTF16LE && to != CH_UTF16BE) { /* Failed multibyte to multibyte. Just copy the default fail char and try again. */ outbuf[0] = lp_failed_convert_char(); inbuf++; i_len--; outbuf++; o_len--; if (o_len == 0 || i_len == 0) return destlen - o_len; /* Keep trying with the next char... */ goto again; } else { /* Keep compiler happy.... */ return destlen - o_len; } } }
} else { dump_octets(fp, data->s, MAX_TEXT/2); fputs(" ...\n", fp); dump_octets(fp, data->s + data->len - MAX_TEXT/2, MAX_TEXT/2); } #undef MAX_TEXT } static int dump_one_section(int partno, charset_t charset, int encoding, const char *subtype, struct buf *data, void *rock __attribute__((unused))) { #define MAX_TEXT 512 printf("SECTION partno=%d length=%llu subtype=%s charset=%s encoding=%s\n", partno, (unsigned long long)data->len, subtype, charset_name(charset), encoding_name(encoding)); dump_buf(stdout, data); return 0; #undef MAX_TEXT } static int dump_text_sections(message_t *message) { return message_foreach_text_section(message, dump_one_section, NULL); } /*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/ static int dump_message(message_t *message) { return dump_text_sections(message);