aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--camel/ChangeLog23
-rw-r--r--camel/camel-charset-map.c160
-rw-r--r--camel/camel-charset-map.h5
-rw-r--r--camel/camel-mime-filter-charset.c4
-rw-r--r--camel/camel-mime-part-utils.c4
-rw-r--r--camel/camel-mime-utils.c25
-rw-r--r--camel/camel-pgp-context.c4
-rw-r--r--camel/camel-sasl-digest-md5.c4
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);