1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /* camel-imap-store.c : class for a imap store */
4 * Authors: Michael Zucchi <notzed@ximian.com>
6 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of version 2 of the GNU Lesser General Public
10 * License as published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
27 #include <sys/types.h>
31 #include <sys/socket.h>
32 #include <netinet/in.h>
39 #include <glib/gstdio.h>
40 #include <glib/gi18n-lib.h>
42 #include "camel-imapx-folder.h"
43 #include "camel-imapx-server.h"
44 #include "camel-imapx-settings.h"
45 #include "camel-imapx-store.h"
46 #include "camel-imapx-summary.h"
47 #include "camel-imapx-utils.h"
49 /* Specified in RFC 2060 section 2.1 */
51 #define IMAPS_PORT 993
53 #define FINFO_REFRESH_INTERVAL 60
55 static GInitableIface *parent_initable_interface;
57 /* Forward Declarations */
58 static void camel_imapx_store_initable_init (GInitableIface *interface);
59 static void camel_network_service_init (CamelNetworkServiceInterface *interface);
60 static void camel_subscribable_init (CamelSubscribableInterface *interface);
62 G_DEFINE_TYPE_WITH_CODE (
65 CAMEL_TYPE_OFFLINE_STORE,
66 G_IMPLEMENT_INTERFACE (
68 camel_imapx_store_initable_init)
69 G_IMPLEMENT_INTERFACE (
70 CAMEL_TYPE_NETWORK_SERVICE,
71 camel_network_service_init)
72 G_IMPLEMENT_INTERFACE (
73 CAMEL_TYPE_SUBSCRIBABLE,
74 camel_subscribable_init))
77 imapx_name_hash (gconstpointer key)
79 if (g_ascii_strcasecmp(key, "INBOX") == 0)
80 return g_str_hash("INBOX");
82 return g_str_hash (key);
86 imapx_name_equal (gconstpointer a,
89 gconstpointer aname = a, bname = b;
91 if (g_ascii_strcasecmp(a, "INBOX") == 0)
93 if (g_ascii_strcasecmp(b, "INBOX") == 0)
95 return g_str_equal (aname, bname);
99 imapx_store_dispose (GObject *object)
101 CamelIMAPXStore *imapx_store = CAMEL_IMAPX_STORE (object);
103 /* Force disconnect so we dont have it run later,
104 * after we've cleaned up some stuff. */
105 if (imapx_store->con_man != NULL) {
106 camel_service_disconnect_sync (
107 CAMEL_SERVICE (imapx_store), TRUE, NULL, NULL);
108 g_object_unref (imapx_store->con_man);
109 imapx_store->con_man = NULL;
112 if (imapx_store->authenticating_server != NULL) {
113 g_object_unref (imapx_store->authenticating_server);
114 imapx_store->authenticating_server = NULL;
117 if (imapx_store->summary != NULL) {
118 g_object_unref (imapx_store->summary);
119 imapx_store->summary = NULL;
122 /* Chain up to parent's dispose() method. */
123 G_OBJECT_CLASS (camel_imapx_store_parent_class)->dispose (object);
127 imapx_store_finalize (GObject *object)
129 CamelIMAPXStore *imapx_store = CAMEL_IMAPX_STORE (object);
131 g_mutex_free (imapx_store->get_finfo_lock);
133 /* Chain up to parent's finalize() method. */
134 G_OBJECT_CLASS (camel_imapx_store_parent_class)->finalize (object);
138 imapx_get_name (CamelService *service,
141 CamelNetworkSettings *network_settings;
142 CamelSettings *settings;
147 settings = camel_service_get_settings (service);
149 network_settings = CAMEL_NETWORK_SETTINGS (settings);
150 host = camel_network_settings_dup_host (network_settings);
151 user = camel_network_settings_dup_user (network_settings);
154 name = g_strdup_printf (
155 _("IMAP server %s"), host);
157 name = g_strdup_printf (
158 _("IMAP service for %s on %s"), user, host);
167 camel_imapx_store_get_server (CamelIMAPXStore *istore,
168 const gchar *folder_name,
169 GCancellable *cancellable,
172 return camel_imapx_conn_manager_get_connection (
173 istore->con_man, folder_name, cancellable, error);
177 camel_imapx_store_op_done (CamelIMAPXStore *istore,
178 CamelIMAPXServer *server,
179 const gchar *folder_name)
181 g_return_if_fail (server != NULL);
183 camel_imapx_conn_manager_update_con_info (
184 istore->con_man, server, folder_name);
188 imapx_connect_sync (CamelService *service,
189 GCancellable *cancellable,
192 CamelIMAPXStore *istore = (CamelIMAPXStore *) service;
193 CamelIMAPXServer *server;
195 server = camel_imapx_store_get_server (istore, NULL, cancellable, error);
197 g_object_unref (server);
205 imapx_disconnect_sync (CamelService *service,
207 GCancellable *cancellable,
210 CamelIMAPXStore *istore = CAMEL_IMAPX_STORE (service);
211 CamelServiceClass *service_class;
213 service_class = CAMEL_SERVICE_CLASS (camel_imapx_store_parent_class);
214 if (!service_class->disconnect_sync (service, clean, cancellable, error))
217 if (istore->con_man != NULL)
218 camel_imapx_conn_manager_close_connections (istore->con_man);
223 static CamelAuthenticationResult
224 imapx_authenticate_sync (CamelService *service,
225 const gchar *mechanism,
226 GCancellable *cancellable,
229 CamelIMAPXStore *istore = CAMEL_IMAPX_STORE (service);
230 CamelIMAPXServer *server;
232 /* CamelIMAPXConnManager sets this before calling
233 * camel_imapx_server_connect()(), and then clears it
234 * immediately after, all while holding the recursive
235 * connection lock (CAMEL_SERVICE_REC_CONNECT_LOCK).
236 * Otherwise we'd have no way of knowing which server
237 * is trying to authenticate. */
238 server = istore->authenticating_server;
240 g_return_val_if_fail (
241 CAMEL_IS_IMAPX_SERVER (server),
242 CAMEL_AUTHENTICATION_REJECTED);
244 return camel_imapx_server_authenticate (
245 server, mechanism, cancellable, error);
248 CamelServiceAuthType camel_imapx_password_authtype = {
251 N_("This option will connect to the IMAP server using a "
252 "plaintext password."),
259 imapx_query_auth_types_sync (CamelService *service,
260 GCancellable *cancellable,
263 CamelIMAPXStore *istore = CAMEL_IMAPX_STORE (service);
264 CamelServiceAuthType *authtype;
265 GList *sasl_types, *t, *next;
267 CamelIMAPXServer *server;
269 if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (istore))) {
271 error, CAMEL_SERVICE_ERROR,
272 CAMEL_SERVICE_ERROR_UNAVAILABLE,
273 _("You must be working online to complete this operation"));
277 server = camel_imapx_server_new (CAMEL_STORE (istore));
279 connected = server->stream != NULL;
281 connected = imapx_connect_to_server (server, cancellable, error);
285 sasl_types = camel_sasl_authtype_list (FALSE);
286 for (t = sasl_types; t; t = next) {
290 if (!g_hash_table_lookup (server->cinfo->auth_types, authtype->authproto)) {
291 sasl_types = g_list_remove_link (sasl_types, t);
296 g_object_unref (server);
298 return g_list_prepend (sasl_types, &camel_imapx_password_authtype);
302 get_folder_offline (CamelStore *store,
303 const gchar *folder_name,
307 CamelIMAPXStore *imapx_store = CAMEL_IMAPX_STORE (store);
308 CamelFolder *new_folder = NULL;
310 CamelService *service;
311 const gchar *user_cache_dir;
313 service = CAMEL_SERVICE (store);
314 user_cache_dir = camel_service_get_user_cache_dir (service);
316 si = camel_store_summary_path ((CamelStoreSummary *) imapx_store->summary, folder_name);
318 gchar *folder_dir, *storage_path;
320 /* Note: Although the INBOX is defined to be case-insensitive in the IMAP RFC
321 * it is still up to the server how to acutally name it in a LIST response. Since
322 * we stored the name as the server provided it us in the summary we take that name
323 * to look up the folder.
324 * But for the on-disk cache we do always capitalize the Inbox no matter what the
327 if (!g_ascii_strcasecmp (folder_name, "INBOX"))
328 folder_name = "INBOX";
330 storage_path = g_build_filename (user_cache_dir, "folders", NULL);
331 folder_dir = imapx_path_to_physical (storage_path, folder_name);
332 g_free (storage_path);
334 new_folder = camel_imapx_folder_new (store, folder_dir, folder_name, error);
337 camel_store_summary_info_free ((CamelStoreSummary *) imapx_store->summary, si);
340 error, CAMEL_STORE_ERROR,
341 CAMEL_STORE_ERROR_NO_FOLDER,
342 _("No such folder %s"), folder_name);
348 /* folder_name is path name */
349 static CamelFolderInfo *
350 imapx_build_folder_info (CamelIMAPXStore *imapx_store,
351 const gchar *folder_name)
356 fi = camel_folder_info_new ();
357 fi->full_name = g_strdup (folder_name);
361 name = strrchr (fi->full_name, '/');
363 name = fi->full_name;
366 if (!g_ascii_strcasecmp (fi->full_name, "INBOX"))
367 fi->display_name = g_strdup (_("Inbox"));
368 /* Do not localize the rest, these are from a server, thus shouldn't be localized */
369 /*else if (!g_ascii_strcasecmp (fi->full_name, "Drafts"))
370 fi->display_name = g_strdup (_("Drafts"));
371 else if (!g_ascii_strcasecmp (fi->full_name, "Sent"))
372 fi->display_name = g_strdup (_("Sent"));
373 else if (!g_ascii_strcasecmp (fi->full_name, "Templates"))
374 fi->display_name = g_strdup (_("Templates"));
375 else if (!g_ascii_strcasecmp (fi->full_name, "Trash"))
376 fi->display_name = g_strdup (_("Trash"));*/
378 fi->display_name = g_strdup (name);
384 fill_fi (CamelStore *store,
389 CamelService *service = (CamelService *) store;
390 CamelSettings *settings;
391 gboolean mobile_mode;
393 settings = camel_service_get_settings (service);
394 mobile_mode = camel_imapx_settings_get_mobile_mode (
395 CAMEL_IMAPX_SETTINGS (settings));
397 folder = camel_object_bag_peek (store->folders, fi->full_name);
399 CamelIMAPXSummary *ims;
402 ims = (CamelIMAPXSummary *) folder->summary;
404 ims = (CamelIMAPXSummary *) camel_imapx_summary_new (folder);
406 /* Mobile clients would still love to see the total unread of actual mails
407 * than what they just have downloaded. So we override that information by giving
408 * what the server has instead of what we have downloaded. */
410 fi->unread = ((CamelIMAPXFolder *) folder)->unread_on_server;
412 fi->unread = camel_folder_summary_get_unread_count ((CamelFolderSummary *) ims);
413 fi->total = camel_folder_summary_get_saved_count ((CamelFolderSummary *) ims);
415 if (!folder->summary)
416 g_object_unref (ims);
417 g_object_unref (folder);
421 /* imap needs to treat inbox case insensitive */
422 /* we'll assume the names are normalized already */
424 folder_hash (gconstpointer ap)
428 if (g_ascii_strcasecmp(a, "INBOX") == 0)
431 return g_str_hash (a);
435 folder_eq (gconstpointer ap,
441 if (g_ascii_strcasecmp(a, "INBOX") == 0)
443 if (g_ascii_strcasecmp(b, "INBOX") == 0)
446 return g_str_equal (a, b);
450 imapx_match_pattern (CamelIMAPXStoreNamespace *ns,
451 const gchar *pattern,
466 } else if (p == '%') {
472 } else if (p == '*') {
478 return n == 0 && (p == '%' || p == 0);
482 imapx_unmark_folder_subscribed (CamelIMAPXStore *istore,
483 const gchar *folder_name,
484 gboolean emit_signal)
488 si = camel_store_summary_path ((CamelStoreSummary *) istore->summary, folder_name);
490 if (si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED) {
491 si->flags &= ~CAMEL_STORE_INFO_FOLDER_SUBSCRIBED;
492 camel_store_summary_touch ((CamelStoreSummary *) istore->summary);
493 camel_store_summary_save ((CamelStoreSummary *) istore->summary);
495 camel_store_summary_info_free ((CamelStoreSummary *) istore->summary, si);
501 fi = imapx_build_folder_info (istore, folder_name);
502 camel_subscribable_folder_unsubscribed (
503 CAMEL_SUBSCRIBABLE (istore), fi);
504 camel_folder_info_free (fi);
509 imapx_mark_folder_subscribed (CamelIMAPXStore *istore,
510 const gchar *folder_name,
511 gboolean emit_signal)
515 si = camel_store_summary_path ((CamelStoreSummary *) istore->summary, folder_name);
517 if ((si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED) == 0) {
518 si->flags |= CAMEL_STORE_INFO_FOLDER_SUBSCRIBED;
519 camel_store_summary_touch ((CamelStoreSummary *) istore->summary);
520 camel_store_summary_save ((CamelStoreSummary *) istore->summary);
522 camel_store_summary_info_free ((CamelStoreSummary *) istore->summary, si);
528 fi = imapx_build_folder_info (istore, folder_name);
529 camel_subscribable_folder_subscribed (
530 CAMEL_SUBSCRIBABLE (istore), fi);
531 camel_folder_info_free (fi);
536 imapx_subscribe_folder (CamelStore *store,
537 const gchar *folder_name,
538 gboolean emit_signal,
539 GCancellable *cancellable,
542 CamelIMAPXStore *istore = (CamelIMAPXStore *) store;
543 CamelIMAPXServer *server;
546 if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store)))
549 server = camel_imapx_store_get_server (istore, NULL, cancellable, error);
553 success = camel_imapx_server_manage_subscription (
554 server, folder_name, TRUE, cancellable, error);
555 g_object_unref (server);
558 imapx_mark_folder_subscribed (istore, folder_name, emit_signal);
564 imapx_unsubscribe_folder (CamelStore *store,
565 const gchar *folder_name,
566 gboolean emit_signal,
567 GCancellable *cancellable,
570 CamelIMAPXStore *istore = (CamelIMAPXStore *) store;
571 CamelIMAPXServer *server;
574 if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store)))
577 server = camel_imapx_store_get_server (istore, NULL, cancellable, error);
581 success = camel_imapx_server_manage_subscription (
582 server, folder_name, FALSE, cancellable, error);
583 g_object_unref (server);
586 imapx_unmark_folder_subscribed (istore, folder_name, emit_signal);
592 imapx_delete_folder_from_cache (CamelIMAPXStore *istore,
593 const gchar *folder_name)
596 gchar *folder_dir, *storage_path;
598 CamelService *service;
599 const gchar *user_cache_dir;
601 service = CAMEL_SERVICE (istore);
602 user_cache_dir = camel_service_get_user_cache_dir (service);
604 storage_path = g_build_filename (user_cache_dir, "folders", NULL);
605 folder_dir = imapx_path_to_physical (storage_path, folder_name);
606 g_free (storage_path);
607 if (g_access (folder_dir, F_OK) != 0) {
612 /* Delete summary and all the data */
613 state_file = g_build_filename (folder_dir, "cmeta", NULL);
614 g_unlink (state_file);
617 camel_db_delete_folder (((CamelStore *) istore)->cdb_w, folder_name, NULL);
618 g_rmdir (folder_dir);
620 state_file = g_build_filename (folder_dir, "subfolders", NULL);
621 g_rmdir (state_file);
624 g_rmdir (folder_dir);
628 camel_store_summary_remove_path ((CamelStoreSummary *) istore->summary, folder_name);
629 camel_store_summary_save ((CamelStoreSummary *) istore->summary);
631 fi = imapx_build_folder_info (istore, folder_name);
632 camel_store_folder_deleted (CAMEL_STORE (istore), fi);
633 camel_folder_info_free (fi);
637 rename_folder_info (CamelIMAPXStore *istore,
638 const gchar *old_name,
639 const gchar *new_name)
643 gint olen = strlen (old_name);
645 gchar *npath, *nfull;
647 count = camel_store_summary_count ((CamelStoreSummary *) istore->summary);
648 for (i = 0; i < count; i++) {
649 si = camel_store_summary_index ((CamelStoreSummary *) istore->summary, i);
652 path = camel_store_info_path (istore->summary, si);
653 if (strncmp (path, old_name, olen) == 0) {
654 if (strlen (path) > olen)
655 npath = g_strdup_printf("%s/%s", new_name, path+olen+1);
657 npath = g_strdup (new_name);
658 nfull = camel_imapx_store_summary_path_to_full (istore->summary, npath, istore->dir_sep);
660 camel_store_info_set_string ((CamelStoreSummary *) istore->summary, si, CAMEL_STORE_INFO_PATH, npath);
661 camel_store_info_set_string ((CamelStoreSummary *) istore->summary, si, CAMEL_IMAPX_STORE_INFO_FULL_NAME, nfull);
663 camel_store_summary_touch ((CamelStoreSummary *) istore->summary);
667 camel_store_summary_info_free ((CamelStoreSummary *) istore->summary, si);
671 static CamelFolderInfo *
672 get_folder_info_offline (CamelStore *store,
677 CamelIMAPXStore *imapx_store = CAMEL_IMAPX_STORE (store);
678 CamelService *service;
679 CamelSettings *settings;
680 gboolean include_inbox = FALSE;
683 gchar *pattern, *name;
684 gboolean use_namespace;
685 gboolean use_subscriptions;
688 service = CAMEL_SERVICE (store);
689 settings = camel_service_get_settings (service);
691 use_namespace = camel_imapx_settings_get_use_namespace (
692 CAMEL_IMAPX_SETTINGS (settings));
694 use_subscriptions = camel_imapx_settings_get_use_subscriptions (
695 CAMEL_IMAPX_SETTINGS (settings));
697 /* FIXME: obey other flags */
699 folders = g_ptr_array_new ();
701 if (top == NULL || top[0] == '\0') {
702 include_inbox = TRUE;
706 /* get starting point */
708 gchar *namespace = NULL;
711 namespace = camel_imapx_settings_dup_namespace (
712 CAMEL_IMAPX_SETTINGS (settings));
714 if (namespace != NULL) {
715 name = g_strdup (imapx_store->summary->namespaces->personal->full_name);
716 top = imapx_store->summary->namespaces->personal->path;
722 name = camel_imapx_store_summary_full_from_path (imapx_store->summary, top);
724 name = camel_imapx_store_summary_path_to_full (imapx_store->summary, top, imapx_store->dir_sep);
727 pattern = imapx_concat(imapx_store, name, "*");
729 /* folder_info_build will insert parent nodes as necessary and mark
730 * them as noselect, which is information we actually don't have at
731 * the moment. So let it do the right thing by bailing out if it's
732 * not a folder we're explicitly interested in. */
734 for (i = 0; i < camel_store_summary_count ((CamelStoreSummary *) imapx_store->summary); i++) {
735 CamelStoreInfo *si = camel_store_summary_index ((CamelStoreSummary *) imapx_store->summary, i);
736 const gchar *full_name;
737 CamelIMAPXStoreNamespace *ns;
742 full_name = camel_imapx_store_info_full_name (imapx_store->summary, si);
743 if (!full_name || !*full_name) {
744 camel_store_summary_info_free ((CamelStoreSummary *) imapx_store->summary, si);
748 ns = camel_imapx_store_summary_namespace_find_full (imapx_store->summary, full_name);
750 /* Modify the checks to see match the namespaces from preferences */
751 if ((g_str_equal (name, full_name)
752 || imapx_match_pattern (ns, pattern, full_name)
753 || (include_inbox && !g_ascii_strcasecmp (full_name, "INBOX")))
754 && ( (!use_subscriptions
755 || (flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED) == 0)
756 || (si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED)
757 || (flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIPTION_LIST) != 0)) {
759 fi = imapx_build_folder_info (imapx_store, camel_store_info_path ((CamelStoreSummary *) imapx_store->summary, si));
760 fi->unread = si->unread;
761 fi->total = si->total;
762 fi->flags = si->flags;
763 /* HACK: some servers report noinferiors for all folders (uw-imapd)
764 * We just translate this into nochildren, and let the imap layer enforce
765 * it. See create folder */
766 if (fi->flags & CAMEL_FOLDER_NOINFERIORS)
767 fi->flags = (fi->flags & ~CAMEL_FOLDER_NOINFERIORS) | CAMEL_FOLDER_NOCHILDREN;
769 /* blah, this gets lost somewhere, i can't be bothered finding out why */
770 if (!g_ascii_strcasecmp(fi->full_name, "inbox")) {
771 fi->flags = (fi->flags & ~CAMEL_FOLDER_TYPE_MASK) | CAMEL_FOLDER_TYPE_INBOX;
772 fi->flags |= CAMEL_FOLDER_SYSTEM;
775 if (!(si->flags & CAMEL_FOLDER_NOSELECT))
776 fill_fi ((CamelStore *) imapx_store, fi, 0);
779 fi->flags |= CAMEL_FOLDER_NOCHILDREN;
780 g_ptr_array_add (folders, fi);
782 camel_store_summary_info_free ((CamelStoreSummary *) imapx_store->summary, si);
786 fi = camel_folder_info_build (folders, top, '/', TRUE);
787 g_ptr_array_free (folders, TRUE);
794 add_folders_to_summary (CamelIMAPXStore *istore,
795 CamelIMAPXServer *server,
802 for (i = 0; i < folders->len; i++) {
803 struct _list_info *li = folders->pdata[i];
804 CamelIMAPXStoreInfo *si;
806 CamelFolderInfo *fi, *sfi;
810 path = camel_imapx_store_summary_path_to_full (istore->summary, li->name, li->separator);
811 sfi = g_hash_table_lookup (table, path);
813 sfi->flags |= CAMEL_STORE_INFO_FOLDER_SUBSCRIBED;
819 si = camel_imapx_store_summary_add_from_full (istore->summary, li->name, li->separator);
823 new_flags = (si->info.flags & (CAMEL_STORE_INFO_FOLDER_SUBSCRIBED | CAMEL_STORE_INFO_FOLDER_CHECK_FOR_NEW)) |
824 (li->flags & ~CAMEL_STORE_INFO_FOLDER_SUBSCRIBED);
826 if (!(server->cinfo->capa & IMAPX_CAPABILITY_NAMESPACE))
827 istore->dir_sep = li->separator;
829 if (si->info.flags != new_flags) {
830 si->info.flags = new_flags;
831 camel_store_summary_touch ((CamelStoreSummary *) istore->summary);
834 fi = camel_folder_info_new ();
835 fi->full_name = g_strdup (camel_store_info_path (istore->summary, si));
836 if (!g_ascii_strcasecmp(fi->full_name, "inbox")) {
837 li->flags |= CAMEL_FOLDER_SYSTEM | CAMEL_FOLDER_TYPE_INBOX;
838 fi->display_name = g_strdup (_("Inbox"));
840 fi->display_name = g_strdup (camel_store_info_name (istore->summary, si));
842 /* HACK: some servers report noinferiors for all folders (uw-imapd)
843 * We just translate this into nochildren, and let the imap layer enforce
844 * it. See create folder */
845 if (li->flags & CAMEL_FOLDER_NOINFERIORS)
846 li->flags = (li->flags & ~CAMEL_FOLDER_NOINFERIORS) | CAMEL_FOLDER_NOCHILDREN;
847 fi->flags = li->flags;
852 g_hash_table_insert (table, fi->full_name, fi);
857 free_list (gpointer data,
860 struct _list_info *li = data;
861 imapx_free_list (li);
865 imapx_get_folders_free (gpointer k,
869 camel_folder_info_free (v);
873 fetch_folders_for_pattern (CamelIMAPXStore *istore,
874 CamelIMAPXServer *server,
875 const gchar *pattern,
879 GCancellable *cancellable,
884 folders = camel_imapx_server_list (
885 server, pattern, flags, ext, cancellable, error);
889 add_folders_to_summary (istore, server, folders, table, (flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED));
891 g_ptr_array_foreach (folders, free_list, folders);
892 g_ptr_array_free (folders, TRUE);
898 get_namespaces (CamelIMAPXStore *istore)
900 GList *namespaces = NULL;
901 CamelIMAPXNamespaceList *nsl = NULL;
903 /* Add code to return the namespaces from preference else all of them */
904 nsl = istore->summary->namespaces;
906 namespaces = g_list_append (namespaces, nsl->personal);
908 namespaces = g_list_append (namespaces, nsl->other);
910 namespaces = g_list_append (namespaces, nsl->shared);
916 fetch_folders_for_namespaces (CamelIMAPXStore *istore,
917 const gchar *pattern,
919 GCancellable *cancellable,
922 CamelIMAPXServer *server;
923 GHashTable *folders = NULL;
924 GList *namespaces = NULL, *l;
926 server = camel_imapx_store_get_server (istore, NULL, cancellable, error);
930 folders = g_hash_table_new (folder_hash, folder_eq);
931 namespaces = get_namespaces (istore);
933 for (l = namespaces; l != NULL; l = g_list_next (l))
935 CamelIMAPXStoreNamespace *ns = l->data;
940 const gchar *list_ext = NULL;
946 pat = g_strdup_printf ("%s%c", ns->path, ns->sep);
948 pat = g_strdup (pattern);
951 flags |= CAMEL_STORE_FOLDER_INFO_SUBSCRIPTION_LIST;
953 if (server->cinfo->capa & IMAPX_CAPABILITY_LIST_EXTENDED)
954 list_ext = "RETURN (SUBSCRIBED)";
956 flags |= CAMEL_STORE_FOLDER_INFO_RECURSIVE;
957 if (!fetch_folders_for_pattern (
958 istore, server, pat, flags, list_ext,
959 folders, cancellable, error)) {
964 /* If the server doesn't support LIST-EXTENDED then we have to
965 * issue LSUB to list the subscribed folders separately */
966 flags |= CAMEL_STORE_FOLDER_INFO_SUBSCRIBED;
967 if (!fetch_folders_for_pattern (
968 istore, server, pat, flags, NULL,
969 folders, cancellable, error)) {
982 g_list_free (namespaces);
984 g_object_unref (server);
988 g_object_unref (server);
989 g_hash_table_destroy (folders);
994 sync_folders (CamelIMAPXStore *istore,
995 const gchar *pattern,
997 GCancellable *cancellable,
1000 GHashTable *folders_from_server;
1003 folders_from_server = fetch_folders_for_namespaces (
1004 istore, pattern, sync, cancellable, error);
1005 if (folders_from_server == NULL)
1008 total = camel_store_summary_count ((CamelStoreSummary *) istore->summary);
1009 for (i = 0; i < total; i++) {
1011 const gchar *full_name;
1012 CamelFolderInfo *fi;
1014 si = camel_store_summary_index ((CamelStoreSummary *) istore->summary, i);
1018 full_name = camel_imapx_store_info_full_name (istore->summary, si);
1019 if (!full_name || !*full_name) {
1020 camel_store_summary_info_free ((CamelStoreSummary *) istore->summary, si);
1024 if (!pattern || !*pattern || imapx_match_pattern (camel_imapx_store_summary_namespace_find_full (istore->summary, full_name), pattern, full_name)) {
1025 if ((fi = g_hash_table_lookup (folders_from_server, camel_store_info_path (istore->summary, si))) != NULL) {
1026 if (((fi->flags ^ si->flags) & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED)) {
1027 si->flags = (si->flags & ~CAMEL_FOLDER_SUBSCRIBED) | (fi->flags & CAMEL_FOLDER_SUBSCRIBED);
1028 camel_store_summary_touch ((CamelStoreSummary *) istore->summary);
1030 camel_store_folder_created (CAMEL_STORE (istore), fi);
1031 camel_subscribable_folder_subscribed (CAMEL_SUBSCRIBABLE (istore), fi);
1034 gchar *dup_folder_name = g_strdup (camel_store_info_path (istore->summary, si));
1036 if (dup_folder_name) {
1037 imapx_unmark_folder_subscribed (istore,dup_folder_name, TRUE);
1038 imapx_delete_folder_from_cache (istore, dup_folder_name);
1039 g_free (dup_folder_name);
1041 camel_store_summary_remove ((CamelStoreSummary *) istore->summary, si);
1048 camel_store_summary_info_free ((CamelStoreSummary *) istore->summary, si);
1051 g_hash_table_foreach (folders_from_server, imapx_get_folders_free, NULL);
1052 g_hash_table_destroy (folders_from_server);
1058 imapx_refresh_finfo (CamelSession *session,
1059 GCancellable *cancellable,
1060 CamelIMAPXStore *store,
1063 CamelService *service;
1064 const gchar *display_name;
1066 service = CAMEL_SERVICE (store);
1067 display_name = camel_service_get_display_name (service);
1069 camel_operation_push_message (
1070 cancellable, _("Retrieving folder list for %s"),
1073 if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store)))
1076 if (!camel_service_connect_sync (
1077 CAMEL_SERVICE (store), cancellable, error))
1080 /* look in all namespaces */
1081 sync_folders (store, "", FALSE, cancellable, error);
1083 camel_store_summary_save (CAMEL_STORE_SUMMARY (store->summary));
1086 camel_operation_pop_message (cancellable);
1090 discover_inbox (CamelStore *store,
1091 GCancellable *cancellable)
1094 CamelIMAPXStore *istore = (CamelIMAPXStore *) store;
1096 si = camel_store_summary_path((CamelStoreSummary *) istore->summary, "INBOX");
1097 if (si == NULL || (si->flags & CAMEL_FOLDER_SUBSCRIBED) == 0) {
1098 if (imapx_subscribe_folder (store, "INBOX", FALSE, cancellable, NULL) && !si)
1099 sync_folders (istore, "INBOX", TRUE, cancellable, NULL);
1102 camel_store_summary_info_free ((CamelStoreSummary *) istore->summary, si);
1107 imapx_can_refresh_folder (CamelStore *store,
1108 CamelFolderInfo *info,
1111 CamelService *service;
1112 CamelSettings *settings;
1113 CamelStoreClass *store_class;
1115 gboolean check_subscribed;
1116 gboolean subscribed;
1118 GError *local_error = NULL;
1120 store_class = CAMEL_STORE_CLASS (camel_imapx_store_parent_class);
1122 service = CAMEL_SERVICE (store);
1123 settings = camel_service_get_settings (service);
1125 check_all = camel_imapx_settings_get_check_all (
1126 CAMEL_IMAPX_SETTINGS (settings));
1128 check_subscribed = camel_imapx_settings_get_check_subscribed (
1129 CAMEL_IMAPX_SETTINGS (settings));
1131 subscribed = ((info->flags & CAMEL_FOLDER_SUBSCRIBED) != 0);
1133 res = store_class->can_refresh_folder (store, info, &local_error) ||
1134 check_all || (check_subscribed && subscribed);
1136 if (!res && local_error == NULL && CAMEL_IS_IMAPX_STORE (store)) {
1138 CamelStoreSummary *sm = CAMEL_STORE_SUMMARY (((CamelIMAPXStore *)(store))->summary);
1143 si = camel_store_summary_path (sm, info->full_name);
1145 res = (si->flags & CAMEL_STORE_INFO_FOLDER_CHECK_FOR_NEW) != 0 ? TRUE : FALSE;
1147 camel_store_summary_info_free (sm, si);
1151 if (local_error != NULL)
1152 g_propagate_error (error, local_error);
1157 static CamelFolder *
1158 imapx_store_get_folder_sync (CamelStore *store,
1159 const gchar *folder_name,
1160 CamelStoreGetFolderFlags flags,
1161 GCancellable *cancellable,
1164 CamelFolder *folder;
1166 folder = get_folder_offline (store, folder_name, flags, NULL);
1167 if (folder == NULL) {
1169 error, CAMEL_STORE_ERROR,
1170 CAMEL_STORE_ERROR_NO_FOLDER,
1171 _("No such folder: %s"), folder_name);
1178 static CamelFolderInfo *
1179 imapx_store_get_folder_info_sync (CamelStore *store,
1181 CamelStoreGetFolderInfoFlags flags,
1182 GCancellable *cancellable,
1185 CamelIMAPXStore *istore = (CamelIMAPXStore *) store;
1186 CamelFolderInfo * fi= NULL;
1187 CamelService *service;
1188 CamelSession *session;
1189 CamelSettings *settings;
1190 gboolean initial_setup = FALSE;
1191 gboolean use_subscriptions;
1194 service = CAMEL_SERVICE (store);
1195 session = camel_service_get_session (service);
1196 settings = camel_service_get_settings (service);
1198 use_subscriptions = camel_imapx_settings_get_use_subscriptions (
1199 CAMEL_IMAPX_SETTINGS (settings));
1204 g_mutex_lock (istore->get_finfo_lock);
1206 if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store))) {
1207 fi = get_folder_info_offline (store, top, flags, error);
1209 g_mutex_unlock (istore->get_finfo_lock);
1213 if (camel_store_summary_count ((CamelStoreSummary *) istore->summary) == 0)
1214 initial_setup = TRUE;
1216 if (!initial_setup && flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED) {
1217 time_t now = time (NULL);
1219 if (now - istore->last_refresh_time > FINFO_REFRESH_INTERVAL) {
1220 istore->last_refresh_time = time (NULL);
1222 camel_session_submit_job (
1223 session, (CamelSessionCallback)
1224 imapx_refresh_finfo,
1225 g_object_ref (store),
1226 (GDestroyNotify) g_object_unref);
1229 fi = get_folder_info_offline (store, top, flags, error);
1230 g_mutex_unlock (istore->get_finfo_lock);
1234 if (!camel_service_connect_sync (
1235 CAMEL_SERVICE (store), cancellable, error)) {
1236 g_mutex_unlock (istore->get_finfo_lock);
1240 if (*top && flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIPTION_LIST) {
1241 fi = get_folder_info_offline (store, top, flags, error);
1242 g_mutex_unlock (istore->get_finfo_lock);
1250 name = camel_imapx_store_summary_full_from_path (istore->summary, top);
1252 name = camel_imapx_store_summary_path_to_full (istore->summary, top, istore->dir_sep);
1255 pattern = g_alloca (i + 5);
1256 strcpy (pattern, name);
1259 pattern = g_alloca (1);
1263 if (!sync_folders (istore, pattern, TRUE, cancellable, error)) {
1264 g_mutex_unlock (istore->get_finfo_lock);
1268 camel_store_summary_save ((CamelStoreSummary *) istore->summary);
1270 /* ensure the INBOX is subscribed if lsub was preferred*/
1271 if (initial_setup && use_subscriptions)
1272 discover_inbox (store, cancellable);
1274 fi = get_folder_info_offline (store, top, flags, error);
1275 g_mutex_unlock (istore->get_finfo_lock);
1279 static CamelFolder *
1280 imapx_store_get_junk_folder_sync (CamelStore *store,
1281 GCancellable *cancellable,
1284 CamelFolder *folder;
1285 CamelStoreClass *store_class;
1287 store_class = CAMEL_STORE_CLASS (camel_imapx_store_parent_class);
1288 folder = store_class->get_junk_folder_sync (store, cancellable, error);
1291 CamelObject *object = CAMEL_OBJECT (folder);
1292 CamelService *service;
1293 const gchar *user_cache_dir;
1296 service = CAMEL_SERVICE (store);
1297 user_cache_dir = camel_service_get_user_cache_dir (service);
1299 state = g_build_filename (
1300 user_cache_dir, "system", "Junk.cmeta", NULL);
1302 camel_object_set_state_filename (object, state);
1305 camel_object_state_read (object);
1311 static CamelFolder *
1312 imapx_store_get_trash_folder_sync (CamelStore *store,
1313 GCancellable *cancellable,
1316 CamelFolder *folder;
1317 CamelStoreClass *store_class;
1319 store_class = CAMEL_STORE_CLASS (camel_imapx_store_parent_class);
1320 folder = store_class->get_trash_folder_sync (store, cancellable, error);
1323 CamelObject *object = CAMEL_OBJECT (folder);
1324 CamelService *service;
1325 const gchar *user_cache_dir;
1328 service = CAMEL_SERVICE (store);
1329 user_cache_dir = camel_service_get_user_cache_dir (service);
1331 state = g_build_filename (
1332 user_cache_dir, "system", "Trash.cmeta", NULL);
1334 camel_object_set_state_filename (object, state);
1337 camel_object_state_read (object);
1343 static CamelFolderInfo *
1344 imapx_store_create_folder_sync (CamelStore *store,
1345 const gchar *parent_name,
1346 const gchar *folder_name,
1347 GCancellable *cancellable,
1351 CamelIMAPXStoreNamespace *ns;
1352 CamelIMAPXStore *istore = (CamelIMAPXStore *) store;
1353 CamelIMAPXServer *server;
1354 gchar *real_name, *full_name, *parent_real;
1355 CamelFolderInfo *fi = NULL;
1359 if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store))) {
1361 error, CAMEL_SERVICE_ERROR,
1362 CAMEL_SERVICE_ERROR_UNAVAILABLE,
1363 _("You must be working online to complete this operation"));
1367 server = camel_imapx_store_get_server (istore, NULL, cancellable, error);
1374 ns = camel_imapx_store_summary_namespace_find_path (istore->summary, parent_name);
1380 if (strchr (folder_name, dir_sep)) {
1382 error, CAMEL_FOLDER_ERROR,
1383 CAMEL_FOLDER_ERROR_INVALID_PATH,
1384 _("The folder name \"%s\" is invalid because it contains the character \"%c\""),
1385 folder_name, dir_sep);
1386 g_object_unref (server);
1390 parent_real = camel_imapx_store_summary_full_from_path (istore->summary, parent_name);
1391 if (parent_real == NULL) {
1393 error, CAMEL_FOLDER_ERROR,
1394 CAMEL_FOLDER_ERROR_INVALID_STATE,
1395 _("Unknown parent folder: %s"), parent_name);
1396 g_object_unref (server);
1400 si = camel_store_summary_path ((CamelStoreSummary *) istore->summary, parent_name);
1401 if (si && si->flags & CAMEL_STORE_INFO_FOLDER_NOINFERIORS) {
1403 error, CAMEL_FOLDER_ERROR,
1404 CAMEL_FOLDER_ERROR_INVALID_STATE,
1405 _("The parent folder is not allowed to contain subfolders"));
1406 g_object_unref (server);
1411 camel_store_summary_info_free ((CamelStoreSummary *) istore->summary, si);
1413 real_name = camel_imapx_store_summary_path_to_full (istore->summary, folder_name, dir_sep);
1414 full_name = imapx_concat (istore, parent_real, real_name);
1417 success = camel_imapx_server_create_folder (
1418 server, full_name, cancellable, error);
1419 g_object_unref (server);
1422 CamelIMAPXStoreInfo *si;
1424 si = camel_imapx_store_summary_add_from_full (istore->summary, full_name, dir_sep);
1425 camel_store_summary_save ((CamelStoreSummary *) istore->summary);
1426 fi = imapx_build_folder_info (istore, camel_store_info_path (istore->summary, si));
1427 fi->flags |= CAMEL_FOLDER_NOCHILDREN;
1428 camel_store_folder_created (store, fi);
1432 g_free (parent_real);
1438 imapx_store_delete_folder_sync (CamelStore *store,
1439 const gchar *folder_name,
1440 GCancellable *cancellable,
1443 CamelIMAPXStore *istore = (CamelIMAPXStore *) store;
1444 CamelIMAPXServer *server;
1447 if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store))) {
1449 error, CAMEL_SERVICE_ERROR,
1450 CAMEL_SERVICE_ERROR_UNAVAILABLE,
1451 _("You must be working online to complete this operation"));
1454 /* Use INBOX connection as the implementation would try to select inbox to ensure
1455 * we are not selected on the folder being deleted */
1456 server = camel_imapx_store_get_server (istore, "INBOX", cancellable, error);
1460 success = camel_imapx_server_delete_folder (
1461 server, folder_name, cancellable, error);
1462 g_object_unref (server);
1465 imapx_delete_folder_from_cache (istore, folder_name);
1471 imapx_store_rename_folder_sync (CamelStore *store,
1474 GCancellable *cancellable,
1477 CamelIMAPXStore *istore = (CamelIMAPXStore *) store;
1478 CamelIMAPXServer *server;
1479 CamelService *service;
1480 CamelSettings *settings;
1481 const gchar *user_cache_dir;
1482 gchar *oldpath, *newpath, *storage_path;
1483 gboolean use_subscriptions;
1484 gboolean success = FALSE;
1486 service = CAMEL_SERVICE (store);
1487 settings = camel_service_get_settings (service);
1488 user_cache_dir = camel_service_get_user_cache_dir (service);
1490 use_subscriptions = camel_imapx_settings_get_use_subscriptions (
1491 CAMEL_IMAPX_SETTINGS (settings));
1493 if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store))) {
1495 error, CAMEL_SERVICE_ERROR,
1496 CAMEL_SERVICE_ERROR_UNAVAILABLE,
1497 _("You must be working online to complete this operation"));
1501 if (use_subscriptions)
1502 imapx_unsubscribe_folder (store, old, FALSE, cancellable, NULL);
1504 /* Use INBOX connection as the implementation would try to select inbox to ensure
1505 * we are not selected on the folder being renamed */
1506 server = camel_imapx_store_get_server(istore, "INBOX", cancellable, error);
1508 success = camel_imapx_server_rename_folder (
1509 server, old, new, cancellable, error);
1510 g_object_unref (server);
1514 imapx_subscribe_folder (store, old, FALSE, cancellable, NULL);
1518 /* rename summary, and handle broken server */
1519 rename_folder_info (istore, old, new);
1521 if (use_subscriptions)
1522 success = imapx_subscribe_folder (
1523 store, new, FALSE, cancellable, error);
1525 storage_path = g_build_filename (user_cache_dir, "folders", NULL);
1526 oldpath = imapx_path_to_physical (storage_path, old);
1527 newpath = imapx_path_to_physical (storage_path, new);
1528 g_free (storage_path);
1530 /* So do we care if this didn't work? Its just a cache? */
1531 if (g_rename (oldpath, newpath) == -1) {
1532 g_warning ("Could not rename message cache '%s' to '%s': %s: cache reset",
1533 oldpath, newpath, g_strerror (errno));
1543 imapx_store_noop_sync (CamelStore *store,
1544 GCancellable *cancellable,
1547 CamelIMAPXStore *istore = (CamelIMAPXStore *) store;
1549 gboolean success = TRUE;
1551 if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store)))
1554 list = camel_imapx_conn_manager_get_connections (istore->con_man);
1556 for (link = list; link != NULL; link = g_list_next (link)) {
1557 CamelIMAPXServer *server = CAMEL_IMAPX_SERVER (link->data);
1559 /* we just return last noops value, technically not correct though */
1560 success = camel_imapx_server_noop (server, NULL, cancellable, error);
1565 g_list_free_full (list, (GDestroyNotify) g_object_unref);
1571 imapx_migrate_to_user_cache_dir (CamelService *service)
1573 const gchar *user_data_dir, *user_cache_dir;
1575 g_return_if_fail (service != NULL);
1576 g_return_if_fail (CAMEL_IS_SERVICE (service));
1578 user_data_dir = camel_service_get_user_data_dir (service);
1579 user_cache_dir = camel_service_get_user_cache_dir (service);
1581 g_return_if_fail (user_data_dir != NULL);
1582 g_return_if_fail (user_cache_dir != NULL);
1584 /* migrate only if the source directory exists and the destination doesn't */
1585 if (g_file_test (user_data_dir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR) &&
1586 !g_file_test (user_cache_dir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) {
1589 parent_dir = g_path_get_dirname (user_cache_dir);
1590 g_mkdir_with_parents (parent_dir, S_IRWXU);
1591 g_free (parent_dir);
1593 if (g_rename (user_data_dir, user_cache_dir) == -1)
1594 g_debug ("%s: Failed to migrate '%s' to '%s': %s", G_STRFUNC, user_data_dir, user_cache_dir, g_strerror (errno));
1599 imapx_store_initable_init (GInitable *initable,
1600 GCancellable *cancellable,
1603 CamelIMAPXStore *imapx_store;
1605 CamelService *service;
1606 const gchar *user_cache_dir;
1609 imapx_store = CAMEL_IMAPX_STORE (initable);
1610 store = CAMEL_STORE (initable);
1611 service = CAMEL_SERVICE (initable);
1613 store->flags |= CAMEL_STORE_USE_CACHE_DIR;
1614 imapx_migrate_to_user_cache_dir (service);
1616 /* Chain up to parent interface's init() method. */
1617 if (!parent_initable_interface->init (initable, cancellable, error))
1620 service = CAMEL_SERVICE (initable);
1621 user_cache_dir = camel_service_get_user_cache_dir (service);
1623 imapx_store->summary = camel_imapx_store_summary_new ();
1625 summary = g_build_filename (user_cache_dir, ".ev-store-summary", NULL);
1626 camel_store_summary_set_filename ((CamelStoreSummary *) imapx_store->summary, summary);
1627 camel_store_summary_load ((CamelStoreSummary *) imapx_store->summary);
1634 static const gchar *
1635 imapx_store_get_service_name (CamelNetworkService *service,
1636 CamelNetworkSecurityMethod method)
1638 const gchar *service_name;
1641 case CAMEL_NETWORK_SECURITY_METHOD_SSL_ON_ALTERNATE_PORT:
1642 service_name = "imaps";
1646 service_name = "imap";
1650 return service_name;
1654 imapx_store_get_default_port (CamelNetworkService *service,
1655 CamelNetworkSecurityMethod method)
1657 guint16 default_port;
1660 case CAMEL_NETWORK_SECURITY_METHOD_SSL_ON_ALTERNATE_PORT:
1661 default_port = IMAPS_PORT;
1665 default_port = IMAP_PORT;
1669 return default_port;
1673 imapx_store_folder_is_subscribed (CamelSubscribable *subscribable,
1674 const gchar *folder_name)
1676 CamelIMAPXStore *istore = CAMEL_IMAPX_STORE (subscribable);
1678 gint is_subscribed = FALSE;
1680 si = camel_store_summary_path ((CamelStoreSummary *) istore->summary, folder_name);
1682 is_subscribed = (si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED) != 0;
1683 camel_store_summary_info_free ((CamelStoreSummary *) istore->summary, si);
1686 return is_subscribed;
1690 imapx_store_subscribe_folder_sync (CamelSubscribable *subscribable,
1691 const gchar *folder_name,
1692 GCancellable *cancellable,
1695 return imapx_subscribe_folder (
1696 CAMEL_STORE (subscribable),
1697 folder_name, TRUE, cancellable, error);
1701 imapx_store_unsubscribe_folder_sync (CamelSubscribable *subscribable,
1702 const gchar *folder_name,
1703 GCancellable *cancellable,
1706 return imapx_unsubscribe_folder (
1707 CAMEL_STORE (subscribable),
1708 folder_name, TRUE, cancellable, error);
1712 camel_imapx_store_class_init (CamelIMAPXStoreClass *class)
1714 GObjectClass *object_class;
1715 CamelServiceClass *service_class;
1716 CamelStoreClass *store_class;
1718 object_class = G_OBJECT_CLASS (class);
1719 object_class->dispose = imapx_store_dispose;
1720 object_class->finalize = imapx_store_finalize;
1722 service_class = CAMEL_SERVICE_CLASS (class);
1723 service_class->settings_type = CAMEL_TYPE_IMAPX_SETTINGS;
1724 service_class->get_name = imapx_get_name;
1725 service_class->connect_sync = imapx_connect_sync;
1726 service_class->disconnect_sync = imapx_disconnect_sync;
1727 service_class->authenticate_sync = imapx_authenticate_sync;
1728 service_class->query_auth_types_sync = imapx_query_auth_types_sync;
1730 store_class = CAMEL_STORE_CLASS (class);
1731 store_class->hash_folder_name = imapx_name_hash;
1732 store_class->compare_folder_name = imapx_name_equal;
1733 store_class->can_refresh_folder = imapx_can_refresh_folder;
1734 store_class->free_folder_info = camel_store_free_folder_info_full;
1735 store_class->get_folder_sync = imapx_store_get_folder_sync;
1736 store_class->get_folder_info_sync = imapx_store_get_folder_info_sync;
1737 store_class->get_junk_folder_sync = imapx_store_get_junk_folder_sync;
1738 store_class->get_trash_folder_sync = imapx_store_get_trash_folder_sync;
1739 store_class->create_folder_sync = imapx_store_create_folder_sync;
1740 store_class->delete_folder_sync = imapx_store_delete_folder_sync;
1741 store_class->rename_folder_sync = imapx_store_rename_folder_sync;
1742 store_class->noop_sync = imapx_store_noop_sync;
1746 camel_imapx_store_initable_init (GInitableIface *interface)
1748 parent_initable_interface = g_type_interface_peek_parent (interface);
1750 interface->init = imapx_store_initable_init;
1754 camel_network_service_init (CamelNetworkServiceInterface *interface)
1756 interface->get_service_name = imapx_store_get_service_name;
1757 interface->get_default_port = imapx_store_get_default_port;
1761 camel_subscribable_init (CamelSubscribableInterface *interface)
1763 interface->folder_is_subscribed = imapx_store_folder_is_subscribed;
1764 interface->subscribe_folder_sync = imapx_store_subscribe_folder_sync;
1765 interface->unsubscribe_folder_sync = imapx_store_unsubscribe_folder_sync;
1769 camel_imapx_store_init (CamelIMAPXStore *istore)
1771 istore->get_finfo_lock = g_mutex_new ();
1772 istore->last_refresh_time = time (NULL) - (FINFO_REFRESH_INTERVAL + 10);
1773 istore->dir_sep = '/';
1774 istore->con_man = camel_imapx_conn_manager_new (CAMEL_STORE (istore));
1776 imapx_utils_init ();