[Evolution-hackers] Porting the namespace stuff to upstream camel



Hi there,

I'm doing a shot at trying to port the namespace things that I did for
Tny's Camel-lite to Evolution.

It's not working yet and I have not tested it, there are probably quite
a few things still wrong with the patch too ...

Nonetheless, I'm sending it already to get ideas/opinions from the other
developers.

Some remarks so far ...

I think in the end we'll have to bite the bullet and remove those 
imap_store->dir_sep and imap_store->namespace things. This is where most
of the current ugly things come from.

Perhaps just rewriting get_folders_sync completely in stead of having
three different versions of it (like what I did) might also cleanup the
patch (and make it look smaller).

I'm not a big fan of how refresh_refresh vs. get_folder_info_online
works. I don't think Evolution should periodically update the list, but
should always update it the first time after the startup of the
application (no matter what) and perhaps start supporting NOTIFY to get
notifications about mailbox changes more early while running.

Perhaps for users who run Evolution for years without restarting
(unrealistic).

Imho is refresh_refresh very error prone, probably very untested, that
wont update the UI screens with folder lists anyway, ...

But anyway ...

(my point is, that I don't see the point of that piece of code)


Once you have the full_name strings at SELECT context, it looks like all
folder operations just work (no need to prefix them with something that
comes from the namespace's name).

I also adapted CamelImapSummaryStore to cope with multiple namespaces.
Also this part of the patch was quickly done without a lot of error
checking (to get something working quickly).



-- 
Philip Van Hoof, freelance software developer
home: me at pvanhoof dot be 
gnome: pvanhoof at gnome dot org 
http://pvanhoof.be/blog
http://codeminded.be



Index: camel-imap-store.c
===================================================================
--- camel-imap-store.c	(revision 8315)
+++ camel-imap-store.c	(working copy)
@@ -210,6 +210,9 @@
 		disco->diary = NULL;
 	}
 
+	if (imap_store->namespaces)
+		imap_namespaces_destroy (imap_store->namespaces);
+
 	g_free (imap_store->custom_headers);
 }
 
@@ -1452,6 +1455,10 @@
 	/* Get namespace and hierarchy separator */
 	if ((store->capabilities & IMAP_CAPABILITY_NAMESPACE) &&
 	    !(store->parameters & IMAP_PARAM_OVERRIDE_NAMESPACE)) {
+
+
+		struct _namespaces *namespaces;
+
 		response = camel_imap_command (store, NULL, ex, "NAMESPACE");
 		if (!response)
 			goto done;
@@ -1460,28 +1467,41 @@
 		if (!result)
 			goto done;
 
-#if 0
-		/* new code... */
-		namespaces = imap_parse_namespace_response (result);
-		imap_namespaces_destroy (namespaces);
-		/* end new code */
-#endif
+		store->namespaces = imap_parse_namespace_response (result);
+		namespaces = store->namespaces;
 
-		name = camel_strstrcase (result, "NAMESPACE ((");
-		if (name) {
-			char *sep;
+		if (namespaces && namespaces->personal) {
+			store->namespace = namespaces->personal->prefix;
+			store->dir_sep = namespaces->personal->delim;
+		} else {
+			store->namespace = NULL;
+			store->dir_sep = 0;
+		}
 
-			name += 12;
-			store->namespace = imap_parse_string ((const char **) &name, &len);
-			if (name && *name++ == ' ') {
-				sep = imap_parse_string ((const char **) &name, &len);
-				if (sep) {
-					store->dir_sep = *sep;
-					g_free (sep);
-				}
-			}
+		if (namespaces && namespaces->personal) {
+			ns = camel_imap_store_summary_namespace_new(store->summary, namespaces->personal->prefix, namespaces->personal->delim);
+			camel_imap_store_summary_namespace_add(store->summary,ns);
+			camel_imap_store_summary_namespace_set(store->summary, ns);
 		}
+
+		if (namespaces && namespaces->other) {
+			ns = camel_imap_store_summary_namespace_new(store->summary, namespaces->other->prefix, namespaces->other->delim);
+			camel_imap_store_summary_namespace_add(store->summary,ns);
+		}
+
+		if (namespaces && namespaces->shared) {
+			ns = camel_imap_store_summary_namespace_new(store->summary, namespaces->shared->prefix, namespaces->shared->delim);
+			camel_imap_store_summary_namespace_add(store->summary,ns);
+		}
+
+
 		g_free (result);
+
+
+	} else {
+		ns = camel_imap_store_summary_namespace_new(store->summary, store->namespace, store->dir_sep);
+		camel_imap_store_summary_namespace_add(store->summary,ns);
+		camel_imap_store_summary_namespace_set(store->summary, ns);
 	}
 
 	if (!store->namespace)
@@ -2591,6 +2611,241 @@
 	g_hash_table_destroy(present);
 }
 
