[evolution-kolab/ek-wip-porting: 5/8] KolabMailImapClient: require folder type argument for folder creation



commit 01b31ffbff82b3dae9b5c46b33a537f2c35992dc
Author: Christian Hilberg <hilberg kernelconcepts de>
Date:   Fri Aug 31 17:41:24 2012 +0200

    KolabMailImapClient: require folder type argument for folder creation
    
    * since the collection backend needs to be able to create folders
      of all types, regardless of the folder context it is configured
      for, we need to be able to pass in the type of the folder to
      be created
    * this type information will temporarily override the configured
      folder type. The configured folder type will be restored once
      the folder creation operation finishes

 src/libekolab/kolab-mail-imap-client.c |  847 ++++++++++++++++++--------------
 src/libekolab/kolab-mail-imap-client.h |    1 +
 2 files changed, 467 insertions(+), 381 deletions(-)
---
diff --git a/src/libekolab/kolab-mail-imap-client.c b/src/libekolab/kolab-mail-imap-client.c
index 625f603..b8c7801 100644
--- a/src/libekolab/kolab-mail-imap-client.c
+++ b/src/libekolab/kolab-mail-imap-client.c
@@ -685,149 +685,488 @@ mail_imap_client_query_foldernames (KolabMailImapClient *self,
 }
 
 /*----------------------------------------------------------------------------*/
-/* object config/status */
+/* store / delete internals */
 
-gboolean
-kolab_mail_imap_client_configure (KolabMailImapClient *self,
-                                  EBackend *backend,
-                                  KolabSettingsHandler *ksettings,
-                                  KolabMailMimeBuilder *mimebuilder,
-                                  GError **err)
+static gboolean
+mail_imap_client_store (KolabMailImapClient *self,
+                        KolabMailHandle *kmailhandle,
+                        const gchar *foldername,
+                        KolabFolderTypeID foldertype,
+                        gboolean update,
+                        GCancellable *cancellable,
+                        GError **err)
 {
 	KolabMailImapClientPrivate *priv = NULL;
-	/* const gchar *tmp_str = NULL; */
-	const gchar *data_dir = NULL;
-	const gchar *cache_dir = NULL;
+	KolabMailMimeBuilderHeaderInfo *headerinfo = NULL;
+	KolabMailSummary *summary = NULL;
+	const Kolab_conv_mail *kconvmail = NULL;
+	const gchar *kolab_uid = NULL;
+	const gchar *imap_uid = NULL;
+	const gchar *handle_foldername = NULL;
+	gchar *stored_imap_uid = NULL;
+	gchar *parent_name = NULL;
+	gchar *folder_name = NULL;
+	CamelMimeMessage *new_message = NULL;
+	CamelMimeMessage *orig_message = NULL;
+	CamelMimeMessage *stored_message = NULL;
+	CamelFolder *folder = NULL;
+	CamelFolderInfo *fi = NULL;
 	GError *tmp_err = NULL;
+	gboolean ok = TRUE;
 
 	g_assert (KOLAB_IS_MAIL_IMAP_CLIENT (self));
-	g_assert (E_IS_BACKEND (backend));
-	g_assert (KOLAB_IS_SETTINGS_HANDLER (ksettings));
-	g_assert (KOLAB_IS_MAIL_MIME_BUILDER (mimebuilder));
+	g_assert ((kmailhandle != NULL) || (foldername != NULL));
+	if (kmailhandle != NULL)
+		g_assert (KOLAB_IS_MAIL_HANDLE (kmailhandle));
+	g_assert (foldertype < KOLAB_FOLDER_LAST_TYPE);
 	g_return_val_if_fail (err == NULL || *err == NULL, FALSE);
 
 	priv = KOLAB_MAIL_IMAP_CLIENT_PRIVATE (self);
 
-	g_assert (priv->is_up == FALSE);
-	g_assert (priv->is_online == FALSE);
-
-	if (priv->ksettings != NULL)
-		return TRUE;
-
-	g_object_ref (ksettings); /* unref'd in dispose() */
-	g_object_ref (mimebuilder);
-	priv->ksettings = ksettings;
-	priv->mimebuilder = mimebuilder;
+	g_assert (priv->is_up == TRUE);
 
-	/* we store the context locally, all else we can/should get on-the-fly
-	 * from the settings handler
+	/* TODO
+	 * - check whether we cover all cases
+	 * - check for code dupe with retrieve()
 	 */
-	priv->context = kolab_settings_handler_get_uint_field (priv->ksettings,
-	                                                       KOLAB_SETTINGS_HANDLER_UINT_FIELD_FOLDER_CONTEXT,
-	                                                       &tmp_err);
-	if (tmp_err != NULL) {
-		g_propagate_error (err, tmp_err);
-		return FALSE;
-	}
-	if (priv->context == KOLAB_FOLDER_CONTEXT_INVAL) {
-		g_set_error (err,
-		             KOLAB_BACKEND_ERROR,
-		             KOLAB_BACKEND_ERROR_GENERIC,
-		             _("Internal inconsistency detected: Folder PIM context not set"));
-		return FALSE;
-	}
 
-	/* set up session object directories (create if not existing) */
-	data_dir = \
-		kolab_settings_handler_get_char_field (priv->ksettings,
-		                                       KOLAB_SETTINGS_HANDLER_CHAR_FIELD_CAMEL_DATA_DIR,
-		                                       &tmp_err);
-	if (data_dir == NULL) {
-		g_propagate_error (err, tmp_err);
-		return FALSE;
-	}
-	cache_dir = \
-		kolab_settings_handler_get_char_field (priv->ksettings,
-		                                       KOLAB_SETTINGS_HANDLER_CHAR_FIELD_CAMEL_CACHE_DIR,
-		                                       &tmp_err);
-	if (cache_dir == NULL) {
-		g_propagate_error (err, tmp_err);
-		return FALSE;
-	}
+	/* folder creation */
+	if ((kmailhandle == NULL) && (foldername != NULL)) {
+		KolabFolderTypeID cnf_ftype = KOLAB_FOLDER_TYPE_INVAL;
+		KolabUtilCamelIMAPPath *path = NULL;
+
+		/* Save the originally-configured folder creation type.
+		 * Since folder creation needs to be context-agnostic
+		 * (to be usable in the collection backend for all folder
+		 * types), we need some kind of a temporary override here
+		 * which we undo right after folder creation attempt
+		 */
+		cnf_ftype =  camel_kolab_imapx_store_get_folder_creation_type (priv->store);
+		ok = camel_kolab_imapx_store_set_folder_creation_type (priv->store,
+		                                                       foldertype,
+		                                                       FALSE);
+		if (! ok) {
+			g_set_error (&tmp_err,
+			             KOLAB_BACKEND_ERROR,
+			             KOLAB_BACKEND_ERROR_CAMEL,
+			             _("Internal inconsistency detected: Could not set temporary folder creation type on CamelKolabIMAPXStore"));
+			goto cleanup;
+		}
 
-	/* create session object */
-	priv->session = camel_kolab_session_new (backend, data_dir, cache_dir);
+		/* split foldername into parent_name and folder_name
+		 * (we get full path here)
+		 */
+		path = kolab_util_camel_imap_path_split (foldername, "/"); /* FIXME get delimiter from store */
+		if (path == NULL) {
+			g_warning ("%s()[%u]: KolabUtilCamelIMAPPath instance for path '%s' is NULL. This should never happen.",
+			           __func__, __LINE__, foldername);
+			goto cleanup;
+		}
+		
+		fi = camel_store_create_folder_sync (CAMEL_STORE (priv->store),
+		                                     path->parent_name,
+		                                     path->folder_name,
+		                                     cancellable,
+		                                     &tmp_err);
 
-	/* set to offline state first */
-	camel_session_set_online (CAMEL_SESSION (priv->session), FALSE);
+		kolab_util_camel_imap_path_free (path);
+
+		/* restore previously-configured folder creation type */
+		ok = camel_kolab_imapx_store_set_folder_creation_type (priv->store,
+		                                                       cnf_ftype,
+		                                                       FALSE);
+		if (!ok) {
+			/* should never happen, even with context check */
+			g_warning ("%s()[%u] Internal inconsistency detected: Could not restore original folder creation type on CamelKolabIMAPXStore",
+			           __func__, __LINE__);
+			ok = TRUE;
+		}
+		
+		if (tmp_err != NULL)
+			goto cleanup;
 
-	return TRUE;
-}
+		/* set folder type annotation */
+		
+		goto cleanup;
+	}
 
