1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Authors: Jeffrey Stedfast <fejj@novell.com>
5 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
27 #include <glib/gi18n-lib.h>
29 #include "camel-debug.h"
30 #include "camel-offline-folder.h"
31 #include "camel-offline-settings.h"
32 #include "camel-offline-store.h"
33 #include "camel-operation.h"
34 #include "camel-session.h"
36 #define CAMEL_OFFLINE_FOLDER_GET_PRIVATE(obj) \
37 (G_TYPE_INSTANCE_GET_PRIVATE \
38 ((obj), CAMEL_TYPE_OFFLINE_FOLDER, CamelOfflineFolderPrivate))
40 typedef struct _AsyncContext AsyncContext;
41 typedef struct _OfflineDownsyncData OfflineDownsyncData;
43 struct _CamelOfflineFolderPrivate {
44 gboolean offline_sync;
47 struct _AsyncContext {
52 struct _OfflineDownsyncData {
54 CamelFolderChangeInfo *changes;
57 /* The custom property ID is a CamelArg artifact.
58 * It still identifies the property in state files. */
61 PROP_OFFLINE_SYNC = 0x2400
64 G_DEFINE_TYPE (CamelOfflineFolder, camel_offline_folder, CAMEL_TYPE_FOLDER)
67 async_context_free (AsyncContext *async_context)
69 g_free (async_context->expression);
71 g_slice_free (AsyncContext, async_context);
75 offline_downsync_data_free (OfflineDownsyncData *data)
77 if (data->changes != NULL)
78 camel_folder_change_info_free (data->changes);
80 g_object_unref (data->folder);
82 g_slice_free (OfflineDownsyncData, data);
86 offline_folder_downsync_background (CamelSession *session,
87 GCancellable *cancellable,
88 OfflineDownsyncData *data,
91 camel_operation_push_message (
93 _("Downloading new messages for offline mode"));
97 gboolean success = TRUE;
100 uid_added = data->changes->uid_added;
102 for (ii = 0; success && ii < uid_added->len; ii++) {
106 percent = ii * 100 / uid_added->len;
107 uid = g_ptr_array_index (uid_added, ii);
109 camel_operation_progress (cancellable, percent);
111 success = camel_folder_synchronize_message_sync (
112 data->folder, uid, cancellable, error);
115 camel_offline_folder_downsync_sync (
116 CAMEL_OFFLINE_FOLDER (data->folder),
117 "(match-all)", cancellable, error);
120 camel_operation_pop_message (cancellable);
124 offline_folder_changed (CamelFolder *folder,
125 CamelFolderChangeInfo *changes)
127 CamelStore *parent_store;
128 CamelService *service;
129 CamelSession *session;
130 CamelSettings *settings;
132 gboolean sync_folder;
134 parent_store = camel_folder_get_parent_store (folder);
136 service = CAMEL_SERVICE (parent_store);
137 session = camel_service_get_session (service);
139 settings = camel_service_ref_settings (service);
141 sync_store = camel_offline_settings_get_stay_synchronized (
142 CAMEL_OFFLINE_SETTINGS (settings));
144 g_object_unref (settings);
146 sync_folder = camel_offline_folder_get_offline_sync (
147 CAMEL_OFFLINE_FOLDER (folder));
149 if (changes->uid_added->len > 0 && (sync_store || sync_folder)) {
150 OfflineDownsyncData *data;
152 data = g_slice_new0 (OfflineDownsyncData);
153 data->changes = camel_folder_change_info_new ();
154 camel_folder_change_info_cat (data->changes, changes);
155 data->folder = g_object_ref (folder);
157 camel_session_submit_job (
158 session, (CamelSessionCallback)
159 offline_folder_downsync_background, data,
160 (GDestroyNotify) offline_downsync_data_free);
165 offline_folder_set_property (GObject *object,
170 switch (property_id) {
171 case PROP_OFFLINE_SYNC:
172 camel_offline_folder_set_offline_sync (
173 CAMEL_OFFLINE_FOLDER (object),
174 g_value_get_boolean (value));
178 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
182 offline_folder_get_property (GObject *object,
187 switch (property_id) {
188 case PROP_OFFLINE_SYNC:
189 g_value_set_boolean (
190 value, camel_offline_folder_get_offline_sync (
191 CAMEL_OFFLINE_FOLDER (object)));
195 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
199 offline_folder_downsync_sync (CamelOfflineFolder *offline,
200 const gchar *expression,
201 GCancellable *cancellable,
204 CamelFolder *folder = (CamelFolder *) offline;
205 GPtrArray *uids, *uncached_uids = NULL;
206 const gchar *display_name;
207 const gchar *message;
210 message = _("Syncing messages in folder '%s' to disk");
211 display_name = camel_folder_get_display_name (folder);
212 camel_operation_push_message (cancellable, message, display_name);
215 uids = camel_folder_search_by_expression (folder, expression, cancellable, NULL);
217 uids = camel_folder_get_uids (folder);
221 uncached_uids = camel_folder_get_uncached_uids (folder, uids, NULL);
224 camel_folder_search_free (folder, uids);
226 camel_folder_free_uids (folder, uids);
232 for (i = 0; i < uncached_uids->len; i++) {
233 camel_folder_synchronize_message_sync (
234 folder, uncached_uids->pdata[i], cancellable, NULL);
235 camel_operation_progress (
236 cancellable, i * 100 / uncached_uids->len);
241 camel_folder_free_uids (folder, uncached_uids);
243 camel_operation_pop_message (cancellable);
249 offline_folder_downsync_thread (GSimpleAsyncResult *simple,
251 GCancellable *cancellable)
253 AsyncContext *async_context;
254 GError *error = NULL;
256 async_context = g_simple_async_result_get_op_res_gpointer (simple);
258 camel_offline_folder_downsync_sync (
259 CAMEL_OFFLINE_FOLDER (object), async_context->expression,
260 cancellable, &error);
263 g_simple_async_result_take_error (simple, error);
267 offline_folder_downsync (CamelOfflineFolder *folder,
268 const gchar *expression,
270 GCancellable *cancellable,
271 GAsyncReadyCallback callback,
274 GSimpleAsyncResult *simple;
275 AsyncContext *async_context;
277 async_context = g_slice_new0 (AsyncContext);
278 async_context->expression = g_strdup (expression);
280 simple = g_simple_async_result_new (
281 G_OBJECT (folder), callback,
282 user_data, offline_folder_downsync);
284 g_simple_async_result_set_check_cancellable (simple, cancellable);
286 g_simple_async_result_set_op_res_gpointer (
287 simple, async_context, (GDestroyNotify) async_context_free);
289 g_simple_async_result_run_in_thread (
290 simple, offline_folder_downsync_thread,
291 io_priority, cancellable);
293 g_object_unref (simple);
297 offline_folder_downsync_finish (CamelOfflineFolder *folder,
298 GAsyncResult *result,
301 GSimpleAsyncResult *simple;
303 g_return_val_if_fail (
304 g_simple_async_result_is_valid (
305 result, G_OBJECT (folder), offline_folder_downsync), FALSE);
307 simple = G_SIMPLE_ASYNC_RESULT (result);
309 /* Assume success unless a GError is set. */
310 return !g_simple_async_result_propagate_error (simple, error);
314 camel_offline_folder_class_init (CamelOfflineFolderClass *class)
316 GObjectClass *object_class;
318 g_type_class_add_private (class, sizeof (CamelOfflineFolderPrivate));
320 object_class = G_OBJECT_CLASS (class);
321 object_class->set_property = offline_folder_set_property;
322 object_class->get_property = offline_folder_get_property;
324 class->downsync_sync = offline_folder_downsync_sync;
325 class->downsync = offline_folder_downsync;
326 class->downsync_finish = offline_folder_downsync_finish;
328 g_object_class_install_property (
331 g_param_spec_boolean (
334 _("Copy folder content locally for _offline operation"),
337 CAMEL_PARAM_PERSISTENT));
341 camel_offline_folder_init (CamelOfflineFolder *folder)
343 folder->priv = CAMEL_OFFLINE_FOLDER_GET_PRIVATE (folder);
347 G_CALLBACK (offline_folder_changed), NULL);
351 * camel_offline_folder_get_offline_sync:
352 * @folder: a #CamelOfflineFolder
357 camel_offline_folder_get_offline_sync (CamelOfflineFolder *folder)
359 g_return_val_if_fail (CAMEL_IS_OFFLINE_FOLDER (folder), FALSE);
361 return folder->priv->offline_sync;
365 * camel_offline_folder_set_offline_sync:
366 * @folder: a #CamelOfflineFolder
367 * @offline_sync: whether to synchronize for offline use
372 camel_offline_folder_set_offline_sync (CamelOfflineFolder *folder,
373 gboolean offline_sync)
375 g_return_if_fail (CAMEL_IS_OFFLINE_FOLDER (folder));
377 if ((folder->priv->offline_sync ? 1 : 0) == (offline_sync ? 1 : 0))
380 folder->priv->offline_sync = offline_sync;
382 g_object_notify (G_OBJECT (folder), "offline-sync");
386 * camel_offline_folder_downsync_sync:
387 * @folder: a #CamelOfflineFolder
388 * @expression: search expression describing which set of messages
389 * to downsync (%NULL for all)
390 * @cancellable: optional #GCancellable object, or %NULL
391 * @error: return location for a #GError, or %NULL
393 * Synchronizes messages in @folder described by the search @expression to
394 * the local machine for offline availability.
396 * Returns: %TRUE on success, %FALSE on error
401 camel_offline_folder_downsync_sync (CamelOfflineFolder *folder,
402 const gchar *expression,
403 GCancellable *cancellable,
406 CamelOfflineFolderClass *class;
409 g_return_val_if_fail (CAMEL_IS_OFFLINE_FOLDER (folder), FALSE);
411 class = CAMEL_OFFLINE_FOLDER_GET_CLASS (folder);
412 g_return_val_if_fail (class->downsync_sync != NULL, FALSE);
414 success = class->downsync_sync (
415 folder, expression, cancellable, error);
416 CAMEL_CHECK_GERROR (folder, downsync_sync, success, error);
422 * camel_offline_folder_downsync:
423 * @folder: a #CamelOfflineFolder
424 * @expression: search expression describing which set of messages
425 * to downsync (%NULL for all)
426 * @io_priority: the I/O priority of the request
427 * @cancellable: optional #GCancellable object, or %NULl
428 * @callback: a #GAsyncReadyCallback to call when the request is satisfied
429 * @user_data: data to pass to the callback function
431 * Synchronizes messages in @folder described by the search @expression to
432 * the local machine asynchronously for offline availability.
434 * When the operation is finished, @callback will be called. You can then
435 * call camel_offline_folder_downsync_finish() to get the result of the
441 camel_offline_folder_downsync (CamelOfflineFolder *folder,
442 const gchar *expression,
444 GCancellable *cancellable,
445 GAsyncReadyCallback callback,
448 CamelOfflineFolderClass *class;
450 g_return_if_fail (CAMEL_IS_OFFLINE_FOLDER (folder));
452 class = CAMEL_OFFLINE_FOLDER_GET_CLASS (folder);
453 g_return_if_fail (class->downsync != NULL);
456 folder, expression, io_priority,
457 cancellable, callback, user_data);
461 * camel_offline_folder_downsync_finish:
462 * @folder: a #CamelOfflineFolder
463 * @result: a #GAsyncResult
464 * @error: return location for a #GError, or %NULL
466 * Finishes the operation started with camel_offline_folder_downsync().
468 * Returns: %TRUE on success, %FALSE on error
473 camel_offline_folder_downsync_finish (CamelOfflineFolder *folder,
474 GAsyncResult *result,
477 CamelOfflineFolderClass *class;
479 g_return_val_if_fail (CAMEL_IS_OFFLINE_FOLDER (folder), FALSE);
480 g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
482 class = CAMEL_OFFLINE_FOLDER_GET_CLASS (folder);
483 g_return_val_if_fail (class->downsync_finish != NULL, FALSE);
485 return class->downsync_finish (folder, result, error);