+
+
+static void
+get_folders_sync_ns(CamelImapStore *imap_store, struct _namespace *namespace, gboolean has_other, gboolean has_shared, CamelException *ex)
+{
+	CamelImapResponse *response;
+	CamelFolderInfo *fi = NULL, *first = NULL, *hfi;
+	char *list;
+	int i, count, j;
+	GHashTable *present;
+	CamelStoreInfo *si;
+	int loops = 2;
+	char *prefix, *lst = "*";
+	gboolean bah = FALSE;
+
+	if (!namespace->prefix || strlen (namespace->prefix) == 0) {
+
+		/**
+		 * NAMESPACE (("" ".") ("x" "y") ("x" "y") ... 
+		 * In this case the IMAP server didn't give us a cute namespace,
+		 * for personal but it has other namespaces. Therefore we'll
+		 * have to do two LIST requests (to get personal): 
+		 * 
+		 *    o. LIST "" %   -  and store the first in thefirst
+		 *
+		 *    o. - If there was a thefirst in the result, we ask for
+		 *         LIST "thefirst." *, 
+		 *         
+		 *       - If there was no thefirst in the result, we ask for
+		 *         LIST "INBOX." *
+		 * 
+		 * But in case there are no other namespaces than personal, we'll
+		 * just ask for LIST "" *, which will be fine (in that case) as
+		 * we won't get a huge list for the shared and other namespaces.
+		 **/
+
+ 		/* We'll start with SELECT context */
+		prefix = g_strdup_printf ("");
+
+ 		/* We'll start with % if we know that there are other namespaces.
+		 * The reason is that otherwise we'd ask for LIST "" * here:
+		 * That request could result in a huge LIST on some IMAP servers.
+		 * For example IMAP servers that proxy NNTP newsgroups the 
+		 * shared or other namespaces. */
+
+		if (has_other || has_shared) {
+			bah = TRUE;
+			lst = "%";
+		}
+
+	} else if (namespace->prefix[strlen(namespace->prefix)-1] != namespace->delim)
+
+		/**
+		 * NAMESPACE (("something" ".") ...
+		 * Usually, IMAP servers give you "something." in stead, but
+		 * this one didn't, so we'll just do that here. I don't really
+		 * understand from the IMAP spec what the correct way is, looks
+		 * like there's quite a bit of confusion among the IMAP server
+		 * developers about this too. So let's just cope with both here.
+		 **/
+		prefix = g_strdup_printf ("%s%c", namespace->prefix, namespace->delim);
+	else 
+		/**
+		 * NAMESPACE (("something." ".")..
+		 * This one is fine as-is. We'll just ask for LIST "something." *
+		 **/
+		prefix = g_strdup(namespace->prefix);
+
+	present = g_hash_table_new(folder_hash, folder_eq);
+
+
+	/* Future LIST-EXTENDED above this */
+	{
+
+		/* If we don't have LIST-EXTENDED we'll have to ask both the
+		   LIST and the LSUB (this one is about the personal namespace,
+		   so recursively asking for all is probably fine). */
+
+		if (bah)
+			loops = 4;
+		else
+			loops = 2;
+
+		for (j = 0; j < loops; j++) {
+
+			if (j == 2) {
+				/* If we got the first last time, ask for the 
+				 * list under that first. */
+				gchar *str = "INBOX";
+				g_free (prefix);
+				if (first && first->full_name)
+					str = first->full_name;
+				prefix = g_strdup_printf ("%s%c", str, namespace->delim);
+				lst = "*";
+			}
+
+			response = camel_imap_command (imap_store, NULL, ex,
+				"%s \"%s\" %s", j==1 ? "LSUB" : "LIST", 
+				prefix, lst);
+
+			if (!response)
+				goto fail;
+
+			for (i = 0; i < response->untagged->len; i++) 
+			{
+				list = response->untagged->pdata[i];
+				fi = parse_list_response_as_folder_info (imap_store, list);
+
+				if (fi) {
+
+					hfi = g_hash_table_lookup(present, fi->full_name);
+					if (hfi == NULL) {
+
+						if (j == 1 || j == 3) {
+							/* It's in LSUB but not in LIST, so it's 
+							 * a \ NonExistent (like above in LIST-EXTENDED) */
+							fi->flags |= CAMEL_FOLDER_SUBSCRIBED /* Future: | CAMEL_FOLDER_NONEXISTENT*/;
+							camel_folder_info_free(fi);
+						} else {
+							g_hash_table_insert(present, fi->full_name, fi);
+							if (!first)
+								first = fi;
+						}
+					} else {
+						/* It's in LSUB and in LIST, so subscribed */
+						if (j == 1 || j == 3) {
+							fi->flags |= CAMEL_FOLDER_SUBSCRIBED;
+							hfi->flags |= CAMEL_STORE_INFO_FOLDER_SUBSCRIBED;
+						} else {
+							hfi->unread = fi->unread;
+							hfi->total = fi->total;
+						}
+					}
+				}
+			}
+			camel_imap_response_free (imap_store, response);
+		}
+	}
+
+
+	g_free (prefix);
+
+	/* Sync summary to match */
+
+	/* FIXME: we need to emit folder_create/subscribed/etc events for any new folders */
+	count = camel_store_summary_count((CamelStoreSummary *)imap_store->summary);
+
+	for (i=0;i<count;i++) {
+		si = camel_store_summary_index((CamelStoreSummary *)imap_store->summary, i);
+		if (si == NULL)
+			continue;
+
+		if ((fi = g_hash_table_lookup(present, camel_store_info_path(imap_store->summary, si))) != NULL) {
+			if (((fi->flags ^ si->flags) & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED))
+				si->flags = (si->flags & ~CAMEL_FOLDER_SUBSCRIBED) | (fi->flags & CAMEL_FOLDER_SUBSCRIBED);
+			si->unread = fi->unread;
+			si->total = fi->total;
+			camel_store_summary_touch((CamelStoreSummary *)imap_store->summary);
+			camel_store_summary_save((CamelStoreSummary *)imap_store->summary, ex);
+		} else {
+			camel_store_summary_remove((CamelStoreSummary *)imap_store->summary, si);
+			camel_store_summary_save((CamelStoreSummary *)imap_store->summary, ex);
+			count--;
+			i--;
+		}
+		camel_store_summary_info_free((CamelStoreSummary *)imap_store->summary, si);
+	}
+fail:
+	g_hash_table_foreach(present, get_folders_free, NULL);
+	g_hash_table_destroy(present);
+
+}
+
+
+
+static void
+get_folders_sync_ns_only_lsub (CamelImapStore *imap_store, struct _namespace *namespace, CamelException *ex)
+{
+	CamelImapResponse *response;
+	CamelFolderInfo *fi, *hfi;
+	char *list;
+	int i, count, j;
+	GHashTable *present;
+	CamelStoreInfo *si;
+	present = g_hash_table_new(folder_hash, folder_eq);
+
+	response = camel_imap_command (imap_store, NULL, ex,
+		"LSUB \"%s\" %G", namespace->prefix, 
+		(strlen (namespace->prefix) > 0)?"*":"%");
+
+	if (!response)
+		goto fail;
+
+	for (i = 0; i < response->untagged->len; i++) {
+		list = response->untagged->pdata[i];
+		fi = parse_list_response_as_folder_info (imap_store, list);
+
+		hfi = g_hash_table_lookup(present, fi->full_name);
+
+		if (hfi == NULL) {
+			fi->flags |= CAMEL_FOLDER_SUBSCRIBED;
+			g_hash_table_insert(present, fi->full_name, fi);
+		}
+	}
+
+	camel_imap_response_free (imap_store, response);
+
+	count = camel_store_summary_count((CamelStoreSummary *)imap_store->summary);
+
+	for (i=0;i<count;i++) {
+		si = camel_store_summary_index((CamelStoreSummary *)imap_store->summary, i);
+		if (si == NULL)
+			continue;
+
+		if ((fi = g_hash_table_lookup(present, camel_store_info_path(imap_store->summary, si))) != NULL) {
+			if (((fi->flags ^ si->flags) & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED))
+				si->flags = (si->flags & ~CAMEL_FOLDER_SUBSCRIBED) | (fi->flags & CAMEL_FOLDER_SUBSCRIBED);
+			si->unread = fi->unread;
+			si->total = fi->total;
+			camel_store_summary_touch((CamelStoreSummary *)imap_store->summary);
+			camel_store_summary_save((CamelStoreSummary *)imap_store->summary, ex);
+		} else {
+			/* camel_store_summary_remove((CamelStoreSummary *)imap_store->summary, si);
+			camel_store_summary_save((CamelStoreSummary *)imap_store->summary, ex);
+			count--;
+			i--;*/
+		}
+		camel_store_summary_info_free((CamelStoreSummary *)imap_store->summary, si);
+	}
+fail:
+	g_hash_table_foreach(present, get_folders_free, NULL);
+	g_hash_table_destroy(present);
+
+}
+
 #if 0
 static void
 dumpfi(CamelFolderInfo *fi)