-static void
-mail_imap_client_configure_store_settings (KolabMailImapClient *self)
-{
-	KolabMailImapClientPrivate *priv = NULL;
-	CamelService *service = NULL;
-	CamelKolabIMAPXSettings *settings;
+	handle_foldername = kolab_mail_handle_get_foldername (kmailhandle);
 
-	g_assert (KOLAB_IS_MAIL_IMAP_CLIENT (self));
+	/* moving to a different folder */
+	if ((handle_foldername != NULL) && (foldername != NULL)) {
+		if (g_strcmp0 (handle_foldername, foldername) != 0) {
+			/* FIXME implement me */
+			g_set_error (&tmp_err,
+			             KOLAB_BACKEND_ERROR,
+			             KOLAB_BACKEND_ERROR_INTERNAL,
+			             _("Moving object to different folder not yet implemented"));
+			goto cleanup;
+		}
+	}
 
-	priv = KOLAB_MAIL_IMAP_CLIENT_PRIVATE (self);
+	/* update the CamelFolder */
+	if (update) {
+		ok = mail_imap_client_update_folder (self,
+		                                     foldername,
+		                                     cancellable,
+		                                     &tmp_err);
+		if (! ok)
+			goto cleanup;
+	}
 
-	service = CAMEL_SERVICE (priv->store);
-	settings = kolab_settings_handler_get_camel_settings (priv->ksettings);
+	/* normal store operation (handle_foldername may be unset) */
+	folder = mail_imap_client_camel_get_folder (self,
+	                                            foldername,
+	                                            cancellable,
+	                                            &tmp_err);
+	if (tmp_err != NULL)
+		goto cleanup;
 
-	/* The CamelKolabIMAPXSettings held by CamelSettingsHandler
-	 * is authoritative, so just plug it into the CamelService. */
-	camel_service_set_settings (service, CAMEL_SETTINGS (settings));
-}
+	if (folder == NULL) {
+		g_set_error (&tmp_err,
+		             KOLAB_BACKEND_ERROR,
+		             KOLAB_BACKEND_ERROR_NOTFOUND,
+		             _("Could not get Camel folder for '%s'"),
+		             foldername);
+		goto cleanup;
+	}
 
