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 {
74 gchar *auth_mechanism;
75 CamelAuthenticationResult auth_result;
89 /* Forward Declarations */
90 static void camel_service_initable_init (GInitableIface *interface);
92 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (
93 CamelService, camel_service, CAMEL_TYPE_OBJECT,
94 G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, camel_service_initable_init))
97 async_context_free (AsyncContext *async_context)
99 g_list_free (async_context->auth_types);
101 g_free (async_context->auth_mechanism);
103 g_slice_free (AsyncContext, async_context);
107 service_find_old_data_dir (CamelService *service)
109 CamelProvider *provider;
110 CamelSession *session;
113 gboolean allows_host;
114 gboolean allows_user;
118 const gchar *base_dir;
121 provider = camel_service_get_provider (service);
122 session = camel_service_get_session (service);
123 url = camel_service_get_camel_url (service);
125 allows_host = CAMEL_PROVIDER_ALLOWS (provider, CAMEL_URL_PART_HOST);
126 allows_user = CAMEL_PROVIDER_ALLOWS (provider, CAMEL_URL_PART_USER);
128 needs_host = CAMEL_PROVIDER_NEEDS (provider, CAMEL_URL_PART_HOST);
129 needs_path = CAMEL_PROVIDER_NEEDS (provider, CAMEL_URL_PART_PATH);
130 needs_user = CAMEL_PROVIDER_NEEDS (provider, CAMEL_URL_PART_USER);
132 /* This function reproduces the way service data directories used
133 * to be determined before we moved to just using the UID. If the
134 * old data directory exists, try renaming it to the new form.
136 * A virtual class method was used to determine the directory path,
137 * but no known CamelProviders ever overrode the default algorithm
138 * below. So this should work for everyone. */
140 path = g_string_new (provider->protocol);
143 g_string_append_c (path, '/');
144 if (url->user != NULL)
145 g_string_append (path, url->user);
147 g_string_append_c (path, '@');
148 if (url->host != NULL)
149 g_string_append (path, url->host);
151 g_string_append_c (path, ':');
152 g_string_append_printf (path, "%d", url->port);
154 } else if (!needs_user) {
155 g_string_append_c (path, '@');
158 } else if (allows_host) {
159 g_string_append_c (path, '/');
161 g_string_append_c (path, '@');
162 if (url->host != NULL)
163 g_string_append (path, url->host);
165 g_string_append_c (path, ':');
166 g_string_append_printf (path, "%d", url->port);
171 if (*url->path != '/')
172 g_string_append_c (path, '/');
173 g_string_append (path, url->path);
176 base_dir = camel_session_get_user_data_dir (session);
177 old_data_dir = g_build_filename (base_dir, path->str, NULL);
179 g_string_free (path, TRUE);
181 if (!g_file_test (old_data_dir, G_FILE_TEST_IS_DIR)) {
182 g_free (old_data_dir);
190 service_set_provider (CamelService *service,
191 CamelProvider *provider)
193 g_return_if_fail (provider != NULL);
194 g_return_if_fail (service->priv->provider == NULL);
196 service->priv->provider = provider;
200 service_set_session (CamelService *service,
201 CamelSession *session)
203 g_return_if_fail (CAMEL_IS_SESSION (session));
204 g_return_if_fail (service->priv->session == NULL);
206 service->priv->session = session;
208 g_object_add_weak_pointer (
209 G_OBJECT (session), &service->priv->session);
213 service_set_uid (CamelService *service,
216 g_return_if_fail (uid != NULL);
217 g_return_if_fail (service->priv->uid == NULL);
219 service->priv->uid = g_strdup (uid);
223 service_set_url (CamelService *service,
226 g_return_if_fail (url != NULL);
227 g_return_if_fail (service->priv->url == NULL);
229 service->priv->url = camel_url_copy (url);
233 service_set_property (GObject *object,
238 switch (property_id) {
239 case PROP_DISPLAY_NAME:
240 camel_service_set_display_name (
241 CAMEL_SERVICE (object),
242 g_value_get_string (value));
246 camel_service_set_password (
247 CAMEL_SERVICE (object),
248 g_value_get_string (value));
252 service_set_provider (
253 CAMEL_SERVICE (object),
254 g_value_get_pointer (value));
258 service_set_session (
259 CAMEL_SERVICE (object),
260 g_value_get_object (value));
264 camel_service_set_settings (
265 CAMEL_SERVICE (object),
266 g_value_get_object (value));
271 CAMEL_SERVICE (object),
272 g_value_get_string (value));
277 CAMEL_SERVICE (object),
278 g_value_get_boxed (value));
282 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
286 service_get_property (GObject *object,
291 switch (property_id) {
292 case PROP_DISPLAY_NAME:
294 value, camel_service_get_display_name (
295 CAMEL_SERVICE (object)));
300 value, camel_service_get_password (
301 CAMEL_SERVICE (object)));
305 g_value_set_pointer (
306 value, camel_service_get_provider (
307 CAMEL_SERVICE (object)));
312 value, camel_service_get_session (
313 CAMEL_SERVICE (object)));
318 value, camel_service_get_settings (
319 CAMEL_SERVICE (object)));
324 value, camel_service_get_uid (
325 CAMEL_SERVICE (object)));
330 value, camel_service_get_url (
331 CAMEL_SERVICE (object)));
335 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
339 service_dispose (GObject *object)
341 CamelServicePrivate *priv;
343 priv = CAMEL_SERVICE_GET_PRIVATE (object);
345 if (priv->session != NULL) {
346 g_object_remove_weak_pointer (
347 G_OBJECT (priv->session), &priv->session);
348 priv->session = NULL;
351 if (priv->settings != NULL) {
352 g_object_unref (priv->settings);
353 priv->settings = NULL;
356 /* Chain up to parent's dispose() method. */
357 G_OBJECT_CLASS (camel_service_parent_class)->dispose (object);
361 service_finalize (GObject *object)
363 CamelServicePrivate *priv;
365 priv = CAMEL_SERVICE_GET_PRIVATE (object);
367 if (priv->status == CAMEL_SERVICE_CONNECTED)
368 CAMEL_SERVICE_GET_CLASS (object)->disconnect_sync (
369 CAMEL_SERVICE (object), TRUE, NULL, NULL);
371 if (priv->url != NULL)
372 camel_url_free (priv->url);
374 g_free (priv->display_name);
375 g_free (priv->user_data_dir);
376 g_free (priv->user_cache_dir);
378 g_free (priv->password);
380 g_static_rec_mutex_free (&priv->connect_lock);
381 g_static_mutex_free (&priv->connect_op_lock);
383 /* Chain up to parent's finalize() method. */
384 G_OBJECT_CLASS (camel_service_parent_class)->finalize (object);
388 service_constructed (GObject *object)
390 CamelService *service;
391 CamelSession *session;
392 const gchar *base_dir;
395 /* Chain up to parent's constructed() method. */
396 G_OBJECT_CLASS (camel_service_parent_class)->constructed (object);
398 service = CAMEL_SERVICE (object);
399 session = camel_service_get_session (service);
401 uid = camel_service_get_uid (service);
403 base_dir = camel_session_get_user_data_dir (session);
404 service->priv->user_data_dir = g_build_filename (base_dir, uid, NULL);
406 base_dir = camel_session_get_user_cache_dir (session);
407 service->priv->user_cache_dir = g_build_filename (base_dir, uid, NULL);
411 service_get_name (CamelService *service,
415 "%s does not implement CamelServiceClass::get_name()",
416 G_OBJECT_TYPE_NAME (service));
418 return g_strdup (G_OBJECT_TYPE_NAME (service));
422 service_cancel_connect (CamelService *service)
424 g_cancellable_cancel (service->priv->connect_op);
428 service_connect_sync (CamelService *service,
429 GCancellable *cancellable,
432 /* Things like the CamelMboxStore can validly
433 * not define a connect function. */
438 service_disconnect_sync (CamelService *service,
440 GCancellable *cancellable,
443 /* We let people get away with not having a disconnect
444 * function -- CamelMboxStore, for example. */
449 service_query_auth_types_sync (CamelService *service,
450 GCancellable *cancellable,
457 service_authenticate_thread (GSimpleAsyncResult *simple,
459 GCancellable *cancellable)
461 AsyncContext *async_context;
462 GError *error = NULL;
464 async_context = g_simple_async_result_get_op_res_gpointer (simple);
466 async_context->auth_result = camel_service_authenticate_sync (
467 CAMEL_SERVICE (object), async_context->auth_mechanism,
468 cancellable, &error);
471 g_simple_async_result_take_error (simple, error);
475 service_authenticate (CamelService *service,
476 const gchar *mechanism,
478 GCancellable *cancellable,
479 GAsyncReadyCallback callback,
482 GSimpleAsyncResult *simple;
483 AsyncContext *async_context;
485 async_context = g_slice_new0 (AsyncContext);
486 async_context->auth_mechanism = g_strdup (mechanism);
488 simple = g_simple_async_result_new (
489 G_OBJECT (service), callback, user_data, service_authenticate);
491 g_simple_async_result_set_op_res_gpointer (
492 simple, async_context, (GDestroyNotify) async_context_free);
494 g_simple_async_result_run_in_thread (
495 simple, service_authenticate_thread, io_priority, cancellable);
497 g_object_unref (simple);
500 static CamelAuthenticationResult
501 service_authenticate_finish (CamelService *service,
502 GAsyncResult *result,
505 GSimpleAsyncResult *simple;
506 AsyncContext *async_context;
508 g_return_val_if_fail (
509 g_simple_async_result_is_valid (
510 result, G_OBJECT (service), service_authenticate),
511 CAMEL_AUTHENTICATION_REJECTED);
513 simple = G_SIMPLE_ASYNC_RESULT (result);
514 async_context = g_simple_async_result_get_op_res_gpointer (simple);
516 if (g_simple_async_result_propagate_error (simple, error))
517 return CAMEL_AUTHENTICATION_ERROR;
519 return async_context->auth_result;
523 service_query_auth_types_thread (GSimpleAsyncResult *simple,
525 GCancellable *cancellable)
527 AsyncContext *async_context;
528 GError *error = NULL;
530 async_context = g_simple_async_result_get_op_res_gpointer (simple);
532 async_context->auth_types = camel_service_query_auth_types_sync (
533 CAMEL_SERVICE (object), cancellable, &error);
536 g_simple_async_result_take_error (simple, error);
540 service_query_auth_types (CamelService *service,
542 GCancellable *cancellable,
543 GAsyncReadyCallback callback,
546 GSimpleAsyncResult *simple;
547 AsyncContext *async_context;
549 async_context = g_slice_new0 (AsyncContext);
551 simple = g_simple_async_result_new (
552 G_OBJECT (service), callback,
553 user_data, service_query_auth_types);
555 g_simple_async_result_set_op_res_gpointer (
556 simple, async_context, (GDestroyNotify) async_context_free);
558 g_simple_async_result_run_in_thread (
559 simple, service_query_auth_types_thread,
560 io_priority, cancellable);
562 g_object_unref (simple);
566 service_query_auth_types_finish (CamelService *service,
567 GAsyncResult *result,
570 GSimpleAsyncResult *simple;
571 AsyncContext *async_context;
573 g_return_val_if_fail (
574 g_simple_async_result_is_valid (
575 result, G_OBJECT (service),
576 service_query_auth_types), NULL);
578 simple = G_SIMPLE_ASYNC_RESULT (result);
579 async_context = g_simple_async_result_get_op_res_gpointer (simple);
581 if (g_simple_async_result_propagate_error (simple, error))
584 return g_list_copy (async_context->auth_types);
588 service_initable_init (GInitable *initable,
589 GCancellable *cancellable,
592 CamelProvider *provider;
593 CamelService *service;
595 gboolean success = FALSE;
596 const gchar *new_data_dir;
600 service = CAMEL_SERVICE (initable);
601 url = camel_service_get_camel_url (service);
602 provider = camel_service_get_provider (service);
604 url_string = camel_url_to_string (url, 0);
606 if (CAMEL_PROVIDER_NEEDS (provider, CAMEL_URL_PART_USER)) {
607 if (url->user == NULL || *url->user == '\0') {
609 error, CAMEL_SERVICE_ERROR,
610 CAMEL_SERVICE_ERROR_URL_INVALID,
611 _("URL '%s' needs a user component"),
617 if (CAMEL_PROVIDER_NEEDS (provider, CAMEL_URL_PART_HOST)) {
618 if (url->host == NULL || *url->host == '\0') {
620 error, CAMEL_SERVICE_ERROR,
621 CAMEL_SERVICE_ERROR_URL_INVALID,
622 _("URL '%s' needs a host component"),
628 if (CAMEL_PROVIDER_NEEDS (provider, CAMEL_URL_PART_PATH)) {
629 if (url->path == NULL || *url->path == '\0') {
631 error, CAMEL_SERVICE_ERROR,
632 CAMEL_SERVICE_ERROR_URL_INVALID,
633 _("URL '%s' needs a path component"),
639 new_data_dir = camel_service_get_user_data_dir (service);
640 old_data_dir = service_find_old_data_dir (service);
642 /* If the old data directory name exists, try renaming
643 * it to the new data directory. Failure is non-fatal. */
644 if (old_data_dir != NULL) {
645 g_rename (old_data_dir, new_data_dir);
646 g_free (old_data_dir);
658 camel_service_class_init (CamelServiceClass *class)
660 GObjectClass *object_class;
662 g_type_class_add_private (class, sizeof (CamelServicePrivate));
664 object_class = G_OBJECT_CLASS (class);
665 object_class->set_property = service_set_property;
666 object_class->get_property = service_get_property;
667 object_class->dispose = service_dispose;
668 object_class->finalize = service_finalize;
669 object_class->constructed = service_constructed;
671 class->settings_type = CAMEL_TYPE_SETTINGS;
672 class->get_name = service_get_name;
673 class->cancel_connect = service_cancel_connect;
674 class->connect_sync = service_connect_sync;
675 class->disconnect_sync = service_disconnect_sync;
676 class->query_auth_types_sync = service_query_auth_types_sync;
678 class->authenticate = service_authenticate;
679 class->authenticate_finish = service_authenticate_finish;
680 class->query_auth_types = service_query_auth_types;
681 class->query_auth_types_finish = service_query_auth_types_finish;
683 g_object_class_install_property (
686 g_param_spec_string (
689 "The display name for the service",
693 G_PARAM_STATIC_STRINGS));
695 g_object_class_install_property (
698 g_param_spec_string (
701 "The password for the service",
705 G_PARAM_STATIC_STRINGS));
707 g_object_class_install_property (
710 g_param_spec_pointer (
713 "The CamelProvider for the service",
715 G_PARAM_CONSTRUCT_ONLY |
716 G_PARAM_STATIC_STRINGS));
718 g_object_class_install_property (
721 g_param_spec_object (
724 "A CamelSession instance",
727 G_PARAM_CONSTRUCT_ONLY |
728 G_PARAM_STATIC_STRINGS));
730 g_object_class_install_property (
733 g_param_spec_object (
736 "A CamelSettings instance",
740 G_PARAM_STATIC_STRINGS));
742 g_object_class_install_property (
745 g_param_spec_string (
748 "The unique identity of the service",
751 G_PARAM_CONSTRUCT_ONLY |
752 G_PARAM_STATIC_STRINGS));
754 g_object_class_install_property (
760 "The CamelURL for the service",
763 G_PARAM_CONSTRUCT_ONLY |
764 G_PARAM_STATIC_STRINGS));
768 camel_service_initable_init (GInitableIface *interface)
770 interface->init = service_initable_init;
774 camel_service_init (CamelService *service)
776 service->priv = CAMEL_SERVICE_GET_PRIVATE (service);
778 service->priv->status = CAMEL_SERVICE_DISCONNECTED;
780 g_static_rec_mutex_init (&service->priv->connect_lock);
781 g_static_mutex_init (&service->priv->connect_op_lock);
785 camel_service_error_quark (void)
787 static GQuark quark = 0;
789 if (G_UNLIKELY (quark == 0)) {
790 const gchar *string = "camel-service-error-quark";
791 quark = g_quark_from_static_string (string);
798 * camel_service_cancel_connect:
799 * @service: a #CamelService
801 * If @service is currently attempting to connect to or disconnect
802 * from a server, this causes it to stop and fail. Otherwise it is a
806 camel_service_cancel_connect (CamelService *service)
808 CamelServiceClass *class;
810 g_return_if_fail (CAMEL_IS_SERVICE (service));
812 class = CAMEL_SERVICE_GET_CLASS (service);
813 g_return_if_fail (class->cancel_connect != NULL);
815 camel_service_lock (service, CAMEL_SERVICE_CONNECT_OP_LOCK);
816 if (service->priv->connect_op)
817 class->cancel_connect (service);
818 camel_service_unlock (service, CAMEL_SERVICE_CONNECT_OP_LOCK);
822 * camel_service_get_display_name:
823 * @service: a #CamelService
825 * Returns the display name for @service, or %NULL if @service has not
826 * been given a display name. The display name is intended for use in
827 * a user interface and should generally be given a user-defined name.
829 * Compare this with camel_service_get_name(), which returns a built-in
830 * description of the type of service (IMAP, SMTP, etc.).
832 * Returns: the display name for @service, or %NULL
837 camel_service_get_display_name (CamelService *service)
839 g_return_val_if_fail (CAMEL_IS_SERVICE (service), NULL);
841 return service->priv->display_name;
845 * camel_service_set_display_name:
846 * @service: a #CamelService
847 * @display_name: a valid UTF-8 string, or %NULL
849 * Assigns a UTF-8 display name to @service. The display name is intended
850 * for use in a user interface and should generally be given a user-defined
853 * Compare this with camel_service_get_name(), which returns a built-in
854 * description of the type of service (IMAP, SMTP, etc.).
859 camel_service_set_display_name (CamelService *service,
860 const gchar *display_name)
862 g_return_if_fail (CAMEL_IS_SERVICE (service));
864 if (display_name != NULL)
865 g_return_if_fail (g_utf8_validate (display_name, -1, NULL));
867 g_free (service->priv->display_name);
868 service->priv->display_name = g_strdup (display_name);
870 g_object_notify (G_OBJECT (service), "display-name");
874 * camel_service_get_password:
875 * @service: a #CamelService
877 * Returns the password for @service. Some SASL mechanisms use this
878 * when attempting to authenticate.
880 * Returns: the password for @service
885 camel_service_get_password (CamelService *service)
887 g_return_val_if_fail (CAMEL_IS_SERVICE (service), NULL);
889 return service->priv->password;
893 * camel_service_set_password:
894 * @service: a #CamelService
895 * @password: the password for @service
897 * Sets the password for @service. Use this function to cache the password
898 * in memory after obtaining it through camel_session_get_password(). Some
899 * SASL mechanisms use this when attempting to authenticate.
904 camel_service_set_password (CamelService *service,
905 const gchar *password)
907 g_return_if_fail (CAMEL_IS_SERVICE (service));
909 g_free (service->priv->password);
910 service->priv->password = g_strdup (password);
912 g_object_notify (G_OBJECT (service), "password");
916 * camel_service_get_user_data_dir:
917 * @service: a #CamelService
919 * Returns the base directory under which to store user-specific data
920 * for @service. The directory is formed by appending the directory
921 * returned by camel_session_get_user_data_dir() with the service's
922 * #CamelService:uid value.
924 * Returns: the base directory for @service
929 camel_service_get_user_data_dir (CamelService *service)
931 g_return_val_if_fail (CAMEL_IS_SERVICE (service), NULL);
933 return service->priv->user_data_dir;
937 * camel_service_get_user_cache_dir:
938 * @service: a #CamelService
940 * Returns the base directory under which to store cache data
941 * for @service. The directory is formed by appending the directory
942 * returned by camel_session_get_user_cache_dir() with the service's
943 * #CamelService:uid value.
945 * Returns: the base cache directory for @service
950 camel_service_get_user_cache_dir (CamelService *service)
952 g_return_val_if_fail (CAMEL_IS_SERVICE (service), NULL);
954 return service->priv->user_cache_dir;
958 * camel_service_get_name:
959 * @service: a #CamelService
960 * @brief: whether or not to use a briefer form
962 * This gets the name of the service in a "friendly" (suitable for
963 * humans) form. If @brief is %TRUE, this should be a brief description
964 * such as for use in the folder tree. If @brief is %FALSE, it should
965 * be a more complete and mostly unambiguous description.
967 * Returns: a description of the service which the caller must free
970 camel_service_get_name (CamelService *service,
973 CamelServiceClass *class;
975 g_return_val_if_fail (CAMEL_IS_SERVICE (service), NULL);
976 g_return_val_if_fail (service->priv->url, NULL);
978 class = CAMEL_SERVICE_GET_CLASS (service);
979 g_return_val_if_fail (class->get_name != NULL, NULL);
981 return class->get_name (service, brief);
985 * camel_service_get_provider:
986 * @service: a #CamelService
988 * Gets the #CamelProvider associated with the service.
990 * Returns: the #CamelProvider
993 camel_service_get_provider (CamelService *service)
995 g_return_val_if_fail (CAMEL_IS_SERVICE (service), NULL);
997 return service->priv->provider;
1001 * camel_service_get_session:
1002 * @service: a #CamelService
1004 * Gets the #CamelSession associated with the service.
1006 * Returns: the #CamelSession
1009 camel_service_get_session (CamelService *service)
1011 g_return_val_if_fail (CAMEL_IS_SERVICE (service), NULL);
1013 return CAMEL_SESSION (service->priv->session);
1017 * camel_service_get_settings:
1018 * @service: a #CamelService
1020 * Returns the #CamelSettings instance associated with the service.
1022 * Returns: the #CamelSettings
1027 camel_service_get_settings (CamelService *service)
1029 g_return_val_if_fail (CAMEL_IS_SERVICE (service), NULL);
1031 /* Every service should have a settings object. */
1032 g_warn_if_fail (service->priv->settings != NULL);
1034 return service->priv->settings;
1038 * camel_service_set_settings:
1039 * @service: a #CamelService
1040 * @settings: an instance derviced from #CamelSettings, or %NULL
1042 * Associates a new #CamelSettings instance with the service.
1043 * The @settings instance must match the settings type defined in
1044 * #CamelServiceClass. If @settings is %NULL, a new #CamelSettings
1045 * instance of the appropriate type is created with all properties
1051 camel_service_set_settings (CamelService *service,
1052 CamelSettings *settings)
1054 CamelServiceClass *class;
1056 g_return_if_fail (CAMEL_IS_SERVICE (service));
1058 class = CAMEL_SERVICE_GET_CLASS (service);
1060 if (settings != NULL) {
1063 G_OBJECT_TYPE (settings),
1064 class->settings_type));
1065 g_object_ref (settings);
1070 class->settings_type,
1071 CAMEL_TYPE_SETTINGS));
1072 settings = g_object_new (class->settings_type, NULL);
1073 camel_settings_load_from_url (settings, camel_service_get_camel_url (service));
1076 if (service->priv->settings != NULL)
1077 g_object_unref (service->priv->settings);
1079 service->priv->settings = settings;
1081 g_object_notify (G_OBJECT (service), "settings");
1085 * camel_service_get_uid:
1086 * @service: a #CamelService
1088 * Gets the unique identifier string associated with the service.
1090 * Returns: the UID string
1095 camel_service_get_uid (CamelService *service)
1097 g_return_val_if_fail (CAMEL_IS_SERVICE (service), NULL);
1099 return service->priv->uid;
1103 * camel_service_get_camel_url:
1104 * @service: a #CamelService
1106 * Returns the #CamelURL representing @service.
1108 * Returns: the #CamelURL representing @service
1113 camel_service_get_camel_url (CamelService *service)
1115 g_return_val_if_fail (CAMEL_IS_SERVICE (service), NULL);
1117 return service->priv->url;
1121 * camel_service_get_url:
1122 * @service: a #CamelService
1124 * Gets the URL representing @service. The returned URL must be
1125 * freed when it is no longer needed.
1127 * Returns: the URL representing @service
1130 camel_service_get_url (CamelService *service)
1134 g_return_val_if_fail (CAMEL_IS_SERVICE (service), NULL);
1136 url = camel_service_get_camel_url (service);
1138 return camel_url_to_string (url, 0);
1142 * camel_service_connect_sync:
1143 * @service: a #CamelService
1144 * @error: return location for a #GError, or %NULL
1146 * Connect to the service using the parameters it was initialized
1149 * Returns: %TRUE if the connection is made or %FALSE otherwise
1152 camel_service_connect_sync (CamelService *service,
1155 CamelServiceClass *class;
1157 gboolean ret = FALSE;
1159 g_return_val_if_fail (CAMEL_IS_SERVICE (service), FALSE);
1160 g_return_val_if_fail (service->priv->session != NULL, FALSE);
1161 g_return_val_if_fail (service->priv->url != NULL, FALSE);
1163 class = CAMEL_SERVICE_GET_CLASS (service);
1164 g_return_val_if_fail (class->connect_sync != NULL, FALSE);
1166 camel_service_lock (service, CAMEL_SERVICE_REC_CONNECT_LOCK);
1168 if (service->priv->status == CAMEL_SERVICE_CONNECTED) {
1169 camel_service_unlock (service, CAMEL_SERVICE_REC_CONNECT_LOCK);
1173 /* Register a separate operation for connecting, so that
1174 * the offline code can cancel it. */
1175 camel_service_lock (service, CAMEL_SERVICE_CONNECT_OP_LOCK);
1176 service->priv->connect_op = camel_operation_new ();
1177 op = service->priv->connect_op;
1178 camel_service_unlock (service, CAMEL_SERVICE_CONNECT_OP_LOCK);
1180 service->priv->status = CAMEL_SERVICE_CONNECTING;
1181 ret = class->connect_sync (service, service->priv->connect_op, error);
1182 CAMEL_CHECK_GERROR (service, connect_sync, ret, error);
1183 service->priv->status =
1184 ret ? CAMEL_SERVICE_CONNECTED : CAMEL_SERVICE_DISCONNECTED;
1186 camel_service_lock (service, CAMEL_SERVICE_CONNECT_OP_LOCK);
1187 g_object_unref (op);
1188 if (op == service->priv->connect_op)
1189 service->priv->connect_op = NULL;
1190 camel_service_unlock (service, CAMEL_SERVICE_CONNECT_OP_LOCK);
1192 camel_service_unlock (service, CAMEL_SERVICE_REC_CONNECT_LOCK);
1198 * camel_service_disconnect_sync:
1199 * @service: a #CamelService
1200 * @clean: whether or not to try to disconnect cleanly
1201 * @error: return location for a #GError, or %NULL
1203 * Disconnect from the service. If @clean is %FALSE, it should not
1204 * try to do any synchronizing or other cleanup of the connection.
1206 * Returns: %TRUE if the disconnect was successful or %FALSE otherwise
1209 camel_service_disconnect_sync (CamelService *service,
1213 CamelServiceClass *class;
1214 gboolean res = TRUE;
1216 g_return_val_if_fail (CAMEL_IS_SERVICE (service), FALSE);
1218 class = CAMEL_SERVICE_GET_CLASS (service);
1219 g_return_val_if_fail (class->disconnect_sync != NULL, FALSE);
1221 camel_service_lock (service, CAMEL_SERVICE_REC_CONNECT_LOCK);
1223 if (service->priv->status != CAMEL_SERVICE_DISCONNECTED
1224 && service->priv->status != CAMEL_SERVICE_DISCONNECTING) {
1226 camel_service_lock (service, CAMEL_SERVICE_CONNECT_OP_LOCK);
1227 service->priv->connect_op = camel_operation_new ();
1228 op = service->priv->connect_op;
1229 camel_service_unlock (service, CAMEL_SERVICE_CONNECT_OP_LOCK);
1231 service->priv->status = CAMEL_SERVICE_DISCONNECTING;
1232 res = class->disconnect_sync (
1233 service, clean, service->priv->connect_op, error);
1234 CAMEL_CHECK_GERROR (service, disconnect_sync, res, error);
1235 service->priv->status = CAMEL_SERVICE_DISCONNECTED;
1237 camel_service_lock (service, CAMEL_SERVICE_CONNECT_OP_LOCK);
1238 g_object_unref (op);
1239 if (op == service->priv->connect_op)
1240 service->priv->connect_op = NULL;
1241 camel_service_unlock (service, CAMEL_SERVICE_CONNECT_OP_LOCK);
1244 camel_service_unlock (service, CAMEL_SERVICE_REC_CONNECT_LOCK);
1246 service->priv->status = CAMEL_SERVICE_DISCONNECTED;
1252 * camel_service_get_connection_status:
1253 * @service: a #CamelService
1255 * Returns the connection status for @service.
1257 * Returns: the connection status
1261 CamelServiceConnectionStatus
1262 camel_service_get_connection_status (CamelService *service)
1264 g_return_val_if_fail (
1265 CAMEL_IS_SERVICE (service), CAMEL_SERVICE_DISCONNECTED);
1267 return service->priv->status;
1271 * camel_service_lock:
1272 * @service: a #CamelService
1273 * @lock: lock type to lock
1275 * Locks @service's @lock. Unlock it with camel_service_unlock().
1280 camel_service_lock (CamelService *service,
1281 CamelServiceLock lock)
1283 g_return_if_fail (CAMEL_IS_SERVICE (service));
1286 case CAMEL_SERVICE_REC_CONNECT_LOCK:
1287 g_static_rec_mutex_lock (&service->priv->connect_lock);
1289 case CAMEL_SERVICE_CONNECT_OP_LOCK:
1290 g_static_mutex_lock (&service->priv->connect_op_lock);
1293 g_return_if_reached ();
1298 * camel_service_unlock:
1299 * @service: a #CamelService
1300 * @lock: lock type to unlock
1302 * Unlocks @service's @lock, previously locked with camel_service_lock().
1307 camel_service_unlock (CamelService *service,
1308 CamelServiceLock lock)
1310 g_return_if_fail (CAMEL_IS_SERVICE (service));
1313 case CAMEL_SERVICE_REC_CONNECT_LOCK:
1314 g_static_rec_mutex_unlock (&service->priv->connect_lock);
1316 case CAMEL_SERVICE_CONNECT_OP_LOCK:
1317 g_static_mutex_unlock (&service->priv->connect_op_lock);
1320 g_return_if_reached ();
1325 * camel_service_authenticate_sync:
1326 * @service: a #CamelService
1327 * @mechanism: a SASL mechanism name, or %NULL
1328 * @cancellable: optional #GCancellable object, or %NULL
1329 * @error: return location for a #GError, or %NULL
1331 * Attempts to authenticate @service using @mechanism and, if necessary,
1332 * @service's #CamelService:password property. The function makes only
1333 * ONE attempt at authentication and does not loop.
1335 * If the authentication attempt completed and the server accepted the
1336 * credentials, the function returns #CAMEL_AUTHENTICATION_ACCEPTED.
1338 * If the authentication attempt completed but the server rejected the
1339 * credentials, the function returns #CAMEL_AUTHENTICATION_REJECTED.
1341 * If the authentication attempt failed to complete due to a network
1342 * communication issue or some other mishap, the function sets @error
1343 * and returns #CAMEL_AUTHENTICATION_ERROR.
1345 * Generally this function should only be called from a #CamelSession
1346 * subclass in order to implement its own authentication loop.
1348 * Returns: the authentication result
1352 CamelAuthenticationResult
1353 camel_service_authenticate_sync (CamelService *service,
1354 const gchar *mechanism,
1355 GCancellable *cancellable,
1358 CamelServiceClass *class;
1359 CamelAuthenticationResult result;
1361 g_return_val_if_fail (
1362 CAMEL_IS_SERVICE (service),
1363 CAMEL_AUTHENTICATION_REJECTED);
1365 class = CAMEL_SERVICE_GET_CLASS (service);
1366 g_return_val_if_fail (
1367 class->authenticate_sync != NULL,
1368 CAMEL_AUTHENTICATION_REJECTED);
1370 result = class->authenticate_sync (
1371 service, mechanism, cancellable, error);
1372 CAMEL_CHECK_GERROR (
1373 service, authenticate_sync,
1374 result != CAMEL_AUTHENTICATION_ERROR, error);
1380 * camel_service_authenticate:
1381 * @service: a #CamelService
1382 * @mechanism: a SASL mechanism name, or %NULL
1383 * @io_priority: the I/O priority of the request
1384 * @cancellable: optional #GCancellable object, or %NULL
1385 * @callback: a #GAsyncReadyCallback to call when the request is satisfied
1386 * @user_data: data to pass to the callback function
1388 * Asynchronously attempts to authenticate @service using @mechanism and,
1389 * if necessary, @service's #CamelService:password property. The function
1390 * makes only ONE attempt at authentication and does not loop.
1392 * Generally this function should only be called from a #CamelSession
1393 * subclass in order to implement its own authentication loop.
1395 * When the operation is finished, @callback will be called. You can
1396 * then call camel_service_authenticate_finish() to get the result of
1402 camel_service_authenticate (CamelService *service,
1403 const gchar *mechanism,
1405 GCancellable *cancellable,
1406 GAsyncReadyCallback callback,
1409 CamelServiceClass *class;
1411 g_return_if_fail (CAMEL_IS_SERVICE (service));
1413 class = CAMEL_SERVICE_GET_CLASS (service);
1414 g_return_if_fail (class->authenticate != NULL);
1416 class->authenticate (
1417 service, mechanism, io_priority,
1418 cancellable, callback, user_data);
1422 * camel_service_authenticate_finish:
1423 * @service: a #CamelService
1424 * @result: a #GAsyncResult
1425 * @error: return location for a #GError, or %NULL
1427 * Finishes the operation started with camel_service_authenticate().
1429 * If the authentication attempt completed and the server accepted the
1430 * credentials, the function returns #CAMEL_AUTHENTICATION_ACCEPTED.
1432 * If the authentication attempt completed but the server rejected the
1433 * credentials, the function returns #CAMEL_AUTHENTICATION_REJECTED.
1435 * If the authentication attempt failed to complete due to a network
1436 * communication issue or some other mishap, the function sets @error
1437 * and returns #CAMEL_AUTHENTICATION_ERROR.
1439 * Returns: the authentication result
1443 CamelAuthenticationResult
1444 camel_service_authenticate_finish (CamelService *service,
1445 GAsyncResult *result,
1448 CamelServiceClass *class;
1450 g_return_val_if_fail (
1451 CAMEL_IS_SERVICE (service),
1452 CAMEL_AUTHENTICATION_REJECTED);
1453 g_return_val_if_fail (
1454 G_IS_ASYNC_RESULT (result),
1455 CAMEL_AUTHENTICATION_REJECTED);
1457 class = CAMEL_SERVICE_GET_CLASS (service);
1458 g_return_val_if_fail (
1459 class->authenticate_finish,
1460 CAMEL_AUTHENTICATION_REJECTED);
1462 return class->authenticate_finish (service, result, error);
1466 * camel_service_query_auth_types_sync:
1467 * @service: a #CamelService
1468 * @cancellable: optional #GCancellable object, or %NULL
1469 * @error: return location for a #GError, or %NULL
1471 * Obtains a list of authentication types supported by @service.
1472 * Free the returned list with g_list_free().
1474 * Returns: a list of #CamelServiceAuthType structs
1477 camel_service_query_auth_types_sync (CamelService *service,
1478 GCancellable *cancellable,
1481 CamelServiceClass *class;
1484 g_return_val_if_fail (CAMEL_IS_SERVICE (service), NULL);
1486 class = CAMEL_SERVICE_GET_CLASS (service);
1487 g_return_val_if_fail (class->query_auth_types_sync != NULL, NULL);
1489 /* Note that we get the connect lock here, which means the
1490 * callee must not call the connect functions itself. */
1491 camel_service_lock (service, CAMEL_SERVICE_REC_CONNECT_LOCK);
1492 list = class->query_auth_types_sync (service, cancellable, error);
1493 camel_service_unlock (service, CAMEL_SERVICE_REC_CONNECT_LOCK);
1499 * camel_service_query_auth_types:
1500 * @service: a #CamelService
1501 * @io_priority: the I/O priority of the request
1502 * @cancellable: optional #GCancellable object, or %NULL
1503 * @callback: a #GAsyncReadyCallback to call when the request is satisfied
1504 * @user_data: data to pass to the callback function
1506 * Asynchronously obtains a list of authentication types supported by
1509 * When the operation is finished, @callback will be called. You can
1510 * then call camel_service_query_auth_types_finish() to get the result
1516 camel_service_query_auth_types (CamelService *service,
1518 GCancellable *cancellable,
1519 GAsyncReadyCallback callback,
1522 CamelServiceClass *class;
1524 g_return_if_fail (CAMEL_IS_SERVICE (service));
1526 class = CAMEL_SERVICE_GET_CLASS (service);
1527 g_return_if_fail (class->query_auth_types != NULL);
1529 class->query_auth_types (
1530 service, io_priority,
1531 cancellable, callback, user_data);
1535 * camel_service_query_auth_types_finish:
1536 * @service: a #CamelService
1537 * @result: a #GAsyncResult
1538 * @error: return location for a #GError, or %NULL
1540 * Finishes the operation started with camel_service_query_auth_types().
1541 * Free the returned list with g_list_free().
1543 * Returns: a list of #CamelServiceAuthType structs
1548 camel_service_query_auth_types_finish (CamelService *service,
1549 GAsyncResult *result,
1552 CamelServiceClass *class;
1554 g_return_val_if_fail (CAMEL_IS_SERVICE (service), NULL);
1555 g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
1557 class = CAMEL_SERVICE_GET_CLASS (service);
1558 g_return_val_if_fail (class->query_auth_types_finish != NULL, NULL);
1560 return class->query_auth_types_finish (service, result, error);