| File: | src/camel/providers/local/camel-maildir-store.c |
| Warning: | line 1308, column 14 File position of the stream might be 'indeterminate' after a failed operation. Can cause undefined behavior |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* | |||
| 2 | * SPDX-FileCopyrightText: (C) 1999-2008 Novell, Inc. (www.novell.com) | |||
| 3 | * SPDX-License-Identifier: LGPL-2.0-or-later | |||
| 4 | * SPDX-FileContributor: Michael Zucchi <notzed@ximian.com> | |||
| 5 | */ | |||
| 6 | ||||
| 7 | #include "evolution-data-server-config.h" | |||
| 8 | ||||
| 9 | #include <dirent.h> | |||
| 10 | #include <errno(*__errno_location ()).h> | |||
| 11 | #include <string.h> | |||
| 12 | #include <unistd.h> | |||
| 13 | #include <sys/stat.h> | |||
| 14 | #include <sys/types.h> | |||
| 15 | ||||
| 16 | #include <glib/gstdio.h> | |||
| 17 | #include <glib/gi18n-lib.h> | |||
| 18 | ||||
| 19 | #include "camel-maildir-folder.h" | |||
| 20 | #include "camel-maildir-store.h" | |||
| 21 | #include "camel-maildir-summary.h" | |||
| 22 | ||||
| 23 | #define d(x) | |||
| 24 | ||||
| 25 | /* after the space is a version of the folder structure */ | |||
| 26 | #define MAILDIR_CONTENT_VERSION_STR"maildir++ 1" "maildir++ 1" | |||
| 27 | #define MAILDIR_CONTENT_VERSION1 1 | |||
| 28 | ||||
| 29 | #define HIER_SEP"." "." | |||
| 30 | #define HIER_SEP_CHAR'.' '.' | |||
| 31 | ||||
| 32 | #define CHECK_MKDIR(x,d)do { gint mkdir_ret = (x); if (mkdir_ret == -1 && (*__errno_location ()) != 17) { g_debug ("%s: mkdir of '%s' failed: %s", ((const char*) (__func__)), (d), g_strerror ((*__errno_location ())) ); } } while (0) G_STMT_STARTdo { \ | |||
| 33 | gint mkdir_ret = (x); \ | |||
| 34 | if (mkdir_ret == -1 && errno(*__errno_location ()) != EEXIST17) { \ | |||
| 35 | g_debug ("%s: mkdir of '%s' failed: %s", G_STRFUNC((const char*) (__func__)), (d), g_strerror (errno(*__errno_location ()))); \ | |||
| 36 | } \ | |||
| 37 | } G_STMT_ENDwhile (0) | |||
| 38 | ||||
| 39 | struct _CamelMaildirStorePrivate { | |||
| 40 | gchar filename_flag_sep; | |||
| 41 | gboolean already_migrated; | |||
| 42 | gboolean can_escape_dots; | |||
| 43 | }; | |||
| 44 | ||||
| 45 | static CamelFolder * maildir_store_get_folder_sync (CamelStore *store, const gchar *folder_name, CamelStoreGetFolderFlags flags, | |||
| 46 | GCancellable *cancellable, GError **error); | |||
| 47 | static CamelFolderInfo *maildir_store_create_folder_sync (CamelStore *store, const gchar *parent_name, const gchar *folder_name, | |||
| 48 | GCancellable *cancellable, GError **error); | |||
| 49 | static gboolean maildir_store_delete_folder_sync (CamelStore * store, const gchar *folder_name, GCancellable *cancellable, GError **error); | |||
| 50 | ||||
| 51 | static gchar *maildir_full_name_to_dir_name (gboolean can_escape_dots, const gchar *full_name); | |||
| 52 | static gchar *maildir_dir_name_to_fullname (gboolean can_escape_dots, const gchar *dir_name); | |||
| 53 | static gchar *maildir_get_full_path (CamelLocalStore *ls, const gchar *full_name); | |||
| 54 | static gchar *maildir_get_meta_path (CamelLocalStore *ls, const gchar *full_name, const gchar *ext); | |||
| 55 | static void maildir_migrate_hierarchy (CamelMaildirStore *mstore, gint maildir_version, GCancellable *cancellable, GError **error); | |||
| 56 | static gboolean maildir_version_requires_migrate (const gchar *meta_filename, gboolean *file_exists, gint *maildir_version); | |||
| 57 | ||||
| 58 | G_DEFINE_TYPE_WITH_PRIVATE (CamelMaildirStore, camel_maildir_store, CAMEL_TYPE_LOCAL_STORE)static void camel_maildir_store_init (CamelMaildirStore *self ); static void camel_maildir_store_class_init (CamelMaildirStoreClass *klass); static GType camel_maildir_store_get_type_once (void ); static gpointer camel_maildir_store_parent_class = ((void* )0); static gint CamelMaildirStore_private_offset; static void camel_maildir_store_class_intern_init (gpointer klass) { camel_maildir_store_parent_class = g_type_class_peek_parent (klass); if (CamelMaildirStore_private_offset != 0) g_type_class_adjust_private_offset (klass, &CamelMaildirStore_private_offset ); camel_maildir_store_class_init ((CamelMaildirStoreClass*) klass ); } __attribute__ ((__unused__)) static inline gpointer camel_maildir_store_get_instance_private (CamelMaildirStore *self) { return (((gpointer) ((guint8*) ( self) + (glong) (CamelMaildirStore_private_offset)))); } GType camel_maildir_store_get_type (void) { static gsize static_g_define_type_id = 0; if ((__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id ) == sizeof (gpointer), "Expression evaluates to false"); (void ) (0 ? (gpointer) *(&static_g_define_type_id) : ((void*)0 )); (!(__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id ) == sizeof (gpointer), "Expression evaluates to false"); __typeof__ (*(&static_g_define_type_id)) gapg_temp_newval; __typeof__ ((&static_g_define_type_id)) gapg_temp_atomic = (&static_g_define_type_id ); __atomic_load (gapg_temp_atomic, &gapg_temp_newval, 5) ; gapg_temp_newval; })) && g_once_init_enter (&static_g_define_type_id )); }))) { GType g_define_type_id = camel_maildir_store_get_type_once (); (__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id ) == sizeof (gpointer), "Expression evaluates to false"); 0 ? (void) (*(&static_g_define_type_id) = (g_define_type_id) ) : (void) 0; g_once_init_leave ((&static_g_define_type_id ), (gsize) (g_define_type_id)); })); } return static_g_define_type_id ; } __attribute__ ((__noinline__)) static GType camel_maildir_store_get_type_once (void) { GType g_define_type_id = g_type_register_static_simple ((camel_local_store_get_type ()), g_intern_static_string ("CamelMaildirStore" ), sizeof (CamelMaildirStoreClass), (GClassInitFunc)(void (*) (void)) camel_maildir_store_class_intern_init, sizeof (CamelMaildirStore ), (GInstanceInitFunc)(void (*)(void)) camel_maildir_store_init , (GTypeFlags) 0); { {{ CamelMaildirStore_private_offset = g_type_add_instance_private (g_define_type_id, sizeof (CamelMaildirStorePrivate)); };} } return g_define_type_id; } | |||
| 59 | ||||
| 60 | /* This fixes up some historical cruft of names starting with "./" */ | |||
| 61 | static const gchar * | |||
| 62 | md_canon_name (const gchar *a) | |||
| 63 | { | |||
| 64 | if (a != NULL((void*)0)) { | |||
| 65 | if (a[0] == '/') | |||
| 66 | a++; | |||
| 67 | if (a[0] == '.' && a[1] == '/') | |||
| 68 | a+=2; | |||
| 69 | } | |||
| 70 | ||||
| 71 | return a; | |||
| 72 | } | |||
| 73 | ||||
| 74 | static CamelFolderInfo * | |||
| 75 | maildir_store_create_folder_sync (CamelStore *store, | |||
| 76 | const gchar *parent_name, | |||
| 77 | const gchar *folder_name, | |||
| 78 | GCancellable *cancellable, | |||
| 79 | GError **error) | |||
| 80 | { | |||
| 81 | CamelLocalSettings *local_settings; | |||
| 82 | CamelSettings *settings; | |||
| 83 | CamelService *service; | |||
| 84 | CamelFolder *folder; | |||
| 85 | CamelFolderInfo *info = NULL((void*)0); | |||
| 86 | gchar *name = NULL((void*)0), *fullname = NULL((void*)0); | |||
| 87 | gchar *path; | |||
| 88 | struct stat st; | |||
| 89 | ||||
| 90 | /* This is a pretty hacky version of create folder, but should basically work */ | |||
| 91 | ||||
| 92 | service = CAMEL_SERVICE (store)((((CamelService*) (void *) ((store))))); | |||
| 93 | ||||
| 94 | settings = camel_service_ref_settings (service); | |||
| 95 | ||||
| 96 | local_settings = CAMEL_LOCAL_SETTINGS (settings)((((CamelLocalSettings*) (void *) ((settings))))); | |||
| 97 | path = camel_local_settings_dup_path (local_settings); | |||
| 98 | ||||
| 99 | g_object_unref (settings); | |||
| 100 | ||||
| 101 | if (!g_path_is_absolute (path)) { | |||
| 102 | g_set_error ( | |||
| 103 | error, CAMEL_STORE_ERROR(camel_store_error_quark ()), | |||
| 104 | CAMEL_STORE_ERROR_NO_FOLDER, | |||
| 105 | _("Store root %s is not an absolute path")((char *) g_dgettext ("evolution-data-server", "Store root %s is not an absolute path" )), path); | |||
| 106 | goto exit; | |||
| 107 | } | |||
| 108 | ||||
| 109 | if (folder_name && !CAMEL_MAILDIR_STORE (store)((((CamelMaildirStore*) (void *) ((store)))))->priv->can_escape_dots && strchr (folder_name, HIER_SEP_CHAR'.')) { | |||
| 110 | g_set_error ( | |||
| 111 | error, CAMEL_STORE_ERROR(camel_store_error_quark ()), | |||
| 112 | CAMEL_STORE_ERROR_INVALID, | |||
| 113 | _("Cannot create folder containing “%s”")((char *) g_dgettext ("evolution-data-server", "Cannot create folder containing “%s”" )), HIER_SEP"."); | |||
| 114 | goto exit; | |||
| 115 | } | |||
| 116 | ||||
| 117 | if ((!parent_name || !*parent_name) && !g_ascii_strcasecmp (folder_name, "Inbox")) { | |||
| 118 | g_set_error ( | |||
| 119 | error, CAMEL_STORE_ERROR(camel_store_error_quark ()), | |||
| 120 | CAMEL_STORE_ERROR_NO_FOLDER, | |||
| 121 | _("Folder %s already exists")((char *) g_dgettext ("evolution-data-server", "Folder %s already exists" )), folder_name); | |||
| 122 | goto exit; | |||
| 123 | } | |||
| 124 | ||||
| 125 | if (parent_name && *parent_name) { | |||
| 126 | fullname = g_strdup_printf ("%s/%s", parent_name, folder_name); | |||
| 127 | name = maildir_full_name_to_dir_name (CAMEL_MAILDIR_STORE (store)((((CamelMaildirStore*) (void *) ((store)))))->priv->can_escape_dots, fullname); | |||
| 128 | g_free (fullname); | |||
| 129 | } else | |||
| 130 | name = maildir_full_name_to_dir_name (CAMEL_MAILDIR_STORE (store)((((CamelMaildirStore*) (void *) ((store)))))->priv->can_escape_dots, folder_name); | |||
| 131 | ||||
| 132 | fullname = g_build_filename (path, name, NULL((void*)0)); | |||
| 133 | ||||
| 134 | g_free (name); | |||
| 135 | name = NULL((void*)0); | |||
| 136 | ||||
| 137 | if (g_statstat (fullname, &st) == 0) { | |||
| 138 | g_set_error ( | |||
| 139 | error, G_IO_ERRORg_io_error_quark(), G_IO_ERROR_EXISTS, | |||
| 140 | _("Folder %s already exists")((char *) g_dgettext ("evolution-data-server", "Folder %s already exists" )), folder_name); | |||
| 141 | goto exit; | |||
| 142 | ||||
| 143 | } else if (errno(*__errno_location ()) != ENOENT2) { | |||
| 144 | g_set_error ( | |||
| 145 | error, G_IO_ERRORg_io_error_quark(), | |||
| 146 | g_io_error_from_errno (errno(*__errno_location ())), | |||
| 147 | _("Cannot get folder: %s: %s")((char *) g_dgettext ("evolution-data-server", "Cannot get folder: %s: %s" )), | |||
| 148 | folder_name, g_strerror (errno(*__errno_location ()))); | |||
| 149 | goto exit; | |||
| 150 | } | |||
| 151 | ||||
| 152 | g_free (fullname); | |||
| 153 | fullname = NULL((void*)0); | |||
| 154 | ||||
| 155 | if (parent_name && *parent_name) | |||
| 156 | name = g_strdup_printf ("%s/%s", parent_name, folder_name); | |||
| 157 | else | |||
| 158 | name = g_strdup_printf ("%s", folder_name); | |||
| 159 | ||||
| 160 | if (camel_store_db_get_folder_id (camel_store_get_db (store), name) > 0) { | |||
| 161 | g_set_error ( | |||
| 162 | error, G_IO_ERRORg_io_error_quark(), G_IO_ERROR_EXISTS, | |||
| 163 | _("Folder %s already exists")((char *) g_dgettext ("evolution-data-server", "Folder %s already exists" )), name); | |||
| 164 | goto exit; | |||
| 165 | } | |||
| 166 | ||||
| 167 | folder = maildir_store_get_folder_sync (store, name, CAMEL_STORE_FOLDER_CREATE, cancellable, error); | |||
| 168 | if (folder) { | |||
| 169 | g_object_unref (folder); | |||
| 170 | info = CAMEL_STORE_GET_CLASS (store)((((CamelStoreClass*) (((GTypeInstance*) ((store)))->g_class ))))->get_folder_info_sync ( | |||
| 171 | store, name, 0, cancellable, error); | |||
| 172 | } | |||
| 173 | ||||
| 174 | exit: | |||
| 175 | g_free (fullname); | |||
| 176 | g_free (name); | |||
| 177 | g_free (path); | |||
| 178 | ||||
| 179 | return info; | |||
| 180 | } | |||
| 181 | ||||
| 182 | static CamelFolder * | |||
| 183 | maildir_store_get_folder_sync (CamelStore *store, | |||
| 184 | const gchar *folder_name, | |||
| 185 | CamelStoreGetFolderFlags flags, | |||
| 186 | GCancellable *cancellable, | |||
| 187 | GError **error) | |||
| 188 | { | |||
| 189 | CamelStoreClass *store_class; | |||
| 190 | CamelLocalSettings *local_settings; | |||
| 191 | CamelSettings *settings; | |||
| 192 | CamelService *service; | |||
| 193 | CamelMaildirStore *maildir_store; | |||
| 194 | gchar *name, *tmp, *cur, *new, *dir_name; | |||
| 195 | gchar *path; | |||
| 196 | struct stat st; | |||
| 197 | CamelFolder *folder = NULL((void*)0); | |||
| 198 | ||||
| 199 | g_return_val_if_fail (CAMEL_IS_MAILDIR_STORE (store), NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_24 = 0; if ((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((store)); GType __t = ((camel_maildir_store_get_type ())) ; gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0) ); else __r = g_type_check_instance_is_a (__inst, __t); __r; } ))))) _g_boolean_var_24 = 1; _g_boolean_var_24; }), 1))) { } else { g_return_if_fail_warning ("camel-local-provider", ((const char *) (__func__)), "CAMEL_IS_MAILDIR_STORE (store)"); return ((( void*)0)); } } while (0); | |||
| 200 | ||||
| 201 | maildir_store = CAMEL_MAILDIR_STORE (store)((((CamelMaildirStore*) (void *) ((store))))); | |||
| 202 | ||||
| 203 | if (!maildir_store->priv->already_migrated && | |||
| 204 | maildir_store->priv->can_escape_dots) { | |||
| 205 | CamelFolderInfo *folder_info; | |||
| 206 | ||||
| 207 | /* Not interested in any errors here, this is to invoke folder | |||
| 208 | content migration only. */ | |||
| 209 | folder_info = camel_store_get_folder_info_sync (store, NULL((void*)0), CAMEL_STORE_FOLDER_INFO_RECURSIVE, cancellable, NULL((void*)0)); | |||
| 210 | if (folder_info) | |||
| 211 | camel_folder_info_free (folder_info); | |||
| 212 | } | |||
| 213 | ||||
| 214 | service = CAMEL_SERVICE (store)((((CamelService*) (void *) ((store))))); | |||
| 215 | ||||
| 216 | settings = camel_service_ref_settings (service); | |||
| 217 | ||||
| 218 | local_settings = CAMEL_LOCAL_SETTINGS (settings)((((CamelLocalSettings*) (void *) ((settings))))); | |||
| 219 | path = camel_local_settings_dup_path (local_settings); | |||
| 220 | ||||
| 221 | g_object_unref (settings); | |||
| 222 | ||||
| 223 | folder_name = md_canon_name (folder_name); | |||
| 224 | dir_name = maildir_full_name_to_dir_name (CAMEL_MAILDIR_STORE (store)((((CamelMaildirStore*) (void *) ((store)))))->priv->can_escape_dots, folder_name); | |||
| 225 | ||||
| 226 | /* maildir++ directory names start with a '.' */ | |||
| 227 | name = g_build_filename (path, dir_name, NULL((void*)0)); | |||
| 228 | ||||
| 229 | g_free (dir_name); | |||
| 230 | g_free (path); | |||
| 231 | ||||
| 232 | /* Chain up to parent's get_folder() method. */ | |||
| 233 | store_class = CAMEL_STORE_CLASS (camel_maildir_store_parent_class)((((CamelStoreClass*) (void *) ((camel_maildir_store_parent_class ))))); | |||
| 234 | if (!store_class->get_folder_sync (store, name, flags, cancellable, error)) { | |||
| 235 | g_free (name); | |||
| 236 | return NULL((void*)0); | |||
| 237 | } | |||
| 238 | ||||
| 239 | tmp = g_strdup_printf ("%s/tmp", name); | |||
| 240 | cur = g_strdup_printf ("%s/cur", name); | |||
| 241 | new = g_strdup_printf ("%s/new", name); | |||
| 242 | ||||
| 243 | if (!g_ascii_strcasecmp (folder_name, "Inbox")) { | |||
| 244 | /* special case "." (aka inbox), may need to be created */ | |||
| 245 | if (g_statstat (tmp, &st) != 0 || !S_ISDIR (st.st_mode)((((st.st_mode)) & 0170000) == (0040000)) | |||
| 246 | || g_statstat (cur, &st) != 0 || !S_ISDIR (st.st_mode)((((st.st_mode)) & 0170000) == (0040000)) | |||
| 247 | || g_statstat (new, &st) != 0 || !S_ISDIR (st.st_mode)((((st.st_mode)) & 0170000) == (0040000))) { | |||
| 248 | if ((g_mkdirmkdir (tmp, 0700) != 0 && errno(*__errno_location ()) != EEXIST17) | |||
| 249 | || (g_mkdirmkdir (cur, 0700) != 0 && errno(*__errno_location ()) != EEXIST17) | |||
| 250 | || (g_mkdirmkdir (new, 0700) != 0 && errno(*__errno_location ()) != EEXIST17)) { | |||
| 251 | g_set_error ( | |||
| 252 | error, G_IO_ERRORg_io_error_quark(), | |||
| 253 | g_io_error_from_errno (errno(*__errno_location ())), | |||
| 254 | _("Cannot create folder “%s”: %s")((char *) g_dgettext ("evolution-data-server", "Cannot create folder “%s”: %s" )), | |||
| 255 | folder_name, g_strerror (errno(*__errno_location ()))); | |||
| 256 | rmdir (tmp); | |||
| 257 | rmdir (cur); | |||
| 258 | rmdir (new); | |||
| 259 | goto fail; | |||
| 260 | } | |||
| 261 | } | |||
| 262 | folder = camel_maildir_folder_new (store, folder_name, flags, cancellable, error); | |||
| 263 | } else if (g_statstat (name, &st) == -1) { | |||
| 264 | /* folder doesn't exist, see if we should create it */ | |||
| 265 | if (errno(*__errno_location ()) != ENOENT2) { | |||
| 266 | g_set_error ( | |||
| 267 | error, G_IO_ERRORg_io_error_quark(), | |||
| 268 | g_io_error_from_errno (errno(*__errno_location ())), | |||
| 269 | _("Cannot get folder “%s”: %s")((char *) g_dgettext ("evolution-data-server", "Cannot get folder “%s”: %s" )), | |||
| 270 | folder_name, g_strerror (errno(*__errno_location ()))); | |||
| 271 | } else if ((flags & CAMEL_STORE_FOLDER_CREATE) == 0) { | |||
| 272 | g_set_error ( | |||
| 273 | error, CAMEL_STORE_ERROR(camel_store_error_quark ()), | |||
| 274 | CAMEL_STORE_ERROR_NO_FOLDER, | |||
| 275 | _("Cannot get folder “%s”: folder does not exist.")((char *) g_dgettext ("evolution-data-server", "Cannot get folder “%s”: folder does not exist." )), | |||
| 276 | folder_name); | |||
| 277 | } else { | |||
| 278 | if ((g_mkdirmkdir (name, 0700) != 0 && errno(*__errno_location ()) != EEXIST17) | |||
| 279 | || (g_mkdirmkdir (tmp, 0700) != 0 && errno(*__errno_location ()) != EEXIST17) | |||
| 280 | || (g_mkdirmkdir (cur, 0700) != 0 && errno(*__errno_location ()) != EEXIST17) | |||
| 281 | || (g_mkdirmkdir (new, 0700) != 0 && errno(*__errno_location ()) != EEXIST17)) { | |||
| 282 | g_set_error ( | |||
| 283 | error, G_IO_ERRORg_io_error_quark(), | |||
| 284 | g_io_error_from_errno (errno(*__errno_location ())), | |||
| 285 | _("Cannot create folder “%s”: %s")((char *) g_dgettext ("evolution-data-server", "Cannot create folder “%s”: %s" )), | |||
| 286 | folder_name, g_strerror (errno(*__errno_location ()))); | |||
| 287 | rmdir (tmp); | |||
| 288 | rmdir (cur); | |||
| 289 | rmdir (new); | |||
| 290 | rmdir (name); | |||
| 291 | } else { | |||
| 292 | folder = camel_maildir_folder_new (store, folder_name, flags, cancellable, error); | |||
| 293 | } | |||
| 294 | } | |||
| 295 | } else if (!S_ISDIR (st.st_mode)((((st.st_mode)) & 0170000) == (0040000)) | |||
| 296 | || g_statstat (tmp, &st) != 0 || !S_ISDIR (st.st_mode)((((st.st_mode)) & 0170000) == (0040000)) | |||
| 297 | || g_statstat (cur, &st) != 0 || !S_ISDIR (st.st_mode)((((st.st_mode)) & 0170000) == (0040000)) | |||
| 298 | || g_statstat (new, &st) != 0 || !S_ISDIR (st.st_mode)((((st.st_mode)) & 0170000) == (0040000))) { | |||
| 299 | /* folder exists, but not maildir */ | |||
| 300 | g_set_error ( | |||
| 301 | error, CAMEL_ERROR(camel_error_quark ()), CAMEL_ERROR_GENERIC, | |||
| 302 | _("Cannot get folder “%s”: not a maildir directory.")((char *) g_dgettext ("evolution-data-server", "Cannot get folder “%s”: not a maildir directory." )), | |||
| 303 | name); | |||
| 304 | } else { | |||
| 305 | folder = camel_maildir_folder_new (store, folder_name, flags, cancellable, error); | |||
| 306 | } | |||
| 307 | fail: | |||
| 308 | g_free (name); | |||
| 309 | g_free (tmp); | |||
| 310 | g_free (cur); | |||
| 311 | g_free (new); | |||
| 312 | ||||
| 313 | return folder; | |||
| 314 | } | |||
| 315 | ||||
| 316 | static gboolean | |||
| 317 | maildir_store_delete_folder_sync (CamelStore *store, | |||
| 318 | const gchar *folder_name, | |||
| 319 | GCancellable *cancellable, | |||
| 320 | GError **error) | |||
| 321 | { | |||
| 322 | CamelLocalSettings *local_settings; | |||
| 323 | CamelSettings *settings; | |||
| 324 | CamelService *service; | |||
| 325 | gchar *name, *tmp, *cur, *new, *dir_name; | |||
| 326 | gchar *path; | |||
| 327 | struct stat st; | |||
| 328 | gboolean success = TRUE(!(0)); | |||
| 329 | ||||
| 330 | if (g_ascii_strcasecmp (folder_name, "Inbox") == 0) { | |||
| 331 | g_set_error ( | |||
| 332 | error, CAMEL_STORE_ERROR(camel_store_error_quark ()), | |||
| 333 | CAMEL_STORE_ERROR_NO_FOLDER, | |||
| 334 | _("Cannot delete folder: %s: Invalid operation")((char *) g_dgettext ("evolution-data-server", "Cannot delete folder: %s: Invalid operation" )), | |||
| 335 | _("Inbox")((char *) g_dgettext ("evolution-data-server", "Inbox"))); | |||
| 336 | return FALSE(0); | |||
| 337 | } | |||
| 338 | ||||
| 339 | service = CAMEL_SERVICE (store)((((CamelService*) (void *) ((store))))); | |||
| 340 | ||||
| 341 | settings = camel_service_ref_settings (service); | |||
| 342 | ||||
| 343 | local_settings = CAMEL_LOCAL_SETTINGS (settings)((((CamelLocalSettings*) (void *) ((settings))))); | |||
| 344 | path = camel_local_settings_dup_path (local_settings); | |||
| 345 | ||||
| 346 | g_object_unref (settings); | |||
| 347 | ||||
| 348 | /* maildir++ directory names start with a '.' */ | |||
| 349 | dir_name = maildir_full_name_to_dir_name (CAMEL_MAILDIR_STORE (store)((((CamelMaildirStore*) (void *) ((store)))))->priv->can_escape_dots, folder_name); | |||
| 350 | name = g_build_filename (path, dir_name, NULL((void*)0)); | |||
| 351 | g_free (dir_name); | |||
| 352 | ||||
| 353 | g_free (path); | |||
| 354 | ||||
| 355 | tmp = g_strdup_printf ("%s/tmp", name); | |||
| 356 | cur = g_strdup_printf ("%s/cur", name); | |||
| 357 | new = g_strdup_printf ("%s/new", name); | |||
| 358 | ||||
| 359 | if (g_statstat (name, &st) == -1 || !S_ISDIR (st.st_mode)((((st.st_mode)) & 0170000) == (0040000)) | |||
| 360 | || g_statstat (tmp, &st) == -1 || !S_ISDIR (st.st_mode)((((st.st_mode)) & 0170000) == (0040000)) | |||
| 361 | || g_statstat (cur, &st) == -1 || !S_ISDIR (st.st_mode)((((st.st_mode)) & 0170000) == (0040000)) | |||
| 362 | || g_statstat (new, &st) == -1 || !S_ISDIR (st.st_mode)((((st.st_mode)) & 0170000) == (0040000))) { | |||
| 363 | g_set_error ( | |||
| 364 | error, G_IO_ERRORg_io_error_quark(), | |||
| 365 | g_io_error_from_errno (errno(*__errno_location ())), | |||
| 366 | _("Could not delete folder “%s”: %s")((char *) g_dgettext ("evolution-data-server", "Could not delete folder “%s”: %s" )), | |||
| 367 | folder_name, errno(*__errno_location ()) ? g_strerror (errno(*__errno_location ())) : | |||
| 368 | _("not a maildir directory")((char *) g_dgettext ("evolution-data-server", "not a maildir directory" ))); | |||
| 369 | } else { | |||
| 370 | gint err = 0; | |||
| 371 | ||||
| 372 | /* remove subdirs first - will fail if not empty */ | |||
| 373 | if (rmdir (cur) == -1 || rmdir (new) == -1) { | |||
| 374 | err = errno(*__errno_location ()); | |||
| 375 | } else { | |||
| 376 | DIR *dir; | |||
| 377 | struct dirent *d; | |||
| 378 | ||||
| 379 | /* for tmp (only), its contents is irrelevant */ | |||
| 380 | dir = opendir (tmp); | |||
| 381 | if (dir) { | |||
| 382 | while ((d = readdir (dir))) { | |||
| 383 | gchar *dname = d->d_name, *file; | |||
| 384 | ||||
| 385 | if (!strcmp (dname, ".") || !strcmp (dname, "..")) | |||
| 386 | continue; | |||
| 387 | file = g_strdup_printf ("%s/%s", tmp, dname); | |||
| 388 | unlink (file); | |||
| 389 | g_free (file); | |||
| 390 | } | |||
| 391 | closedir (dir); | |||
| 392 | } | |||
| 393 | if (rmdir (tmp) == -1 || rmdir (name) == -1) | |||
| 394 | err = errno(*__errno_location ()); | |||
| 395 | } | |||
| 396 | ||||
| 397 | if (err != 0) { | |||
| 398 | /* easier just to mkdir all (and let them fail), than remember what we got to */ | |||
| 399 | CHECK_MKDIR (g_mkdir (name, 0700), name)do { gint mkdir_ret = (mkdir (name, 0700)); if (mkdir_ret == - 1 && (*__errno_location ()) != 17) { g_debug ("%s: mkdir of '%s' failed: %s" , ((const char*) (__func__)), (name), g_strerror ((*__errno_location ()))); } } while (0); | |||
| 400 | CHECK_MKDIR (g_mkdir (cur, 0700), cur)do { gint mkdir_ret = (mkdir (cur, 0700)); if (mkdir_ret == - 1 && (*__errno_location ()) != 17) { g_debug ("%s: mkdir of '%s' failed: %s" , ((const char*) (__func__)), (cur), g_strerror ((*__errno_location ()))); } } while (0); | |||
| 401 | CHECK_MKDIR (g_mkdir (new, 0700), new)do { gint mkdir_ret = (mkdir (new, 0700)); if (mkdir_ret == - 1 && (*__errno_location ()) != 17) { g_debug ("%s: mkdir of '%s' failed: %s" , ((const char*) (__func__)), (new), g_strerror ((*__errno_location ()))); } } while (0); | |||
| 402 | CHECK_MKDIR (g_mkdir (tmp, 0700), tmp)do { gint mkdir_ret = (mkdir (tmp, 0700)); if (mkdir_ret == - 1 && (*__errno_location ()) != 17) { g_debug ("%s: mkdir of '%s' failed: %s" , ((const char*) (__func__)), (tmp), g_strerror ((*__errno_location ()))); } } while (0); | |||
| 403 | g_set_error ( | |||
| 404 | error, G_IO_ERRORg_io_error_quark(), | |||
| 405 | g_io_error_from_errno (err), | |||
| 406 | _("Could not delete folder “%s”: %s")((char *) g_dgettext ("evolution-data-server", "Could not delete folder “%s”: %s" )), | |||
| 407 | folder_name, g_strerror (err)); | |||
| 408 | } else { | |||
| 409 | CamelStoreClass *store_class; | |||
| 410 | ||||
| 411 | /* Chain up to parent's delete_folder() method. */ | |||
| 412 | store_class = CAMEL_STORE_CLASS (camel_maildir_store_parent_class)((((CamelStoreClass*) (void *) ((camel_maildir_store_parent_class ))))); | |||
| 413 | success = store_class->delete_folder_sync ( | |||
| 414 | store, folder_name, cancellable, error); | |||
| 415 | } | |||
| 416 | } | |||
| 417 | ||||
| 418 | g_free (name); | |||
| 419 | g_free (tmp); | |||
| 420 | g_free (cur); | |||
| 421 | g_free (new); | |||
| 422 | ||||
| 423 | return success; | |||
| 424 | } | |||
| 425 | ||||
| 426 | static void | |||
| 427 | fill_fi (CamelStore *store, | |||
| 428 | CamelFolderInfo *fi, | |||
| 429 | guint32 flags, | |||
| 430 | GCancellable *cancellable) | |||
| 431 | { | |||
| 432 | CamelFolder *folder; | |||
| 433 | ||||
| 434 | folder = camel_object_bag_peek (camel_store_get_folders_bag (store), fi->full_name); | |||
| 435 | if (folder) { | |||
| 436 | CamelFolderSummary *summary; | |||
| 437 | ||||
| 438 | if ((flags & CAMEL_STORE_FOLDER_INFO_FAST) == 0) | |||
| 439 | camel_folder_refresh_info_sync (folder, cancellable, NULL((void*)0)); | |||
| 440 | summary = camel_folder_get_folder_summary (folder); | |||
| 441 | fi->unread = camel_folder_summary_get_unread_count (summary); | |||
| 442 | fi->total = camel_folder_summary_count (summary); | |||
| 443 | g_object_unref (folder); | |||
| 444 | } else { | |||
| 445 | CamelLocalSettings *local_settings; | |||
| 446 | CamelSettings *settings; | |||
| 447 | CamelService *service; | |||
| 448 | CamelMaildirStore *maildir_store; | |||
| 449 | gchar *folderpath, *dir_name; | |||
| 450 | CamelFolderSummary *s; | |||
| 451 | gchar *root; | |||
| 452 | ||||
| 453 | service = CAMEL_SERVICE (store)((((CamelService*) (void *) ((store))))); | |||
| 454 | ||||
| 455 | settings = camel_service_ref_settings (service); | |||
| 456 | ||||
| 457 | local_settings = CAMEL_LOCAL_SETTINGS (settings)((((CamelLocalSettings*) (void *) ((settings))))); | |||
| 458 | root = camel_local_settings_dup_path (local_settings); | |||
| 459 | ||||
| 460 | g_object_unref (settings); | |||
| 461 | ||||
| 462 | maildir_store = CAMEL_MAILDIR_STORE (store)((((CamelMaildirStore*) (void *) ((store))))); | |||
| 463 | ||||
| 464 | /* This should be fast enough not to have to test for INFO_FAST */ | |||
| 465 | dir_name = maildir_full_name_to_dir_name (maildir_store->priv->can_escape_dots, fi->full_name); | |||
| 466 | ||||
| 467 | if (!strcmp (dir_name, ".")) | |||
| 468 | folderpath = g_strdup (root)g_strdup_inline (root); | |||
| 469 | else | |||
| 470 | folderpath = g_build_filename (root, dir_name, NULL((void*)0)); | |||
| 471 | ||||
| 472 | g_free (root); | |||
| 473 | ||||
| 474 | s = (CamelFolderSummary *) camel_maildir_summary_new (NULL((void*)0), folderpath, NULL((void*)0), camel_maildir_store_get_filename_flag_sep (maildir_store)); | |||
| 475 | if (camel_folder_summary_header_load (s, store, fi->full_name, NULL((void*)0))) { | |||
| 476 | fi->unread = camel_folder_summary_get_unread_count (s); | |||
| 477 | fi->total = camel_folder_summary_get_saved_count (s); | |||
| 478 | } | |||
| 479 | g_object_unref (s); | |||
| 480 | g_free (folderpath); | |||
| 481 | g_free (dir_name); | |||
| 482 | } | |||
| 483 | ||||
| 484 | if (camel_local_store_is_main_store (CAMEL_LOCAL_STORE (store)((((CamelLocalStore*) (void *) ((store)))))) && fi->full_name | |||
| 485 | && (fi->flags & CAMEL_FOLDER_TYPE_MASK(0x3F << (10))) == CAMEL_FOLDER_TYPE_NORMAL) | |||
| 486 | fi->flags = (fi->flags & ~CAMEL_FOLDER_TYPE_MASK(0x3F << (10))) | |||
| 487 | | camel_local_store_get_folder_type_by_full_name (CAMEL_LOCAL_STORE (store)((((CamelLocalStore*) (void *) ((store))))), fi->full_name); | |||
| 488 | } | |||
| 489 | ||||
| 490 | static CamelFolderInfo * | |||
| 491 | scan_fi (CamelStore *store, | |||
| 492 | guint32 flags, | |||
| 493 | const gchar *full, | |||
| 494 | const gchar *name, | |||
| 495 | GCancellable *cancellable) | |||
| 496 | { | |||
| 497 | CamelLocalSettings *local_settings; | |||
| 498 | CamelSettings *settings; | |||
| 499 | CamelService *service; | |||
| 500 | CamelFolderInfo *fi; | |||
| 501 | gchar *tmp, *cur, *new, *dir_name; | |||
| 502 | gchar *path; | |||
| 503 | struct stat st; | |||
| 504 | ||||
| 505 | service = CAMEL_SERVICE (store)((((CamelService*) (void *) ((store))))); | |||
| 506 | ||||
| 507 | settings = camel_service_ref_settings (service); | |||
| 508 | ||||
| 509 | local_settings = CAMEL_LOCAL_SETTINGS (settings)((((CamelLocalSettings*) (void *) ((settings))))); | |||
| 510 | path = camel_local_settings_dup_path (local_settings); | |||
| 511 | ||||
| 512 | g_object_unref (settings); | |||
| 513 | ||||
| 514 | g_return_val_if_fail (path != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_25 = 0; if (path != ((void*)0)) _g_boolean_var_25 = 1; _g_boolean_var_25 ; }), 1))) { } else { g_return_if_fail_warning ("camel-local-provider" , ((const char*) (__func__)), "path != NULL"); return (((void *)0)); } } while (0); | |||
| 515 | ||||
| 516 | fi = camel_folder_info_new (); | |||
| 517 | fi->full_name = g_strdup (full)g_strdup_inline (full); | |||
| 518 | fi->display_name = g_strdup (name)g_strdup_inline (name); | |||
| 519 | ||||
| 520 | fi->unread = -1; | |||
| 521 | fi->total = -1; | |||
| 522 | ||||
| 523 | /* we only calculate nochildren properly if we're recursive */ | |||
| 524 | if (((flags & CAMEL_STORE_FOLDER_INFO_RECURSIVE) != 0)) | |||
| 525 | fi->flags = CAMEL_FOLDER_NOCHILDREN; | |||
| 526 | ||||
| 527 | dir_name = maildir_full_name_to_dir_name (CAMEL_MAILDIR_STORE (store)((((CamelMaildirStore*) (void *) ((store)))))->priv->can_escape_dots, fi->full_name); | |||
| 528 | d (printf ("Adding maildir info: '%s' '%s' '%s'\n", fi->name, dir_name, fi->uri)); | |||
| 529 | ||||
| 530 | tmp = g_build_filename (path, dir_name, "tmp", NULL((void*)0)); | |||
| 531 | cur = g_build_filename (path, dir_name, "cur", NULL((void*)0)); | |||
| 532 | new = g_build_filename (path, dir_name, "new", NULL((void*)0)); | |||
| 533 | ||||
| 534 | if (!(g_statstat (cur, &st) == 0 && S_ISDIR (st.st_mode)((((st.st_mode)) & 0170000) == (0040000)) | |||
| 535 | && g_statstat (new, &st) == 0 && S_ISDIR (st.st_mode)((((st.st_mode)) & 0170000) == (0040000)) | |||
| 536 | /* Create 'tmp' dir on demand, if other directories are there, | |||
| 537 | because some backup tools can drop the 'tmp' directory. */ | |||
| 538 | && ((g_statstat (tmp, &st) == 0 && S_ISDIR (st.st_mode)((((st.st_mode)) & 0170000) == (0040000))) || g_mkdirmkdir (tmp, 0700) == 0))) | |||
| 539 | fi->flags |= CAMEL_FOLDER_NOSELECT; | |||
| 540 | ||||
| 541 | g_free (new); | |||
| 542 | g_free (cur); | |||
| 543 | g_free (tmp); | |||
| 544 | g_free (dir_name); | |||
| 545 | ||||
| 546 | fill_fi (store, fi, flags, cancellable); | |||
| 547 | ||||
| 548 | g_free (path); | |||
| 549 | ||||
| 550 | return fi; | |||
| 551 | } | |||
| 552 | ||||
| 553 | /* Folder names begin with a dot */ | |||
| 554 | static gchar * | |||
| 555 | maildir_full_name_to_dir_name (gboolean can_escape_dots, | |||
| 556 | const gchar *full_name) | |||
| 557 | { | |||
| 558 | gchar *path; | |||
| 559 | ||||
| 560 | if (g_ascii_strcasecmp (full_name, "Inbox") == 0) { | |||
| 561 | path = g_strdup (".")g_strdup_inline ("."); | |||
| 562 | } else { | |||
| 563 | if (g_ascii_strncasecmp (full_name, "Inbox/", 6) == 0) | |||
| 564 | path = g_strconcat ("/", full_name + 5, NULL((void*)0)); | |||
| 565 | else | |||
| 566 | path = g_strconcat ("/", full_name, NULL((void*)0)); | |||
| 567 | ||||
| 568 | if (can_escape_dots && (strchr (path, HIER_SEP_CHAR'.') || strchr (path, '_'))) { | |||
| 569 | GString *tmp = g_string_new (""); | |||
| 570 | const gchar *pp; | |||
| 571 | ||||
| 572 | for (pp = path; *pp; pp++) { | |||
| 573 | if (*pp == HIER_SEP_CHAR'.' || *pp == '_') | |||
| 574 | g_string_append_printf (tmp, "_%02X", *pp); | |||
| 575 | else | |||
| 576 | g_string_append_c (tmp, *pp)g_string_append_c_inline (tmp, *pp); | |||
| 577 | } | |||
| 578 | ||||
| 579 | g_free (path); | |||
| 580 | path = g_string_free (tmp, FALSE(0)); | |||
| 581 | } | |||
| 582 | ||||
| 583 | g_strdelimit (path, "/", HIER_SEP_CHAR'.'); | |||
| 584 | } | |||
| 585 | ||||
| 586 | return path; | |||
| 587 | } | |||
| 588 | ||||
| 589 | static gchar * | |||
| 590 | maildir_dir_name_to_fullname (gboolean can_escape_dots, | |||
| 591 | const gchar *dir_name) | |||
| 592 | { | |||
| 593 | gchar *full_name; | |||
| 594 | ||||
| 595 | if (!g_ascii_strncasecmp (dir_name, "..", 2)) | |||
| 596 | full_name = g_strconcat ("Inbox/", dir_name + 2, NULL((void*)0)); | |||
| 597 | else | |||
| 598 | full_name = g_strdup (dir_name + 1)g_strdup_inline (dir_name + 1); | |||
| 599 | ||||
| 600 | g_strdelimit (full_name, HIER_SEP".", '/'); | |||
| 601 | ||||
| 602 | if (can_escape_dots && strchr (full_name, '_')) { | |||
| 603 | gint ii, jj; | |||
| 604 | ||||
| 605 | for (ii = 0, jj = 0; full_name[ii]; ii++, jj++) { | |||
| 606 | if (full_name[ii] == '_' && g_ascii_isxdigit (full_name[ii + 1])((g_ascii_table[(guchar) (full_name[ii + 1])] & G_ASCII_XDIGIT ) != 0) && g_ascii_isxdigit (full_name[ii + 2])((g_ascii_table[(guchar) (full_name[ii + 2])] & G_ASCII_XDIGIT ) != 0)) { | |||
| 607 | full_name[jj] = 16 * g_ascii_xdigit_value (full_name[ii + 1]) + g_ascii_xdigit_value (full_name[ii + 2]); | |||
| 608 | ii += 2; | |||
| 609 | } else if (ii != jj) { | |||
| 610 | full_name[jj] = full_name[ii]; | |||
| 611 | } | |||
| 612 | } | |||
| 613 | ||||
| 614 | full_name[jj] = '\0'; | |||
| 615 | } | |||
| 616 | ||||
| 617 | return full_name; | |||
| 618 | } | |||
| 619 | ||||
| 620 | static gint | |||
| 621 | scan_dirs (CamelStore *store, | |||
| 622 | guint32 flags, | |||
| 623 | gboolean can_inbox_sibling, | |||
| 624 | CamelFolderInfo **topfi, | |||
| 625 | GCancellable *cancellable, | |||
| 626 | GError **error) | |||
| 627 | { | |||
| 628 | CamelLocalSettings *local_settings; | |||
| 629 | CamelMaildirStore *maildir_store; | |||
| 630 | CamelSettings *settings; | |||
| 631 | CamelService *service; | |||
| 632 | CamelFolderInfo *fi; | |||
| 633 | GPtrArray *folders; | |||
| 634 | gint res = -1; | |||
| 635 | DIR *dir; | |||
| 636 | struct dirent *d; | |||
| 637 | gchar *path; | |||
| 638 | ||||
| 639 | service = CAMEL_SERVICE (store)((((CamelService*) (void *) ((store))))); | |||
| 640 | maildir_store = CAMEL_MAILDIR_STORE (store)((((CamelMaildirStore*) (void *) ((store))))); | |||
| 641 | ||||
| 642 | settings = camel_service_ref_settings (service); | |||
| 643 | ||||
| 644 | local_settings = CAMEL_LOCAL_SETTINGS (settings)((((CamelLocalSettings*) (void *) ((settings))))); | |||
| 645 | path = camel_local_settings_dup_path (local_settings); | |||
| 646 | ||||
| 647 | g_object_unref (settings); | |||
| 648 | ||||
| 649 | g_return_val_if_fail (path != NULL, -1)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_26 = 0; if (path != ((void*)0)) _g_boolean_var_26 = 1; _g_boolean_var_26 ; }), 1))) { } else { g_return_if_fail_warning ("camel-local-provider" , ((const char*) (__func__)), "path != NULL"); return (-1); } } while (0); | |||
| ||||
| 650 | ||||
| 651 | folders = g_ptr_array_new (); | |||
| 652 | if (!g_ascii_strcasecmp ((*topfi)->full_name, "Inbox")) | |||
| 653 | g_ptr_array_add (folders, (*topfi)); | |||
| 654 | ||||
| 655 | dir = opendir (path); | |||
| 656 | if (dir
| |||
| 657 | g_set_error ( | |||
| 658 | error, G_IO_ERRORg_io_error_quark(), | |||
| 659 | g_io_error_from_errno (errno(*__errno_location ())), | |||
| 660 | _("Could not scan folder “%s”: %s")((char *) g_dgettext ("evolution-data-server", "Could not scan folder “%s”: %s" )), | |||
| 661 | path, g_strerror (errno(*__errno_location ()))); | |||
| 662 | goto exit; | |||
| 663 | } | |||
| 664 | ||||
| 665 | if (!maildir_store->priv->already_migrated && | |||
| 666 | maildir_store->priv->can_escape_dots) { | |||
| 667 | gchar *meta_path = NULL((void*)0), *ptr; | |||
| 668 | gint maildir_version = 0; | |||
| 669 | gboolean file_exists = FALSE(0), requires_migrate; | |||
| 670 | ||||
| 671 | meta_path = maildir_get_meta_path ((CamelLocalStore *) store, "?", "maildir++"); | |||
| 672 | ptr = strrchr (meta_path, '?'); | |||
| 673 | if (!ptr) { | |||
| 674 | g_warn_if_reached ()do { g_warn_message ("camel-local-provider", "/builds/GNOME/evolution-data-server/src/camel/providers/local/camel-maildir-store.c" , 674, ((const char*) (__func__)), ((void*)0)); } while (0); | |||
| 675 | closedir (dir); | |||
| 676 | res = -1; | |||
| 677 | ||||
| 678 | goto exit; | |||
| 679 | } | |||
| 680 | ||||
| 681 | maildir_store->priv->already_migrated = TRUE(!(0)); | |||
| 682 | ||||
| 683 | /* Do not migrate folders out of user's data data, which is completely | |||
| 684 | handled by Camel/Evolution, thus these tweaks can be done there. */ | |||
| 685 | maildir_store->priv->can_escape_dots = g_str_has_prefix (meta_path, camel_service_get_user_data_dir (service))(__builtin_constant_p (camel_service_get_user_data_dir (service ))? __extension__ ({ const char * const __str = (meta_path); const char * const __prefix = (camel_service_get_user_data_dir (service )); gboolean __result = (0); if (__builtin_expect (__extension__ ({ int _g_boolean_var_27 = 0; if (__str == ((void*)0) || __prefix == ((void*)0)) _g_boolean_var_27 = 1; _g_boolean_var_27; }), 0)) __result = (g_str_has_prefix) (__str, __prefix); else { const size_t __str_len = strlen (((__str) + !(__str))); const size_t __prefix_len = strlen (((__prefix) + !(__prefix))); if (__str_len >= __prefix_len) __result = memcmp (((__str) + !(__str)), ((__prefix) + !(__prefix)), __prefix_len) == 0; } __result; } ) : (g_str_has_prefix) (meta_path, camel_service_get_user_data_dir (service)) ); | |||
| 686 | ||||
| 687 | /* cannot pass dot inside maildir_get_meta_path(), because it escapes it */ | |||
| 688 | ptr[0] = '.'; | |||
| 689 | ||||
| 690 | requires_migrate = maildir_version_requires_migrate (meta_path, &file_exists, &maildir_version); | |||
| 691 | if (file_exists) { | |||
| 692 | /* Users can enable dot escaping by adding ..maildir++ file into the root Maildir folder */ | |||
| 693 | maildir_store->priv->can_escape_dots = TRUE(!(0)); | |||
| 694 | } | |||
| 695 | ||||
| 696 | if (requires_migrate && maildir_store->priv->can_escape_dots) | |||
| 697 | maildir_migrate_hierarchy ((CamelMaildirStore *) store, maildir_version, cancellable, error); | |||
| 698 | ||||
| 699 | g_free (meta_path); | |||
| 700 | } | |||
| 701 | ||||
| 702 | while ((d = readdir (dir))) { | |||
| 703 | gchar *full_name, *filename; | |||
| 704 | const gchar *short_name; | |||
| 705 | struct stat st; | |||
| 706 | ||||
| 707 | if (strcmp (d->d_name, "tmp") == 0 | |||
| 708 | || strcmp (d->d_name, "cur") == 0 | |||
| 709 | || strcmp (d->d_name, "new") == 0 | |||
| 710 | || strcmp (d->d_name, ".#evolution") == 0 | |||
| 711 | || strcmp (d->d_name, ".") == 0 | |||
| 712 | || strcmp (d->d_name, "..") == 0 | |||
| 713 | || !g_str_has_prefix (d->d_name, ".")(__builtin_constant_p (".")? __extension__ ({ const char * const __str = (d->d_name); const char * const __prefix = ("."); gboolean __result = (0); if (__builtin_expect (__extension__ ({ int _g_boolean_var_28 = 0; if (__str == ((void*)0) || __prefix == ((void*)0)) _g_boolean_var_28 = 1; _g_boolean_var_28; }), 0)) __result = (g_str_has_prefix) (__str, __prefix); else { const size_t __str_len = strlen (((__str) + !(__str))); const size_t __prefix_len = strlen (((__prefix) + !(__prefix))); if (__str_len >= __prefix_len) __result = memcmp (((__str) + !(__str)), ((__prefix) + !(__prefix)), __prefix_len) == 0; } __result; } ) : (g_str_has_prefix) (d->d_name, ".") )) | |||
| 714 | ||||
| 715 | continue; | |||
| 716 | ||||
| 717 | filename = g_build_filename (path, d->d_name, NULL((void*)0)); | |||
| 718 | if (!(g_statstat (filename, &st) == 0 && S_ISDIR (st.st_mode)((((st.st_mode)) & 0170000) == (0040000)))) { | |||
| 719 | g_free (filename); | |||
| 720 | continue; | |||
| 721 | } | |||
| 722 | g_free (filename); | |||
| 723 | full_name = maildir_dir_name_to_fullname (maildir_store->priv->can_escape_dots, d->d_name); | |||
| 724 | short_name = strrchr (full_name, '/'); | |||
| 725 | if (!short_name) | |||
| 726 | short_name = full_name; | |||
| 727 | else | |||
| 728 | short_name++; | |||
| 729 | ||||
| 730 | if ((g_ascii_strcasecmp ((*topfi)->full_name, "Inbox") != 0 | |||
| 731 | && (!g_str_has_prefix (full_name, (*topfi)->full_name)(__builtin_constant_p ((*topfi)->full_name)? __extension__ ({ const char * const __str = (full_name); const char * const __prefix = ((*topfi)->full_name); gboolean __result = (0) ; if (__builtin_expect (__extension__ ({ int _g_boolean_var_29 = 0; if (__str == ((void*)0) || __prefix == ((void*)0)) _g_boolean_var_29 = 1; _g_boolean_var_29; }), 0)) __result = (g_str_has_prefix ) (__str, __prefix); else { const size_t __str_len = strlen ( ((__str) + !(__str))); const size_t __prefix_len = strlen ((( __prefix) + !(__prefix))); if (__str_len >= __prefix_len) __result = memcmp (((__str) + !(__str)), ((__prefix) + !(__prefix)), __prefix_len ) == 0; } __result; }) : (g_str_has_prefix) (full_name, (*topfi )->full_name) ) || | |||
| 732 | (full_name[strlen ((*topfi)->full_name)] != '\0' && | |||
| 733 | full_name[strlen ((*topfi)->full_name)] != '/'))) | |||
| 734 | || (!can_inbox_sibling | |||
| 735 | && g_ascii_strcasecmp ((*topfi)->full_name, "Inbox") == 0 | |||
| 736 | && (!g_str_has_prefix (full_name, (*topfi)->full_name)(__builtin_constant_p ((*topfi)->full_name)? __extension__ ({ const char * const __str = (full_name); const char * const __prefix = ((*topfi)->full_name); gboolean __result = (0) ; if (__builtin_expect (__extension__ ({ int _g_boolean_var_30 = 0; if (__str == ((void*)0) || __prefix == ((void*)0)) _g_boolean_var_30 = 1; _g_boolean_var_30; }), 0)) __result = (g_str_has_prefix ) (__str, __prefix); else { const size_t __str_len = strlen ( ((__str) + !(__str))); const size_t __prefix_len = strlen ((( __prefix) + !(__prefix))); if (__str_len >= __prefix_len) __result = memcmp (((__str) + !(__str)), ((__prefix) + !(__prefix)), __prefix_len ) == 0; } __result; }) : (g_str_has_prefix) (full_name, (*topfi )->full_name) ) || | |||
| 737 | (full_name[strlen ((*topfi)->full_name)] != '\0' && | |||
| 738 | full_name[strlen ((*topfi)->full_name)] != '/')))) { | |||
| 739 | g_free (full_name); | |||
| 740 | continue; | |||
| 741 | } | |||
| 742 | ||||
| 743 | fi = scan_fi (store, flags, full_name, short_name, cancellable); | |||
| 744 | g_free (full_name); | |||
| 745 | ||||
| 746 | g_ptr_array_add (folders, fi); | |||
| 747 | } | |||
| 748 | ||||
| 749 | closedir (dir); | |||
| 750 | ||||
| 751 | if (folders->len != 0) { | |||
| 752 | if (!g_ascii_strcasecmp ((*topfi)->full_name, "Inbox")) { | |||
| 753 | *topfi = camel_folder_info_build (folders, "", '/', TRUE(!(0))); | |||
| 754 | } else { | |||
| 755 | CamelFolderInfo *old_topfi = *topfi; | |||
| 756 | ||||
| 757 | *topfi = camel_folder_info_build (folders, (*topfi)->full_name, '/', TRUE(!(0))); | |||
| 758 | camel_folder_info_free (old_topfi); | |||
| 759 | } | |||
| 760 | ||||
| 761 | fi = *topfi; | |||
| 762 | ||||
| 763 | if (fi && (flags & CAMEL_STORE_FOLDER_INFO_RECURSIVE) != 0) { | |||
| 764 | while (fi) { | |||
| 765 | if (fi->child) { | |||
| 766 | fi->flags = fi->flags & (~CAMEL_FOLDER_NOCHILDREN); | |||
| 767 | fi->flags = fi->flags | CAMEL_FOLDER_CHILDREN; | |||
| 768 | ||||
| 769 | fi = fi->child; | |||
| 770 | } else if (fi->next) { | |||
| 771 | fi = fi->next; | |||
| 772 | } else { | |||
| 773 | while (fi) { | |||
| 774 | fi = fi->parent; | |||
| 775 | if (fi && fi->next) { | |||
| 776 | fi = fi->next; | |||
| 777 | break; | |||
| 778 | } | |||
| 779 | } | |||
| 780 | } | |||
| 781 | } | |||
| 782 | } | |||
| 783 | ||||
| 784 | res = 0; | |||
| 785 | } else | |||
| 786 | res = -1; | |||
| 787 | ||||
| 788 | exit: | |||
| 789 | g_ptr_array_free (folders, TRUE(!(0))); | |||
| 790 | ||||
| 791 | g_free (path); | |||
| 792 | ||||
| 793 | return res; | |||
| 794 | } | |||
| 795 | ||||
| 796 | static guint | |||
| 797 | maildir_store_hash_folder_name (gconstpointer a) | |||
| 798 | { | |||
| 799 | return g_str_hash (md_canon_name (a)); | |||
| 800 | } | |||
| 801 | ||||
| 802 | static gboolean | |||
| 803 | maildir_store_equal_folder_name (gconstpointer a, | |||
| 804 | gconstpointer b) | |||
| 805 | { | |||
| 806 | return g_str_equal (md_canon_name (a), md_canon_name (b))(strcmp ((const char *) (md_canon_name (a)), (const char *) ( md_canon_name (b))) == 0); | |||
| 807 | } | |||
| 808 | ||||
| 809 | static CamelFolderInfo * | |||
| 810 | maildir_store_get_folder_info_sync (CamelStore *store, | |||
| 811 | const gchar *top, | |||
| 812 | CamelStoreGetFolderInfoFlags flags, | |||
| 813 | GCancellable *cancellable, | |||
| 814 | GError **error) | |||
| 815 | { | |||
| 816 | CamelFolderInfo *fi = NULL((void*)0); | |||
| 817 | ||||
| 818 | if (top == NULL((void*)0) || top[0] == 0) { | |||
| 819 | /* create a dummy "." parent inbox, use to scan, then put back at the top level */ | |||
| 820 | fi = scan_fi (store, flags, "Inbox", _("Inbox")((char *) g_dgettext ("evolution-data-server", "Inbox")), cancellable); | |||
| 821 | if (scan_dirs (store, flags, TRUE(!(0)), &fi, cancellable, error) == -1) | |||
| 822 | goto fail; | |||
| 823 | ||||
| 824 | fi->flags |= CAMEL_FOLDER_SYSTEM | CAMEL_FOLDER_TYPE_INBOX; | |||
| 825 | } else if (!strcmp (top, ".")) { | |||
| 826 | fi = scan_fi (store, flags, "Inbox", _("Inbox")((char *) g_dgettext ("evolution-data-server", "Inbox")), cancellable); | |||
| 827 | fi->flags |= CAMEL_FOLDER_SYSTEM | CAMEL_FOLDER_TYPE_INBOX; | |||
| 828 | } else { | |||
| 829 | const gchar *name = strrchr (top, '/'); | |||
| 830 | ||||
| 831 | fi = scan_fi (store, flags, top, name ? name + 1 : top, cancellable); | |||
| 832 | if (g_strcmp0 (fi->full_name, CAMEL_VTRASH_NAME".#evolution/Trash") != 0 && | |||
| 833 | g_strcmp0 (fi->full_name, CAMEL_VJUNK_NAME".#evolution/Junk") != 0 && | |||
| 834 | scan_dirs (store, flags, FALSE(0), &fi, cancellable, error) == -1) | |||
| 835 | goto fail; | |||
| 836 | } | |||
| 837 | ||||
| 838 | return fi; | |||
| 839 | ||||
| 840 | fail: | |||
| 841 | camel_folder_info_free (fi); | |||
| 842 | ||||
| 843 | return NULL((void*)0); | |||
| 844 | } | |||
| 845 | ||||
| 846 | static CamelFolder * | |||
| 847 | maildir_store_get_inbox_sync (CamelStore *store, | |||
| 848 | GCancellable *cancellable, | |||
| 849 | GError **error) | |||
| 850 | { | |||
| 851 | return camel_store_get_folder_sync ( | |||
| 852 | store, "Inbox", CAMEL_STORE_FOLDER_CREATE, cancellable, error); | |||
| 853 | } | |||
| 854 | ||||
| 855 | static gboolean | |||
| 856 | rename_traverse_fi (CamelStore *store, | |||
| 857 | CamelStoreClass *store_class, | |||
| 858 | CamelFolderInfo *fi, | |||
| 859 | const gchar *old_full_name_prefix, | |||
| 860 | const gchar *new_full_name_prefix, | |||
| 861 | GCancellable *cancellable, | |||
| 862 | GError **error) | |||
| 863 | { | |||
| 864 | gint old_prefix_len = strlen (old_full_name_prefix); | |||
| 865 | gboolean ret = TRUE(!(0)); | |||
| 866 | ||||
| 867 | while (fi && ret) { | |||
| 868 | if (fi->full_name && g_str_has_prefix (fi->full_name, old_full_name_prefix)(__builtin_constant_p (old_full_name_prefix)? __extension__ ( { const char * const __str = (fi->full_name); const char * const __prefix = (old_full_name_prefix); gboolean __result = (0); if (__builtin_expect (__extension__ ({ int _g_boolean_var_31 = 0; if (__str == ((void*)0) || __prefix == ((void*)0)) _g_boolean_var_31 = 1; _g_boolean_var_31; }), 0)) __result = (g_str_has_prefix ) (__str, __prefix); else { const size_t __str_len = strlen ( ((__str) + !(__str))); const size_t __prefix_len = strlen ((( __prefix) + !(__prefix))); if (__str_len >= __prefix_len) __result = memcmp (((__str) + !(__str)), ((__prefix) + !(__prefix)), __prefix_len ) == 0; } __result; }) : (g_str_has_prefix) (fi->full_name , old_full_name_prefix) )) { | |||
| 869 | gchar *new_full_name, *old_dir, *new_dir; | |||
| 870 | ||||
| 871 | new_full_name = g_strconcat (new_full_name_prefix, fi->full_name + old_prefix_len, NULL((void*)0)); | |||
| 872 | old_dir = maildir_full_name_to_dir_name (CAMEL_MAILDIR_STORE (store)((((CamelMaildirStore*) (void *) ((store)))))->priv->can_escape_dots, fi->full_name); | |||
| 873 | new_dir = maildir_full_name_to_dir_name (CAMEL_MAILDIR_STORE (store)((((CamelMaildirStore*) (void *) ((store)))))->priv->can_escape_dots, new_full_name); | |||
| 874 | ||||
| 875 | /* Chain up to parent's rename_folder_sync() method. */ | |||
| 876 | ret = store_class->rename_folder_sync (store, old_dir, new_dir, cancellable, error); | |||
| 877 | ||||
| 878 | g_free (old_dir); | |||
| 879 | g_free (new_dir); | |||
| 880 | g_free (new_full_name); | |||
| 881 | } | |||
| 882 | ||||
| 883 | if (fi->child && !rename_traverse_fi (store, store_class, fi->child, old_full_name_prefix, new_full_name_prefix, cancellable, error)) | |||
| 884 | return FALSE(0); | |||
| 885 | ||||
| 886 | fi = fi->next; | |||
| 887 | } | |||
| 888 | ||||
| 889 | return ret; | |||
| 890 | } | |||
| 891 | ||||
| 892 | static gboolean | |||
| 893 | maildir_store_rename_folder_sync (CamelStore *store, | |||
| 894 | const gchar *old, | |||
| 895 | const gchar *new, | |||
| 896 | GCancellable *cancellable, | |||
| 897 | GError **error) | |||
| 898 | { | |||
| 899 | CamelStoreClass *store_class; | |||
| 900 | gboolean ret; | |||
| 901 | gchar *old_dir, *new_dir; | |||
| 902 | CamelFolderInfo *subfolders; | |||
| 903 | ||||
| 904 | if (strcmp (old, ".") == 0) { | |||
| 905 | g_set_error ( | |||
| 906 | error, CAMEL_STORE_ERROR(camel_store_error_quark ()), | |||
| 907 | CAMEL_STORE_ERROR_NO_FOLDER, | |||
| 908 | _("Cannot rename folder: %s: Invalid operation")((char *) g_dgettext ("evolution-data-server", "Cannot rename folder: %s: Invalid operation" )), | |||
| 909 | _("Inbox")((char *) g_dgettext ("evolution-data-server", "Inbox"))); | |||
| 910 | return FALSE(0); | |||
| 911 | } | |||
| 912 | ||||
| 913 | if (!g_ascii_strcasecmp (new, "Inbox")) { | |||
| 914 | g_set_error ( | |||
| 915 | error, CAMEL_STORE_ERROR(camel_store_error_quark ()), | |||
| 916 | CAMEL_STORE_ERROR_NO_FOLDER, | |||
| 917 | _("Folder %s already exists")((char *) g_dgettext ("evolution-data-server", "Folder %s already exists" )), new); | |||
| 918 | return FALSE(0); | |||
| 919 | } | |||
| 920 | ||||
| 921 | if (new && !CAMEL_MAILDIR_STORE (store)((((CamelMaildirStore*) (void *) ((store)))))->priv->can_escape_dots && strchr (new, HIER_SEP_CHAR'.')) { | |||
| 922 | g_set_error ( | |||
| 923 | error, CAMEL_STORE_ERROR(camel_store_error_quark ()), | |||
| 924 | CAMEL_STORE_ERROR_INVALID, | |||
| 925 | _("Cannot create folder containing “%s”")((char *) g_dgettext ("evolution-data-server", "Cannot create folder containing “%s”" )), HIER_SEP"."); | |||
| 926 | return FALSE(0); | |||
| 927 | } | |||
| 928 | ||||
| 929 | subfolders = maildir_store_get_folder_info_sync ( | |||
| 930 | store, old, | |||
| 931 | CAMEL_STORE_FOLDER_INFO_RECURSIVE | | |||
| 932 | CAMEL_STORE_FOLDER_INFO_NO_VIRTUAL, | |||
| 933 | cancellable, NULL((void*)0)); | |||
| 934 | ||||
| 935 | old_dir = maildir_full_name_to_dir_name (CAMEL_MAILDIR_STORE (store)((((CamelMaildirStore*) (void *) ((store)))))->priv->can_escape_dots, old); | |||
| 936 | new_dir = maildir_full_name_to_dir_name (CAMEL_MAILDIR_STORE (store)((((CamelMaildirStore*) (void *) ((store)))))->priv->can_escape_dots, new); | |||
| 937 | ||||
| 938 | /* Chain up to parent's rename_folder_sync() method. */ | |||
| 939 | store_class = CAMEL_STORE_CLASS (camel_maildir_store_parent_class)((((CamelStoreClass*) (void *) ((camel_maildir_store_parent_class ))))); | |||
| 940 | ret = store_class->rename_folder_sync ( | |||
| 941 | store, old_dir, new_dir, cancellable, error); | |||
| 942 | ||||
| 943 | if (subfolders) { | |||
| 944 | if (ret) | |||
| 945 | ret = rename_traverse_fi ( | |||
| 946 | store, store_class, | |||
| 947 | subfolders->child, | |||
| 948 | old, new, | |||
| 949 | cancellable, error); | |||
| 950 | ||||
| 951 | camel_folder_info_free (subfolders); | |||
| 952 | } | |||
| 953 | ||||
| 954 | g_free (old_dir); | |||
| 955 | g_free (new_dir); | |||
| 956 | ||||
| 957 | return ret; | |||
| 958 | } | |||
| 959 | ||||
| 960 | static void | |||
| 961 | camel_maildir_store_class_init (CamelMaildirStoreClass *class) | |||
| 962 | { | |||
| 963 | CamelStoreClass *store_class; | |||
| 964 | CamelLocalStoreClass *local_class; | |||
| 965 | ||||
| 966 | store_class = CAMEL_STORE_CLASS (class)((((CamelStoreClass*) (void *) ((class))))); | |||
| 967 | store_class->hash_folder_name = maildir_store_hash_folder_name; | |||
| 968 | store_class->equal_folder_name = maildir_store_equal_folder_name; | |||
| 969 | store_class->create_folder_sync = maildir_store_create_folder_sync; | |||
| 970 | store_class->get_folder_sync = maildir_store_get_folder_sync; | |||
| 971 | store_class->get_folder_info_sync = maildir_store_get_folder_info_sync; | |||
| 972 | store_class->get_inbox_folder_sync = maildir_store_get_inbox_sync; | |||
| 973 | store_class->delete_folder_sync = maildir_store_delete_folder_sync; | |||
| 974 | store_class->rename_folder_sync = maildir_store_rename_folder_sync; | |||
| 975 | ||||
| 976 | local_class = CAMEL_LOCAL_STORE_CLASS (class)((((CamelLocalStoreClass*) (void *) ((class))))); | |||
| 977 | local_class->get_full_path = maildir_get_full_path; | |||
| 978 | local_class->get_meta_path = maildir_get_meta_path; | |||
| 979 | } | |||
| 980 | ||||
| 981 | static void | |||
| 982 | camel_maildir_store_init (CamelMaildirStore *maildir_store) | |||
| 983 | { | |||
| 984 | maildir_store->priv = camel_maildir_store_get_instance_private (maildir_store); | |||
| 985 | maildir_store->priv->already_migrated = FALSE(0); | |||
| 986 | maildir_store->priv->can_escape_dots = TRUE(!(0)); | |||
| 987 | } | |||
| 988 | ||||
| 989 | static gchar * | |||
| 990 | maildir_get_full_path (CamelLocalStore *ls, | |||
| 991 | const gchar *full_name) | |||
| 992 | { | |||
| 993 | CamelLocalSettings *local_settings; | |||
| 994 | CamelSettings *settings; | |||
| 995 | CamelService *service; | |||
| 996 | gchar *filename; | |||
| 997 | gchar *dir_name; | |||
| 998 | gchar *path; | |||
| 999 | ||||
| 1000 | service = CAMEL_SERVICE (ls)((((CamelService*) (void *) ((ls))))); | |||
| 1001 | ||||
| 1002 | settings = camel_service_ref_settings (service); | |||
| 1003 | ||||
| 1004 | local_settings = CAMEL_LOCAL_SETTINGS (settings)((((CamelLocalSettings*) (void *) ((settings))))); | |||
| 1005 | path = camel_local_settings_dup_path (local_settings); | |||
| 1006 | ||||
| 1007 | g_object_unref (settings); | |||
| 1008 | ||||
| 1009 | dir_name = maildir_full_name_to_dir_name (CAMEL_MAILDIR_STORE (ls)((((CamelMaildirStore*) (void *) ((ls)))))->priv->can_escape_dots, full_name); | |||
| 1010 | filename = g_build_filename (path, dir_name, NULL((void*)0)); | |||
| 1011 | g_free (dir_name); | |||
| 1012 | ||||
| 1013 | g_free (path); | |||
| 1014 | ||||
| 1015 | return filename; | |||
| 1016 | } | |||
| 1017 | ||||
| 1018 | static gchar * | |||
| 1019 | maildir_get_meta_path (CamelLocalStore *ls, | |||
| 1020 | const gchar *full_name, | |||
| 1021 | const gchar *ext) | |||
| 1022 | { | |||
| 1023 | CamelLocalSettings *local_settings; | |||
| 1024 | CamelSettings *settings; | |||
| 1025 | CamelService *service; | |||
| 1026 | gchar *filename; | |||
| 1027 | gchar *dir_name; | |||
| 1028 | gchar *path; | |||
| 1029 | gchar *tmp; | |||
| 1030 | ||||
| 1031 | service = CAMEL_SERVICE (ls)((((CamelService*) (void *) ((ls))))); | |||
| 1032 | ||||
| 1033 | settings = camel_service_ref_settings (service); | |||
| 1034 | ||||
| 1035 | local_settings = CAMEL_LOCAL_SETTINGS (settings)((((CamelLocalSettings*) (void *) ((settings))))); | |||
| 1036 | path = camel_local_settings_dup_path (local_settings); | |||
| 1037 | ||||
| 1038 | g_object_unref (settings); | |||
| 1039 | ||||
| 1040 | dir_name = maildir_full_name_to_dir_name (CAMEL_MAILDIR_STORE (ls)((((CamelMaildirStore*) (void *) ((ls)))))->priv->can_escape_dots, full_name); | |||
| 1041 | tmp = g_build_filename (path, dir_name, NULL((void*)0)); | |||
| 1042 | filename = g_strconcat (tmp, ext, NULL((void*)0)); | |||
| 1043 | g_free (tmp); | |||
| 1044 | g_free (dir_name); | |||
| 1045 | ||||
| 1046 | g_free (path); | |||
| 1047 | ||||
| 1048 | return filename; | |||
| 1049 | } | |||
| 1050 | ||||
| 1051 | /* Migration from old to maildir++ hierarchy */ | |||
| 1052 | ||||
| 1053 | struct _scan_node { | |||
| 1054 | CamelFolderInfo *fi; | |||
| 1055 | ||||
| 1056 | dev_t dnode; | |||
| 1057 | ino_t inode; | |||
| 1058 | }; | |||
| 1059 | ||||
| 1060 | static guint | |||
| 1061 | scan_hash (gconstpointer d) | |||
| 1062 | { | |||
| 1063 | const struct _scan_node *v = d; | |||
| 1064 | ||||
| 1065 | return v->inode ^ v->dnode; | |||
| 1066 | } | |||
| 1067 | ||||
| 1068 | static gboolean | |||
| 1069 | scan_equal (gconstpointer a, | |||
| 1070 | gconstpointer b) | |||
| 1071 | { | |||
| 1072 | const struct _scan_node *v1 = a, *v2 = b; | |||
| 1073 | ||||
| 1074 | return v1->inode == v2->inode && v1->dnode == v2->dnode; | |||
| 1075 | } | |||
| 1076 | ||||
| 1077 | static void | |||
| 1078 | scan_free (gpointer k, | |||
| 1079 | gpointer v, | |||
| 1080 | gpointer d) | |||
| 1081 | { | |||
| 1082 | g_free (k); | |||
| 1083 | } | |||
| 1084 | ||||
| 1085 | static gint | |||
| 1086 | scan_old_dir_info (CamelStore *store, | |||
| 1087 | CamelFolderInfo *topfi, | |||
| 1088 | GError **error) | |||
| 1089 | { | |||
| 1090 | CamelLocalSettings *local_settings; | |||
| 1091 | CamelSettings *settings; | |||
| 1092 | CamelService *service; | |||
| 1093 | GQueue queue = G_QUEUE_INIT{ ((void*)0), ((void*)0), 0 }; | |||
| 1094 | struct _scan_node *sn; | |||
| 1095 | gchar *path; | |||
| 1096 | gchar *tmp; | |||
| 1097 | GHashTable *visited; | |||
| 1098 | struct stat st; | |||
| 1099 | gint res = -1; | |||
| 1100 | ||||
| 1101 | service = CAMEL_SERVICE (store)((((CamelService*) (void *) ((store))))); | |||
| 1102 | ||||
| 1103 | settings = camel_service_ref_settings (service); | |||
| 1104 | ||||
| 1105 | local_settings = CAMEL_LOCAL_SETTINGS (settings)((((CamelLocalSettings*) (void *) ((settings))))); | |||
| 1106 | path = camel_local_settings_dup_path (local_settings); | |||
| 1107 | ||||
| 1108 | g_object_unref (settings); | |||
| 1109 | ||||
| 1110 | visited = g_hash_table_new (scan_hash, scan_equal); | |||
| 1111 | ||||
| 1112 | sn = g_malloc0 (sizeof (*sn)); | |||
| 1113 | sn->fi = topfi; | |||
| 1114 | g_queue_push_tail (&queue, sn); | |||
| 1115 | g_hash_table_insert (visited, sn, sn); | |||
| 1116 | ||||
| 1117 | while (!g_queue_is_empty (&queue)) { | |||
| 1118 | gchar *name; | |||
| 1119 | DIR *dir; | |||
| 1120 | struct dirent *d; | |||
| 1121 | CamelFolderInfo *last; | |||
| 1122 | ||||
| 1123 | sn = g_queue_pop_head (&queue); | |||
| 1124 | ||||
| 1125 | last = (CamelFolderInfo *) &sn->fi->child; | |||
| 1126 | ||||
| 1127 | if (!strcmp (sn->fi->full_name, ".")) | |||
| 1128 | name = g_strdup (path)g_strdup_inline (path); | |||
| 1129 | else | |||
| 1130 | name = g_build_filename (path, sn->fi->full_name, NULL((void*)0)); | |||
| 1131 | ||||
| 1132 | dir = opendir (name); | |||
| 1133 | if (dir == NULL((void*)0)) { | |||
| 1134 | g_free (name); | |||
| 1135 | g_set_error ( | |||
| 1136 | error, G_IO_ERRORg_io_error_quark(), | |||
| 1137 | g_io_error_from_errno (errno(*__errno_location ())), | |||
| 1138 | _("Could not scan folder “%s”: %s")((char *) g_dgettext ("evolution-data-server", "Could not scan folder “%s”: %s" )), | |||
| 1139 | path, g_strerror (errno(*__errno_location ()))); | |||
| 1140 | goto exit; | |||
| 1141 | } | |||
| 1142 | ||||
| 1143 | while ((d = readdir (dir))) { | |||
| 1144 | if (strcmp (d->d_name, "tmp") == 0 | |||
| 1145 | || strcmp (d->d_name, "cur") == 0 | |||
| 1146 | || strcmp (d->d_name, "new") == 0 | |||
| 1147 | || strcmp (d->d_name, ".#evolution") == 0 | |||
| 1148 | || strcmp (d->d_name, ".") == 0 | |||
| 1149 | || strcmp (d->d_name, "..") == 0) | |||
| 1150 | continue; | |||
| 1151 | ||||
| 1152 | tmp = g_build_filename (name, d->d_name, NULL((void*)0)); | |||
| 1153 | if (stat (tmp, &st) == 0 && S_ISDIR (st.st_mode)((((st.st_mode)) & 0170000) == (0040000))) { | |||
| 1154 | struct _scan_node in; | |||
| 1155 | ||||
| 1156 | memset (&in, 0, sizeof (struct _scan_node)); | |||
| 1157 | in.dnode = st.st_dev; | |||
| 1158 | in.inode = st.st_ino; | |||
| 1159 | ||||
| 1160 | /* see if we've visited already */ | |||
| 1161 | if (g_hash_table_lookup (visited, &in) == NULL((void*)0)) { | |||
| 1162 | struct _scan_node *snew = g_malloc (sizeof (*snew)); | |||
| 1163 | gchar *full; | |||
| 1164 | CamelFolderInfo *fi = NULL((void*)0); | |||
| 1165 | ||||
| 1166 | snew->dnode = in.dnode; | |||
| 1167 | snew->inode = in.inode; | |||
| 1168 | ||||
| 1169 | if (!strcmp (sn->fi->full_name, ".")) | |||
| 1170 | full = g_strdup (d->d_name)g_strdup_inline (d->d_name); | |||
| 1171 | else | |||
| 1172 | full = g_strdup_printf ("%s/%s", sn->fi->full_name, d->d_name); | |||
| 1173 | ||||
| 1174 | fi = camel_folder_info_new (); | |||
| 1175 | fi->full_name = full; | |||
| 1176 | fi->display_name = g_strdup (d->d_name)g_strdup_inline (d->d_name); | |||
| 1177 | snew->fi = fi; | |||
| 1178 | ||||
| 1179 | last->next = snew->fi; | |||
| 1180 | last = snew->fi; | |||
| 1181 | snew->fi->parent = sn->fi; | |||
| 1182 | ||||
| 1183 | g_hash_table_insert (visited, snew, snew); | |||
| 1184 | g_queue_push_tail (&queue, snew); | |||
| 1185 | } | |||
| 1186 | } | |||
| 1187 | g_free (tmp); | |||
| 1188 | } | |||
| 1189 | closedir (dir); | |||
| 1190 | g_free (name); | |||
| 1191 | } | |||
| 1192 | ||||
| 1193 | res = 0; | |||
| 1194 | ||||
| 1195 | exit: | |||
| 1196 | g_hash_table_foreach (visited, scan_free, NULL((void*)0)); | |||
| 1197 | g_hash_table_destroy (visited); | |||
| 1198 | ||||
| 1199 | g_free (path); | |||
| 1200 | ||||
| 1201 | return res; | |||
| 1202 | } | |||
| 1203 | ||||
| 1204 | static void | |||
| 1205 | maildir_maybe_rename_old_folder (CamelMaildirStore *mstore, | |||
| 1206 | CamelFolderInfo *fi, | |||
| 1207 | gint maildir_version, | |||
| 1208 | GCancellable *cancellable, | |||
| 1209 | GError **error) | |||
| 1210 | { | |||
| 1211 | gchar *new_name = NULL((void*)0); | |||
| 1212 | ||||
| 1213 | if (g_str_equal (fi->full_name, ".")(strcmp ((const char *) (fi->full_name), (const char *) ("." )) == 0) || g_str_equal (fi->full_name, "..")(strcmp ((const char *) (fi->full_name), (const char *) (".." )) == 0)) | |||
| 1214 | return; | |||
| 1215 | ||||
| 1216 | if (maildir_version == -1) { | |||
| 1217 | /* this is when maildir was not converted yet to maildir++ at all, | |||
| 1218 | * the '_' and '.' are still there and the dir separator is slash | |||
| 1219 | */ | |||
| 1220 | new_name = maildir_full_name_to_dir_name (mstore->priv->can_escape_dots, fi->full_name); | |||
| 1221 | } else if (maildir_version == 0) { | |||
| 1222 | /* this is a conversion with maildir folder being already there, | |||
| 1223 | * only with no version; there should be escaped only '_', because | |||
| 1224 | * the '.' is already garbled; | |||
| 1225 | * fi->full_name is a dir name here | |||
| 1226 | */ | |||
| 1227 | gchar *full_name; | |||
| 1228 | ||||
| 1229 | if (!g_ascii_strncasecmp (fi->full_name, "..", 2)) | |||
| 1230 | full_name = g_strconcat ("Inbox/", fi->full_name + 2, NULL((void*)0)); | |||
| 1231 | else if (fi->full_name[0] == '.') | |||
| 1232 | full_name = g_strdup (fi->full_name + 1)g_strdup_inline (fi->full_name + 1); | |||
| 1233 | else | |||
| 1234 | full_name = g_strdup (fi->full_name)g_strdup_inline (fi->full_name); | |||
| 1235 | ||||
| 1236 | g_strdelimit (full_name, HIER_SEP".", '/'); | |||
| 1237 | ||||
| 1238 | new_name = maildir_full_name_to_dir_name (mstore->priv->can_escape_dots, full_name); | |||
| 1239 | ||||
| 1240 | g_free (full_name); | |||
| 1241 | } else { | |||
| 1242 | return; | |||
| 1243 | } | |||
| 1244 | ||||
| 1245 | if (!g_str_equal (fi->full_name, new_name)(strcmp ((const char *) (fi->full_name), (const char *) (new_name )) == 0)) { | |||
| 1246 | CamelStoreClass *store_class; | |||
| 1247 | GError *local_error = NULL((void*)0); | |||
| 1248 | ||||
| 1249 | store_class = CAMEL_STORE_CLASS (camel_maildir_store_parent_class)((((CamelStoreClass*) (void *) ((camel_maildir_store_parent_class ))))); | |||
| 1250 | /* Do not propagate these errors, only warn about them on console */ | |||
| 1251 | store_class->rename_folder_sync ((CamelStore *) mstore, fi->full_name, new_name, cancellable, &local_error); | |||
| 1252 | ||||
| 1253 | if (local_error) { | |||
| 1254 | g_warning ("%s: Failed to rename '%s' to '%s': %s", G_STRFUNC((const char*) (__func__)), fi->full_name, new_name, local_error->message); | |||
| 1255 | g_error_free (local_error); | |||
| 1256 | } | |||
| 1257 | } | |||
| 1258 | ||||
| 1259 | g_free (new_name); | |||
| 1260 | } | |||
| 1261 | ||||
| 1262 | static void | |||
| 1263 | traverse_rename_folder_info (CamelMaildirStore *mstore, | |||
| 1264 | CamelFolderInfo *fi, | |||
| 1265 | gint maildir_version, | |||
| 1266 | GCancellable *cancellable, | |||
| 1267 | GError **error) | |||
| 1268 | { | |||
| 1269 | while (fi != NULL((void*)0)) { | |||
| 1270 | if (fi->child) | |||
| 1271 | traverse_rename_folder_info (mstore, fi->child, maildir_version, cancellable, error); | |||
| 1272 | ||||
| 1273 | maildir_maybe_rename_old_folder (mstore, fi, maildir_version, cancellable, error); | |||
| 1274 | ||||
| 1275 | fi = fi->next; | |||
| 1276 | } | |||
| 1277 | } | |||
| 1278 | ||||
| 1279 | static gboolean | |||
| 1280 | maildir_version_requires_migrate (const gchar *meta_filename, | |||
| 1281 | gboolean *file_exists, | |||
| 1282 | gint *maildir_version) | |||
| 1283 | { | |||
| 1284 | FILE *metafile; | |||
| 1285 | gint cc; | |||
| 1286 | gint verpos = 0; | |||
| 1287 | gboolean res = FALSE(0); | |||
| 1288 | ||||
| 1289 | g_return_val_if_fail (meta_filename != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_32 = 0; if (meta_filename != ((void*)0)) _g_boolean_var_32 = 1; _g_boolean_var_32; }), 1))) { } else { g_return_if_fail_warning ("camel-local-provider", ((const char*) (__func__)), "meta_filename != NULL" ); return ((0)); } } while (0); | |||
| 1290 | g_return_val_if_fail (file_exists != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_33 = 0; if (file_exists != ((void*)0)) _g_boolean_var_33 = 1; _g_boolean_var_33 ; }), 1))) { } else { g_return_if_fail_warning ("camel-local-provider" , ((const char*) (__func__)), "file_exists != NULL"); return ( (0)); } } while (0); | |||
| 1291 | g_return_val_if_fail (maildir_version != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_34 = 0; if (maildir_version != ((void*)0)) _g_boolean_var_34 = 1 ; _g_boolean_var_34; }), 1))) { } else { g_return_if_fail_warning ("camel-local-provider", ((const char*) (__func__)), "maildir_version != NULL" ); return ((0)); } } while (0); | |||
| 1292 | ||||
| 1293 | /* nonexistent file is -1 */ | |||
| 1294 | *maildir_version = -1; | |||
| 1295 | *file_exists = FALSE(0); | |||
| 1296 | ||||
| 1297 | if (!g_file_test (meta_filename, G_FILE_TEST_EXISTS)) | |||
| 1298 | return TRUE(!(0)); | |||
| 1299 | ||||
| 1300 | /* existing file without version is 0 */ | |||
| 1301 | *maildir_version = 0; | |||
| 1302 | *file_exists = TRUE(!(0)); | |||
| 1303 | ||||
| 1304 | metafile = fopen (meta_filename, "rb"); | |||
| 1305 | if (!metafile
| |||
| 1306 | return FALSE(0); | |||
| 1307 | ||||
| 1308 | while (cc = fgetc (metafile), !res
| |||
| ||||
| 1309 | if (verpos
| |||
| 1310 | if (cc >= '0' && cc <= '9') { | |||
| 1311 | (*maildir_version) = (*maildir_version) * 10 + cc - '0'; | |||
| 1312 | } else if (cc == ' ' || cc == '\n' || cc == '\r' || cc == '\t') { | |||
| 1313 | break; | |||
| 1314 | } else { | |||
| 1315 | res = TRUE(!(0)); | |||
| 1316 | } | |||
| 1317 | } else if (cc == MAILDIR_CONTENT_VERSION_STR"maildir++ 1"[verpos]) { | |||
| 1318 | verpos++; | |||
| 1319 | } else { | |||
| 1320 | res = TRUE(!(0)); | |||
| 1321 | } | |||
| 1322 | } | |||
| 1323 | ||||
| 1324 | fclose (metafile); | |||
| 1325 | ||||
| 1326 | return res || (*maildir_version) < MAILDIR_CONTENT_VERSION1; | |||
| 1327 | } | |||
| 1328 | ||||
| 1329 | static void | |||
| 1330 | maildir_migrate_hierarchy (CamelMaildirStore *mstore, | |||
| 1331 | gint maildir_version, | |||
| 1332 | GCancellable *cancellable, | |||
| 1333 | GError **error) | |||
| 1334 | { | |||
| 1335 | CamelFolderInfo *topfi; | |||
| 1336 | gchar *meta_path = NULL((void*)0), *ptr; | |||
| 1337 | ||||
| 1338 | g_return_if_fail (mstore->priv->can_escape_dots)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_35 = 0; if (mstore->priv->can_escape_dots) _g_boolean_var_35 = 1; _g_boolean_var_35; }), 1))) { } else { g_return_if_fail_warning ("camel-local-provider", ((const char*) (__func__)), "mstore->priv->can_escape_dots" ); return; } } while (0); | |||
| 1339 | ||||
| 1340 | topfi = camel_folder_info_new (); | |||
| 1341 | topfi->full_name = g_strdup (".")g_strdup_inline ("."); | |||
| 1342 | topfi->display_name = g_strdup ("Inbox")g_strdup_inline ("Inbox"); | |||
| 1343 | ||||
| 1344 | if (scan_old_dir_info ((CamelStore *) mstore, topfi, error) == -1) { | |||
| 1345 | g_warning ("%s: Failed to scan the old folder info", G_STRFUNC((const char*) (__func__))); | |||
| 1346 | goto done; | |||
| 1347 | } | |||
| 1348 | ||||
| 1349 | meta_path = maildir_get_meta_path ((CamelLocalStore *) mstore, "?", "maildir++"); | |||
| 1350 | ptr = strrchr (meta_path, '?'); | |||
| 1351 | g_return_if_fail (ptr != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_36 = 0; if (ptr != ((void*)0)) _g_boolean_var_36 = 1; _g_boolean_var_36 ; }), 1))) { } else { g_return_if_fail_warning ("camel-local-provider" , ((const char*) (__func__)), "ptr != NULL"); return; } } while (0); | |||
| 1352 | ||||
| 1353 | /* cannot pass dot inside maildir_get_meta_path(), because it is escaped */ | |||
| 1354 | ptr[0] = '.'; | |||
| 1355 | ||||
| 1356 | /* First create/overwrite the file, only then do the migration, otherwise, | |||
| 1357 | if the file creation fails, the folder structure would be migrated repeatedly. */ | |||
| 1358 | if (!g_file_set_contents (meta_path, MAILDIR_CONTENT_VERSION_STR"maildir++ 1", -1, error) || (error && *error)) { | |||
| 1359 | g_warning ("Failed to save the maildir version in ‘%s’.", meta_path); | |||
| 1360 | goto done; | |||
| 1361 | } | |||
| 1362 | ||||
| 1363 | if (maildir_version < 1) { | |||
| 1364 | traverse_rename_folder_info (mstore, topfi, maildir_version, cancellable, error); | |||
| 1365 | } | |||
| 1366 | ||||
| 1367 | done: | |||
| 1368 | camel_folder_info_free (topfi); | |||
| 1369 | g_free (meta_path); | |||
| 1370 | } | |||
| 1371 | ||||
| 1372 | gchar | |||
| 1373 | camel_maildir_store_get_filename_flag_sep (CamelMaildirStore *maildir_store) | |||
| 1374 | { | |||
| 1375 | g_return_val_if_fail (CAMEL_IS_MAILDIR_STORE (maildir_store), CAMEL_MAILDIR_FILENAME_FLAG_SEP)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_37 = 0; if ((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((maildir_store)); GType __t = ((camel_maildir_store_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst-> g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; }))))) _g_boolean_var_37 = 1; _g_boolean_var_37; }), 1) )) { } else { g_return_if_fail_warning ("camel-local-provider" , ((const char*) (__func__)), "CAMEL_IS_MAILDIR_STORE (maildir_store)" ); return (':'); } } while (0); | |||
| 1376 | ||||
| 1377 | /* Populate the value on the first access. It's too early in the constructed(), | |||
| 1378 | the settings might not be read there yet. */ | |||
| 1379 | if (!maildir_store->priv->filename_flag_sep) { | |||
| 1380 | CamelSettings *settings; | |||
| 1381 | ||||
| 1382 | settings = camel_service_ref_settings (CAMEL_SERVICE (maildir_store)((((CamelService*) (void *) ((maildir_store)))))); | |||
| 1383 | ||||
| 1384 | if (camel_local_settings_get_maildir_alt_flag_sep (CAMEL_LOCAL_SETTINGS (settings)((((CamelLocalSettings*) (void *) ((settings))))))) { | |||
| 1385 | maildir_store->priv->filename_flag_sep = CAMEL_MAILDIR_FILENAME_FLAG_SEP_ALT'!'; | |||
| 1386 | } else { | |||
| 1387 | maildir_store->priv->filename_flag_sep = CAMEL_MAILDIR_FILENAME_FLAG_SEP':'; | |||
| 1388 | } | |||
| 1389 | ||||
| 1390 | g_clear_object (&settings)do { _Static_assert (sizeof *((&settings)) == sizeof (gpointer ), "Expression evaluates to false"); __typeof__ (((&settings ))) _pp = ((&settings)); __typeof__ (*((&settings))) _ptr = *_pp; *_pp = ((void*)0); if (_ptr) (g_object_unref) (_ptr) ; } while (0); | |||
| 1391 | } | |||
| 1392 | ||||
| 1393 | return maildir_store->priv->filename_flag_sep; | |||
| 1394 | } |