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);
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 CamelIMAPXServer *server = NULL;
174 camel_service_lock (CAMEL_SERVICE (istore), CAMEL_SERVICE_REC_CONNECT_LOCK);
176 server = camel_imapx_conn_manager_get_connection (istore->con_man, folder_name, cancellable, error);
178 camel_service_unlock (CAMEL_SERVICE (istore), CAMEL_SERVICE_REC_CONNECT_LOCK);
184 camel_imapx_store_op_done (CamelIMAPXStore *istore,
185 CamelIMAPXServer *server,
186 const gchar *folder_name)
188 g_return_if_fail (server != NULL);
190 camel_imapx_conn_manager_update_con_info (istore->con_man, server, folder_name);
194 imapx_connect_sync (CamelService *service,
195 GCancellable *cancellable,
198 CamelIMAPXStore *istore = (CamelIMAPXStore *) service;
199 CamelIMAPXServer *server;
201 server = camel_imapx_store_get_server (istore, NULL, cancellable, error);
203 g_object_unref (server);
211 imapx_disconnect_sync (CamelService *service,
213 GCancellable *cancellable,
216 CamelIMAPXStore *istore = CAMEL_IMAPX_STORE (service);
217 CamelServiceClass *service_class;
219 service_class = CAMEL_SERVICE_CLASS (camel_imapx_store_parent_class);
220 if (!service_class->disconnect_sync (service, clean, cancellable, error))
223 camel_service_lock (service, CAMEL_SERVICE_REC_CONNECT_LOCK);
225 if (istore->con_man) {
226 camel_imapx_conn_manager_close_connections (istore->con_man);
229 camel_service_unlock (service, CAMEL_SERVICE_REC_CONNECT_LOCK);
234 static CamelAuthenticationResult
235 imapx_authenticate_sync (CamelService *service,
236 const gchar *mechanism,
237 GCancellable *cancellable,
240 CamelIMAPXStore *istore = CAMEL_IMAPX_STORE (service);
241 CamelIMAPXServer *server;
243 /* CamelIMAPXConnManager sets this before calling
244 * camel_imapx_server_connect()(), and then clears it
245 * immediately after, all while holding the recursive
246 * connection lock (CAMEL_SERVICE_REC_CONNECT_LOCK).
247 * Otherwise we'd have no way of knowing which server
248 * is trying to authenticate. */
249 server = istore->authenticating_server;
251 g_return_val_if_fail (
252 CAMEL_IS_IMAPX_SERVER (server),
253 CAMEL_AUTHENTICATION_REJECTED);
255 return camel_imapx_server_authenticate (
256 server, mechanism, cancellable, error);
259 CamelServiceAuthType camel_imapx_password_authtype = {
262 N_("This option will connect to the IMAP server using a "
263 "plaintext password."),
270 imapx_query_auth_types_sync (CamelService *service,
271 GCancellable *cancellable,
274 CamelIMAPXStore *istore = CAMEL_IMAPX_STORE (service);
275 CamelServiceAuthType *authtype;
276 GList *sasl_types, *t, *next;
278 CamelIMAPXServer *server;
280 if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (istore))) {
282 error, CAMEL_SERVICE_ERROR,
283 CAMEL_SERVICE_ERROR_UNAVAILABLE,
284 _("You must be working online to complete this operation"));
288 camel_service_lock (service, CAMEL_SERVICE_REC_CONNECT_LOCK);
290 server = camel_imapx_server_new (CAMEL_STORE (istore));
292 connected = server->stream != NULL;
294 connected = imapx_connect_to_server (server, cancellable, error);
295 camel_service_unlock (service, CAMEL_SERVICE_REC_CONNECT_LOCK);
299 sasl_types = camel_sasl_authtype_list (FALSE);
300 for (t = sasl_types; t; t = next) {
304 if (!g_hash_table_lookup (server->cinfo->auth_types, authtype->authproto)) {
305 sasl_types = g_list_remove_link (sasl_types, t);
310 g_object_unref (server);
312 return g_list_prepend (sasl_types, &camel_imapx_password_authtype);
316 get_folder_offline (CamelStore *store,
317 const gchar *folder_name,
321 CamelIMAPXStore *imapx_store = CAMEL_IMAPX_STORE (store);
322 CamelFolder *new_folder = NULL;
324 CamelService *service;
325 const gchar *user_cache_dir;
327 service = CAMEL_SERVICE (store);
328 user_cache_dir = camel_service_get_user_cache_dir (service);
330 si = camel_store_summary_path ((CamelStoreSummary *) imapx_store->summary, folder_name);
332 gchar *folder_dir, *storage_path;
334 /* Note: Although the INBOX is defined to be case-insensitive in the IMAP RFC
335 * it is still up to the server how to acutally name it in a LIST response. Since
336 * we stored the name as the server provided it us in the summary we take that name
337 * to look up the folder.
338 * But for the on-disk cache we do always capitalize the Inbox no matter what the
341 if (!g_ascii_strcasecmp (folder_name, "INBOX"))
342 folder_name = "INBOX";
344 storage_path = g_build_filename (user_cache_dir, "folders", NULL);
345 folder_dir = imapx_path_to_physical (storage_path, folder_name);
346 g_free (storage_path);
348 new_folder = camel_imapx_folder_new (store, folder_dir, folder_name, error);
351 camel_store_summary_info_free ((CamelStoreSummary *) imapx_store->summary, si);
354 error, CAMEL_STORE_ERROR,
355 CAMEL_STORE_ERROR_NO_FOLDER,
356 _("No such folder %s"), folder_name);
362 /* folder_name is path name */
363 static CamelFolderInfo *
364 imapx_build_folder_info (CamelIMAPXStore *imapx_store,
365 const gchar *folder_name)
370 fi = camel_folder_info_new ();
371 fi->full_name = g_strdup (folder_name);
375 name = strrchr (fi->full_name, '/');
377 name = fi->full_name;
380 if (!g_ascii_strcasecmp (fi->full_name, "INBOX"))
381 fi->display_name = g_strdup (_("Inbox"));
382 /* Do not localize the rest, these are from a server, thus shouldn't be localized */
383 /*else if (!g_ascii_strcasecmp (fi->full_name, "Drafts"))
384 fi->display_name = g_strdup (_("Drafts"));
385 else if (!g_ascii_strcasecmp (fi->full_name, "Sent"))
386 fi->display_name = g_strdup (_("Sent"));
387 else if (!g_ascii_strcasecmp (fi->full_name, "Templates"))
388 fi->display_name = g_strdup (_("Templates"));
389 else if (!g_ascii_strcasecmp (fi->full_name, "Trash"))
390 fi->display_name = g_strdup (_("Trash"));*/
392 fi->display_name = g_strdup (name);
398 fill_fi (CamelStore *store,
403 CamelService *service = (CamelService *) store;
404 CamelSettings *settings;
405 gboolean mobile_mode;
407 settings = camel_service_get_settings (service);
408 mobile_mode = camel_imapx_settings_get_mobile_mode (
409 CAMEL_IMAPX_SETTINGS (settings));
411 folder = camel_object_bag_peek (store->folders, fi->full_name);
413 CamelIMAPXSummary *ims;
416 ims = (CamelIMAPXSummary *) folder->summary;
418 ims = (CamelIMAPXSummary *) camel_imapx_summary_new (folder);
420 /* Mobile clients would still love to see the total unread of actual mails
421 * than what they just have downloaded. So we override that information by giving
422 * what the server has instead of what we have downloaded. */
424 fi->unread = ((CamelIMAPXFolder *) folder)->unread_on_server;
426 fi->unread = camel_folder_summary_get_unread_count ((CamelFolderSummary *) ims);
427 fi->total = camel_folder_summary_get_saved_count ((CamelFolderSummary *) ims);
429 if (!folder->summary)
430 g_object_unref (ims);
431 g_object_unref (folder);
435 /* imap needs to treat inbox case insensitive */
436 /* we'll assume the names are normalized already */
438 folder_hash (gconstpointer ap)
442 if (g_ascii_strcasecmp(a, "INBOX") == 0)
445 return g_str_hash (a);
449 folder_eq (gconstpointer ap,
455 if (g_ascii_strcasecmp(a, "INBOX") == 0)
457 if (g_ascii_strcasecmp(b, "INBOX") == 0)
460 return g_str_equal (a, b);
464 imapx_match_pattern (CamelIMAPXStoreNamespace *ns,
465 const gchar *pattern,
480 } else if (p == '%') {
486 } else if (p == '*') {
492 return n == 0 && (p == '%' || p == 0);
496 imapx_unmark_folder_subscribed (CamelIMAPXStore *istore,
497 const gchar *folder_name,
498 gboolean emit_signal)
502 si = camel_store_summary_path ((CamelStoreSummary *) istore->summary, folder_name);
504 if (si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED) {
505 si->flags &= ~CAMEL_STORE_INFO_FOLDER_SUBSCRIBED;
506 camel_store_summary_touch ((CamelStoreSummary *) istore->summary);
507 camel_store_summary_save ((CamelStoreSummary *) istore->summary);
509 camel_store_summary_info_free ((CamelStoreSummary *) istore->summary, si);
515 fi = imapx_build_folder_info (istore, folder_name);
516 camel_subscribable_folder_unsubscribed (
517 CAMEL_SUBSCRIBABLE (istore), fi);
518 camel_folder_info_free (fi);
523 imapx_mark_folder_subscribed (CamelIMAPXStore *istore,
524 const gchar *folder_name,
525 gboolean emit_signal)
529 si = camel_store_summary_path ((CamelStoreSummary *) istore->summary, folder_name);
531 if ((si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED) == 0) {
532 si->flags |= CAMEL_STORE_INFO_FOLDER_SUBSCRIBED;
533 camel_store_summary_touch ((CamelStoreSummary *) istore->summary);
534 camel_store_summary_save ((CamelStoreSummary *) istore->summary);
536 camel_store_summary_info_free ((CamelStoreSummary *) istore->summary, si);
542 fi = imapx_build_folder_info (istore, folder_name);
543 camel_subscribable_folder_subscribed (
544 CAMEL_SUBSCRIBABLE (istore), fi);
545 camel_folder_info_free (fi);
550 imapx_subscribe_folder (CamelStore *store,
551 const gchar *folder_name,
552 gboolean emit_signal,
553 GCancellable *cancellable,
556 CamelIMAPXStore *istore = (CamelIMAPXStore *) store;
557 CamelIMAPXServer *server;
560 if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store)))
563 server = camel_imapx_store_get_server (istore, NULL, cancellable, error);
567 success = camel_imapx_server_manage_subscription (
568 server, folder_name, TRUE, cancellable, error);
569 g_object_unref (server);
572 imapx_mark_folder_subscribed (istore, folder_name, emit_signal);
578 imapx_unsubscribe_folder (CamelStore *store,
579 const gchar *folder_name,
580 gboolean emit_signal,
581 GCancellable *cancellable,
584 CamelIMAPXStore *istore = (CamelIMAPXStore *) store;
585 CamelIMAPXServer *server;
588 if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store)))
591 server = camel_imapx_store_get_server (istore, NULL, cancellable, error);
595 success = camel_imapx_server_manage_subscription (
596 server, folder_name, FALSE, cancellable, error);
597 g_object_unref (server);
600 imapx_unmark_folder_subscribed (istore, folder_name, emit_signal);
606 imapx_delete_folder_from_cache (CamelIMAPXStore *istore,
607 const gchar *folder_name)
610 gchar *folder_dir, *storage_path;
612 CamelService *service;
613 const gchar *user_cache_dir;
615 service = CAMEL_SERVICE (istore);
616 user_cache_dir = camel_service_get_user_cache_dir (service);
618 storage_path = g_build_filename (user_cache_dir, "folders", NULL);
619 folder_dir = imapx_path_to_physical (storage_path, folder_name);
620 g_free (storage_path);
621 if (g_access (folder_dir, F_OK) != 0) {
626 /* Delete summary and all the data */
627 state_file = g_build_filename (folder_dir, "cmeta", NULL);
628 g_unlink (state_file);
631 camel_db_delete_folder (((CamelStore *) istore)->cdb_w, folder_name, NULL);
632 g_rmdir (folder_dir);
634 state_file = g_build_filename (folder_dir, "subfolders", NULL);
635 g_rmdir (state_file);
638 g_rmdir (folder_dir);
642 camel_store_summary_remove_path ((CamelStoreSummary *) istore->summary, folder_name);
643 camel_store_summary_save ((CamelStoreSummary *) istore->summary);
645 fi = imapx_build_folder_info (istore, folder_name);
646 camel_store_folder_deleted (CAMEL_STORE (istore), fi);
647 camel_folder_info_free (fi);
651 rename_folder_info (CamelIMAPXStore *istore,
652 const gchar *old_name,
653 const gchar *new_name)
657 gint olen = strlen (old_name);
659 gchar *npath, *nfull;
661 count = camel_store_summary_count ((CamelStoreSummary *) istore->summary);
662 for (i = 0; i < count; i++) {
663 si = camel_store_summary_index ((CamelStoreSummary *) istore->summary, i);
666 path = camel_store_info_path (istore->summary, si);
667 if (strncmp (path, old_name, olen) == 0) {
668 if (strlen (path) > olen)
669 npath = g_strdup_printf("%s/%s", new_name, path+olen+1);
671 npath = g_strdup (new_name);
672 nfull = camel_imapx_store_summary_path_to_full (istore->summary, npath, istore->dir_sep);
674 camel_store_info_set_string ((CamelStoreSummary *) istore->summary, si, CAMEL_STORE_INFO_PATH, npath);
675 camel_store_info_set_string ((CamelStoreSummary *) istore->summary, si, CAMEL_IMAPX_STORE_INFO_FULL_NAME, nfull);
677 camel_store_summary_touch ((CamelStoreSummary *) istore->summary);
681 camel_store_summary_info_free ((CamelStoreSummary *) istore->summary, si);
685 static CamelFolderInfo *
686 get_folder_info_offline (CamelStore *store,
691 CamelIMAPXStore *imapx_store = CAMEL_IMAPX_STORE (store);
692 CamelService *service;
693 CamelSettings *settings;
694 gboolean include_inbox = FALSE;
697 gchar *pattern, *name;
698 gboolean use_namespace;
699 gboolean use_subscriptions;
702 service = CAMEL_SERVICE (store);
703 settings = camel_service_get_settings (service);
705 use_namespace = camel_imapx_settings_get_use_namespace (
706 CAMEL_IMAPX_SETTINGS (settings));
708 use_subscriptions = camel_imapx_settings_get_use_subscriptions (
709 CAMEL_IMAPX_SETTINGS (settings));
711 /* FIXME: obey other flags */
713 folders = g_ptr_array_new ();
715 if (top == NULL || top[0] == '\0') {
716 include_inbox = TRUE;
720 /* get starting point */
722 gchar *namespace = NULL;
725 namespace = camel_imapx_settings_dup_namespace (
726 CAMEL_IMAPX_SETTINGS (settings));
728 if (namespace != NULL) {
729 name = g_strdup (imapx_store->summary->namespaces->personal->full_name);
730 top = imapx_store->summary->namespaces->personal->path;
736 name = camel_imapx_store_summary_full_from_path (imapx_store->summary, top);
738 name = camel_imapx_store_summary_path_to_full (imapx_store->summary, top, imapx_store->dir_sep);
741 pattern = imapx_concat(imapx_store, name, "*");
743 /* folder_info_build will insert parent nodes as necessary and mark
744 * them as noselect, which is information we actually don't have at
745 * the moment. So let it do the right thing by bailing out if it's
746 * not a folder we're explicitly interested in. */
748 for (i = 0; i < camel_store_summary_count ((CamelStoreSummary *) imapx_store->summary); i++) {
749 CamelStoreInfo *si = camel_store_summary_index ((CamelStoreSummary *) imapx_store->summary, i);
750 const gchar *full_name;
751 CamelIMAPXStoreNamespace *ns;
756 full_name = camel_imapx_store_info_full_name (imapx_store->summary, si);
757 if (!full_name || !*full_name) {
758 camel_store_summary_info_free ((CamelStoreSummary *) imapx_store->summary, si);
762 ns = camel_imapx_store_summary_namespace_find_full (imapx_store->summary, full_name);
764 /* Modify the checks to see match the namespaces from preferences */
765 if ((g_str_equal (name, full_name)
766 || imapx_match_pattern (ns, pattern, full_name)
767 || (include_inbox && !g_ascii_strcasecmp (full_name, "INBOX")))
768 && ( (!use_subscriptions
769 || (flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED) == 0)
770 || (si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED)
771 || (flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIPTION_LIST) != 0)) {
773 fi = imapx_build_folder_info (imapx_store, camel_store_info_path ((CamelStoreSummary *) imapx_store->summary, si));
774 fi->unread = si->unread;
775 fi->total = si->total;
776 fi->flags = si->flags;
777 /* HACK: some servers report noinferiors for all folders (uw-imapd)
778 * We just translate this into nochildren, and let the imap layer enforce
779 * it. See create folder */
780 if (fi->flags & CAMEL_FOLDER_NOINFERIORS)
781 fi->flags = (fi->flags & ~CAMEL_FOLDER_NOINFERIORS) | CAMEL_FOLDER_NOCHILDREN;
783 /* blah, this gets lost somewhere, i can't be bothered finding out why */
784 if (!g_ascii_strcasecmp(fi->full_name, "inbox")) {
785 fi->flags = (fi->flags & ~CAMEL_FOLDER_TYPE_MASK) | CAMEL_FOLDER_TYPE_INBOX;
786 fi->flags |= CAMEL_FOLDER_SYSTEM;
789 if (!(si->flags & CAMEL_FOLDER_NOSELECT))
790 fill_fi ((CamelStore *) imapx_store, fi, 0);
793 fi->flags |= CAMEL_FOLDER_NOCHILDREN;
794 g_ptr_array_add (folders, fi);
796 camel_store_summary_info_free ((CamelStoreSummary *) imapx_store->summary, si);
800 fi = camel_folder_info_build (folders, top, '/', TRUE);
801 g_ptr_array_free (folders, TRUE);
808 add_folders_to_summary (CamelIMAPXStore *istore,
809 CamelIMAPXServer *server,
816 for (i = 0; i < folders->len; i++) {
817 struct _list_info *li = folders->pdata[i];
818 CamelIMAPXStoreInfo *si;
820 CamelFolderInfo *fi, *sfi;
824 path = camel_imapx_store_summary_path_to_full (istore->summary, li->name, li->separator);
825 sfi = g_hash_table_lookup (table, path);
827 sfi->flags |= CAMEL_STORE_INFO_FOLDER_SUBSCRIBED;
833 si = camel_imapx_store_summary_add_from_full (istore->summary, li->name, li->separator);
837 new_flags = (si->info.flags & (CAMEL_STORE_INFO_FOLDER_SUBSCRIBED | CAMEL_STORE_INFO_FOLDER_CHECK_FOR_NEW)) |
838 (li->flags & ~CAMEL_STORE_INFO_FOLDER_SUBSCRIBED);
840 if (!(server->cinfo->capa & IMAPX_CAPABILITY_NAMESPACE))
841 istore->dir_sep = li->separator;
843 if (si->info.flags != new_flags) {
844 si->info.flags = new_flags;
845 camel_store_summary_touch ((CamelStoreSummary *) istore->summary);
848 fi = camel_folder_info_new ();
849 fi->full_name = g_strdup (camel_store_info_path (istore->summary, si));
850 if (!g_ascii_strcasecmp(fi->full_name, "inbox")) {
851 li->flags |= CAMEL_FOLDER_SYSTEM | CAMEL_FOLDER_TYPE_INBOX;
852 fi->display_name = g_strdup (_("Inbox"));
854 fi->display_name = g_strdup (camel_store_info_name (istore->summary, si));
856 /* HACK: some servers report noinferiors for all folders (uw-imapd)
857 * We just translate this into nochildren, and let the imap layer enforce
858 * it. See create folder */
859 if (li->flags & CAMEL_FOLDER_NOINFERIORS)
860 li->flags = (li->flags & ~CAMEL_FOLDER_NOINFERIORS) | CAMEL_FOLDER_NOCHILDREN;
861 fi->flags = li->flags;
866 g_hash_table_insert (table, fi->full_name, fi);
871 free_list (gpointer data,
874 struct _list_info *li = data;
875 imapx_free_list (li);
879 imapx_get_folders_free (gpointer k,
883 camel_folder_info_free (v);
887 fetch_folders_for_pattern (CamelIMAPXStore *istore,
888 CamelIMAPXServer *server,
889 const gchar *pattern,
893 GCancellable *cancellable,
898 folders = camel_imapx_server_list (
899 server, pattern, flags, ext, cancellable, error);
903 add_folders_to_summary (istore, server, folders, table, (flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED));
905 g_ptr_array_foreach (folders, free_list, folders);
906 g_ptr_array_free (folders, TRUE);
912 get_namespaces (CamelIMAPXStore *istore)
914 GList *namespaces = NULL;
915 CamelIMAPXNamespaceList *nsl = NULL;
917 /* Add code to return the namespaces from preference else all of them */
918 nsl = istore->summary->namespaces;
920 namespaces = g_list_append (namespaces, nsl->personal);
922 namespaces = g_list_append (namespaces, nsl->other);
924 namespaces = g_list_append (namespaces, nsl->shared);
930 fetch_folders_for_namespaces (CamelIMAPXStore *istore,
931 const gchar *pattern,
933 GCancellable *cancellable,
936 CamelIMAPXServer *server;
937 GHashTable *folders = NULL;
938 GList *namespaces = NULL, *l;
940 server = camel_imapx_store_get_server (istore, NULL, cancellable, error);
944 folders = g_hash_table_new (folder_hash, folder_eq);
945 namespaces = get_namespaces (istore);
947 for (l = namespaces; l != NULL; l = g_list_next (l))
949 CamelIMAPXStoreNamespace *ns = l->data;
954 const gchar *list_ext = NULL;
960 pat = g_strdup_printf ("%s%c", ns->path, ns->sep);
962 pat = g_strdup (pattern);
965 flags |= CAMEL_STORE_FOLDER_INFO_SUBSCRIPTION_LIST;
967 if (server->cinfo->capa & IMAPX_CAPABILITY_LIST_EXTENDED)
968 list_ext = "RETURN (SUBSCRIBED)";
970 flags |= CAMEL_STORE_FOLDER_INFO_RECURSIVE;
971 if (!fetch_folders_for_pattern (
972 istore, server, pat, flags, list_ext,
973 folders, cancellable, error)) {
978 /* If the server doesn't support LIST-EXTENDED then we have to
979 * issue LSUB to list the subscribed folders separately */
980 flags |= CAMEL_STORE_FOLDER_INFO_SUBSCRIBED;
981 if (!fetch_folders_for_pattern (
982 istore, server, pat, flags, NULL,
983 folders, cancellable, error)) {
996 g_list_free (namespaces);
998 g_object_unref (server);
1002 g_object_unref (server);
1003 g_hash_table_destroy (folders);
1008 sync_folders (CamelIMAPXStore *istore,
1009 const gchar *pattern,
1011 GCancellable *cancellable,
1014 GHashTable *folders_from_server;
1017 folders_from_server = fetch_folders_for_namespaces (
1018 istore, pattern, sync, cancellable, error);
1019 if (folders_from_server == NULL)
1022 total = camel_store_summary_count ((CamelStoreSummary *) istore->summary);
1023 for (i = 0; i < total; i++) {
1025 const gchar *full_name;
1026 CamelFolderInfo *fi;
1028 si = camel_store_summary_index ((CamelStoreSummary *) istore->summary, i);
1032 full_name = camel_imapx_store_info_full_name (istore->summary, si);
1033 if (!full_name || !*full_name) {
1034 camel_store_summary_info_free ((CamelStoreSummary *) istore->summary, si);
1038 if (!pattern || !*pattern || imapx_match_pattern (camel_imapx_store_summary_namespace_find_full (istore->summary, full_name), pattern, full_name)) {
1039 if ((fi = g_hash_table_lookup (folders_from_server, camel_store_info_path (istore->summary, si))) != NULL) {
1040 if (((fi->flags ^ si->flags) & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED)) {
1041 si->flags = (si->flags & ~CAMEL_FOLDER_SUBSCRIBED) | (fi->flags & CAMEL_FOLDER_SUBSCRIBED);
1042 camel_store_summary_touch ((CamelStoreSummary *) istore->summary);
1044 camel_store_folder_created (CAMEL_STORE (istore), fi);
1045 camel_subscribable_folder_subscribed (CAMEL_SUBSCRIBABLE (istore), fi);
1048 gchar *dup_folder_name = g_strdup (camel_store_info_path (istore->summary, si));
1050 if (dup_folder_name) {
1051 imapx_unmark_folder_subscribed (istore,dup_folder_name, TRUE);
1052 imapx_delete_folder_from_cache (istore, dup_folder_name);
1053 g_free (dup_folder_name);
1055 camel_store_summary_remove ((CamelStoreSummary *) istore->summary, si);
1062 camel_store_summary_info_free ((CamelStoreSummary *) istore->summary, si);
1065 g_hash_table_foreach (folders_from_server, imapx_get_folders_free, NULL);
1066 g_hash_table_destroy (folders_from_server);
1072 imapx_refresh_finfo (CamelSession *session,
1073 GCancellable *cancellable,
1074 CamelIMAPXStore *store,
1077 CamelService *service;
1078 const gchar *display_name;
1080 service = CAMEL_SERVICE (store);
1081 display_name = camel_service_get_display_name (service);
1083 camel_operation_push_message (
1084 cancellable, _("Retrieving folder list for %s"),
1087 if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store)))
1090 if (!camel_service_connect_sync (CAMEL_SERVICE (store), error))
1093 /* look in all namespaces */
1094 sync_folders (store, "", FALSE, cancellable, error);
1096 camel_store_summary_save (CAMEL_STORE_SUMMARY (store->summary));
1099 camel_operation_pop_message (cancellable);
1103 discover_inbox (CamelStore *store,
1104 GCancellable *cancellable)
1107 CamelIMAPXStore *istore = (CamelIMAPXStore *) store;
1109 si = camel_store_summary_path((CamelStoreSummary *) istore->summary, "INBOX");
1110 if (si == NULL || (si->flags & CAMEL_FOLDER_SUBSCRIBED) == 0) {
1111 if (imapx_subscribe_folder (store, "INBOX", FALSE, cancellable, NULL) && !si)
1112 sync_folders (istore, "INBOX", TRUE, cancellable, NULL);
1115 camel_store_summary_info_free ((CamelStoreSummary *) istore->summary, si);
1120 imapx_can_refresh_folder (CamelStore *store,
1121 CamelFolderInfo *info,
1124 CamelService *service;
1125 CamelSettings *settings;
1126 CamelStoreClass *store_class;
1128 gboolean check_subscribed;
1129 gboolean subscribed;
1131 GError *local_error = NULL;
1133 store_class = CAMEL_STORE_CLASS (camel_imapx_store_parent_class);
1135 service = CAMEL_SERVICE (store);
1136 settings = camel_service_get_settings (service);
1138 check_all = camel_imapx_settings_get_check_all (
1139 CAMEL_IMAPX_SETTINGS (settings));
1141 check_subscribed = camel_imapx_settings_get_check_subscribed (
1142 CAMEL_IMAPX_SETTINGS (settings));
1144 subscribed = ((info->flags & CAMEL_FOLDER_SUBSCRIBED) != 0);
1146 res = store_class->can_refresh_folder (store, info, &local_error) ||
1147 check_all || (check_subscribed && subscribed);
1149 if (!res && local_error == NULL && CAMEL_IS_IMAPX_STORE (store)) {
1151 CamelStoreSummary *sm = CAMEL_STORE_SUMMARY (((CamelIMAPXStore *)(store))->summary);
1156 si = camel_store_summary_path (sm, info->full_name);
1158 res = (si->flags & CAMEL_STORE_INFO_FOLDER_CHECK_FOR_NEW) != 0 ? TRUE : FALSE;
1160 camel_store_summary_info_free (sm, si);
1164 if (local_error != NULL)
1165 g_propagate_error (error, local_error);
1170 static CamelFolder *
1171 imapx_store_get_folder_sync (CamelStore *store,
1172 const gchar *folder_name,
1173 CamelStoreGetFolderFlags flags,
1174 GCancellable *cancellable,
1177 CamelFolder *folder;
1179 folder = get_folder_offline (store, folder_name, flags, NULL);
1180 if (folder == NULL) {
1182 error, CAMEL_STORE_ERROR,
1183 CAMEL_STORE_ERROR_NO_FOLDER,
1184 _("No such folder: %s"), folder_name);
1191 static CamelFolderInfo *
1192 imapx_store_get_folder_info_sync (CamelStore *store,
1194 CamelStoreGetFolderInfoFlags flags,
1195 GCancellable *cancellable,
1198 CamelIMAPXStore *istore = (CamelIMAPXStore *) store;
1199 CamelFolderInfo * fi= NULL;
1200 CamelService *service;
1201 CamelSession *session;
1202 CamelSettings *settings;
1203 gboolean initial_setup = FALSE;
1204 gboolean use_subscriptions;
1207 service = CAMEL_SERVICE (store);
1208 session = camel_service_get_session (service);
1209 settings = camel_service_get_settings (service);
1211 use_subscriptions = camel_imapx_settings_get_use_subscriptions (
1212 CAMEL_IMAPX_SETTINGS (settings));
1217 g_mutex_lock (istore->get_finfo_lock);
1219 if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store))) {
1220 fi = get_folder_info_offline (store, top, flags, error);
1222 g_mutex_unlock (istore->get_finfo_lock);
1226 if (camel_store_summary_count ((CamelStoreSummary *) istore->summary) == 0)
1227 initial_setup = TRUE;
1229 if (!initial_setup && flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED) {
1230 time_t now = time (NULL);
1232 if (now - istore->last_refresh_time > FINFO_REFRESH_INTERVAL) {
1233 istore->last_refresh_time = time (NULL);
1235 camel_session_submit_job (
1236 session, (CamelSessionCallback)
1237 imapx_refresh_finfo,
1238 g_object_ref (store),
1239 (GDestroyNotify) g_object_unref);
1242 fi = get_folder_info_offline (store, top, flags, error);
1243 g_mutex_unlock (istore->get_finfo_lock);
1247 if (!camel_service_connect_sync ((CamelService *) store, error)) {
1248 g_mutex_unlock (istore->get_finfo_lock);
1252 if (*top && flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIPTION_LIST) {
1253 fi = get_folder_info_offline (store, top, flags, error);
1254 g_mutex_unlock (istore->get_finfo_lock);
1262 name = camel_imapx_store_summary_full_from_path (istore->summary, top);
1264 name = camel_imapx_store_summary_path_to_full (istore->summary, top, istore->dir_sep);
1267 pattern = g_alloca (i + 5);
1268 strcpy (pattern, name);
1271 pattern = g_alloca (1);
1275 if (!sync_folders (istore, pattern, TRUE, cancellable, error)) {
1276 g_mutex_unlock (istore->get_finfo_lock);
1280 camel_store_summary_save ((CamelStoreSummary *) istore->summary);
1282 /* ensure the INBOX is subscribed if lsub was preferred*/
1283 if (initial_setup && use_subscriptions)
1284 discover_inbox (store, cancellable);
1286 fi = get_folder_info_offline (store, top, flags, error);
1287 g_mutex_unlock (istore->get_finfo_lock);
1291 static CamelFolder *
1292 imapx_store_get_junk_folder_sync (CamelStore *store,
1293 GCancellable *cancellable,
1296 CamelFolder *folder;
1297 CamelStoreClass *store_class;
1299 store_class = CAMEL_STORE_CLASS (camel_imapx_store_parent_class);
1300 folder = store_class->get_junk_folder_sync (store, cancellable, error);
1303 CamelObject *object = CAMEL_OBJECT (folder);
1304 CamelService *service;
1305 const gchar *user_cache_dir;
1308 service = CAMEL_SERVICE (store);
1309 user_cache_dir = camel_service_get_user_cache_dir (service);
1311 state = g_build_filename (
1312 user_cache_dir, "system", "Junk.cmeta", NULL);
1314 camel_object_set_state_filename (object, state);
1317 camel_object_state_read (object);
1323 static CamelFolder *
1324 imapx_store_get_trash_folder_sync (CamelStore *store,
1325 GCancellable *cancellable,
1328 CamelFolder *folder;
1329 CamelStoreClass *store_class;
1331 store_class = CAMEL_STORE_CLASS (camel_imapx_store_parent_class);
1332 folder = store_class->get_trash_folder_sync (store, cancellable, error);
1335 CamelObject *object = CAMEL_OBJECT (folder);
1336 CamelService *service;
1337 const gchar *user_cache_dir;
1340 service = CAMEL_SERVICE (store);
1341 user_cache_dir = camel_service_get_user_cache_dir (service);
1343 state = g_build_filename (
1344 user_cache_dir, "system", "Trash.cmeta", NULL);
1346 camel_object_set_state_filename (object, state);
1349 camel_object_state_read (object);
1355 static CamelFolderInfo *
1356 imapx_store_create_folder_sync (CamelStore *store,
1357 const gchar *parent_name,
1358 const gchar *folder_name,
1359 GCancellable *cancellable,
1363 CamelIMAPXStoreNamespace *ns;
1364 CamelIMAPXStore *istore = (CamelIMAPXStore *) store;
1365 CamelIMAPXServer *server;
1366 gchar *real_name, *full_name, *parent_real;
1367 CamelFolderInfo *fi = NULL;
1371 if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store))) {
1373 error, CAMEL_SERVICE_ERROR,
1374 CAMEL_SERVICE_ERROR_UNAVAILABLE,
1375 _("You must be working online to complete this operation"));
1379 server = camel_imapx_store_get_server (istore, NULL, cancellable, error);
1386 ns = camel_imapx_store_summary_namespace_find_path (istore->summary, parent_name);
1392 if (strchr (folder_name, dir_sep)) {
1394 error, CAMEL_FOLDER_ERROR,
1395 CAMEL_FOLDER_ERROR_INVALID_PATH,
1396 _("The folder name \"%s\" is invalid because it contains the character \"%c\""),
1397 folder_name, dir_sep);
1398 g_object_unref (server);
1402 parent_real = camel_imapx_store_summary_full_from_path (istore->summary, parent_name);
1403 if (parent_real == NULL) {
1405 error, CAMEL_FOLDER_ERROR,
1406 CAMEL_FOLDER_ERROR_INVALID_STATE,
1407 _("Unknown parent folder: %s"), parent_name);
1408 g_object_unref (server);
1412 si = camel_store_summary_path ((CamelStoreSummary *) istore->summary, parent_name);
1413 if (si && si->flags & CAMEL_STORE_INFO_FOLDER_NOINFERIORS) {
1415 error, CAMEL_FOLDER_ERROR,
1416 CAMEL_FOLDER_ERROR_INVALID_STATE,
1417 _("The parent folder is not allowed to contain subfolders"));
1418 g_object_unref (server);
1423 camel_store_summary_info_free ((CamelStoreSummary *) istore->summary, si);
1425 real_name = camel_imapx_store_summary_path_to_full (istore->summary, folder_name, dir_sep);
1426 full_name = imapx_concat (istore, parent_real, real_name);
1429 success = camel_imapx_server_create_folder (
1430 server, full_name, cancellable, error);
1431 g_object_unref (server);
1434 CamelIMAPXStoreInfo *si;
1436 si = camel_imapx_store_summary_add_from_full (istore->summary, full_name, dir_sep);
1437 camel_store_summary_save ((CamelStoreSummary *) istore->summary);
1438 fi = imapx_build_folder_info (istore, camel_store_info_path (istore->summary, si));
1439 fi->flags |= CAMEL_FOLDER_NOCHILDREN;
1440 camel_store_folder_created (store, fi);
1444 g_free (parent_real);
1450 imapx_store_delete_folder_sync (CamelStore *store,
1451 const gchar *folder_name,
1452 GCancellable *cancellable,
1455 CamelIMAPXStore *istore = (CamelIMAPXStore *) store;
1456 CamelIMAPXServer *server;
1459 if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store))) {
1461 error, CAMEL_SERVICE_ERROR,
1462 CAMEL_SERVICE_ERROR_UNAVAILABLE,
1463 _("You must be working online to complete this operation"));
1466 /* Use INBOX connection as the implementation would try to select inbox to ensure
1467 * we are not selected on the folder being deleted */
1468 server = camel_imapx_store_get_server (istore, "INBOX", cancellable, error);
1472 success = camel_imapx_server_delete_folder (
1473 server, folder_name, cancellable, error);
1474 g_object_unref (server);
1477 imapx_delete_folder_from_cache (istore, folder_name);
1483 imapx_store_rename_folder_sync (CamelStore *store,
1486 GCancellable *cancellable,
1489 CamelIMAPXStore *istore = (CamelIMAPXStore *) store;
1490 CamelIMAPXServer *server;
1491 CamelService *service;
1492 CamelSettings *settings;
1493 const gchar *user_cache_dir;
1494 gchar *oldpath, *newpath, *storage_path;
1495 gboolean use_subscriptions;
1496 gboolean success = FALSE;
1498 service = CAMEL_SERVICE (store);
1499 settings = camel_service_get_settings (service);
1500 user_cache_dir = camel_service_get_user_cache_dir (service);
1502 use_subscriptions = camel_imapx_settings_get_use_subscriptions (
1503 CAMEL_IMAPX_SETTINGS (settings));
1505 if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store))) {
1507 error, CAMEL_SERVICE_ERROR,
1508 CAMEL_SERVICE_ERROR_UNAVAILABLE,
1509 _("You must be working online to complete this operation"));
1513 if (use_subscriptions)
1514 imapx_unsubscribe_folder (store, old, FALSE, cancellable, NULL);
1516 /* Use INBOX connection as the implementation would try to select inbox to ensure
1517 * we are not selected on the folder being renamed */
1518 server = camel_imapx_store_get_server(istore, "INBOX", cancellable, error);
1520 success = camel_imapx_server_rename_folder (
1521 server, old, new, cancellable, error);
1522 g_object_unref (server);
1526 imapx_subscribe_folder (store, old, FALSE, cancellable, NULL);
1530 /* rename summary, and handle broken server */
1531 rename_folder_info (istore, old, new);
1533 if (use_subscriptions)
1534 success = imapx_subscribe_folder (
1535 store, new, FALSE, cancellable, error);
1537 storage_path = g_build_filename (user_cache_dir, "folders", NULL);
1538 oldpath = imapx_path_to_physical (storage_path, old);
1539 newpath = imapx_path_to_physical (storage_path, new);
1540 g_free (storage_path);
1542 /* So do we care if this didn't work? Its just a cache? */
1543 if (g_rename (oldpath, newpath) == -1) {
1544 g_warning ("Could not rename message cache '%s' to '%s': %s: cache reset",
1545 oldpath, newpath, g_strerror (errno));
1555 imapx_store_noop_sync (CamelStore *store,
1556 GCancellable *cancellable,
1559 CamelIMAPXStore *istore = (CamelIMAPXStore *) store;
1560 GList *servers = NULL, *l;
1561 gboolean success = FALSE;
1563 if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store)))
1566 servers = camel_imapx_conn_manager_get_connections (istore->con_man);
1568 for (l = servers; l != NULL; l = g_list_next (l)) {
1569 CamelIMAPXServer *server = CAMEL_IMAPX_SERVER (l->data);
1571 /* we just return last noops value, technically not correct though */
1572 success = camel_imapx_server_noop (server, NULL, cancellable, error);
1573 g_object_unref (server);
1576 g_list_free (servers);
1582 imapx_migrate_to_user_cache_dir (CamelService *service)
1584 const gchar *user_data_dir, *user_cache_dir;
1586 g_return_if_fail (service != NULL);
1587 g_return_if_fail (CAMEL_IS_SERVICE (service));
1589 user_data_dir = camel_service_get_user_data_dir (service);
1590 user_cache_dir = camel_service_get_user_cache_dir (service);
1592 g_return_if_fail (user_data_dir != NULL);
1593 g_return_if_fail (user_cache_dir != NULL);
1595 /* migrate only if the source directory exists and the destination doesn't */
1596 if (g_file_test (user_data_dir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR) &&
1597 !g_file_test (user_cache_dir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) {
1600 parent_dir = g_path_get_dirname (user_cache_dir);
1601 g_mkdir_with_parents (parent_dir, S_IRWXU);
1602 g_free (parent_dir);
1604 if (g_rename (user_data_dir, user_cache_dir) == -1)
1605 g_debug ("%s: Failed to migrate '%s' to '%s': %s", G_STRFUNC, user_data_dir, user_cache_dir, g_strerror (errno));
1610 imapx_store_initable_init (GInitable *initable,
1611 GCancellable *cancellable,
1614 CamelIMAPXStore *imapx_store;
1616 CamelService *service;
1617 const gchar *user_cache_dir;
1620 imapx_store = CAMEL_IMAPX_STORE (initable);
1621 store = CAMEL_STORE (initable);
1622 service = CAMEL_SERVICE (initable);
1624 store->flags |= CAMEL_STORE_USE_CACHE_DIR;
1625 imapx_migrate_to_user_cache_dir (service);
1627 /* Chain up to parent interface's init() method. */
1628 if (!parent_initable_interface->init (initable, cancellable, error))
1631 service = CAMEL_SERVICE (initable);
1632 user_cache_dir = camel_service_get_user_cache_dir (service);
1634 imapx_store->summary = camel_imapx_store_summary_new ();
1636 summary = g_build_filename (user_cache_dir, ".ev-store-summary", NULL);
1637 camel_store_summary_set_filename ((CamelStoreSummary *) imapx_store->summary, summary);
1638 camel_store_summary_load ((CamelStoreSummary *) imapx_store->summary);
1645 static const gchar *
1646 imapx_store_get_service_name (CamelNetworkService *service,
1647 CamelNetworkSecurityMethod method)
1649 const gchar *service_name;
1652 case CAMEL_NETWORK_SECURITY_METHOD_SSL_ON_ALTERNATE_PORT:
1653 service_name = "imaps";
1657 service_name = "imap";
1661 return service_name;
1665 imapx_store_get_default_port (CamelNetworkService *service,
1666 CamelNetworkSecurityMethod method)
1668 guint16 default_port;
1671 case CAMEL_NETWORK_SECURITY_METHOD_SSL_ON_ALTERNATE_PORT:
1672 default_port = IMAPS_PORT;
1676 default_port = IMAP_PORT;
1680 return default_port;
1684 imapx_store_folder_is_subscribed (CamelSubscribable *subscribable,
1685 const gchar *folder_name)
1687 CamelIMAPXStore *istore = CAMEL_IMAPX_STORE (subscribable);
1689 gint is_subscribed = FALSE;
1691 si = camel_store_summary_path ((CamelStoreSummary *) istore->summary, folder_name);
1693 is_subscribed = (si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED) != 0;
1694 camel_store_summary_info_free ((CamelStoreSummary *) istore->summary, si);
1697 return is_subscribed;
1701 imapx_store_subscribe_folder_sync (CamelSubscribable *subscribable,
1702 const gchar *folder_name,
1703 GCancellable *cancellable,
1706 return imapx_subscribe_folder (
1707 CAMEL_STORE (subscribable),
1708 folder_name, TRUE, cancellable, error);
1712 imapx_store_unsubscribe_folder_sync (CamelSubscribable *subscribable,
1713 const gchar *folder_name,
1714 GCancellable *cancellable,
1717 return imapx_unsubscribe_folder (
1718 CAMEL_STORE (subscribable),
1719 folder_name, TRUE, cancellable, error);
1723 camel_imapx_store_class_init (CamelIMAPXStoreClass *class)
1725 GObjectClass *object_class;
1726 CamelServiceClass *service_class;
1727 CamelStoreClass *store_class;
1729 object_class = G_OBJECT_CLASS (class);
1730 object_class->dispose = imapx_store_dispose;
1731 object_class->finalize = imapx_store_finalize;
1733 service_class = CAMEL_SERVICE_CLASS (class);
1734 service_class->settings_type = CAMEL_TYPE_IMAPX_SETTINGS;
1735 service_class->get_name = imapx_get_name;
1736 service_class->connect_sync = imapx_connect_sync;
1737 service_class->disconnect_sync = imapx_disconnect_sync;
1738 service_class->authenticate_sync = imapx_authenticate_sync;
1739 service_class->query_auth_types_sync = imapx_query_auth_types_sync;
1741 store_class = CAMEL_STORE_CLASS (class);
1742 store_class->hash_folder_name = imapx_name_hash;
1743 store_class->compare_folder_name = imapx_name_equal;
1744 store_class->can_refresh_folder = imapx_can_refresh_folder;
1745 store_class->free_folder_info = camel_store_free_folder_info_full;
1746 store_class->get_folder_sync = imapx_store_get_folder_sync;
1747 store_class->get_folder_info_sync = imapx_store_get_folder_info_sync;
1748 store_class->get_junk_folder_sync = imapx_store_get_junk_folder_sync;
1749 store_class->get_trash_folder_sync = imapx_store_get_trash_folder_sync;
1750 store_class->create_folder_sync = imapx_store_create_folder_sync;
1751 store_class->delete_folder_sync = imapx_store_delete_folder_sync;
1752 store_class->rename_folder_sync = imapx_store_rename_folder_sync;
1753 store_class->noop_sync = imapx_store_noop_sync;
1757 camel_imapx_store_initable_init (GInitableIface *interface)
1759 parent_initable_interface = g_type_interface_peek_parent (interface);
1761 interface->init = imapx_store_initable_init;
1765 camel_network_service_init (CamelNetworkServiceInterface *interface)
1767 interface->get_service_name = imapx_store_get_service_name;
1768 interface->get_default_port = imapx_store_get_default_port;
1772 camel_subscribable_init (CamelSubscribableInterface *interface)
1774 interface->folder_is_subscribed = imapx_store_folder_is_subscribed;
1775 interface->subscribe_folder_sync = imapx_store_subscribe_folder_sync;
1776 interface->unsubscribe_folder_sync = imapx_store_unsubscribe_folder_sync;
1780 camel_imapx_store_init (CamelIMAPXStore *istore)
1782 istore->get_finfo_lock = g_mutex_new ();
1783 istore->last_refresh_time = time (NULL) - (FINFO_REFRESH_INTERVAL + 10);
1784 istore->dir_sep = '/';
1785 istore->con_man = camel_imapx_conn_manager_new (CAMEL_STORE (istore));