Enable GUI option for 'custom command' connection. Don't g_free strings in
[platform/upstream/evolution-data-server.git] / camel / camel-disco-folder.c
index 91a12ad..61e8250 100644 (file)
@@ -7,9 +7,8 @@
  * Copyright (C) 2001 Ximian, Inc.
  *
  * This program is free software; you can redistribute it and/or 
- * modify it under the terms of the GNU General Public License as 
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
+ * modify it under the terms of version 2 of the GNU 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
@@ -30,6 +29,8 @@
 #include "camel-disco-store.h"
 #include "camel-exception.h"
 
+#include "camel-session.h"
+
 #define CF_CLASS(o) (CAMEL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS (o)))
 #define CDF_CLASS(o) (CAMEL_DISCO_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS (o)))
 
@@ -40,12 +41,18 @@ static void disco_sync (CamelFolder *folder, gboolean expunge, CamelException *e
 static void disco_expunge (CamelFolder *folder, CamelException *ex);
 
 static void disco_append_message (CamelFolder *folder, CamelMimeMessage *message,
-                                 const CamelMessageInfo *info, CamelException *ex);
-static void disco_copy_messages_to (CamelFolder *source, GPtrArray *uids,
-                                   CamelFolder *destination, CamelException *ex);
-static void disco_move_messages_to (CamelFolder *source, GPtrArray *uids,
-                                   CamelFolder *destination, CamelException *ex);
-
+                                 const CamelMessageInfo *info, char **appended_uid, CamelException *ex);
+static void disco_transfer_messages_to (CamelFolder *source, GPtrArray *uids,
+                                       CamelFolder *destination,
+                                       GPtrArray **transferred_uids,
+                                       gboolean delete_originals,
+                                       CamelException *ex);
+
+static void disco_cache_message       (CamelDiscoFolder *disco_folder,
+                                      const char *uid, CamelException *ex);
+static void disco_prepare_for_offline (CamelDiscoFolder *disco_folder,
+                                      const char *expression,
+                                      CamelException *ex);
 
 static void
 camel_disco_folder_class_init (CamelDiscoFolderClass *camel_disco_folder_class)
@@ -54,14 +61,88 @@ camel_disco_folder_class_init (CamelDiscoFolderClass *camel_disco_folder_class)
 
        parent_class = CAMEL_FOLDER_CLASS (camel_type_get_global_classfuncs (camel_folder_get_type ()));
 
+       /* virtual method definition */
+       camel_disco_folder_class->cache_message = disco_cache_message;
+       camel_disco_folder_class->prepare_for_offline = disco_prepare_for_offline;
+
        /* virtual method overload */
        camel_folder_class->refresh_info = disco_refresh_info;
        camel_folder_class->sync = disco_sync;
        camel_folder_class->expunge = disco_expunge;
 
        camel_folder_class->append_message = disco_append_message;
-       camel_folder_class->copy_messages_to = disco_copy_messages_to;
-       camel_folder_class->move_messages_to = disco_move_messages_to;
+       camel_folder_class->transfer_messages_to = disco_transfer_messages_to;
+}
+
+struct _cdf_sync_msg {
+       CamelSessionThreadMsg msg;
+
+       CamelFolder *folder;
+       CamelFolderChangeInfo *changes;
+};
+
+static void
+cdf_sync_offline(CamelSession *session, CamelSessionThreadMsg *mm)
+{
+       struct _cdf_sync_msg *m = (struct _cdf_sync_msg *)mm;
+       int i;
+
+       camel_operation_start(NULL, _("Downloading new messages for offline mode"));
+
+       if (m->changes) {
+               for (i=0;i<m->changes->uid_added->len;i++) {
+                       int pc = i * 100 / m->changes->uid_added->len;
+
+                       camel_operation_progress(NULL, pc);
+                       camel_disco_folder_cache_message((CamelDiscoFolder *)m->folder,
+                                                        m->changes->uid_added->pdata[i],
+                                                        &mm->ex);
+               }
+       } else {
+               camel_disco_folder_prepare_for_offline((CamelDiscoFolder *)m->folder,
+                                                      "(match-all)",
+                                                      &mm->ex);
+       }
+
+       camel_operation_end(NULL);
+}
+
+static void
+cdf_sync_free(CamelSession *session, CamelSessionThreadMsg *mm)
+{
+       struct _cdf_sync_msg *m = (struct _cdf_sync_msg *)mm;
+
+       if (m->changes)
+               camel_folder_change_info_free(m->changes);
+       camel_object_unref(m->folder);
+}
+
+static CamelSessionThreadOps cdf_sync_ops = {
+       cdf_sync_offline,
+       cdf_sync_free,
+};
+
+static void
+cdf_folder_changed(CamelFolder *folder, CamelFolderChangeInfo *changes, void *dummy)
+{
+       if (changes->uid_added->len > 0
+           && camel_url_get_param(((CamelService *)folder->parent_store)->url, "offline_sync")) {
+               CamelSession *session = ((CamelService *)folder->parent_store)->session;
+               struct _cdf_sync_msg *m;
+
+               m = camel_session_thread_msg_new(session, &cdf_sync_ops, sizeof(*m));
+               m->changes = camel_folder_change_info_new();
+               camel_folder_change_info_cat(m->changes, changes);
+               m->folder = folder;
+               camel_object_ref(folder);
+               camel_session_thread_queue(session, &m->msg, 0);
+       }
+}
+
+static void
+camel_disco_folder_init(CamelDiscoFolder *folder)
+{
+       camel_object_hook_event(folder, "folder_changed", (CamelObjectEventHookFunc)cdf_folder_changed, NULL);
 }
 
 CamelType
