diff options
Diffstat (limited to 'camel/providers/local/camel-mbox-store.c')
-rw-r--r-- | camel/providers/local/camel-mbox-store.c | 753 |
1 files changed, 0 insertions, 753 deletions
diff --git a/camel/providers/local/camel-mbox-store.c b/camel/providers/local/camel-mbox-store.c deleted file mode 100644 index ffce19171f..0000000000 --- a/camel/providers/local/camel-mbox-store.c +++ /dev/null @@ -1,753 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * - * Authors: Michael Zucchi <notzed@ximian.com> - * - * Copyright (C) 2000 Ximian, Inc. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <string.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <unistd.h> -#include <dirent.h> -#include <fcntl.h> -#include <errno.h> - -#include "camel-mbox-store.h" -#include "camel-mbox-folder.h" -#include "camel-file-utils.h" -#include "camel-text-index.h" -#include "camel-exception.h" -#include "camel-url.h" - -#define d(x) - -static CamelLocalStoreClass *parent_class = NULL; - -/* Returns the class for a CamelMboxStore */ -#define CMBOXS_CLASS(so) CAMEL_MBOX_STORE_CLASS (CAMEL_OBJECT_GET_CLASS(so)) -#define CF_CLASS(so) CAMEL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(so)) -#define CMBOXF_CLASS(so) CAMEL_MBOX_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(so)) - -extern char *camel_mbox_folder_get_full_path (const char *toplevel_dir, const char *full_name); -extern char *camel_mbox_folder_get_meta_path (const char *toplevel_dir, const char *full_name, const char *ext); - -static CamelFolder *get_folder(CamelStore *store, const char *folder_name, guint32 flags, CamelException *ex); -static void delete_folder(CamelStore *store, const char *folder_name, CamelException *ex); -static void rename_folder (CamelStore *store, const char *old, const char *new, CamelException *ex); -static CamelFolderInfo *create_folder (CamelStore *store, const char *parent_name, const char *folder_name, CamelException *ex); -static CamelFolderInfo *get_folder_info (CamelStore *store, const char *top, guint32 flags, CamelException *ex); - -static void -camel_mbox_store_class_init (CamelMboxStoreClass *camel_mbox_store_class) -{ - CamelStoreClass *camel_store_class = CAMEL_STORE_CLASS (camel_mbox_store_class); - - parent_class = (CamelLocalStoreClass *)camel_type_get_global_classfuncs(camel_local_store_get_type()); - - /* virtual method overload */ - camel_store_class->get_folder = get_folder; - camel_store_class->delete_folder = delete_folder; - camel_store_class->rename_folder = rename_folder; - camel_store_class->create_folder = create_folder; - - camel_store_class->get_folder_info = get_folder_info; - camel_store_class->free_folder_info = camel_store_free_folder_info_full; -} - -CamelType -camel_mbox_store_get_type (void) -{ - static CamelType camel_mbox_store_type = CAMEL_INVALID_TYPE; - - if (camel_mbox_store_type == CAMEL_INVALID_TYPE) { - camel_mbox_store_type = camel_type_register (CAMEL_LOCAL_STORE_TYPE, "CamelMboxStore", - sizeof (CamelMboxStore), - sizeof (CamelMboxStoreClass), - (CamelObjectClassInitFunc) camel_mbox_store_class_init, - NULL, - NULL, - NULL); - } - - return camel_mbox_store_type; -} - -static char * -mbox_folder_name_to_path (CamelStore *store, const char *folder_name) -{ - const char *toplevel_dir = CAMEL_LOCAL_STORE (store)->toplevel_dir; - - return camel_mbox_folder_get_full_path (toplevel_dir, folder_name); -} - -static char * -mbox_folder_name_to_meta_path (CamelStore *store, const char *folder_name, const char *ext) -{ - const char *toplevel_dir = CAMEL_LOCAL_STORE (store)->toplevel_dir; - - return camel_mbox_folder_get_meta_path (toplevel_dir, folder_name, ext); -} - -static char *extensions[] = { - ".msf", ".ev-summary", ".ibex.index", ".ibex.index.data", ".cmeta" -}; - -static gboolean -ignore_file (const char *filename, gboolean sbd) -{ - int flen, len, i; - - flen = strlen (filename); - for (i = 0; i < (sizeof (extensions) / sizeof (extensions[0])); i++) { - len = strlen (extensions[i]); - if (len < flen && !strcmp (filename + flen - len, extensions[i])) - return TRUE; - } - - if (sbd && flen > 4 && !strcmp (filename + flen - 4, ".sbd")) - return TRUE; - - return FALSE; -} - -static CamelFolder * -get_folder (CamelStore *store, const char *folder_name, guint32 flags, CamelException *ex) -{ - struct stat st; - char *name; - - if (!((CamelStoreClass *) parent_class)->get_folder (store, folder_name, flags, ex)) - return NULL; - - name = mbox_folder_name_to_path (store, folder_name); - - if (stat (name, &st) == -1) { - char *dirname; - int fd; - - if (errno != ENOENT) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not open file `%s':\n%s"), - name, g_strerror (errno)); - g_free (name); - return NULL; - } - - if ((flags & CAMEL_STORE_FOLDER_CREATE) == 0) { - camel_exception_setv (ex, CAMEL_EXCEPTION_STORE_NO_FOLDER, - _("Folder `%s' does not exist."), - folder_name); - g_free (name); - return NULL; - } - - dirname = g_path_get_dirname (name); - if (camel_mkdir (dirname, 0777) == -1 && errno != EEXIST) { - camel_exception_setv (ex, CAMEL_EXCEPTION_STORE_NO_FOLDER, - _("Could not create directory `%s':\n%s"), - dirname, g_strerror (errno)); - g_free (dirname); - g_free (name); - return NULL; - } - - g_free (dirname); - - fd = open (name, O_WRONLY | O_CREAT | O_APPEND, 0666); - if (fd == -1) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not create file `%s':\n%s"), - name, g_strerror (errno)); - g_free (name); - return NULL; - } - - g_free (name); - close (fd); - } else if (!S_ISREG (st.st_mode)) { - camel_exception_setv (ex, CAMEL_EXCEPTION_STORE_NO_FOLDER, - _("`%s' is not a regular file."), - name); - g_free (name); - return NULL; - } else - g_free (name); - - return camel_mbox_folder_new (store, folder_name, flags, ex); -} - -static void -delete_folder (CamelStore *store, const char *folder_name, CamelException *ex) -{ - CamelFolderInfo *fi; - CamelException lex; - CamelFolder *lf; - char *name, *path; - struct stat st; - - name = mbox_folder_name_to_path (store, folder_name); - path = g_strdup_printf ("%s.sbd", name); - - if (rmdir (path) == -1 && errno != ENOENT) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not delete folder `%s':\n%s"), - folder_name, g_strerror (errno)); - g_free (path); - g_free (name); - return; - } - - g_free (path); - - if (stat (name, &st) == -1) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not delete folder `%s':\n%s"), - folder_name, g_strerror (errno)); - g_free (name); - return; - } - - if (!S_ISREG (st.st_mode)) { - camel_exception_setv (ex, CAMEL_EXCEPTION_STORE_NO_FOLDER, - _("`%s' is not a regular file."), name); - g_free (name); - return; - } - - if (st.st_size != 0) { - camel_exception_setv (ex, CAMEL_EXCEPTION_FOLDER_NON_EMPTY, - _("Folder `%s' is not empty. Not deleted."), - folder_name); - g_free (name); - return; - } - - if (unlink (name) == -1 && errno != ENOENT) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not delete folder `%s':\n%s"), - name, g_strerror (errno)); - g_free (name); - return; - } - - /* FIXME: we have to do our own meta cleanup here rather than - * calling our parent class' delete_folder() method since our - * naming convention is different. Need to find a way for - * CamelLocalStore to be able to construct the folder & meta - * paths itself */ - path = mbox_folder_name_to_meta_path (store, folder_name, ".ev-summary"); - if (unlink (path) == -1 && errno != ENOENT) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not delete folder summary file `%s': %s"), - path, g_strerror (errno)); - g_free (path); - g_free (name); - return; - } - - g_free (path); - - path = mbox_folder_name_to_meta_path (store, folder_name, ".ibex"); - if (camel_text_index_remove (path) == -1 && errno != ENOENT) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not delete folder index file `%s': %s"), - path, g_strerror (errno)); - g_free (path); - g_free (name); - return; - } - - g_free (path); - - camel_exception_init (&lex); - if ((lf = camel_store_get_folder (store, folder_name, 0, &lex))) { - camel_object_get (lf, NULL, CAMEL_OBJECT_STATE_FILE, &path, NULL); - camel_object_set (lf, NULL, CAMEL_OBJECT_STATE_FILE, NULL, NULL); - camel_object_unref (lf); - } else { - camel_exception_clear (&lex); - } - - if (path == NULL) - path = mbox_folder_name_to_meta_path (store, folder_name, ".cmeta"); - - if (unlink (path) == -1 && errno != ENOENT) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not delete folder meta file `%s': %s"), - path, g_strerror (errno)); - - g_free (path); - g_free (name); - return; - } - - g_free (path); - g_free (name); - - fi = g_new0 (CamelFolderInfo, 1); - fi->full_name = g_strdup (folder_name); - fi->name = g_path_get_basename (folder_name); - fi->url = g_strdup_printf ("mbox:%s#%s", ((CamelService *) store)->url->path, folder_name); - fi->unread_message_count = -1; - camel_folder_info_build_path (fi, '/'); - - camel_object_trigger_event (store, "folder_deleted", fi); - - camel_folder_info_free (fi); -} - -static CamelFolderInfo * -create_folder (CamelStore *store, const char *parent_name, const char *folder_name, CamelException *ex) -{ - /* FIXME: this is almost an exact copy of CamelLocalStore::create_folder() except that we use - * different path schemes... need to find a way to share parent's code? */ - const char *toplevel_dir = ((CamelLocalStore *) store)->toplevel_dir; - CamelFolderInfo *info = NULL; - char *path, *name, *dir; - CamelFolder *folder; - struct stat st; - - if (toplevel_dir[0] != '/') { - camel_exception_setv (ex, CAMEL_EXCEPTION_STORE_NO_FOLDER, - _("Store root %s is not an absolute path"), toplevel_dir); - return NULL; - } - - if (folder_name[0] == '.' || ignore_file (folder_name, TRUE)) { - camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, - _("Cannot create a folder by this name.")); - return NULL; - } - - if (parent_name && *parent_name) - name = g_strdup_printf ("%s/%s", parent_name, folder_name); - else - name = g_strdup (folder_name); - - path = mbox_folder_name_to_path (store, name); - - dir = g_path_get_dirname (path); - if (camel_mkdir (dir, 0777) == -1 && errno != EEXIST) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot create directory `%s': %s."), - dir, g_strerror (errno)); - - g_free (path); - g_free (name); - g_free (dir); - - return NULL; - } - - g_free (dir); - - if (stat (path, &st) == 0 || errno != ENOENT) { - camel_exception_setv (ex, CAMEL_EXCEPTION_STORE_NO_FOLDER, - _("Cannot create folder: %s: %s"), - path, errno ? g_strerror (errno) : - _("Folder already exists")); - - g_free (path); - g_free (name); - - return NULL; - } - - g_free (path); - - folder = ((CamelStoreClass *) ((CamelObject *) store)->klass)->get_folder (store, name, CAMEL_STORE_FOLDER_CREATE, ex); - if (folder) { - camel_object_unref (folder); - info = ((CamelStoreClass *) ((CamelObject *) store)->klass)->get_folder_info (store, name, 0, ex); - } - - g_free (name); - - return info; -} - -static int -xrename (CamelStore *store, const char *old_name, const char *new_name, const char *ext, gboolean missingok, CamelException *ex) -{ - const char *toplevel_dir = ((CamelLocalStore *) store)->toplevel_dir; - char *oldpath, *newpath; - struct stat st; - int ret = -1; - int err = 0; - - if (ext != NULL) { - oldpath = camel_mbox_folder_get_meta_path (toplevel_dir, old_name, ext); - newpath = camel_mbox_folder_get_meta_path (toplevel_dir, new_name, ext); - } else { - oldpath = camel_mbox_folder_get_full_path (toplevel_dir, old_name); - newpath = camel_mbox_folder_get_full_path (toplevel_dir, new_name); - } - - if (stat (oldpath, &st) == -1) { - if (missingok && errno == ENOENT) { - ret = 0; - } else { - err = errno; - ret = -1; - } - } else if (S_ISDIR (st.st_mode)) { - /* use rename for dirs */ - if (rename (oldpath, newpath) == 0 || stat (newpath, &st) == 0) { - ret = 0; - } else { - err = errno; - ret = -1; - } - } else if (link (oldpath, newpath) == 0 /* and link for files */ - || (stat (newpath, &st) == 0 && st.st_nlink == 2)) { - if (unlink (oldpath) == 0) { - ret = 0; - } else { - err = errno; - unlink (newpath); - ret = -1; - } - } else { - err = errno; - ret = -1; - } - - if (ret == -1) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not rename %s to %s: %s"), - oldpath, newpath, g_strerror (err)); - } - - g_free (oldpath); - g_free (newpath); - - return ret; -} - -static void -rename_folder (CamelStore *store, const char *old, const char *new, CamelException *ex) -{ - CamelLocalFolder *folder = NULL; - char *oldibex, *newibex; - - if (new[0] == '.' || ignore_file (new, TRUE)) { - printf ("exception: The new folder name is illegal.\n"); - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("The new folder name is illegal.")); - return; - } - - /* try to rollback failures, has obvious races */ - - oldibex = mbox_folder_name_to_meta_path (store, old, ".ibex"); - newibex = mbox_folder_name_to_meta_path (store, new, ".ibex"); - - folder = camel_object_bag_get (store->folders, old); - if (folder && folder->index) { - if (camel_index_rename (folder->index, newibex) == -1) - goto ibex_failed; - } else { - /* TODO: camel_text_index_rename should find out if we have an active index itself? */ - if (camel_text_index_rename (oldibex, newibex) == -1) - goto ibex_failed; - } - - if (xrename (store, old, new, ".ev-summary", TRUE, ex)) - goto summary_failed; - - if (xrename (store, old, new, NULL, FALSE, ex)) - goto base_failed; - - g_free (oldibex); - g_free (newibex); - - if (folder) - camel_object_unref (folder); - - return; - - base_failed: - - xrename (store, new, old, ".ev-summary", TRUE, ex); - - summary_failed: - - if (folder) { - if (folder->index) - camel_index_rename (folder->index, oldibex); - } else - camel_text_index_rename (newibex, oldibex); - ibex_failed: - - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not rename '%s': %s"), - old, g_strerror (errno)); - - g_free (newibex); - g_free (oldibex); - - if (folder) - camel_object_unref (folder); -} - - -/* used to find out where we've visited already */ -struct _inode { - dev_t dnode; - ino_t inode; -}; - -static guint -inode_hash (const void *d) -{ - const struct _inode *v = d; - - return v->inode ^ v->dnode; -} - -static gboolean -inode_equal (const void *a, const void *b) -{ - const struct _inode *v1 = a, *v2 = b; - - return v1->inode == v2->inode && v1->dnode == v2->dnode; -} - -static void -inode_free (void *k, void *v, void *d) -{ - g_free (k); -} - -static CamelFolderInfo * -scan_dir (CamelStore *store, GHashTable *visited, CamelFolderInfo *parent, const char *root, - const char *name, guint32 flags, CamelException *ex) -{ - CamelFolderInfo *folders, *tail, *fi; - GHashTable *folder_hash; - struct dirent *dent; - DIR *dir; - - tail = folders = NULL; - - if (!(dir = opendir (root))) - return NULL; - - folder_hash = g_hash_table_new (g_str_hash, g_str_equal); - - /* FIXME: it would be better if we queue'd up the recursive - * scans till the end so that we can limit the number of - * directory descriptors open at any given time... */ - - while ((dent = readdir (dir))) { - char *short_name, *full_name, *path, *ext; - CamelFolder *folder; - struct stat st; - int unread = -1; - - if (dent->d_name[0] == '.') - continue; - - if (ignore_file (dent->d_name, FALSE)) - continue; - - path = g_strdup_printf ("%s/%s", root, dent->d_name); - if (stat (path, &st) == -1) { - g_free (path); - continue; - } - - if (S_ISDIR (st.st_mode)) { - struct _inode in = { st.st_dev, st.st_ino }; - - if (g_hash_table_lookup (visited, &in)) { - g_free (path); - continue; - } - } - - short_name = g_strdup (dent->d_name); - if ((ext = strrchr (short_name, '.')) && !strcmp (ext, ".sbd")) - *ext = '\0'; - - if (name != NULL) - full_name = g_strdup_printf ("%s/%s", name, short_name); - else - full_name = g_strdup (short_name); - - if (!S_ISDIR (st.st_mode)) { - folder = camel_object_bag_get (store->folders, full_name); - if (folder) { - if ((flags & CAMEL_STORE_FOLDER_INFO_FAST) == 0) - camel_folder_refresh_info (folder, NULL); - unread = camel_folder_get_unread_message_count (folder); - camel_object_unref (folder); - } - } - - if ((fi = g_hash_table_lookup (folder_hash, short_name)) != NULL) { - g_free (short_name); - g_free (full_name); - - if (S_ISDIR (st.st_mode)) { - fi->flags = (fi->flags & ~CAMEL_FOLDER_NOINFERIORS) | CAMEL_FOLDER_CHILDREN; - } else { - fi->unread_message_count = unread; - fi->flags &= ~CAMEL_FOLDER_NOSELECT; - if ((ext = strchr (fi->url, ';')) && !strncmp (ext, ";noselect=yes", 13)) - memmove (ext, ext + 13, strlen (ext + 13) + 1); - } - } else { - fi = g_new0 (CamelFolderInfo, 1); - fi->parent = parent; - - /* add ";noselect=yes" if we haven't found the mbox file yet. when we find it, remove the noselect */ - fi->url = g_strdup_printf ("mbox:%s%s#%s", ((CamelService *) store)->url->path, - S_ISDIR (st.st_mode) ? ";noselect=yes" : "", full_name); - fi->name = short_name; - fi->full_name = full_name; - fi->path = g_strdup_printf ("/%s", full_name); - fi->unread_message_count = unread; - - if (S_ISDIR (st.st_mode)) - fi->flags = CAMEL_FOLDER_NOSELECT; - else - fi->flags = CAMEL_FOLDER_NOINFERIORS; - - if (tail == NULL) - folders = fi; - else - tail->sibling = fi; - - tail = fi; - - g_hash_table_insert (folder_hash, fi->name, fi); - } - - if ((flags & CAMEL_STORE_FOLDER_INFO_RECURSIVE) && S_ISDIR (st.st_mode)) { - struct _inode in = { st.st_dev, st.st_ino }; - - if (g_hash_table_lookup (visited, &in) == NULL) { - struct _inode *inew = g_new (struct _inode, 1); - - *inew = in; - - g_hash_table_insert (visited, inew, inew); - - if ((fi->child = scan_dir (store, visited, fi, path, fi->full_name, flags, ex))) - fi->flags |= CAMEL_FOLDER_CHILDREN; - } - } - - g_free (path); - } - - closedir (dir); - - g_hash_table_destroy (folder_hash); - - return folders; -} - -static CamelFolderInfo * -get_folder_info (CamelStore *store, const char *top, guint32 flags, CamelException *ex) -{ - GHashTable *visited; - struct _inode *inode; - char *path, *subdir; - CamelFolderInfo *fi; - CamelFolder *folder; - const char *base; - struct stat st; - int unread = -1; - - top = top ? top : ""; - path = mbox_folder_name_to_path (store, top); - - if (*top == '\0') { - /* requesting root dir scan */ - if (stat (path, &st) == -1 || !S_ISDIR (st.st_mode)) { - g_free (path); - return NULL; - } - - visited = g_hash_table_new (inode_hash, inode_equal); - - inode = g_new (struct _inode, 1); - inode->dnode = st.st_dev; - inode->inode = st.st_ino; - - g_hash_table_insert (visited, inode, inode); - - fi = scan_dir (store, visited, NULL, path, NULL, flags, ex); - g_hash_table_foreach (visited, inode_free, NULL); - g_hash_table_destroy (visited); - g_free (path); - - return fi; - } - - /* requesting scan of specific folder */ - if (stat (path, &st) == -1 || !S_ISREG (st.st_mode)) { - g_free (path); - return NULL; - } - - visited = g_hash_table_new (inode_hash, inode_equal); - - if (!(base = strrchr (top, '/'))) - base = top; - else - base++; - - folder = camel_object_bag_get (store->folders, top); - if (folder) { - if ((flags & CAMEL_STORE_FOLDER_INFO_FAST) == 0) - camel_folder_refresh_info (folder, NULL); - unread = camel_folder_get_unread_message_count (folder); - camel_object_unref (folder); - } - - fi = g_new0 (CamelFolderInfo, 1); - fi->parent = NULL; - fi->url = g_strdup_printf ("mbox:%s#%s", ((CamelService *) store)->url->path, top); - fi->name = g_strdup (base); - fi->full_name = g_strdup (top); - fi->unread_message_count = unread; - fi->path = g_strdup_printf ("/%s", top); - - subdir = g_strdup_printf ("%s.sbd", path); - if (stat (subdir, &st) == 0 && S_ISDIR (st.st_mode)) - fi->child = scan_dir (store, visited, fi, subdir, top, flags, ex); - - if (fi->child) - fi->flags |= CAMEL_FOLDER_CHILDREN; - else - fi->flags |= CAMEL_FOLDER_NOINFERIORS; - - g_free (subdir); - - g_hash_table_foreach (visited, inode_free, NULL); - g_hash_table_destroy (visited); - g_free (path); - - return fi; -} |