-gboolean
-kolab_mail_imap_client_bringup (KolabMailImapClient *self,
-                                GCancellable *cancellable,
-                                GError **err)
-{
-	KolabMailImapClientPrivate *priv = NULL;
-	CamelService *service = NULL;
-	gchar *dbpath = NULL;
-	gchar *account_uid = NULL;
-	GError *tmp_err = NULL;
-	gboolean ok = FALSE;
+	/* try with imap uid first */
+	summary = kolab_mail_handle_get_summary_nonconst (kmailhandle);
+	g_assert (summary != NULL);
+	imap_uid = kolab_mail_summary_get_char_field (summary,
+	                                              KOLAB_MAIL_SUMMARY_CHAR_FIELD_IMAP_UID);
+	kolab_uid = kolab_mail_handle_get_uid (kmailhandle);
 
-	g_assert (KOLAB_IS_MAIL_IMAP_CLIENT (self));
-	/* cancellable may be NULL */
-	g_return_val_if_fail (err == NULL || *err == NULL, FALSE);
+	if (imap_uid != NULL) {
+		orig_message = mail_imap_client_camel_get_msg_imap_uid (self,
+		                                                        foldername,
+		                                                        imap_uid,
+		                                                        kolab_uid,
+		                                                        cancellable,
+		                                                        &tmp_err);
+		if (tmp_err != NULL) {
+			g_warning ("%s: %s", __func__, tmp_err->message);
+			g_error_free (tmp_err);
+			tmp_err = NULL;
+		}
+	}
 
-	priv = KOLAB_MAIL_IMAP_CLIENT_PRIVATE (self);
+	/* if no luck with imap uid, we'll need to search messages for kolab uid */
+	if (orig_message == NULL) {
+		orig_message = mail_imap_client_camel_get_msg_kolab_uid (self,
+		                                                         foldername,
+		                                                         kolab_uid,
+		                                                         cancellable,
+		                                                         &tmp_err);
+		if (tmp_err != NULL) {
+			g_warning ("%s: %s", __func__, tmp_err->message);
+			g_error_free (tmp_err);
+			tmp_err = NULL;
+		}
+	}
 
-	if (priv->is_up == TRUE)
-		return TRUE;
+	/* orig_message may still be NULL (non-existent on server) */
+	kconvmail = kolab_mail_handle_get_kconvmail (kmailhandle);
+	g_assert (kconvmail != NULL); /* must be ok since the handle is complete */
+	new_message = kolab_mail_mime_builder_camel_new_from_conv (priv->mimebuilder,
+	                                                           kconvmail,
+	                                                           cancellable,
+	                                                           &tmp_err);
+	if (new_message == NULL)
+		goto cleanup;
 
-	g_assert (priv->is_online == FALSE);
+	headerinfo = g_new0 (KolabMailMimeBuilderHeaderInfo, 1);
+	headerinfo->kolab_uid = g_strdup (kolab_uid);
+	headerinfo->from_name = g_strdup (KOLAB_IMAP_CLIENT_DUMMY_FROM_NAME);
+	headerinfo->from_addr = g_strdup (KOLAB_IMAP_CLIENT_DUMMY_FROM_ADDR);
+	ok = kolab_mail_mime_builder_camel_set_header (priv->mimebuilder,
+	                                               new_message,
+	                                               headerinfo,
+	                                               orig_message,
+	                                               &tmp_err);
+	g_free (headerinfo->from_addr);
+	g_free (headerinfo->from_name);
+	g_free (headerinfo->kolab_uid);
+	g_free (headerinfo);
+	if (! ok)
+		goto cleanup;
 
-	/* bring up session object */
-	ok = camel_kolab_session_bringup (priv->session,
+	/* append the new message to the imap folder */
+	camel_folder_append_message_sync (folder,
+	                                  new_message,
+	                                  NULL,
+	                                  /* new IMAP UID never reported by IMAPX */ NULL,
 	                                  cancellable,
 	                                  &tmp_err);
-	if (! ok) {
-		g_propagate_error (err, tmp_err);
-		return FALSE;
-	}
 
-	/* create the service uid for the storage path */
-	account_uid = \
-		kolab_util_backend_account_uid_new_from_settings (priv->ksettings,
-		                                                  &tmp_err);
-	if (account_uid == NULL) {
-		g_propagate_error (err, tmp_err);
-		return FALSE;
-	}
+	/* FIXME CamelIMAPX error reporting is not working in all cases
+	 *       - tmp_ex is not set here if the server rejects the message
+	 *         because of NUL bytes, so the original would get lost if we
+	 *         just sync'ed the CamelFolder without further checking
+	 *       - IMAPX currently never reports the IMAP UID of a freshly
+	 *         stored message
+	 */
+	if (tmp_err != NULL)
+		goto cleanup;
 
-	/* register Kolab service (store) with CamelSession */
-	service = camel_session_add_service (CAMEL_SESSION (priv->session),
-	                                     account_uid,
-	                                     KOLAB_CAMEL_PROVIDER_PROTOCOL,
+	/* FIXME need to read-back email from the server right away for several reasons:
+	 *       - presently, it's the only way to be sure that the append operation
+	 *         was really successful (see above FIXME). Might have been fixed in 2.32
+	 *	   and above
+	 *       - if we do not read-back, the mail will not be in the IMAPX store (so
+	 *         that we can use it in offline mode)
+	 *       - IMAPX apparently never returnes a stored_imap_uid, so we need to
+	 *         grovel-search for the Kolab UID (stored in the mail subject) in it's
+	 *         folder either way
+	 *       - camel_folder_sync_message() needs the IMAP UID of a message to be stored
+	 *         in the IMAPX offline store, but the IMAP UID of the freshly stored message
+	 *         is exactly what IMAPX does not provide us with here (see above)
+	 */
+	stored_message = mail_imap_client_camel_get_msg_kolab_uid (self,
+	                                                           foldername,
+	                                                           kolab_uid,
+	                                                           cancellable,
+	                                                           &tmp_err);
+	if (tmp_err != NULL)
+		goto cleanup;
+
+	if (stored_message == NULL) {
+		g_set_error (&tmp_err,
+		             KOLAB_BACKEND_ERROR,
+		             KOLAB_BACKEND_ERROR_CAMEL,
+		             _("Could not read-back mail message from server, UID '%s', Folder '%s'"),
+		             kolab_uid, foldername);
+		goto cleanup;
+	}
+
+	stored_imap_uid = g_strdup (camel_medium_get_header (CAMEL_MEDIUM (stored_message),
+	                                                     KOLAB_IMAP_CLIENT_X_EVO_UID_HEADER));
+	if (stored_imap_uid == NULL) {
+		g_set_error (&tmp_err,
+		             KOLAB_BACKEND_ERROR,
+		             KOLAB_BACKEND_ERROR_INTERNAL,
+		             _("Could not get IMAP UID from message, UID '%s', Folder '%s'"),
+		             kolab_uid, foldername);
+		goto cleanup;
+	}
+
+	camel_medium_set_header (CAMEL_MEDIUM (stored_message),
+	                         KOLAB_IMAP_CLIENT_X_EVO_UID_HEADER,
+	                         NULL);
+
+	/* mark old, existing message as deleted */
+	if (orig_message != NULL) {
+		const gchar *local_imap_uid = NULL;
+		local_imap_uid = camel_medium_get_header (CAMEL_MEDIUM (orig_message),
+		                                          KOLAB_IMAP_CLIENT_X_EVO_UID_HEADER);
+		g_debug ("%s: Kolab UID (%s) Folder (%s) IMAP UID (%s) marking for deletion",
+		         __func__, kolab_uid, foldername, local_imap_uid);
+		if (local_imap_uid != NULL) {
+			camel_folder_delete_message (folder, local_imap_uid);
+			camel_medium_set_header (CAMEL_MEDIUM (orig_message),
+			                         KOLAB_IMAP_CLIENT_X_EVO_UID_HEADER,
+			                         NULL);
+		} else {
+			g_warning ("%s: Kolab UID (%s) Folder (%s) IMAP UID not set on camel message",
+			           __func__, kolab_uid, foldername);
+		}
+	}
+
+	/* update folder */
+	camel_folder_synchronize_sync (folder,
+	                               TRUE,
+	                               cancellable,
+	                               &tmp_err);
+	if (tmp_err != NULL)
+		goto cleanup;
+
+	/* refresh folder info */
+	camel_folder_refresh_info_sync (folder,
+	                                cancellable,
+	                                &tmp_err);
+	if (tmp_err != NULL)
+		goto cleanup;
+
+	kolab_mail_summary_set_char_field (summary,
+	                                   KOLAB_MAIL_SUMMARY_CHAR_FIELD_IMAP_UID,
+	                                   stored_imap_uid);
+	g_debug ("%s: Kolab UID (%s) Folder (%s) IMAP UID (%s) successfully stored",
+	         __func__, kolab_uid, foldername, stored_imap_uid);
+	stored_imap_uid = NULL; /* data now owned by mail summary, do not free() */
+
+	/* drop kconvmail from handle */
+	kolab_mail_handle_drop_kconvmail (kmailhandle);
+
+ cleanup:
+	if (tmp_err != NULL) {
+		ok = FALSE;
+		g_propagate_error (err, tmp_err);
+	}
+	if (orig_message != NULL)
+		g_object_unref (orig_message);
+	if (new_message != NULL)
+		g_object_unref (new_message);
+	if (stored_message != NULL)
+		g_object_unref (stored_message);
+	if (folder != NULL)
+		g_object_unref (folder);
+	if (stored_imap_uid != NULL)
+		g_free (stored_imap_uid);
+	if (parent_name != NULL)
+		g_free (parent_name);
+	if (folder_name != NULL)
+		g_free (folder_name);
+	if (fi != NULL)
+		camel_store_free_folder_info (CAMEL_STORE (priv->store), fi);
+
+	return ok; /* TRUE or FALSE */
+}
+
+/*----------------------------------------------------------------------------*/
+/* object config/status */
+
+gboolean
+kolab_mail_imap_client_configure (KolabMailImapClient *self,
+                                  EBackend *backend,
+                                  KolabSettingsHandler *ksettings,
+                                  KolabMailMimeBuilder *mimebuilder,
+                                  GError **err)
+{
+	KolabMailImapClientPrivate *priv = NULL;
+	/* const gchar *tmp_str = NULL; */
+	const gchar *data_dir = NULL;
+	const gchar *cache_dir = NULL;
+	GError *tmp_err = NULL;
+
+	g_assert (KOLAB_IS_MAIL_IMAP_CLIENT (self));
+	g_assert (E_IS_BACKEND (backend));
+	g_assert (KOLAB_IS_SETTINGS_HANDLER (ksettings));
+	g_assert (KOLAB_IS_MAIL_MIME_BUILDER (mimebuilder));
+	g_return_val_if_fail (err == NULL || *err == NULL, FALSE);
+
+	priv = KOLAB_MAIL_IMAP_CLIENT_PRIVATE (self);
+
+	g_assert (priv->is_up == FALSE);
+	g_assert (priv->is_online == FALSE);
+
+	if (priv->ksettings != NULL)
+		return TRUE;
+
+	g_object_ref (ksettings); /* unref'd in dispose() */
+	g_object_ref (mimebuilder);
+	priv->ksettings = ksettings;
+	priv->mimebuilder = mimebuilder;
+
+	/* we store the context locally, all else we can/should get on-the-fly
+	 * from the settings handler
+	 */
+	priv->context = kolab_settings_handler_get_uint_field (priv->ksettings,
+	                                                       KOLAB_SETTINGS_HANDLER_UINT_FIELD_FOLDER_CONTEXT,
+	                                                       &tmp_err);
+	if (tmp_err != NULL) {
+		g_propagate_error (err, tmp_err);
+		return FALSE;
+	}
+	if (priv->context == KOLAB_FOLDER_CONTEXT_INVAL) {
+		g_set_error (err,
+		             KOLAB_BACKEND_ERROR,
+		             KOLAB_BACKEND_ERROR_GENERIC,
+		             _("Internal inconsistency detected: Folder PIM context not set"));
+		return FALSE;
+	}
+
+	/* set up session object directories (create if not existing) */
+	data_dir = \
+		kolab_settings_handler_get_char_field (priv->ksettings,
+		                                       KOLAB_SETTINGS_HANDLER_CHAR_FIELD_CAMEL_DATA_DIR,
+		                                       &tmp_err);
+	if (data_dir == NULL) {
+		g_propagate_error (err, tmp_err);
+		return FALSE;
+	}
+	cache_dir = \
+		kolab_settings_handler_get_char_field (priv->ksettings,
+		                                       KOLAB_SETTINGS_HANDLER_CHAR_FIELD_CAMEL_CACHE_DIR,
+		                                       &tmp_err);
+	if (cache_dir == NULL) {
+		g_propagate_error (err, tmp_err);
+		return FALSE;
+	}
+
+	/* create session object */
+	priv->session = camel_kolab_session_new (backend, data_dir, cache_dir);
+
+	/* set to offline state first */
+	camel_session_set_online (CAMEL_SESSION (priv->session), FALSE);
+
+	return TRUE;
+}
+
+static void
+mail_imap_client_configure_store_settings (KolabMailImapClient *self)
+{
+	KolabMailImapClientPrivate *priv = NULL;
+	CamelService *service = NULL;
+	CamelKolabIMAPXSettings *settings;
+
+	g_assert (KOLAB_IS_MAIL_IMAP_CLIENT (self));
+
+	priv = KOLAB_MAIL_IMAP_CLIENT_PRIVATE (self);
+
+	service = CAMEL_SERVICE (priv->store);
+	settings = kolab_settings_handler_get_camel_settings (priv->ksettings);
+
+	/* The CamelKolabIMAPXSettings held by CamelSettingsHandler
+	 * is authoritative, so just plug it into the CamelService. */
+	camel_service_set_settings (service, CAMEL_SETTINGS (settings));
+}
+
+gboolean
+kolab_mail_imap_client_bringup (KolabMailImapClient *self,
+                                GCancellable *cancellable,
+                                GError **err)
+{
+	KolabMailImapClientPrivate *priv = NULL;
+	CamelService *service = NULL;
+	gchar *dbpath = NULL;
+	gchar *account_uid = NULL;
+	GError *tmp_err = NULL;
+	gboolean ok = FALSE;
+
+	g_assert (KOLAB_IS_MAIL_IMAP_CLIENT (self));
+	/* cancellable may be NULL */
+	g_return_val_if_fail (err == NULL || *err == NULL, FALSE);
+
+	priv = KOLAB_MAIL_IMAP_CLIENT_PRIVATE (self);
+
+	if (priv->is_up == TRUE)
+		return TRUE;
+
+	g_assert (priv->is_online == FALSE);
+
+	/* bring up session object */
+	ok = camel_kolab_session_bringup (priv->session,
+	                                  cancellable,
+	                                  &tmp_err);
+	if (! ok) {
+		g_propagate_error (err, tmp_err);
+		return FALSE;
+	}
+
+	/* create the service uid for the storage path */
+	account_uid = \
+		kolab_util_backend_account_uid_new_from_settings (priv->ksettings,
+		                                                  &tmp_err);
+	if (account_uid == NULL) {
+		g_propagate_error (err, tmp_err);
+		return FALSE;
+	}
+
+	/* register Kolab service (store) with CamelSession */
+	service = camel_session_add_service (CAMEL_SESSION (priv->session),
+	                                     account_uid,
+	                                     KOLAB_CAMEL_PROVIDER_PROTOCOL,
 	                                     CAMEL_PROVIDER_STORE,
 	                                     &tmp_err);
 	g_free (account_uid);
@@ -1298,6 +1637,7 @@ kolab_mail_imap_client_query_foldernames_anon (gpointer self,
 gboolean
 kolab_mail_imap_client_create_folder (KolabMailImapClient *self,
                                       const gchar *foldername,
+                                      KolabFolderTypeID foldertype,
                                       GCancellable *cancellable,
                                       GError **err)
 {
@@ -1314,12 +1654,13 @@ kolab_mail_imap_client_create_folder (KolabMailImapClient *self,
 
 	g_assert (priv->is_up == TRUE);
 
-	ok = kolab_mail_imap_client_store (self,
-	                                   NULL,
-	                                   foldername,
-	                                   TRUE,
-	                                   cancellable,
-	                                   &tmp_err);
+	ok = mail_imap_client_store (self,
+	                             NULL,
+	                             foldername,
+	                             foldertype,
+	                             TRUE,
+	                             cancellable,
+	                             &tmp_err);
 	if (! ok) {
 		g_propagate_error (err, tmp_err);
 		return FALSE;
@@ -1455,271 +1796,15 @@ kolab_mail_imap_client_store (KolabMailImapClient *self,
                               GCancellable *cancellable,
                               GError **err)
 {
-	KolabMailImapClientPrivate *priv = NULL;
-	KolabMailMimeBuilderHeaderInfo *headerinfo = NULL;
-	KolabMailSummary *summary = NULL;
-	const Kolab_conv_mail *kconvmail = NULL;
-	const gchar *kolab_uid = NULL;
-	const gchar *imap_uid = NULL;
-	const gchar *handle_foldername = NULL;
-	gchar *stored_imap_uid = NULL;
-	CamelMimeMessage *new_message = NULL;
-	CamelMimeMessage *orig_message = NULL;
-	CamelMimeMessage *stored_message = NULL;
-	CamelFolder *folder = NULL;
-	GError *tmp_err = NULL;
-	gboolean ok = TRUE;
-
-	g_assert (KOLAB_IS_MAIL_IMAP_CLIENT (self));
-	g_assert ((kmailhandle != NULL) || (foldername != NULL));
-	if (kmailhandle != NULL)
-		g_assert (KOLAB_IS_MAIL_HANDLE (kmailhandle));
-	g_return_val_if_fail (err == NULL || *err == NULL, FALSE);
-
-	priv = KOLAB_MAIL_IMAP_CLIENT_PRIVATE (self);
-
-	g_assert (priv->is_up == TRUE);
-
-	/* TODO
-	 * - check whether we cover all cases
-	 * - check for code dupe with retrieve()
-	 */
-
-	/* folder creation */
-	if ((kmailhandle == NULL) && (foldername != NULL)) {
-		/* FIXME implement me */
-		g_set_error (&tmp_err,
-		             KOLAB_BACKEND_ERROR,
-		             KOLAB_BACKEND_ERROR_INTERNAL,
-		             _("Folder creation not yet implemented"));
-		goto cleanup;
-	}
-
-	handle_foldername = kolab_mail_handle_get_foldername (kmailhandle);
-
-	/* moving to a different folder */
-	if ((handle_foldername != NULL) && (foldername != NULL)) {
-		if (g_strcmp0 (handle_foldername, foldername) != 0) {
-			/* FIXME implement me */
-			g_set_error (&tmp_err,
-			             KOLAB_BACKEND_ERROR,
-			             KOLAB_BACKEND_ERROR_INTERNAL,
-			             _("Moving object to different folder not yet implemented"));
-			goto cleanup;
-		}
-	}
-
-	/* update the CamelFolder */
-	if (update) {
-		ok = mail_imap_client_update_folder (self,
-		                                     foldername,
-		                                     cancellable,
-		                                     &tmp_err);
-		if (! ok)
-			goto cleanup;
-	}
-
-	/* normal store operation (handle_foldername may be unset) */
-	folder = mail_imap_client_camel_get_folder (self,
-	                                            foldername,
-	                                            cancellable,
-	                                            &tmp_err);
-	if (tmp_err != NULL)
-		goto cleanup;
+	g_return_val_if_fail (KOLAB_IS_MAIL_IMAP_CLIENT (self), FALSE);
 
-	if (folder == NULL) {
-		g_set_error (&tmp_err,
-		             KOLAB_BACKEND_ERROR,
-		             KOLAB_BACKEND_ERROR_NOTFOUND,
-		             _("Could not get Camel folder for '%s'"),
-		             foldername);
-		goto cleanup;
-	}
-
-	/* try with imap uid first */
-	summary = kolab_mail_handle_get_summary_nonconst (kmailhandle);
-	g_assert (summary != NULL);
-	imap_uid = kolab_mail_summary_get_char_field (summary,
-	                                              KOLAB_MAIL_SUMMARY_CHAR_FIELD_IMAP_UID);
-	kolab_uid = kolab_mail_handle_get_uid (kmailhandle);
-
-	if (imap_uid != NULL) {
-		orig_message = mail_imap_client_camel_get_msg_imap_uid (self,
-		                                                        foldername,
-		                                                        imap_uid,
-		                                                        kolab_uid,
-		                                                        cancellable,
-		                                                        &tmp_err);
-		if (tmp_err != NULL) {
-			g_warning ("%s: %s", __func__, tmp_err->message);
-			g_error_free (tmp_err);
-			tmp_err = NULL;
-		}
-	}
-
-	/* if no luck with imap uid, we'll need to search messages for kolab uid */
-	if (orig_message == NULL) {
-		orig_message = mail_imap_client_camel_get_msg_kolab_uid (self,
-		                                                         foldername,
-		                                                         kolab_uid,
-		                                                         cancellable,
-		                                                         &tmp_err);
-		if (tmp_err != NULL) {
-			g_warning ("%s: %s", __func__, tmp_err->message);
-			g_error_free (tmp_err);
-			tmp_err = NULL;
-		}
-	}
-
-	/* orig_message may still be NULL (non-existent on server) */
-	kconvmail = kolab_mail_handle_get_kconvmail (kmailhandle);
-	g_assert (kconvmail != NULL); /* must be ok since the handle is complete */
-	new_message = kolab_mail_mime_builder_camel_new_from_conv (priv->mimebuilder,
-	                                                           kconvmail,
-	                                                           cancellable,
-	                                                           &tmp_err);
-	if (new_message == NULL)
-		goto cleanup;
-
-	headerinfo = g_new0 (KolabMailMimeBuilderHeaderInfo, 1);
-	headerinfo->kolab_uid = g_strdup (kolab_uid);
-	headerinfo->from_name = g_strdup (KOLAB_IMAP_CLIENT_DUMMY_FROM_NAME);
-	headerinfo->from_addr = g_strdup (KOLAB_IMAP_CLIENT_DUMMY_FROM_ADDR);
-	ok = kolab_mail_mime_builder_camel_set_header (priv->mimebuilder,
-	                                               new_message,
-	                                               headerinfo,
-	                                               orig_message,
-	                                               &tmp_err);
-	g_free (headerinfo->from_addr);
-	g_free (headerinfo->from_name);
-	g_free (headerinfo->kolab_uid);
-	g_free (headerinfo);
-	if (! ok)
-		goto cleanup;
-
-	/* append the new message to the imap folder */
-	camel_folder_append_message_sync (folder,
-	                                  new_message,
-	                                  NULL,
-	                                  /* new IMAP UID never reported by IMAPX */ NULL,
-	                                  cancellable,
-	                                  &tmp_err);
-
-	/* FIXME CamelIMAPX error reporting is not working in all cases
-	 *       - tmp_ex is not set here if the server rejects the message
-	 *         because of NUL bytes, so the original would get lost if we
-	 *         just sync'ed the CamelFolder without further checking
-	 *       - IMAPX currently never reports the IMAP UID of a freshly
-	 *         stored message
-	 */
-	if (tmp_err != NULL)
-		goto cleanup;
-
-	/* FIXME need to read-back email from the server right away for several reasons:
-	 *       - presently, it's the only way to be sure that the append operation
-	 *         was really successful (see above FIXME). Might have been fixed in 2.32
-	 *	   and above
-	 *       - if we do not read-back, the mail will not be in the IMAPX store (so
-	 *         that we can use it in offline mode)
-	 *       - IMAPX apparently never returnes a stored_imap_uid, so we need to
-	 *         grovel-search for the Kolab UID (stored in the mail subject) in it's
-	 *         folder either way
-	 *       - camel_folder_sync_message() needs the IMAP UID of a message to be stored
-	 *         in the IMAPX offline store, but the IMAP UID of the freshly stored message
-	 *         is exactly what IMAPX does not provide us with here (see above)
-	 */
-	stored_message = mail_imap_client_camel_get_msg_kolab_uid (self,
-	                                                           foldername,
-	                                                           kolab_uid,
-	                                                           cancellable,
-	                                                           &tmp_err);
-	if (tmp_err != NULL)
-		goto cleanup;
-
-	if (stored_message == NULL) {
-		g_set_error (&tmp_err,
-		             KOLAB_BACKEND_ERROR,
-		             KOLAB_BACKEND_ERROR_CAMEL,
-		             _("Could not read-back mail message from server, UID '%s', Folder '%s'"),
-		             kolab_uid, foldername);
-		goto cleanup;
-	}
-
-	stored_imap_uid = g_strdup (camel_medium_get_header (CAMEL_MEDIUM (stored_message),
-	                                                     KOLAB_IMAP_CLIENT_X_EVO_UID_HEADER));
-	if (stored_imap_uid == NULL) {
-		g_set_error (&tmp_err,
-		             KOLAB_BACKEND_ERROR,
-		             KOLAB_BACKEND_ERROR_INTERNAL,
-		             _("Could not get IMAP UID from message, UID '%s', Folder '%s'"),
-		             kolab_uid, foldername);
-		goto cleanup;
-	}
-
-	camel_medium_set_header (CAMEL_MEDIUM (stored_message),
-	                         KOLAB_IMAP_CLIENT_X_EVO_UID_HEADER,
-	                         NULL);
-
-	/* mark old, existing message as deleted */
-	if (orig_message != NULL) {
-		const gchar *local_imap_uid = NULL;
-		local_imap_uid = camel_medium_get_header (CAMEL_MEDIUM (orig_message),
-		                                          KOLAB_IMAP_CLIENT_X_EVO_UID_HEADER);
-		g_debug ("%s: Kolab UID (%s) Folder (%s) IMAP UID (%s) marking for deletion",
-		         __func__, kolab_uid, foldername, local_imap_uid);
-		if (local_imap_uid != NULL) {
-			camel_folder_delete_message (folder, local_imap_uid);
-			camel_medium_set_header (CAMEL_MEDIUM (orig_message),
-			                         KOLAB_IMAP_CLIENT_X_EVO_UID_HEADER,
-			                         NULL);
-		} else {
-			g_warning ("%s: Kolab UID (%s) Folder (%s) IMAP UID not set on camel message",
-			           __func__, kolab_uid, foldername);
-		}
-	}
-
-	/* update folder */
-	camel_folder_synchronize_sync (folder,
-	                               TRUE,
+	return mail_imap_client_store (self,
+	                               kmailhandle,
+	                               foldername,
+	                               KOLAB_FOLDER_TYPE_AUTO, /* type only needed for folder ops */
+	                               update,
 	                               cancellable,
-	                               &tmp_err);
-	if (tmp_err != NULL)
-		goto cleanup;
-
-	/* refresh folder info */
-	camel_folder_refresh_info_sync (folder,
-	                                cancellable,
-	                                &tmp_err);
-	if (tmp_err != NULL)
-		goto cleanup;
-
-	kolab_mail_summary_set_char_field (summary,
-	                                   KOLAB_MAIL_SUMMARY_CHAR_FIELD_IMAP_UID,
-	                                   stored_imap_uid);
-	g_debug ("%s: Kolab UID (%s) Folder (%s) IMAP UID (%s) successfully stored",
-	         __func__, kolab_uid, foldername, stored_imap_uid);
-	stored_imap_uid = NULL; /* data now owned by mail summary, do not free() */
-
-	/* drop kconvmail from handle */
-	kolab_mail_handle_drop_kconvmail (kmailhandle);
-
- cleanup:
-	if (tmp_err != NULL) {
-		ok = FALSE;
-		g_propagate_error (err, tmp_err);
-	}
-	if (orig_message != NULL)
-		g_object_unref (orig_message);
-	if (new_message != NULL)
-		g_object_unref (new_message);
-	if (stored_message != NULL)
-		g_object_unref (stored_message);
-	if (folder != NULL)
-		g_object_unref (folder);
-	if (stored_imap_uid != NULL)
-		g_free (stored_imap_uid);
-
-	return ok; /* TRUE or FALSE */
+	                               err);
 }
 
 gboolean
diff --git a/src/libekolab/kolab-mail-imap-client.h b/src/libekolab/kolab-mail-imap-client.h
index 31d9be8..2e781da 100644
--- a/src/libekolab/kolab-mail-imap-client.h
+++ b/src/libekolab/kolab-mail-imap-client.h
@@ -162,6 +162,7 @@ kolab_mail_imap_client_query_folder_summary (KolabMailImapClient *self,
 gboolean
 kolab_mail_imap_client_create_folder (KolabMailImapClient *self,
                                       const gchar *foldername,
+                                      KolabFolderTypeID foldertype,
                                       GCancellable *cancellable,
                                       GError **err);
 



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