diff options
-rw-r--r-- | camel/ChangeLog | 23 | ||||
-rw-r--r-- | camel/camel-charset-map.c | 160 | ||||
-rw-r--r-- | camel/camel-charset-map.h | 5 | ||||
-rw-r--r-- | camel/camel-mime-filter-charset.c | 4 | ||||
-rw-r--r-- | camel/camel-mime-part-utils.c | 4 | ||||
-rw-r--r-- | camel/camel-mime-utils.c | 25 | ||||
-rw-r--r-- | camel/camel-pgp-context.c | 4 | ||||
-rw-r--r-- | camel/camel-sasl-digest-md5.c | 4 |
8 files changed, 207 insertions, 22 deletions
diff --git a/camel/ChangeLog b/camel/ChangeLog index 28e367be14..9f4c6b6653 100644 --- a/camel/ChangeLog +++ b/camel/ChangeLog @@ -1,3 +1,26 @@ +2001-10-02 <NotZed@Ximian.com> + + * camel-sasl-digest-md5.c (digest_response): Change to + camel_charset_iconv_open/close. + + * camel-pgp-context.c (pgp_verify): Change to + camel_charset_iconv_open/close. + + * camel-mime-part-utils.c (convert_buffer): Change to + camel_charset_iconv_open(). + + * camel-mime-filter-charset.c + (camel_mime_filter_charset_new_convert, finalise): Change to + camel_charset_iconv_open, etc. + + * camel-mime-utils.c: Use the camel_charset_iconv_open/close() + functions to open/close it. + + * camel-charset-map.c (camel_charset_iconv_open): New function, + wrap iconv_open, so we can cache ic's. + (camel_charset_iconv_close): Likewise for close. + (camel_charset_map_init,shutdown): Init/free iconv cache. + 2001-10-02 Jeffrey Stedfast <fejj@ximian.com> * camel-charset-map.c (camel_charset_to_iconv): Revert my diff --git a/camel/camel-charset-map.c b/camel/camel-charset-map.c index d25cf2cabc..39904b71e3 100644 --- a/camel/camel-charset-map.c +++ b/camel/camel-charset-map.c @@ -203,10 +203,15 @@ void main(void) #include <string.h> #include <ctype.h> #include <glib.h> +#include <e-util/e-msgport.h> #ifdef ENABLE_THREADS #include <pthread.h> #endif +#ifdef HAVE_ALLOCA_H +#include <alloca.h> +#endif +#define cd(x) /* 'cache debug' */ #ifdef ENABLE_THREADS static pthread_mutex_t iconv_charsets_lock = PTHREAD_MUTEX_INITIALIZER; @@ -217,6 +222,25 @@ static pthread_mutex_t iconv_charsets_lock = PTHREAD_MUTEX_INITIALIZER; #define ICONV_CHARSETS_UNLOCK() #endif /* ENABLE_THREADS */ +struct _iconv_cache_node { + EDListNode ln; + + iconv_t ip; +}; + +struct _iconv_cache { + EDListNode ln; + + char *conv; + + EDList inuse; /* opened ic's in use - if both these lists empty == failed to open conversion */ + EDList free; /* opened ic's free */ +}; + +#define CAMEL_ICONV_CACHE_SIZE (16) + +static EDList iconv_cache_list; + static GHashTable *iconv_charsets = NULL; static char *locale_charset = NULL; @@ -252,11 +276,40 @@ shutdown_foreach (gpointer key, gpointer value, gpointer data) } static void +flush_iconv_entry(struct _iconv_cache *ic) +{ + struct _iconv_cache_node *node; + + cd(printf("Flushing iconv cache entry: %s\n", ic->conv)); + + while ( (node = (struct _iconv_cache_node *)e_dlist_remhead(&ic->inuse)) ) { + iconv_close(node->ip); + g_free(node); + } + while ( (node = (struct _iconv_cache_node *)e_dlist_remhead(&ic->free)) ) { + iconv_close(node->ip); + g_free(node); + } + g_free(ic->conv); + g_free(ic); +} + +static void camel_charset_map_shutdown (void) { + struct _iconv_cache *ic, *in; + g_hash_table_foreach (iconv_charsets, shutdown_foreach, NULL); g_hash_table_destroy (iconv_charsets); g_free (locale_charset); + + ic = (struct _iconv_cache *)iconv_cache_list.head; + in = (struct _iconv_cache *)ic->ln.next; + while (in) { + flush_iconv_entry(ic); + ic = in; + in = (struct _iconv_cache *)in->ln.next; + } } void @@ -273,7 +326,9 @@ camel_charset_map_init (void) g_hash_table_insert (iconv_charsets, g_strdup (known_iconv_charsets[i].charset), g_strdup (known_iconv_charsets[i].iconv_name)); } - + + e_dlist_init(&iconv_cache_list); + locale = setlocale (LC_ALL, NULL); if (!locale || !strcmp (locale, "C") || !strcmp (locale, "POSIX")) { @@ -439,5 +494,108 @@ camel_charset_to_iconv (const char *name) return charset; } +iconv_t camel_charset_iconv_open(const char *oto, const char *ofrom) +{ + const char *to, *from; + char *tofrom; + struct _iconv_cache *ic, *icnew = NULL; + struct _iconv_cache_node *node; + iconv_t ip; + + to = camel_charset_to_iconv(oto); + from = camel_charset_to_iconv(ofrom); + tofrom = alloca(strlen(to) +strlen(from) + 1); + sprintf(tofrom, "%s%s", to, from); + + ICONV_CHARSETS_LOCK(); + ic = (struct _iconv_cache *)iconv_cache_list.head; + while (ic->ln.next) { + if (!strcasecmp(ic->conv, tofrom)) + break; + ic = (struct _iconv_cache *)ic->ln.next; + } + + if (ic->ln.next == NULL) { + int extra = e_dlist_length(&iconv_cache_list) - CAMEL_ICONV_CACHE_SIZE; + struct _iconv_cache *old = (struct _iconv_cache *)iconv_cache_list.head, + *next = (struct _iconv_cache *)old->ln.next; + + /* flush any 'old' entries out, if we can */ + while (extra>0 && next) { + if (e_dlist_empty(&old->inuse)) { + e_dlist_remove(&old->ln); + flush_iconv_entry(old); + extra--; + } + old = next; + next = (struct _iconv_cache *)old->ln.next; + } + + icnew = ic = g_malloc(sizeof(*ic)); + e_dlist_init(&ic->inuse); + e_dlist_init(&ic->free); + ic->conv = g_strdup(tofrom); + } else { + e_dlist_remove(&ic->ln); + } + + node = (struct _iconv_cache_node *)e_dlist_remhead(&ic->free); + if (node) { + cd(printf("Returning cached success of: %s to %s\n", from, to)); + e_dlist_addhead(&ic->inuse, &node->ln); + ip = node->ip; + } else { + if (e_dlist_empty(&ic->inuse) && icnew == NULL) { + cd(printf("returning cached failure of conversion: %s to %s\n", from, to)); + ip = (iconv_t)-1; + } else { + ip = iconv_open(to, from); + if (ip != (iconv_t)-1) { + cd(printf("Creating cached opening of: %s to %s = %p\n", from, to, ip)); + node = g_malloc(sizeof(*node)); + node->ip = ip; + e_dlist_addhead(&ic->inuse, &node->ln); + } + } + } + + e_dlist_addtail(&iconv_cache_list, &ic->ln); + + ICONV_CHARSETS_UNLOCK(); + + return ip; +} + +void camel_charset_iconv_close(iconv_t ip) +{ + struct _iconv_cache *ic; + struct _iconv_cache_node *node; + + if (ip == (iconv_t)-1) + return; + + ICONV_CHARSETS_LOCK(); + ic = (struct _iconv_cache *)iconv_cache_list.tailpred; + while (ic->ln.prev) { + cd(printf("closing iconv %p, checking against name '%s'\n", ip, ic->conv)); + node = (struct _iconv_cache_node *)ic->inuse.head; + while (node->ln.next) { + cd(printf("closing iconv %p, checking against node '%p'\n", ip, node->ip)); + if (node->ip == ip) { + e_dlist_remove(&node->ln); + e_dlist_addhead(&ic->free, &node->ln); + ICONV_CHARSETS_UNLOCK(); + return; + } + node = (struct _iconv_cache_node *)node->ln.next; + } + ic = (struct _iconv_cache *)ic->ln.prev; + } + + ICONV_CHARSETS_UNLOCK(); + + g_warning("Trying to close iconv i dont know about: %p", ip); +} + #endif /* !BUILD_MAP */ diff --git a/camel/camel-charset-map.h b/camel/camel-charset-map.h index 0bf2c706c5..749f02dfc2 100644 --- a/camel/camel-charset-map.h +++ b/camel/camel-charset-map.h @@ -21,6 +21,8 @@ #ifndef _CAMEL_CHARSET_MAP_H #define _CAMEL_CHARSET_MAP_H +#include <iconv.h> + typedef struct _CamelCharset CamelCharset; struct _CamelCharset { @@ -41,4 +43,7 @@ const char *camel_charset_locale_name (void); const char *camel_charset_to_iconv (const char *name); +iconv_t camel_charset_iconv_open(const char *to, const char *from); +void camel_charset_iconv_close(iconv_t ic); + #endif /* ! _CAMEL_CHARSET_MAP_H */ diff --git a/camel/camel-mime-filter-charset.c b/camel/camel-mime-filter-charset.c index 4e59478683..bb9dd06acb 100644 --- a/camel/camel-mime-filter-charset.c +++ b/camel/camel-mime-filter-charset.c @@ -61,7 +61,7 @@ camel_mime_filter_charset_finalize(CamelObject *o) g_free(f->from); g_free(f->to); if (f->ic != (iconv_t)-1) { - iconv_close(f->ic); + camel_charset_iconv_close(f->ic); f->ic = (iconv_t) -1; } } @@ -234,7 +234,7 @@ camel_mime_filter_charset_new_convert (const char *from_charset, const char *to_ from_charset = camel_charset_to_iconv (from_charset); to_charset = camel_charset_to_iconv (to_charset); - new->ic = iconv_open (to_charset, from_charset); + new->ic = camel_charset_iconv_open (to_charset, from_charset); if (new->ic == (iconv_t) -1) { g_warning("Cannot create charset conversion from %s to %s: %s", from_charset, to_charset, strerror(errno)); camel_object_unref ((CamelObject *)new); diff --git a/camel/camel-mime-part-utils.c b/camel/camel-mime-part-utils.c index ba9bf07d5f..8314330f21 100644 --- a/camel/camel-mime-part-utils.c +++ b/camel/camel-mime-part-utils.c @@ -105,7 +105,7 @@ static GByteArray *convert_buffer(GByteArray *in, const char *to, const char *fr d(printf("converting buffer from %s to %s: '%.*s'\n", from, to, (int)in->len, in->data)); - ic = iconv_open(to, from); + ic = camel_charset_iconv_open(to, from); if (ic == (iconv_t) -1) { g_warning("Cannot convert from '%s' to '%s': %s", from, to, strerror(errno)); return NULL; @@ -146,7 +146,7 @@ static GByteArray *convert_buffer(GByteArray *in, const char *to, const char *fr break; } while (1); - iconv_close(ic); + camel_charset_iconv_close(ic); return out; } diff --git a/camel/camel-mime-utils.c b/camel/camel-mime-utils.c index aed930eca5..38b932a280 100644 --- a/camel/camel-mime-utils.c +++ b/camel/camel-mime-utils.c @@ -963,9 +963,8 @@ rfc2047_decode_word(const char *in, int len) outbase = alloca (outlen); outbuf = outbase; - /* TODO: Should this cache iconv converters? */ retry: - ic = iconv_open ("UTF-8", charset); + ic = camel_charset_iconv_open ("UTF-8", charset); if (ic != (iconv_t)-1) { ret = iconv (ic, &inbuf, &inlen, &outbuf, &outlen); if (ret >= 0) { @@ -973,7 +972,7 @@ rfc2047_decode_word(const char *in, int len) *outbuf = 0; decoded = g_strdup (outbase); } - iconv_close (ic); + camel_charset_iconv_close (ic); } else { w(g_warning ("Cannot decode charset, header display may be corrupt: %s: %s", charset, g_strerror (errno))); @@ -1039,7 +1038,7 @@ append_8bit (GString *out, const char *inbuf, int inlen, const char *charset) int outlen; iconv_t ic; - ic = iconv_open ("UTF-8", charset); + ic = camel_charset_iconv_open ("UTF-8", charset); if (ic == (iconv_t) -1) return FALSE; @@ -1049,13 +1048,14 @@ append_8bit (GString *out, const char *inbuf, int inlen, const char *charset) if (iconv(ic, &inbuf, &inlen, &outbuf, &outlen) == -1) { w(g_warning("Conversion to '%s' failed: %s", charset, strerror(errno))); g_free(outbase); + camel_charset_iconv_close(ic); return FALSE; } *outbuf = 0; g_string_append(out, outbase); g_free(outbase); - iconv_close(ic); + camel_charset_iconv_close(ic); return TRUE; @@ -1141,7 +1141,7 @@ rfc2047_encode_word(GString *outstring, const char *in, int len, const char *typ ascii = alloca (bufflen); if (strcasecmp (type, "UTF-8") != 0) - ic = iconv_open (type, "UTF-8"); + ic = camel_charset_iconv_open (type, "UTF-8"); while (inlen) { int convlen, i, proclen; @@ -1218,9 +1218,8 @@ rfc2047_encode_word(GString *outstring, const char *in, int len, const char *typ } } - if (ic != (iconv_t) -1) { - iconv_close(ic); - } + if (ic != (iconv_t) -1) + camel_charset_iconv_close(ic); } @@ -1795,7 +1794,7 @@ rfc2184_decode (const char *in, int len) inbuf = decword = hex_decode (inptr, inend - inptr); inlen = strlen (inbuf); - ic = iconv_open ("UTF-8", charset); + ic = camel_charset_iconv_open("UTF-8", charset); if (ic != (iconv_t) -1) { int ret; @@ -1810,7 +1809,7 @@ rfc2184_decode (const char *in, int len) decoded = outbase; } - iconv_close (ic); + camel_charset_iconv_close(ic); } else { decoded = decword; } @@ -1950,7 +1949,7 @@ header_decode_param (const char **in, char **paramp, char **valuep, int *is_rfc2 inlen = strlen (inbuf); charset = camel_charset_locale_name (); - ic = iconv_open ("UTF-8", charset ? charset : "ISO-8859-1"); + ic = camel_charset_iconv_open ("UTF-8", charset ? charset : "ISO-8859-1"); if (ic != (iconv_t) -1) { int ret; @@ -1963,7 +1962,7 @@ header_decode_param (const char **in, char **paramp, char **valuep, int *is_rfc2 *outbuf = '\0'; } - iconv_close (ic); + camel_charset_iconv_close (ic); g_free (value); value = outbase; diff --git a/camel/camel-pgp-context.c b/camel/camel-pgp-context.c index 9a5fa74e0e..180a1a10e2 100644 --- a/camel/camel-pgp-context.c +++ b/camel/camel-pgp-context.c @@ -1003,7 +1003,7 @@ pgp_verify (CamelCipherContext *ctx, CamelCipherHash hash, CamelStream *istream, if (!locale) locale = "iso-8859-1"; - cd = iconv_open ("UTF-8", locale); + cd = camel_charset_iconv_open ("UTF-8", locale); if (cd != (iconv_t) -1) { const char *inbuf; int ret; @@ -1013,7 +1013,7 @@ pgp_verify (CamelCipherContext *ctx, CamelCipherHash hash, CamelStream *istream, if (ret >= 0) { iconv (cd, NULL, 0, &outbuf, &outlen); } - iconv_close (cd); + camel_charset_iconv_close (cd); *outbuf = '\0'; } else { diff --git a/camel/camel-sasl-digest-md5.c b/camel/camel-sasl-digest-md5.c index 106414fa2c..b2f2427048 100644 --- a/camel/camel-sasl-digest-md5.c +++ b/camel/camel-sasl-digest-md5.c @@ -702,7 +702,7 @@ digest_response (struct _DigestResponse *resp) if (!charset) charset = "iso-8859-1"; - cd = iconv_open (resp->charset, charset); + cd = camel_charset_iconv_open (resp->charset, charset); len = strlen (resp->username); outlen = 2 * len; /* plenty of space */ @@ -720,7 +720,7 @@ digest_response (struct _DigestResponse *resp) } if (cd != (iconv_t) -1) - iconv_close (cd); + camel_charset_iconv_close (cd); g_byte_array_append (buffer, username, strlen (username)); g_free (username); |