Index: camel/camel-filter-search.c
===================================================================
--- camel/camel-filter-search.c	(revision 8620)
+++ camel/camel-filter-search.c	(working copy)
@@ -45,12 +45,12 @@
 #include <sys/wait.h>
 #endif
 
-#include <libedataserver/e-iconv.h>
 #include <libedataserver/e-sexp.h>
 
 #include "camel-debug.h"
 #include "camel-exception.h"
 #include "camel-filter-search.h"
+#include "camel-iconv.h"
 #include "camel-mime-message.h"
 #include "camel-multipart.h"
 #include "camel-provider.h"
@@ -180,7 +180,7 @@ check_header (struct _ESExp *f, int argc
 				ct = camel_mime_part_get_content_type (CAMEL_MIME_PART (message));
 				if (ct) {
 					charset = camel_content_type_param (ct, "charset");
-					charset = e_iconv_charset_name (charset);
+					charset = camel_iconv_charset_name (charset);
 				}
 			}
 
Index: camel/providers/imapp/camel-imapp-driver.c
===================================================================
--- camel/providers/imapp/camel-imapp-driver.c	(revision 8620)
+++ camel/providers/imapp/camel-imapp-driver.c	(working copy)
@@ -927,7 +927,7 @@ camel_imapp_driver_worker(CamelIMAPPDriv
 	int go = TRUE;
 
 	do {
-		/*m = (CamelIMAPPMsg *)e_msgport_get(id->queue);*/
+		/*m = (CamelIMAPPMsg *)camel_msgport_try_pop(id->queue);*/
 		switch (m->type) {
 		case CAMEL_IMAPP_MSG_FETCH:
 			/*e_dlist_addtail(&id->fetch_queue, (EDListNode *)m);*/
Index: camel/providers/imapp/camel-imapp-engine.c
===================================================================
--- camel/providers/imapp/camel-imapp-engine.c	(revision 8620)
+++ camel/providers/imapp/camel-imapp-engine.c	(working copy)
@@ -44,7 +44,7 @@ object_init(CamelIMAPPEngine *ie, CamelI
 	e_dlist_init(&ie->active);
 	e_dlist_init(&ie->done);
 
-	ie->port = e_msgport_new();
+	ie->port = camel_msgport_new();
 
 	ie->tagprefix = ieclass->tagprefix;
 	ieclass->tagprefix++;
@@ -688,7 +688,7 @@ camel_imapp_engine_command_queue(CamelIM
 	if (ic->mem)
 		imap_engine_command_complete(imap, ic);
 
-	e_msgport_put(imap->port, (EMsg *)ic);
+	camel_msgport_push(imap->port, (EMsg *)ic);
 }
 
 CamelIMAPPCommand *
Index: camel/camel-mime-utils.c
===================================================================
--- camel/camel-mime-utils.c	(revision 8620)
+++ camel/camel-mime-utils.c	(working copy)
@@ -46,10 +46,10 @@
 
 #include <glib.h>
 
-#include <libedataserver/e-iconv.h>
 #include <libedataserver/e-time-utils.h>
 
 #include "camel-charset-map.h"
+#include "camel-iconv.h"
 #include "camel-mime-utils.h"
 #include "camel-net-utils.h"
 #include "camel-utf8.h"
@@ -915,7 +915,7 @@ decode_8bit (const char *text, size_t le
 	if (default_charset && g_ascii_strcasecmp (default_charset, "UTF-8") != 0)
 		charsets[i++] = default_charset;
 	
-	locale_charset = e_iconv_locale_charset ();
+	locale_charset = camel_iconv_locale_charset ();
 	if (locale_charset && g_ascii_strcasecmp (locale_charset, "UTF-8") != 0)
 		charsets[i++] = locale_charset;
 	
@@ -926,7 +926,7 @@ decode_8bit (const char *text, size_t le
 	out = g_malloc (outlen + 1);
 	
 	for (i = 0; charsets[i]; i++) {
-		if ((cd = e_iconv_open ("UTF-8", charsets[i])) == (iconv_t) -1)
+		if ((cd = camel_iconv_open ("UTF-8", charsets[i])) == (iconv_t) -1)
 			continue;
 		
 		outleft = outlen;
@@ -961,7 +961,7 @@ decode_8bit (const char *text, size_t le
 		rc = iconv (cd, NULL, NULL, &outbuf, &outleft);
 		*outbuf = '\0';
 		
-		e_iconv_close (cd);
+		camel_iconv_close (cd);
 		
 		if (rc != (size_t) -1 && n == 0)
 			return out;
@@ -976,7 +976,7 @@ decode_8bit (const char *text, size_t le
 	 * try to find the one that fit the best and use that to convert what we can,
 	 * replacing any byte we can't convert with a '?' */
 	
-	if ((cd = e_iconv_open ("UTF-8", best)) == (iconv_t) -1) {
+	if ((cd = camel_iconv_open ("UTF-8", best)) == (iconv_t) -1) {
 		/* this shouldn't happen... but if we are here, then
 		 * it did...  the only thing we can do at this point
 		 * is replace the 8bit garbage and pray */
@@ -1028,7 +1028,7 @@ decode_8bit (const char *text, size_t le
 	iconv (cd, NULL, NULL, &outbuf, &outleft);
 	*outbuf = '\0';
 	
-	e_iconv_close (cd);
+	camel_iconv_close (cd);
 	
 	return out;
 }
@@ -1116,9 +1116,9 @@ rfc2047_decode_word (const char *in, siz
 	}
 	
 	if (charset[0])
-		charset = e_iconv_charset_name (charset);
+		charset = camel_iconv_charset_name (charset);
 	
-	if (!charset[0] || (cd = e_iconv_open ("UTF-8", charset)) == (iconv_t) -1) {
+	if (!charset[0] || (cd = camel_iconv_open ("UTF-8", charset)) == (iconv_t) -1) {
 		w(g_warning ("Cannot convert from %s to UTF-8, header display may "
 			     "be corrupt: %s", charset[0] ? charset : "unspecified charset",
 			     g_strerror (errno)));
@@ -1127,7 +1127,7 @@ rfc2047_decode_word (const char *in, siz
 	}
 	
 	buf = camel_iconv_strndup (cd, (char *) decoded, declen);
-	e_iconv_close (cd);
+	camel_iconv_close (cd);
 	
 	if (buf != NULL)
 		return buf;
@@ -1167,26 +1167,26 @@ append_8bit (GString *out, const char *i
 	size_t outlen;
 	iconv_t ic;
 
-	ic = e_iconv_open ("UTF-8", charset);
+	ic = camel_iconv_open ("UTF-8", charset);
 	if (ic == (iconv_t) -1)
 		return FALSE;
 
 	outlen = inlen * 6 + 16;
 	outbuf = outbase = g_malloc(outlen);
 
-	if (e_iconv (ic, &inbuf, &inlen, &outbuf, &outlen) == (size_t) -1) {
+	if (camel_iconv (ic, &inbuf, &inlen, &outbuf, &outlen) == (size_t) -1) {
 		w(g_warning("Conversion to '%s' failed: %s", charset, strerror (errno)));
 		g_free(outbase);
-		e_iconv_close (ic);
+		camel_iconv_close (ic);
 		return FALSE;
 	}
 
-	e_iconv (ic, NULL, NULL, &outbuf, &outlen);
+	camel_iconv (ic, NULL, NULL, &outbuf, &outlen);
 
 	*outbuf = 0;
 	g_string_append(out, outbase);
 	g_free(outbase);
-	e_iconv_close (ic);
+	camel_iconv_close (ic);
 
 	return TRUE;
 
@@ -1391,7 +1391,7 @@ rfc2047_encode_word(GString *outstring, 
 	ascii = g_alloca (bufflen);
 
 	if (g_ascii_strcasecmp (type, "UTF-8") != 0)
-		ic = e_iconv_open (type, "UTF-8");
+		ic = camel_iconv_open (type, "UTF-8");
 
 	while (inlen) {
 		ssize_t convlen, proclen;
@@ -1444,13 +1444,13 @@ rfc2047_encode_word(GString *outstring, 
 			   hopefully-small-enough chunks, and leave it at that */
 			convlen = MIN(inlen, CAMEL_FOLD_PREENCODED);
 			p = inptr;
-			if (e_iconv (ic, &inptr, &convlen, &out, &outlen) == (size_t) -1 && errno != EINVAL) {
+			if (camel_iconv (ic, &inptr, &convlen, &out, &outlen) == (size_t) -1 && errno != EINVAL) {
 				w(g_warning("Conversion problem: conversion truncated: %s", strerror (errno)));
 				/* blah, we include it anyway, better than infinite loop ... */
 				inptr += convlen;
 			} else {
 				/* make sure we flush out any shift state */
-				e_iconv (ic, NULL, 0, &out, &outlen);
+				camel_iconv (ic, NULL, 0, &out, &outlen);
 			}
 			inlen -= (inptr - p);
 		}
@@ -1475,7 +1475,7 @@ rfc2047_encode_word(GString *outstring, 
 	}
 
 	if (ic != (iconv_t) -1)
-		e_iconv_close (ic);
+		camel_iconv_close (ic);
 }
 
 
@@ -2074,20 +2074,20 @@ header_convert(const char *to, const cha
 	size_t outlen, ret;
 	char *outbuf, *outbase, *result = NULL;
 
-	ic = e_iconv_open(to, from);
+	ic = camel_iconv_open(to, from);
 	if (ic == (iconv_t) -1)
 		return NULL;
 
 	outlen = inlen * 6 + 16;
 	outbuf = outbase = g_malloc(outlen);
 
-	ret = e_iconv(ic, &in, &inlen, &outbuf, &outlen);
+	ret = camel_iconv(ic, &in, &inlen, &outbuf, &outlen);
 	if (ret != (size_t) -1) {
-		e_iconv(ic, NULL, 0, &outbuf, &outlen);
+		camel_iconv(ic, NULL, 0, &outbuf, &outlen);
 		*outbuf = '\0';
 		result = g_strdup(outbase);
 	}
-	e_iconv_close(ic);
+	camel_iconv_close(ic);
 	g_free(outbase);
 
 	return result;
@@ -2112,7 +2112,7 @@ rfc2184_decode (const char *in, size_t l
 	encoding = g_alloca(inptr-in+1);
 	memcpy(encoding, in, inptr-in);
 	encoding[inptr-in] = 0;
-	charset = e_iconv_charset_name (encoding);
+	charset = camel_iconv_charset_name (encoding);
 
 	inptr = memchr (inptr + 1, '\'', inend - inptr - 1);
 	if (!inptr)
@@ -2658,7 +2658,7 @@ header_decode_mailbox(const char **in, c
 			const char *locale_charset;
 			GString *out;
 
-			locale_charset = e_iconv_locale_charset ();
+			locale_charset = camel_iconv_locale_charset ();
 
 			out = g_string_new ("");
 
@@ -3163,7 +3163,7 @@ header_append_param(struct _camel_header
 	    && (node->value = header_decode_text(value, FALSE, NULL))) {
 		g_free(value);
 	} else if (g_ascii_strcasecmp (name, "boundary") != 0 && !g_utf8_validate(value, -1, NULL)) {
-		const char *charset = e_iconv_locale_charset();
+		const char *charset = camel_iconv_locale_charset();
 
 		if ((node->value = header_convert("UTF-8", charset?charset:"ISO-8859-1", value, strlen(value)))) {
 			g_free(value);
Index: camel/camel-net-utils.c
===================================================================
--- camel/camel-net-utils.c	(revision 8620)
+++ camel/camel-net-utils.c	(working copy)
@@ -36,9 +36,8 @@
 #include <sys/poll.h>
 #endif
 
-#include <libedataserver/e-msgport.h>
-
 #include "camel-exception.h"
+#include "camel-msgport.h"
 #include "camel-net-utils.h"
 #include "camel-operation.h"
 
@@ -407,7 +406,7 @@ camel_gethostbyaddr_r (const char *addr,
 
 /* ********************************************************************** */
 struct _addrinfo_msg {
-	EMsg msg;
+	CamelMsg msg;
 	unsigned int cancelled:1;
 
 	/* for host lookup */
@@ -449,7 +448,7 @@ cs_freeinfo(struct _addrinfo_msg *msg)
 static int
 cs_waitinfo(void *(worker)(void *), struct _addrinfo_msg *msg, const char *error, CamelException *ex)
 {
-	EMsgPort *reply_port;
+	CamelMsgPort *reply_port;
 	pthread_t id;
 	int err, cancel_fd, cancel = 0, fd;
 
@@ -459,8 +458,8 @@ cs_waitinfo(void *(worker)(void *), stru
 		return 0;
 	}
 
-	reply_port = msg->msg.reply_port = e_msgport_new();
-	fd = e_msgport_fd(msg->msg.reply_port);
+	reply_port = msg->msg.reply_port = camel_msgport_new();
+	fd = camel_msgport_fd(msg->msg.reply_port);
 	if ((err = pthread_create(&id, NULL, worker, msg)) == 0) {
 		int status;
 #ifndef G_OS_WIN32
@@ -514,7 +513,7 @@ cs_waitinfo(void *(worker)(void *), stru
 			pthread_cancel(id);
 			cancel = 1;
 		} else {
-			struct _addrinfo_msg *reply = (struct _addrinfo_msg *)e_msgport_get(reply_port);
+			struct _addrinfo_msg *reply = (struct _addrinfo_msg *)camel_msgport_try_pop(reply_port);
 
 			g_assert(reply == msg);
 			d(printf("waiting for child to exit\n"));
@@ -524,7 +523,7 @@ cs_waitinfo(void *(worker)(void *), stru
 	} else {
 		camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, "%s: %s: %s", error, _("cannot create thread"), g_strerror(err));
 	}
-	e_msgport_destroy(reply_port);
+	camel_msgport_destroy(reply_port);
 
 	return cancel;
 }
@@ -630,7 +629,7 @@ cs_getaddrinfo(void *data)
 		}
 	}
 reply:
-	e_msgport_reply((EMsg *)msg);
+	camel_msgport_reply((CamelMsg *)msg);
 	return NULL;
 cancel:
 	cs_freeinfo(msg);
@@ -647,7 +646,7 @@ cs_getaddrinfo(void *data)
 	if (info->cancelled) {
 		cs_freeinfo(info);
 	} else {
-		e_msgport_reply((EMsg *)info);
+		camel_msgport_reply((CamelMsg *)info);
 	}
 
 	return NULL;
@@ -766,7 +765,7 @@ cs_getnameinfo(void *data)
 	if (msg->serv)
 		sprintf(msg->serv, "%d", sin->sin_port);
 
-	e_msgport_reply((EMsg *)msg);
+	camel_msgport_reply((CamelMsg *)msg);
 	return NULL;
 cancel:
 	cs_freeinfo(msg);
@@ -784,7 +783,7 @@ cs_getnameinfo(void *data)
 	if (msg->cancelled)
 		cs_freeinfo(msg);
 	else
-		e_msgport_reply((EMsg *)msg);
+		camel_msgport_reply((CamelMsg *)msg);
 
 	return NULL;
 }
Index: camel/camel-operation.c
===================================================================
--- camel/camel-operation.c	(revision 8620)
+++ camel/camel-operation.c	(working copy)
@@ -35,9 +35,10 @@
 
 #include <glib.h>
 
-#include <libedataserver/e-msgport.h>
+#include <libedataserver/e-msgport.h>  /* for EDList */
 
 #include "camel-operation.h"
+#include "camel-msgport.h"
 
 #define d(x)
 
@@ -67,7 +68,7 @@ struct _CamelOperation {
 	GSList *status_stack;
 	struct _status_stack *lastreport;
 
-	EMsgPort *cancel_port;
+	CamelMsgPort *cancel_port;
 	int cancel_fd;
 #ifdef HAVE_NSS
 	PRFileDesc *cancel_prfd;
@@ -91,7 +92,7 @@ static pthread_key_t operation_key;
 static pthread_once_t operation_once = PTHREAD_ONCE_INIT;
 
 typedef struct _CamelOperationMsg {
-	EMsg msg;
+	CamelMsg msg;
 } CamelOperationMsg ;
 
 static void
@@ -134,7 +135,7 @@ camel_operation_new (CamelOperationStatu
 	cc->refcount = 1;
 	cc->status = status;
 	cc->status_data = status_data;
-	cc->cancel_port = e_msgport_new();
+	cc->cancel_port = camel_msgport_new();
 	cc->cancel_fd = -1;
 
 	LOCK();
@@ -211,10 +212,10 @@ camel_operation_unref (CamelOperation *c
 
 		e_dlist_remove((EDListNode *)cc);
 
-		while ((msg = (CamelOperationMsg *)e_msgport_get(cc->cancel_port)))
+		while ((msg = (CamelOperationMsg *)camel_msgport_pop(cc->cancel_port)))
 			g_free(msg);
 
-		e_msgport_destroy(cc->cancel_port);
+		camel_msgport_destroy(cc->cancel_port);
 
 		n = cc->status_stack;
 		while (n) {
@@ -294,7 +295,7 @@ camel_operation_cancel (CamelOperation *
 		while (cn) {
 			cc->flags |= CAMEL_OPERATION_CANCELLED;
 			msg = g_malloc0(sizeof(*msg));
-			e_msgport_put(cc->cancel_port, (EMsg *)msg);
+			camel_msgport_push(cc->cancel_port, (CamelMsg *)msg);
 			cc = cn;
 			cn = cn->next;
 		}
@@ -303,7 +304,7 @@ camel_operation_cancel (CamelOperation *
 
 		cc->flags |= CAMEL_OPERATION_CANCELLED;
 		msg = g_malloc0(sizeof(*msg));
-		e_msgport_put(cc->cancel_port, (EMsg *)msg);
+		camel_msgport_push(cc->cancel_port, (CamelMsg *)msg);
 	}
 
 	UNLOCK();
@@ -330,7 +331,7 @@ camel_operation_uncancel(CamelOperation 
 		CamelOperationMsg *msg;
 
 		LOCK();
-		while ((msg = (CamelOperationMsg *)e_msgport_get(cc->cancel_port)))
+		while ((msg = (CamelOperationMsg *)camel_msgport_try_pop(cc->cancel_port)))
 			g_free(msg);
 
 		cc->flags &= ~CAMEL_OPERATION_CANCELLED;
@@ -403,11 +404,11 @@ camel_operation_cancel_check (CamelOpera
 	} else if (cc->flags & CAMEL_OPERATION_CANCELLED) {
 		d(printf("previously cancelled\n"));
 		cancelled = TRUE;
-	} else if ((msg = (CamelOperationMsg *)e_msgport_get(cc->cancel_port))) {
+	} else if ((msg = (CamelOperationMsg *)camel_msgport_try_pop(cc->cancel_port))) {
 		d(printf("Got cancellation message\n"));
 		do {
 			g_free(msg);
-		} while ((msg = (CamelOperationMsg *)e_msgport_get(cc->cancel_port)));
+		} while ((msg = (CamelOperationMsg *)camel_msgport_try_pop(cc->cancel_port)));
 		cc->flags |= CAMEL_OPERATION_CANCELLED;
 		cancelled = TRUE;
 	} else
@@ -440,7 +441,7 @@ camel_operation_cancel_fd (CamelOperatio
 	LOCK();
 
 	if (cc->cancel_fd == -1)
-		cc->cancel_fd = e_msgport_fd(cc->cancel_port);
+		cc->cancel_fd = camel_msgport_fd(cc->cancel_port);
 
 	UNLOCK();
 
@@ -470,7 +471,7 @@ camel_operation_cancel_prfd (CamelOperat
 	LOCK();
 
 	if (cc->cancel_prfd == NULL)
-		cc->cancel_prfd = e_msgport_prfd(cc->cancel_port);
+		cc->cancel_prfd = camel_msgport_prfd(cc->cancel_port);
 
 	UNLOCK();
 
Index: camel/camel-mime-part-utils.c
===================================================================
--- camel/camel-mime-part-utils.c	(revision 8620)
+++ camel/camel-mime-part-utils.c	(working copy)
@@ -32,8 +32,6 @@
 #include <string.h>
 #include <unistd.h>
 
-#include <libedataserver/e-iconv.h>
-
 #include "camel-charset-map.h"
 #include "camel-html-parser.h"
 #include "camel-mime-filter-basic.h"
Index: camel/camel-mime-part.c
===================================================================
--- camel/camel-mime-part.c	(revision 8620)
+++ camel/camel-mime-part.c	(working copy)
@@ -33,10 +33,9 @@
 #include <stdio.h>
 #include <string.h>
 
-#include <libedataserver/e-iconv.h>
-
 #include "camel-charset-map.h"
 #include "camel-exception.h"
+#include "camel-iconv.h"
 #include "camel-mime-filter-basic.h"
 #include "camel-mime-filter-charset.h"
 #include "camel-mime-filter-crlf.h"
@@ -228,7 +227,7 @@ process_header(CamelMedium *medium, cons
 		g_free (mime_part->description);
 		if (((CamelDataWrapper *) mime_part)->mime_type) {
 			charset = camel_content_type_param (((CamelDataWrapper *) mime_part)->mime_type, "charset");
-			charset = e_iconv_charset_name (charset);
+			charset = camel_iconv_charset_name (charset);
 		} else
 			charset = NULL;
 		mime_part->description = g_strstrip (camel_header_decode_string (value, charset));
@@ -832,8 +831,8 @@ write_to_stream (CamelDataWrapper *dw, C
 			part_charset = camel_content_type_param (dw->mime_type, "charset");
 
 			if (content_charset && part_charset) {
-				content_charset = e_iconv_charset_name (content_charset);
-				part_charset = e_iconv_charset_name (part_charset);
+				content_charset = camel_iconv_charset_name (content_charset);
+				part_charset = camel_iconv_charset_name (part_charset);
 			}
 		}
 
Index: camel/Makefile.am
===================================================================
--- camel/Makefile.am	(revision 8620)
+++ camel/Makefile.am	(working copy)
@@ -161,6 +161,7 @@ libcamel_1_2_la_SOURCES = 			\
 	camel-exception.c			\
 	camel-file-utils.c			\
 	camel-html-parser.c			\
+	camel-iconv.c				\
 	camel-index.c				\
 	camel-internet-address.c		\
 	camel-junk-plugin.c			\
@@ -190,6 +191,7 @@ libcamel_1_2_la_SOURCES = 			\
 	camel-mime-part.c			\
 	camel-mime-utils.c			\
 	camel-mime-tables.c			\
+	camel-msgport.c				\
 	camel-multipart-encrypted.c		\
 	camel-multipart-signed.c		\
 	camel-multipart.c			\
@@ -209,6 +211,7 @@ libcamel_1_2_la_SOURCES = 			\
 	camel-stream.c				\
 	camel-string-utils.c			\
 	camel-text-index.c			\
+	camel-trie.c				\
 	camel-url-scanner.c			\
 	camel-url.c				\
 	camel-utf8.c				\
@@ -229,6 +232,7 @@ libcamelinclude_HEADERS =			\
 	camel-exception.h			\
 	camel-file-utils.h			\
 	camel-i18n.h				\
+	camel-iconv.h				\
 	camel-index.h				\
 	camel-internet-address.h		\
 	camel-junk-plugin.h			\
@@ -258,6 +262,7 @@ libcamelinclude_HEADERS =			\
 	camel-mime-part-utils.h			\
 	camel-mime-part.h			\
 	camel-mime-utils.h			\
+	camel-msgport.h				\
 	camel-multipart-encrypted.h		\
 	camel-multipart-signed.h		\
 	camel-multipart.h			\
@@ -279,6 +284,7 @@ libcamelinclude_HEADERS =			\
 	camel-stream.h				\
 	camel-string-utils.h			\
 	camel-text-index.h			\
+	camel-trie.h				\
 	camel-types.h				\
 	camel-url-scanner.h			\
 	camel-url.h				\
Index: camel/camel-session.h
===================================================================
--- camel/camel-session.h	(revision 8620)
+++ camel/camel-session.h	(working copy)
@@ -27,12 +27,11 @@
 #ifndef CAMEL_SESSION_H
 #define CAMEL_SESSION_H 1
 
+#include <camel/camel-msgport.h>
 #include <camel/camel-object.h>
 #include <camel/camel-provider.h>
 #include <camel/camel-junk-plugin.h>
 
-#include <libedataserver/e-msgport.h>
-
 #define CAMEL_SESSION_TYPE     (camel_session_get_type ())
 #define CAMEL_SESSION(obj)     (CAMEL_CHECK_CAST((obj), CAMEL_SESSION_TYPE, CamelSession))
 #define CAMEL_SESSION_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), CAMEL_SESSION_TYPE, CamelSessionClass))
@@ -179,7 +178,7 @@ struct _CamelSessionThreadOps {
 };
 
 struct _CamelSessionThreadMsg {
-	EMsg msg;
+	CamelMsg msg;
 
 	int id;
 
Index: camel/camel-msgport.c
===================================================================
--- camel/camel-msgport.c	(revision 0)
+++ camel/camel-msgport.c	(revision 0)
@@ -0,0 +1,424 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright 2007 Novell, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <unistd.h>
+
+#ifdef HAVE_NSS
+#include <nspr.h>
+#endif
+
+#ifdef G_OS_WIN32
+#include <winsock2.h>
+#endif
+
+#include "camel-msgport.h"
+
+#ifdef G_OS_WIN32
+#define MP_CLOSE(socket)		closesocket (socket)
+#define MP_READ(socket, buf, nbytes)	recv((socket), (buf), (nbytes), 0)
+#define MP_WRITE(socket, buf, nbytes)	send((socket), (buf), (nbytes), 0)
+#define MP_IS_STATUS_INTR()		0 /* No WSAEINTR errors in WinSock2 */
+#else
+#define MP_CLOSE(socket)		close (socket)
+#define MP_READ(socket, buf, nbytes)	read((socket), (buf), (nbytes))
+#define MP_WRITE(socket, buf, nbytes)	write((socket), (buf), (nbytes))
+#define MP_IS_STATUS_INTR()		(errno == EINTR)
+#endif
+
+/* message flags */
+enum {
+	MSG_FLAG_SYNC_WITH_PIPE    = 1 << 0,
+	MSG_FLAG_SYNC_WITH_PR_PIPE = 1 << 1
+};
+
+struct _CamelMsgPort {
+	GAsyncQueue *queue;
+	gint pipe[2];  /* on Win32, actually a pair of SOCKETs */
+#ifdef HAVE_NSS
+	PRFileDesc *prpipe[2];
+#endif
+};
+
+static int
+msgport_pipe (int *fds)
+{
+#ifndef G_OS_WIN32
+	if (pipe (fds) != -1)
+		return 0;
+	
+	fds[0] = -1;
+	fds[1] = -1;
+	
+	return -1;
+#else
+	SOCKET temp, socket1 = -1, socket2 = -1;
+	struct sockaddr_in saddr;
+	int len;
+	u_long arg;
+	fd_set read_set, write_set;
+	struct timeval tv;
+
+	temp = socket (AF_INET, SOCK_STREAM, 0);
+	
+	if (temp == INVALID_SOCKET) {
+		goto out0;
+	}
+  	
+	arg = 1;
+	if (ioctlsocket (temp, FIONBIO, &arg) == SOCKET_ERROR) {
+		goto out0;
+	}
+
+	memset (&saddr, 0, sizeof (saddr));
+	saddr.sin_family = AF_INET;
+	saddr.sin_port = 0;
+	saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
+
+	if (bind (temp, (struct sockaddr *)&saddr, sizeof (saddr))) {
+		goto out0;
+	}
+
+	if (listen (temp, 1) == SOCKET_ERROR) {
+		goto out0;
+	}
+
+	len = sizeof (saddr);
+	if (getsockname (temp, (struct sockaddr *)&saddr, &len)) {
+		goto out0;
+	}
+
+	socket1 = socket (AF_INET, SOCK_STREAM, 0);
+	
+	if (socket1 == INVALID_SOCKET) {
+		goto out0;
+	}
+
+	arg = 1;
+	if (ioctlsocket (socket1, FIONBIO, &arg) == SOCKET_ERROR) { 
+		goto out1;
+	}
+
+	if (connect (socket1, (struct sockaddr  *)&saddr, len) != SOCKET_ERROR ||
+	    WSAGetLastError () != WSAEWOULDBLOCK) {
+		goto out1;
+	}
+
+	FD_ZERO (&read_set);
+	FD_SET (temp, &read_set);
+
+	tv.tv_sec = 0;
+	tv.tv_usec = 0;
+
+	if (select (0, &read_set, NULL, NULL, NULL) == SOCKET_ERROR) {
+		goto out1;
+	}
+
+	if (!FD_ISSET (temp, &read_set)) {
+		goto out1;
+	}
+
+	socket2 = accept (temp, (struct sockaddr *) &saddr, &len);
+	if (socket2 == INVALID_SOCKET) {
+		goto out1;
+	}
+
+	FD_ZERO (&write_set);
+	FD_SET (socket1, &write_set);
+
+	tv.tv_sec = 0;
+	tv.tv_usec = 0;
+
+	if (select (0, NULL, &write_set, NULL, NULL) == SOCKET_ERROR) {
+		goto out2;
+	}
+
+	if (!FD_ISSET (socket1, &write_set)) {
+		goto out2;
+	}
+
+	arg = 0;
+	if (ioctlsocket (socket1, FIONBIO, &arg) == SOCKET_ERROR) {
+		goto out2;
+	}
+
+	arg = 0;
+	if (ioctlsocket (socket2, FIONBIO, &arg) == SOCKET_ERROR) {
+		goto out2;
+	}
+
+	fds[0] = socket1;
+	fds[1] = socket2;
+
+	closesocket (temp);
+
+	return 0;
+
+out2:
+	closesocket (socket2);
+out1:
+	closesocket (socket1);
+out0:
+	closesocket (temp);
+	errno = EMFILE;		/* FIXME: use the real syscall errno? */
+	
+	fds[0] = -1;
+	fds[1] = -1;
+	
+	return -1;
+
+#endif
+}
+
+#ifdef HAVE_NSS
+static int
+msgport_prpipe (PRFileDesc **fds)
+{
+#ifdef G_OS_WIN32
+	if (PR_NewTCPSocketPair (fds) != PR_FAILURE)
+		return 0;
+#else
+	if (PR_CreatePipe (&fds[0], &fds[1]) != PR_FAILURE)
+		return 0;
+#endif
+	
+	fds[0] = NULL;
+	fds[1] = NULL;
+	
+	return -1;
+}
+#endif
+
+static void
+msgport_sync_with_pipe (gint fd)
+{
+	gchar buffer[1];
+
+	while (fd >= 0) {
+		if (MP_READ (fd, buffer, 1) > 0)
+			break;
+		else if (!MP_IS_STATUS_INTR ()) {
+			g_warning ("%s: Failed to read from pipe: %s",
+				G_STRFUNC, g_strerror (errno));
+			break;
+		}
+	}
+}
+
+#ifdef HAVE_NSS
+static void
+msgport_sync_with_prpipe (PRFileDesc *prfd)
+{
+	gchar buffer[1];
+
+	while (prfd != NULL) {
+		if (PR_Read (prfd, buffer, 1) > 0)
+			break;
+		else if (PR_GetError () != PR_PENDING_INTERRUPT_ERROR) {
+			gchar *text = g_alloca (PR_GetErrorTextLength ());
+			PR_GetErrorText (text);
+			g_warning ("%s: Failed to read from NSPR pipe: %s",
+				G_STRFUNC, text);
+			break;
+		}
+	}
+}
+#endif
+
+CamelMsgPort *
+camel_msgport_new (void)
+{
+	CamelMsgPort *msgport;
+
+	msgport = g_slice_new (CamelMsgPort);
+	msgport->queue = g_async_queue_new ();
+	msgport->pipe[0] = -1;
+	msgport->pipe[1] = -1;
+#ifdef HAVE_NSS
+	msgport->prpipe[0] = NULL;
+	msgport->prpipe[1] = NULL;
+#endif
+
+	return msgport;
+}
+
+void
+camel_msgport_destroy (CamelMsgPort *msgport)
+{
+	g_return_if_fail (msgport != NULL);
+
+	if (msgport->pipe[0] >= 0) {
+		MP_CLOSE (msgport->pipe[0]);
+		MP_CLOSE (msgport->pipe[1]);
+	}
+#ifdef HAVE_NSS
+	if (msgport->prpipe[0] != NULL) {
+		PR_Close (msgport->prpipe[0]);
+		PR_Close (msgport->prpipe[1]);
+	}
+#endif
+
+	g_async_queue_unref (msgport->queue);
+	g_slice_free (CamelMsgPort, msgport);
+}
+
+gint
+camel_msgport_fd (CamelMsgPort *msgport)
+{
+	gint fd;
+
+	g_return_val_if_fail (msgport != NULL, -1);
+
+	g_async_queue_lock (msgport->queue);
+	fd = msgport->pipe[0];
+	if (fd < 0 && msgport_pipe (msgport->pipe) == 0)
+		fd = msgport->pipe[0];
+	g_async_queue_unlock (msgport->queue);
+
+	return fd;
+}
+
+#ifdef HAVE_NSS
+PRFileDesc *
+camel_msgport_prfd (CamelMsgPort *msgport)
+{
+	PRFileDesc *prfd;
+
+	g_return_val_if_fail (msgport != NULL, NULL);
+
+	g_async_queue_lock (msgport->queue);
+	prfd = msgport->prpipe[0];
+	if (prfd == NULL && msgport_prpipe (msgport->prpipe) == 0)
+		prfd = msgport->prpipe[0];
+	g_async_queue_unlock (msgport->queue);
+
+	return prfd;
+}
+#endif
+
+void
+camel_msgport_push (CamelMsgPort *msgport, CamelMsg *msg)
+{
+	gint fd;
+#ifdef HAVE_NSS
+	PRFileDesc *prfd;
+#endif
+
+	g_return_if_fail (msgport != NULL);
+	g_return_if_fail (msg != NULL);
+
+	g_async_queue_lock (msgport->queue);
+
+	msg->flags = 0;
+
+	fd = msgport->pipe[1];
+	while (fd >= 0) {
+		if (MP_WRITE (fd, "E", 1) > 0) {
+			msg->flags |= MSG_FLAG_SYNC_WITH_PIPE;
+			break;
+		} else if (!MP_IS_STATUS_INTR ()) {
+			g_warning ("%s: Failed to write to pipe: %s",
+				G_STRFUNC, g_strerror (errno));
+			break;
+		}
+	}
+
+#ifdef HAVE_NSS
+	prfd = msgport->prpipe[1];
+	while (prfd != NULL) {
+		if (PR_Write (prfd, "E", 1) > 0) {
+			msg->flags |= MSG_FLAG_SYNC_WITH_PR_PIPE;
+			break;
+		} else if (PR_GetError () != PR_PENDING_INTERRUPT_ERROR) {
+			gchar *text = g_alloca (PR_GetErrorTextLength ());
+			PR_GetErrorText (text);
+			g_warning ("%s: Failed to write to NSPR pipe: %s",
+				G_STRFUNC, text);
+			break;
+		}
+	}
+#endif
+
+	g_async_queue_push_unlocked (msgport->queue, msg);
+	g_async_queue_unlock (msgport->queue);
+}
+
+CamelMsg *
+camel_msgport_pop (CamelMsgPort *msgport)
+{
+	CamelMsg *msg;
+
+	g_return_val_if_fail (msgport != NULL, NULL);
+
+	g_async_queue_lock (msgport->queue);
+
+	msg = g_async_queue_pop_unlocked (msgport->queue);
+
+	g_assert (msg != NULL);
+
+	if (msg->flags & MSG_FLAG_SYNC_WITH_PIPE)
+		msgport_sync_with_pipe (msgport->pipe[0]);
+#ifdef HAVE_NSS
+	if (msg->flags & MSG_FLAG_SYNC_WITH_PR_PIPE)
+		msgport_sync_with_prpipe (msgport->prpipe[0]);
+#endif
+
+	g_async_queue_unlock (msgport->queue);
+
+	return msg;
+}
+
+CamelMsg *
+camel_msgport_try_pop (CamelMsgPort *msgport)
+{
+	CamelMsg *msg;
+
+	g_return_val_if_fail (msgport != NULL, NULL);
+
+	g_async_queue_lock (msgport->queue);
+
+	msg = g_async_queue_try_pop_unlocked (msgport->queue);
+
+	if (msg != NULL && msg->flags & MSG_FLAG_SYNC_WITH_PIPE)
+		msgport_sync_with_pipe (msgport->pipe[0]);
+#ifdef HAVE_NSS
+	if (msg != NULL && msg->flags & MSG_FLAG_SYNC_WITH_PR_PIPE)
+		msgport_sync_with_prpipe (msgport->prpipe[0]);
+#endif
+
+	g_async_queue_unlock (msgport->queue);
+
+	return msg;
+}
+
+void
+camel_msgport_reply (CamelMsg *msg)
+{
+	g_return_if_fail (msg != NULL);
+
+	if (msg->reply_port)
+		camel_msgport_push (msg->reply_port, msg);
+
+	/* else lost? */
+}
Index: camel/camel-msgport.h
===================================================================
--- camel/camel-msgport.h	(revision 0)
+++ camel/camel-msgport.h	(revision 0)
@@ -0,0 +1,51 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ *  Copyright 2007 Novell, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU Lesser General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef CAMEL_MSGPORT_H
+#define CAMEL_MSGPORT_H
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef struct _CamelMsg CamelMsg;
+typedef struct _CamelMsgPort CamelMsgPort;
+
+struct _CamelMsg {
+	CamelMsgPort *reply_port;
+	gint flags;
+};
+
+CamelMsgPort *	camel_msgport_new		(void);
+void		camel_msgport_destroy		(CamelMsgPort *msgport);
+gint		camel_msgport_fd		(CamelMsgPort *msgport);
+void		camel_msgport_push		(CamelMsgPort *msgport,
+						 CamelMsg *msg);
+CamelMsg *	camel_msgport_pop		(CamelMsgPort *msgport);
+CamelMsg *	camel_msgport_try_pop		(CamelMsgPort *msgport);
+void		camel_msgport_reply		(CamelMsg *msg);
+
+#ifdef HAVE_NSS
+struct PRFileDesc * camel_msgport_prfd		(CamelMsgPort *msgport);
+#endif
+
+G_END_DECLS
+
+#endif  /* CAMEL_MSGPORT_H */
Index: camel/camel-trie.c
===================================================================
--- camel/camel-trie.c	(revision 0)
+++ camel/camel-trie.c	(revision 0)
@@ -0,0 +1,382 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ *  Copyright 2007 Novell, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU Lesser General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#include <libedataserver/e-memory.h>
+
+#include "camel-trie.h"
+
+#define d(x)
+
+struct _trie_state {
+	struct _trie_state *next;
+	struct _trie_state *fail;
+	struct _trie_match *match;
+	unsigned int final;
+	int id;
+};
+
+struct _trie_match {
+	struct _trie_match *next;
+	struct _trie_state *state;
+	gunichar c;
+};
+
+/**
+ * CamelTrie:
+ *
+ * A trie data structure.
+ **/
+struct _CamelTrie {
+	struct _trie_state root;
+	GPtrArray *fail_states;
+	gboolean icase;
+	
+	EMemChunk *match_chunks;
+	EMemChunk *state_chunks;
+};
+
+
+static inline gunichar
+trie_utf8_getc (const unsigned char **in, size_t inlen)
+{
+	register const unsigned char *inptr = *in;
+	const unsigned char *inend = inptr + inlen;
+	register unsigned char c, r;
+	register gunichar u, m;
+	
+	if (inlen == 0)
+		return 0;
+	
+	r = *inptr++;
+	if (r < 0x80) {
+		*in = inptr;
+		u = r;
+	} else if (r < 0xfe) { /* valid start char? */
+		u = r;
+		m = 0x7f80;	/* used to mask out the length bits */
+		do {
+			if (inptr >= inend)
+				return 0;
+			
+			c = *inptr++;
+			if ((c & 0xc0) != 0x80)
+				goto error;
+			
+			u = (u << 6) | (c & 0x3f);
+			r <<= 1;
+			m <<= 5;
+		} while (r & 0x40);
+		
+		*in = inptr;
+		
+		u &= ~m;
+	} else {
+	error:
+		*in = (*in)+1;
+		u = 0xfffe;
+	}
+	
+	return u;
+}
+
+/**
+ * camel_trie_new:
+ * @icase: Case sensitivity for the #CamelTrie.
+ *
+ * Creates a new #CamelTrie. If @icase is %TRUE, then pattern matching
+ * done by the CamelTrie will be case insensitive.
+ *
+ * Returns: The newly-created #CamelTrie.
+ **/
+CamelTrie *
+camel_trie_new (gboolean icase)
+{
+	CamelTrie *trie;
+	
+	trie = g_new (CamelTrie, 1);
+	trie->root.next = NULL;
+	trie->root.fail = NULL;
+	trie->root.match = NULL;
+	trie->root.final = 0;
+	
+	trie->fail_states = g_ptr_array_sized_new (8);
+	trie->icase = icase;
+	
+	trie->match_chunks = e_memchunk_new (8, sizeof (struct _trie_match));
+	trie->state_chunks = e_memchunk_new (8, sizeof (struct _trie_state));
+	
+	return trie;
+}
+
+/**
+ * camel_trie_free:
+ * @trie: The #CamelTrie to free.
+ *
+ * Frees the memory associated with the #CamelTrie @trie.
+ **/
+void
+camel_trie_free (CamelTrie *trie)
+{
+	g_ptr_array_free (trie->fail_states, TRUE);
+	e_memchunk_destroy (trie->match_chunks);
+	e_memchunk_destroy (trie->state_chunks);
+	g_free (trie);
+}
+
+
+
+static struct _trie_match *
+g (struct _trie_state *s, gunichar c)
+{
+	struct _trie_match *m = s->match;
+	
+	while (m && m->c != c)
+		m = m->next;
+	
+	return m;
+}
+
+static struct _trie_state *
+trie_insert (CamelTrie *trie, int depth, struct _trie_state *q, gunichar c)
+{
+	struct _trie_match *m;
+	
+	m = e_memchunk_alloc (trie->match_chunks);
+	m->next = q->match;
+	m->c = c;
+	
+	q->match = m;
+	q = m->state = e_memchunk_alloc (trie->state_chunks);
+	q->match = NULL;
+	q->fail = &trie->root;
+	q->final = 0;
+	q->id = -1;
+	
+	if (trie->fail_states->len < depth + 1) {
+		unsigned int size = trie->fail_states->len;
+		
+		size = MAX (size + 64, depth + 1);
+		g_ptr_array_set_size (trie->fail_states, size);
+	}
+	
+	q->next = trie->fail_states->pdata[depth];
+	trie->fail_states->pdata[depth] = q;
+	
+	return q;
+}
+
+
+#if 1
+static void 
+dump_trie (struct _trie_state *s, int depth)
+{
+	char *p = g_alloca ((depth * 2) + 1);
+	struct _trie_match *m;
+	
+	memset (p, ' ', depth * 2);
+	p[depth * 2] = '\0';
+	
+	fprintf (stderr, "%s[state] %p: final=%d; pattern-id=%d; fail=%p\n",
+		 p, s, s->final, s->id, s->fail);
+	m = s->match;
+	while (m) {
+		fprintf (stderr, " %s'%c' -> %p\n", p, m->c, m->state);
+		if (m->state)
+			dump_trie (m->state, depth + 1);
+		
+		m = m->next;
+	}
+}
+#endif
+
+
+/*
+ * final = empty set
+ * FOR p = 1 TO #pat
+ *   q = root
+ *   FOR j = 1 TO m[p]
+ *     IF g(q, pat[p][j]) == null
+ *       insert(q, pat[p][j])
+ *     ENDIF
+ *     q = g(q, pat[p][j])
+ *   ENDFOR
+ *   final = union(final, q)
+ * ENDFOR
+*/
+
+/**
+ * camel_trie_add:
+ * @trie: The #CamelTrie to add a pattern to.
+ * @pattern: The pattern to add.
+ * @pattern_id: The id to use for the pattern.
+ *
+ * Add a new pattern to the #CamelTrie @trie.
+ **/
+void
+camel_trie_add (CamelTrie *trie, const gchar *pattern, gint pattern_id)
+{
+	const unsigned char *inptr = (const unsigned char *) pattern;
+	struct _trie_state *q, *q1, *r;
+	struct _trie_match *m, *n;
+	int i, depth = 0;
+	gunichar c;
+	
+	/* Step 1: add the pattern to the trie */
+	
+	q = &trie->root;
+	
+	while ((c = trie_utf8_getc (&inptr, -1))) {
+		if (trie->icase)
+			c = g_unichar_tolower (c);
+		
+		m = g (q, c);
+		if (m == NULL) {
+			q = trie_insert (trie, depth, q, c);
+		} else {
+			q = m->state;
+		}
+		
+		depth++;
+	}
+	
+	q->final = depth;
+	q->id = pattern_id;
+	
+	/* Step 2: compute failure graph */
+	
+	for (i = 0; i < trie->fail_states->len; i++) {
+		q = trie->fail_states->pdata[i];
+		while (q) {
+			m = q->match;
+			while (m) {
+				c = m->c;
+				q1 = m->state;
+				r = q->fail;
+				while (r && (n = g (r, c)) == NULL)
+					r = r->fail;
+				
+				if (r != NULL) {
+					q1->fail = n->state;
+					if (q1->fail->final > q1->final)
+						q1->final = q1->fail->final;
+				} else {
+					if ((n = g (&trie->root, c)))
+						q1->fail = n->state;
+					else
+						q1->fail = &trie->root;
+				}
+				
+				m = m->next;
+			}
+			
+			q = q->next;
+		}
+	}
+	
+	d(fprintf (stderr, "\nafter adding pattern '%s' to trie %p:\n", pattern, trie));
+	d(dump_trie (&trie->root, 0));
+}
+
+/*
+ * Aho-Corasick
+ *
+ * q = root
+ * FOR i = 1 TO n
+ *   WHILE q != fail AND g(q, text[i]) == fail
+ *     q = h(q)
+ *   ENDWHILE
+ *   IF q == fail
+ *     q = root
+ *   ELSE
+ *     q = g(q, text[i])
+ *   ENDIF
+ *   IF isElement(q, final)
+ *     RETURN TRUE
+ *   ENDIF
+ * ENDFOR
+ * RETURN FALSE
+ */
+
+/**
+ * camel_trie_search:
+ * @trie: The #CamelTrie to search in.
+ * @buffer: The string to match against a pattern in @trie.
+ * @buflen: The length of @buffer.
+ * @matched_id: An integer address to store the matched pattern id in.
+ *
+ * Try to match the string @buffer with a pattern in @trie.
+ *
+ * Returns: The matched pattern, or %NULL if no pattern is matched.
+ **/
+const gchar *
+camel_trie_search (CamelTrie *trie, const gchar *buffer, gsize buflen,
+                   gint *matched_id)
+{
+	const unsigned char *inptr, *inend, *prev, *pat;
+	register size_t inlen = buflen;
+	struct _trie_state *q;
+	struct _trie_match *m = NULL; /* init to please gcc */
+	gunichar c;
+	
+	inptr = (const unsigned char *) buffer;
+	inend = inptr + buflen;
+	
+	q = &trie->root;
+	pat = prev = inptr;
+	while ((c = trie_utf8_getc (&inptr, inlen))) {
+		inlen = (inend - inptr);
+		
+		if (c != 0xfffe) {
+			if (trie->icase)
+				c = g_unichar_tolower (c);
+			
+			while (q != NULL && (m = g (q, c)) == NULL)
+				q = q->fail;
+			
+			if (q == &trie->root)
+				pat = prev;
+			
+			if (q == NULL) {
+				q = &trie->root;
+				pat = inptr;
+			} else if (m != NULL) {
+				q = m->state;
+				
+				if (q->final) {
+					if (matched_id)
+						*matched_id = q->id;
+					
+					return (const char *) pat;
+				}
+			}
+		}
+		
+		prev = inptr;
+	}
+	
+	return NULL;
+}
Index: camel/camel-charset-map.c
===================================================================
--- camel/camel-charset-map.c	(revision 8620)
+++ camel/camel-charset-map.c	(working copy)
@@ -39,6 +39,8 @@
 #include <iconv.h>
 #include <errno.h>
 
+#include "camel-iconv.h"
+
 /*
   if you want to build the charset map, compile this with something like:
     gcc -DBUILD_MAP camel-charset-map.c `pkg-config --cflags --libs glib-2.0`
@@ -305,8 +307,6 @@ int main (int argc, char **argv)
 #include "camel-charset-map-private.h"
 #include "camel-utf8.h"
 
-#include <libedataserver/e-iconv.h>
-
 void
 camel_charset_init (CamelCharset *c)
 {
@@ -353,10 +353,10 @@ camel_charset_best_mask(unsigned int mas
 	const char *locale_lang, *lang;
 	int i;
 
-	locale_lang = e_iconv_locale_language ();
+	locale_lang = camel_iconv_locale_language ();
 	for (i = 0; i < G_N_ELEMENTS (camel_charinfo); i++) {
 		if (camel_charinfo[i].bit & mask) {
-			lang = e_iconv_charset_language (camel_charinfo[i].name);
+			lang = camel_iconv_charset_language (camel_charinfo[i].name);
 
 			if (!locale_lang || (lang && !strncmp (locale_lang, lang, 2)))
 				return camel_charinfo[i].name;
Index: camel/camel.h
===================================================================
--- camel/camel.h	(revision 8620)
+++ camel/camel.h	(working copy)
@@ -82,6 +82,7 @@
 #include <camel/camel-mime-part-utils.h>
 #include <camel/camel-mime-utils.h>
 #include <camel/camel-movemail.h>
+#include <camel/camel-msgport.h>
 #include <camel/camel-multipart.h>
 #include <camel/camel-multipart-encrypted.h>
 #include <camel/camel-multipart-signed.h>
@@ -127,6 +128,7 @@
 #include <camel/camel-tcp-stream-ssl.h>
 #include <camel/camel-text-index.h>
 #include <camel/camel-transport.h>
+#include <camel/camel-trie.h>
 #include <camel/camel-types.h>
 #include <camel/camel-uid-cache.h>
 #include <camel/camel-url.h>
Index: camel/camel-trie.h
===================================================================
--- camel/camel-trie.h	(revision 0)
+++ camel/camel-trie.h	(revision 0)
@@ -0,0 +1,42 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ *  Copyright 2007 Novell, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU Lesser General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef CAMEL_TRIE_H
+#define CAMEL_TRIE_H
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef struct _CamelTrie CamelTrie;
+
+CamelTrie *	camel_trie_new			(gboolean icase);
+void		camel_trie_free			(CamelTrie *trie);
+void		camel_trie_add			(CamelTrie *trie,
+						 const gchar *pattern,
+						 gint pattern_id);
+const gchar *	camel_trie_search		(CamelTrie *trie,
+						 const gchar *buffer,
+						 gsize buflen,
+						 gint *matched_id);
+
+G_END_DECLS
+
+#endif /* CAMEL_TRIE_H */
Index: camel/camel-iconv.c
===================================================================
--- camel/camel-iconv.c	(revision 0)
+++ camel/camel-iconv.c	(revision 0)
@@ -0,0 +1,630 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* 
+ * camel-iconv.c
+ * Copyright 2000, 2001, Ximian, Inc.
+ *
+ * Authors:
+ *   Michael Zucchi <notzed@ximian.com>
+ *   Jeffery Stedfast <fejj@ximian.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License, version 2, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <glib.h>
+
+#include <locale.h>
+
+#ifdef HAVE_CODESET
+#include <langinfo.h>
+#endif
+
+#include "camel-iconv.h"
+#include "iconv-detect.h"
+
+#define cd(x) 
+
+#ifdef G_THREADS_ENABLED
+static GStaticMutex lock = G_STATIC_MUTEX_INIT;
+#define LOCK() g_static_mutex_lock(&lock)
+#define UNLOCK() g_static_mutex_unlock(&lock)
+#else
+#define LOCK()
+#define UNLOCK()
+#endif
+
+typedef struct _EDListNode {
+	struct _EDListNode *next;
+	struct _EDListNode *prev;
+} EDListNode;
+
+typedef struct _EDList {
+	struct _EDListNode *head;
+	struct _EDListNode *tail;
+	struct _EDListNode *tailpred;
+} EDList;
+
+#define E_DLIST_INITIALISER(l) { (EDListNode *)&l.tail, 0, (EDListNode *)&l.head }
+
+struct _iconv_cache_node {
+	struct _iconv_cache_node *next;
+	struct _iconv_cache_node *prev;
+
+	struct _iconv_cache *parent;
+
+	int busy;
+	iconv_t ip;
+};
+
+struct _iconv_cache {
+	struct _iconv_cache *next;
+	struct _iconv_cache *prev;
+
+	char *conv;
+
+	EDList open;		/* stores iconv_cache_nodes, busy ones up front */
+};
+
+#define E_ICONV_CACHE_SIZE (16)
+
+static EDList iconv_cache_list;
+static GHashTable *iconv_cache;
+static GHashTable *iconv_cache_open;
+static unsigned int iconv_cache_size = 0;
+
+static GHashTable *iconv_charsets = NULL;
+static char *locale_charset = NULL;
+static char *locale_lang = NULL;
+
+struct {
+	char *charset;
+	char *iconv_name;
+} known_iconv_charsets[] = {
+#if 0
+	/* charset name, iconv-friendly charset name */
+	{ "iso-8859-1",     "iso-8859-1" },
+	{ "iso8859-1",      "iso-8859-1" },
+	/* the above mostly serves as an example for iso-style charsets,
+	   but we have code that will populate the iso-*'s if/when they
+	   show up in camel_iconv_charset_name() so I'm
+	   not going to bother putting them all in here... */
+	{ "windows-cp1251", "cp1251"     },
+	{ "windows-1251",   "cp1251"     },
+	{ "cp1251",         "cp1251"     },
+	/* the above mostly serves as an example for windows-style
+	   charsets, but we have code that will parse and convert them
+	   to their cp#### equivalents if/when they show up in
+	   camel_iconv_charset_name() so I'm not going to bother
+	   putting them all in here either... */
+#endif
+	/* charset name (lowercase!), iconv-friendly name (sometimes case sensitive) */
+	{ "utf-8",          "UTF-8"      },
+
+	/* 10646 is a special case, its usually UCS-2 big endian */
+	/* This might need some checking but should be ok for solaris/linux */
+	{ "iso-10646-1",    "UCS-2BE"    },
+	{ "iso_10646-1",    "UCS-2BE"    },
+	{ "iso10646-1",     "UCS-2BE"    },
+	{ "iso-10646",      "UCS-2BE"    },
+	{ "iso_10646",      "UCS-2BE"    },
+	{ "iso10646",       "UCS-2BE"    },
+
+	{ "ks_c_5601-1987", "EUC-KR"     },
+
+	/* FIXME: Japanese/Korean/Chinese stuff needs checking */
+	{ "euckr-0",        "EUC-KR"     },
+	{ "5601",           "EUC-KR"     },
+	{ "zh_TW-euc",      "EUC-TW"     },
+	{ "zh_CN.euc",      "gb2312"     },
+	{ "zh_TW-big5",     "BIG5"       },
+	{ "euc-cn",         "gb2312"     },
+	{ "big5-0",         "BIG5"       },
+	{ "big5.eten-0",    "BIG5"       },
+	{ "big5hkscs-0",    "BIG5HKSCS"  },
+	{ "gb2312-0",       "gb2312"     },
+	{ "gb2312.1980-0",  "gb2312"     },
+	{ "gb-2312",        "gb2312"     },
+	{ "gb18030-0",      "gb18030"    },
+	{ "gbk-0",          "GBK"        },
+
+	{ "eucjp-0",        "eucJP"  	 },
+	{ "ujis-0",         "ujis"  	 },
+	{ "jisx0208.1983-0","SJIS"       },
+	{ "jisx0212.1990-0","SJIS"       },
+	{ "pck",	    "SJIS"       },
+	{ NULL,             NULL         }
+};
+
+
+
+/* Another copy of this trivial list implementation
+   Why?  This stuff gets called a lot (potentially), should run fast,
+   and g_list's are f@@#$ed up to make this a hassle */
+static void e_dlist_init(EDList *v)
+{
+        v->head = (EDListNode *)&v->tail;
+        v->tail = NULL;
+        v->tailpred = (EDListNode *)&v->head;
+}
+
+static EDListNode *e_dlist_addhead(EDList *l, EDListNode *n)
+{
+        n->next = l->head;
+        n->prev = (EDListNode *)&l->head;
+        l->head->prev = n;
+        l->head = n;
+        return n;
+}
+
+static EDListNode *e_dlist_addtail(EDList *l, EDListNode *n)
+{
+        n->next = (EDListNode *)&l->tail;
+        n->prev = l->tailpred;
+        l->tailpred->next = n;
+        l->tailpred = n;
+        return n;
+}
+
+static EDListNode *e_dlist_remove(EDListNode *n)
+{
+        n->next->prev = n->prev;
+        n->prev->next = n->next;
+        return n;
+}
+
+
+/* fucking glib... */
+static const char *
+e_strdown (char *str)
+{
+	register char *s = str;
+	
+	while (*s) {
+		if (*s >= 'A' && *s <= 'Z')
+			*s += 0x20;
+		s++;
+	}
+	
+	return str;
+}
+
+static const char *
+e_strup (char *str)
+{
+	register char *s = str;
+	
+	while (*s) {
+		if (*s >= 'a' && *s <= 'z')
+			*s -= 0x20;
+		s++;
+	}
+	
+	return str;
+}
+
+
+static void
+locale_parse_lang (const char *locale)
+{
+	char *codeset, *lang;
+	
+	if ((codeset = strchr (locale, '.')))
+		lang = g_strndup (locale, codeset - locale);
+	else
+		lang = g_strdup (locale);
+	
+	/* validate the language */
+	if (strlen (lang) >= 2) {
+		if (lang[2] == '-' || lang[2] == '_') {
+			/* canonicalise the lang */
+			e_strdown (lang);
+			
+			/* validate the country code */
+			if (strlen (lang + 3) > 2) {
+				/* invalid country code */
+				lang[2] = '\0';
+			} else {
+				lang[2] = '-';
+				e_strup (lang + 3);
+			}
+		} else if (lang[2] != '\0') {
+			/* invalid language */
+			g_free (lang);
+			lang = NULL;
+		}
+		
+		locale_lang = lang;
+	} else {
+		/* invalid language */
+		locale_lang = NULL;
+		g_free (lang);
+	}
+}
+
+/* NOTE: Owns the lock on return if keep is TRUE ! */
+static void
+camel_iconv_init(int keep)
+{
+	char *from, *to, *locale;
+	int i;
+
+	LOCK();
+
+	if (iconv_charsets != NULL) {
+		if (!keep)
+			UNLOCK();
+		return;
+	}
+
+	iconv_charsets = g_hash_table_new(g_str_hash, g_str_equal);
+	
+	for (i = 0; known_iconv_charsets[i].charset != NULL; i++) {
+		from = g_strdup(known_iconv_charsets[i].charset);
+		to = g_strdup(known_iconv_charsets[i].iconv_name);
+		e_strdown (from);
+		g_hash_table_insert(iconv_charsets, from, to);
+	}
+
+	e_dlist_init(&iconv_cache_list);
+	iconv_cache = g_hash_table_new(g_str_hash, g_str_equal);
+	iconv_cache_open = g_hash_table_new(NULL, NULL);
+	
+#ifndef G_OS_WIN32
+	locale = setlocale (LC_ALL, NULL);
+#else
+	locale = g_win32_getlocale ();
+#endif
+	
+	if (!locale || !strcmp (locale, "C") || !strcmp (locale, "POSIX")) {
+		/* The locale "C"  or  "POSIX"  is  a  portable  locale;  its
+		 * LC_CTYPE  part  corresponds  to  the 7-bit ASCII character
+		 * set.
+		 */
+		
+		locale_charset = NULL;
+		locale_lang = NULL;
+	} else {
+#ifdef G_OS_WIN32
+		g_get_charset (&locale_charset);
+		locale_charset = g_strdup (locale_charset);
+		e_strdown (locale_charset);
+#else
+#ifdef HAVE_CODESET
+		locale_charset = g_strdup (nl_langinfo (CODESET));
+		e_strdown (locale_charset);
+#else
+		/* A locale name is typically of  the  form  language[_terri-
+		 * tory][.codeset][@modifier],  where  language is an ISO 639
+		 * language code, territory is an ISO 3166 country code,  and
+		 * codeset  is  a  character  set or encoding identifier like
+		 * ISO-8859-1 or UTF-8.
+		 */
+		char *codeset, *p;
+		
+		codeset = strchr (locale, '.');
+		if (codeset) {
+			codeset++;
+			
+			/* ; is a hack for debian systems and / is a hack for Solaris systems */
+			for (p = codeset; *p && !strchr ("@;/", *p); p++);
+			locale_charset = g_strndup (codeset, p - codeset);
+			e_strdown (locale_charset);
+		} else {
+			/* charset unknown */
+			locale_charset = NULL;
+		}
+#endif		
+#endif	/* !G_OS_WIN32 */
+		
+		/* parse the locale lang */
+		locale_parse_lang (locale);
+
+	}
+
+#ifdef G_OS_WIN32
+	g_free (locale);
+#endif
+	if (!keep)
+		UNLOCK();
+}
+
+const gchar *
+camel_iconv_charset_name (const gchar *charset)
+{
+	char *name, *ret, *tmp;
+
+	if (charset == NULL)
+		return NULL;
+
+	name = g_alloca (strlen (charset) + 1);
+	strcpy (name, charset);
+	e_strdown (name);
+	
+	camel_iconv_init(TRUE);
+	ret = g_hash_table_lookup(iconv_charsets, name);
+	if (ret != NULL) {
+		UNLOCK();
+		return ret;
+	}
+
+	/* Unknown, try canonicalise some basic charset types to something that should work */
+	if (strncmp(name, "iso", 3) == 0) {
+		/* Convert iso-nnnn-n or isonnnn-n or iso_nnnn-n to iso-nnnn-n or isonnnn-n */
+		int iso, codepage;
+		char *p;
+		
+		tmp = name + 3;
+		if (*tmp == '-' || *tmp == '_')
+			tmp++;
+		
+		iso = strtoul (tmp, &p, 10);
+		
+		if (iso == 10646) {
+			/* they all become ICONV_10646 */
+			ret = g_strdup (ICONV_10646);
+		} else {
+			tmp = p;
+			if (*tmp == '-' || *tmp == '_')
+				tmp++;
+			
+			codepage = strtoul (tmp, &p, 10);
+			
+			if (p > tmp) {
+				/* codepage is numeric */
+#ifdef __aix__
+				if (codepage == 13)
+					ret = g_strdup ("IBM-921");
+				else
+#endif /* __aix__ */
+					ret = g_strdup_printf (ICONV_ISO_D_FORMAT, iso, codepage);
+			} else {
+				/* codepage is a string - probably iso-2022-jp or something */
+				ret = g_strdup_printf (ICONV_ISO_S_FORMAT, iso, p);
+			}
+		}
+	} else if (strncmp(name, "windows-", 8) == 0) {
+		/* Convert windows-nnnnn or windows-cpnnnnn to cpnnnn */
+		tmp = name+8;
+		if (!strncmp(tmp, "cp", 2))
+			tmp+=2;
+		ret = g_strdup_printf("CP%s", tmp);
+	} else if (strncmp(name, "microsoft-", 10) == 0) {
+		/* Convert microsoft-nnnnn or microsoft-cpnnnnn to cpnnnn */
+		tmp = name+10;
+		if (!strncmp(tmp, "cp", 2))
+			tmp+=2;
+		ret = g_strdup_printf("CP%s", tmp);	
+	} else {
+		/* Just assume its ok enough as is, case and all */
+		ret = g_strdup(charset);
+	}
+
+	g_hash_table_insert(iconv_charsets, g_strdup(name), ret);
+	UNLOCK();
+
+	return ret;
+}
+
+static void
+flush_entry(struct _iconv_cache *ic)
+{
+	struct _iconv_cache_node *in, *nn;
+
+	in = (struct _iconv_cache_node *)ic->open.head;
+	nn = in->next;
+	while (nn) {
+		if (in->ip != (iconv_t)-1) {
+			g_hash_table_remove(iconv_cache_open, in->ip);
+			iconv_close(in->ip);
+		}
+		g_free(in);
+		in = nn;
+		nn = in->next;
+	}
+	g_free(ic->conv);
+	g_free(ic);
+}
+
+/* This should run pretty quick, its called a lot */
+iconv_t
+camel_iconv_open (const gchar *oto, const gchar *ofrom)
+{
+	const char *to, *from;
+	char *tofrom;
+	struct _iconv_cache *ic;
+	struct _iconv_cache_node *in;
+	int errnosav;
+	iconv_t ip;
+
+	if (oto == NULL || ofrom == NULL) {
+		errno = EINVAL;
+		return (iconv_t) -1;
+	}
+	
+	to = camel_iconv_charset_name (oto);
+	from = camel_iconv_charset_name (ofrom);
+	tofrom = g_alloca (strlen (to) + strlen (from) + 2);
+	sprintf(tofrom, "%s%%%s", to, from);
+
+	LOCK();
+
+	ic = g_hash_table_lookup(iconv_cache, tofrom);
+	if (ic) {
+		e_dlist_remove((EDListNode *)ic);
+	} else {
+		struct _iconv_cache *last = (struct _iconv_cache *)iconv_cache_list.tailpred;
+		struct _iconv_cache *prev;
+
+		prev = last->prev;
+		while (prev && iconv_cache_size > E_ICONV_CACHE_SIZE) {
+			in = (struct _iconv_cache_node *)last->open.head;
+			if (in->next && !in->busy) {
+				cd(printf("Flushing iconv converter '%s'\n", last->conv));
+				e_dlist_remove((EDListNode *)last);
+				g_hash_table_remove(iconv_cache, last->conv);
+				flush_entry(last);
+				iconv_cache_size--;
+			}
+			last = prev;
+			prev = last->prev;
+		}
+
+		iconv_cache_size++;
+		
+		ic = g_malloc(sizeof(*ic));
+		e_dlist_init(&ic->open);
+		ic->conv = g_strdup(tofrom);
+		g_hash_table_insert(iconv_cache, ic->conv, ic);
+
+		cd(printf("Creating iconv converter '%s'\n", ic->conv));
+	}
+	e_dlist_addhead(&iconv_cache_list, (EDListNode *)ic);
+
+	/* If we have a free iconv, use it */
+	in = (struct _iconv_cache_node *)ic->open.tailpred;
+	if (in->prev && !in->busy) {
+		cd(printf("using existing iconv converter '%s'\n", ic->conv));
+		ip = in->ip;
+		if (ip != (iconv_t)-1) {
+			/* work around some broken iconv implementations 
+			 * that die if the length arguments are NULL 
+			 */
+			size_t buggy_iconv_len = 0;
+			char *buggy_iconv_buf = NULL;
+
+			/* resets the converter */
+			iconv(ip, &buggy_iconv_buf, &buggy_iconv_len, &buggy_iconv_buf, &buggy_iconv_len);
+			in->busy = TRUE;
+			e_dlist_remove((EDListNode *)in);
+			e_dlist_addhead(&ic->open, (EDListNode *)in);
+		}
+	} else {
+		cd(printf("creating new iconv converter '%s'\n", ic->conv));
+		ip = iconv_open(to, from);
+		in = g_malloc(sizeof(*in));
+		in->ip = ip;
+		in->parent = ic;
+		e_dlist_addhead(&ic->open, (EDListNode *)in);
+		if (ip != (iconv_t)-1) {
+			g_hash_table_insert(iconv_cache_open, ip, in);
+			in->busy = TRUE;
+		} else {
+			errnosav = errno;
+			g_warning("Could not open converter for '%s' to '%s' charset", from, to);
+			in->busy = FALSE;
+			errno = errnosav;
+		}
+	}
+
+	UNLOCK();
+
+	return ip;
+}
+
+gsize
+camel_iconv (iconv_t cd, const gchar **inbuf, gsize *inbytesleft,
+             gchar ** outbuf, gsize *outbytesleft)
+{
+	return iconv(cd, (char **) inbuf, inbytesleft, outbuf, outbytesleft);
+}
+
+void
+camel_iconv_close (iconv_t ip)
+{
+	struct _iconv_cache_node *in;
+
+	if (ip == (iconv_t)-1)
+		return;
+
+	LOCK();
+	in = g_hash_table_lookup(iconv_cache_open, ip);
+	if (in) {
+		cd(printf("closing iconv converter '%s'\n", in->parent->conv));
+		e_dlist_remove((EDListNode *)in);
+		in->busy = FALSE;
+		e_dlist_addtail(&in->parent->open, (EDListNode *)in);
+	} else {
+		g_warning("trying to close iconv i dont know about: %p", ip);
+		iconv_close(ip);
+	}
+	UNLOCK();
+
+}
+
+const gchar *
+camel_iconv_locale_charset (void)
+{
+	camel_iconv_init(FALSE);
+
+	return locale_charset;
+}
+
+
+const gchar *
+camel_iconv_locale_language (void)
+{
+	camel_iconv_init (FALSE);
+	
+	return locale_lang;
+}
+
+/* map CJKR charsets to their language code */
+/* NOTE: only support charset names that will be returned by
+ * camel_iconv_charset_name() so that we don't have to keep track of all
+ * the aliases too. */
+static struct {
+	char *charset;
+	char *lang;
+} cjkr_lang_map[] = {
+	{ "Big5",        "zh" },
+	{ "BIG5HKSCS",   "zh" },
+	{ "gb2312",      "zh" },
+	{ "gb18030",     "zh" },
+	{ "gbk",         "zh" },
+	{ "euc-tw",      "zh" },
+	{ "iso-2022-jp", "ja" },
+	{ "sjis",        "ja" },
+	{ "ujis",        "ja" },
+	{ "eucJP",       "ja" },
+	{ "euc-jp",      "ja" },
+	{ "euc-kr",      "ko" },
+	{ "koi8-r",      "ru" },
+	{ "koi8-u",      "uk" }
+};
+
+const gchar *
+camel_iconv_charset_language (const gchar *charset)
+{
+	int i;
+	
+	if (!charset)
+		return NULL;
+	
+	charset = camel_iconv_charset_name (charset);
+	for (i = 0; i < G_N_ELEMENTS (cjkr_lang_map); i++) {
+		if (!g_ascii_strcasecmp (cjkr_lang_map[i].charset, charset))
+			return cjkr_lang_map[i].lang;
+	}
+	
+	return NULL;
+}
Index: camel/camel-iconv.h
===================================================================
--- camel/camel-iconv.h	(revision 8620)
+++ camel/camel-iconv.h	(working copy)
@@ -26,19 +26,24 @@
 
 #include <sys/types.h>
 #include <iconv.h>
+#include <glib.h>
 
 G_BEGIN_DECLS
 
-const char *camel_iconv_locale_charset (void);
-const char *camel_iconv_locale_language (void);
+const gchar *	camel_iconv_locale_charset	(void);
+const gchar *	camel_iconv_locale_language	(void);
 
-const char *camel_iconv_charset_name (const char *charset);
+const gchar *	camel_iconv_charset_name	(const gchar *charset);
+const gchar *	camel_iconv_charset_language	(const gchar *charset);
 
-const char *camel_iconv_charset_language (const char *charset);
-
-iconv_t camel_iconv_open (const char *to, const char *from);
-size_t camel_iconv (iconv_t cd, const char **inbuf, size_t *inleft, char **outbuf, size_t *outleft);
-void camel_iconv_close (iconv_t cd);
+iconv_t		camel_iconv_open		(const gchar *to,
+						 const gchar *from);
+gsize		camel_iconv			(iconv_t cd,
+						 const gchar **inbuf,
+						 gsize *inleft,
+						 gchar **outbuf,
+						 gsize *outleft);
+void		camel_iconv_close		(iconv_t cd);
 
 G_END_DECLS
 
Index: camel/camel-url-scanner.c
===================================================================
--- camel/camel-url-scanner.c	(revision 8620)
+++ camel/camel-url-scanner.c	(working copy)
@@ -29,14 +29,13 @@
 #include <stdio.h>
 #include <string.h>
 
-#include <libedataserver/e-trie.h>
-
+#include "camel-trie.h"
 #include "camel-url-scanner.h"
 #include "camel-utf8.h"
 
 struct _CamelUrlScanner {
 	GPtrArray *patterns;
-	ETrie *trie;
+	CamelTrie *trie;
 };
 
 
@@ -47,7 +46,7 @@ camel_url_scanner_new (void)
 
 	scanner = g_new (CamelUrlScanner, 1);
 	scanner->patterns = g_ptr_array_new ();
-	scanner->trie = e_trie_new (TRUE);
+	scanner->trie = camel_trie_new (TRUE);
 
 	return scanner;
 }
@@ -59,7 +58,7 @@ camel_url_scanner_free (CamelUrlScanner 
 	g_return_if_fail (scanner != NULL);
 
 	g_ptr_array_free (scanner->patterns, TRUE);
-	e_trie_free (scanner->trie);
+	camel_trie_free (scanner->trie);
 	g_free (scanner);
 }
 
@@ -69,7 +68,7 @@ camel_url_scanner_add (CamelUrlScanner *
 {
 	g_return_if_fail (scanner != NULL);
 
-	e_trie_add (scanner->trie, pattern->pattern, scanner->patterns->len);
+	camel_trie_add (scanner->trie, pattern->pattern, scanner->patterns->len);
 	g_ptr_array_add (scanner->patterns, pattern);
 }
 
@@ -89,7 +88,7 @@ camel_url_scanner_scan (CamelUrlScanner 
 	inend = inptr + inlen;
 
 	do {
-		if (!(pos = e_trie_search (scanner->trie, (const char *)inptr, inlen, &pattern)))
+		if (!(pos = camel_trie_search (scanner->trie, (const char *)inptr, inlen, &pattern)))
 			return FALSE;
 
 		pat = g_ptr_array_index (scanner->patterns, pattern);
Index: camel/camel-sasl-digest-md5.c
===================================================================
--- camel/camel-sasl-digest-md5.c	(revision 8620)
+++ camel/camel-sasl-digest-md5.c	(working copy)
@@ -32,9 +32,8 @@
 #include <glib.h>
 #include <glib/gi18n-lib.h>
 
-#include <libedataserver/e-iconv.h>
-
 #include "camel-charset-map.h"
+#include "camel-iconv.h"
 #include "camel-mime-utils.h"
 #include "camel-net-utils.h"
 #include "camel-sasl-digest-md5.h"
@@ -736,18 +735,18 @@ digest_response (struct _DigestResponse 
 		const char *inbuf;
 		iconv_t cd;
 
-		charset = e_iconv_locale_charset ();
+		charset = camel_iconv_locale_charset ();
 		if (!charset)
 			charset = "iso-8859-1";
 
-		cd = e_iconv_open (resp->charset, charset);
+		cd = camel_iconv_open (resp->charset, charset);
 
 		len = strlen (resp->username);
 		outlen = 2 * len; /* plenty of space */
 
 		outbuf = username = g_malloc0 (outlen + 1);
 		inbuf = resp->username;
-		if (cd == (iconv_t) -1 || e_iconv (cd, &inbuf, &len, &outbuf, &outlen) == (size_t) -1) {
+		if (cd == (iconv_t) -1 || camel_iconv (cd, &inbuf, &len, &outbuf, &outlen) == (size_t) -1) {
 			/* We can't convert to UTF-8 - pretend we never got a charset param? */
 			g_free (resp->charset);
 			resp->charset = NULL;
@@ -758,7 +757,7 @@ digest_response (struct _DigestResponse 
 		}
 
 		if (cd != (iconv_t) -1)
-			e_iconv_close (cd);
+			camel_iconv_close (cd);
 
 		g_byte_array_append (buffer, (guint8 *) username, strlen (username));
 		g_free (username);
Index: camel/camel-mime-message.c
===================================================================
--- camel/camel-mime-message.c	(revision 8620)
+++ camel/camel-mime-message.c	(working copy)
@@ -32,9 +32,9 @@
 #include <stdio.h>
 #include <string.h>
 
-#include <libedataserver/e-iconv.h>
 #include <libedataserver/e-time-utils.h>
 
+#include "camel-iconv.h"
 #include "camel-mime-filter-bestenc.h"
 #include "camel-mime-filter-charset.h"
 #include "camel-mime-message.h"
@@ -692,7 +692,7 @@ process_header (CamelMedium *medium, con
 		g_free (message->subject);
 		if (((CamelDataWrapper *) message)->mime_type) {
 			charset = camel_content_type_param (((CamelDataWrapper *) message)->mime_type, "charset");
-			charset = e_iconv_charset_name (charset);
+			charset = camel_iconv_charset_name (charset);
 		} else
 			charset = NULL;
 		
Index: camel/camel-gpg-context.c
===================================================================
--- camel/camel-gpg-context.c	(revision 8620)
+++ camel/camel-gpg-context.c	(working copy)
@@ -53,10 +53,9 @@
 #include <termios.h>
 #endif
 
-#include <libedataserver/e-iconv.h>
-
 #include "camel-debug.h"
 #include "camel-gpg-context.h"
+#include "camel-iconv.h"
 #include "camel-mime-filter-canon.h"
 #include "camel-mime-filter-charset.h"
 #include "camel-mime-part.h"
@@ -298,7 +297,7 @@ gpg_ctx_new (CamelSession *session)
 	gpg->diagbuf = CAMEL_STREAM_MEM (stream)->buffer;
 	gpg->diagflushed = FALSE;
 
-	if ((charset = e_iconv_locale_charset ()) && g_ascii_strcasecmp (charset, "UTF-8") != 0) {
+	if ((charset = camel_iconv_locale_charset ()) && g_ascii_strcasecmp (charset, "UTF-8") != 0) {
 		CamelMimeFilterCharset *filter;
 		CamelStreamFilter *fstream;
 
Index: camel/camel-mime-filter-charset.c
===================================================================
--- camel/camel-mime-filter-charset.c	(revision 8620)
+++ camel/camel-mime-filter-charset.c	(working copy)
@@ -27,9 +27,8 @@
 #include <errno.h>
 #include <string.h>
 
-#include <libedataserver/e-iconv.h>
-
 #include "camel-charset-map.h"
+#include "camel-iconv.h"
 #include "camel-mime-filter-charset.h"
 
 #define d(x)
@@ -67,7 +66,7 @@ camel_mime_filter_charset_finalize(Camel
 	g_free(f->from);
 	g_free(f->to);
 	if (f->ic != (iconv_t) -1) {
-		e_iconv_close (f->ic);
+		camel_iconv_close (f->ic);
 		f->ic = (iconv_t) -1;
 	}
 }
@@ -83,7 +82,7 @@ reset(CamelMimeFilter *mf)
 	/* what happens with the output bytes if this resets the state? */
 	if (f->ic != (iconv_t) -1) {
 		buffer = buf;
-		e_iconv (f->ic, NULL, NULL, &buffer, &outlen);
+		camel_iconv (f->ic, NULL, NULL, &buffer, &outlen);
 	}
 }
 
@@ -107,7 +106,7 @@ complete(CamelMimeFilter *mf, char *in, 
 
 	if (inleft > 0) {
 		do {
-			converted = e_iconv (charset->ic, &inbuf, &inleft, &outbuf, &outleft);
+			converted = camel_iconv (charset->ic, &inbuf, &inleft, &outbuf, &outleft);
 			if (converted == (size_t) -1) {
 				if (errno == E2BIG) {
 					/*
@@ -147,7 +146,7 @@ complete(CamelMimeFilter *mf, char *in, 
 	}
 
 	/* flush the iconv conversion */
-	e_iconv (charset->ic, NULL, NULL, &outbuf, &outleft);
+	camel_iconv (charset->ic, NULL, NULL, &outbuf, &outleft);
 
 	*out = mf->outbuf;
 	*outlen = mf->outsize - outleft;
@@ -181,7 +180,7 @@ filter(CamelMimeFilter *mf, char *in, si
 	inleft = len;
 
 	do {
-		converted = e_iconv (charset->ic, &inbuf, &inleft, &outbuf, &outleft);
+		converted = camel_iconv (charset->ic, &inbuf, &inleft, &outbuf, &outleft);
 		if (converted == (size_t) -1) {
 			if (errno == E2BIG || errno == EINVAL)
 				break;
@@ -273,7 +272,7 @@ camel_mime_filter_charset_new_convert (c
 
 	new = CAMEL_MIME_FILTER_CHARSET (camel_object_new (camel_mime_filter_charset_get_type ()));
 
-	new->ic = e_iconv_open (to_charset, from_charset);
+	new->ic = camel_iconv_open (to_charset, from_charset);
 	if (new->ic == (iconv_t) -1) {
 		w(g_warning ("Cannot create charset conversion from %s to %s: %s",
 			     from_charset ? from_charset : "(null)",
Index: camel/camel-folder-summary.c
===================================================================
--- camel/camel-folder-summary.c	(revision 8620)
+++ camel/camel-folder-summary.c	(working copy)
@@ -36,12 +36,12 @@
 #include <glib.h>
 #include <glib/gstdio.h>
 
-#include <libedataserver/e-iconv.h>
 #include <libedataserver/e-memory.h>
 
 #include "camel-file-utils.h"
 #include "camel-folder-summary.h"
 #include "camel-folder.h"
+#include "camel-iconv.h"
 #include "camel-mime-filter-basic.h"
 #include "camel-mime-filter-charset.h"
 #include "camel-mime-filter-html.h"
@@ -1758,7 +1758,7 @@ message_info_new_from_header(CamelFolder
 	     && (g_ascii_strcasecmp(charset, "us-ascii") == 0))
 		charset = NULL;
 
-	charset = charset ? e_iconv_charset_name (charset) : NULL;
+	charset = charset ? camel_iconv_charset_name (charset) : NULL;
 
 	subject = summary_format_string(h, "subject", charset);
 	from = summary_format_address(h, "from", charset);
@@ -2023,7 +2023,7 @@ content_info_new_from_header(CamelFolder
 
 	ci = camel_folder_summary_content_info_new (s);
 
-	charset = e_iconv_locale_charset ();
+	charset = camel_iconv_locale_charset ();
 	ci->id = camel_header_msgid_decode (camel_header_raw_find (&h, "content-id", NULL));
 	ci->description = camel_header_decode_string (camel_header_raw_find (&h, "content-description", NULL), charset);
 	ci->encoding = camel_content_transfer_encoding_decode (camel_header_raw_find (&h, "content-transfer-encoding", NULL));
Index: docs/reference/camel/camel-sections.txt
===================================================================
--- docs/reference/camel/camel-sections.txt	(revision 8620)
+++ docs/reference/camel/camel-sections.txt	(working copy)
@@ -629,6 +629,16 @@ camel_internet_address_get_type
 </SECTION>
 
 <SECTION>
+<FILE>camel-md5-utils</FILE>
+CamelMD5Context
+camel_md5_get_digest
+camel_md5_get_digest_from_file
+camel_md5_init
+camel_md5_update
+camel_md5_final
+</SECTION>
+
+<SECTION>
 <FILE>camel-medium</FILE>
 <TITLE>CamelMedium</TITLE>
 CamelMedium
@@ -1077,6 +1087,21 @@ camel_mime_part_get_type
 </SECTION>
 
 <SECTION>
+<FILE>camel-msgport</FILE>
+<TITLE>CamelMsgPort</TITLE>
+CamelMsg
+CamelMsgPort
+camel_msgport_new
+camel_msgport_destroy
+camel_msgport_fd
+camel_msgport_push
+camel_msgport_pop
+camel_msgport_try_pop
+camel_msgport_reply
+camel_msgport_prfd
+</SECTION>
+
+<SECTION>
 <FILE>camel-multipart-encrypted</FILE>
 <TITLE>CamelMultipartEncrypted</TITLE>
 CamelMultipartEncrypted
@@ -1958,6 +1983,15 @@ camel_transport_get_type
 </SECTION>
 
 <SECTION>
+<FILE>camel-trie</FILE>
+CamelTrie
+camel_trie_new
+camel_trie_free
+camel_trie_add
+camel_trie_search
+</SECTION>
+
+<SECTION>
 <FILE>camel-vee-folder</FILE>
 <TITLE>CamelVeeFolder</TITLE>
 CamelVeeFolder
Index: docs/reference/camel/camel-docs.sgml
===================================================================
--- docs/reference/camel/camel-docs.sgml	(revision 8620)
+++ docs/reference/camel/camel-docs.sgml	(working copy)
@@ -20,11 +20,13 @@
 <!ENTITY CamelGPGContext SYSTEM "xml/camel-gpg-context.xml">
 <!ENTITY CamelHTMLParser SYSTEM "xml/camel-html-parser.xml">
 <!ENTITY CamelHTTPStream SYSTEM "xml/camel-http-stream.xml">
+<!ENTITY CamelIconv SYSTEM "xml/camel-iconv.xml">
 <!ENTITY CamelIndex SYSTEM "xml/camel-index.xml">
 <!ENTITY CamelInternetAddress SYSTEM "xml/camel-internet-address.xml">
 <!ENTITY CamelListUtils SYSTEM "xml/camel-list-utils.xml">
 <!ENTITY CamelLock SYSTEM "xml/camel-lock.xml">
 <!ENTITY CamelLockClient SYSTEM "xml/camel-lock-client.xml">
+<!ENTITY CamelMD5Utils SYSTEM "xml/camel-md5-utils.xml">
 <!ENTITY CamelMedium SYSTEM "xml/camel-medium.xml">
 <!ENTITY CamelMIMEFilter SYSTEM "xml/camel-mime-filter.xml">
 <!ENTITY CamelMIMEFilterBasic SYSTEM "xml/camel-mime-filter-basic.xml">
@@ -46,6 +48,7 @@
 <!ENTITY CamelMIMEPart SYSTEM "xml/camel-mime-part.xml">
 <!ENTITY CamelMIMEPartUtils SYSTEM "xml/camel-mime-part-utils.xml">
 <!ENTITY CamelMIMEUtils SYSTEM "xml/camel-mime-utils.xml">
+<!ENTITY CamelMsgPort SYSTEM "xml/camel-msgport.xml">
 <!ENTITY CamelMultipart SYSTEM "xml/camel-multipart.xml">
 <!ENTITY CamelMultipartEncrypted SYSTEM "xml/camel-multipart-encrypted.xml">
 <!ENTITY CamelMultipartSigned SYSTEM "xml/camel-multipart-signed.xml">
@@ -88,6 +91,7 @@
 <!ENTITY CamelTcpStreamSSL SYSTEM "xml/camel-tcp-stream-ssl.xml">
 <!ENTITY CamelTextIndex SYSTEM "xml/camel-text-index.xml">
 <!ENTITY CamelTransport SYSTEM "xml/camel-transport.xml">
+<!ENTITY CamelTrie SYSTEM "xml/camel-trie.xml">
 <!ENTITY CamelUIDCache SYSTEM "xml/camel-uid-cache.xml">
 <!ENTITY CamelURL SYSTEM "xml/camel-url.xml">
 <!ENTITY CamelURLScanner SYSTEM "xml/camel-url-scanner.xml">
Index: docs/reference/camel/tmpl/camel-unused.sgml
===================================================================
--- docs/reference/camel/tmpl/camel-unused.sgml	(revision 8620)
+++ docs/reference/camel/tmpl/camel-unused.sgml	(working copy)
@@ -286,6 +286,12 @@ camel-types
 
 @search_lock: 
 
+<!-- ##### STRUCT CamelMD5Context ##### -->
+<para>
+
+</para>
+
+
 <!-- ##### STRUCT CamelMimeFilterChomp ##### -->
 <para>
 
@@ -458,6 +464,47 @@ camel-types
 
 @Returns: 
 
+<!-- ##### FUNCTION camel_md5_final ##### -->
+<para>
+
+</para>
+
+@ctx: 
+@digest: 
+
+<!-- ##### FUNCTION camel_md5_get_digest ##### -->
+<para>
+
+</para>
+
+@buffer: 
+@buffer_size: 
+@digest: 
+
+<!-- ##### FUNCTION camel_md5_get_digest_from_file ##### -->
+<para>
+
+</para>
+
+@filename: 
+@digest: 
+
+<!-- ##### FUNCTION camel_md5_init ##### -->
+<para>
+
+</para>
+
+@ctx: 
+
+<!-- ##### FUNCTION camel_md5_update ##### -->
+<para>
+
+</para>
+
+@ctx: 
+@buf: 
+@len: 
+
 <!-- ##### FUNCTION camel_partition_table_get_type ##### -->
 <para>
 
Index: libedataserver/e-iconv.h
===================================================================
--- libedataserver/e-iconv.h	(revision 8620)
+++ libedataserver/e-iconv.h	(working copy)
@@ -22,9 +22,13 @@
  * 02110-1301, USA.
  */
 
+/* This API has been moved to Camel. */
+
 #ifndef _E_ICONV_H_
 #define _E_ICONV_H_
 
+#ifndef EDS_DISABLE_DEPRECATED
+
 #include <iconv.h>
 
 #ifdef __cplusplus
@@ -46,4 +50,6 @@ const char *e_iconv_charset_language (co
 }
 #endif /* __cplusplus */
 
+#endif /* EDS_DISABLE_DEPRECATED */
+
 #endif /* !_E_ICONV_H_ */
Index: libedataserver/e-trie.h
===================================================================
--- libedataserver/e-trie.h	(revision 8620)
+++ libedataserver/e-trie.h	(working copy)
@@ -20,10 +20,13 @@
  *
  */
 
+/* This API has been moved to Camel. */
 
 #ifndef __E_TRIE_H__
 #define __E_TRIE_H__
 
+#ifndef EDS_DISABLE_DEPRECATED
+
 #ifdef __cplusplus
 extern "C" {
 #pragma }
@@ -44,4 +47,6 @@ const char *e_trie_search (ETrie *trie, 
 }
 #endif /* __cplusplus */
 
+#endif /* EDS_DISABLE_DEPRECATED */
+
 #endif /* __E_TRIE_H__ */
Index: libedataserver/e-msgport.h
===================================================================
--- libedataserver/e-msgport.h	(revision 8620)
+++ libedataserver/e-msgport.h	(working copy)
@@ -48,6 +48,7 @@ void em_cache_node_unref(EMCache *emc, E
 void em_cache_add(EMCache *emc, EMCacheNode *n);
 void em_cache_clear(EMCache *emc);
 
+#ifndef EDS_DISABLE_DEPRECATED
 /* message ports - a simple inter-thread 'ipc' primitive */
 /* opaque handle */
 typedef struct _EMsgPort EMsgPort;
@@ -70,6 +71,7 @@ void e_msgport_reply(EMsg *msg);
 #ifdef HAVE_NSS
 struct PRFileDesc *e_msgport_prfd(EMsgPort *mp);
 #endif
+#endif /* EDS_DISABLE_DEPRECATED */
 
 #ifndef EDS_DISABLE_DEPRECATED
 /* e threads, a server thread with a message based request-response, and flexible queuing */
@@ -93,7 +95,7 @@ void e_thread_set_reply_port(EThread *e,
 void e_thread_set_msg_received(EThread *e, EThreadFunc received, void *data);
 void e_thread_put(EThread *e, EMsg *msg);
 int e_thread_busy(EThread *e);
-#endif
+#endif /* EDS_DISABLE_DEPRECATED */
 
 #ifndef EDS_DISABLE_DEPRECATED
 /* sigh, another mutex interface, this one allows different mutex types, portably */
@@ -111,6 +113,6 @@ int e_mutex_unlock(EMutex *m);
 void e_mutex_assert_locked(EMutex *m);
 /* this uses pthread cond's */
 int e_mutex_cond_wait(void *cond, EMutex *m);
-#endif
+#endif /* EDS_DISABLE_DEPRECATED */
 
 #endif
