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_clear (&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_ref_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);
153 g_object_unref (settings);
156 name = g_strdup_printf (
157 _("IMAP server %s"), host);
159 name = g_strdup_printf (
160 _("IMAP service for %s on %s"), user, host);
169 camel_imapx_store_get_server (CamelIMAPXStore *istore,
170 const gchar *folder_name,
171 GCancellable *cancellable,
174 return camel_imapx_conn_manager_get_connection (
175 istore->con_man, folder_name, cancellable, error);
179 camel_imapx_store_op_done (CamelIMAPXStore *istore,
180 CamelIMAPXServer *server,
181 const gchar *folder_name)
183 g_return_if_fail (server != NULL);
185 camel_imapx_conn_manager_update_con_info (
186 istore->con_man, server, folder_name);
190 imapx_connect_sync (CamelService *service,
191 GCancellable *cancellable,
194 CamelIMAPXStore *istore = (CamelIMAPXStore *) service;
195 CamelIMAPXServer *server;
197 server = camel_imapx_store_get_server (istore, NULL, cancellable, error);
199 g_object_unref (server);
207 imapx_disconnect_sync (CamelService *service,
209 GCancellable *cancellable,
212 CamelIMAPXStore *istore = CAMEL_IMAPX_STORE (service);
213 CamelServiceClass *service_class;
215 service_class = CAMEL_SERVICE_CLASS (camel_imapx_store_parent_class);
216 if (!service_class->disconnect_sync (service, clean, cancellable, error))
219 if (istore->con_man != NULL)
220 camel_imapx_conn_manager_close_connections (istore->con_man);
225 static CamelAuthenticationResult
226 imapx_authenticate_sync (CamelService *service,
227 const gchar *mechanism,
228 GCancellable *cancellable,
231 CamelIMAPXStore *istore = CAMEL_IMAPX_STORE (service);
232 CamelIMAPXServer *server;
234 /* CamelIMAPXConnManager sets this before calling
235 * camel_imapx_server_connect()(), and then clears it
236 * immediately after, all while holding the recursive
237 * connection lock (CAMEL_SERVICE_REC_CONNECT_LOCK).
238 * Otherwise we'd have no way of knowing which server
239 * is trying to authenticate. */
240 server = istore->authenticating_server;
242 g_return_val_if_fail (
243 CAMEL_IS_IMAPX_SERVER (server),
244 CAMEL_AUTHENTICATION_REJECTED);
246 return camel_imapx_server_authenticate (
247 server, mechanism, cancellable, error);
250 CamelServiceAuthType camel_imapx_password_authtype = {
253 N_("This option will connect to the IMAP server using a "
254 "plaintext password."),
261 imapx_query_auth_types_sync (CamelService *service,
262 GCancellable *cancellable,
265 CamelIMAPXStore *istore = CAMEL_IMAPX_STORE (service);
266 CamelServiceAuthType *authtype;
267 GList *sasl_types, *t, *next;
268 CamelIMAPXServer *server;
269 CamelIMAPXStream *stream;
272 if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (istore))) {
274 error, CAMEL_SERVICE_ERROR,
275 CAMEL_SERVICE_ERROR_UNAVAILABLE,
276 _("You must be working online to complete this operation"));
280 server = camel_imapx_server_new (istore);
282 stream = camel_imapx_server_ref_stream (server);
283 if (stream != NULL) {
285 g_object_unref (stream);
287 connected = imapx_connect_to_server (
288 server, cancellable, error);
294 sasl_types = camel_sasl_authtype_list (FALSE);
295 for (t = sasl_types; t; t = next) {
299 if (!server->cinfo || !g_hash_table_lookup (server->cinfo->auth_types, authtype->authproto)) {
300 sasl_types = g_list_remove_link (sasl_types, t);
305 g_object_unref (server);
307 return g_list_prepend (sasl_types, &camel_imapx_password_authtype);
311 get_folder_offline (CamelStore *store,
312 const gchar *folder_name,
316 CamelIMAPXStore *imapx_store = CAMEL_IMAPX_STORE (store);
317 CamelFolder *new_folder = NULL;
319 CamelService *service;
320 const gchar *user_cache_dir;
322 service = CAMEL_SERVICE (store);
323 user_cache_dir = camel_service_get_user_cache_dir (service);
325 si = camel_store_summary_path ((CamelStoreSummary *) imapx_store->summary, folder_name);
326 if (!si && g_ascii_strcasecmp (folder_name, "INBOX") == 0)
327 si = (CamelStoreInfo *) camel_imapx_store_summary_full_name (imapx_store->summary, folder_name);
329 gchar *folder_dir, *storage_path;
331 storage_path = g_build_filename (user_cache_dir, "folders", NULL);
332 /* Note: Although the INBOX is defined to be case-insensitive in the IMAP RFC
333 * it is still up to the server how to acutally name it in a LIST response. Since
334 * we stored the name as the server provided it us in the summary we take that name
335 * to look up the folder.
336 * But for the on-disk cache we do always capitalize the Inbox no matter what the
339 folder_dir = imapx_path_to_physical (
341 g_ascii_strcasecmp (folder_name, "INBOX") == 0 ? "INBOX" : folder_name);
342 g_free (storage_path);
344 new_folder = camel_imapx_folder_new (store, folder_dir, folder_name, error);
347 camel_store_summary_info_free ((CamelStoreSummary *) imapx_store->summary, si);
350 error, CAMEL_STORE_ERROR,
351 CAMEL_STORE_ERROR_NO_FOLDER,
352 _("No such folder %s"), folder_name);
358 /* folder_name is path name */
359 static CamelFolderInfo *
360 imapx_build_folder_info (CamelIMAPXStore *imapx_store,
361 const gchar *folder_name)
366 fi = camel_folder_info_new ();
367 fi->full_name = g_strdup (folder_name);
371 name = strrchr (fi->full_name, '/');
373 name = fi->full_name;
376 if (!g_ascii_strcasecmp (fi->full_name, "INBOX"))
377 fi->display_name = g_strdup (_("Inbox"));
378 /* Do not localize the rest, these are from a server, thus shouldn't be localized */
379 /*else if (!g_ascii_strcasecmp (fi->full_name, "Drafts"))
380 fi->display_name = g_strdup (_("Drafts"));
381 else if (!g_ascii_strcasecmp (fi->full_name, "Sent"))
382 fi->display_name = g_strdup (_("Sent"));
383 else if (!g_ascii_strcasecmp (fi->full_name, "Templates"))
384 fi->display_name = g_strdup (_("Templates"));
385 else if (!g_ascii_strcasecmp (fi->full_name, "Trash"))
386 fi->display_name = g_strdup (_("Trash"));*/
388 fi->display_name = g_strdup (name);
394 fill_fi (CamelStore *store,
399 CamelService *service = (CamelService *) store;
400 CamelSettings *settings;
401 gboolean mobile_mode;
403 settings = camel_service_ref_settings (service);
405 mobile_mode = camel_imapx_settings_get_mobile_mode (
406 CAMEL_IMAPX_SETTINGS (settings));
408 g_object_unref (settings);
410 folder = camel_object_bag_peek (store->folders, fi->full_name);
412 CamelIMAPXSummary *ims;
415 ims = (CamelIMAPXSummary *) folder->summary;
417 ims = (CamelIMAPXSummary *) camel_imapx_summary_new (folder);
419 /* Mobile clients would still love to see the total unread of actual mails
420 * than what they just have downloaded. So we override that information by giving
421 * what the server has instead of what we have downloaded. */
423 fi->unread = ((CamelIMAPXFolder *) folder)->unread_on_server;
425 fi->unread = camel_folder_summary_get_unread_count ((CamelFolderSummary *) ims);
426 fi->total = camel_folder_summary_get_saved_count ((CamelFolderSummary *) ims);
428 if (!folder->summary)
429 g_object_unref (ims);
430 g_object_unref (folder);
434 /* imap needs to treat inbox case insensitive */
435 /* we'll assume the names are normalized already */
437 folder_hash (gconstpointer ap)
441 if (g_ascii_strcasecmp (a, "INBOX") == 0)
444 return g_str_hash (a);
448 folder_eq (gconstpointer ap,
454 if (g_ascii_strcasecmp (a, "INBOX") == 0)
456 if (g_ascii_strcasecmp (b, "INBOX") == 0)
459 return g_str_equal (a, b);
463 imapx_match_pattern (CamelIMAPXStoreNamespace *ns,
464 const gchar *pattern,
481 } else if (p == '%') {
487 } else if (p == '*') {
493 return n == 0 && (p == '%' || p == 0);
497 imapx_unmark_folder_subscribed (CamelIMAPXStore *istore,
498 const gchar *folder_name,
499 gboolean emit_signal)
503 si = camel_store_summary_path ((CamelStoreSummary *) istore->summary, folder_name);
505 if (si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED) {
506 si->flags &= ~CAMEL_STORE_INFO_FOLDER_SUBSCRIBED;
507 camel_store_summary_touch ((CamelStoreSummary *) istore->summary);
508 camel_store_summary_save ((CamelStoreSummary *) istore->summary);
510 camel_store_summary_info_free ((CamelStoreSummary *) istore->summary, si);
516 fi = imapx_build_folder_info (istore, folder_name);
517 camel_subscribable_folder_unsubscribed (
518 CAMEL_SUBSCRIBABLE (istore), fi);
519 camel_folder_info_free (fi);
524 imapx_mark_folder_subscribed (CamelIMAPXStore *istore,
525 const gchar *folder_name,
526 gboolean emit_signal)
530 si = camel_store_summary_path ((CamelStoreSummary *) istore->summary, folder_name);
532 if ((si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED) == 0) {
533 si->flags |= CAMEL_STORE_INFO_FOLDER_SUBSCRIBED;
534 camel_store_summary_touch ((CamelStoreSummary *) istore->summary);
535 camel_store_summary_save ((CamelStoreSummary *) istore->summary);
537 camel_store_summary_info_free ((CamelStoreSummary *) istore->summary, si);
543 fi = imapx_build_folder_info (istore, folder_name);
544 camel_subscribable_folder_subscribed (
545 CAMEL_SUBSCRIBABLE (istore), fi);
546 camel_folder_info_free (fi);
551 imapx_subscribe_folder (CamelStore *store,
552 const gchar *folder_name,
553 gboolean emit_signal,
554 GCancellable *cancellable,
557 CamelIMAPXStore *istore = (CamelIMAPXStore *) store;
558 CamelIMAPXServer *server;
561 if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store)))
564 server = camel_imapx_store_get_server (istore, NULL, cancellable, error);
568 if (folder_name && *folder_name == '/')
571 success = camel_imapx_server_manage_subscription (
572 server, folder_name, TRUE, cancellable, error);
573 g_object_unref (server);
576 imapx_mark_folder_subscribed (istore, folder_name, emit_signal);
582 imapx_unsubscribe_folder (CamelStore *store,
583 const gchar *folder_name,
584 gboolean emit_signal,
585 GCancellable *cancellable,
588 CamelIMAPXStore *istore = (CamelIMAPXStore *) store;
589 CamelIMAPXServer *server;
592 if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store)))
595 server = camel_imapx_store_get_server (istore, NULL, cancellable, error);
599 if (folder_name && *folder_name == '/')
602 success = camel_imapx_server_manage_subscription (
603 server, folder_name, FALSE, cancellable, error);
604 g_object_unref (server);
607 imapx_unmark_folder_subscribed (istore, folder_name, emit_signal);
613 imapx_delete_folder_from_cache (CamelIMAPXStore *istore,
614 const gchar *folder_name)
617 gchar *folder_dir, *storage_path;
619 CamelService *service;
620 const gchar *user_cache_dir;
622 service = CAMEL_SERVICE (istore);
623 user_cache_dir = camel_service_get_user_cache_dir (service);
625 storage_path = g_build_filename (user_cache_dir, "folders", NULL);
626 folder_dir = imapx_path_to_physical (storage_path, folder_name);
627 g_free (storage_path);
628 if (g_access (folder_dir, F_OK) != 0) {
633 /* Delete summary and all the data */
634 state_file = g_build_filename (folder_dir, "cmeta", NULL);
635 g_unlink (state_file);
638 camel_db_delete_folder (((CamelStore *) istore)->cdb_w, folder_name, NULL);
639 g_rmdir (folder_dir);
641 state_file = g_build_filename (folder_dir, "subfolders", NULL);
642 g_rmdir (state_file);
645 g_rmdir (folder_dir);
649 camel_store_summary_remove_path ((CamelStoreSummary *) istore->summary, folder_name);
650 camel_store_summary_save ((CamelStoreSummary *) istore->summary);
652 fi = imapx_build_folder_info (istore, folder_name);
653 camel_store_folder_deleted (CAMEL_STORE (istore), fi);
654 camel_folder_info_free (fi);
658 rename_folder_info (CamelIMAPXStore *istore,
659 const gchar *old_name,
660 const gchar *new_name)
664 gint olen = strlen (old_name);
666 gchar *npath, *nfull;
668 count = camel_store_summary_count ((CamelStoreSummary *) istore->summary);
669 for (i = 0; i < count; i++) {
670 si = camel_store_summary_index ((CamelStoreSummary *) istore->summary, i);
673 path = camel_store_info_path (istore->summary, si);
674 if (strncmp (path, old_name, olen) == 0) {
675 if (strlen (path) > olen)
676 npath = g_strdup_printf ("%s/%s", new_name, path + olen + 1);
678 npath = g_strdup (new_name);
679 nfull = camel_imapx_store_summary_path_to_full (istore->summary, npath, istore->dir_sep);
681 camel_store_info_set_string ((CamelStoreSummary *) istore->summary, si, CAMEL_STORE_INFO_PATH, npath);
682 camel_store_info_set_string ((CamelStoreSummary *) istore->summary, si, CAMEL_IMAPX_STORE_INFO_FULL_NAME, nfull);
684 camel_store_summary_touch ((CamelStoreSummary *) istore->summary);
688 camel_store_summary_info_free ((CamelStoreSummary *) istore->summary, si);
692 static CamelFolderInfo *
693 get_folder_info_offline (CamelStore *store,
698 CamelIMAPXStore *imapx_store = CAMEL_IMAPX_STORE (store);
699 CamelService *service;
700 CamelSettings *settings;
701 gboolean include_inbox = FALSE;
704 gchar *pattern, *name;
705 gboolean use_namespace;
706 gboolean use_subscriptions;
709 service = CAMEL_SERVICE (store);
711 settings = camel_service_ref_settings (service);
713 use_namespace = camel_imapx_settings_get_use_namespace (
714 CAMEL_IMAPX_SETTINGS (settings));
716 use_subscriptions = camel_imapx_settings_get_use_subscriptions (
717 CAMEL_IMAPX_SETTINGS (settings));
719 g_object_unref (settings);
721 /* FIXME: obey other flags */
723 folders = g_ptr_array_new ();
725 if (top == NULL || top[0] == '\0') {
726 include_inbox = TRUE;
730 /* get starting point */
732 gchar *namespace = NULL;
735 settings = camel_service_ref_settings (service);
737 namespace = camel_imapx_settings_dup_namespace (
738 CAMEL_IMAPX_SETTINGS (settings));
740 g_object_unref (settings);
743 if (namespace != NULL) {
744 name = g_strdup (imapx_store->summary->namespaces->personal->full_name);
745 top = imapx_store->summary->namespaces->personal->path;
747 name = g_strdup ("");
751 name = camel_imapx_store_summary_full_from_path (imapx_store->summary, top);
753 name = camel_imapx_store_summary_path_to_full (imapx_store->summary, top, imapx_store->dir_sep);
756 pattern = imapx_concat (imapx_store, name, "*");
758 /* folder_info_build will insert parent nodes as necessary and mark
759 * them as noselect, which is information we actually don't have at
760 * the moment. So let it do the right thing by bailing out if it's
761 * not a folder we're explicitly interested in. */
763 for (i = 0; i < camel_store_summary_count ((CamelStoreSummary *) imapx_store->summary); i++) {
764 CamelStoreInfo *si = camel_store_summary_index ((CamelStoreSummary *) imapx_store->summary, i);
765 const gchar *full_name;
766 CamelIMAPXStoreNamespace *ns;
771 full_name = camel_imapx_store_info_full_name (imapx_store->summary, si);
772 if (!full_name || !*full_name) {
773 camel_store_summary_info_free ((CamelStoreSummary *) imapx_store->summary, si);
777 ns = camel_imapx_store_summary_namespace_find_full (imapx_store->summary, full_name);
779 /* Modify the checks to see match the namespaces from preferences */
780 if ((g_str_equal (name, full_name)
781 || imapx_match_pattern (ns, pattern, full_name)
782 || (include_inbox && !g_ascii_strcasecmp (full_name, "INBOX")))
783 && ( (!use_subscriptions
784 || (flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED) == 0)
785 || (si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED)
786 || (flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIPTION_LIST) != 0)) {
788 fi = imapx_build_folder_info (imapx_store, camel_store_info_path ((CamelStoreSummary *) imapx_store->summary, si));
789 fi->unread = si->unread;
790 fi->total = si->total;
791 fi->flags = si->flags;
792 /* HACK: some servers report noinferiors for all folders (uw-imapd)
793 * We just translate this into nochildren, and let the imap layer enforce
794 * it. See create folder */
795 if (fi->flags & CAMEL_FOLDER_NOINFERIORS)
796 fi->flags = (fi->flags & ~CAMEL_FOLDER_NOINFERIORS) | CAMEL_FOLDER_NOCHILDREN;
798 /* blah, this gets lost somewhere, i can't be bothered finding out why */
799 if (!g_ascii_strcasecmp (fi->full_name, "inbox")) {
800 fi->flags = (fi->flags & ~CAMEL_FOLDER_TYPE_MASK) | CAMEL_FOLDER_TYPE_INBOX;
801 fi->flags |= CAMEL_FOLDER_SYSTEM;
804 if (!(si->flags & CAMEL_FOLDER_NOSELECT))
805 fill_fi ((CamelStore *) imapx_store, fi, 0);
808 fi->flags |= CAMEL_FOLDER_NOCHILDREN;
809 g_ptr_array_add (folders, fi);
811 camel_store_summary_info_free ((CamelStoreSummary *) imapx_store->summary, si);
815 fi = camel_folder_info_build (folders, top, '/', TRUE);
816 g_ptr_array_free (folders, TRUE);
823 add_folders_to_summary (CamelIMAPXStore *istore,
824 CamelIMAPXServer *server,
831 for (i = 0; i < folders->len; i++) {
832 struct _list_info *li = folders->pdata[i];
833 CamelIMAPXStoreInfo *si;
835 CamelFolderInfo *fi, *sfi;
839 path = camel_imapx_store_summary_path_to_full (istore->summary, li->name, li->separator);
840 sfi = g_hash_table_lookup (table, path);
842 sfi->flags |= CAMEL_STORE_INFO_FOLDER_SUBSCRIBED;
848 si = camel_imapx_store_summary_add_from_full (istore->summary, li->name, li->separator);
852 new_flags = (si->info.flags & (CAMEL_STORE_INFO_FOLDER_SUBSCRIBED | CAMEL_STORE_INFO_FOLDER_CHECK_FOR_NEW)) |
853 (li->flags & ~CAMEL_STORE_INFO_FOLDER_SUBSCRIBED);
855 if (server->cinfo && !(server->cinfo->capa & IMAPX_CAPABILITY_NAMESPACE))
856 istore->dir_sep = li->separator;
858 if (si->info.flags != new_flags) {
859 si->info.flags = new_flags;
860 camel_store_summary_touch ((CamelStoreSummary *) istore->summary);
863 fi = camel_folder_info_new ();
864 fi->full_name = g_strdup (camel_store_info_path (istore->summary, si));
865 if (!g_ascii_strcasecmp (fi->full_name, "inbox")) {
866 li->flags |= CAMEL_FOLDER_SYSTEM | CAMEL_FOLDER_TYPE_INBOX;
867 fi->display_name = g_strdup (_("Inbox"));
869 fi->display_name = g_strdup (camel_store_info_name (istore->summary, si));
871 /* HACK: some servers report noinferiors for all folders (uw-imapd)
872 * We just translate this into nochildren, and let the imap layer enforce
873 * it. See create folder */
874 if (li->flags & CAMEL_FOLDER_NOINFERIORS)
875 li->flags = (li->flags & ~CAMEL_FOLDER_NOINFERIORS) | CAMEL_FOLDER_NOCHILDREN;
876 fi->flags = li->flags;
881 g_hash_table_insert (table, fi->full_name, fi);
886 free_list (gpointer data,
889 struct _list_info *li = data;
890 imapx_free_list (li);
894 imapx_get_folders_free (gpointer k,
898 camel_folder_info_free (v);
902 fetch_folders_for_pattern (CamelIMAPXStore *istore,
903 CamelIMAPXServer *server,
904 const gchar *pattern,
908 GCancellable *cancellable,
913 folders = camel_imapx_server_list (
914 server, pattern, flags, ext, cancellable, error);
918 add_folders_to_summary (istore, server, folders, table, (flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED));
920 g_ptr_array_foreach (folders, free_list, folders);
921 g_ptr_array_free (folders, TRUE);
927 get_namespaces (CamelIMAPXStore *istore)
929 GList *namespaces = NULL;
930 CamelIMAPXNamespaceList *nsl = NULL;
932 /* Add code to return the namespaces from preference else all of them */
933 nsl = istore->summary->namespaces;
935 namespaces = g_list_append (namespaces, nsl->personal);
937 namespaces = g_list_append (namespaces, nsl->other);
939 namespaces = g_list_append (namespaces, nsl->shared);
945 fetch_folders_for_namespaces (CamelIMAPXStore *istore,
946 const gchar *pattern,
948 GCancellable *cancellable,
951 CamelIMAPXServer *server;
952 GHashTable *folders = NULL;
953 GList *namespaces = NULL, *l;
955 server = camel_imapx_store_get_server (istore, NULL, cancellable, error);
959 folders = g_hash_table_new (folder_hash, folder_eq);
960 namespaces = get_namespaces (istore);
962 for (l = namespaces; l != NULL; l = g_list_next (l))
964 CamelIMAPXStoreNamespace *ns = l->data;
969 const gchar *list_ext = NULL;
975 pat = g_strdup_printf ("%s%c", ns->path, ns->sep);
977 pat = g_strdup (pattern);
980 flags |= CAMEL_STORE_FOLDER_INFO_SUBSCRIPTION_LIST;
982 if (server->cinfo && (server->cinfo->capa & IMAPX_CAPABILITY_LIST_EXTENDED) != 0)
983 list_ext = "RETURN (SUBSCRIBED)";
985 flags |= CAMEL_STORE_FOLDER_INFO_RECURSIVE;
986 if (!fetch_folders_for_pattern (
987 istore, server, pat, flags, list_ext,
988 folders, cancellable, error)) {
993 /* If the server doesn't support LIST-EXTENDED then we have to
994 * issue LSUB to list the subscribed folders separately */
995 flags |= CAMEL_STORE_FOLDER_INFO_SUBSCRIBED;
996 if (!fetch_folders_for_pattern (
997 istore, server, pat, flags, NULL,
998 folders, cancellable, error)) {
1012 g_list_free (namespaces);
1013 g_object_unref (server);
1017 g_list_free (namespaces);
1018 g_object_unref (server);
1019 g_hash_table_destroy (folders);
1024 sync_folders (CamelIMAPXStore *istore,
1025 const gchar *pattern,
1027 GCancellable *cancellable,
1030 CamelSettings *settings;
1031 GHashTable *folders_from_server;
1032 gboolean notify_all;
1035 folders_from_server = fetch_folders_for_namespaces (
1036 istore, pattern, sync, cancellable, error);
1037 if (folders_from_server == NULL)
1040 settings = camel_service_ref_settings (CAMEL_SERVICE (istore));
1041 notify_all = !camel_imapx_settings_get_use_subscriptions (CAMEL_IMAPX_SETTINGS (settings));
1042 g_object_unref (settings);
1044 total = camel_store_summary_count ((CamelStoreSummary *) istore->summary);
1045 for (i = 0; i < total; i++) {
1047 const gchar *full_name;
1048 CamelFolderInfo *fi;
1050 si = camel_store_summary_index ((CamelStoreSummary *) istore->summary, i);
1054 full_name = camel_imapx_store_info_full_name (istore->summary, si);
1055 if (!full_name || !*full_name) {
1056 camel_store_summary_info_free ((CamelStoreSummary *) istore->summary, si);
1060 if (!pattern || !*pattern || imapx_match_pattern (camel_imapx_store_summary_namespace_find_full (istore->summary, full_name), pattern, full_name)) {
1061 if ((fi = g_hash_table_lookup (folders_from_server, camel_store_info_path (istore->summary, si))) != NULL) {
1062 gboolean do_notify = notify_all;
1064 if (((fi->flags ^ si->flags) & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED)) {
1065 si->flags = (si->flags & ~CAMEL_FOLDER_SUBSCRIBED) | (fi->flags & CAMEL_FOLDER_SUBSCRIBED);
1066 camel_store_summary_touch ((CamelStoreSummary *) istore->summary);
1071 camel_store_folder_created (CAMEL_STORE (istore), fi);
1072 camel_subscribable_folder_subscribed (CAMEL_SUBSCRIBABLE (istore), fi);
1075 gchar *dup_folder_name = g_strdup (camel_store_info_path (istore->summary, si));
1077 if (dup_folder_name) {
1078 imapx_unmark_folder_subscribed (istore,dup_folder_name, TRUE);
1079 imapx_delete_folder_from_cache (istore, dup_folder_name);
1080 g_free (dup_folder_name);
1082 camel_store_summary_remove ((CamelStoreSummary *) istore->summary, si);
1089 camel_store_summary_info_free ((CamelStoreSummary *) istore->summary, si);
1092 g_hash_table_foreach (folders_from_server, imapx_get_folders_free, NULL);
1093 g_hash_table_destroy (folders_from_server);
1099 imapx_refresh_finfo (CamelSession *session,
1100 GCancellable *cancellable,
1101 CamelIMAPXStore *store,
1104 CamelService *service;
1105 const gchar *display_name;
1107 service = CAMEL_SERVICE (store);
1108 display_name = camel_service_get_display_name (service);
1110 camel_operation_push_message (
1111 cancellable, _("Retrieving folder list for %s"),
1114 if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store)))
1117 if (!camel_service_connect_sync (
1118 CAMEL_SERVICE (store), cancellable, error))
1121 /* look in all namespaces */
1122 sync_folders (store, "", FALSE, cancellable, error);
1124 camel_store_summary_save (CAMEL_STORE_SUMMARY (store->summary));
1127 camel_operation_pop_message (cancellable);
1131 discover_inbox (CamelStore *store,
1132 GCancellable *cancellable)
1135 CamelIMAPXStore *istore = (CamelIMAPXStore *) store;
1137 si = camel_store_summary_path ((CamelStoreSummary *) istore->summary, "INBOX");
1138 if (si == NULL || (si->flags & CAMEL_FOLDER_SUBSCRIBED) == 0) {
1139 if (imapx_subscribe_folder (store, "INBOX", FALSE, cancellable, NULL) && !si)
1140 sync_folders (istore, "INBOX", TRUE, cancellable, NULL);
1143 camel_store_summary_info_free ((CamelStoreSummary *) istore->summary, si);
1148 imapx_can_refresh_folder (CamelStore *store,
1149 CamelFolderInfo *info,
1152 CamelService *service;
1153 CamelSettings *settings;
1154 CamelStoreClass *store_class;
1156 gboolean check_subscribed;
1157 gboolean subscribed;
1159 GError *local_error = NULL;
1161 store_class = CAMEL_STORE_CLASS (camel_imapx_store_parent_class);
1163 service = CAMEL_SERVICE (store);
1165 settings = camel_service_ref_settings (service);
1167 check_all = camel_imapx_settings_get_check_all (
1168 CAMEL_IMAPX_SETTINGS (settings));
1170 check_subscribed = camel_imapx_settings_get_check_subscribed (
1171 CAMEL_IMAPX_SETTINGS (settings));
1173 g_object_unref (settings);
1175 subscribed = ((info->flags & CAMEL_FOLDER_SUBSCRIBED) != 0);
1177 res = store_class->can_refresh_folder (store, info, &local_error) ||
1178 check_all || (check_subscribed && subscribed);
1180 if (!res && local_error == NULL && CAMEL_IS_IMAPX_STORE (store)) {
1182 CamelStoreSummary *sm = CAMEL_STORE_SUMMARY (((CamelIMAPXStore *)(store))->summary);
1187 si = camel_store_summary_path (sm, info->full_name);
1189 res = (si->flags & CAMEL_STORE_INFO_FOLDER_CHECK_FOR_NEW) != 0 ? TRUE : FALSE;
1191 camel_store_summary_info_free (sm, si);
1195 if (local_error != NULL)
1196 g_propagate_error (error, local_error);
1201 static CamelFolder *
1202 imapx_store_get_folder_sync (CamelStore *store,
1203 const gchar *folder_name,
1204 CamelStoreGetFolderFlags flags,
1205 GCancellable *cancellable,
1208 CamelFolder *folder;
1210 folder = get_folder_offline (store, folder_name, flags, NULL);
1211 if (folder == NULL) {
1213 error, CAMEL_STORE_ERROR,
1214 CAMEL_STORE_ERROR_NO_FOLDER,
1215 _("No such folder: %s"), folder_name);
1222 static CamelFolderInfo *
1223 imapx_store_get_folder_info_sync (CamelStore *store,
1225 CamelStoreGetFolderInfoFlags flags,
1226 GCancellable *cancellable,
1229 CamelIMAPXStore *istore = (CamelIMAPXStore *) store;
1230 CamelFolderInfo * fi= NULL;
1231 CamelService *service;
1232 CamelSession *session;
1233 CamelSettings *settings;
1234 gboolean initial_setup = FALSE;
1235 gboolean use_subscriptions;
1238 service = CAMEL_SERVICE (store);
1239 session = camel_service_get_session (service);
1241 settings = camel_service_ref_settings (service);
1243 use_subscriptions = camel_imapx_settings_get_use_subscriptions (
1244 CAMEL_IMAPX_SETTINGS (settings));
1246 g_object_unref (settings);
1251 g_mutex_lock (&istore->get_finfo_lock);
1253 if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store))) {
1254 fi = get_folder_info_offline (store, top, flags, error);
1256 g_mutex_unlock (&istore->get_finfo_lock);
1260 if (camel_store_summary_count ((CamelStoreSummary *) istore->summary) == 0)
1261 initial_setup = TRUE;
1263 if (!initial_setup && flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED) {
1264 time_t now = time (NULL);
1266 if (now - istore->last_refresh_time > FINFO_REFRESH_INTERVAL) {
1267 istore->last_refresh_time = time (NULL);
1269 camel_session_submit_job (
1270 session, (CamelSessionCallback)
1271 imapx_refresh_finfo,
1272 g_object_ref (store),
1273 (GDestroyNotify) g_object_unref);
1276 fi = get_folder_info_offline (store, top, flags, error);
1277 g_mutex_unlock (&istore->get_finfo_lock);
1281 if (!camel_service_connect_sync (
1282 CAMEL_SERVICE (store), cancellable, error)) {
1283 g_mutex_unlock (&istore->get_finfo_lock);
1287 if (*top && flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIPTION_LIST) {
1288 fi = get_folder_info_offline (store, top, flags, error);
1289 g_mutex_unlock (&istore->get_finfo_lock);
1297 name = camel_imapx_store_summary_full_from_path (istore->summary, top);
1299 name = camel_imapx_store_summary_path_to_full (istore->summary, top, istore->dir_sep);
1302 pattern = g_alloca (i + 5);
1303 strcpy (pattern, name);
1306 pattern = g_alloca (1);
1310 if (!sync_folders (istore, pattern, TRUE, cancellable, error)) {
1311 g_mutex_unlock (&istore->get_finfo_lock);
1315 camel_store_summary_save ((CamelStoreSummary *) istore->summary);
1317 /* ensure the INBOX is subscribed if lsub was preferred*/
1318 if (initial_setup && use_subscriptions)
1319 discover_inbox (store, cancellable);
1321 fi = get_folder_info_offline (store, top, flags, error);
1322 g_mutex_unlock (&istore->get_finfo_lock);
1326 static CamelFolder *
1327 imapx_store_get_junk_folder_sync (CamelStore *store,
1328 GCancellable *cancellable,
1331 CamelFolder *folder;
1332 CamelStoreClass *store_class;
1334 store_class = CAMEL_STORE_CLASS (camel_imapx_store_parent_class);
1335 folder = store_class->get_junk_folder_sync (store, cancellable, error);
1338 CamelObject *object = CAMEL_OBJECT (folder);
1339 CamelService *service;
1340 const gchar *user_cache_dir;
1343 service = CAMEL_SERVICE (store);
1344 user_cache_dir = camel_service_get_user_cache_dir (service);
1346 state = g_build_filename (
1347 user_cache_dir, "system", "Junk.cmeta", NULL);
1349 camel_object_set_state_filename (object, state);
1352 camel_object_state_read (object);
1358 static CamelFolder *
1359 imapx_store_get_trash_folder_sync (CamelStore *store,
1360 GCancellable *cancellable,
1363 CamelFolder *folder;
1364 CamelStoreClass *store_class;
1366 store_class = CAMEL_STORE_CLASS (camel_imapx_store_parent_class);
1367 folder = store_class->get_trash_folder_sync (store, cancellable, error);
1370 CamelObject *object = CAMEL_OBJECT (folder);
1371 CamelService *service;
1372 const gchar *user_cache_dir;
1375 service = CAMEL_SERVICE (store);
1376 user_cache_dir = camel_service_get_user_cache_dir (service);
1378 state = g_build_filename (
1379 user_cache_dir, "system", "Trash.cmeta", NULL);
1381 camel_object_set_state_filename (object, state);
1384 camel_object_state_read (object);
1390 static CamelFolderInfo *
1391 imapx_store_create_folder_sync (CamelStore *store,
1392 const gchar *parent_name,
1393 const gchar *folder_name,
1394 GCancellable *cancellable,
1398 CamelIMAPXStoreNamespace *ns;
1399 CamelIMAPXStore *istore = (CamelIMAPXStore *) store;
1400 CamelIMAPXServer *server;
1401 gchar *real_name, *full_name, *parent_real;
1402 CamelFolderInfo *fi = NULL;
1406 if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store))) {
1408 error, CAMEL_SERVICE_ERROR,
1409 CAMEL_SERVICE_ERROR_UNAVAILABLE,
1410 _("You must be working online to complete this operation"));
1414 server = camel_imapx_store_get_server (istore, NULL, cancellable, error);
1421 ns = camel_imapx_store_summary_namespace_find_path (istore->summary, parent_name);
1428 if (strchr (folder_name, dir_sep)) {
1430 error, CAMEL_FOLDER_ERROR,
1431 CAMEL_FOLDER_ERROR_INVALID_PATH,
1432 _("The folder name \"%s\" is invalid because it contains the character \"%c\""),
1433 folder_name, dir_sep);
1434 g_object_unref (server);
1438 parent_real = camel_imapx_store_summary_full_from_path (istore->summary, parent_name);
1439 if (parent_real == NULL) {
1441 error, CAMEL_FOLDER_ERROR,
1442 CAMEL_FOLDER_ERROR_INVALID_STATE,
1443 _("Unknown parent folder: %s"), parent_name);
1444 g_object_unref (server);
1448 si = camel_store_summary_path ((CamelStoreSummary *) istore->summary, parent_name);
1449 if (si && si->flags & CAMEL_STORE_INFO_FOLDER_NOINFERIORS) {
1451 error, CAMEL_FOLDER_ERROR,
1452 CAMEL_FOLDER_ERROR_INVALID_STATE,
1453 _("The parent folder is not allowed to contain subfolders"));
1454 g_object_unref (server);
1459 camel_store_summary_info_free ((CamelStoreSummary *) istore->summary, si);
1461 real_name = camel_imapx_store_summary_path_to_full (istore->summary, folder_name, dir_sep);
1462 full_name = imapx_concat (istore, parent_real, real_name);
1465 success = camel_imapx_server_create_folder (
1466 server, full_name, cancellable, error);
1467 g_object_unref (server);
1470 CamelIMAPXStoreInfo *si;
1472 si = camel_imapx_store_summary_add_from_full (istore->summary, full_name, dir_sep);
1473 camel_store_summary_save ((CamelStoreSummary *) istore->summary);
1474 fi = imapx_build_folder_info (istore, camel_store_info_path (istore->summary, si));
1475 fi->flags |= CAMEL_FOLDER_NOCHILDREN;
1476 camel_store_folder_created (store, fi);
1480 g_free (parent_real);
1486 imapx_store_delete_folder_sync (CamelStore *store,
1487 const gchar *folder_name,
1488 GCancellable *cancellable,
1491 CamelIMAPXStore *istore = (CamelIMAPXStore *) store;
1492 CamelIMAPXServer *server;
1495 if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store))) {
1497 error, CAMEL_SERVICE_ERROR,
1498 CAMEL_SERVICE_ERROR_UNAVAILABLE,
1499 _("You must be working online to complete this operation"));
1502 /* Use INBOX connection as the implementation would try to select inbox to ensure
1503 * we are not selected on the folder being deleted */
1504 server = camel_imapx_store_get_server (istore, "INBOX", cancellable, error);
1508 success = camel_imapx_server_delete_folder (
1509 server, folder_name, cancellable, error);
1510 g_object_unref (server);
1513 imapx_delete_folder_from_cache (istore, folder_name);
1519 imapx_store_rename_folder_sync (CamelStore *store,
1522 GCancellable *cancellable,
1525 CamelIMAPXStore *istore = (CamelIMAPXStore *) store;
1526 CamelIMAPXServer *server;
1527 CamelService *service;
1528 CamelSettings *settings;
1529 const gchar *user_cache_dir;
1530 gchar *oldpath, *newpath, *storage_path;
1531 gboolean use_subscriptions;
1532 gboolean success = FALSE;
1534 service = CAMEL_SERVICE (store);
1535 user_cache_dir = camel_service_get_user_cache_dir (service);
1537 settings = camel_service_ref_settings (service);
1539 use_subscriptions = camel_imapx_settings_get_use_subscriptions (
1540 CAMEL_IMAPX_SETTINGS (settings));
1542 g_object_unref (settings);
1544 if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store))) {
1546 error, CAMEL_SERVICE_ERROR,
1547 CAMEL_SERVICE_ERROR_UNAVAILABLE,
1548 _("You must be working online to complete this operation"));
1552 if (use_subscriptions)
1553 imapx_unsubscribe_folder (store, old, FALSE, cancellable, NULL);
1555 /* Use INBOX connection as the implementation would try to select inbox to ensure
1556 * we are not selected on the folder being renamed */
1557 server = camel_imapx_store_get_server (istore, "INBOX", cancellable, error);
1559 success = camel_imapx_server_rename_folder (
1560 server, old, new, cancellable, error);
1561 g_object_unref (server);
1565 imapx_subscribe_folder (store, old, FALSE, cancellable, NULL);
1569 /* rename summary, and handle broken server */
1570 rename_folder_info (istore, old, new);
1572 if (use_subscriptions)
1573 success = imapx_subscribe_folder (
1574 store, new, FALSE, cancellable, error);
1576 storage_path = g_build_filename (user_cache_dir, "folders", NULL);
1577 oldpath = imapx_path_to_physical (storage_path, old);
1578 newpath = imapx_path_to_physical (storage_path, new);
1579 g_free (storage_path);
1581 /* So do we care if this didn't work? Its just a cache? */
1582 if (g_rename (oldpath, newpath) == -1) {
1584 "Could not rename message cache '%s' to '%s': %s: cache reset",
1585 oldpath, newpath, g_strerror (errno));
1595 imapx_store_noop_sync (CamelStore *store,
1596 GCancellable *cancellable,
1599 CamelIMAPXStore *istore = (CamelIMAPXStore *) store;
1601 gboolean success = TRUE;
1603 if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store)))
1606 list = camel_imapx_conn_manager_get_connections (istore->con_man);
1608 for (link = list; link != NULL; link = g_list_next (link)) {
1609 CamelIMAPXServer *server = CAMEL_IMAPX_SERVER (link->data);
1611 /* we just return last noops value, technically not correct though */
1612 success = camel_imapx_server_noop (server, NULL, cancellable, error);
1617 g_list_free_full (list, (GDestroyNotify) g_object_unref);
1623 imapx_migrate_to_user_cache_dir (CamelService *service)
1625 const gchar *user_data_dir, *user_cache_dir;
1627 g_return_if_fail (service != NULL);
1628 g_return_if_fail (CAMEL_IS_SERVICE (service));
1630 user_data_dir = camel_service_get_user_data_dir (service);
1631 user_cache_dir = camel_service_get_user_cache_dir (service);
1633 g_return_if_fail (user_data_dir != NULL);
1634 g_return_if_fail (user_cache_dir != NULL);
1636 /* migrate only if the source directory exists and the destination doesn't */
1637 if (g_file_test (user_data_dir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR) &&
1638 !g_file_test (user_cache_dir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) {
1641 parent_dir = g_path_get_dirname (user_cache_dir);
1642 g_mkdir_with_parents (parent_dir, S_IRWXU);
1643 g_free (parent_dir);
1645 if (g_rename (user_data_dir, user_cache_dir) == -1)
1646 g_debug ("%s: Failed to migrate '%s' to '%s': %s", G_STRFUNC, user_data_dir, user_cache_dir, g_strerror (errno));
1651 imapx_store_initable_init (GInitable *initable,
1652 GCancellable *cancellable,
1655 CamelIMAPXStore *imapx_store;
1657 CamelService *service;
1658 const gchar *user_cache_dir;
1661 imapx_store = CAMEL_IMAPX_STORE (initable);
1662 store = CAMEL_STORE (initable);
1663 service = CAMEL_SERVICE (initable);
1665 store->flags |= CAMEL_STORE_USE_CACHE_DIR;
1666 imapx_migrate_to_user_cache_dir (service);
1668 /* Chain up to parent interface's init() method. */
1669 if (!parent_initable_interface->init (initable, cancellable, error))
1672 service = CAMEL_SERVICE (initable);
1673 user_cache_dir = camel_service_get_user_cache_dir (service);
1675 imapx_store->summary = camel_imapx_store_summary_new ();
1677 summary = g_build_filename (user_cache_dir, ".ev-store-summary", NULL);
1678 camel_store_summary_set_filename ((CamelStoreSummary *) imapx_store->summary, summary);
1679 camel_store_summary_load ((CamelStoreSummary *) imapx_store->summary);
1686 static const gchar *
1687 imapx_store_get_service_name (CamelNetworkService *service,
1688 CamelNetworkSecurityMethod method)
1690 const gchar *service_name;
1693 case CAMEL_NETWORK_SECURITY_METHOD_SSL_ON_ALTERNATE_PORT:
1694 service_name = "imaps";
1698 service_name = "imap";
1702 return service_name;
1706 imapx_store_get_default_port (CamelNetworkService *service,
1707 CamelNetworkSecurityMethod method)
1709 guint16 default_port;
1712 case CAMEL_NETWORK_SECURITY_METHOD_SSL_ON_ALTERNATE_PORT:
1713 default_port = IMAPS_PORT;
1717 default_port = IMAP_PORT;
1721 return default_port;
1725 imapx_store_folder_is_subscribed (CamelSubscribable *subscribable,
1726 const gchar *folder_name)
1728 CamelIMAPXStore *istore = CAMEL_IMAPX_STORE (subscribable);
1730 gint is_subscribed = FALSE;
1732 if (folder_name && *folder_name == '/')
1735 si = camel_store_summary_path ((CamelStoreSummary *) istore->summary, folder_name);
1737 is_subscribed = (si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED) != 0;
1738 camel_store_summary_info_free ((CamelStoreSummary *) istore->summary, si);
1741 return is_subscribed;
1745 imapx_store_subscribe_folder_sync (CamelSubscribable *subscribable,
1746 const gchar *folder_name,
1747 GCancellable *cancellable,
1750 return imapx_subscribe_folder (
1751 CAMEL_STORE (subscribable),
1752 folder_name, TRUE, cancellable, error);
1756 imapx_store_unsubscribe_folder_sync (CamelSubscribable *subscribable,
1757 const gchar *folder_name,
1758 GCancellable *cancellable,
1761 return imapx_unsubscribe_folder (
1762 CAMEL_STORE (subscribable),
1763 folder_name, TRUE, cancellable, error);
1767 camel_imapx_store_class_init (CamelIMAPXStoreClass *class)
1769 GObjectClass *object_class;
1770 CamelServiceClass *service_class;
1771 CamelStoreClass *store_class;
1773 object_class = G_OBJECT_CLASS (class);
1774 object_class->dispose = imapx_store_dispose;
1775 object_class->finalize = imapx_store_finalize;
1777 service_class = CAMEL_SERVICE_CLASS (class);
1778 service_class->settings_type = CAMEL_TYPE_IMAPX_SETTINGS;
1779 service_class->get_name = imapx_get_name;
1780 service_class->connect_sync = imapx_connect_sync;
1781 service_class->disconnect_sync = imapx_disconnect_sync;
1782 service_class->authenticate_sync = imapx_authenticate_sync;
1783 service_class->query_auth_types_sync = imapx_query_auth_types_sync;
1785 store_class = CAMEL_STORE_CLASS (class);
1786 store_class->hash_folder_name = imapx_name_hash;
1787 store_class->equal_folder_name = imapx_name_equal;
1788 store_class->can_refresh_folder = imapx_can_refresh_folder;
1789 store_class->free_folder_info = camel_store_free_folder_info_full;
1790 store_class->get_folder_sync = imapx_store_get_folder_sync;
1791 store_class->get_folder_info_sync = imapx_store_get_folder_info_sync;
1792 store_class->get_junk_folder_sync = imapx_store_get_junk_folder_sync;
1793 store_class->get_trash_folder_sync = imapx_store_get_trash_folder_sync;
1794 store_class->create_folder_sync = imapx_store_create_folder_sync;
1795 store_class->delete_folder_sync = imapx_store_delete_folder_sync;
1796 store_class->rename_folder_sync = imapx_store_rename_folder_sync;
1797 store_class->noop_sync = imapx_store_noop_sync;
1801 camel_imapx_store_initable_init (GInitableIface *interface)
1803 parent_initable_interface = g_type_interface_peek_parent (interface);
1805 interface->init = imapx_store_initable_init;
1809 camel_network_service_init (CamelNetworkServiceInterface *interface)
1811 interface->get_service_name = imapx_store_get_service_name;
1812 interface->get_default_port = imapx_store_get_default_port;
1816 camel_subscribable_init (CamelSubscribableInterface *interface)
1818 interface->folder_is_subscribed = imapx_store_folder_is_subscribed;
1819 interface->subscribe_folder_sync = imapx_store_subscribe_folder_sync;
1820 interface->unsubscribe_folder_sync = imapx_store_unsubscribe_folder_sync;
1824 camel_imapx_store_init (CamelIMAPXStore *istore)
1826 g_mutex_init (&istore->get_finfo_lock);
1827 istore->last_refresh_time = time (NULL) - (FINFO_REFRESH_INTERVAL + 10);
1828 istore->dir_sep = '/';
1829 istore->con_man = camel_imapx_conn_manager_new (CAMEL_STORE (istore));
1831 imapx_utils_init ();