1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /* camel-service.c : Abstract class for an email service */
7 * Bertrand Guiheneuf <bertrand@helixcode.com>
9 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of version 2 of the GNU Lesser General Public
13 * License as published by the Free Software Foundation.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
35 #include <glib/gstdio.h>
36 #include <glib/gi18n-lib.h>
38 #include "camel-debug.h"
39 #include "camel-enumtypes.h"
40 #include "camel-local-settings.h"
41 #include "camel-network-service.h"
42 #include "camel-network-settings.h"
43 #include "camel-operation.h"
44 #include "camel-service.h"
45 #include "camel-session.h"
50 #define CAMEL_SERVICE_GET_PRIVATE(obj) \
51 (G_TYPE_INSTANCE_GET_PRIVATE \
52 ((obj), CAMEL_TYPE_SERVICE, CamelServicePrivate))
54 typedef struct _AsyncClosure AsyncClosure;
55 typedef struct _AsyncContext AsyncContext;
56 typedef struct _ConnectionOp ConnectionOp;
58 struct _CamelServicePrivate {
61 CamelSettings *settings;
64 CamelProvider *provider;
68 gchar *user_cache_dir;
72 GMutex connection_lock;
73 ConnectionOp *connection_op;
74 CamelServiceConnectionStatus status;
77 /* This is copied from EAsyncClosure in libedataserver.
78 * If this proves useful elsewhere in Camel we may want
79 * to split this out and make it part of the public API. */
80 struct _AsyncClosure {
82 GMainContext *context;
86 struct _AsyncContext {
88 gchar *auth_mechanism;
89 CamelAuthenticationResult auth_result;
92 /* The GQueue is only modified while CamelService's
93 * connection_lock is held, so it does not need its
95 struct _ConnectionOp {
96 volatile gint ref_count;
99 GSimpleAsyncResult *simple;
100 GCancellable *cancellable;
106 PROP_CONNECTION_STATUS,
115 /* Forward Declarations */
116 void camel_network_service_init (CamelNetworkService *service);
117 static void camel_service_initable_init (GInitableIface *interface);
119 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (
120 CamelService, camel_service, CAMEL_TYPE_OBJECT,
121 G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, camel_service_initable_init))
123 static AsyncClosure *
124 async_closure_new (void)
126 AsyncClosure *closure;
128 closure = g_slice_new0 (AsyncClosure);
129 closure->context = g_main_context_new ();
130 closure->loop = g_main_loop_new (closure->context, FALSE);
132 g_main_context_push_thread_default (closure->context);
137 static GAsyncResult *
138 async_closure_wait (AsyncClosure *closure)
140 g_return_val_if_fail (closure != NULL, NULL);
142 g_main_loop_run (closure->loop);
144 return closure->result;
148 async_closure_free (AsyncClosure *closure)
150 g_return_if_fail (closure != NULL);
152 g_main_context_pop_thread_default (closure->context);
154 g_main_loop_unref (closure->loop);
155 g_main_context_unref (closure->context);
157 if (closure->result != NULL)
158 g_object_unref (closure->result);
160 g_slice_free (AsyncClosure, closure);
164 async_closure_callback (GObject *object,
165 GAsyncResult *result,
168 AsyncClosure *real_closure;
170 g_return_if_fail (G_IS_OBJECT (object));
171 g_return_if_fail (G_IS_ASYNC_RESULT (result));
172 g_return_if_fail (closure != NULL);
174 real_closure = closure;
176 /* Replace any previous result. */
177 if (real_closure->result != NULL)
178 g_object_unref (real_closure->result);
179 real_closure->result = g_object_ref (result);
181 g_main_loop_quit (real_closure->loop);
185 async_context_free (AsyncContext *async_context)
187 g_list_free (async_context->auth_types);
189 g_free (async_context->auth_mechanism);
191 g_slice_free (AsyncContext, async_context);
194 static ConnectionOp *
195 connection_op_new (GSimpleAsyncResult *simple,
196 GCancellable *cancellable)
200 op = g_slice_new0 (ConnectionOp);
202 g_mutex_init (&op->simple_lock);
203 op->simple = g_object_ref (simple);
205 if (G_IS_CANCELLABLE (cancellable))
206 op->cancellable = g_object_ref (cancellable);
211 static ConnectionOp *
212 connection_op_ref (ConnectionOp *op)
214 g_return_val_if_fail (op != NULL, NULL);
215 g_return_val_if_fail (op->ref_count > 0, NULL);
217 g_atomic_int_inc (&op->ref_count);
223 connection_op_unref (ConnectionOp *op)
225 g_return_if_fail (op != NULL);
226 g_return_if_fail (op->ref_count > 0);
228 if (g_atomic_int_dec_and_test (&op->ref_count)) {
230 /* The pending queue should be empty. */
231 g_warn_if_fail (g_queue_is_empty (&op->pending));
233 g_mutex_clear (&op->simple_lock);
235 if (op->simple != NULL)
236 g_object_unref (op->simple);
238 if (op->cancel_id > 0)
239 g_cancellable_disconnect (
240 op->cancellable, op->cancel_id);
242 if (op->cancellable != NULL)
243 g_object_unref (op->cancellable);
245 g_slice_free (ConnectionOp, op);
250 connection_op_complete (ConnectionOp *op,
253 g_mutex_lock (&op->simple_lock);
255 if (op->simple != NULL && error != NULL)
256 g_simple_async_result_set_from_error (op->simple, error);
258 if (op->simple != NULL) {
259 g_simple_async_result_complete_in_idle (op->simple);
260 g_object_unref (op->simple);
264 g_mutex_unlock (&op->simple_lock);
268 connection_op_cancelled (GCancellable *cancellable,
271 /* Because we called g_simple_async_result_set_check_cancellable()
272 * we don't need to explicitly set a G_IO_ERROR_CANCELLED here. */
273 connection_op_complete (op, NULL);
277 connection_op_add_pending (ConnectionOp *op,
278 GSimpleAsyncResult *simple,
279 GCancellable *cancellable)
281 ConnectionOp *pending_op;
283 g_return_if_fail (op != NULL);
285 pending_op = connection_op_new (simple, cancellable);
287 if (pending_op->cancellable != NULL)
288 pending_op->cancel_id = g_cancellable_connect (
289 pending_op->cancellable,
290 G_CALLBACK (connection_op_cancelled),
291 pending_op, (GDestroyNotify) NULL);
293 g_queue_push_tail (&op->pending, pending_op);
297 connection_op_complete_pending (ConnectionOp *op,
300 ConnectionOp *pending_op;
302 g_return_if_fail (op != NULL);
304 while (!g_queue_is_empty (&op->pending)) {
305 pending_op = g_queue_pop_head (&op->pending);
306 connection_op_complete (pending_op, error);
307 connection_op_unref (pending_op);
312 service_find_old_data_dir (CamelService *service)
314 CamelProvider *provider;
315 CamelSession *session;
318 gboolean allows_host;
319 gboolean allows_user;
323 const gchar *base_dir;
326 provider = camel_service_get_provider (service);
327 url = camel_service_new_camel_url (service);
329 allows_host = CAMEL_PROVIDER_ALLOWS (provider, CAMEL_URL_PART_HOST);
330 allows_user = CAMEL_PROVIDER_ALLOWS (provider, CAMEL_URL_PART_USER);
332 needs_host = CAMEL_PROVIDER_NEEDS (provider, CAMEL_URL_PART_HOST);
333 needs_path = CAMEL_PROVIDER_NEEDS (provider, CAMEL_URL_PART_PATH);
334 needs_user = CAMEL_PROVIDER_NEEDS (provider, CAMEL_URL_PART_USER);
336 /* This function reproduces the way service data directories used
337 * to be determined before we moved to just using the UID. If the
338 * old data directory exists, try renaming it to the new form.
340 * A virtual class method was used to determine the directory path,
341 * but no known CamelProviders ever overrode the default algorithm
342 * below. So this should work for everyone. */
344 path = g_string_new (provider->protocol);
347 g_string_append_c (path, '/');
348 if (url->user != NULL)
349 g_string_append (path, url->user);
351 g_string_append_c (path, '@');
352 if (url->host != NULL)
353 g_string_append (path, url->host);
355 g_string_append_c (path, ':');
356 g_string_append_printf (path, "%d", url->port);
358 } else if (!needs_user) {
359 g_string_append_c (path, '@');
362 } else if (allows_host) {
363 g_string_append_c (path, '/');
365 g_string_append_c (path, '@');
366 if (url->host != NULL)
367 g_string_append (path, url->host);
369 g_string_append_c (path, ':');
370 g_string_append_printf (path, "%d", url->port);
374 if (needs_path && url->path) {
375 if (*url->path != '/')
376 g_string_append_c (path, '/');
377 g_string_append (path, url->path);
380 session = camel_service_ref_session (service);
382 base_dir = camel_session_get_user_data_dir (session);
383 old_data_dir = g_build_filename (base_dir, path->str, NULL);
385 g_object_unref (session);
387 g_string_free (path, TRUE);
389 if (!g_file_test (old_data_dir, G_FILE_TEST_IS_DIR)) {
390 g_free (old_data_dir);
394 camel_url_free (url);
400 service_notify_connection_status_cb (gpointer user_data)
402 CamelService *service = CAMEL_SERVICE (user_data);
404 g_object_notify (G_OBJECT (service), "connection-status");
410 service_queue_notify_connection_status (CamelService *service)
412 CamelSession *session;
414 session = camel_service_ref_session (service);
416 /* Prioritize ahead of GTK+ redraws. */
417 camel_session_idle_add (
418 session, G_PRIORITY_HIGH_IDLE,
419 service_notify_connection_status_cb,
420 g_object_ref (service),
421 (GDestroyNotify) g_object_unref);
423 g_object_unref (session);
427 service_shared_connect_cb (GObject *source_object,
428 GAsyncResult *result,
431 CamelService *service;
432 CamelServiceClass *class;
433 ConnectionOp *op = user_data;
435 GError *error = NULL;
437 /* This avoids a compiler warning
438 * in the CAMEL_CHECK_GERROR macro. */
439 GError **p_error = &error;
441 service = CAMEL_SERVICE (source_object);
442 class = CAMEL_SERVICE_GET_CLASS (service);
443 g_return_if_fail (class->connect_finish != NULL);
445 success = class->connect_finish (service, result, &error);
446 CAMEL_CHECK_GERROR (service, connect_sync, success, p_error);
448 g_mutex_lock (&service->priv->connection_lock);
450 if (service->priv->connection_op == op) {
451 connection_op_unref (service->priv->connection_op);
452 service->priv->connection_op = NULL;
454 service->priv->status = CAMEL_SERVICE_CONNECTED;
456 service->priv->status = CAMEL_SERVICE_DISCONNECTED;
457 service_queue_notify_connection_status (service);
460 connection_op_complete (op, error);
461 connection_op_complete_pending (op, error);
463 g_mutex_unlock (&service->priv->connection_lock);
465 connection_op_unref (op);
466 g_clear_error (&error);
470 service_shared_disconnect_cb (GObject *source_object,
471 GAsyncResult *result,
474 CamelService *service;
475 CamelServiceClass *class;
476 ConnectionOp *op = user_data;
478 GError *error = NULL;
480 /* This avoids a compiler warning
481 * in the CAMEL_CHECK_GERROR macro. */
482 GError **p_error = &error;
484 service = CAMEL_SERVICE (source_object);
485 class = CAMEL_SERVICE_GET_CLASS (service);
486 g_return_if_fail (class->disconnect_finish != NULL);
488 success = class->disconnect_finish (service, result, &error);
489 CAMEL_CHECK_GERROR (service, disconnect_sync, success, p_error);
491 g_mutex_lock (&service->priv->connection_lock);
493 if (service->priv->connection_op == op) {
494 connection_op_unref (service->priv->connection_op);
495 service->priv->connection_op = NULL;
497 service->priv->status = CAMEL_SERVICE_DISCONNECTED;
499 service->priv->status = CAMEL_SERVICE_CONNECTED;
500 service_queue_notify_connection_status (service);
503 connection_op_complete (op, error);
504 connection_op_complete_pending (op, error);
506 g_mutex_unlock (&service->priv->connection_lock);
508 connection_op_unref (op);
509 g_clear_error (&error);
513 service_set_provider (CamelService *service,
514 CamelProvider *provider)
516 g_return_if_fail (provider != NULL);
517 g_return_if_fail (service->priv->provider == NULL);
519 service->priv->provider = provider;
523 service_set_session (CamelService *service,
524 CamelSession *session)
526 g_return_if_fail (CAMEL_IS_SESSION (session));
528 g_weak_ref_set (&service->priv->session, session);
532 service_set_uid (CamelService *service,
535 g_return_if_fail (uid != NULL);
536 g_return_if_fail (service->priv->uid == NULL);
538 service->priv->uid = g_strdup (uid);
542 service_set_property (GObject *object,
547 switch (property_id) {
548 case PROP_DISPLAY_NAME:
549 camel_service_set_display_name (
550 CAMEL_SERVICE (object),
551 g_value_get_string (value));
555 camel_service_set_password (
556 CAMEL_SERVICE (object),
557 g_value_get_string (value));
561 service_set_provider (
562 CAMEL_SERVICE (object),
563 g_value_get_pointer (value));
567 service_set_session (
568 CAMEL_SERVICE (object),
569 g_value_get_object (value));
573 camel_service_set_settings (
574 CAMEL_SERVICE (object),
575 g_value_get_object (value));
580 CAMEL_SERVICE (object),
581 g_value_get_string (value));
585 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
589 service_get_property (GObject *object,
594 switch (property_id) {
595 case PROP_CONNECTION_STATUS:
597 value, camel_service_get_connection_status (
598 CAMEL_SERVICE (object)));
601 case PROP_DISPLAY_NAME:
603 value, camel_service_get_display_name (
604 CAMEL_SERVICE (object)));
609 value, camel_service_get_password (
610 CAMEL_SERVICE (object)));
614 g_value_set_pointer (
615 value, camel_service_get_provider (
616 CAMEL_SERVICE (object)));
620 g_value_take_object (
621 value, camel_service_ref_session (
622 CAMEL_SERVICE (object)));
626 g_value_take_object (
627 value, camel_service_ref_settings (
628 CAMEL_SERVICE (object)));
633 value, camel_service_get_uid (
634 CAMEL_SERVICE (object)));
638 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
642 service_dispose (GObject *object)
644 CamelServicePrivate *priv;
646 priv = CAMEL_SERVICE_GET_PRIVATE (object);
648 g_weak_ref_set (&priv->session, NULL);
650 if (priv->settings != NULL) {
651 g_object_unref (priv->settings);
652 priv->settings = NULL;
655 /* Chain up to parent's dispose() method. */
656 G_OBJECT_CLASS (camel_service_parent_class)->dispose (object);
660 service_finalize (GObject *object)
662 CamelServicePrivate *priv;
664 priv = CAMEL_SERVICE_GET_PRIVATE (object);
666 if (priv->status == CAMEL_SERVICE_CONNECTED)
667 CAMEL_SERVICE_GET_CLASS (object)->disconnect_sync (
668 CAMEL_SERVICE (object), TRUE, NULL, NULL);
670 g_mutex_clear (&priv->settings_lock);
672 g_free (priv->display_name);
673 g_free (priv->user_data_dir);
674 g_free (priv->user_cache_dir);
676 g_free (priv->password);
678 /* There should be no outstanding connection operations. */
679 g_warn_if_fail (priv->connection_op == NULL);
680 g_mutex_clear (&priv->connection_lock);
682 /* Chain up to parent's finalize() method. */
683 G_OBJECT_CLASS (camel_service_parent_class)->finalize (object);
687 service_constructed (GObject *object)
689 CamelService *service;
690 CamelSession *session;
691 const gchar *base_dir;
694 /* Chain up to parent's constructed() method. */
695 G_OBJECT_CLASS (camel_service_parent_class)->constructed (object);
697 service = CAMEL_SERVICE (object);
698 session = camel_service_ref_session (service);
700 uid = camel_service_get_uid (service);
702 base_dir = camel_session_get_user_data_dir (session);
703 service->priv->user_data_dir = g_build_filename (base_dir, uid, NULL);
705 base_dir = camel_session_get_user_cache_dir (session);
706 service->priv->user_cache_dir = g_build_filename (base_dir, uid, NULL);
708 g_object_unref (session);
710 /* The CamelNetworkService interface needs initialization. */
711 if (CAMEL_IS_NETWORK_SERVICE (service))
712 camel_network_service_init (CAMEL_NETWORK_SERVICE (service));
716 service_get_name (CamelService *service,
720 "%s does not implement CamelServiceClass::get_name()",
721 G_OBJECT_TYPE_NAME (service));
723 return g_strdup (G_OBJECT_TYPE_NAME (service));
727 service_connect_sync (CamelService *service,
728 GCancellable *cancellable,
731 /* Default behavior for local storage providers. */
736 service_disconnect_sync (CamelService *service,
738 GCancellable *cancellable,
741 /* Default behavior for local storage providers. */
746 service_query_auth_types_sync (CamelService *service,
747 GCancellable *cancellable,
754 service_connect_thread (GSimpleAsyncResult *simple,
756 GCancellable *cancellable)
758 CamelService *service;
759 CamelServiceClass *class;
760 GError *error = NULL;
762 /* Note we call the class method directly here. */
764 service = CAMEL_SERVICE (object);
766 class = CAMEL_SERVICE_GET_CLASS (service);
767 g_return_if_fail (class->connect_sync != NULL);
769 class->connect_sync (service, cancellable, &error);
772 g_simple_async_result_take_error (simple, error);
776 service_connect (CamelService *service,
778 GCancellable *cancellable,
779 GAsyncReadyCallback callback,
782 GSimpleAsyncResult *simple;
784 simple = g_simple_async_result_new (
785 G_OBJECT (service), callback, user_data, service_connect);
787 g_simple_async_result_set_check_cancellable (simple, cancellable);
789 g_simple_async_result_run_in_thread (
790 simple, service_connect_thread, io_priority, cancellable);
792 g_object_unref (simple);
796 service_connect_finish (CamelService *service,
797 GAsyncResult *result,
800 GSimpleAsyncResult *simple;
802 g_return_val_if_fail (
803 g_simple_async_result_is_valid (
804 result, G_OBJECT (service), service_connect), FALSE);
806 simple = G_SIMPLE_ASYNC_RESULT (result);
808 /* Assume success unless a GError is set. */
809 return !g_simple_async_result_propagate_error (simple, error);
813 service_disconnect_thread (GSimpleAsyncResult *simple,
815 GCancellable *cancellable)
817 CamelService *service;
818 CamelServiceClass *class;
820 GError *error = NULL;
822 /* Note we call the class method directly here. */
824 service = CAMEL_SERVICE (object);
825 clean = g_simple_async_result_get_op_res_gboolean (simple);
827 class = CAMEL_SERVICE_GET_CLASS (service);
828 g_return_if_fail (class->disconnect_sync != NULL);
830 class->disconnect_sync (service, clean, cancellable, &error);
833 g_simple_async_result_take_error (simple, error);
837 service_disconnect (CamelService *service,
840 GCancellable *cancellable,
841 GAsyncReadyCallback callback,
844 GSimpleAsyncResult *simple;
846 simple = g_simple_async_result_new (
847 G_OBJECT (service), callback, user_data, service_disconnect);
849 g_simple_async_result_set_check_cancellable (simple, cancellable);
851 g_simple_async_result_set_op_res_gboolean (simple, clean);
853 g_simple_async_result_run_in_thread (
854 simple, service_disconnect_thread, io_priority, cancellable);
856 g_object_unref (simple);
860 service_disconnect_finish (CamelService *service,
861 GAsyncResult *result,
864 GSimpleAsyncResult *simple;
866 g_return_val_if_fail (
867 g_simple_async_result_is_valid (
868 result, G_OBJECT (service), service_disconnect), FALSE);
870 simple = G_SIMPLE_ASYNC_RESULT (result);
872 /* Assume success unless a GError is set. */
873 return !g_simple_async_result_propagate_error (simple, error);
877 service_authenticate_thread (GSimpleAsyncResult *simple,
879 GCancellable *cancellable)
881 AsyncContext *async_context;
882 GError *error = NULL;
884 async_context = g_simple_async_result_get_op_res_gpointer (simple);
886 async_context->auth_result = camel_service_authenticate_sync (
887 CAMEL_SERVICE (object), async_context->auth_mechanism,
888 cancellable, &error);
891 g_simple_async_result_take_error (simple, error);
895 service_authenticate (CamelService *service,
896 const gchar *mechanism,
898 GCancellable *cancellable,
899 GAsyncReadyCallback callback,
902 GSimpleAsyncResult *simple;
903 AsyncContext *async_context;
905 async_context = g_slice_new0 (AsyncContext);
906 async_context->auth_mechanism = g_strdup (mechanism);
908 simple = g_simple_async_result_new (
909 G_OBJECT (service), callback, user_data, service_authenticate);
911 g_simple_async_result_set_check_cancellable (simple, cancellable);
913 g_simple_async_result_set_op_res_gpointer (
914 simple, async_context, (GDestroyNotify) async_context_free);
916 g_simple_async_result_run_in_thread (
917 simple, service_authenticate_thread, io_priority, cancellable);
919 g_object_unref (simple);
922 static CamelAuthenticationResult
923 service_authenticate_finish (CamelService *service,
924 GAsyncResult *result,
927 GSimpleAsyncResult *simple;
928 AsyncContext *async_context;
930 g_return_val_if_fail (
931 g_simple_async_result_is_valid (
932 result, G_OBJECT (service), service_authenticate),
933 CAMEL_AUTHENTICATION_REJECTED);
935 simple = G_SIMPLE_ASYNC_RESULT (result);
936 async_context = g_simple_async_result_get_op_res_gpointer (simple);
938 if (g_simple_async_result_propagate_error (simple, error))
939 return CAMEL_AUTHENTICATION_ERROR;
941 return async_context->auth_result;
945 service_query_auth_types_thread (GSimpleAsyncResult *simple,
947 GCancellable *cancellable)
949 AsyncContext *async_context;
950 GError *error = NULL;
952 async_context = g_simple_async_result_get_op_res_gpointer (simple);
954 async_context->auth_types = camel_service_query_auth_types_sync (
955 CAMEL_SERVICE (object), cancellable, &error);
958 g_simple_async_result_take_error (simple, error);
962 service_query_auth_types (CamelService *service,
964 GCancellable *cancellable,
965 GAsyncReadyCallback callback,
968 GSimpleAsyncResult *simple;
969 AsyncContext *async_context;
971 async_context = g_slice_new0 (AsyncContext);
973 simple = g_simple_async_result_new (
974 G_OBJECT (service), callback,
975 user_data, service_query_auth_types);
977 g_simple_async_result_set_check_cancellable (simple, cancellable);
979 g_simple_async_result_set_op_res_gpointer (
980 simple, async_context, (GDestroyNotify) async_context_free);
982 g_simple_async_result_run_in_thread (
983 simple, service_query_auth_types_thread,
984 io_priority, cancellable);
986 g_object_unref (simple);
990 service_query_auth_types_finish (CamelService *service,
991 GAsyncResult *result,
994 GSimpleAsyncResult *simple;
995 AsyncContext *async_context;
997 g_return_val_if_fail (
998 g_simple_async_result_is_valid (
999 result, G_OBJECT (service),
1000 service_query_auth_types), NULL);
1002 simple = G_SIMPLE_ASYNC_RESULT (result);
1003 async_context = g_simple_async_result_get_op_res_gpointer (simple);
1005 if (g_simple_async_result_propagate_error (simple, error))
1008 return g_list_copy (async_context->auth_types);
1012 service_initable_init (GInitable *initable,
1013 GCancellable *cancellable,
1016 /* Nothing to do here, but we may need add something in the future.
1017 * For now this is a placeholder so subclasses can safely chain up. */
1023 camel_service_class_init (CamelServiceClass *class)
1025 GObjectClass *object_class;
1027 g_type_class_add_private (class, sizeof (CamelServicePrivate));
1029 object_class = G_OBJECT_CLASS (class);
1030 object_class->set_property = service_set_property;
1031 object_class->get_property = service_get_property;
1032 object_class->dispose = service_dispose;
1033 object_class->finalize = service_finalize;
1034 object_class->constructed = service_constructed;
1036 class->settings_type = CAMEL_TYPE_SETTINGS;
1037 class->get_name = service_get_name;
1038 class->connect_sync = service_connect_sync;
1039 class->disconnect_sync = service_disconnect_sync;
1040 class->query_auth_types_sync = service_query_auth_types_sync;
1042 class->connect = service_connect;
1043 class->connect_finish = service_connect_finish;
1044 class->disconnect = service_disconnect;
1045 class->disconnect_finish = service_disconnect_finish;
1046 class->authenticate = service_authenticate;
1047 class->authenticate_finish = service_authenticate_finish;
1048 class->query_auth_types = service_query_auth_types;
1049 class->query_auth_types_finish = service_query_auth_types_finish;
1051 g_object_class_install_property (
1053 PROP_CONNECTION_STATUS,
1055 "connection-status",
1056 "Connection Status",
1057 "The connection status for the service",
1058 CAMEL_TYPE_SERVICE_CONNECTION_STATUS,
1059 CAMEL_SERVICE_DISCONNECTED,
1061 G_PARAM_STATIC_STRINGS));
1063 g_object_class_install_property (
1066 g_param_spec_string (
1069 "The display name for the service",
1073 G_PARAM_STATIC_STRINGS));
1075 g_object_class_install_property (
1078 g_param_spec_string (
1081 "The password for the service",
1085 G_PARAM_STATIC_STRINGS));
1087 g_object_class_install_property (
1090 g_param_spec_pointer (
1093 "The CamelProvider for the service",
1095 G_PARAM_CONSTRUCT_ONLY |
1096 G_PARAM_STATIC_STRINGS));
1098 g_object_class_install_property (
1101 g_param_spec_object (
1104 "A CamelSession instance",
1107 G_PARAM_CONSTRUCT_ONLY |
1108 G_PARAM_STATIC_STRINGS));
1110 g_object_class_install_property (
1113 g_param_spec_object (
1116 "A CamelSettings instance",
1117 CAMEL_TYPE_SETTINGS,
1120 G_PARAM_STATIC_STRINGS));
1122 g_object_class_install_property (
1125 g_param_spec_string (
1128 "The unique identity of the service",
1131 G_PARAM_CONSTRUCT_ONLY |
1132 G_PARAM_STATIC_STRINGS));
1136 camel_service_initable_init (GInitableIface *interface)
1138 interface->init = service_initable_init;
1142 camel_service_init (CamelService *service)
1144 service->priv = CAMEL_SERVICE_GET_PRIVATE (service);
1146 g_mutex_init (&service->priv->settings_lock);
1147 g_mutex_init (&service->priv->connection_lock);
1148 service->priv->status = CAMEL_SERVICE_DISCONNECTED;
1151 G_DEFINE_QUARK (camel-service-error-quark, camel_service_error)
1154 * camel_service_migrate_files:
1155 * @service: a #CamelService
1157 * Performs any necessary file migrations for @service. This should be
1158 * called after installing or configuring the @service's #CamelSettings,
1159 * since it requires building a URL string for @service.
1164 camel_service_migrate_files (CamelService *service)
1166 const gchar *new_data_dir;
1167 gchar *old_data_dir;
1169 g_return_if_fail (CAMEL_IS_SERVICE (service));
1171 new_data_dir = camel_service_get_user_data_dir (service);
1172 old_data_dir = service_find_old_data_dir (service);
1174 /* If the old data directory name exists, try renaming
1175 * it to the new data directory. Failure is non-fatal. */
1176 if (old_data_dir != NULL) {
1177 g_rename (old_data_dir, new_data_dir);
1178 g_free (old_data_dir);
1183 * camel_service_new_camel_url:
1184 * @service: a #CamelService
1186 * Returns a new #CamelURL representing @service.
1187 * Free the returned #CamelURL with camel_url_free().
1189 * Returns: a new #CamelURL
1194 camel_service_new_camel_url (CamelService *service)
1197 CamelProvider *provider;
1198 CamelSettings *settings;
1204 g_return_val_if_fail (CAMEL_IS_SERVICE (service), NULL);
1206 provider = camel_service_get_provider (service);
1207 g_return_val_if_fail (provider != NULL, NULL);
1209 settings = camel_service_ref_settings (service);
1211 /* Allocate as camel_url_new_with_base() does. */
1212 url = g_new0 (CamelURL, 1);
1214 if (CAMEL_IS_NETWORK_SETTINGS (settings)) {
1215 CamelNetworkSettings *network_settings;
1217 network_settings = CAMEL_NETWORK_SETTINGS (settings);
1218 host = camel_network_settings_dup_host (network_settings);
1219 port = camel_network_settings_get_port (network_settings);
1220 user = camel_network_settings_dup_user (network_settings);
1223 if (CAMEL_IS_LOCAL_SETTINGS (settings)) {
1224 CamelLocalSettings *local_settings;
1226 local_settings = CAMEL_LOCAL_SETTINGS (settings);
1227 path = camel_local_settings_dup_path (local_settings);
1230 camel_url_set_protocol (url, provider->protocol);
1231 camel_url_set_host (url, host);
1232 camel_url_set_port (url, port);
1233 camel_url_set_user (url, user);
1234 camel_url_set_path (url, path);
1240 g_object_unref (settings);
1246 * camel_service_get_connection_status:
1247 * @service: a #CamelService
1249 * Returns the connection status for @service.
1251 * Returns: the connection status
1255 CamelServiceConnectionStatus
1256 camel_service_get_connection_status (CamelService *service)
1258 g_return_val_if_fail (
1259 CAMEL_IS_SERVICE (service),
1260 CAMEL_SERVICE_DISCONNECTED);
1262 return service->priv->status;
1266 * camel_service_get_display_name:
1267 * @service: a #CamelService
1269 * Returns the display name for @service, or %NULL if @service has not
1270 * been given a display name. The display name is intended for use in
1271 * a user interface and should generally be given a user-defined name.
1273 * Compare this with camel_service_get_name(), which returns a built-in
1274 * description of the type of service (IMAP, SMTP, etc.).
1276 * Returns: the display name for @service, or %NULL
1281 camel_service_get_display_name (CamelService *service)
1283 g_return_val_if_fail (CAMEL_IS_SERVICE (service), NULL);
1285 return service->priv->display_name;
1289 * camel_service_set_display_name:
1290 * @service: a #CamelService
1291 * @display_name: a valid UTF-8 string, or %NULL
1293 * Assigns a UTF-8 display name to @service. The display name is intended
1294 * for use in a user interface and should generally be given a user-defined
1297 * Compare this with camel_service_get_name(), which returns a built-in
1298 * description of the type of service (IMAP, SMTP, etc.).
1303 camel_service_set_display_name (CamelService *service,
1304 const gchar *display_name)
1306 g_return_if_fail (CAMEL_IS_SERVICE (service));
1308 if (g_strcmp0 (service->priv->display_name, display_name) == 0)
1311 if (display_name != NULL)
1312 g_return_if_fail (g_utf8_validate (display_name, -1, NULL));
1314 g_free (service->priv->display_name);
1315 service->priv->display_name = g_strdup (display_name);
1317 g_object_notify (G_OBJECT (service), "display-name");
1321 * camel_service_get_password:
1322 * @service: a #CamelService
1324 * Returns the password for @service. Some SASL mechanisms use this
1325 * when attempting to authenticate.
1327 * Returns: the password for @service
1332 camel_service_get_password (CamelService *service)
1334 g_return_val_if_fail (CAMEL_IS_SERVICE (service), NULL);
1336 return service->priv->password;
1340 * camel_service_set_password:
1341 * @service: a #CamelService
1342 * @password: the password for @service
1344 * Sets the password for @service. Use this function to cache the password
1345 * in memory after obtaining it through camel_session_get_password(). Some
1346 * SASL mechanisms use this when attempting to authenticate.
1351 camel_service_set_password (CamelService *service,
1352 const gchar *password)
1354 g_return_if_fail (CAMEL_IS_SERVICE (service));
1356 if (g_strcmp0 (service->priv->password, password) == 0)
1359 g_free (service->priv->password);
1360 service->priv->password = g_strdup (password);
1362 g_object_notify (G_OBJECT (service), "password");
1366 * camel_service_get_user_data_dir:
1367 * @service: a #CamelService
1369 * Returns the base directory under which to store user-specific data
1370 * for @service. The directory is formed by appending the directory
1371 * returned by camel_session_get_user_data_dir() with the service's
1372 * #CamelService:uid value.
1374 * Returns: the base directory for @service
1379 camel_service_get_user_data_dir (CamelService *service)
1381 g_return_val_if_fail (CAMEL_IS_SERVICE (service), NULL);
1383 return service->priv->user_data_dir;
1387 * camel_service_get_user_cache_dir:
1388 * @service: a #CamelService
1390 * Returns the base directory under which to store cache data
1391 * for @service. The directory is formed by appending the directory
1392 * returned by camel_session_get_user_cache_dir() with the service's
1393 * #CamelService:uid value.
1395 * Returns: the base cache directory for @service
1400 camel_service_get_user_cache_dir (CamelService *service)
1402 g_return_val_if_fail (CAMEL_IS_SERVICE (service), NULL);
1404 return service->priv->user_cache_dir;
1408 * camel_service_get_name:
1409 * @service: a #CamelService
1410 * @brief: whether or not to use a briefer form
1412 * This gets the name of the service in a "friendly" (suitable for
1413 * humans) form. If @brief is %TRUE, this should be a brief description
1414 * such as for use in the folder tree. If @brief is %FALSE, it should
1415 * be a more complete and mostly unambiguous description.
1417 * Returns: a description of the service which the caller must free
1420 camel_service_get_name (CamelService *service,
1423 CamelServiceClass *class;
1425 g_return_val_if_fail (CAMEL_IS_SERVICE (service), NULL);
1427 class = CAMEL_SERVICE_GET_CLASS (service);
1428 g_return_val_if_fail (class->get_name != NULL, NULL);
1430 return class->get_name (service, brief);
1434 * camel_service_get_provider:
1435 * @service: a #CamelService
1437 * Gets the #CamelProvider associated with the service.
1439 * Returns: the #CamelProvider
1442 camel_service_get_provider (CamelService *service)
1444 g_return_val_if_fail (CAMEL_IS_SERVICE (service), NULL);
1446 return service->priv->provider;
1450 * camel_service_ref_session:
1451 * @service: a #CamelService
1453 * Returns the #CamelSession associated with the service.
1455 * The returned #CamelSession is referenced for thread-safety. Unreference
1456 * the #CamelSession with g_object_unref() when finished with it.
1458 * Returns: the #CamelSession
1463 camel_service_ref_session (CamelService *service)
1465 g_return_val_if_fail (CAMEL_IS_SERVICE (service), NULL);
1467 return g_weak_ref_get (&service->priv->session);
1471 * camel_service_get_session:
1472 * @service: a #CamelService
1474 * Returns the #CamelSession associated with the service.
1476 * Note this function is not thread-safe. The returned #CamelSession could
1477 * be finalized by another thread while the caller is still using it.
1479 * Returns: the #CamelSession
1481 * Deprecated: 3.8: Use camel_service_ref_session() instead.
1484 camel_service_get_session (CamelService *service)
1486 CamelSession *session;
1488 g_return_val_if_fail (CAMEL_IS_SERVICE (service), NULL);
1490 session = camel_service_ref_session (service);
1492 /* XXX Drop the CamelSession reference for backward-compatibility.
1493 * This is risky. Without a reference, the CamelSession could
1494 * be finalized while the caller is still using it. */
1495 if (session != NULL)
1496 g_object_unref (session);
1502 * camel_service_ref_settings:
1503 * @service: a #CamelService
1505 * Returns the #CamelSettings instance associated with the service.
1507 * The returned #CamelSettings is referenced for thread-safety and must
1508 * be unreferenced with g_object_unref() when finished with it.
1510 * Returns: the #CamelSettings
1515 camel_service_ref_settings (CamelService *service)
1517 CamelSettings *settings;
1519 g_return_val_if_fail (CAMEL_IS_SERVICE (service), NULL);
1521 /* Every service should have a settings object. */
1522 g_return_val_if_fail (service->priv->settings != NULL, NULL);
1524 g_mutex_lock (&service->priv->settings_lock);
1526 settings = g_object_ref (service->priv->settings);
1528 g_mutex_unlock (&service->priv->settings_lock);
1534 * camel_service_set_settings:
1535 * @service: a #CamelService
1536 * @settings: an instance derviced from #CamelSettings, or %NULL
1538 * Associates a new #CamelSettings instance with the service.
1539 * The @settings instance must match the settings type defined in
1540 * #CamelServiceClass. If @settings is %NULL, a new #CamelSettings
1541 * instance of the appropriate type is created with all properties
1547 camel_service_set_settings (CamelService *service,
1548 CamelSettings *settings)
1550 CamelServiceClass *class;
1552 g_return_if_fail (CAMEL_IS_SERVICE (service));
1554 class = CAMEL_SERVICE_GET_CLASS (service);
1556 if (settings != NULL) {
1559 G_OBJECT_TYPE (settings),
1560 class->settings_type));
1561 g_object_ref (settings);
1566 class->settings_type,
1567 CAMEL_TYPE_SETTINGS));
1568 settings = g_object_new (class->settings_type, NULL);
1571 g_mutex_lock (&service->priv->settings_lock);
1573 if (service->priv->settings != NULL)
1574 g_object_unref (service->priv->settings);
1576 service->priv->settings = settings; /* takes ownership */
1578 g_mutex_unlock (&service->priv->settings_lock);
1580 g_object_notify (G_OBJECT (service), "settings");
1584 * camel_service_get_uid:
1585 * @service: a #CamelService
1587 * Gets the unique identifier string associated with the service.
1589 * Returns: the UID string
1594 camel_service_get_uid (CamelService *service)
1596 g_return_val_if_fail (CAMEL_IS_SERVICE (service), NULL);
1598 return service->priv->uid;
1602 * camel_service_connect_sync:
1603 * @service: a #CamelService
1604 * @cancellable: optional #GCancellable object, or %NULL
1605 * @error: return location for a #GError, or %NULL
1607 * Connects @service to a remote server using the information in its
1608 * #CamelService:settings instance.
1610 * If a connect operation is already in progress when this function is
1611 * called, its results will be reflected in this connect operation.
1613 * Returns: %TRUE if the connection is made or %FALSE otherwise
1618 camel_service_connect_sync (CamelService *service,
1619 GCancellable *cancellable,
1622 AsyncClosure *closure;
1623 GAsyncResult *result;
1626 g_return_val_if_fail (CAMEL_IS_SERVICE (service), FALSE);
1628 closure = async_closure_new ();
1630 camel_service_connect (
1631 service, G_PRIORITY_DEFAULT, cancellable,
1632 async_closure_callback, closure);
1634 result = async_closure_wait (closure);
1636 success = camel_service_connect_finish (service, result, error);
1638 async_closure_free (closure);
1644 * camel_service_connect:
1645 * @service: a #CamelService
1646 * @io_priority: the I/O priority of the request
1647 * @cancellable: optional #GCancellable object, or %NULL
1648 * @callback: a #GAsyncReadyCallback to call when the request is satisfied
1649 * @user_data: data to pass to the callback function
1651 * Asynchronously connects @service to a remote server using the information
1652 * in its #CamelService:settings instance.
1654 * If a connect operation is already in progress when this function is
1655 * called, its results will be reflected in this connect operation.
1657 * If any disconnect operations are in progress when this function is
1658 * called, they will be cancelled.
1660 * When the operation is finished, @callback will be called. You can
1661 * then call camel_service_connect_finish() to get the result of the
1667 camel_service_connect (CamelService *service,
1669 GCancellable *cancellable,
1670 GAsyncReadyCallback callback,
1674 CamelServiceClass *class;
1675 GSimpleAsyncResult *simple;
1677 g_return_if_fail (CAMEL_IS_SERVICE (service));
1679 class = CAMEL_SERVICE_GET_CLASS (service);
1680 g_return_if_fail (class->connect != NULL);
1682 simple = g_simple_async_result_new (
1683 G_OBJECT (service), callback,
1684 user_data, camel_service_connect);
1686 g_simple_async_result_set_check_cancellable (simple, cancellable);
1688 g_mutex_lock (&service->priv->connection_lock);
1690 switch (service->priv->status) {
1692 /* If a connect operation is already in progress,
1693 * queue this operation so it completes at the same
1694 * time the first connect operation completes. */
1695 case CAMEL_SERVICE_CONNECTING:
1696 connection_op_add_pending (
1697 service->priv->connection_op,
1698 simple, cancellable);
1701 /* If we're already connected, just report success. */
1702 case CAMEL_SERVICE_CONNECTED:
1703 g_simple_async_result_complete_in_idle (simple);
1706 /* If a disconnect operation is currently in progress,
1707 * cancel it and make room for the connect operation. */
1708 case CAMEL_SERVICE_DISCONNECTING:
1710 service->priv->connection_op != NULL);
1711 g_cancellable_cancel (
1712 service->priv->connection_op->cancellable);
1713 connection_op_unref (service->priv->connection_op);
1714 service->priv->connection_op = NULL;
1717 /* Start a new connect operation. Subsequent connect
1718 * operations are queued until this operation completes
1719 * and will share this operation's result. */
1720 case CAMEL_SERVICE_DISCONNECTED:
1722 service->priv->connection_op == NULL);
1724 op = connection_op_new (simple, cancellable);
1725 service->priv->connection_op = op;
1727 service->priv->status = CAMEL_SERVICE_CONNECTING;
1728 service_queue_notify_connection_status (service);
1734 service_shared_connect_cb,
1735 connection_op_ref (op));
1739 g_warn_if_reached ();
1742 g_mutex_unlock (&service->priv->connection_lock);
1744 g_object_unref (simple);
1748 * camel_service_connect_finish:
1749 * @service: a #CamelService
1750 * @result: a #GAsyncResult
1751 * @error: return location for a #GError, or %NULL
1753 * Finishes the operation started with camel_service_connect().
1755 * Returns: %TRUE if the connection was made or %FALSE otherwise
1760 camel_service_connect_finish (CamelService *service,
1761 GAsyncResult *result,
1764 GSimpleAsyncResult *simple;
1766 g_return_val_if_fail (
1767 g_simple_async_result_is_valid (
1768 result, G_OBJECT (service), camel_service_connect), FALSE);
1770 simple = G_SIMPLE_ASYNC_RESULT (result);
1772 /* Assume success unless a GError is set. */
1773 return !g_simple_async_result_propagate_error (simple, error);
1777 * camel_service_disconnect_sync:
1778 * @service: a #CamelService
1779 * @clean: whether or not to try to disconnect cleanly
1780 * @cancellable: optional #GCancellable object, or %NULL
1781 * @error: return location for a #GError, or %NULL
1783 * Disconnect from the service. If @clean is %FALSE, it should not
1784 * try to do any synchronizing or other cleanup of the connection.
1786 * If a disconnect operation is already in progress when this function is
1787 * called, its results will be reflected in this disconnect operation.
1789 * If any connect operations are in progress when this function is called,
1790 * they will be cancelled.
1792 * Returns: %TRUE if the connection was severed or %FALSE otherwise
1797 camel_service_disconnect_sync (CamelService *service,
1799 GCancellable *cancellable,
1802 AsyncClosure *closure;
1803 GAsyncResult *result;
1806 g_return_val_if_fail (CAMEL_IS_SERVICE (service), FALSE);
1808 closure = async_closure_new ();
1810 camel_service_disconnect (
1811 service, clean, G_PRIORITY_DEFAULT,
1812 cancellable, async_closure_callback, closure);
1814 result = async_closure_wait (closure);
1816 success = camel_service_disconnect_finish (service, result, error);
1818 async_closure_free (closure);
1824 * camel_service_disconnect:
1825 * @service: a #CamelService
1826 * @clean: whether or not to try to disconnect cleanly
1827 * @io_priority: the I/O priority of the request
1828 * @cancellable: optional #GCancellable object, or %NULL
1829 * @callback: a #GAsyncReadyCallback to call when the request is satisfied
1830 * @user_data: data to pass to the callback function
1832 * If a disconnect operation is already in progress when this function is
1833 * called, its results will be reflected in this disconnect operation.
1835 * If any connect operations are in progress when this function is called,
1836 * they will be cancelled.
1838 * When the operation is finished, @callback will be called. You can
1839 * then call camel_service_disconnect_finish() to get the result of the
1845 camel_service_disconnect (CamelService *service,
1848 GCancellable *cancellable,
1849 GAsyncReadyCallback callback,
1853 CamelServiceClass *class;
1854 GSimpleAsyncResult *simple;
1856 g_return_if_fail (CAMEL_IS_SERVICE (service));
1858 class = CAMEL_SERVICE_GET_CLASS (service);
1859 g_return_if_fail (class->disconnect != NULL);
1861 simple = g_simple_async_result_new (
1862 G_OBJECT (service), callback,
1863 user_data, camel_service_disconnect);
1865 g_simple_async_result_set_check_cancellable (simple, cancellable);
1867 g_mutex_lock (&service->priv->connection_lock);
1869 switch (service->priv->status) {
1871 /* If a connect operation is currently in progress,
1872 * cancel it and make room for the disconnect operation. */
1873 case CAMEL_SERVICE_CONNECTING:
1875 service->priv->connection_op != NULL);
1876 g_cancellable_cancel (
1877 service->priv->connection_op->cancellable);
1878 connection_op_unref (service->priv->connection_op);
1879 service->priv->connection_op = NULL;
1882 /* Start a new disconnect operation. Subsequent disconnect
1883 * operations are queued until this operation completes and
1884 * will share this operation's result. */
1885 case CAMEL_SERVICE_CONNECTED:
1887 service->priv->connection_op == NULL);
1889 op = connection_op_new (simple, cancellable);
1890 service->priv->connection_op = op;
1892 service->priv->status = CAMEL_SERVICE_DISCONNECTING;
1893 service_queue_notify_connection_status (service);
1899 service_shared_disconnect_cb,
1900 connection_op_ref (op));
1903 /* If a disconnect operation is already in progress,
1904 * queue this operation so it completes at the same
1905 * time the first disconnect operation completes. */
1906 case CAMEL_SERVICE_DISCONNECTING:
1907 connection_op_add_pending (
1908 service->priv->connection_op,
1909 simple, cancellable);
1912 /* If we're already disconnected, just report success. */
1913 case CAMEL_SERVICE_DISCONNECTED:
1914 g_simple_async_result_complete_in_idle (simple);
1918 g_warn_if_reached ();
1921 g_mutex_unlock (&service->priv->connection_lock);
1923 g_object_unref (simple);
1927 * camel_service_disconnect_finish:
1928 * @service: a #CamelService
1929 * @result: a #GAsyncResult
1930 * @error: return location for a #GError, or %NULL
1932 * Finishes the operation started with camel_service_disconnect().
1934 * Returns: %TRUE if the connection was severed or %FALSE otherwise
1939 camel_service_disconnect_finish (CamelService *service,
1940 GAsyncResult *result,
1943 GSimpleAsyncResult *simple;
1945 g_return_val_if_fail (
1946 g_simple_async_result_is_valid (
1947 result, G_OBJECT (service), camel_service_disconnect), FALSE);
1949 simple = G_SIMPLE_ASYNC_RESULT (result);
1951 /* Assume success unless a GError is set. */
1952 return !g_simple_async_result_propagate_error (simple, error);
1956 * camel_service_authenticate_sync:
1957 * @service: a #CamelService
1958 * @mechanism: a SASL mechanism name, or %NULL
1959 * @cancellable: optional #GCancellable object, or %NULL
1960 * @error: return location for a #GError, or %NULL
1962 * Attempts to authenticate @service using @mechanism and, if necessary,
1963 * @service's #CamelService:password property. The function makes only
1964 * ONE attempt at authentication and does not loop.
1966 * If the authentication attempt completed and the server accepted the
1967 * credentials, the function returns #CAMEL_AUTHENTICATION_ACCEPTED.
1969 * If the authentication attempt completed but the server rejected the
1970 * credentials, the function returns #CAMEL_AUTHENTICATION_REJECTED.
1972 * If the authentication attempt failed to complete due to a network
1973 * communication issue or some other mishap, the function sets @error
1974 * and returns #CAMEL_AUTHENTICATION_ERROR.
1976 * Generally this function should only be called from a #CamelSession
1977 * subclass in order to implement its own authentication loop.
1979 * Returns: the authentication result
1983 CamelAuthenticationResult
1984 camel_service_authenticate_sync (CamelService *service,
1985 const gchar *mechanism,
1986 GCancellable *cancellable,
1989 CamelServiceClass *class;
1990 CamelAuthenticationResult result;
1992 g_return_val_if_fail (
1993 CAMEL_IS_SERVICE (service),
1994 CAMEL_AUTHENTICATION_REJECTED);
1996 class = CAMEL_SERVICE_GET_CLASS (service);
1997 g_return_val_if_fail (
1998 class->authenticate_sync != NULL,
1999 CAMEL_AUTHENTICATION_REJECTED);
2001 result = class->authenticate_sync (
2002 service, mechanism, cancellable, error);
2003 CAMEL_CHECK_GERROR (
2004 service, authenticate_sync,
2005 result != CAMEL_AUTHENTICATION_ERROR, error);
2011 * camel_service_authenticate:
2012 * @service: a #CamelService
2013 * @mechanism: a SASL mechanism name, or %NULL
2014 * @io_priority: the I/O priority of the request
2015 * @cancellable: optional #GCancellable object, or %NULL
2016 * @callback: a #GAsyncReadyCallback to call when the request is satisfied
2017 * @user_data: data to pass to the callback function
2019 * Asynchronously attempts to authenticate @service using @mechanism and,
2020 * if necessary, @service's #CamelService:password property. The function
2021 * makes only ONE attempt at authentication and does not loop.
2023 * Generally this function should only be called from a #CamelSession
2024 * subclass in order to implement its own authentication loop.
2026 * When the operation is finished, @callback will be called. You can
2027 * then call camel_service_authenticate_finish() to get the result of
2033 camel_service_authenticate (CamelService *service,
2034 const gchar *mechanism,
2036 GCancellable *cancellable,
2037 GAsyncReadyCallback callback,
2040 CamelServiceClass *class;
2042 g_return_if_fail (CAMEL_IS_SERVICE (service));
2044 class = CAMEL_SERVICE_GET_CLASS (service);
2045 g_return_if_fail (class->authenticate != NULL);
2047 class->authenticate (
2048 service, mechanism, io_priority,
2049 cancellable, callback, user_data);
2053 * camel_service_authenticate_finish:
2054 * @service: a #CamelService
2055 * @result: a #GAsyncResult
2056 * @error: return location for a #GError, or %NULL
2058 * Finishes the operation started with camel_service_authenticate().
2060 * If the authentication attempt completed and the server accepted the
2061 * credentials, the function returns #CAMEL_AUTHENTICATION_ACCEPTED.
2063 * If the authentication attempt completed but the server rejected the
2064 * credentials, the function returns #CAMEL_AUTHENTICATION_REJECTED.
2066 * If the authentication attempt failed to complete due to a network
2067 * communication issue or some other mishap, the function sets @error
2068 * and returns #CAMEL_AUTHENTICATION_ERROR.
2070 * Returns: the authentication result
2074 CamelAuthenticationResult
2075 camel_service_authenticate_finish (CamelService *service,
2076 GAsyncResult *result,
2079 CamelServiceClass *class;
2081 g_return_val_if_fail (
2082 CAMEL_IS_SERVICE (service),
2083 CAMEL_AUTHENTICATION_REJECTED);
2084 g_return_val_if_fail (
2085 G_IS_ASYNC_RESULT (result),
2086 CAMEL_AUTHENTICATION_REJECTED);
2088 class = CAMEL_SERVICE_GET_CLASS (service);
2089 g_return_val_if_fail (
2090 class->authenticate_finish,
2091 CAMEL_AUTHENTICATION_REJECTED);
2093 return class->authenticate_finish (service, result, error);
2097 * camel_service_query_auth_types_sync:
2098 * @service: a #CamelService
2099 * @cancellable: optional #GCancellable object, or %NULL
2100 * @error: return location for a #GError, or %NULL
2102 * Obtains a list of authentication types supported by @service.
2103 * Free the returned list with g_list_free().
2105 * Returns: a list of #CamelServiceAuthType structs
2108 camel_service_query_auth_types_sync (CamelService *service,
2109 GCancellable *cancellable,
2112 CamelServiceClass *class;
2114 g_return_val_if_fail (CAMEL_IS_SERVICE (service), NULL);
2116 class = CAMEL_SERVICE_GET_CLASS (service);
2117 g_return_val_if_fail (class->query_auth_types_sync != NULL, NULL);
2119 return class->query_auth_types_sync (service, cancellable, error);
2123 * camel_service_query_auth_types:
2124 * @service: a #CamelService
2125 * @io_priority: the I/O priority of the request
2126 * @cancellable: optional #GCancellable object, or %NULL
2127 * @callback: a #GAsyncReadyCallback to call when the request is satisfied
2128 * @user_data: data to pass to the callback function
2130 * Asynchronously obtains a list of authentication types supported by
2133 * When the operation is finished, @callback will be called. You can
2134 * then call camel_service_query_auth_types_finish() to get the result
2140 camel_service_query_auth_types (CamelService *service,
2142 GCancellable *cancellable,
2143 GAsyncReadyCallback callback,
2146 CamelServiceClass *class;
2148 g_return_if_fail (CAMEL_IS_SERVICE (service));
2150 class = CAMEL_SERVICE_GET_CLASS (service);
2151 g_return_if_fail (class->query_auth_types != NULL);
2153 class->query_auth_types (
2154 service, io_priority,
2155 cancellable, callback, user_data);
2159 * camel_service_query_auth_types_finish:
2160 * @service: a #CamelService
2161 * @result: a #GAsyncResult
2162 * @error: return location for a #GError, or %NULL
2164 * Finishes the operation started with camel_service_query_auth_types().
2165 * Free the returned list with g_list_free().
2167 * Returns: a list of #CamelServiceAuthType structs
2172 camel_service_query_auth_types_finish (CamelService *service,
2173 GAsyncResult *result,
2176 CamelServiceClass *class;
2178 g_return_val_if_fail (CAMEL_IS_SERVICE (service), NULL);
2179 g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
2181 class = CAMEL_SERVICE_GET_CLASS (service);
2182 g_return_val_if_fail (class->query_auth_types_finish != NULL, NULL);
2184 return class->query_auth_types_finish (service, result, error);