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 extern CamelServiceAuthType camel_imapx_password_authtype;
262 imapx_query_auth_types_sync (CamelService *service,
263 GCancellable *cancellable,
266 CamelIMAPXStore *istore = CAMEL_IMAPX_STORE (service);
267 CamelServiceAuthType *authtype;
268 GList *sasl_types, *t, *next;
270 CamelIMAPXServer *server;
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 camel_service_lock (service, CAMEL_SERVICE_REC_CONNECT_LOCK);
282 server = camel_imapx_server_new (CAMEL_STORE (istore));
284 connected = server->stream != NULL;
286 connected = imapx_connect_to_server (server, cancellable, error);
287 camel_service_unlock (service, CAMEL_SERVICE_REC_CONNECT_LOCK);
291 sasl_types = camel_sasl_authtype_list (FALSE);
292 for (t = sasl_types; t; t = next) {
296 if (!g_hash_table_lookup (server->cinfo->auth_types, authtype->authproto)) {
297 sasl_types = g_list_remove_link (sasl_types, t);
302 g_object_unref (server);
304 return g_list_prepend (sasl_types, &camel_imapx_password_authtype);
308 get_folder_offline (CamelStore *store,
309 const gchar *folder_name,
313 CamelIMAPXStore *imapx_store = CAMEL_IMAPX_STORE (store);
314 CamelFolder *new_folder = NULL;
316 CamelService *service;
317 const gchar *user_cache_dir;
319 service = CAMEL_SERVICE (store);
320 user_cache_dir = camel_service_get_user_cache_dir (service);
322 si = camel_store_summary_path ((CamelStoreSummary *) imapx_store->summary, folder_name);
324 gchar *folder_dir, *storage_path;
326 /* Note: Although the INBOX is defined to be case-insensitive in the IMAP RFC
327 * it is still up to the server how to acutally name it in a LIST response. Since
328 * we stored the name as the server provided it us in the summary we take that name
329 * to look up the folder.
330 * But for the on-disk cache we do always capitalize the Inbox no matter what the
333 if (!g_ascii_strcasecmp (folder_name, "INBOX"))
334 folder_name = "INBOX";
336 storage_path = g_build_filename (user_cache_dir, "folders", NULL);
337 folder_dir = imapx_path_to_physical (storage_path, folder_name);
338 g_free (storage_path);
340 new_folder = camel_imapx_folder_new (store, folder_dir, folder_name, error);
343 camel_store_summary_info_free ((CamelStoreSummary *) imapx_store->summary, si);
346 error, CAMEL_STORE_ERROR,
347 CAMEL_STORE_ERROR_NO_FOLDER,
348 _("No such folder %s"), folder_name);
354 /* folder_name is path name */
355 static CamelFolderInfo *
356 imapx_build_folder_info (CamelIMAPXStore *imapx_store,
357 const gchar *folder_name)
362 fi = camel_folder_info_new ();
363 fi->full_name = g_strdup (folder_name);
367 name = strrchr (fi->full_name, '/');
369 name = fi->full_name;
372 if (!g_ascii_strcasecmp (fi->full_name, "INBOX"))
373 fi->display_name = g_strdup (_("Inbox"));
374 /* Do not localize the rest, these are from a server, thus shouldn't be localized */
375 /*else if (!g_ascii_strcasecmp (fi->full_name, "Drafts"))
376 fi->display_name = g_strdup (_("Drafts"));
377 else if (!g_ascii_strcasecmp (fi->full_name, "Sent"))
378 fi->display_name = g_strdup (_("Sent"));
379 else if (!g_ascii_strcasecmp (fi->full_name, "Templates"))
380 fi->display_name = g_strdup (_("Templates"));
381 else if (!g_ascii_strcasecmp (fi->full_name, "Trash"))
382 fi->display_name = g_strdup (_("Trash"));*/
384 fi->display_name = g_strdup (name);
390 fill_fi (CamelStore *store,
395 CamelService *service = (CamelService *) store;
396 CamelSettings *settings;
397 gboolean mobile_mode;
399 settings = camel_service_get_settings (service);
400 mobile_mode = camel_imapx_settings_get_mobile_mode (
401 CAMEL_IMAPX_SETTINGS (settings));
403 folder = camel_object_bag_peek (store->folders, fi->full_name);
405 CamelIMAPXSummary *ims;
408 ims = (CamelIMAPXSummary *) folder->summary;
410 ims = (CamelIMAPXSummary *) camel_imapx_summary_new (folder);
412 /* Mobile clients would still love to see the total unread of actual mails
413 * than what they just have downloaded. So we override that information by giving
414 * what the server has instead of what we have downloaded. */
416 fi->unread = ((CamelIMAPXFolder *) folder)->unread_on_server;
418 fi->unread = camel_folder_summary_get_unread_count ((CamelFolderSummary *) ims);
419 fi->total = camel_folder_summary_get_saved_count ((CamelFolderSummary *) ims);
421 if (!folder->summary)
422 g_object_unref (ims);
423 g_object_unref (folder);
427 /* imap needs to treat inbox case insensitive */
428 /* we'll assume the names are normalized already */
430 folder_hash (gconstpointer ap)
434 if (g_ascii_strcasecmp(a, "INBOX") == 0)
437 return g_str_hash (a);
441 folder_eq (gconstpointer ap,
447 if (g_ascii_strcasecmp(a, "INBOX") == 0)
449 if (g_ascii_strcasecmp(b, "INBOX") == 0)
452 return g_str_equal (a, b);
456 imapx_match_pattern (CamelIMAPXStoreNamespace *ns,
457 const gchar *pattern,
472 } else if (p == '%') {
478 } else if (p == '*') {
484 return n == 0 && (p == '%' || p == 0);
488 imapx_unmark_folder_subscribed (CamelIMAPXStore *istore,
489 const gchar *folder_name,
490 gboolean emit_signal)
494 si = camel_store_summary_path ((CamelStoreSummary *) istore->summary, folder_name);
496 if (si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED) {
497 si->flags &= ~CAMEL_STORE_INFO_FOLDER_SUBSCRIBED;
498 camel_store_summary_touch ((CamelStoreSummary *) istore->summary);
499 camel_store_summary_save ((CamelStoreSummary *) istore->summary);
501 camel_store_summary_info_free ((CamelStoreSummary *) istore->summary, si);
507 fi = imapx_build_folder_info (istore, folder_name);
508 camel_subscribable_folder_unsubscribed (
509 CAMEL_SUBSCRIBABLE (istore), fi);
510 camel_folder_info_free (fi);
515 imapx_mark_folder_subscribed (CamelIMAPXStore *istore,
516 const gchar *folder_name,
517 gboolean emit_signal)
521 si = camel_store_summary_path ((CamelStoreSummary *) istore->summary, folder_name);
523 if ((si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED) == 0) {
524 si->flags |= CAMEL_STORE_INFO_FOLDER_SUBSCRIBED;
525 camel_store_summary_touch ((CamelStoreSummary *) istore->summary);
526 camel_store_summary_save ((CamelStoreSummary *) istore->summary);
528 camel_store_summary_info_free ((CamelStoreSummary *) istore->summary, si);
534 fi = imapx_build_folder_info (istore, folder_name);
535 camel_subscribable_folder_subscribed (
536 CAMEL_SUBSCRIBABLE (istore), fi);
537 camel_folder_info_free (fi);
542 imapx_subscribe_folder (CamelStore *store,
543 const gchar *folder_name,
544 gboolean emit_signal,
545 GCancellable *cancellable,
548 CamelIMAPXStore *istore = (CamelIMAPXStore *) store;
549 CamelIMAPXServer *server;
552 if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store)))
555 server = camel_imapx_store_get_server (istore, NULL, cancellable, error);
559 success = camel_imapx_server_manage_subscription (
560 server, folder_name, TRUE, cancellable, error);
561 g_object_unref (server);
564 imapx_mark_folder_subscribed (istore, folder_name, emit_signal);
570 imapx_unsubscribe_folder (CamelStore *store,
571 const gchar *folder_name,
572 gboolean emit_signal,
573 GCancellable *cancellable,
576 CamelIMAPXStore *istore = (CamelIMAPXStore *) store;
577 CamelIMAPXServer *server;
580 if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store)))
583 server = camel_imapx_store_get_server (istore, NULL, cancellable, error);
587 success = camel_imapx_server_manage_subscription (
588 server, folder_name, FALSE, cancellable, error);
589 g_object_unref (server);
592 imapx_unmark_folder_subscribed (istore, folder_name, emit_signal);
598 imapx_delete_folder_from_cache (CamelIMAPXStore *istore,
599 const gchar *folder_name)
602 gchar *folder_dir, *storage_path;
604 CamelService *service;
605 const gchar *user_cache_dir;
607 service = CAMEL_SERVICE (istore);
608 user_cache_dir = camel_service_get_user_cache_dir (service);
610 storage_path = g_build_filename (user_cache_dir, "folders", NULL);
611 folder_dir = imapx_path_to_physical (storage_path, folder_name);
612 g_free (storage_path);
613 if (g_access (folder_dir, F_OK) != 0) {
618 /* Delete summary and all the data */
619 state_file = g_build_filename (folder_dir, "cmeta", NULL);
620 g_unlink (state_file);
623 camel_db_delete_folder (((CamelStore *) istore)->cdb_w, folder_name, NULL);
624 g_rmdir (folder_dir);
626 state_file = g_build_filename (folder_dir, "subfolders", NULL);
627 g_rmdir (state_file);
630 g_rmdir (folder_dir);
634 camel_store_summary_remove_path ((CamelStoreSummary *) istore->summary, folder_name);
635 camel_store_summary_save ((CamelStoreSummary *) istore->summary);
637 fi = imapx_build_folder_info (istore, folder_name);
638 camel_store_folder_deleted (CAMEL_STORE (istore), fi);
639 camel_folder_info_free (fi);
643 rename_folder_info (CamelIMAPXStore *istore,
644 const gchar *old_name,
645 const gchar *new_name)
649 gint olen = strlen (old_name);
651 gchar *npath, *nfull;
653 count = camel_store_summary_count ((CamelStoreSummary *) istore->summary);
654 for (i = 0; i < count; i++) {
655 si = camel_store_summary_index ((CamelStoreSummary *) istore->summary, i);
658 path = camel_store_info_path (istore->summary, si);
659 if (strncmp (path, old_name, olen) == 0) {
660 if (strlen (path) > olen)
661 npath = g_strdup_printf("%s/%s", new_name, path+olen+1);
663 npath = g_strdup (new_name);
664 nfull = camel_imapx_store_summary_path_to_full (istore->summary, npath, istore->dir_sep);
666 camel_store_info_set_string ((CamelStoreSummary *) istore->summary, si, CAMEL_STORE_INFO_PATH, npath);
667 camel_store_info_set_string ((CamelStoreSummary *) istore->summary, si, CAMEL_IMAPX_STORE_INFO_FULL_NAME, nfull);
669 camel_store_summary_touch ((CamelStoreSummary *) istore->summary);
673 camel_store_summary_info_free ((CamelStoreSummary *) istore->summary, si);
677 static CamelFolderInfo *
678 get_folder_info_offline (CamelStore *store,
683 CamelIMAPXStore *imapx_store = CAMEL_IMAPX_STORE (store);
684 CamelService *service;
685 CamelSettings *settings;
686 gboolean include_inbox = FALSE;
689 gchar *pattern, *name;
690 gboolean use_namespace;
691 gboolean use_subscriptions;
694 service = CAMEL_SERVICE (store);
695 settings = camel_service_get_settings (service);
697 use_namespace = camel_imapx_settings_get_use_namespace (
698 CAMEL_IMAPX_SETTINGS (settings));
700 use_subscriptions = camel_imapx_settings_get_use_subscriptions (
701 CAMEL_IMAPX_SETTINGS (settings));
703 /* FIXME: obey other flags */
705 folders = g_ptr_array_new ();
707 if (top == NULL || top[0] == '\0') {
708 include_inbox = TRUE;
712 /* get starting point */
714 gchar *namespace = NULL;
717 namespace = camel_imapx_settings_dup_namespace (
718 CAMEL_IMAPX_SETTINGS (settings));
720 if (namespace != NULL) {
721 name = g_strdup (imapx_store->summary->namespaces->personal->full_name);
722 top = imapx_store->summary->namespaces->personal->path;
728 name = camel_imapx_store_summary_full_from_path (imapx_store->summary, top);
730 name = camel_imapx_store_summary_path_to_full (imapx_store->summary, top, imapx_store->dir_sep);
733 pattern = imapx_concat(imapx_store, name, "*");
735 /* folder_info_build will insert parent nodes as necessary and mark
736 * them as noselect, which is information we actually don't have at
737 * the moment. So let it do the right thing by bailing out if it's
738 * not a folder we're explicitly interested in. */
740 for (i = 0; i < camel_store_summary_count ((CamelStoreSummary *) imapx_store->summary); i++) {
741 CamelStoreInfo *si = camel_store_summary_index ((CamelStoreSummary *) imapx_store->summary, i);
742 const gchar *full_name;
743 CamelIMAPXStoreNamespace *ns;
748 full_name = camel_imapx_store_info_full_name (imapx_store->summary, si);
749 if (!full_name || !*full_name) {
750 camel_store_summary_info_free ((CamelStoreSummary *) imapx_store->summary, si);
754 ns = camel_imapx_store_summary_namespace_find_full (imapx_store->summary, full_name);
756 /* Modify the checks to see match the namespaces from preferences */
757 if ((g_str_equal (name, full_name)
758 || imapx_match_pattern (ns, pattern, full_name)
759 || (include_inbox && !g_ascii_strcasecmp (full_name, "INBOX")))
760 && ( (!use_subscriptions
761 || (flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED) == 0)
762 || (si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED)
763 || (flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIPTION_LIST) != 0)) {
765 fi = imapx_build_folder_info (imapx_store, camel_store_info_path ((CamelStoreSummary *) imapx_store->summary, si));
766 fi->unread = si->unread;
767 fi->total = si->total;
768 fi->flags = si->flags;
769 /* HACK: some servers report noinferiors for all folders (uw-imapd)
770 * We just translate this into nochildren, and let the imap layer enforce
771 * it. See create folder */
772 if (fi->flags & CAMEL_FOLDER_NOINFERIORS)
773 fi->flags = (fi->flags & ~CAMEL_FOLDER_NOINFERIORS) | CAMEL_FOLDER_NOCHILDREN;
775 /* blah, this gets lost somewhere, i can't be bothered finding out why */
776 if (!g_ascii_strcasecmp(fi->full_name, "inbox")) {
777 fi->flags = (fi->flags & ~CAMEL_FOLDER_TYPE_MASK) | CAMEL_FOLDER_TYPE_INBOX;
778 fi->flags |= CAMEL_FOLDER_SYSTEM;
781 if (!(si->flags & CAMEL_FOLDER_NOSELECT))
782 fill_fi ((CamelStore *) imapx_store, fi, 0);
785 fi->flags |= CAMEL_FOLDER_NOCHILDREN;
786 g_ptr_array_add (folders, fi);
788 camel_store_summary_info_free ((CamelStoreSummary *) imapx_store->summary, si);
792 fi = camel_folder_info_build (folders, top, '/', TRUE);
793 g_ptr_array_free (folders, TRUE);
800 add_folders_to_summary (CamelIMAPXStore *istore,
801 CamelIMAPXServer *server,
808 for (i = 0; i < folders->len; i++) {
809 struct _list_info *li = folders->pdata[i];
810 CamelIMAPXStoreInfo *si;
812 CamelFolderInfo *fi, *sfi;
816 path = camel_imapx_store_summary_path_to_full (istore->summary, li->name, li->separator);
817 sfi = g_hash_table_lookup (table, path);
819 sfi->flags |= CAMEL_STORE_INFO_FOLDER_SUBSCRIBED;
825 si = camel_imapx_store_summary_add_from_full (istore->summary, li->name, li->separator);
829 new_flags = (si->info.flags & (CAMEL_STORE_INFO_FOLDER_SUBSCRIBED | CAMEL_STORE_INFO_FOLDER_CHECK_FOR_NEW)) |
830 (li->flags & ~CAMEL_STORE_INFO_FOLDER_SUBSCRIBED);
832 if (!(server->cinfo->capa & IMAPX_CAPABILITY_NAMESPACE))
833 istore->dir_sep = li->separator;
835 if (si->info.flags != new_flags) {
836 si->info.flags = new_flags;
837 camel_store_summary_touch ((CamelStoreSummary *) istore->summary);
840 fi = camel_folder_info_new ();
841 fi->full_name = g_strdup (camel_store_info_path (istore->summary, si));
842 if (!g_ascii_strcasecmp(fi->full_name, "inbox")) {
843 li->flags |= CAMEL_FOLDER_SYSTEM | CAMEL_FOLDER_TYPE_INBOX;
844 fi->display_name = g_strdup (_("Inbox"));
846 fi->display_name = g_strdup (camel_store_info_name (istore->summary, si));
848 /* HACK: some servers report noinferiors for all folders (uw-imapd)
849 * We just translate this into nochildren, and let the imap layer enforce
850 * it. See create folder */
851 if (li->flags & CAMEL_FOLDER_NOINFERIORS)
852 li->flags = (li->flags & ~CAMEL_FOLDER_NOINFERIORS) | CAMEL_FOLDER_NOCHILDREN;
853 fi->flags = li->flags;
858 g_hash_table_insert (table, fi->full_name, fi);
863 free_list (gpointer data,
866 struct _list_info *li = data;
867 imapx_free_list (li);
871 imapx_get_folders_free (gpointer k,
875 camel_folder_info_free (v);
879 fetch_folders_for_pattern (CamelIMAPXStore *istore,
880 CamelIMAPXServer *server,
881 const gchar *pattern,
885 GCancellable *cancellable,
890 folders = camel_imapx_server_list (
891 server, pattern, flags, ext, cancellable, error);
895 add_folders_to_summary (istore, server, folders, table, (flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED));
897 g_ptr_array_foreach (folders, free_list, folders);
898 g_ptr_array_free (folders, TRUE);
904 get_namespaces (CamelIMAPXStore *istore)
906 GList *namespaces = NULL;
907 CamelIMAPXNamespaceList *nsl = NULL;
909 /* Add code to return the namespaces from preference else all of them */
910 nsl = istore->summary->namespaces;
912 namespaces = g_list_append (namespaces, nsl->personal);
914 namespaces = g_list_append (namespaces, nsl->other);
916 namespaces = g_list_append (namespaces, nsl->shared);
922 fetch_folders_for_namespaces (CamelIMAPXStore *istore,
923 const gchar *pattern,
925 GCancellable *cancellable,
928 CamelIMAPXServer *server;
929 GHashTable *folders = NULL;
930 GList *namespaces = NULL, *l;
932 server = camel_imapx_store_get_server (istore, NULL, cancellable, error);
936 folders = g_hash_table_new (folder_hash, folder_eq);
937 namespaces = get_namespaces (istore);
939 for (l = namespaces; l != NULL; l = g_list_next (l))
941 CamelIMAPXStoreNamespace *ns = l->data;
946 const gchar *list_ext = NULL;
952 pat = g_strdup_printf ("%s%c", ns->path, ns->sep);
954 pat = g_strdup (pattern);
957 flags |= CAMEL_STORE_FOLDER_INFO_SUBSCRIPTION_LIST;
959 if (server->cinfo->capa & IMAPX_CAPABILITY_LIST_EXTENDED)
960 list_ext = "RETURN (SUBSCRIBED)";
962 flags |= CAMEL_STORE_FOLDER_INFO_RECURSIVE;
963 if (!fetch_folders_for_pattern (
964 istore, server, pat, flags, list_ext,
965 folders, cancellable, error)) {
970 /* If the server doesn't support LIST-EXTENDED then we have to
971 * issue LSUB to list the subscribed folders separately */
972 flags |= CAMEL_STORE_FOLDER_INFO_SUBSCRIBED;
973 if (!fetch_folders_for_pattern (
974 istore, server, pat, flags, NULL,
975 folders, cancellable, error)) {
988 g_list_free (namespaces);
990 g_object_unref (server);
994 g_object_unref (server);
995 g_hash_table_destroy (folders);
1000 sync_folders (CamelIMAPXStore *istore,
1001 const gchar *pattern,
1003 GCancellable *cancellable,
1006 GHashTable *folders_from_server;
1009 folders_from_server = fetch_folders_for_namespaces (
1010 istore, pattern, sync, cancellable, error);
1011 if (folders_from_server == NULL)
1014 total = camel_store_summary_count ((CamelStoreSummary *) istore->summary);
1015 for (i = 0; i < total; i++) {
1017 const gchar *full_name;
1018 CamelFolderInfo *fi;
1020 si = camel_store_summary_index ((CamelStoreSummary *) istore->summary, i);
1024 full_name = camel_imapx_store_info_full_name (istore->summary, si);
1025 if (!full_name || !*full_name) {
1026 camel_store_summary_info_free ((CamelStoreSummary *) istore->summary, si);
1030 if (!pattern || !*pattern || imapx_match_pattern (camel_imapx_store_summary_namespace_find_full (istore->summary, full_name), pattern, full_name)) {
1031 if ((fi = g_hash_table_lookup (folders_from_server, camel_store_info_path (istore->summary, si))) != NULL) {
1032 if (((fi->flags ^ si->flags) & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED)) {
1033 si->flags = (si->flags & ~CAMEL_FOLDER_SUBSCRIBED) | (fi->flags & CAMEL_FOLDER_SUBSCRIBED);
1034 camel_store_summary_touch ((CamelStoreSummary *) istore->summary);
1036 camel_store_folder_created (CAMEL_STORE (istore), fi);
1037 camel_subscribable_folder_subscribed (CAMEL_SUBSCRIBABLE (istore), fi);
1040 gchar *dup_folder_name = g_strdup (camel_store_info_path (istore->summary, si));
1042 if (dup_folder_name) {
1043 imapx_unmark_folder_subscribed (istore,dup_folder_name, TRUE);
1044 imapx_delete_folder_from_cache (istore, dup_folder_name);
1045 g_free (dup_folder_name);
1047 camel_store_summary_remove ((CamelStoreSummary *) istore->summary, si);
1054 camel_store_summary_info_free ((CamelStoreSummary *) istore->summary, si);
1057 g_hash_table_foreach (folders_from_server, imapx_get_folders_free, NULL);
1058 g_hash_table_destroy (folders_from_server);
1064 imapx_refresh_finfo (CamelSession *session,
1065 GCancellable *cancellable,
1066 CamelIMAPXStore *store,
1069 CamelService *service;
1070 const gchar *display_name;
1072 service = CAMEL_SERVICE (store);
1073 display_name = camel_service_get_display_name (service);
1075 camel_operation_push_message (
1076 cancellable, _("Retrieving folder list for %s"),
1079 if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store)))
1082 if (!camel_service_connect_sync (CAMEL_SERVICE (store), error))
1085 /* look in all namespaces */
1086 sync_folders (store, "", FALSE, cancellable, error);
1088 camel_store_summary_save (CAMEL_STORE_SUMMARY (store->summary));
1091 camel_operation_pop_message (cancellable);
1095 discover_inbox (CamelStore *store,
1096 GCancellable *cancellable)
1099 CamelIMAPXStore *istore = (CamelIMAPXStore *) store;
1101 si = camel_store_summary_path((CamelStoreSummary *) istore->summary, "INBOX");
1102 if (si == NULL || (si->flags & CAMEL_FOLDER_SUBSCRIBED) == 0) {
1103 if (imapx_subscribe_folder (store, "INBOX", FALSE, cancellable, NULL) && !si)
1104 sync_folders (istore, "INBOX", TRUE, cancellable, NULL);
1107 camel_store_summary_info_free ((CamelStoreSummary *) istore->summary, si);
1112 imapx_can_refresh_folder (CamelStore *store,
1113 CamelFolderInfo *info,
1116 CamelService *service;
1117 CamelSettings *settings;
1118 CamelStoreClass *store_class;
1120 gboolean check_subscribed;
1121 gboolean subscribed;
1123 GError *local_error = NULL;
1125 store_class = CAMEL_STORE_CLASS (camel_imapx_store_parent_class);
1127 service = CAMEL_SERVICE (store);
1128 settings = camel_service_get_settings (service);
1130 check_all = camel_imapx_settings_get_check_all (
1131 CAMEL_IMAPX_SETTINGS (settings));
1133 check_subscribed = camel_imapx_settings_get_check_subscribed (
1134 CAMEL_IMAPX_SETTINGS (settings));
1136 subscribed = ((info->flags & CAMEL_FOLDER_SUBSCRIBED) != 0);
1138 res = store_class->can_refresh_folder (store, info, &local_error) ||
1139 check_all || (check_subscribed && subscribed);
1141 if (!res && local_error == NULL && CAMEL_IS_IMAPX_STORE (store)) {
1143 CamelStoreSummary *sm = CAMEL_STORE_SUMMARY (((CamelIMAPXStore *)(store))->summary);
1148 si = camel_store_summary_path (sm, info->full_name);
1150 res = (si->flags & CAMEL_STORE_INFO_FOLDER_CHECK_FOR_NEW) != 0 ? TRUE : FALSE;
1152 camel_store_summary_info_free (sm, si);
1156 if (local_error != NULL)
1157 g_propagate_error (error, local_error);
1162 static CamelFolder *
1163 imapx_store_get_folder_sync (CamelStore *store,
1164 const gchar *folder_name,
1165 CamelStoreGetFolderFlags flags,
1166 GCancellable *cancellable,
1169 CamelFolder *folder;
1171 folder = get_folder_offline (store, folder_name, flags, NULL);
1172 if (folder == NULL) {
1174 error, CAMEL_STORE_ERROR,
1175 CAMEL_STORE_ERROR_NO_FOLDER,
1176 _("No such folder: %s"), folder_name);
1183 static CamelFolderInfo *
1184 imapx_store_get_folder_info_sync (CamelStore *store,
1186 CamelStoreGetFolderInfoFlags flags,
1187 GCancellable *cancellable,
1190 CamelIMAPXStore *istore = (CamelIMAPXStore *) store;
1191 CamelFolderInfo * fi= NULL;
1192 CamelService *service;
1193 CamelSession *session;
1194 CamelSettings *settings;
1195 gboolean initial_setup = FALSE;
1196 gboolean use_subscriptions;
1199 service = CAMEL_SERVICE (store);
1200 session = camel_service_get_session (service);
1201 settings = camel_service_get_settings (service);
1203 use_subscriptions = camel_imapx_settings_get_use_subscriptions (
1204 CAMEL_IMAPX_SETTINGS (settings));
1209 g_mutex_lock (istore->get_finfo_lock);
1211 if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store))) {
1212 fi = get_folder_info_offline (store, top, flags, error);
1214 g_mutex_unlock (istore->get_finfo_lock);
1218 if (camel_store_summary_count ((CamelStoreSummary *) istore->summary) == 0)
1219 initial_setup = TRUE;
1221 if (!initial_setup && flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED) {
1222 time_t now = time (NULL);
1224 if (now - istore->last_refresh_time > FINFO_REFRESH_INTERVAL) {
1225 istore->last_refresh_time = time (NULL);
1227 camel_session_submit_job (
1228 session, (CamelSessionCallback)
1229 imapx_refresh_finfo,
1230 g_object_ref (store),
1231 (GDestroyNotify) g_object_unref);
1234 fi = get_folder_info_offline (store, top, flags, error);
1235 g_mutex_unlock (istore->get_finfo_lock);
1239 if (!camel_service_connect_sync ((CamelService *) store, error)) {
1240 g_mutex_unlock (istore->get_finfo_lock);
1244 if (*top && flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIPTION_LIST) {
1245 fi = get_folder_info_offline (store, top, flags, error);
1246 g_mutex_unlock (istore->get_finfo_lock);
1254 name = camel_imapx_store_summary_full_from_path (istore->summary, top);
1256 name = camel_imapx_store_summary_path_to_full (istore->summary, top, istore->dir_sep);
1259 pattern = g_alloca (i + 5);
1260 strcpy (pattern, name);
1263 pattern = g_alloca (1);
1267 if (!sync_folders (istore, pattern, TRUE, cancellable, error)) {
1268 g_mutex_unlock (istore->get_finfo_lock);
1272 camel_store_summary_save ((CamelStoreSummary *) istore->summary);
1274 /* ensure the INBOX is subscribed if lsub was preferred*/
1275 if (initial_setup && use_subscriptions)
1276 discover_inbox (store, cancellable);
1278 fi = get_folder_info_offline (store, top, flags, error);
1279 g_mutex_unlock (istore->get_finfo_lock);
1283 static CamelFolder *
1284 imapx_store_get_junk_folder_sync (CamelStore *store,
1285 GCancellable *cancellable,
1288 CamelFolder *folder;
1289 CamelStoreClass *store_class;
1291 store_class = CAMEL_STORE_CLASS (camel_imapx_store_parent_class);
1292 folder = store_class->get_junk_folder_sync (store, cancellable, error);
1295 CamelObject *object = CAMEL_OBJECT (folder);
1296 CamelService *service;
1297 const gchar *user_cache_dir;
1300 service = CAMEL_SERVICE (store);
1301 user_cache_dir = camel_service_get_user_cache_dir (service);
1303 state = g_build_filename (
1304 user_cache_dir, "system", "Junk.cmeta", NULL);
1306 camel_object_set_state_filename (object, state);
1309 camel_object_state_read (object);
1315 static CamelFolder *
1316 imapx_store_get_trash_folder_sync (CamelStore *store,
1317 GCancellable *cancellable,
1320 CamelFolder *folder;
1321 CamelStoreClass *store_class;
1323 store_class = CAMEL_STORE_CLASS (camel_imapx_store_parent_class);
1324 folder = store_class->get_trash_folder_sync (store, cancellable, error);
1327 CamelObject *object = CAMEL_OBJECT (folder);
1328 CamelService *service;
1329 const gchar *user_cache_dir;
1332 service = CAMEL_SERVICE (store);
1333 user_cache_dir = camel_service_get_user_cache_dir (service);
1335 state = g_build_filename (
1336 user_cache_dir, "system", "Trash.cmeta", NULL);
1338 camel_object_set_state_filename (object, state);
1341 camel_object_state_read (object);
1347 static CamelFolderInfo *
1348 imapx_store_create_folder_sync (CamelStore *store,
1349 const gchar *parent_name,
1350 const gchar *folder_name,
1351 GCancellable *cancellable,
1355 CamelIMAPXStoreNamespace *ns;
1356 CamelIMAPXStore *istore = (CamelIMAPXStore *) store;
1357 CamelIMAPXServer *server;
1358 gchar *real_name, *full_name, *parent_real;
1359 CamelFolderInfo *fi = NULL;
1363 if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store))) {
1365 error, CAMEL_SERVICE_ERROR,
1366 CAMEL_SERVICE_ERROR_UNAVAILABLE,
1367 _("You must be working online to complete this operation"));
1371 server = camel_imapx_store_get_server (istore, NULL, cancellable, error);
1378 ns = camel_imapx_store_summary_namespace_find_path (istore->summary, parent_name);
1384 if (strchr (folder_name, dir_sep)) {
1386 error, CAMEL_FOLDER_ERROR,
1387 CAMEL_FOLDER_ERROR_INVALID_PATH,
1388 _("The folder name \"%s\" is invalid because it contains the character \"%c\""),
1389 folder_name, dir_sep);
1390 g_object_unref (server);
1394 parent_real = camel_imapx_store_summary_full_from_path (istore->summary, parent_name);
1395 if (parent_real == NULL) {
1397 error, CAMEL_FOLDER_ERROR,
1398 CAMEL_FOLDER_ERROR_INVALID_STATE,
1399 _("Unknown parent folder: %s"), parent_name);
1400 g_object_unref (server);
1404 si = camel_store_summary_path ((CamelStoreSummary *) istore->summary, parent_name);
1405 if (si && si->flags & CAMEL_STORE_INFO_FOLDER_NOINFERIORS) {
1407 error, CAMEL_FOLDER_ERROR,
1408 CAMEL_FOLDER_ERROR_INVALID_STATE,
1409 _("The parent folder is not allowed to contain subfolders"));
1410 g_object_unref (server);
1415 camel_store_summary_info_free ((CamelStoreSummary *) istore->summary, si);
1417 real_name = camel_imapx_store_summary_path_to_full (istore->summary, folder_name, dir_sep);
1418 full_name = imapx_concat (istore, parent_real, real_name);
1421 success = camel_imapx_server_create_folder (
1422 server, full_name, cancellable, error);
1423 g_object_unref (server);
1426 CamelIMAPXStoreInfo *si;
1428 si = camel_imapx_store_summary_add_from_full (istore->summary, full_name, dir_sep);
1429 camel_store_summary_save ((CamelStoreSummary *) istore->summary);
1430 fi = imapx_build_folder_info (istore, camel_store_info_path (istore->summary, si));
1431 fi->flags |= CAMEL_FOLDER_NOCHILDREN;
1432 camel_store_folder_created (store, fi);
1436 g_free (parent_real);
1442 imapx_store_delete_folder_sync (CamelStore *store,
1443 const gchar *folder_name,
1444 GCancellable *cancellable,
1447 CamelIMAPXStore *istore = (CamelIMAPXStore *) store;
1448 CamelIMAPXServer *server;
1451 if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store))) {
1453 error, CAMEL_SERVICE_ERROR,
1454 CAMEL_SERVICE_ERROR_UNAVAILABLE,
1455 _("You must be working online to complete this operation"));
1458 /* Use INBOX connection as the implementation would try to select inbox to ensure
1459 * we are not selected on the folder being deleted */
1460 server = camel_imapx_store_get_server (istore, "INBOX", cancellable, error);
1464 success = camel_imapx_server_delete_folder (
1465 server, folder_name, cancellable, error);
1466 g_object_unref (server);
1469 imapx_delete_folder_from_cache (istore, folder_name);
1475 imapx_store_rename_folder_sync (CamelStore *store,
1478 GCancellable *cancellable,
1481 CamelIMAPXStore *istore = (CamelIMAPXStore *) store;
1482 CamelIMAPXServer *server;
1483 CamelService *service;
1484 CamelSettings *settings;
1485 const gchar *user_cache_dir;
1486 gchar *oldpath, *newpath, *storage_path;
1487 gboolean use_subscriptions;
1488 gboolean success = FALSE;
1490 service = CAMEL_SERVICE (store);
1491 settings = camel_service_get_settings (service);
1492 user_cache_dir = camel_service_get_user_cache_dir (service);
1494 use_subscriptions = camel_imapx_settings_get_use_subscriptions (
1495 CAMEL_IMAPX_SETTINGS (settings));
1497 if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store))) {
1499 error, CAMEL_SERVICE_ERROR,
1500 CAMEL_SERVICE_ERROR_UNAVAILABLE,
1501 _("You must be working online to complete this operation"));
1505 if (use_subscriptions)
1506 imapx_unsubscribe_folder (store, old, FALSE, cancellable, NULL);
1508 /* Use INBOX connection as the implementation would try to select inbox to ensure
1509 * we are not selected on the folder being renamed */
1510 server = camel_imapx_store_get_server(istore, "INBOX", cancellable, error);
1512 success = camel_imapx_server_rename_folder (
1513 server, old, new, cancellable, error);
1514 g_object_unref (server);
1518 imapx_subscribe_folder (store, old, FALSE, cancellable, NULL);
1522 /* rename summary, and handle broken server */
1523 rename_folder_info (istore, old, new);
1525 if (use_subscriptions)
1526 success = imapx_subscribe_folder (
1527 store, new, FALSE, cancellable, error);
1529 storage_path = g_build_filename (user_cache_dir, "folders", NULL);
1530 oldpath = imapx_path_to_physical (storage_path, old);
1531 newpath = imapx_path_to_physical (storage_path, new);
1532 g_free (storage_path);
1534 /* So do we care if this didn't work? Its just a cache? */
1535 if (g_rename (oldpath, newpath) == -1) {
1536 g_warning ("Could not rename message cache '%s' to '%s': %s: cache reset",
1537 oldpath, newpath, g_strerror (errno));
1547 imapx_store_noop_sync (CamelStore *store,
1548 GCancellable *cancellable,
1551 CamelIMAPXStore *istore = (CamelIMAPXStore *) store;
1552 GList *servers = NULL, *l;
1553 gboolean success = FALSE;
1555 if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store)))
1558 servers = camel_imapx_conn_manager_get_connections (istore->con_man);
1560 for (l = servers; l != NULL; l = g_list_next (l)) {
1561 CamelIMAPXServer *server = CAMEL_IMAPX_SERVER (l->data);
1563 /* we just return last noops value, technically not correct though */
1564 success = camel_imapx_server_noop (server, NULL, cancellable, error);
1565 g_object_unref (server);
1568 g_list_free (servers);
1574 imapx_migrate_to_user_cache_dir (CamelService *service)
1576 const gchar *user_data_dir, *user_cache_dir;
1578 g_return_if_fail (service != NULL);
1579 g_return_if_fail (CAMEL_IS_SERVICE (service));
1581 user_data_dir = camel_service_get_user_data_dir (service);
1582 user_cache_dir = camel_service_get_user_cache_dir (service);
1584 g_return_if_fail (user_data_dir != NULL);
1585 g_return_if_fail (user_cache_dir != NULL);
1587 /* migrate only if the source directory exists and the destination doesn't */
1588 if (g_file_test (user_data_dir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR) &&
1589 !g_file_test (user_cache_dir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) {
1592 parent_dir = g_path_get_dirname (user_cache_dir);
1593 g_mkdir_with_parents (parent_dir, S_IRWXU);
1594 g_free (parent_dir);
1596 if (g_rename (user_data_dir, user_cache_dir) == -1)
1597 g_debug ("%s: Failed to migrate '%s' to '%s': %s", G_STRFUNC, user_data_dir, user_cache_dir, g_strerror (errno));
1602 imapx_store_initable_init (GInitable *initable,
1603 GCancellable *cancellable,
1606 CamelIMAPXStore *imapx_store;
1608 CamelService *service;
1609 const gchar *user_cache_dir;
1612 imapx_store = CAMEL_IMAPX_STORE (initable);
1613 store = CAMEL_STORE (initable);
1614 service = CAMEL_SERVICE (initable);
1616 store->flags |= CAMEL_STORE_USE_CACHE_DIR;
1617 imapx_migrate_to_user_cache_dir (service);
1619 /* Chain up to parent interface's init() method. */
1620 if (!parent_initable_interface->init (initable, cancellable, error))
1623 service = CAMEL_SERVICE (initable);
1624 user_cache_dir = camel_service_get_user_cache_dir (service);
1626 imapx_store->summary = camel_imapx_store_summary_new ();
1628 summary = g_build_filename (user_cache_dir, ".ev-store-summary", NULL);
1629 camel_store_summary_set_filename ((CamelStoreSummary *) imapx_store->summary, summary);
1630 camel_store_summary_load ((CamelStoreSummary *) imapx_store->summary);
1637 static const gchar *
1638 imapx_store_get_service_name (CamelNetworkService *service,
1639 CamelNetworkSecurityMethod method)
1641 const gchar *service_name;
1644 case CAMEL_NETWORK_SECURITY_METHOD_SSL_ON_ALTERNATE_PORT:
1645 service_name = "imaps";
1649 service_name = "imap";
1653 return service_name;
1657 imapx_store_get_default_port (CamelNetworkService *service,
1658 CamelNetworkSecurityMethod method)
1660 guint16 default_port;
1663 case CAMEL_NETWORK_SECURITY_METHOD_SSL_ON_ALTERNATE_PORT:
1664 default_port = IMAPS_PORT;
1668 default_port = IMAP_PORT;
1672 return default_port;
1676 imapx_store_folder_is_subscribed (CamelSubscribable *subscribable,
1677 const gchar *folder_name)
1679 CamelIMAPXStore *istore = CAMEL_IMAPX_STORE (subscribable);
1681 gint is_subscribed = FALSE;
1683 si = camel_store_summary_path ((CamelStoreSummary *) istore->summary, folder_name);
1685 is_subscribed = (si->flags & CAMEL_STORE_INFO_FOLDER_SUBSCRIBED) != 0;
1686 camel_store_summary_info_free ((CamelStoreSummary *) istore->summary, si);
1689 return is_subscribed;
1693 imapx_store_subscribe_folder_sync (CamelSubscribable *subscribable,
1694 const gchar *folder_name,
1695 GCancellable *cancellable,
1698 return imapx_subscribe_folder (
1699 CAMEL_STORE (subscribable),
1700 folder_name, TRUE, cancellable, error);
1704 imapx_store_unsubscribe_folder_sync (CamelSubscribable *subscribable,
1705 const gchar *folder_name,
1706 GCancellable *cancellable,
1709 return imapx_unsubscribe_folder (
1710 CAMEL_STORE (subscribable),
1711 folder_name, TRUE, cancellable, error);
1715 camel_imapx_store_class_init (CamelIMAPXStoreClass *class)
1717 GObjectClass *object_class;
1718 CamelServiceClass *service_class;
1719 CamelStoreClass *store_class;
1721 object_class = G_OBJECT_CLASS (class);
1722 object_class->dispose = imapx_store_dispose;
1723 object_class->finalize = imapx_store_finalize;
1725 service_class = CAMEL_SERVICE_CLASS (class);
1726 service_class->settings_type = CAMEL_TYPE_IMAPX_SETTINGS;
1727 service_class->get_name = imapx_get_name;
1728 service_class->connect_sync = imapx_connect_sync;
1729 service_class->disconnect_sync = imapx_disconnect_sync;
1730 service_class->authenticate_sync = imapx_authenticate_sync;
1731 service_class->query_auth_types_sync = imapx_query_auth_types_sync;
1733 store_class = CAMEL_STORE_CLASS (class);
1734 store_class->hash_folder_name = imapx_name_hash;
1735 store_class->compare_folder_name = imapx_name_equal;
1736 store_class->can_refresh_folder = imapx_can_refresh_folder;
1737 store_class->free_folder_info = camel_store_free_folder_info_full;
1738 store_class->get_folder_sync = imapx_store_get_folder_sync;
1739 store_class->get_folder_info_sync = imapx_store_get_folder_info_sync;
1740 store_class->get_junk_folder_sync = imapx_store_get_junk_folder_sync;
1741 store_class->get_trash_folder_sync = imapx_store_get_trash_folder_sync;
1742 store_class->create_folder_sync = imapx_store_create_folder_sync;
1743 store_class->delete_folder_sync = imapx_store_delete_folder_sync;
1744 store_class->rename_folder_sync = imapx_store_rename_folder_sync;
1745 store_class->noop_sync = imapx_store_noop_sync;
1749 camel_imapx_store_initable_init (GInitableIface *interface)
1751 parent_initable_interface = g_type_interface_peek_parent (interface);
1753 interface->init = imapx_store_initable_init;
1757 camel_network_service_init (CamelNetworkServiceInterface *interface)
1759 interface->get_service_name = imapx_store_get_service_name;
1760 interface->get_default_port = imapx_store_get_default_port;
1764 camel_subscribable_init (CamelSubscribableInterface *interface)
1766 interface->folder_is_subscribed = imapx_store_folder_is_subscribed;
1767 interface->subscribe_folder_sync = imapx_store_subscribe_folder_sync;
1768 interface->unsubscribe_folder_sync = imapx_store_unsubscribe_folder_sync;
1772 camel_imapx_store_init (CamelIMAPXStore *istore)
1774 istore->get_finfo_lock = g_mutex_new ();
1775 istore->last_refresh_time = time (NULL) - (FINFO_REFRESH_INTERVAL + 10);
1776 istore->dir_sep = '/';
1777 istore->con_man = camel_imapx_conn_manager_new (CAMEL_STORE (istore));