@@ -74,8 +155,8 @@ camel_disco_folder_get_type (void)
                        CAMEL_FOLDER_TYPE, "CamelDiscoFolder",
                        sizeof (CamelDiscoFolder),
                        sizeof (CamelDiscoFolderClass),
-                       (CamelObjectClassInitFunc) camel_disco_folder_class_init,
-                       NULL, NULL, NULL);
+                       (CamelObjectClassInitFunc)camel_disco_folder_class_init, NULL,
+                       (CamelObjectInitFunc)camel_disco_folder_init, NULL);
        }
 
        return camel_disco_folder_type;
@@ -107,6 +188,10 @@ disco_sync (CamelFolder *folder, gboolean expunge, CamelException *ex)
        case CAMEL_DISCO_STORE_OFFLINE:
                CDF_CLASS (folder)->sync_offline (folder, ex);
                break;
+
+       case CAMEL_DISCO_STORE_RESYNCING:
+               CDF_CLASS (folder)->sync_resyncing (folder, ex);
+               break;
        }
 }
 
@@ -125,10 +210,10 @@ disco_expunge_uids (CamelFolder *folder, GPtrArray *uids, CamelException *ex)
 
        case CAMEL_DISCO_STORE_OFFLINE:
                CDF_CLASS (folder)->expunge_uids_offline (folder, uids, ex);
-#ifdef NOTYET
-               if (!camel_exception_is_set (ex))
-                       camel_disco_diary_log (disco->diary, CAMEL_DISCO_DIARY_FOLDER_EXPUNGE, folder, uids);
-#endif
+               break;
+
+       case CAMEL_DISCO_STORE_RESYNCING:
+               CDF_CLASS (folder)->expunge_uids_resyncing (folder, uids, ex);
                break;
        }
 }
@@ -158,65 +243,53 @@ disco_expunge (CamelFolder *folder, CamelException *ex)
 
 static void
 disco_append_message (CamelFolder *folder, CamelMimeMessage *message,
-                     const CamelMessageInfo *info, CamelException *ex)
+                     const CamelMessageInfo *info, char **appended_uid,
+                     CamelException *ex)
 {
        CamelDiscoStore *disco = CAMEL_DISCO_STORE (folder->parent_store);
-       char *uid;
 
        switch (camel_disco_store_status (disco)) {
        case CAMEL_DISCO_STORE_ONLINE:
-               uid = CDF_CLASS (folder)->append_online (folder, message, info, ex);
+               CDF_CLASS (folder)->append_online (folder, message, info,
+                                                  appended_uid, ex);
                break;
 
        case CAMEL_DISCO_STORE_OFFLINE:
-               uid = CDF_CLASS (folder)->append_offline (folder, message, info, ex);
-#ifdef NOTYET
-               if (uid)
-                       camel_disco_diary_log (disco->diary, CAMEL_DISCO_DIARY_FOLDER_APPEND, folder, uid);
-#endif
+               CDF_CLASS (folder)->append_offline (folder, message, info,
+                                                   appended_uid, ex);
                break;
-       }
-       g_free (uid);
-}
-
-static void
-disco_copy_messages_to (CamelFolder *source, GPtrArray *uids,
-                       CamelFolder *destination, CamelException *ex)
-{
-       CamelDiscoStore *disco = CAMEL_DISCO_STORE (source->parent_store);
 
-       switch (camel_disco_store_status (disco)) {
-       case CAMEL_DISCO_STORE_ONLINE:
-               CDF_CLASS (source)->copy_online (source, uids, destination, ex);
-               break;
-
-       case CAMEL_DISCO_STORE_OFFLINE:
-               CDF_CLASS (source)->copy_offline (source, uids, destination, ex);
-#ifdef NOTYET
-               if (!camel_exception_is_set (ex))
-                       camel_disco_diary_log (disco->diary, CAMEL_DISCO_DIARY_FOLDER_COPY, source, destination, uids);
-#endif
+       case CAMEL_DISCO_STORE_RESYNCING:
+               CDF_CLASS (folder)->append_resyncing (folder, message, info,
+                                                     appended_uid, ex);
                break;
        }
 }
 
 static void