@@ -2723,6 +2978,7 @@
 	} else {
 		char *pattern;
 		int i;
+		gboolean still_fetch = TRUE;
 
 		CAMEL_SERVICE_REC_LOCK(store, connect_lock);
 
@@ -2730,22 +2986,64 @@
 			goto fail;
 
 		if (top[0] == 0) {
-			if (imap_store->namespace && imap_store->namespace[0]) {
-				get_folders_sync(imap_store, "INBOX", ex);
+
+			if (imap_store->capabilities & IMAP_CAPABILITY_NAMESPACE) 
+			{ 
+				still_fetch = FALSE;
+
+				struct _namespaces *ns = imap_store->namespaces;
+
+				/* Asking LIST and LSUB recursively is fine for the personal 
+				 * namespace. Whoever puts thousands of folders in his personal
+				 * namespace is just asking for it ... */
+
+				if (ns->personal)
+					get_folders_sync_ns (imap_store, ns->personal, 
+						(gboolean) ns->other, 
+						(gboolean) ns->shared, ex);
+
 				if (camel_exception_is_set(ex))
 					goto fail;
 
-				i = strlen(imap_store->namespace)-1;
-				pattern = g_alloca(i+5);
-				strcpy(pattern, imap_store->namespace);
-				while (i>0 && pattern[i] == imap_store->dir_sep)
-					pattern[i--] = 0;
-				i++;
+				/* However, administrators sometimes put NNTP newsgroup roots 
+				 * in either Other or Shared. Therefore perhaps we should not 
+				 * ask for LIST in those namespaces. At least not for now, as 
+				 * right now we really only support recursively asking, in 
+				 * stead of node per node and using % in stead of * as wildcart
+				 * character. (recursively fetching alt.* of NNTP is not a 
+				 * very good idea nowadays...) */
+
+				if (ns->other)
+					get_folders_sync_ns_only_lsub (imap_store, ns->other, ex);
+
+				if (camel_exception_is_set(ex))
+					goto fail;
+
+				if (ns->shared)
+					get_folders_sync_ns_only_lsub (imap_store, ns->shared, ex);
+
+				if (camel_exception_is_set(ex))
+					goto fail;
+
 			} else {
-				pattern = g_alloca(2);
-				pattern[0] = '*';
-				pattern[1] = 0;
-				i=0;
+			
+				if (imap_store->namespace && imap_store->namespace[0]) {
+					get_folders_sync(imap_store, "INBOX", ex);
+					if (camel_exception_is_set(ex))
+						goto fail;
+	
+					i = strlen(imap_store->namespace)-1;
+					pattern = g_alloca(i+5);
+					strcpy(pattern, imap_store->namespace);
+					while (i>0 && pattern[i] == imap_store->dir_sep)
+						pattern[i--] = 0;
+					i++;
+				} else {
+					pattern = g_alloca(2);
+					pattern[0] = '*';
+					pattern[1] = 0;
+					i=0;
+				}
 			}
 		} else {
 			char *name;
@@ -2760,15 +3058,18 @@
 			g_free(name);
 		}
 
-		get_folders_sync(imap_store, pattern, ex);
-		if (camel_exception_is_set(ex))
-			goto fail;
-		if (pattern[0] != '*' && imap_store->dir_sep) {
-			pattern[i] = imap_store->dir_sep;
-			pattern[i+1] = (flags & CAMEL_STORE_FOLDER_INFO_RECURSIVE)?'*':'%';
-			pattern[i+2] = 0;
+		if (still_fetch) {
 			get_folders_sync(imap_store, pattern, ex);
+			if (camel_exception_is_set(ex))
+				goto fail;
+			if (pattern[0] != '*' && imap_store->dir_sep) {
+				pattern[i] = imap_store->dir_sep;
+				pattern[i+1] = (flags & CAMEL_STORE_FOLDER_INFO_RECURSIVE)?'*':'%';
+				pattern[i+2] = 0;
+				get_folders_sync(imap_store, pattern, ex);
+			}
 		}
+
 		camel_store_summary_save((CamelStoreSummary *)imap_store->summary);
 		CAMEL_SERVICE_REC_UNLOCK(store, connect_lock);
 	}
Index: camel-imap-store-summary.h
===================================================================
--- camel-imap-store-summary.h	(revision 8315)
+++ camel-imap-store-summary.h	(working copy)
@@ -63,7 +63,8 @@
 	/* header info */
 	guint32 version;	/* version of base part of file */
 	guint32 capabilities;
-	CamelImapStoreNamespace *namespace; /* eventually to be a list */
+	GList *namespaces; /* eventually to be a list */
+	CamelImapStoreNamespace *namespace;
 };
 
 struct _CamelImapStoreSummaryClass {
@@ -76,6 +77,7 @@
 /* TODO: this api needs some more work, needs to support lists */
 CamelImapStoreNamespace *camel_imap_store_summary_namespace_new(CamelImapStoreSummary *s, const char *full_name, char dir_sep);
 void camel_imap_store_summary_namespace_set(CamelImapStoreSummary *s, CamelImapStoreNamespace *ns);
+void camel_imap_store_summary_namespace_add(CamelImapStoreSummary *s, CamelImapStoreNamespace *ns);
 CamelImapStoreNamespace *camel_imap_store_summary_namespace_find_path(CamelImapStoreSummary *s, const char *path);
 CamelImapStoreNamespace *camel_imap_store_summary_namespace_find_full(CamelImapStoreSummary *s, const char *full_name);
 
Index: camel-imap-store.h
===================================================================
--- camel-imap-store.h	(revision 8315)
+++ camel-imap-store.h	(working copy)
@@ -138,6 +138,7 @@
 	/* NB: namespace should be handled by summary->namespace */
 	char *namespace, dir_sep, *base_url, *storage_path;
 	GHashTable *authtypes;
+	struct _namespaces *namespaces;
 
 	time_t refresh_stamp;
 
Index: camel-imap-store-summary.c
===================================================================
--- camel-imap-store-summary.c	(revision 8315)
+++ camel-imap-store-summary.c	(working copy)
@@ -42,9 +42,9 @@
 #define d(x)
 #define io(x)			/* io debug */
 
-#define CAMEL_IMAP_STORE_SUMMARY_VERSION_0 (0)
+#define CAMEL_IMAP_STORE_SUMMARY_VERSION_0 (1)
 
-#define CAMEL_IMAP_STORE_SUMMARY_VERSION (0)
+#define CAMEL_IMAP_STORE_SUMMARY_VERSION (1)
 
 #define _PRIVATE(o) (((CamelImapStoreSummary *)(o))->priv)
 
@@ -93,14 +93,20 @@
 
 	((CamelStoreSummary *)s)->store_info_size = sizeof(CamelImapStoreInfo);
 	s->version = CAMEL_IMAP_STORE_SUMMARY_VERSION;
+	s->namespaces = NULL;
+	s->namespace = NULL;
 }
 
 static void
 camel_imap_store_summary_finalise (CamelObject *obj)
 {
 	/*struct _CamelImapStoreSummaryPrivate *p;*/
-	/*CamelImapStoreSummary *s = (CamelImapStoreSummary *)obj;*/
+	CamelImapStoreSummary *is = (CamelImapStoreSummary *)obj;
+	CamelStoreSummary *s = (CamelStoreSummary *) s;
 
+	if (is->namespaces)
+		namespace_clear (s);
+
 	/*p = _PRIVATE(obj);
 	  g_free(p);*/
 }
@@ -345,6 +351,9 @@
 	} else
 		d(printf("  failed\n"));
 
