4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) version 3.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with the program; if not, see <http://www.gnu.org/licenses/>
19 #include "camel-subscribable.h"
22 #include <glib/gi18n-lib.h>
24 #include "camel-debug.h"
25 #include "camel-session.h"
26 #include "camel-vtrash-folder.h"
28 typedef struct _AsyncContext AsyncContext;
29 typedef struct _SignalData SignalData;
31 struct _AsyncContext {
36 CamelSubscribable *subscribable;
37 CamelFolderInfo *folder_info;
46 static guint signals[LAST_SIGNAL];
48 G_DEFINE_INTERFACE (CamelSubscribable, camel_subscribable, CAMEL_TYPE_STORE)
51 async_context_free (AsyncContext *async_context)
53 g_free (async_context->folder_name);
55 g_slice_free (AsyncContext, async_context);
59 signal_data_free (SignalData *signal_data)
61 if (signal_data->subscribable != NULL)
62 g_object_unref (signal_data->subscribable);
64 if (signal_data->folder_info != NULL)
65 camel_folder_info_free (signal_data->folder_info);
67 g_slice_free (SignalData, signal_data);
71 subscribable_emit_folder_subscribed_cb (gpointer user_data)
73 SignalData *signal_data = user_data;
76 signal_data->subscribable,
77 signals[FOLDER_SUBSCRIBED], 0,
78 signal_data->folder_info);
84 subscribable_emit_folder_unsubscribed_cb (gpointer user_data)
86 SignalData *signal_data = user_data;
89 signal_data->subscribable,
90 signals[FOLDER_UNSUBSCRIBED], 0,
91 signal_data->folder_info);
97 subscribable_delete_cached_folder (CamelStore *store,
98 const gchar *folder_name)
101 CamelVeeFolder *vfolder;
103 /* XXX Copied from camel-store.c. Should this be public? */
105 if (store->folders == NULL)
108 folder = camel_object_bag_get (store->folders, folder_name);
112 if (store->flags & CAMEL_STORE_VTRASH) {
113 folder_name = CAMEL_VTRASH_NAME;
114 vfolder = camel_object_bag_get (store->folders, folder_name);
115 if (vfolder != NULL) {
116 camel_vee_folder_remove_folder (vfolder, folder, NULL);
117 g_object_unref (vfolder);
121 if (store->flags & CAMEL_STORE_VJUNK) {
122 folder_name = CAMEL_VJUNK_NAME;
123 vfolder = camel_object_bag_get (store->folders, folder_name);
124 if (vfolder != NULL) {
125 camel_vee_folder_remove_folder (vfolder, folder, NULL);
126 g_object_unref (vfolder);
130 camel_folder_delete (folder);
132 camel_object_bag_remove (store->folders, folder);
133 g_object_unref (folder);
137 subscribable_subscribe_folder_thread (GSimpleAsyncResult *simple,
139 GCancellable *cancellable)
141 AsyncContext *async_context;
142 GError *error = NULL;
144 async_context = g_simple_async_result_get_op_res_gpointer (simple);
146 camel_subscribable_subscribe_folder_sync (
147 CAMEL_SUBSCRIBABLE (object),
148 async_context->folder_name,
149 cancellable, &error);
152 g_simple_async_result_take_error (simple, error);
156 subscribable_subscribe_folder (CamelSubscribable *subscribable,
157 const gchar *folder_name,
159 GCancellable *cancellable,
160 GAsyncReadyCallback callback,
163 GSimpleAsyncResult *simple;
164 AsyncContext *async_context;
166 async_context = g_slice_new0 (AsyncContext);
167 async_context->folder_name = g_strdup (folder_name);
169 simple = g_simple_async_result_new (
170 G_OBJECT (subscribable), callback,
171 user_data, subscribable_subscribe_folder);
173 g_simple_async_result_set_check_cancellable (simple, cancellable);
175 g_simple_async_result_set_op_res_gpointer (
176 simple, async_context, (GDestroyNotify) async_context_free);
178 g_simple_async_result_run_in_thread (
179 simple, subscribable_subscribe_folder_thread,
180 io_priority, cancellable);
182 g_object_unref (simple);
186 subscribable_subscribe_folder_finish (CamelSubscribable *subscribable,
187 GAsyncResult *result,
190 GSimpleAsyncResult *simple;
192 g_return_val_if_fail (
193 g_simple_async_result_is_valid (
194 result, G_OBJECT (subscribable),
195 subscribable_subscribe_folder), FALSE);
197 simple = G_SIMPLE_ASYNC_RESULT (result);
199 /* Assume success unless a GError is set. */
200 return !g_simple_async_result_propagate_error (simple, error);
204 subscribable_unsubscribe_folder_thread (GSimpleAsyncResult *simple,
206 GCancellable *cancellable)
208 AsyncContext *async_context;
209 GError *error = NULL;
211 async_context = g_simple_async_result_get_op_res_gpointer (simple);
213 camel_subscribable_unsubscribe_folder_sync (
214 CAMEL_SUBSCRIBABLE (object),
215 async_context->folder_name,
216 cancellable, &error);
219 g_simple_async_result_take_error (simple, error);
223 subscribable_unsubscribe_folder (CamelSubscribable *subscribable,
224 const gchar *folder_name,
226 GCancellable *cancellable,
227 GAsyncReadyCallback callback,
230 GSimpleAsyncResult *simple;
231 AsyncContext *async_context;
233 async_context = g_slice_new0 (AsyncContext);
234 async_context->folder_name = g_strdup (folder_name);
236 simple = g_simple_async_result_new (
237 G_OBJECT (subscribable), callback,
238 user_data, subscribable_unsubscribe_folder);
240 g_simple_async_result_set_check_cancellable (simple, cancellable);
242 g_simple_async_result_set_op_res_gpointer (
243 simple, async_context, (GDestroyNotify) async_context_free);
245 g_simple_async_result_run_in_thread (
246 simple, subscribable_unsubscribe_folder_thread,
247 io_priority, cancellable);
249 g_object_unref (simple);
253 subscribable_unsubscribe_folder_finish (CamelSubscribable *subscribable,
254 GAsyncResult *result,
257 GSimpleAsyncResult *simple;
259 g_return_val_if_fail (
260 g_simple_async_result_is_valid (
261 result, G_OBJECT (subscribable),
262 subscribable_unsubscribe_folder), FALSE);
264 simple = G_SIMPLE_ASYNC_RESULT (result);
266 /* Assume success unless a GError is set. */
267 return !g_simple_async_result_propagate_error (simple, error);
271 camel_subscribable_default_init (CamelSubscribableInterface *interface)
273 interface->subscribe_folder = subscribable_subscribe_folder;
274 interface->subscribe_folder_finish = subscribable_subscribe_folder_finish;
275 interface->unsubscribe_folder = subscribable_unsubscribe_folder;
276 interface->unsubscribe_folder_finish = subscribable_unsubscribe_folder_finish;
278 signals[FOLDER_SUBSCRIBED] = g_signal_new (
280 G_OBJECT_CLASS_TYPE (interface),
283 CamelSubscribableInterface,
286 g_cclosure_marshal_VOID__POINTER,
290 signals[FOLDER_UNSUBSCRIBED] = g_signal_new (
291 "folder-unsubscribed",
292 G_OBJECT_CLASS_TYPE (interface),
295 CamelSubscribableInterface,
296 folder_unsubscribed),
298 g_cclosure_marshal_VOID__POINTER,
304 * camel_subscribable_folder_is_subscribed:
305 * @subscribable: a #CamelSubscribable
306 * @folder_name: full path of the folder
308 * Find out if a folder has been subscribed to.
310 * Returns: %TRUE if the folder has been subscribed to or %FALSE otherwise
315 camel_subscribable_folder_is_subscribed (CamelSubscribable *subscribable,
316 const gchar *folder_name)
318 CamelSubscribableInterface *interface;
319 gboolean is_subscribed;
321 g_return_val_if_fail (CAMEL_IS_SUBSCRIBABLE (subscribable), FALSE);
322 g_return_val_if_fail (folder_name != NULL, FALSE);
324 interface = CAMEL_SUBSCRIBABLE_GET_INTERFACE (subscribable);
325 g_return_val_if_fail (interface->folder_is_subscribed != NULL, FALSE);
328 CAMEL_STORE (subscribable),
329 CAMEL_STORE_FOLDER_LOCK);
331 is_subscribed = interface->folder_is_subscribed (
332 subscribable, folder_name);
335 CAMEL_STORE (subscribable),
336 CAMEL_STORE_FOLDER_LOCK);
338 return is_subscribed;
342 * camel_subscribable_subscribe_folder_sync:
343 * @subscribable: a #CamelSubscribable
344 * @folder_name: full path of the folder
345 * @cancellable: optional #GCancellable object, or %NULL
346 * @error: return location for a #GError, or %NULL
348 * Subscribes to the folder described by @folder_name.
350 * Returns: %TRUE on success, %FALSE on error
355 camel_subscribable_subscribe_folder_sync (CamelSubscribable *subscribable,
356 const gchar *folder_name,
357 GCancellable *cancellable,
360 CamelSubscribableInterface *interface;
361 const gchar *message;
364 g_return_val_if_fail (CAMEL_IS_SUBSCRIBABLE (subscribable), FALSE);
365 g_return_val_if_fail (folder_name != NULL, FALSE);
367 interface = CAMEL_SUBSCRIBABLE_GET_INTERFACE (subscribable);
368 g_return_val_if_fail (interface->subscribe_folder_sync != NULL, FALSE);
371 CAMEL_STORE (subscribable),
372 CAMEL_STORE_FOLDER_LOCK);
374 /* Check for cancellation after locking. */
375 if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
380 /* Need to establish a connection before subscribing. */
381 success = camel_service_connect_sync (
382 CAMEL_SERVICE (subscribable), cancellable, error);
386 message = _("Subscribing to folder '%s'");
387 camel_operation_push_message (cancellable, message, folder_name);
389 success = interface->subscribe_folder_sync (
390 subscribable, folder_name, cancellable, error);
392 subscribable, subscribe_folder_sync, success, error);
394 camel_operation_pop_message (cancellable);
398 CAMEL_STORE (subscribable),
399 CAMEL_STORE_FOLDER_LOCK);
405 * camel_subscribable_subscribe_folder:
406 * @subscribable: a #CamelSubscribable
407 * @folder_name: full path of the folder
408 * @io_priority: the I/O priority of the request
409 * @cancellable: optional #GCancellable object, or %NULL
410 * @callback: a #GAsyncReadyCallback to call when the request is satisfied
411 * @user_data: data to pass to the callback function
413 * Asynchronously subscribes to the folder described by @folder_name.
415 * When the operation is finished, @callback will be called. You can then
416 * call camel_subscribable_subscribe_folder_finish() to get the result of
422 camel_subscribable_subscribe_folder (CamelSubscribable *subscribable,
423 const gchar *folder_name,
425 GCancellable *cancellable,
426 GAsyncReadyCallback callback,
429 CamelSubscribableInterface *interface;
431 g_return_if_fail (CAMEL_IS_SUBSCRIBABLE (subscribable));
432 g_return_if_fail (folder_name != NULL);
434 interface = CAMEL_SUBSCRIBABLE_GET_INTERFACE (subscribable);
435 g_return_if_fail (interface->subscribe_folder != NULL);
437 interface->subscribe_folder (
438 subscribable, folder_name, io_priority,
439 cancellable, callback, user_data);
443 * camel_subscribable_subscribe_folder_finish:
444 * @subscribable: a #CamelSubscribable
445 * @result: a #GAsyncResult
446 * @error: return location for a #GError, or %NULL
448 * Finishes the operation started with camel_subscribable_subscribe_folder().
450 * Returns: %TRUE on success, %FALSE on error
455 camel_subscribable_subscribe_folder_finish (CamelSubscribable *subscribable,
456 GAsyncResult *result,
459 CamelSubscribableInterface *interface;
461 g_return_val_if_fail (CAMEL_IS_SUBSCRIBABLE (subscribable), FALSE);
462 g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
464 interface = CAMEL_SUBSCRIBABLE_GET_INTERFACE (subscribable);
465 g_return_val_if_fail (
466 interface->subscribe_folder_finish != NULL, FALSE);
468 return interface->subscribe_folder_finish (
469 subscribable, result, error);
473 * camel_subscribable_unsubscribe_folder_sync:
474 * @subscribable: a #CamelSubscribable
475 * @folder_name: full path of the folder
476 * @cancellable: optional #GCancellable object, or %NULL
477 * @error: return location for a #GError, or %NULL
479 * Unsubscribes from the folder described by @folder_name.
481 * Returns: %TRUE on success, %FALSE on error
486 camel_subscribable_unsubscribe_folder_sync (CamelSubscribable *subscribable,
487 const gchar *folder_name,
488 GCancellable *cancellable,
491 CamelSubscribableInterface *interface;
492 const gchar *message;
495 g_return_val_if_fail (CAMEL_IS_SUBSCRIBABLE (subscribable), FALSE);
496 g_return_val_if_fail (folder_name != NULL, FALSE);
498 interface = CAMEL_SUBSCRIBABLE_GET_INTERFACE (subscribable);
499 g_return_val_if_fail (
500 interface->unsubscribe_folder_sync != NULL, FALSE);
503 CAMEL_STORE (subscribable),
504 CAMEL_STORE_FOLDER_LOCK);
506 /* Check for cancellation after locking. */
507 if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
512 /* Need to establish a connection before unsubscribing. */
513 success = camel_service_connect_sync (
514 CAMEL_SERVICE (subscribable), cancellable, error);
518 message = _("Unsubscribing from folder '%s'");
519 camel_operation_push_message (cancellable, message, folder_name);
521 success = interface->unsubscribe_folder_sync (
522 subscribable, folder_name, cancellable, error);
524 subscribable, unsubscribe_folder_sync, success, error);
527 subscribable_delete_cached_folder (
528 CAMEL_STORE (subscribable), folder_name);
530 camel_operation_pop_message (cancellable);
534 CAMEL_STORE (subscribable),
535 CAMEL_STORE_FOLDER_LOCK);
541 * camel_subscribable_unsubscribe_folder:
542 * @subscribable: a #CamelSubscribable
543 * @folder_name: full path of the folder
544 * @io_priority: the I/O priority of the request
545 * @cancellable: optional #GCancellable object, or %NULL
546 * @callback: a #GAsyncReadyCallback to call when the request is satisfied
547 * @user_data: data to pass to the callback function
549 * Asynchronously unsubscribes from the folder described by @folder_name.
551 * When the operation is finished, @callback will be called. You can then
552 * call camel_subscribable_unsubscribe_folder_finish() to get the result of
558 camel_subscribable_unsubscribe_folder (CamelSubscribable *subscribable,
559 const gchar *folder_name,
561 GCancellable *cancellable,
562 GAsyncReadyCallback callback,
565 CamelSubscribableInterface *interface;
567 g_return_if_fail (CAMEL_IS_SUBSCRIBABLE (subscribable));
568 g_return_if_fail (folder_name != NULL);
570 interface = CAMEL_SUBSCRIBABLE_GET_INTERFACE (subscribable);
571 g_return_if_fail (interface->unsubscribe_folder != NULL);
573 interface->unsubscribe_folder (
574 subscribable, folder_name, io_priority,
575 cancellable, callback, user_data);
579 * camel_subscribable_unsubscribe_folder_finish:
580 * @subscribable: a #CamelSubscribable
581 * @result: a #GAsyncResult
582 * @error: return location for a #GError, or %NULL
584 * Finishes the operation started with camel_subscribable_unsubscribe_folder().
586 * Returns: %TRUE on success, %FALSE on error
591 camel_subscribable_unsubscribe_folder_finish (CamelSubscribable *subscribable,
592 GAsyncResult *result,
595 CamelSubscribableInterface *interface;
597 g_return_val_if_fail (CAMEL_IS_SUBSCRIBABLE (subscribable), FALSE);
598 g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
600 interface = CAMEL_SUBSCRIBABLE_GET_INTERFACE (subscribable);
601 g_return_val_if_fail (
602 interface->unsubscribe_folder_finish != NULL, FALSE);
604 return interface->unsubscribe_folder_finish (
605 subscribable, result, error);
609 * camel_subscribable_folder_subscribed:
610 * @subscribable: a #CamelSubscribable
611 * @folder_info: information about the subscribed folder
613 * Emits the #CamelSubscribable::folder-subscribed signal from an idle source
614 * on the main loop. The idle source's priority is #G_PRIORITY_DEFAULT_IDLE.
616 * This function is only intended for Camel providers.
621 camel_subscribable_folder_subscribed (CamelSubscribable *subscribable,
622 CamelFolderInfo *folder_info)
624 CamelService *service;
625 CamelSession *session;
626 SignalData *signal_data;
628 g_return_if_fail (CAMEL_IS_SUBSCRIBABLE (subscribable));
629 g_return_if_fail (folder_info != NULL);
631 service = CAMEL_SERVICE (subscribable);
632 session = camel_service_get_session (service);
634 signal_data = g_slice_new0 (SignalData);
635 signal_data->subscribable = g_object_ref (subscribable);
636 signal_data->folder_info = camel_folder_info_clone (folder_info);
638 camel_session_idle_add (
639 session, G_PRIORITY_DEFAULT_IDLE,
640 subscribable_emit_folder_subscribed_cb,
641 signal_data, (GDestroyNotify) signal_data_free);
645 * camel_subscribable_folder_unsubscribed:
646 * @subscribable: a #CamelSubscribable
647 * @folder_info: information about the unsubscribed folder
649 * Emits the #CamelSubscribable::folder-unsubscribed signal from an idle source
650 * on the main loop. The idle source's priority is #G_PRIORITY_DEFAULT_IDLE.
652 * This function is only intended for Camel providers.
657 camel_subscribable_folder_unsubscribed (CamelSubscribable *subscribable,
658 CamelFolderInfo *folder_info)
660 CamelService *service;
661 CamelSession *session;
662 SignalData *signal_data;
664 g_return_if_fail (CAMEL_IS_SUBSCRIBABLE (subscribable));
665 g_return_if_fail (folder_info != NULL);
667 service = CAMEL_SERVICE (subscribable);
668 session = camel_service_get_session (service);
670 signal_data = g_slice_new0 (SignalData);
671 signal_data->subscribable = g_object_ref (subscribable);
672 signal_data->folder_info = camel_folder_info_clone (folder_info);
674 camel_session_idle_add (
675 session, G_PRIORITY_DEFAULT_IDLE,
676 subscribable_emit_folder_unsubscribed_cb,
677 signal_data, (GDestroyNotify) signal_data_free);