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-operation.h"
40 #include "camel-service.h"
41 #include "camel-session.h"
46 #define CAMEL_SERVICE_GET_PRIVATE(obj) \
47 (G_TYPE_INSTANCE_GET_PRIVATE \
48 ((obj), CAMEL_TYPE_SERVICE, CamelServicePrivate))
50 typedef struct _AsyncContext AsyncContext;
52 struct _CamelServicePrivate {
53 gpointer session; /* weak pointer */
55 CamelSettings *settings;
56 CamelProvider *provider;
61 gchar *user_cache_dir;
65 GCancellable *connect_op;
66 CamelServiceConnectionStatus status;
68 GStaticRecMutex connect_lock; /* for locking connection operations */
69 GStaticMutex connect_op_lock; /* for locking the connection_op */
72 struct _AsyncContext {
87 /* Forward Declarations */
88 static void camel_service_initable_init (GInitableIface *interface);
90 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (
91 CamelService, camel_service, CAMEL_TYPE_OBJECT,
92 G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, camel_service_initable_init))
95 async_context_free (AsyncContext *async_context)
97 g_list_free (async_context->auth_types);
99 g_slice_free (AsyncContext, async_context);
103 service_find_old_data_dir (CamelService *service)
105 CamelProvider *provider;
106 CamelSession *session;
109 gboolean allows_host;
110 gboolean allows_user;
114 const gchar *base_dir;
117 provider = camel_service_get_provider (service);
118 session = camel_service_get_session (service);
119 url = camel_service_get_camel_url (service);
121 allows_host = CAMEL_PROVIDER_ALLOWS (provider, CAMEL_URL_PART_HOST);
122 allows_user = CAMEL_PROVIDER_ALLOWS (provider, CAMEL_URL_PART_USER);
124 needs_host = CAMEL_PROVIDER_NEEDS (provider, CAMEL_URL_PART_HOST);
125 needs_path = CAMEL_PROVIDER_NEEDS (provider, CAMEL_URL_PART_PATH);
126 needs_user = CAMEL_PROVIDER_NEEDS (provider, CAMEL_URL_PART_USER);
128 /* This function reproduces the way service data directories used
129 * to be determined before we moved to just using the UID. If the
130 * old data directory exists, try renaming it to the new form.
132 * A virtual class method was used to determine the directory path,
133 * but no known CamelProviders ever overrode the default algorithm
134 * below. So this should work for everyone. */
136 path = g_string_new (provider->protocol);
139 g_string_append_c (path, '/');
140 if (url->user != NULL)
141 g_string_append (path, url->user);
143 g_string_append_c (path, '@');
144 if (url->host != NULL)
145 g_string_append (path, url->host);
147 g_string_append_c (path, ':');
148 g_string_append_printf (path, "%d", url->port);
150 } else if (!needs_user) {
151 g_string_append_c (path, '@');
154 } else if (allows_host) {
155 g_string_append_c (path, '/');
157 g_string_append_c (path, '@');
158 if (url->host != NULL)
159 g_string_append (path, url->host);
161 g_string_append_c (path, ':');
162 g_string_append_printf (path, "%d", url->port);
167 if (*url->path != '/')
168 g_string_append_c (path, '/');
169 g_string_append (path, url->path);
172 base_dir = camel_session_get_user_data_dir (session);
173 old_data_dir = g_build_filename (base_dir, path->str, NULL);
175 g_string_free (path, TRUE);
177 if (!g_file_test (old_data_dir, G_FILE_TEST_IS_DIR)) {
178 g_free (old_data_dir);
186 service_set_provider (CamelService *service,
187 CamelProvider *provider)
189 g_return_if_fail (provider != NULL);
190 g_return_if_fail (service->priv->provider == NULL);
192 service->priv->provider = provider;
196 service_set_session (CamelService *service,
197 CamelSession *session)
199 g_return_if_fail (CAMEL_IS_SESSION (session));
200 g_return_if_fail (service->priv->session == NULL);
202 service->priv->session = session;
204 g_object_add_weak_pointer (
205 G_OBJECT (session), &service->priv->session);
209 service_set_uid (CamelService *service,
212 g_return_if_fail (uid != NULL);
213 g_return_if_fail (service->priv->uid == NULL);
215 service->priv->uid = g_strdup (uid);
219 service_set_url (CamelService *service,
222 g_return_if_fail (url != NULL);
223 g_return_if_fail (service->priv->url == NULL);
225 service->priv->url = camel_url_copy (url);
229 service_set_property (GObject *object,
234 switch (property_id) {
235 case PROP_DISPLAY_NAME:
236 camel_service_set_display_name (
237 CAMEL_SERVICE (object),
238 g_value_get_string (value));
242 camel_service_set_password (
243 CAMEL_SERVICE (object),
244 g_value_get_string (value));
248 service_set_provider (
249 CAMEL_SERVICE (object),
250 g_value_get_pointer (value));
254 service_set_session (
255 CAMEL_SERVICE (object),
256 g_value_get_object (value));
260 camel_service_set_settings (
261 CAMEL_SERVICE (object),
262 g_value_get_object (value));
267 CAMEL_SERVICE (object),
268 g_value_get_string (value));
273 CAMEL_SERVICE (object),
274 g_value_get_boxed (value));
278 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
282 service_get_property (GObject *object,
287 switch (property_id) {
288 case PROP_DISPLAY_NAME:
290 value, camel_service_get_display_name (
291 CAMEL_SERVICE (object)));
296 value, camel_service_get_password (
297 CAMEL_SERVICE (object)));
301 g_value_set_pointer (
302 value, camel_service_get_provider (
303 CAMEL_SERVICE (object)));
308 value, camel_service_get_session (
309 CAMEL_SERVICE (object)));
314 value, camel_service_get_settings (
315 CAMEL_SERVICE (object)));
320 value, camel_service_get_uid (
321 CAMEL_SERVICE (object)));
326 value, camel_service_get_url (
327 CAMEL_SERVICE (object)));
331 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
335 service_dispose (GObject *object)
337 CamelServicePrivate *priv;
339 priv = CAMEL_SERVICE_GET_PRIVATE (object);
341 if (priv->session != NULL) {
342 g_object_remove_weak_pointer (
343 G_OBJECT (priv->session), &priv->session);
344 priv->session = NULL;
347 if (priv->settings != NULL) {
348 g_object_unref (priv->settings);
349 priv->settings = NULL;
352 /* Chain up to parent's dispose() method. */
353 G_OBJECT_CLASS (camel_service_parent_class)->dispose (object);
357 service_finalize (GObject *object)
359 CamelServicePrivate *priv;
361 priv = CAMEL_SERVICE_GET_PRIVATE (object);
363 if (priv->status == CAMEL_SERVICE_CONNECTED)
364 CAMEL_SERVICE_GET_CLASS (object)->disconnect_sync (
365 CAMEL_SERVICE (object), TRUE, NULL, NULL);
367 if (priv->url != NULL)
368 camel_url_free (priv->url);
370 g_free (priv->display_name);
371 g_free (priv->user_data_dir);
372 g_free (priv->user_cache_dir);
374 g_free (priv->password);
376 g_static_rec_mutex_free (&priv->connect_lock);
377 g_static_mutex_free (&priv->connect_op_lock);
379 /* Chain up to parent's finalize() method. */
380 G_OBJECT_CLASS (camel_service_parent_class)->finalize (object);
384 service_constructed (GObject *object)
386 CamelService *service;
387 CamelSession *session;
388 const gchar *base_dir;
391 /* Chain up to parent's constructed() method. */
392 G_OBJECT_CLASS (camel_service_parent_class)->constructed (object);
394 service = CAMEL_SERVICE (object);
395 session = camel_service_get_session (service);
397 uid = camel_service_get_uid (service);
399 base_dir = camel_session_get_user_data_dir (session);
400 service->priv->user_data_dir = g_build_filename (base_dir, uid, NULL);
402 base_dir = camel_session_get_user_cache_dir (session);
403 service->priv->user_cache_dir = g_build_filename (base_dir, uid, NULL);
407 service_get_name (CamelService *service,
411 "%s does not implement CamelServiceClass::get_name()",
412 G_OBJECT_TYPE_NAME (service));
414 return g_strdup (G_OBJECT_TYPE_NAME (service));
418 service_cancel_connect (CamelService *service)
420 g_cancellable_cancel (service->priv->connect_op);
424 service_connect_sync (CamelService *service,
425 GCancellable *cancellable,
428 /* Things like the CamelMboxStore can validly
429 * not define a connect function. */
434 service_disconnect_sync (CamelService *service,
436 GCancellable *cancellable,
439 /* We let people get away with not having a disconnect
440 * function -- CamelMboxStore, for example. */
445 service_query_auth_types_sync (CamelService *service,
446 GCancellable *cancellable,
453 service_query_auth_types_thread (GSimpleAsyncResult *simple,
455 GCancellable *cancellable)
457 AsyncContext *async_context;
458 GError *error = NULL;
460 async_context = g_simple_async_result_get_op_res_gpointer (simple);
462 async_context->auth_types = camel_service_query_auth_types_sync (
463 CAMEL_SERVICE (object), cancellable, &error);
466 g_simple_async_result_take_error (simple, error);
470 service_query_auth_types (CamelService *service,
472 GCancellable *cancellable,
473 GAsyncReadyCallback callback,
476 GSimpleAsyncResult *simple;
477 AsyncContext *async_context;
479 async_context = g_slice_new0 (AsyncContext);
481 simple = g_simple_async_result_new (
482 G_OBJECT (service), callback,
483 user_data, service_query_auth_types);
485 g_simple_async_result_set_op_res_gpointer (
486 simple, async_context, (GDestroyNotify) async_context_free);
488 g_simple_async_result_run_in_thread (
489 simple, service_query_auth_types_thread,
490 io_priority, cancellable);
492 g_object_unref (simple);
496 service_query_auth_types_finish (CamelService *service,
497 GAsyncResult *result,
500 GSimpleAsyncResult *simple;
501 AsyncContext *async_context;
503 g_return_val_if_fail (
504 g_simple_async_result_is_valid (
505 result, G_OBJECT (service),
506 service_query_auth_types), NULL);
508 simple = G_SIMPLE_ASYNC_RESULT (result);
509 async_context = g_simple_async_result_get_op_res_gpointer (simple);
511 if (g_simple_async_result_propagate_error (simple, error))
514 return g_list_copy (async_context->auth_types);
518 service_initable_init (GInitable *initable,
519 GCancellable *cancellable,
522 CamelProvider *provider;
523 CamelService *service;
525 gboolean success = FALSE;
526 const gchar *new_data_dir;
530 service = CAMEL_SERVICE (initable);
531 url = camel_service_get_camel_url (service);
532 provider = camel_service_get_provider (service);
534 url_string = camel_url_to_string (url, 0);
536 if (CAMEL_PROVIDER_NEEDS (provider, CAMEL_URL_PART_USER)) {
537 if (url->user == NULL || *url->user == '\0') {
539 error, CAMEL_SERVICE_ERROR,
540 CAMEL_SERVICE_ERROR_URL_INVALID,
541 _("URL '%s' needs a user component"),
547 if (CAMEL_PROVIDER_NEEDS (provider, CAMEL_URL_PART_HOST)) {
548 if (url->host == NULL || *url->host == '\0') {
550 error, CAMEL_SERVICE_ERROR,
551 CAMEL_SERVICE_ERROR_URL_INVALID,
552 _("URL '%s' needs a host component"),
558 if (CAMEL_PROVIDER_NEEDS (provider, CAMEL_URL_PART_PATH)) {
559 if (url->path == NULL || *url->path == '\0') {
561 error, CAMEL_SERVICE_ERROR,
562 CAMEL_SERVICE_ERROR_URL_INVALID,
563 _("URL '%s' needs a path component"),
569 new_data_dir = camel_service_get_user_data_dir (service);
570 old_data_dir = service_find_old_data_dir (service);
572 /* If the old data directory name exists, try renaming
573 * it to the new data directory. Failure is non-fatal. */
574 if (old_data_dir != NULL) {
575 g_rename (old_data_dir, new_data_dir);
576 g_free (old_data_dir);
588 camel_service_class_init (CamelServiceClass *class)
590 GObjectClass *object_class;
592 g_type_class_add_private (class, sizeof (CamelServicePrivate));
594 object_class = G_OBJECT_CLASS (class);
595 object_class->set_property = service_set_property;
596 object_class->get_property = service_get_property;
597 object_class->dispose = service_dispose;
598 object_class->finalize = service_finalize;
599 object_class->constructed = service_constructed;
601 class->settings_type = CAMEL_TYPE_SETTINGS;
602 class->get_name = service_get_name;
603 class->cancel_connect = service_cancel_connect;
604 class->connect_sync = service_connect_sync;
605 class->disconnect_sync = service_disconnect_sync;
606 class->query_auth_types_sync = service_query_auth_types_sync;
608 class->query_auth_types = service_query_auth_types;
609 class->query_auth_types_finish = service_query_auth_types_finish;
611 g_object_class_install_property (
614 g_param_spec_string (
617 "The display name for the service",
621 G_PARAM_STATIC_STRINGS));
623 g_object_class_install_property (
626 g_param_spec_string (
629 "The password for the service",
633 G_PARAM_STATIC_STRINGS));
635 g_object_class_install_property (
638 g_param_spec_pointer (
641 "The CamelProvider for the service",
643 G_PARAM_CONSTRUCT_ONLY |
644 G_PARAM_STATIC_STRINGS));
646 g_object_class_install_property (
649 g_param_spec_object (
652 "A CamelSession instance",
655 G_PARAM_CONSTRUCT_ONLY |
656 G_PARAM_STATIC_STRINGS));
658 g_object_class_install_property (
661 g_param_spec_object (
664 "A CamelSettings instance",
668 G_PARAM_STATIC_STRINGS));
670 g_object_class_install_property (
673 g_param_spec_string (
676 "The unique identity of the service",
679 G_PARAM_CONSTRUCT_ONLY |
680 G_PARAM_STATIC_STRINGS));
682 g_object_class_install_property (
688 "The CamelURL for the service",
691 G_PARAM_CONSTRUCT_ONLY |
692 G_PARAM_STATIC_STRINGS));
696 camel_service_initable_init (GInitableIface *interface)
698 interface->init = service_initable_init;
702 camel_service_init (CamelService *service)
704 service->priv = CAMEL_SERVICE_GET_PRIVATE (service);
706 service->priv->status = CAMEL_SERVICE_DISCONNECTED;
708 g_static_rec_mutex_init (&service->priv->connect_lock);
709 g_static_mutex_init (&service->priv->connect_op_lock);
713 camel_service_error_quark (void)
715 static GQuark quark = 0;
717 if (G_UNLIKELY (quark == 0)) {
718 const gchar *string = "camel-service-error-quark";
719 quark = g_quark_from_static_string (string);
726 * camel_service_cancel_connect:
727 * @service: a #CamelService
729 * If @service is currently attempting to connect to or disconnect
730 * from a server, this causes it to stop and fail. Otherwise it is a
734 camel_service_cancel_connect (CamelService *service)
736 CamelServiceClass *class;
738 g_return_if_fail (CAMEL_IS_SERVICE (service));
740 class = CAMEL_SERVICE_GET_CLASS (service);
741 g_return_if_fail (class->cancel_connect != NULL);
743 camel_service_lock (service, CAMEL_SERVICE_CONNECT_OP_LOCK);
744 if (service->priv->connect_op)
745 class->cancel_connect (service);
746 camel_service_unlock (service, CAMEL_SERVICE_CONNECT_OP_LOCK);
750 * camel_service_get_display_name:
751 * @service: a #CamelService
753 * Returns the display name for @service, or %NULL if @service has not
754 * been given a display name. The display name is intended for use in
755 * a user interface and should generally be given a user-defined name.
757 * Compare this with camel_service_get_name(), which returns a built-in
758 * description of the type of service (IMAP, SMTP, etc.).
760 * Returns: the display name for @service, or %NULL
765 camel_service_get_display_name (CamelService *service)
767 g_return_val_if_fail (CAMEL_IS_SERVICE (service), NULL);
769 return service->priv->display_name;
773 * camel_service_set_display_name:
774 * @service: a #CamelService
775 * @display_name: a valid UTF-8 string, or %NULL
777 * Assigns a UTF-8 display name to @service. The display name is intended
778 * for use in a user interface and should generally be given a user-defined
781 * Compare this with camel_service_get_name(), which returns a built-in
782 * description of the type of service (IMAP, SMTP, etc.).
787 camel_service_set_display_name (CamelService *service,
788 const gchar *display_name)
790 g_return_if_fail (CAMEL_IS_SERVICE (service));
792 if (display_name != NULL)
793 g_return_if_fail (g_utf8_validate (display_name, -1, NULL));
795 g_free (service->priv->display_name);
796 service->priv->display_name = g_strdup (display_name);
798 g_object_notify (G_OBJECT (service), "display-name");
802 * camel_service_get_password:
803 * @service: a #CamelService
805 * Returns the password for @service. Some SASL mechanisms use this
806 * when attempting to authenticate.
808 * Returns: the password for @service
813 camel_service_get_password (CamelService *service)
815 g_return_val_if_fail (CAMEL_IS_SERVICE (service), NULL);
817 return service->priv->password;
821 * camel_service_set_password:
822 * @service: a #CamelService
823 * @password: the password for @service
825 * Sets the password for @service. Use this function to cache the password
826 * in memory after obtaining it through camel_session_get_password(). Some
827 * SASL mechanisms use this when attempting to authenticate.
832 camel_service_set_password (CamelService *service,
833 const gchar *password)
835 g_return_if_fail (CAMEL_IS_SERVICE (service));
837 g_free (service->priv->password);
838 service->priv->password = g_strdup (password);
840 g_object_notify (G_OBJECT (service), "password");
844 * camel_service_get_user_data_dir:
845 * @service: a #CamelService
847 * Returns the base directory under which to store user-specific data
848 * for @service. The directory is formed by appending the directory
849 * returned by camel_session_get_user_data_dir() with the service's
850 * #CamelService:uid value.
852 * Returns: the base directory for @service
857 camel_service_get_user_data_dir (CamelService *service)
859 g_return_val_if_fail (CAMEL_IS_SERVICE (service), NULL);
861 return service->priv->user_data_dir;
865 * camel_service_get_user_cache_dir:
866 * @service: a #CamelService
868 * Returns the base directory under which to store cache data
869 * for @service. The directory is formed by appending the directory
870 * returned by camel_session_get_user_cache_dir() with the service's
871 * #CamelService:uid value.
873 * Returns: the base cache directory for @service
878 camel_service_get_user_cache_dir (CamelService *service)
880 g_return_val_if_fail (CAMEL_IS_SERVICE (service), NULL);
882 return service->priv->user_cache_dir;
886 * camel_service_get_name:
887 * @service: a #CamelService
888 * @brief: whether or not to use a briefer form
890 * This gets the name of the service in a "friendly" (suitable for
891 * humans) form. If @brief is %TRUE, this should be a brief description
892 * such as for use in the folder tree. If @brief is %FALSE, it should
893 * be a more complete and mostly unambiguous description.
895 * Returns: a description of the service which the caller must free
898 camel_service_get_name (CamelService *service,
901 CamelServiceClass *class;
903 g_return_val_if_fail (CAMEL_IS_SERVICE (service), NULL);
904 g_return_val_if_fail (service->priv->url, NULL);
906 class = CAMEL_SERVICE_GET_CLASS (service);
907 g_return_val_if_fail (class->get_name != NULL, NULL);
909 return class->get_name (service, brief);
913 * camel_service_get_provider:
914 * @service: a #CamelService
916 * Gets the #CamelProvider associated with the service.
918 * Returns: the #CamelProvider
921 camel_service_get_provider (CamelService *service)
923 g_return_val_if_fail (CAMEL_IS_SERVICE (service), NULL);
925 return service->priv->provider;
929 * camel_service_get_session:
930 * @service: a #CamelService
932 * Gets the #CamelSession associated with the service.
934 * Returns: the #CamelSession
937 camel_service_get_session (CamelService *service)
939 g_return_val_if_fail (CAMEL_IS_SERVICE (service), NULL);
941 return CAMEL_SESSION (service->priv->session);
945 * camel_service_get_settings:
946 * @service: a #CamelService
948 * Returns the #CamelSettings instance associated with the service.
950 * Returns: the #CamelSettings
955 camel_service_get_settings (CamelService *service)
957 g_return_val_if_fail (CAMEL_IS_SERVICE (service), NULL);
959 /* Every service should have a settings object. */
960 g_warn_if_fail (service->priv->settings != NULL);
962 return service->priv->settings;
966 * camel_service_set_settings:
967 * @service: a #CamelService
968 * @settings: an instance derviced from #CamelSettings, or %NULL
970 * Associates a new #CamelSettings instance with the service.
971 * The @settings instance must match the settings type defined in
972 * #CamelServiceClass. If @settings is %NULL, a new #CamelSettings
973 * instance of the appropriate type is created with all properties
979 camel_service_set_settings (CamelService *service,
980 CamelSettings *settings)
982 CamelServiceClass *class;
984 g_return_if_fail (CAMEL_IS_SERVICE (service));
986 class = CAMEL_SERVICE_GET_CLASS (service);
988 if (settings != NULL) {
991 G_OBJECT_TYPE (settings),
992 class->settings_type));
993 g_object_ref (settings);
998 class->settings_type,
999 CAMEL_TYPE_SETTINGS));
1000 settings = g_object_new (class->settings_type, NULL);
1001 camel_settings_load_from_url (settings, camel_service_get_camel_url (service));
1004 if (service->priv->settings != NULL)
1005 g_object_unref (service->priv->settings);
1007 service->priv->settings = settings;
1009 g_object_notify (G_OBJECT (service), "settings");
1013 * camel_service_get_uid:
1014 * @service: a #CamelService
1016 * Gets the unique identifier string associated with the service.
1018 * Returns: the UID string
1023 camel_service_get_uid (CamelService *service)
1025 g_return_val_if_fail (CAMEL_IS_SERVICE (service), NULL);
1027 return service->priv->uid;
1031 * camel_service_get_camel_url:
1032 * @service: a #CamelService
1034 * Returns the #CamelURL representing @service.
1036 * Returns: the #CamelURL representing @service
1041 camel_service_get_camel_url (CamelService *service)
1043 g_return_val_if_fail (CAMEL_IS_SERVICE (service), NULL);
1045 return service->priv->url;
1049 * camel_service_get_url:
1050 * @service: a #CamelService
1052 * Gets the URL representing @service. The returned URL must be
1053 * freed when it is no longer needed.
1055 * Returns: the URL representing @service
1058 camel_service_get_url (CamelService *service)
1062 g_return_val_if_fail (CAMEL_IS_SERVICE (service), NULL);
1064 url = camel_service_get_camel_url (service);
1066 return camel_url_to_string (url, 0);
1070 * camel_service_connect_sync:
1071 * @service: a #CamelService
1072 * @error: return location for a #GError, or %NULL
1074 * Connect to the service using the parameters it was initialized
1077 * Returns: %TRUE if the connection is made or %FALSE otherwise
1080 camel_service_connect_sync (CamelService *service,
1083 CamelServiceClass *class;
1085 gboolean ret = FALSE;
1087 g_return_val_if_fail (CAMEL_IS_SERVICE (service), FALSE);
1088 g_return_val_if_fail (service->priv->session != NULL, FALSE);
1089 g_return_val_if_fail (service->priv->url != NULL, FALSE);
1091 class = CAMEL_SERVICE_GET_CLASS (service);
1092 g_return_val_if_fail (class->connect_sync != NULL, FALSE);
1094 camel_service_lock (service, CAMEL_SERVICE_REC_CONNECT_LOCK);
1096 if (service->priv->status == CAMEL_SERVICE_CONNECTED) {
1097 camel_service_unlock (service, CAMEL_SERVICE_REC_CONNECT_LOCK);
1101 /* Register a separate operation for connecting, so that
1102 * the offline code can cancel it. */
1103 camel_service_lock (service, CAMEL_SERVICE_CONNECT_OP_LOCK);
1104 service->priv->connect_op = camel_operation_new ();
1105 op = service->priv->connect_op;
1106 camel_service_unlock (service, CAMEL_SERVICE_CONNECT_OP_LOCK);
1108 service->priv->status = CAMEL_SERVICE_CONNECTING;
1109 ret = class->connect_sync (service, service->priv->connect_op, error);
1110 CAMEL_CHECK_GERROR (service, connect_sync, ret, error);
1111 service->priv->status =
1112 ret ? CAMEL_SERVICE_CONNECTED : CAMEL_SERVICE_DISCONNECTED;
1114 camel_service_lock (service, CAMEL_SERVICE_CONNECT_OP_LOCK);
1115 g_object_unref (op);
1116 if (op == service->priv->connect_op)
1117 service->priv->connect_op = NULL;
1118 camel_service_unlock (service, CAMEL_SERVICE_CONNECT_OP_LOCK);
1120 camel_service_unlock (service, CAMEL_SERVICE_REC_CONNECT_LOCK);
1126 * camel_service_disconnect_sync:
1127 * @service: a #CamelService
1128 * @clean: whether or not to try to disconnect cleanly
1129 * @error: return location for a #GError, or %NULL
1131 * Disconnect from the service. If @clean is %FALSE, it should not
1132 * try to do any synchronizing or other cleanup of the connection.
1134 * Returns: %TRUE if the disconnect was successful or %FALSE otherwise
1137 camel_service_disconnect_sync (CamelService *service,
1141 CamelServiceClass *class;
1142 gboolean res = TRUE;
1144 g_return_val_if_fail (CAMEL_IS_SERVICE (service), FALSE);
1146 class = CAMEL_SERVICE_GET_CLASS (service);
1147 g_return_val_if_fail (class->disconnect_sync != NULL, FALSE);
1149 camel_service_lock (service, CAMEL_SERVICE_REC_CONNECT_LOCK);
1151 if (service->priv->status != CAMEL_SERVICE_DISCONNECTED
1152 && service->priv->status != CAMEL_SERVICE_DISCONNECTING) {
1154 camel_service_lock (service, CAMEL_SERVICE_CONNECT_OP_LOCK);
1155 service->priv->connect_op = camel_operation_new ();
1156 op = service->priv->connect_op;
1157 camel_service_unlock (service, CAMEL_SERVICE_CONNECT_OP_LOCK);
1159 service->priv->status = CAMEL_SERVICE_DISCONNECTING;
1160 res = class->disconnect_sync (
1161 service, clean, service->priv->connect_op, error);
1162 CAMEL_CHECK_GERROR (service, disconnect_sync, res, error);
1163 service->priv->status = CAMEL_SERVICE_DISCONNECTED;
1165 camel_service_lock (service, CAMEL_SERVICE_CONNECT_OP_LOCK);
1166 g_object_unref (op);
1167 if (op == service->priv->connect_op)
1168 service->priv->connect_op = NULL;
1169 camel_service_unlock (service, CAMEL_SERVICE_CONNECT_OP_LOCK);
1172 camel_service_unlock (service, CAMEL_SERVICE_REC_CONNECT_LOCK);
1174 service->priv->status = CAMEL_SERVICE_DISCONNECTED;
1180 * camel_service_get_connection_status:
1181 * @service: a #CamelService
1183 * Returns the connection status for @service.
1185 * Returns: the connection status
1189 CamelServiceConnectionStatus
1190 camel_service_get_connection_status (CamelService *service)
1192 g_return_val_if_fail (
1193 CAMEL_IS_SERVICE (service), CAMEL_SERVICE_DISCONNECTED);
1195 return service->priv->status;
1199 * camel_service_lock:
1200 * @service: a #CamelService
1201 * @lock: lock type to lock
1203 * Locks @service's @lock. Unlock it with camel_service_unlock().
1208 camel_service_lock (CamelService *service,
1209 CamelServiceLock lock)
1211 g_return_if_fail (CAMEL_IS_SERVICE (service));
1214 case CAMEL_SERVICE_REC_CONNECT_LOCK:
1215 g_static_rec_mutex_lock (&service->priv->connect_lock);
1217 case CAMEL_SERVICE_CONNECT_OP_LOCK:
1218 g_static_mutex_lock (&service->priv->connect_op_lock);
1221 g_return_if_reached ();
1226 * camel_service_unlock:
1227 * @service: a #CamelService
1228 * @lock: lock type to unlock
1230 * Unlocks @service's @lock, previously locked with camel_service_lock().
1235 camel_service_unlock (CamelService *service,
1236 CamelServiceLock lock)
1238 g_return_if_fail (CAMEL_IS_SERVICE (service));
1241 case CAMEL_SERVICE_REC_CONNECT_LOCK:
1242 g_static_rec_mutex_unlock (&service->priv->connect_lock);
1244 case CAMEL_SERVICE_CONNECT_OP_LOCK:
1245 g_static_mutex_unlock (&service->priv->connect_op_lock);
1248 g_return_if_reached ();
1253 * camel_service_query_auth_types_sync:
1254 * @service: a #CamelService
1255 * @cancellable: optional #GCancellable object, or %NULL
1256 * @error: return location for a #GError, or %NULL
1258 * Obtains a list of authentication types supported by @service.
1259 * Free the returned list with g_list_free().
1261 * Returns: a list of #CamelServiceAuthType structs
1264 camel_service_query_auth_types_sync (CamelService *service,
1265 GCancellable *cancellable,
1268 CamelServiceClass *class;
1271 g_return_val_if_fail (CAMEL_IS_SERVICE (service), NULL);
1273 class = CAMEL_SERVICE_GET_CLASS (service);
1274 g_return_val_if_fail (class->query_auth_types_sync != NULL, NULL);
1276 /* Note that we get the connect lock here, which means the
1277 * callee must not call the connect functions itself. */
1278 camel_service_lock (service, CAMEL_SERVICE_REC_CONNECT_LOCK);
1279 list = class->query_auth_types_sync (service, cancellable, error);
1280 camel_service_unlock (service, CAMEL_SERVICE_REC_CONNECT_LOCK);
1286 * camel_service_query_auth_types:
1287 * @service: a #CamelService
1288 * @io_priority: the I/O priority of the request
1289 * @cancellable: optional #GCancellable object, or %NULL
1290 * @callback: a #GAsyncReadyCallback to call when the request is satisfied
1291 * @user_data: data to pass to the callback function
1293 * Asynchronously obtains a list of authentication types supported by
1296 * When the operation is finished, @callback will be called. You can
1297 * then call camel_service_query_auth_types_finish() to get the result
1303 camel_service_query_auth_types (CamelService *service,
1305 GCancellable *cancellable,
1306 GAsyncReadyCallback callback,
1309 CamelServiceClass *class;
1311 g_return_if_fail (CAMEL_IS_SERVICE (service));
1313 class = CAMEL_SERVICE_GET_CLASS (service);
1314 g_return_if_fail (class->query_auth_types != NULL);
1316 class->query_auth_types (
1317 service, io_priority,
1318 cancellable, callback, user_data);
1322 * camel_service_query_auth_types_finish:
1323 * @service: a #CamelService
1324 * @result: a #GAsyncResult
1325 * @error: return location for a #GError, or %NULL
1327 * Finishes the operation started with camel_service_query_auth_types().
1328 * Free the returned list with g_list_free().
1330 * Returns: a list of #CamelServiceAuthType structs
1335 camel_service_query_auth_types_finish (CamelService *service,
1336 GAsyncResult *result,
1339 CamelServiceClass *class;
1341 g_return_val_if_fail (CAMEL_IS_SERVICE (service), NULL);
1342 g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
1344 class = CAMEL_SERVICE_GET_CLASS (service);
1345 g_return_val_if_fail (class->query_auth_types_finish != NULL, NULL);
1347 return class->query_auth_types_finish (service, result, error);