+	if (pathu8)
+		g_free (pathu8);
+
 	return info;
 }
 
@@ -392,57 +401,67 @@
 	return ns;
 }
 
+void camel_imap_store_summary_namespace_add(CamelImapStoreSummary *s, CamelImapStoreNamespace *ns)
+{
+	s->namespaces = g_list_prepend (s->namespaces, ns);
+}
+
 void camel_imap_store_summary_namespace_set(CamelImapStoreSummary *s, CamelImapStoreNamespace *ns)
 {
-	d(printf("Setting namesapce to '%s' '%c' -> '%s'\n", ns->full_name, ns->sep, ns->path));
-	namespace_clear((CamelStoreSummary *)s);
 	s->namespace = ns;
-	camel_store_summary_touch((CamelStoreSummary *)s);
+	return;
 }
 
 CamelImapStoreNamespace *
 camel_imap_store_summary_namespace_find_path(CamelImapStoreSummary *s, const char *path)
 {
 	int len;
-	CamelImapStoreNamespace *ns;
+	GList *list;
+	CamelImapStoreNamespace *nsf = NULL;
 
-	/* NB: this currently only compares against 1 namespace, in future compare against others */
-	ns = s->namespace;
-	while (ns) {
+	list = s->namespaces;
+	while (list) {
+		CamelImapStoreNamespace *ns = list->data;
 		len = strlen(ns->path);
 		if (len == 0
 		    || (strncmp(ns->path, path, len) == 0
-			&& (path[len] == '/' || path[len] == 0)))
+			&& (path[len] == '/' || path[len] == 0))) {
+			nsf = ns;
 			break;
-		ns = NULL;
+		}
+		list = list->next;
 	}
 
