A new folder-copy implementation



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



Index: libtinymail-camel/tny-camel-folder.c
===================================================================
--- libtinymail-camel/tny-camel-folder.c	(revision 1954)
+++ libtinymail-camel/tny-camel-folder.c	(working copy)
@@ -1512,266 +1512,368 @@
 	return TNY_CAMEL_FOLDER_GET_CLASS (self)->copy_func (self, into, new_name, del, err);
 }
 
-static TnyFolder*
-tny_camel_folder_copy_default (TnyFolder *self, TnyFolderStore *into, const gchar *new_name, gboolean del, GError **err)
+typedef struct {
+	GList *rems;
+	GList *adds;
+	TnyFolder *created;
+} CpyRecRet;
+
+typedef struct {
+	TnyFolderStore *str;
+	TnyFolder *fol;
+} CpyEvent;
+
+static CpyEvent*
+cpy_event_new (TnyFolderStore *str, TnyFolder *fol)
 {
-	TnyCamelFolderPriv *priv = TNY_CAMEL_FOLDER_GET_PRIVATE (self);
-	guint32 flags = CAMEL_STORE_FOLDER_INFO_FAST | 
-		CAMEL_STORE_FOLDER_INFO_RECURSIVE | CAMEL_STORE_FOLDER_INFO_SUBSCRIBED;
-	GList *pending = NULL, *deleting = NULL, *l; GString *fromname=NULL, *toname=NULL;
-	CamelFolderInfo *fi; const char *tmp; int fromlen;
-	CamelException ex = CAMEL_EXCEPTION_INITIALISER;
-	CamelStore *fromstore; const gchar *frombase;
-	CamelStore *tostore; const gchar *tobase;
-	GStaticRecMutex *tolock=NULL, *fromlock=NULL;
+	CpyEvent *e = g_slice_new (CpyEvent);
+	e->str = (TnyFolderStore *) g_object_ref (str);
+	e->fol = (TnyFolder *) g_object_ref (fol);
+	return e;
+}
+
+static void
+cpy_event_free (CpyEvent *e)
+{
+	g_object_unref (e->str);
+	g_object_unref (e->fol);
+	g_slice_free (CpyEvent, e);
+}
+
+static CpyRecRet*
+recurse_copy (TnyFolder *folder, TnyFolderStore *into, const gchar *new_name, gboolean del, GError **err, GList *rems, GList *adds)
+{
+	CpyRecRet *cpyr = g_slice_new0 (CpyRecRet);
+
 	TnyFolder *retval = NULL;
-	TnyCamelFolderPriv *fpriv;
-	CamelFolderInfo *iter;
-	gchar *final_name;
-	TnyFolderStoreChange *change;
-	TnyFolderStore *old_parent;
+	TnyStoreAccount *acc_to, *acc_from;
+	TnyCamelFolderPriv *fpriv = TNY_CAMEL_FOLDER_GET_PRIVATE (folder);
+	TnyCamelFolderPriv *tpriv = TNY_CAMEL_FOLDER_GET_PRIVATE (into);
+	TnyList *headers;
 
-	if (!_tny_session_check_operation (TNY_FOLDER_PRIV_GET_SESSION(priv), err, 
-			TNY_FOLDER_ERROR, TNY_FOLDER_ERROR_COPY))
-		return NULL;
+	GError *nerr = NULL;
 
-	g_assert (TNY_IS_CAMEL_FOLDER (into) || TNY_IS_CAMEL_STORE_ACCOUNT (into));
-	g_assert (new_name != NULL && strlen (new_name) > 0);
+	g_static_rec_mutex_lock (fpriv->folder_lock);
+	g_static_rec_mutex_lock (tpriv->folder_lock);
 
-	fromstore = priv->store;
-	camel_object_ref (CAMEL_OBJECT (fromstore));
-	frombase = priv->folder_name;
-	fromlock = priv->folder_lock;
+	load_folder_no_lock (fpriv);
+	load_folder_no_lock (tpriv);
 
-	g_assert (frombase != NULL && strlen (frombase) > 0);
+	retval = tny_folder_store_create_folder (into, new_name, &nerr);
+	if (nerr != NULL) {
+		if (retval)
+			g_object_unref (retval);
+		goto exception;
+	}
 
-	if (TNY_IS_CAMEL_FOLDER (into))
-	{
-		TnyCamelFolderPriv *topriv = TNY_CAMEL_FOLDER_GET_PRIVATE (into);
-		tostore = topriv->store;
-		camel_object_ref (CAMEL_OBJECT (tostore));
-		tobase = topriv->folder_name;
-		tolock = topriv->folder_lock;
+	adds = g_list_append (adds, cpy_event_new (TNY_FOLDER_STORE (into), retval));
 
-	} else 
+	if (TNY_IS_FOLDER_STORE (folder))
 	{
-		TnyCamelAccountPriv *apriv = TNY_CAMEL_ACCOUNT_GET_PRIVATE (into);
+		TnyList *folders = tny_simple_list_new ();
+		TnyIterator *iter;
 
-		tobase = "/";
-		tostore = camel_session_get_store ((CamelSession*) apriv->session, 
-			apriv->url_string, &ex);
+		tny_folder_store_get_folders (TNY_FOLDER_STORE (folder), folders, NULL, &nerr);
 
-		/* TODO: a tolock */
+		if (nerr != NULL)
+		{
+			g_object_unref (folders);
+			g_object_unref (retval);
+			goto exception;
+		}
 
-		if (camel_exception_is_set (&ex))
+		iter = tny_list_create_iterator (folders);
+		while (!tny_iterator_is_done (iter))
 		{
-			g_set_error (err, TNY_FOLDER_ERROR, 
-				TNY_FOLDER_ERROR_COPY,
-				camel_exception_get_description (&ex));
-			camel_exception_clear (&ex);
+			TnyFolder *cur = TNY_FOLDER (tny_iterator_get_current (iter));
+			TnyFolder *mnew;
 
-			if (tostore && CAMEL_IS_OBJECT (tostore))
-				camel_object_unref (CAMEL_OBJECT (tostore));
-			_tny_session_stop_operation (TNY_FOLDER_PRIV_GET_SESSION (priv));
-			return NULL;
+			CpyRecRet *rt = recurse_copy (cur, TNY_FOLDER_STORE (retval), 
+				tny_folder_get_name (cur), del, &nerr, rems, adds);
+
+			mnew = rt->created;
+			rems = rt->rems;
+			adds = rt->adds;
+
+			g_slice_free (CpyRecRet, rt);
+
+			if (nerr != NULL)
+			{
+				if (mnew) g_object_unref (mnew);
+				g_object_unref (cur);
+				g_object_unref (iter);
+				g_object_unref (folders);
+				g_object_unref (retval);
+				goto exception;
+			}
+
+			g_object_unref (mnew);
+			g_object_unref (cur);
+			tny_iterator_next (iter);
 		}
+		g_object_unref (iter);
+		g_object_unref (folders);
 	}
 
-	g_assert (tobase != NULL && strlen (tobase) > 0);
+	acc_from = TNY_STORE_ACCOUNT (tny_folder_get_account (folder));
+	rems = g_list_append (rems, cpy_event_new (TNY_FOLDER_STORE (acc_from), folder));
+	g_object_unref (acc_from);
 
-	g_static_rec_mutex_lock (fromlock);
-	if (tolock)
-		g_static_rec_mutex_lock (tolock);
+	headers = tny_simple_list_new ();
+	tny_folder_get_headers (folder, headers, TRUE, &nerr);
+	if (nerr != NULL) {
+		g_object_unref (headers);
+		g_object_unref (retval);
+		retval = NULL;
+		goto exception;
+	}
 
-	if (!(fi = camel_store_get_folder_info (fromstore, frombase, flags, &ex)))
+printf ("Transfer %s to %s\n", tny_folder_get_name (folder), tny_folder_get_name (retval));
+
+	tny_folder_transfer_msgs (folder, headers, retval, del, &nerr);
+
+	if (nerr != NULL) {
+		g_object_unref (headers);
+		g_object_unref (retval);
+		retval = NULL;
 		goto exception;
-	
-	pending = g_list_append (pending, fi);
-	
-	toname = g_string_new ("");
-	fromname = g_string_new ("");
-	
-	tmp = strrchr (frombase, '/');
-	if (tmp == NULL)
-		fromlen = 0;
+	}
+
+	acc_to = TNY_STORE_ACCOUNT (tny_folder_get_account (retval));
+	if (tny_folder_is_subscribed (folder))
+		tny_store_account_subscribe (acc_to, retval);
+	g_object_unref (acc_to);
+
+
+exception:
+
+	if (nerr != NULL)
+		g_propagate_error (err, nerr);
+
+	g_static_rec_mutex_unlock (tpriv->folder_lock);
+	g_static_rec_mutex_unlock (fpriv->folder_lock);
+
+	cpyr->created = retval;
+	cpyr->adds = adds;
+	cpyr->rems = rems;
+
+	return cpyr;
+}
+
+typedef GList * (*lstmodfunc) (GList *list, gpointer data);
+
+static GList*
+recurse_evt (TnyFolder *folder, TnyFolderStore *into, GList *list, lstmodfunc func, gboolean rem)
+{
+	TnyList *folders = tny_simple_list_new ();
+	TnyIterator *iter;
+	TnyStoreAccount *acc;
+
+	acc = TNY_STORE_ACCOUNT (tny_folder_get_account (folder));
+
+	if (rem)
+		tny_store_account_unsubscribe (acc, folder);
 	else
-		fromlen = tmp - frombase + 1;
-	
-	while (pending) 
 	{
-		CamelFolderInfo *info = pending->data;
-		
-		pending = g_list_remove_link (pending, pending);
-		while (info) 
-		{
-			CamelFolder *fromfolder, *tofolder;
-			GPtrArray *uids;
-			int deleted = 0;
-			
-			if (info->child)
-				pending = g_list_append (pending, info->child);
-			
-			if (tobase[0])
-				g_string_printf (toname, "%s/%s", tobase, info->full_name + fromlen);
-			else
-				g_string_printf (toname, "%s", info->full_name + fromlen);
-			
-			if ((info->flags & CAMEL_FOLDER_NOSELECT) == 0) 
-			{
-				if (tostore == fromstore && del) {
-					camel_store_rename_folder (fromstore, info->full_name, toname->str, &ex);
-					if (camel_exception_is_set (&ex))
-						goto exception;
-					
-					if (camel_store_supports_subscriptions (fromstore))
-						camel_store_unsubscribe_folder (fromstore, info->full_name, NULL);
-					
-					deleted = 1;
-				} else {
-					if (!(fromfolder = camel_store_get_folder (fromstore, info->full_name, 0, &ex)))
-						goto exception;
-					
-					if (!(tofolder = camel_store_get_folder (tostore, toname->str, CAMEL_STORE_FOLDER_CREATE, &ex))) {
-						camel_object_unref (fromfolder);
-						goto exception;
-					}
-					
-					uids = camel_folder_get_uids (fromfolder);
-					camel_folder_transfer_messages_to (fromfolder, uids, tofolder, NULL, del, &ex);
-					camel_folder_free_uids (fromfolder, uids);
-					
-					if (del)
-						camel_folder_sync(fromfolder, TRUE, NULL);
-					
-					camel_object_unref (fromfolder);
-					camel_object_unref (tofolder);
-				}
-			}
-			
-			if (camel_exception_is_set (&ex))
-				goto exception;
-			else if (del && !deleted)
-				deleting = g_list_prepend (deleting, info);
-			
-			if (camel_store_supports_subscriptions (tostore)
-				&& !camel_store_folder_subscribed (tostore, toname->str))
-				camel_store_subscribe_folder (tostore, toname->str, NULL);
-			
-			info = info->next;
-		}
+		if (tny_folder_is_subscribed (folder))
+			tny_store_account_subscribe (acc, folder);
 	}
 
-	l = deleting;
-	while (l) 
+	g_object_unref (acc);
+
+	list = func (list, cpy_event_new (TNY_FOLDER_STORE (into), folder));
+
+
+	tny_folder_store_get_folders (TNY_FOLDER_STORE (folder), folders, NULL, NULL);
+
+	iter = tny_list_create_iterator (folders);
+	while (!tny_iterator_is_done (iter))
 	{
-		CamelFolderInfo *info = l->data;
-		
-		if (camel_store_supports_subscriptions (fromstore))
-			camel_store_unsubscribe_folder (fromstore, info->full_name, NULL);
-		
-		camel_store_delete_folder (fromstore, info->full_name, NULL);
-		l = l->next;
+		TnyFolder *cur = TNY_FOLDER (tny_iterator_get_current (iter));
+
+		recurse_evt (cur, TNY_FOLDER_STORE (folder), list, func, rem);
+
+		g_object_unref (cur);
+		tny_iterator_next (iter);
 	}
+	g_object_unref (iter);
+	g_object_unref (folders);
 
-	final_name = g_strdup_printf ("%s/%s", tobase, new_name);
-	iter = camel_store_get_folder_info (tostore, final_name, 
-			CAMEL_STORE_FOLDER_INFO_FAST|CAMEL_STORE_FOLDER_INFO_NO_VIRTUAL,&ex);
-	g_free (final_name);
+	return list;
+}
 