-disco_move_messages_to (CamelFolder *source, GPtrArray *uids,
-                       CamelFolder *destination, CamelException *ex)
+disco_transfer_messages_to (CamelFolder *source, GPtrArray *uids,
+                           CamelFolder *dest, GPtrArray **transferred_uids,
+                           gboolean delete_originals, CamelException *ex)
 {
        CamelDiscoStore *disco = CAMEL_DISCO_STORE (source->parent_store);
 
        switch (camel_disco_store_status (disco)) {
        case CAMEL_DISCO_STORE_ONLINE:
-               CDF_CLASS (source)->move_online (source, uids, destination, ex);
+               CDF_CLASS (source)->transfer_online (source, uids,
+                                                    dest, transferred_uids,
+                                                    delete_originals, ex);
                break;
 
        case CAMEL_DISCO_STORE_OFFLINE:
-               CDF_CLASS (source)->move_offline (source, uids, destination, ex);
-#ifdef NOTYET
-               if (!camel_exception_is_set (ex))
-                       camel_disco_diary_log (disco->diary, CAMEL_DISCO_DIARY_FOLDER_MOVE, source, destination, uids);
-#endif
+               CDF_CLASS (source)->transfer_offline (source, uids,
+                                                     dest, transferred_uids,
+                                                     delete_originals, ex);
+               break;
+
+       case CAMEL_DISCO_STORE_RESYNCING:
+               CDF_CLASS (source)->transfer_resyncing (source, uids,
+                                                       dest, transferred_uids,
+                                                       delete_originals, ex);
                break;
        }
 }
@@ -240,3 +313,87 @@ camel_disco_folder_expunge_uids (CamelFolder *folder, GPtrArray *uids,
 {
        disco_expunge_uids (folder, uids, ex);
 }
+
+
+static void
+disco_cache_message (CamelDiscoFolder *disco_folder, const char *uid,
+                    CamelException *ex)
+{
+       g_warning ("CamelDiscoFolder::cache_message not implemented for `%s'",
+                  camel_type_to_name (CAMEL_OBJECT_GET_TYPE (disco_folder)));
+}
+
+/**
+ * camel_disco_folder_cache_message:
+ * @disco_folder: the folder
+ * @uid: the UID of the message to cache
+ * @ex: a CamelException
+ *
+ * Requests that @disco_folder cache message @uid to disk.
+ **/
+void
+camel_disco_folder_cache_message (CamelDiscoFolder *disco_folder,
+                                 const char *uid, CamelException *ex)
+{
+       CDF_CLASS (disco_folder)->cache_message (disco_folder, uid, ex);
+}
+
+
+static void
+disco_prepare_for_offline (CamelDiscoFolder *disco_folder,
+                          const char *expression,
+                          CamelException *ex)
+{
+       CamelFolder *folder = CAMEL_FOLDER (disco_folder);
+       GPtrArray *uids;
+       int i;
+
+       camel_operation_start(NULL, _("Preparing folder '%s' for offline"), folder->full_name);
+
+       if (expression)
+               uids = camel_folder_search_by_expression (folder, expression, ex);
+       else
+               uids = camel_folder_get_uids (folder);
+
+       if (!uids) {
+               camel_operation_end(NULL);
+               return;
+       }
+
+       for (i = 0; i < uids->len; i++) {
+               int pc = i * 100 / uids->len;
+
+               camel_disco_folder_cache_message (disco_folder, uids->pdata[i], ex);
+               camel_operation_progress(NULL, pc);
+               if (camel_exception_is_set (ex))
+                       break;
+       }
+
+       if (expression)
+               camel_folder_search_free (folder, uids);
+       else
+               camel_folder_free_uids (folder, uids);
+
+       camel_operation_end(NULL);
+}
+
+/**
+ * camel_disco_folder_prepare_for_offline:
+ * @disco_folder: the folder
+ * @expression: an expression describing messages to synchronize, or %NULL
+ * if all messages should be sync'ed.
+ * @ex: a CamelException
+ *
+ * This prepares @disco_folder for offline operation, by downloading
+ * the bodies of all messages described by @expression (using the
+ * same syntax as camel_folder_search_by_expression() ).
+ **/
+void 
+camel_disco_folder_prepare_for_offline (CamelDiscoFolder *disco_folder,
+                                       const char *expression,
+                                       CamelException *ex)
+{
+       g_return_if_fail (CAMEL_IS_DISCO_FOLDER (disco_folder));
+
+       CDF_CLASS (disco_folder)->prepare_for_offline (disco_folder, expression, ex);
+}