-	/* have a default? */
-	return ns;
+	return nsf;
 }
 
 CamelImapStoreNamespace *
 camel_imap_store_summary_namespace_find_full(CamelImapStoreSummary *s, const char *full)
 {
 	int len;
-	CamelImapStoreNamespace *ns;
+	GList *list;
+	CamelImapStoreNamespace *nsf = NULL;
 
 	/* NB: this currently only compares against 1 namespace, in future compare against others */
-	ns = s->namespace;
-	while (ns) {
+	list = s->namespaces;
+	while (list) {
+		CamelImapStoreNamespace *ns = list->data;
 		len = strlen(ns->full_name);
 		d(printf("find_full: comparing namespace '%s' to name '%s'\n", ns->full_name, full));
 		if (len == 0
 		    || (strncmp(ns->full_name, full, len) == 0
-			&& (full[len] == ns->sep || full[len] == 0)))
+			&& (full[len] == ns->sep || full[len] == 0))) {
+			nsf = ns;
 			break;
-		ns = NULL;
+		}
+		list = list->next;
 	}
 
 	/* have a default? */
-	return ns;
+	return nsf;
 }
 
+
 static void
 namespace_free(CamelStoreSummary *s, CamelImapStoreNamespace *ns)
 {
@@ -455,40 +474,90 @@
 namespace_clear(CamelStoreSummary *s)
 {
 	CamelImapStoreSummary *is = (CamelImapStoreSummary *)s;
+	GList *list = is->namespaces;
 
-	if (is->namespace)
-		namespace_free(s, is->namespace);
-	is->namespace = NULL;
+	while (list) {
+		CamelImapStoreNamespace *ns = list->data;
+		namespace_free(s, ns);
+		list=list->next;
+	}
+	g_list_free (is->namespaces);
+	is->namespaces = NULL;
 }
 
-static CamelImapStoreNamespace *
+static int
 namespace_load(CamelStoreSummary *s, FILE *in)
 {
+	CamelImapStoreSummary *is = (CamelImapStoreSummary *) s;
+
 	CamelImapStoreNamespace *ns;
-	guint32 sep = '/';
+	int count = 0, i = 0;
 
-	ns = g_malloc0(sizeof(*ns));
-	if (camel_file_util_decode_string(in, &ns->path) == -1
-	    || camel_file_util_decode_string(in, &ns->full_name) == -1
-	    || camel_file_util_decode_uint32(in, &sep) == -1) {
-		namespace_free(s, ns);
-		ns = NULL;
-	} else {
+	if (is->namespaces)
+		namespace_clear (s);
+
+	if (camel_file_util_decode_uint32(in, &count) == -1)
+		goto nserror;
+
+	for (i=0 ; i< count; i++) {
+		guint32 sep = '/';
+		ns = g_malloc0(sizeof(*ns));
+		if (camel_file_util_decode_string(in, &ns->path) == -1) {
+			namespace_free(s, ns);
+			goto nserror;
+		}
+		if (camel_file_util_decode_string(in, &ns->full_name) == -1) {
+			namespace_free(s, ns);
+			goto nserror;
+		}
+		if (camel_file_util_decode_uint32(in, &sep) == -1) {
+			namespace_free(s, ns);
+			goto nserror;
+		}
 		ns->sep = sep;
+		is->namespaces = g_list_prepend (is->namespaces, ns);
 	}
 
-	return ns;
+	return 0;
+
+ nserror:
+
+	return -1;
 }
 
 static int
-namespace_save(CamelStoreSummary *s, FILE *in, CamelImapStoreNamespace *ns)
+namespace_save(CamelStoreSummary *s, FILE *in)
 {
-	if (camel_file_util_encode_string(in, ns->path) == -1
-	    || camel_file_util_encode_string(in, ns->full_name) == -1
-	    || camel_file_util_encode_uint32(in, (guint32)ns->sep) == -1)
-		return -1;
+	CamelImapStoreSummary *is = (CamelImapStoreSummary *) s;
 
+	GList *list;
+
+	if (camel_file_util_encode_uint32(in, (guint32) g_list_length (is->namespaces)) == -1)
+		goto serr;
+
+	list = is->namespaces;
+
+	while (list) {
+		CamelImapStoreNamespace *ns = list->data;
+
+		if (camel_file_util_encode_string(in, ns->path) == -1)
+			goto serr;
+
+		if (camel_file_util_encode_string(in, ns->full_name) == -1)
+			goto serr;
+
+		if (camel_file_util_encode_uint32(in, (guint32)ns->sep) == -1)
+			goto serr;
+
+		list = list->next;
+	}
+
 	return 0;
+
+ serr:
+	printf ("Error happened while writing\n");
+	return -1;
+
 }
 
 static int
@@ -511,18 +580,12 @@
 	}
 
 	/* note file format can be expanded to contain more namespaces, but only 1 at the moment */
-	if (camel_file_util_decode_fixed_int32(in, &capabilities) == -1
-	    || camel_file_util_decode_fixed_int32(in, &count) == -1
-	    || count > 1)
+	if (camel_file_util_decode_fixed_int32(in, &capabilities) == -1)
 		return -1;
 
 	is->capabilities = capabilities;
-	if (count == 1) {
-		if ((is->namespace = namespace_load(s, in)) == NULL)
-			return -1;
-	}
 
-	return 0;
+	return namespace_load (s, in);
 }
 
 static int
@@ -531,16 +594,13 @@
 	CamelImapStoreSummary *is = (CamelImapStoreSummary *)s;
 	guint32 count;
 
-	count = is->namespace?1:0;
-
 	/* always write as latest version */
 	if (camel_imap_store_summary_parent->summary_header_save((CamelStoreSummary *)s, out) == -1
 	    || camel_file_util_encode_fixed_int32(out, CAMEL_IMAP_STORE_SUMMARY_VERSION) == -1
-	    || camel_file_util_encode_fixed_int32(out, is->capabilities) == -1
-	    || camel_file_util_encode_fixed_int32(out, count) == -1)
+	    || camel_file_util_encode_fixed_int32(out, is->capabilities) == -1)
 		return -1;
 
-	if (is->namespace && namespace_save(s, out, is->namespace) == -1)
+	if (namespace_save(s, out) == -1)
 		return -1;
 
 	return 0;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]