-	if (camel_exception_is_set (&ex))
+
+static void
+notify_folder_store_observers_about_for_store_acc (TnyFolderStore *self, TnyFolderStoreChange *change)
+{
+	TnyCamelStoreAccountPriv *priv = TNY_CAMEL_STORE_ACCOUNT_GET_PRIVATE (self);
+	TnyIterator *iter;
+
+	if (!priv->sobservers)
+		return;
+
+	iter = tny_list_create_iterator (priv->sobservers);
+	while (!tny_iterator_is_done (iter))
 	{
-		if (iter && CAMEL_IS_STORE (tostore))
-			camel_store_free_folder_info (tostore, iter);
-
-		goto exception;
+		TnyFolderStoreObserver *observer = TNY_FOLDER_STORE_OBSERVER (tny_iterator_get_current (iter));
+		tny_folder_store_observer_update (observer, change);
+		g_object_unref (G_OBJECT (observer));
+		tny_iterator_next (iter);
 	}
+	g_object_unref (G_OBJECT (iter));
+}
 
-	old_parent = tny_folder_get_folder_store (self);
+static void
+notify_folder_observers_about_copy (GList *adds, GList *rems, gboolean del)
+{
+	while (rems)
+	{
+		CpyEvent *evt = rems->data;
 
-	if (tostore == fromstore && del) {
-		retval = self;
 
-		/* No need to notify the folder if there was not an
-		 * actual change in the short (visual) name */
+		if (del) {
+			TnyFolderStoreChange *change = tny_folder_store_change_new (evt->str);
+			tny_folder_store_change_add_removed_folder (change, evt->fol);
 
-		if (strcmp (tny_folder_get_name (self), new_name)) {
-			TnyFolderChange *change;
-			
-			change = tny_folder_change_new (self);
-			tny_folder_change_set_rename (change, new_name);
-			notify_folder_observers_about (self, change);
+			if (TNY_IS_CAMEL_STORE_ACCOUNT (evt->str))
+				notify_folder_store_observers_about_for_store_acc (evt->str, change);
+			else
+				notify_folder_store_observers_about (evt->str, change);
+
 			g_object_unref (G_OBJECT (change));
 		}
-	} else {
-		retval = _tny_camel_folder_new ();
-		
-		fpriv = TNY_CAMEL_FOLDER_GET_PRIVATE (retval);
-		camel_object_ref (CAMEL_OBJECT (tostore));
-		fpriv->store = tostore;
+
+		g_print ("R: %s\n", 
+			tny_folder_get_name (evt->fol));
+
+		cpy_event_free (evt);
+		rems = g_list_next (rems);
 	}
 
-	/* Notify the deletion before the addition because otherwise
-	 * we could delete the recently created folder instead of the
-	 * old one. */
+	g_list_free (rems);
 
-	if (del) {
-		TnyFolderStoreChange *change = tny_folder_store_change_new (old_parent);
-		tny_folder_store_change_add_removed_folder (change, self);
-		notify_folder_store_observers_about (old_parent, change);
+	while (adds)
+	{
+		TnyFolderStoreChange *change;
+		CpyEvent *evt = adds->data;
+
+		change = tny_folder_store_change_new (evt->str);
+		tny_folder_store_change_add_created_folder (change, evt->fol);
+
+		if (TNY_IS_CAMEL_STORE_ACCOUNT (evt->str))
+			notify_folder_store_observers_about_for_store_acc (evt->str, change);
+		else
+			notify_folder_store_observers_about (evt->str, change);
+
 		g_object_unref (G_OBJECT (change));
+
+		g_print ("A: %s\n", 
+			tny_folder_get_name (evt->fol));
+
+		cpy_event_free (evt);
+		adds = g_list_next (adds);
 	}
 
-	_tny_camel_folder_set_folder_info (into, TNY_CAMEL_FOLDER (retval), iter);
+	g_list_free (adds);
+}
 
-	/* Notify addition */
-	change = tny_folder_store_change_new (into);
-	tny_folder_store_change_add_created_folder (change, retval);
-	notify_folder_store_observers_about (into, change);
-	g_object_unref (G_OBJECT (change));
+static TnyFolder*
+tny_camel_folder_copy_default (TnyFolder *self, TnyFolderStore *into, const gchar *new_name, gboolean del, GError **err)
+{
+	TnyCamelFolderPriv *priv = TNY_CAMEL_FOLDER_GET_PRIVATE (self);
+	TnyFolder *retval;
+	gboolean succeeded = FALSE;
+	TnyAccount *a, *b;
+	GError *nerr = NULL;
 
-	g_object_unref (G_OBJECT (old_parent));
-	camel_object_unref (CAMEL_OBJECT (tostore));
-	camel_object_unref (CAMEL_OBJECT (fromstore));
+	GList *rems=NULL, *adds=NULL;
 
-	goto noexception;
+	if (!_tny_session_check_operation (TNY_FOLDER_PRIV_GET_SESSION(priv), err, 
+			TNY_FOLDER_ERROR, TNY_FOLDER_ERROR_COPY))
+		return NULL;
 
-exception:
-	if (camel_exception_is_set (&ex))
+	g_static_rec_mutex_lock (priv->folder_lock);
+
+	if (TNY_IS_CAMEL_FOLDER (into) || TNY_IS_CAMEL_STORE_ACCOUNT (into))
 	{
-		g_set_error (err, TNY_FOLDER_ERROR, 
-			TNY_FOLDER_ERROR_COPY,
-			camel_exception_get_description (&ex));
-		camel_exception_clear (&ex);
+		a = tny_folder_get_account (self);
+	
+		if (TNY_IS_FOLDER (into))
+			b = tny_folder_get_account (TNY_FOLDER (into));
+		else
+			b = g_object_ref (into);
 
-		if (fromstore && CAMEL_IS_OBJECT (fromstore))
-			camel_object_unref (CAMEL_OBJECT (fromstore));
+		if (del && (a == b))
+		{
+			TnyCamelFolderPriv *rpriv;
+			TnyCamelFolderPriv *tpriv = TNY_CAMEL_FOLDER_GET_PRIVATE (into);
+			TnyCamelAccountPriv *apriv = TNY_CAMEL_ACCOUNT_GET_PRIVATE (a);
+			CamelException ex = CAMEL_EXCEPTION_INITIALISER;
+			gchar *from, *to;
 
-		if (tostore && CAMEL_IS_OBJECT (tostore))
-			camel_object_unref (CAMEL_OBJECT (tostore));
+			load_folder_no_lock (priv);
+			load_folder_no_lock (tpriv);
+
+			from = priv->folder_name;
+
+			if (TNY_IS_CAMEL_STORE_ACCOUNT (into))
+				to = g_strdup (new_name);
+			else
+				to = g_strdup_printf ("%s/%s", tpriv->folder_name, new_name);
+
+printf ("Rename %s to %s\n", from, to);
+
+			camel_store_rename_folder (CAMEL_STORE (apriv->service), from, to, &ex);
+
+			if (!camel_exception_is_set (&ex))
+			{
+				rems = recurse_evt (self, TNY_FOLDER_STORE (a),
+					rems, g_list_prepend, TRUE);
+
+				adds = recurse_evt (self, TNY_FOLDER_STORE (into), 
+					adds, g_list_append, FALSE);
+
+				retval = g_object_ref (self);
+				rpriv = TNY_CAMEL_FOLDER_GET_PRIVATE (retval);
+				g_free (rpriv->folder_name);
+				rpriv->folder_name = g_strdup (to);
+				succeeded = TRUE;
+			}
+			g_free (to);
+		}
+		g_object_unref (a);
+		g_object_unref (b);
 	}
 
-noexception:
+	if (!succeeded)
+	{
+		CpyRecRet *cpyr = recurse_copy (self, into, new_name, del, &nerr, adds, rems);
+		retval = cpyr->created;
+		adds = cpyr->adds;
+		rems = cpyr->rems;
+		g_slice_free (CpyRecRet, cpyr);
+	}
 
-	camel_store_free_folder_info (fromstore, fi);
-	g_list_free (deleting);
+	if (nerr != NULL)
+		g_propagate_error (err, nerr);
+	else
+		notify_folder_observers_about_copy (adds, rems, del);
 
-	if (toname)
-		g_string_free (toname, TRUE);
-	if (fromname)
-		g_string_free (fromname, TRUE);
+	g_static_rec_mutex_unlock (priv->folder_lock);
 
-	if (tolock)
-		g_static_rec_mutex_unlock (tolock);
-	g_static_rec_mutex_unlock (fromlock);
-
 	_tny_session_stop_operation (TNY_FOLDER_PRIV_GET_SESSION (priv));
 
 	return retval;
 }
 
+
+
+
+
 typedef struct 
 {
 	TnyFolder *self;
+	TnyFolderStore *from;
 	TnyFolderStore *into;
 	gchar *new_name;
 	gboolean delete_originals;
@@ -1780,21 +1882,86 @@
 	guint depth;
 	TnyCopyFolderCallback callback;
 	TnyStatusCallback status_callback;
+	TnyFolder *new_folder;
 	TnySessionCamel *session;
 	TnyIdleStopper *stopper;
 	gboolean cancelled;
 } CopyFolderInfo;
 
 
+static void 
+inform_observers_about_folder_copy (TnyFolder *self, TnyFolderStore *from, TnyFolderStore *to, gboolean del_orig, const gchar *new_name, TnyFolder *new_folder)
+{
+	TnyFolderStoreChange *tochange = tny_folder_store_change_new (to);
+	TnyFolderStoreChange *fromchange = tny_folder_store_change_new (from);
+	TnyFolderChange *origchange = tny_folder_change_new (self);
+/* 	TnyList *folders = tny_simple_list_new (); */
+/* 	TnyIterator *iter; */
+	
+	/* Notify change name (if neccesary) */
+	if (to == from && del_orig) {
+		if (strcmp (tny_folder_get_name (self), new_name)) {		
+			tny_folder_change_set_rename (origchange, new_name);
+			notify_folder_observers_about (self, origchange);
+		}
+	}
+		
+	/* Notify deletion  (if neccesary) */
+	if (del_orig) {
+		tny_folder_store_change_add_removed_folder (fromchange, self);
+		notify_folder_store_observers_about (from, fromchange);
+	}
+
+	/* Notify addition */
+	tny_folder_store_change_add_created_folder (tochange, new_folder);
+	notify_folder_store_observers_about (to, tochange);
+	
+	/* Notify subfolders addition */
+/* 	tny_folder_store_get_folders (TNY_FOLDER_STORE(self), folders, NULL, NULL); */
+/* 	iter = tny_list_create_iterator (folders); */
+/* 	while (!tny_iterator_is_done (iter)) { */
+		
+/* 		TnyFolder *folder = (TnyFolder*) tny_iterator_get_current (iter); */
+/* 		TnyFolderStoreChange *change = tny_folder_store_change_new (TNY_FOLDER_STORE(self)); */
+/* 		tny_folder_store_change_add_created_folder (change, folder); */
+/* 		notify_folder_store_observers_about (TNY_FOLDER_STORE(self), change); */
+
+/* 		tny_iterator_next (iter); */
+
+/*  		g_object_unref (G_OBJECT (folder)); */
+/* 		g_object_unref (G_OBJECT (change)); */
+/* 	} */
+	
+	/* Free */
+/* 	g_object_unref (G_OBJECT (iter)); */
+/* 	g_object_unref (G_OBJECT (folders)); */
+	g_object_unref (G_OBJECT (tochange));
+	g_object_unref (G_OBJECT (fromchange));
+	g_object_unref (G_OBJECT (origchange));
+}
+
 static void
 tny_camel_folder_copy_async_destroyer (gpointer thr_user_data)
 {
 	CopyFolderInfo *info = (CopyFolderInfo *) thr_user_data;
 	TnyCamelFolderPriv *priv = TNY_CAMEL_FOLDER_GET_PRIVATE (info->self);
+	TnyCamelFolderPriv *priv_from = TNY_CAMEL_FOLDER_GET_PRIVATE (info->from);
+	TnyCamelFolderPriv *priv_to = TNY_CAMEL_FOLDER_GET_PRIVATE (info->into);
 
+	inform_observers_about_folder_copy (info->self,
+					    info->from, 
+					    info->into, 
+					    info->delete_originals, 
+					    info->new_name,
+					    info->new_folder);
+	
 	/* thread reference */
 	_tny_camel_folder_unreason (priv);
 	g_object_unref (G_OBJECT (info->self));
+	_tny_camel_folder_unreason (priv_to);
+	g_object_unref (G_OBJECT (info->into));
+	_tny_camel_folder_unreason (priv_from);
+	g_object_unref (G_OBJECT (info->from));
 
 	if (info->err)
 		g_error_free (info->err);
@@ -1853,13 +2020,28 @@
 {
 	CopyFolderInfo *info = thr_user_data;
 	TnyFolder *self = info->self;
+	TnyFolder *new_folder = NULL;
+	TnyFolderStore *into = info->into;
+	TnyFolderStore *from = info->from;
 	TnyCamelFolderPriv *priv = TNY_CAMEL_FOLDER_GET_PRIVATE (self);
+	TnyCamelFolderPriv *priv_dst = TNY_CAMEL_FOLDER_GET_PRIVATE (into);
+	TnyCamelFolderPriv *priv_from = TNY_CAMEL_FOLDER_GET_PRIVATE (from);
 	TnyCamelAccountPriv *apriv = TNY_CAMEL_ACCOUNT_GET_PRIVATE (priv->account);
 	CamelException ex = CAMEL_EXCEPTION_INITIALISER;
 	GError *err = NULL;
 
 	g_static_rec_mutex_lock (priv->folder_lock);
 
+	/* Load oldparent foler */
+	if (!load_folder_no_lock (priv_from))
+	{
+		tny_camel_folder_copy_async_destroyer (info);
+		g_static_rec_mutex_unlock (priv->folder_lock);
+		g_thread_exit (NULL);
+		return NULL;
+	}
+
+	/* Load directory to move */
 	if (!load_folder_no_lock (priv))
 	{
 		tny_camel_folder_copy_async_destroyer (info);
@@ -1868,6 +2050,15 @@
 		return NULL;
 	}
 
+	/* Load new_parent foler */
+	if (!load_folder_no_lock (priv_dst))
+	{
+		tny_camel_folder_copy_async_destroyer (info);
+		g_static_rec_mutex_unlock (priv->folder_lock);
+		g_thread_exit (NULL);
+		return NULL;
+	}
+
 	info->cancelled = FALSE;
 
 	/* start camel operations */
@@ -1876,17 +2067,16 @@
 		"Fetching summary information for new messages in folder");
 
 	/* Do work */
-	tny_camel_folder_copy (self, info->into, info->new_name, info->delete_originals, &info->err);
+	new_folder = tny_camel_folder_copy (self, info->into, info->new_name, info->delete_originals, &info->err);
 
-	/* Check cancellation and fill data */
+	/* Check cancelation and stop operation */
 	info->cancelled = camel_operation_cancel_check (apriv->cancel);
-	priv->cached_length = camel_folder_get_message_count (priv->folder);
+	_tny_camel_account_stop_camel_operation (TNY_CAMEL_ACCOUNT (priv->account));
 
-	if (G_LIKELY (priv->folder) && CAMEL_IS_FOLDER (priv->folder) && G_LIKELY (priv->has_summary_cap))
-		priv->unread_length = (guint)camel_folder_get_unread_message_count (priv->folder);
+	/* Get data */
+	info->new_folder = new_folder;
 
 	/* Stop operation and check errors */
-	_tny_camel_account_stop_camel_operation (TNY_CAMEL_ACCOUNT (priv->account));
 	info->err = NULL;
 	if (camel_exception_is_set (&ex))
 	{
@@ -1915,6 +2105,10 @@
 	} else { /* Thread reference */
 		g_object_unref (G_OBJECT (self));
 		_tny_camel_folder_unreason (priv);
+		g_object_unref (G_OBJECT (into));
+		_tny_camel_folder_unreason (priv_dst);
+		g_object_unref (G_OBJECT (from));
+		_tny_camel_folder_unreason (priv_from);
 	}
 	g_thread_exit (NULL);
 
@@ -1934,7 +2128,10 @@
 	CopyFolderInfo *info = NULL;
 	GThread *thread = NULL;
 	GError *err = NULL;
+	TnyFolderStore *from = NULL;
 	TnyCamelFolderPriv *priv = TNY_CAMEL_FOLDER_GET_PRIVATE (self);
+	TnyCamelFolderPriv *priv_to = TNY_CAMEL_FOLDER_GET_PRIVATE (into);
+	TnyCamelFolderPriv *priv_from = NULL;
 
 	if (!_tny_session_check_operation (TNY_FOLDER_PRIV_GET_SESSION(priv), &err, 
 			TNY_FOLDER_ERROR, TNY_FOLDER_ERROR_REFRESH))
@@ -1945,9 +2142,12 @@
 		return;
 	}
 
+	from = tny_folder_get_folder_store (self);
+	priv_from = TNY_CAMEL_FOLDER_GET_PRIVATE (from);
+
 	/* Idle info for the status callback: */
-
 	info = g_slice_new (CopyFolderInfo);
+	info->from = from;
 	info->into = into;
 	info->new_name = g_strdup(new_name);
 	info->delete_originals = del;
@@ -1966,8 +2166,11 @@
 	info->stopper = tny_idle_stopper_new();
 
 	/* thread reference */
-	g_object_ref (G_OBJECT (self));
+	g_object_ref (G_OBJECT (info->self));
 	_tny_camel_folder_reason (priv);
+	g_object_ref (G_OBJECT (info->into));
+	_tny_camel_folder_reason (priv_to);
+	_tny_camel_folder_reason (priv_from);
 
 	/* This will cause the idle status callback to be called,
 	 * via _tny_camel_account_start_camel_operation,
@@ -2000,6 +2203,7 @@
 	gboolean cancelled;
 } TransferMsgsInfo;
 
+
 static void 
 inform_observers_about_transfer (TnyFolder *from, TnyFolder *to, gboolean del_orig, TnyList *headers, gint from_all, gint to_all, gint from_unread, gint to_unread)
 {
Index: libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-store.c
===================================================================
--- libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-store.c	(revision 1954)
+++ libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-store.c	(working copy)
@@ -2594,12 +2594,73 @@
 	}
 }
 
+static int
+make_path (char *path, int nmode, int parent_mode)
+{
+  int oumask;
+  struct stat sb;
+  char *p, *npath;
+
+  if (stat (path, &sb) == 0)
+    {
+      if (S_ISDIR (sb.st_mode) == 0)
+	  return 1;
+      if (chmod (path, nmode))
+          return 1;
+      return 0;
+    }
+
+  oumask = umask (0);
+  npath = g_strdup (path);	/* So we can write to it. */
+    
+  /* Check whether or not we need to do anything with intermediate dirs. */
+
+  /* Skip leading slashes. */
+  p = npath;
+  while (*p == '/')
+    p++;
+
+  while (p = strchr (p, '/'))
+    {
+      *p = '\0';
+      if (stat (npath, &sb) != 0)
+	{
+	  if (mkdir (npath, parent_mode))
+	    {
+	      free (npath);
+	      return 1;
+	    }
+	}
+      else if (S_ISDIR (sb.st_mode) == 0)
+        {
+          free (npath);
+          return 1;
+        }
+
+      *p++ = '/';	/* restore slash */
+      while (*p == '/')
+	p++;
+    }
+
+  /* Create the final directory component. */
+  if (stat (npath, &sb) && mkdir (npath, nmode))
+    {
+      free (npath);
+      return 1;
+    }
+
+  free (npath);
+  return 0;
+}
+
+
 static void
 rename_folder (CamelStore *store, const char *old_name, const char *new_name_in, CamelException *ex)
 {
 	CamelImapStore *imap_store = CAMEL_IMAP_STORE (store);
 	CamelImapResponse *response;
 	char *oldpath, *newpath, *storage_path;
+	char *tpath, *lslash;
 
 	CAMEL_SERVICE_REC_LOCK (imap_store, connect_lock);
 
@@ -2644,6 +2705,15 @@
 	g_free(storage_path);
 
 	/* So do we care if this didn't work?  Its just a cache? */
+	tpath = g_strdup (newpath);
+	/* TNY TODO: Win32 portage needed */
+	lslash = strrchr (tpath, '/');
+	if (lslash) {
+		lslash = '\0';
+		make_path (tpath, S_IRWXU, S_IRWXU);
+	}
+	g_free (tpath);
+
 	if (g_rename (oldpath, newpath) == -1) {
 		g_warning ("Could not rename message cache '%s' to '%s': %s: cache reset",
 			   oldpath, newpath, strerror (errno));


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