diff options
author | Not Zed <NotZed@HelixCode.com> | 2000-11-28 21:13:23 +0800 |
---|---|---|
committer | Michael Zucci <zucchi@src.gnome.org> | 2000-11-28 21:13:23 +0800 |
commit | 3998a03ae925f47cd1ffcf31fca0a4701f8c75da (patch) | |
tree | 2e4abfb292e1e76da06af4ce5676fd7ae79d2c75 /camel | |
parent | f306b8b912a19e1a0321af66a29faf23664f2077 (diff) | |
download | gsoc2013-evolution-3998a03ae925f47cd1ffcf31fca0a4701f8c75da.tar.gz gsoc2013-evolution-3998a03ae925f47cd1ffcf31fca0a4701f8c75da.tar.zst gsoc2013-evolution-3998a03ae925f47cd1ffcf31fca0a4701f8c75da.zip |
Set the info size's properly, oops!
2000-11-28 Not Zed <NotZed@HelixCode.com>
* providers/local/camel-maildir-summary.c
(camel_maildir_summary_init): Set the info size's properly, oops!
* tests/lib/folders.[ch]: Folder testing helpers.
* tests/folder/test2.c: Test basic message ops on folders.
* tests/folder/test1.c (main): Test basic folder ops on (local)
stores.
* providers/local/camel-local-provider.c
(camel_provider_module_init): Removed some debug.
* providers/local/camel-maildir-folder.c
(camel_maildir_folder_class_init): fix parent class.
* providers/local/camel-mh-folder.c (camel_mh_folder_class_init):
Fix parent class (damn cut & paste).
* providers/local/camel-maildir-store.c (get_folder): Call parent
impl.
(camel_maildir_store_class_init): Fix parent class setup.
(delete_folder): Check the folder exists before trying to delete
it.
(delete_folder): Try and make the delete operation atomic/rollback
failures. e.g. if one directory isn't empty, then create the
other empty ones back. Also clear the tmp directory fully first.
* providers/local/camel-mbox-store.c (get_folder): Call parent
impl.
(camel_mbox_store_class_init): parent class is camel_local_store,
not camel_folder, oops.
(delete_folder): Return an error if it doesn't exist, rather than
covering it up.
* providers/local/camel-mh-store.c (get_folder): Call parent impl.
(camel_mh_store_class_init): fix parent class setup.
(delete_folder): Error if it doesn't exist now.
* camel-folder.c (camel_folder_move_message_to):
(camel_folder_copy_message_to): Added warnings as these functions
are going to be removed later.
* camel-store.c (camel_store_get_root_folder): Fix for an early
api change. We want CAMEL_STORE_FOLDER_CREATE, not TRUE, since
its a flag.
(camel_store_get_default_folder): And here too.
* providers/local/camel-local-store.c (xrename): Handle renaming
folders differently to renaming files.
(get_default_folder_name): local stores dont have a default
folder, so make it so. Or at least, it doesn't seem to make sense
to have one.
(get_root_folder_name): Same for root.
(get_folder): Added parent implementation, that makes sure the
service path exists, if we are creating a new folder (but doesn't
create the folder).
2000-11-27 Not Zed <NotZed@HelixCode.com>
* providers/local/camel-local-store.c (xrename): Fixed races. Use
link/unlink, rather than rename, to properly detect overwriting
another file. And allow some files to be missing.
* providers/Makefile.am: Removed mh, mbox, added local, to the default.
svn path=/trunk/; revision=6693
Diffstat (limited to 'camel')
23 files changed, 1184 insertions, 55 deletions
diff --git a/camel/ChangeLog b/camel/ChangeLog index 364ec4be34..f7a7ddf80c 100644 --- a/camel/ChangeLog +++ b/camel/ChangeLog @@ -1,3 +1,69 @@ +2000-11-28 Not Zed <NotZed@HelixCode.com> + + * providers/local/camel-maildir-summary.c + (camel_maildir_summary_init): Set the info size's properly, oops! + + * tests/lib/folders.[ch]: Folder testing helpers. + + * tests/folder/test2.c: Test basic message ops on folders. + + * tests/folder/test1.c (main): Test basic folder ops on (local) + stores. + + * providers/local/camel-local-provider.c + (camel_provider_module_init): Removed some debug. + + * providers/local/camel-maildir-folder.c + (camel_maildir_folder_class_init): fix parent class. + + * providers/local/camel-mh-folder.c (camel_mh_folder_class_init): + Fix parent class (damn cut & paste). + + * providers/local/camel-maildir-store.c (get_folder): Call parent + impl. + (camel_maildir_store_class_init): Fix parent class setup. + (delete_folder): Check the folder exists before trying to delete + it. + (delete_folder): Try and make the delete operation atomic/rollback + failures. e.g. if one directory isn't empty, then create the + other empty ones back. Also clear the tmp directory fully first. + + * providers/local/camel-mbox-store.c (get_folder): Call parent + impl. + (camel_mbox_store_class_init): parent class is camel_local_store, + not camel_folder, oops. + (delete_folder): Return an error if it doesn't exist, rather than + covering it up. + + * providers/local/camel-mh-store.c (get_folder): Call parent impl. + (camel_mh_store_class_init): fix parent class setup. + (delete_folder): Error if it doesn't exist now. + + * camel-folder.c (camel_folder_move_message_to): + (camel_folder_copy_message_to): Added warnings as these functions + are going to be removed later. + + * camel-store.c (camel_store_get_root_folder): Fix for an early + api change. We want CAMEL_STORE_FOLDER_CREATE, not TRUE, since + its a flag. + (camel_store_get_default_folder): And here too. + + * providers/local/camel-local-store.c (xrename): Handle renaming + folders differently to renaming files. + (get_default_folder_name): local stores dont have a default + folder, so make it so. Or at least, it doesn't seem to make sense + to have one. + (get_root_folder_name): Same for root. + (get_folder): Added parent implementation, that makes sure the + service path exists, if we are creating a new folder (but doesn't + create the folder). + +2000-11-27 Not Zed <NotZed@HelixCode.com> + + * providers/local/camel-local-store.c (xrename): Fixed races. Use + link/unlink, rather than rename, to properly detect overwriting + another file. And allow some files to be missing. + 2000-11-28 Radek Doulik <rodo@helixcode.com> * providers/local/camel-local-summary.c diff --git a/camel/camel-folder.c b/camel/camel-folder.c index 1453f91f3f..d50323f3a4 100644 --- a/camel/camel-folder.c +++ b/camel/camel-folder.c @@ -886,6 +886,9 @@ copy_message_to (CamelFolder *source, const char *uid, CamelFolder *dest, * This copies a message from one folder to another. If the @source and * @dest folders have the same parent_store, this may be more efficient * than a camel_folder_append_message(). + * + * FIXME: This call should be deprecated, as append_message() can determine + * this information for itself. **/ void camel_folder_copy_message_to (CamelFolder *source, const char *uid, @@ -895,6 +898,8 @@ camel_folder_copy_message_to (CamelFolder *source, const char *uid, g_return_if_fail (CAMEL_IS_FOLDER (dest)); g_return_if_fail (uid != NULL); + g_warning("CamelFolder.copy_message_to() is a deprecated api"); + if (source->parent_store == dest->parent_store) { return CF_CLASS (source)->copy_message_to (source, uid, dest, ex); @@ -934,6 +939,9 @@ move_message_to (CamelFolder *source, const char *uid, * @dest folders have the same parent_store, this may be more efficient * than a camel_folder_append_message() followed by * camel_folder_delete_message(). + * + * FIXME: This call should be depracated, since append_message() can + * determine this from the message itself. **/ void camel_folder_move_message_to (CamelFolder *source, const char *uid, @@ -943,6 +951,8 @@ camel_folder_move_message_to (CamelFolder *source, const char *uid, g_return_if_fail (CAMEL_IS_FOLDER (dest)); g_return_if_fail (uid != NULL); + g_warning("CamelFolder.move_message_to() is a deprecated api"); + if (source->parent_store == dest->parent_store) { return CF_CLASS (source)->move_message_to (source, uid, dest, ex); diff --git a/camel/camel-store.c b/camel/camel-store.c index c9236676b2..7712079af7 100644 --- a/camel/camel-store.c +++ b/camel/camel-store.c @@ -354,7 +354,7 @@ camel_store_get_root_folder (CamelStore *store, CamelException *ex) name = CS_CLASS (store)->get_root_folder_name (store, ex); if (name) { - folder = get_folder_internal (store, name, TRUE, ex); + folder = get_folder_internal (store, name, CAMEL_STORE_FOLDER_CREATE, ex); g_free (name); } return folder; @@ -377,7 +377,7 @@ camel_store_get_default_folder (CamelStore *store, CamelException *ex) name = CS_CLASS (store)->get_default_folder_name (store, ex); if (name) { - folder = get_folder_internal (store, name, TRUE, ex); + folder = get_folder_internal (store, name, CAMEL_STORE_FOLDER_CREATE, ex); g_free (name); } return folder; diff --git a/camel/providers/local/camel-local-provider.c b/camel/providers/local/camel-local-provider.c index 603a4a7bf9..ccf7aa58df 100644 --- a/camel/providers/local/camel-local-provider.c +++ b/camel/providers/local/camel-local-provider.c @@ -66,8 +66,6 @@ static CamelProvider maildir_provider = { void camel_provider_module_init(CamelSession * session) { - printf("Initialising local providers\n"); - mh_provider.object_types[CAMEL_PROVIDER_STORE] = camel_mh_store_get_type(); mh_provider.service_cache = g_hash_table_new(camel_url_hash, camel_url_equal); camel_session_register_provider(session, &mh_provider); diff --git a/camel/providers/local/camel-local-store.c b/camel/providers/local/camel-local-store.c index c07a1d2c3a..748cc45290 100644 --- a/camel/providers/local/camel-local-store.c +++ b/camel/providers/local/camel-local-store.c @@ -33,11 +33,16 @@ #include "camel-exception.h" #include "camel-url.h" +#define d(x) + /* Returns the class for a CamelLocalStore */ #define CLOCALS_CLASS(so) CAMEL_LOCAL_STORE_CLASS (CAMEL_OBJECT_GET_CLASS(so)) #define CF_CLASS(so) CAMEL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(so)) +static CamelFolder *get_folder(CamelStore * store, const char *folder_name, guint32 flags, CamelException * ex); static char *get_name(CamelService *service, gboolean brief); +static char *get_root_folder_name (CamelStore *store, CamelException *ex); +static char *get_default_folder_name (CamelStore *store, CamelException *ex); static void rename_folder(CamelStore *store, const char *old_name, const char *new_name, CamelException *ex); static char *get_folder_name(CamelStore *store, const char *folder_name, CamelException *ex); static CamelFolderInfo *get_folder_info (CamelStore *store, const char *top, @@ -55,6 +60,9 @@ camel_local_store_class_init (CamelLocalStoreClass *camel_local_store_class) /* virtual method overload */ camel_service_class->get_name = get_name; + camel_store_class->get_folder = get_folder; + camel_store_class->get_root_folder_name = get_root_folder_name; + camel_store_class->get_default_folder_name = get_default_folder_name; camel_store_class->get_folder_name = get_folder_name; camel_store_class->get_folder_info = get_folder_info; camel_store_class->free_folder_info = camel_store_free_folder_info_full; @@ -99,6 +107,73 @@ camel_local_store_get_toplevel_dir (CamelLocalStore *store) return url->path; } +static CamelFolder * +get_folder(CamelStore * store, const char *folder_name, guint32 flags, CamelException * ex) +{ + struct stat st; + char *path = ((CamelService *)store)->url->path; + char *sub, *slash; + + if (path[0] != '/') { + camel_exception_setv(ex, CAMEL_EXCEPTION_STORE_NO_FOLDER, + _("Store root %s is not an absolute path"), path); + return NULL; + } + + if (stat(path, &st) == 0) { + if (!S_ISDIR(st.st_mode)) { + camel_exception_setv(ex, CAMEL_EXCEPTION_STORE_NO_FOLDER, + _("Store root %s is not a regular directory"), path); + } + return NULL; + } + + if (errno != ENOENT + || (flags & CAMEL_STORE_FOLDER_CREATE) == 0) { + camel_exception_setv(ex, CAMEL_EXCEPTION_STORE_NO_FOLDER, + _("Cannot get folder: %s: %s"), path, strerror(errno)); + return NULL; + } + + /* need to create the dir heirarchy */ + sub = alloca(strlen(path)+1); + strcpy(sub, path); + slash = sub; + do { + slash = strchr(slash+1, '/'); + if (slash) + *slash = 0; + if (stat(sub, &st) == -1) { + if (errno != ENOENT + || mkdir(sub, 0700) == -1) { + camel_exception_setv(ex, CAMEL_EXCEPTION_STORE_NO_FOLDER, + _("Cannot get folder: %s: %s"), path, strerror(errno)); + return NULL; + } + } + if (slash) + *slash = '/'; + } while (slash); + + return NULL; +} + +static char * +get_root_folder_name(CamelStore *store, CamelException *ex) +{ + camel_exception_set(ex, CAMEL_EXCEPTION_STORE_NO_FOLDER, + _("Local stores do not have a root folder")); + return NULL; +} + +static char * +get_default_folder_name(CamelStore *store, CamelException *ex) +{ + camel_exception_set(ex, CAMEL_EXCEPTION_STORE_NO_FOLDER, + _("Local stores do not have a default folder")); + return NULL; +} + static char * get_folder_name (CamelStore *store, const char *folder_name, CamelException *ex) { @@ -134,25 +209,49 @@ get_folder_info (CamelStore *store, const char *top, return NULL; } -static int xrename(const char *oldp, const char *newp, const char *prefix, const char *suffix, CamelException *ex) +static int xrename(const char *oldp, const char *newp, const char *prefix, const char *suffix, int missingok, CamelException *ex) { struct stat st; char *old = g_strconcat(prefix, oldp, suffix, 0); char *new = g_strconcat(prefix, newp, suffix, 0); int ret = -1; + int err = 0; + + d(printf("renaming %s%s to %s%s\n", oldp, suffix, newp, suffix)); - printf("renaming %s%s to %s%s\n", oldp, suffix, newp, suffix); + if (stat(old, &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(old, new) == 0 + || stat(new, &st) == 0) { + ret = 0; + } else { + err = errno; + ret = -1; + } + } else if (link(old, new) == 0 /* and link for files */ + || (stat(new, &st) == 0 && st.st_nlink == 2)) { + if (unlink(old) == 0) { + ret = 0; + } else { + err = errno; + unlink(new); + ret = -1; + } + } else { + err = errno; + ret = -1; + } - /* FIXME: this has races ... */ - if (!(stat(new, &st) == -1 && errno==ENOENT)) { + if (ret == -1) { camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not rename folder %s to %s: destination exists"), - old, new); - } else if (rename(old, new) == 0 || errno==ENOENT) { - ret = 0; - } else if (stat(old, &st) == -1 && errno==ENOENT && stat(new, &st) == 0) { - /* for nfs, check if the rename worked anyway ... */ - ret = 0; + _("Could not rename folder %s to %s: %s"), + old, new, strerror(err)); } g_free(old); @@ -167,16 +266,16 @@ rename_folder(CamelStore *store, const char *old, const char *new, CamelExceptio char *path = CAMEL_SERVICE (store)->url->path; /* try to rollback failures, has obvious races */ - if (xrename(old, new, path, ".ibex", ex)) { + if (xrename(old, new, path, ".ibex", TRUE, ex)) { return; } - if (xrename(old, new, path, ".ev-summary", ex)) { - xrename(new, old, path, ".ibex", ex); + if (xrename(old, new, path, ".ev-summary", TRUE, ex)) { + xrename(new, old, path, ".ibex", TRUE, ex); return; } - if (xrename(old, new, path, "", ex)) { - xrename(new, old, path, ".ev-summary", ex); - xrename(new, old, path, ".ibex", ex); + if (xrename(old, new, path, "", FALSE, ex)) { + xrename(new, old, path, ".ev-summary", TRUE, ex); + xrename(new, old, path, ".ibex", TRUE, ex); } } diff --git a/camel/providers/local/camel-local-summary.c b/camel/providers/local/camel-local-summary.c index 278df6a64c..81cde8e808 100644 --- a/camel/providers/local/camel-local-summary.c +++ b/camel/providers/local/camel-local-summary.c @@ -168,7 +168,7 @@ camel_local_summary_decode_x_evolution(CamelLocalSummary *cls, const char *xev, return ((CamelLocalSummaryClass *)(CAMEL_OBJECT_GET_CLASS(cls)))->decode_x_evolution(cls, xev, info); } -#define DOSTATS +/*#define DOSTATS*/ #ifdef DOSTATS struct _stat_info { int mitotal; diff --git a/camel/providers/local/camel-maildir-folder.c b/camel/providers/local/camel-maildir-folder.c index e3ff088238..1cffbdabd2 100644 --- a/camel/providers/local/camel-maildir-folder.c +++ b/camel/providers/local/camel-maildir-folder.c @@ -40,9 +40,9 @@ #include "camel-mime-message.h" #include "camel-exception.h" -#define d(x) (printf("%s(%d): ", __FILE__, __LINE__),(x)) +#define d(x) /*(printf("%s(%d): ", __FILE__, __LINE__),(x))*/ -static CamelFolderClass *parent_class = NULL; +static CamelLocalFolderClass *parent_class = NULL; /* Returns the class for a CamelMaildirFolder */ #define CMAILDIRF_CLASS(so) CAMEL_MAILDIR_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(so)) @@ -61,7 +61,7 @@ static void camel_maildir_folder_class_init(CamelObjectClass * camel_maildir_fol CamelFolderClass *camel_folder_class = CAMEL_FOLDER_CLASS(camel_maildir_folder_class); CamelLocalFolderClass *lclass = (CamelLocalFolderClass *)camel_maildir_folder_class; - parent_class = CAMEL_FOLDER_CLASS (camel_type_get_global_classfuncs(camel_folder_get_type())); + parent_class = CAMEL_LOCAL_FOLDER_CLASS (camel_type_get_global_classfuncs(camel_local_folder_get_type())); /* virtual method definition */ diff --git a/camel/providers/local/camel-maildir-store.c b/camel/providers/local/camel-maildir-store.c index 0601307449..f5bd353b6f 100644 --- a/camel/providers/local/camel-maildir-store.c +++ b/camel/providers/local/camel-maildir-store.c @@ -27,6 +27,8 @@ #include <string.h> #include <unistd.h> +#include <dirent.h> + #include "camel-maildir-store.h" #include "camel-maildir-folder.h" #include "camel-exception.h" @@ -47,7 +49,7 @@ static void camel_maildir_store_class_init(CamelObjectClass * camel_maildir_stor CamelStoreClass *camel_store_class = CAMEL_STORE_CLASS(camel_maildir_store_class); /*CamelServiceClass *camel_service_class = CAMEL_SERVICE_CLASS(camel_maildir_store_class);*/ - parent_class = (CamelLocalStoreClass *)camel_type_get_global_classfuncs(camel_folder_get_type()); + parent_class = (CamelLocalStoreClass *)camel_type_get_global_classfuncs(camel_local_store_get_type()); /* virtual method overload, use defaults for most */ camel_store_class->get_folder = get_folder; @@ -85,6 +87,10 @@ static CamelFolder *get_folder(CamelStore * store, const char *folder_name, guin struct stat st; CamelFolder *folder = NULL; + (void) ((CamelStoreClass *)parent_class)->get_folder(store, folder_name, flags, ex); + if (camel_exception_is_set(ex)) + return NULL; + name = g_strdup_printf("%s%s", CAMEL_SERVICE(store)->url->path, folder_name); tmp = g_strdup_printf("%s/tmp", name); cur = g_strdup_printf("%s/cur", name); @@ -99,8 +105,6 @@ static CamelFolder *get_folder(CamelStore * store, const char *folder_name, guin camel_exception_setv(ex, CAMEL_EXCEPTION_STORE_NO_FOLDER, _("Folder `%s' does not exist."), folder_name); } else { - printf("creating ...\n"); - if (mkdir(name, 0700) != 0 || mkdir(tmp, 0700) != 0 || mkdir(cur, 0700) != 0 @@ -113,7 +117,6 @@ static CamelFolder *get_folder(CamelStore * store, const char *folder_name, guin rmdir(new); rmdir(name); } else { - printf("created ok?\n"); folder = camel_maildir_folder_new(store, folder_name, flags, ex); } } @@ -138,23 +141,62 @@ static CamelFolder *get_folder(CamelStore * store, const char *folder_name, guin static void delete_folder(CamelStore * store, const char *folder_name, CamelException * ex) { char *name, *tmp, *cur, *new; + struct stat st; name = g_strdup_printf("%s%s", CAMEL_SERVICE(store)->url->path, folder_name); + tmp = g_strdup_printf("%s/tmp", name); cur = g_strdup_printf("%s/cur", name); new = g_strdup_printf("%s/new", name); - /* remove subdirs first - will fail if not empty */ - if ((rmdir(tmp) == -1 && errno != ENOENT) - || (rmdir(new) == -1 && errno != ENOENT) - || (rmdir(cur) == -1 && errno != ENOENT) - || (rmdir(name) == -1 && errno != ENOENT)) { + if (stat(name, &st) == -1 || !S_ISDIR(st.st_mode) + || stat(tmp, &st) == -1 || !S_ISDIR(st.st_mode) + || stat(cur, &st) == -1 || !S_ISDIR(st.st_mode) + || stat(new, &st) == -1 || !S_ISDIR(st.st_mode)) { camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, _("Could not delete folder `%s': %s"), - folder_name, strerror(errno)); + folder_name, errno?strerror(errno):_("not a maildir directory")); } else { - /* and remove metadata */ - ((CamelStoreClass *)parent_class)->delete_folder(store, folder_name, ex); + int err = 0; + + /* remove subdirs first - will fail if not empty */ + if (rmdir(cur) == -1 || rmdir(new) == -1) { + err = errno; + } else { + DIR *dir; + struct dirent *d; + + /* for tmp (only), its contents is irrelevant */ + dir = opendir(tmp); + if (dir) { + while ( (d=readdir(dir)) ) { + char *name = d->d_name, *file; + + if (!strcmp(name, ".") || !strcmp(name, "..")) + continue; + file = g_strdup_printf("%s/%s", tmp, name); + unlink(file); + g_free(file); + } + closedir(dir); + } + if (rmdir(tmp) == -1 || rmdir(name) == -1) + err = errno; + } + + if (err != 0) { + /* easier just to mkdir all (and let them fail), than remember what we got to */ + mkdir(name, 0700); + mkdir(cur, 0700); + mkdir(new, 0700); + mkdir(tmp, 0700); + camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, + _("Could not delete folder `%s': %s"), + folder_name, strerror(err)); + } else { + /* and remove metadata */ + ((CamelStoreClass *)parent_class)->delete_folder(store, folder_name, ex); + } } g_free(name); diff --git a/camel/providers/local/camel-maildir-summary.c b/camel/providers/local/camel-maildir-summary.c index 92b2be23f8..fe88539ca3 100644 --- a/camel/providers/local/camel-maildir-summary.c +++ b/camel/providers/local/camel-maildir-summary.c @@ -33,7 +33,7 @@ #include <ctype.h> -#define d(x) (printf("%s(%d): ", __FILE__, __LINE__),(x)) +#define d(x) /*(printf("%s(%d): ", __FILE__, __LINE__),(x))*/ #define CAMEL_MAILDIR_SUMMARY_VERSION (0x2000) @@ -103,6 +103,9 @@ camel_maildir_summary_init (CamelMaildirSummary *o) /* set unique file version */ s->version += CAMEL_MAILDIR_SUMMARY_VERSION; + s->message_info_size = sizeof(CamelMaildirMessageInfo); + s->content_info_size = sizeof(CamelMaildirMessageContentInfo); + if (gethostname(hostname, 256) == 0) { o->priv->hostname = g_strdup(hostname); } else { diff --git a/camel/providers/local/camel-mbox-store.c b/camel/providers/local/camel-mbox-store.c index 77a291637c..8ae0891b31 100644 --- a/camel/providers/local/camel-mbox-store.c +++ b/camel/providers/local/camel-mbox-store.c @@ -47,7 +47,7 @@ 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_folder_get_type()); + parent_class = (CamelLocalStoreClass *)camel_type_get_global_classfuncs(camel_local_store_get_type()); /* virtual method overload */ camel_store_class->get_folder = get_folder; @@ -87,6 +87,10 @@ get_folder(CamelStore *store, const char *folder_name, guint32 flags, CamelExcep char *name; struct stat st; + (void) ((CamelStoreClass *)parent_class)->get_folder(store, folder_name, flags, ex); + if (camel_exception_is_set(ex)) + return NULL; + name = g_strdup_printf("%s%s", CAMEL_SERVICE(store)->url->path, folder_name); if (stat(name, &st) == -1) { @@ -137,12 +141,6 @@ delete_folder (CamelStore *store, const char *folder_name, CamelException *ex) name = g_strdup_printf ("%s%s", CAMEL_SERVICE (store)->url->path, folder_name); if (stat (name, &st) == -1) { - if (errno == ENOENT) { - /* file doesn't exist - it's kinda like deleting it ;-) */ - g_free (name); - return; - } - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, _("Could not delete folder `%s':\n%s"), folder_name, g_strerror (errno)); diff --git a/camel/providers/local/camel-mh-folder.c b/camel/providers/local/camel-mh-folder.c index c0a9f3f2af..8f223a34c2 100644 --- a/camel/providers/local/camel-mh-folder.c +++ b/camel/providers/local/camel-mh-folder.c @@ -42,7 +42,7 @@ #define d(x) /*(printf("%s(%d): ", __FILE__, __LINE__),(x))*/ -static CamelFolderClass *parent_class = NULL; +static CamelLocalFolderClass *parent_class = NULL; /* Returns the class for a CamelMhFolder */ #define CMHF_CLASS(so) CAMEL_MH_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(so)) @@ -61,7 +61,7 @@ static void camel_mh_folder_class_init(CamelObjectClass * camel_mh_folder_class) CamelFolderClass *camel_folder_class = CAMEL_FOLDER_CLASS(camel_mh_folder_class); CamelLocalFolderClass *lclass = (CamelLocalFolderClass *)camel_mh_folder_class; - parent_class = CAMEL_FOLDER_CLASS (camel_type_get_global_classfuncs(camel_folder_get_type())); + parent_class = CAMEL_LOCAL_FOLDER_CLASS (camel_type_get_global_classfuncs(camel_local_folder_get_type())); /* virtual method definition */ diff --git a/camel/providers/local/camel-mh-store.c b/camel/providers/local/camel-mh-store.c index 82310578d1..3d637e4cad 100644 --- a/camel/providers/local/camel-mh-store.c +++ b/camel/providers/local/camel-mh-store.c @@ -47,7 +47,7 @@ static void camel_mh_store_class_init(CamelObjectClass * camel_mh_store_class) CamelStoreClass *camel_store_class = CAMEL_STORE_CLASS(camel_mh_store_class); /*CamelServiceClass *camel_service_class = CAMEL_SERVICE_CLASS(camel_mh_store_class);*/ - parent_class = (CamelLocalStoreClass *)camel_type_get_global_classfuncs(camel_folder_get_type()); + parent_class = (CamelLocalStoreClass *)camel_type_get_global_classfuncs(camel_local_store_get_type()); /* virtual method overload, use defaults for most */ camel_store_class->get_folder = get_folder; @@ -84,6 +84,10 @@ static CamelFolder *get_folder(CamelStore * store, const char *folder_name, guin char *name; struct stat st; + (void) ((CamelStoreClass *)parent_class)->get_folder(store, folder_name, flags, ex); + if (camel_exception_is_set(ex)) + return NULL; + name = g_strdup_printf("%s%s", CAMEL_SERVICE(store)->url->path, folder_name); if (stat(name, &st) == -1) { @@ -100,8 +104,6 @@ static CamelFolder *get_folder(CamelStore * store, const char *folder_name, guin g_free (name); return NULL; } - printf("creating ...\n"); - if (mkdir(name, 0700) != 0) { camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, _("Could not create folder `%s':\n%s"), @@ -109,8 +111,6 @@ static CamelFolder *get_folder(CamelStore * store, const char *folder_name, guin g_free (name); return NULL; } - printf("created ok?\n"); - } else if (!S_ISDIR(st.st_mode)) { camel_exception_setv(ex, CAMEL_EXCEPTION_STORE_NO_FOLDER, _("`%s' is not a directory."), name); @@ -128,7 +128,7 @@ static void delete_folder(CamelStore * store, const char *folder_name, CamelExce /* remove folder directory - will fail if not empty */ name = g_strdup_printf("%s%s", CAMEL_SERVICE(store)->url->path, folder_name); - if (rmdir(name) == -1 && errno != ENOENT) { + if (rmdir(name) == -1) { camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, _("Could not delete folder `%s': %s"), folder_name, strerror(errno)); diff --git a/camel/tests/Makefile.am b/camel/tests/Makefile.am index c1799b985f..327f75816d 100644 --- a/camel/tests/Makefile.am +++ b/camel/tests/Makefile.am @@ -1,3 +1,4 @@ SUBDIRS = lib \ - message + message folder + diff --git a/camel/tests/README b/camel/tests/README index 2ffcc2dbcc..6815330102 100644 --- a/camel/tests/README +++ b/camel/tests/README @@ -2,6 +2,10 @@ This directory is to contain regression tests that should be run before committing anything to camel. +In each subdirectory of tests there is a README containing a +one-line description of each test file. This README must be kept +uptodate. + To write a new test: copy an existing one and replace the contents. See camel-test.h for a number of functions and macros which setup and diff --git a/camel/tests/folder/Makefile.am b/camel/tests/folder/Makefile.am new file mode 100644 index 0000000000..a036db99e5 --- /dev/null +++ b/camel/tests/folder/Makefile.am @@ -0,0 +1,23 @@ + +INCLUDES = -I$(top_srcdir)/intl -I$(top_srcdir) -I$(top_srcdir)/camel \ + -I$(includedir) \ + -I$(top_srcdir)/camel/tests/lib \ + -DG_LOG_DOMAIN=\"evolution-tests\" + +LDADD = \ + $(top_builddir)/camel/libcamel.la \ + $(top_builddir)/e-util/libeutil.la \ + $(top_builddir)/libibex/libibex.la \ + $(GNOME_LIBDIR) \ + $(top_builddir)/camel/tests/lib/libcameltest.a \ + $(GNOMEUI_LIBS) $(INTLLIBS) $(EXTRA_GNOME_LIBS) + +check_PROGRAMS = \ + test1 \ + test2 +# test3 + +#TESTS = test1 + + + diff --git a/camel/tests/folder/README b/camel/tests/folder/README new file mode 100644 index 0000000000..994c4cdec4 --- /dev/null +++ b/camel/tests/folder/README @@ -0,0 +1,4 @@ + +test1 camel store folder operations (local only) +test2 basic folder operations +test3 folder searching and indexing diff --git a/camel/tests/folder/test1.c b/camel/tests/folder/test1.c new file mode 100644 index 0000000000..020c511a82 --- /dev/null +++ b/camel/tests/folder/test1.c @@ -0,0 +1,149 @@ +/* store testing */ + +#include "camel-test.h" + +#include <camel/camel-exception.h> +#include <camel/camel-service.h> +#include <camel/camel-session.h> +#include <camel/camel-store.h> + +/* god, who designed this horrid interface */ +static char *auth_callback(CamelAuthCallbackMode mode, + char *data, gboolean secret, + CamelService *service, char *item, + CamelException *ex) +{ + return NULL; +} + +#define ARRAY_LEN(x) (sizeof(x)/sizeof(x[0])) + +static char *local_providers[] = { + "mbox", + "mh", + "maildir" +}; + +int main(int argc, char **argv) +{ + CamelSession *session; + CamelStore *store; + CamelException *ex; + CamelFolder *folder, *root; + int i; + char *path; + + ex = camel_exception_new(); + + camel_test_init(argc, argv); + + session = camel_session_new("/tmp/camel-test", auth_callback, NULL, NULL); + + /* todo: cross-check everything with folder_info checks as well */ + /* todo: subscriptions? */ + /* todo: work out how to do imap/pop/nntp tests */ + for (i=0;i<ARRAY_LEN(local_providers);i++) { + char *what = g_strdup_printf("testing local store: %s", local_providers[i]); + + camel_test_start(what); + g_free(what); + + push("getting store"); + path = g_strdup_printf("%s:///tmp/camel-test/%s", local_providers[i], local_providers[i]); + store = camel_session_get_store(session, path, ex); + check_msg(!camel_exception_is_set(ex), "getting store: %s", camel_exception_get_description(ex)); + check(store != NULL); + pull(); + + /* local providers == no root folder */ + push("getting root folder"); + root = camel_store_get_root_folder(store, ex); + check(camel_exception_is_set(ex)); + check(root == NULL); + camel_exception_clear(ex); + pull(); + + /* same for default folder */ + push("getting default folder"); + root = camel_store_get_root_folder(store, ex); + check(camel_exception_is_set(ex)); + check(root == NULL); + camel_exception_clear(ex); + pull(); + + push("getting a non-existant folder, no create"); + folder = camel_store_get_folder(store, "unknown", 0, ex); + check(camel_exception_is_set(ex)); + check(folder == NULL); + camel_exception_clear(ex); + pull(); + + push("getting a non-existant folder, with create"); + folder = camel_store_get_folder(store, "testbox", CAMEL_STORE_FOLDER_CREATE, ex); + check_msg(!camel_exception_is_set(ex), "%s", camel_exception_get_description(ex)); + check(folder != NULL); + camel_object_unref((CamelObject *)folder); + pull(); + + push("getting an existing folder"); + folder = camel_store_get_folder(store, "testbox", 0, ex); + check_msg(!camel_exception_is_set(ex), "%s", camel_exception_get_description(ex)); + check(folder != NULL); + camel_object_unref((CamelObject *)folder); + pull(); + + push("renaming a non-existant folder"); + camel_store_rename_folder(store, "unknown1", "unknown2", ex); + check(camel_exception_is_set(ex)); + camel_exception_clear(ex); + pull(); + + push("renaming an existing folder"); + camel_store_rename_folder(store, "testbox", "testbox2", ex); + check_msg(!camel_exception_is_set(ex), "%s", camel_exception_get_description(ex)); + pull(); + + push("opening the old name of a renamed folder"); + folder = camel_store_get_folder(store, "testbox", 0, ex); + check(camel_exception_is_set(ex)); + check(folder == NULL); + camel_exception_clear(ex); + pull(); + + push("opening the new name of a renamed folder"); + folder = camel_store_get_folder(store, "testbox2", 0, ex); + check_msg(!camel_exception_is_set(ex), "%s", camel_exception_get_description(ex)); + check(folder != NULL); + camel_object_unref((CamelObject *)folder); + pull(); + + push("deleting a non-existant folder"); + camel_store_delete_folder(store, "unknown", ex); + check(camel_exception_is_set(ex)); + camel_exception_clear(ex); + pull(); + + push("deleting an existing folder"); + camel_store_delete_folder(store, "testbox2", ex); + check_msg(!camel_exception_is_set(ex), "%s", camel_exception_get_description(ex)); + pull(); + + push("opening a folder that has been deleted"); + folder = camel_store_get_folder(store, "testbox2", 0, ex); + check(camel_exception_is_set(ex)); + check(folder == NULL); + camel_exception_clear(ex); + pull(); + + camel_object_unref((CamelObject *)store); + + g_free(path); + + camel_test_end(); + } + + camel_object_unref((CamelObject *)session); + camel_exception_free(ex); + + return 0; +} diff --git a/camel/tests/folder/test2.c b/camel/tests/folder/test2.c new file mode 100644 index 0000000000..c7a1af2c33 --- /dev/null +++ b/camel/tests/folder/test2.c @@ -0,0 +1,241 @@ +/* folder testing */ + +#include "camel-test.h" +#include "messages.h" +#include "folders.h" + +#include <camel/camel-exception.h> +#include <camel/camel-service.h> +#include <camel/camel-session.h> +#include <camel/camel-store.h> + +#include <camel/camel-folder.h> +#include <camel/camel-folder-summary.h> +#include <camel/camel-mime-message.h> + +/* god, who designed this horrid interface */ +static char *auth_callback(CamelAuthCallbackMode mode, + char *data, gboolean secret, + CamelService *service, char *item, + CamelException *ex) +{ + return NULL; +} + + +#define ARRAY_LEN(x) (sizeof(x)/sizeof(x[0])) + +static char *stores[] = { + "mbox:///tmp/camel-test/mbox", + "mh:///tmp/camel-test/mh", + "maildir:///tmp/camel-test/maildir" +}; + +int main(int argc, char **argv) +{ + CamelSession *session; + CamelStore *store; + CamelException *ex; + CamelFolder *folder; + CamelMimeMessage *msg; + int i, j; + int indexed; + GPtrArray *uids; + const CamelMessageInfo *info; + + ex = camel_exception_new(); + + camel_test_init(argc, argv); + + session = camel_session_new("/tmp/camel-test", auth_callback, NULL, NULL); + + /* todo: cross-check everything with folder_info checks as well */ + /* todo: work out how to do imap/pop/nntp tests */ + + /* we iterate over all stores we want to test, with indexing or indexing turned on or off */ + for (i=0;i<ARRAY_LEN(stores);i++) { + char *name = stores[i]; + for (indexed = 0;indexed<2;indexed++) { + char *what = g_strdup_printf("folder ops: %s (%sindexed)", name, indexed?"":"non-"); + int flags; + + camel_test_start(what); + test_free(what); + + push("getting store"); + store = camel_session_get_store(session, stores[i], ex); + check_msg(!camel_exception_is_set(ex), "getting store: %s", camel_exception_get_description(ex)); + check(store != NULL); + pull(); + + push("creating %sindexed folder", indexed?"":"non-"); + if (indexed) + flags = CAMEL_STORE_FOLDER_CREATE|CAMEL_STORE_FOLDER_BODY_INDEX; + else + flags = CAMEL_STORE_FOLDER_CREATE; + folder = camel_store_get_folder(store, "testbox", flags, ex); + check_msg(!camel_exception_is_set(ex), "%s", camel_exception_get_description(ex)); + check(folder != NULL); + + /* verify empty/can't get nonexistant stuff */ + test_folder_counts(folder, 0, 0); + test_folder_not_message(folder, "0"); + test_folder_not_message(folder, ""); + + for (j=0;j<10;j++) { + char *content, *subject; + + push("creating test message"); + msg = test_message_create_simple(); + content = g_strdup_printf("Test message %d contents\n\n", j); + test_message_set_content_simple((CamelMimePart *)msg, 0, "text/plain", + content, strlen(content)); + test_free(content); + subject = g_strdup_printf("Test message %d", j); + camel_mime_message_set_subject(msg, subject); + pull(); + + push("appending simple message %d", j); + camel_folder_append_message(folder, msg, NULL, ex); + check_msg(!camel_exception_is_set(ex), "%s", camel_exception_get_description(ex)); + test_folder_counts(folder, j+1, j+1); + + push("checking it is in the right uid slot & exists"); + uids = camel_folder_get_uids(folder); + check(uids != NULL); + check(uids->len == j+1); + test_folder_message(folder, uids->pdata[j]); + pull(); + + push("checking it is the right message (subject): %s", subject); + info = camel_folder_get_message_info(folder, uids->pdata[j]); + check_msg(strcmp(info->subject, subject)==0, "info->subject %s", info->subject); + camel_folder_free_uids(folder, uids); + pull(); + + test_free(subject); + + check_unref(msg, 1); + pull(); + } + + check_unref(folder, 1); + pull(); + + push("deleting test folder, with messages in it"); + camel_store_delete_folder(store, "testbox", ex); + check(camel_exception_is_set(ex)); + camel_exception_clear(ex); + pull(); + + push("re-opening folder"); + folder = camel_store_get_folder(store, "testbox", flags, ex); + check_msg(!camel_exception_is_set(ex), "%s", camel_exception_get_description(ex)); + check(folder != NULL); + + /* verify counts */ + test_folder_counts(folder, 10, 10); + + /* re-check uid's, after a reload */ + uids = camel_folder_get_uids(folder); + check(uids != NULL); + check(uids->len == 10); + for (j=0;j<10;j++) { + char *subject = g_strdup_printf("Test message %d", j); + + push("verify reload of %s", subject); + test_folder_message(folder, uids->pdata[j]); + + info = camel_folder_get_message_info(folder, uids->pdata[j]); + check_msg(strcmp(info->subject, subject)==0, "info->subject %s", info->subject); + test_free(subject); + pull(); + } + + push("deleting first message & expunging"); + camel_folder_delete_message(folder, uids->pdata[0]); + test_folder_counts(folder, 10, 10); + camel_folder_expunge(folder, ex); + check_msg(!camel_exception_is_set(ex), "%s", camel_exception_get_description(ex)); + test_folder_not_message(folder, uids->pdata[0]); + test_folder_counts(folder, 9, 9); + + camel_folder_free_uids(folder, uids); + + uids = camel_folder_get_uids(folder); + check(uids != NULL); + check(uids->len == 9); + for (j=0;j<9;j++) { + char *subject = g_strdup_printf("Test message %d", j+1); + + push("verify after expunge of %s", subject); + test_folder_message(folder, uids->pdata[j]); + + info = camel_folder_get_message_info(folder, uids->pdata[j]); + check_msg(strcmp(info->subject, subject)==0, "info->subject %s", info->subject); + test_free(subject); + pull(); + } + pull(); + + push("deleting last message & expunging"); + camel_folder_delete_message(folder, uids->pdata[8]); + /* sync? */ + test_folder_counts(folder, 9, 9); + camel_folder_expunge(folder, ex); + check_msg(!camel_exception_is_set(ex), "%s", camel_exception_get_description(ex)); + test_folder_not_message(folder, uids->pdata[8]); + test_folder_counts(folder, 8, 8); + + camel_folder_free_uids(folder, uids); + + uids = camel_folder_get_uids(folder); + check(uids != NULL); + check(uids->len == 8); + for (j=0;j<8;j++) { + char *subject = g_strdup_printf("Test message %d", j+1); + + push("verify after expunge of %s", subject); + test_folder_message(folder, uids->pdata[j]); + + info = camel_folder_get_message_info(folder, uids->pdata[j]); + check_msg(strcmp(info->subject, subject)==0, "info->subject %s", info->subject); + test_free(subject); + pull(); + } + pull(); + + push("deleting all messages & expunging"); + for (j=0;j<8;j++) { + camel_folder_delete_message(folder, uids->pdata[j]); + } + /* sync? */ + test_folder_counts(folder, 8, 8); + camel_folder_expunge(folder, ex); + check_msg(!camel_exception_is_set(ex), "%s", camel_exception_get_description(ex)); + for (j=0;j<8;j++) { + test_folder_not_message(folder, uids->pdata[j]); + } + test_folder_counts(folder, 0, 0); + + camel_folder_free_uids(folder, uids); + pull(); + + camel_object_unref((CamelObject *)folder); + pull(); /* re-opening folder */ + + push("deleting test folder, with no messages in it"); + camel_store_delete_folder(store, "testbox", ex); + check_msg(!camel_exception_is_set(ex), "%s", camel_exception_get_description(ex)); + pull(); + + camel_object_unref((CamelObject *)store); + camel_test_end(); + } + } + + camel_object_unref((CamelObject *)session); + camel_exception_free(ex); + + return 0; +} diff --git a/camel/tests/folder/test3.c b/camel/tests/folder/test3.c new file mode 100644 index 0000000000..ecd0a46fe7 --- /dev/null +++ b/camel/tests/folder/test3.c @@ -0,0 +1,290 @@ +/* folder/index testing */ + +#include "camel-test.h" +#include "messages.h" +#include "folders.h" + +#include <camel/camel-exception.h> +#include <camel/camel-service.h> +#include <camel/camel-session.h> +#include <camel/camel-store.h> + +#include <camel/camel-folder.h> +#include <camel/camel-folder-summary.h> +#include <camel/camel-mime-message.h> + +/* god, who designed this horrid interface */ +static char *auth_callback(CamelAuthCallbackMode mode, + char *data, gboolean secret, + CamelService *service, char *item, + CamelException *ex) +{ + return NULL; +} + + +static void +test_folder_search_sub(CamelFolder *folder, const char *expr, int expected) +{ + CamelException *ex = camel_exception_new(); + GPtrArray *uids; + GHashTable *hash; + int i; + + uids = camel_folder_search_by_expression(folder, expr, ex); + check(uids != NULL); + check(uids->len == expected); + check_msg(!camel_exception_is_set(ex), "%s", camel_exception_get_description(ex)); + + /* check the uid's are actually unique, too */ + hash = g_hash_table_new(g_str_hash, g_str_equal); + for (i=0;uids->len;i++) { + check(g_hash_table_lookup(hash, uids->pdata[i]) == NULL); + g_hash_table_insert(hash, uids->pdata[i], uids->pdata[i]); + } + g_hash_table_destroy(hash); + + camel_folder_search_free(folder, uids); + + camel_exception_free(ex); +} + +static void +test_folder_search(CamelFolder *folder, const char *expr, int expected) +{ + char *matchall; + + push("Testing search: %s", expr); + test_folder_search_sub(folder, expr, expected); + pull(); + + matchall = g_strdup_printf("(match-all %s)", expr); + push("Testing search: %s", matchall); + test_folder_search_sub(folder, matchall, expected); + test_free(matchall); + pull(); +} + +#define ARRAY_LEN(x) (sizeof(x)/sizeof(x[0])) + +static char *stores[] = { + "mbox:///tmp/camel-test/mbox", + "mh:///tmp/camel-test/mh", + "maildir:///tmp/camel-test/maildir" +}; + +int main(int argc, char **argv) +{ + CamelSession *session; + CamelStore *store; + CamelException *ex; + CamelFolder *folder; + CamelMimeMessage *msg; + int i, j; + int indexed; + GPtrArray *uids; + + ex = camel_exception_new(); + + camel_test_init(argc, argv); + + session = camel_session_new("/tmp/camel-test", auth_callback, NULL, NULL); + + /* todo: cross-check everything with folder_info checks as well */ + /* todo: work out how to do imap/pop/nntp tests */ + + /* we iterate over all stores we want to test, with indexing or indexing turned on or off */ + for (i=0;i<ARRAY_LEN(stores);i++) { + char *name = stores[i]; + for (indexed = 0;indexed<2;indexed++) { + char *what = g_strdup_printf("folder search: %s (%sindexed)", name, indexed?"":"non-"); + int flags; + + camel_test_start(what); + test_free(what); + + push("getting store"); + store = camel_session_get_store(session, stores[i], ex); + check_msg(!camel_exception_is_set(ex), "getting store: %s", camel_exception_get_description(ex)); + check(store != NULL); + pull(); + + push("creating %sindexed folder", indexed?"":"non-"); + if (indexed) + flags = CAMEL_STORE_FOLDER_CREATE|CAMEL_STORE_FOLDER_BODY_INDEX; + else + flags = CAMEL_STORE_FOLDER_CREATE; + folder = camel_store_get_folder(store, "testbox", flags, ex); + check_msg(!camel_exception_is_set(ex), "%s", camel_exception_get_description(ex)); + check(folder != NULL); + + /* we need an empty folder for this to work */ + test_folder_counts(folder, 0, 0); + pull(); + + /* append a bunch of messages with specific content */ + push("appending 100 test messages"); + for (j=0;j<100;j++) { + char *content, *subject; + + push("creating test message"); + msg = test_message_create_simple(); + content = g_strdup_printf("data%d content\n", j); + test_message_set_content_simple((CamelMimePart *)msg, 0, "text/plain", + content, strlen(content)); + test_free(content); + subject = g_strdup_printf("Test%d message%d subject", j, 100-j); + camel_mime_message_set_subject(msg, subject); + + camel_mime_message_set_date(msg, j*60*24, 0); + + pull(); + + push("appending simple message %d", j); + camel_folder_append_message(folder, msg, NULL, ex); + check_msg(!camel_exception_is_set(ex), "%s", camel_exception_get_description(ex)); + pull(); + + test_free(subject); + + check_unref(msg, 1); + } + pull(); + + push("Setting up some flags &c"); + uids = camel_folder_get_uids(folder); + check(uids->len == 100); + for (j=0;j<100;j++) { + char *uid = uids->pdata[j]; + + if ((j/13)*13 == j) { + camel_folder_set_message_user_flag(folder, uid, "every13", TRUE); + } + if ((j/17)*17 == j) { + camel_folder_set_message_user_flag(folder, uid, "every17", TRUE); + } + if ((j/7)*7 == j) { + char *tag = g_strdup_printf("7tag%d", j/7); + camel_folder_set_message_user_tag(folder, uid, "every7", tag); + test_free(tag); + } + if ((j/11)*11 == j) { + camel_folder_set_message_user_tag(folder, uid, "every11", "11tag"); + } + } + camel_folder_free_uids(folder, uids); + pull(); + + /* should try invalid search strings too */ + + /* try some searches */ + push("performing searches"); + test_folder_search(folder, "(header-contains \"subject\" \"subject\")", 100); + test_folder_search(folder, "(header-contains \"subject\" \"Subject\")", 100); + + test_folder_search(folder, "(body-contains \"content\")", 100); + test_folder_search(folder, "(body-contains \"Content\")", 100); + + test_folder_search(folder, "(user-flag \"every7\")", 0); + test_folder_search(folder, "(user-flag \"every13\")", 100/13); + test_folder_search(folder, "(= \"7tag1\" (user-tag \"every7\"))", 1); + test_folder_search(folder, "(= \"11tag\" (user-tag \"every11\"))", 100/11); + + test_folder_search(folder, "(user-flag \"every13\" \"every17\")", 100/13 + 100/17); + test_folder_search(folder, "(or (user-flag \"every13\") (user-flag \"every17\"))", 100/13 + 100/17); + test_folder_search(folder, "(and (user-flag \"every13\") (user-flag \"every17\"))", 0); + + test_folder_search(folder, "(and (header-contains \"subject\" \"Test1\")" + "(header-contains \"subject\" \"Test2\"))", 0); + test_folder_search(folder, "(and (header-contains \"subject\" \"Test1\")" + "(header-contains \"subject\" \"subject\"))", 1); + test_folder_search(folder, "(and (header-contains \"subject\" \"Test1\")" + "(header-contains \"subject\" \"message99\"))", 1); + + test_folder_search(folder, "(or (header-contains \"subject\" \"Test1\")" + "(header-contains \"subject\" \"Test2\"))", 2); + test_folder_search(folder, "(or (header-contains \"subject\" \"Test1\")" + "(header-contains \"subject\" \"subject\"))", 100); + test_folder_search(folder, "(or (header-contains \"subject\" \"Test1\")" + "(header-contains \"subject\" \"message99\"))", 1); + + /* 7200 is 24*60*50 == half the 'sent date' of the messages */ + test_folder_search(folder, "(> 7200 (get-sent-date))", 49); + test_folder_search(folder, "(< 7200 (get-sent-date))", 49); + test_folder_search(folder, "(= 7200 (get-sent-date))", 1); + test_folder_search(folder, "(= 7201 (get-sent-date))", 0); + + test_folder_search(folder, "(and (user-flag \"every17\") (< 7200 (get-sent-date)))", 49/17); + test_folder_search(folder, "(and (user-flag \"every17\") (> 7200 (get-sent-date)))", 49/17-1); + test_folder_search(folder, "(and (user-flag \"every13\") (< 7200 (get-sent-date)))", 49/13); + test_folder_search(folder, "(and (user-flag \"every13\") (> 7200 (get-sent-date)))", 49/13-1); + + test_folder_search(folder, "(or (user-flag \"every17\") (< 7200 (get-sent-date)))", 49); + test_folder_search(folder, "(or (user-flag \"every17\") (> 7200 (get-sent-date)))", 49); + test_folder_search(folder, "(or (user-flag \"every13\") (< 7200 (get-sent-date)))", 49); + test_folder_search(folder, "(or (user-flag \"every13\") (> 7200 (get-sent-date)))", 49); + + push("deleting every 2nd message & expunging"); + uids = camel_folder_get_uids(folder); + check(uids->len == 100); + for (j=0;j<uids->len;j++) { + camel_folder_delete_message(folder, uids->pdata[j]); + } + + push("searches after deletions, before sync"); + test_folder_search(folder, "(header-contains \"subject\" \"subject\")", 100); + test_folder_search(folder, "(body-contains \"content\")", 100); + pull(); + + camel_folder_sync(folder, FALSE, ex); + + push("searches after sync, before expunge"); + test_folder_search(folder, "(header-contains \"subject\" \"subject\")", 100); + test_folder_search(folder, "(body-contains \"content\")", 100); + pull(); + + camel_folder_expunge(folder, ex); + check_msg(!camel_exception_is_set(ex), "%s", camel_exception_get_description(ex)); + camel_folder_free_uids(folder, uids); + pull(); + + /* more searches */ + push("searches after deletions"); + test_folder_search(folder, "(header-contains \"subject\" \"subject\")", 50); + test_folder_search(folder, "(body-contains \"content\")", 50); + pull(); + + push("deleting remaining messages & expunging"); + uids = camel_folder_get_uids(folder); + check(uids->len == 100); + for (j=0;j<uids->len;j++) { + camel_folder_delete_message(folder, uids->pdata[j]); + } + camel_folder_expunge(folder, ex); + check_msg(!camel_exception_is_set(ex), "%s", camel_exception_get_description(ex)); + camel_folder_free_uids(folder, uids); + pull(); + + push("searches wtih no messages"); + test_folder_search(folder, "(header-contains \"subject\" \"subject\")", 0); + test_folder_search(folder, "(body-contains \"content\")", 0); + pull(); + + check_unref(folder, 1); + pull(); + + push("deleting test folder, with no messages in it"); + camel_store_delete_folder(store, "testbox", ex); + check_msg(!camel_exception_is_set(ex), "%s", camel_exception_get_description(ex)); + pull(); + + camel_object_unref((CamelObject *)store); + camel_test_end(); + } + } + + camel_object_unref((CamelObject *)session); + camel_exception_free(ex); + + return 0; +} diff --git a/camel/tests/lib/Makefile.am b/camel/tests/lib/Makefile.am index 1fae79671d..db09b0cf5e 100644 --- a/camel/tests/lib/Makefile.am +++ b/camel/tests/lib/Makefile.am @@ -4,7 +4,9 @@ check_LIBRARIES = libcameltest.a libcameltest_a_SOURCES = \ camel-test.c camel-test.h \ messages.c messages.h \ - addresses.c addresses.h + addresses.c addresses.h \ + folders.c folders.h + diff --git a/camel/tests/lib/folders.c b/camel/tests/lib/folders.c new file mode 100644 index 0000000000..738f8d2913 --- /dev/null +++ b/camel/tests/lib/folders.c @@ -0,0 +1,183 @@ + +#include "camel-test.h" +#include "folders.h" + +#include "camel/camel-exception.h" + +/* check the total/unread is what we think it should be */ +void +test_folder_counts(CamelFolder *folder, int total, int unread) +{ + GPtrArray *s; + int i, myunread; + const CamelMessageInfo *info; + + push("test folder counts %d total %d unread", total, unread); + + /* first, use the standard functions */ + check(camel_folder_get_message_count(folder) == total); + check(camel_folder_get_unread_message_count(folder) == total); + + /* next, use the summary */ + s = camel_folder_get_summary(folder); + check(s != NULL); + check(s->len == total); + myunread = s->len; + for (i=0;i<s->len;i++) { + info = s->pdata[i]; + if (info->flags & CAMEL_MESSAGE_SEEN) + myunread--; + } + check(unread == myunread); + camel_folder_free_summary(folder, s); + + /* last, use the uid list */ + s = camel_folder_get_uids(folder); + check(s != NULL); + check(s->len == total); + myunread = s->len; + for (i=0;i<s->len;i++) { + info = camel_folder_get_message_info(folder, s->pdata[i]); + if (info->flags & CAMEL_MESSAGE_SEEN) + myunread--; + } + check(unread == myunread); + camel_folder_free_uids(folder, s); + + pull(); +} + +static int +safe_strcmp(const char *a, const char *b) +{ + if (a == NULL && b == NULL) + return 0; + if (a == NULL) + return 1; + if (b == NULL) + return -1; + return strcmp(a, b); +} + +void +test_message_info(CamelMimeMessage *msg, const CamelMessageInfo *info) +{ + check_msg(safe_strcmp(info->subject, camel_mime_message_get_subject(msg)) == 0, + "info->subject = '%s', get_subject() = '%s'", info->subject, camel_mime_message_get_subject(msg)); + + /* FIXME: testing from/cc/to, etc is more tricky */ + + check(info->date_sent == camel_mime_message_get_date(msg, NULL)); + + /* date received isn't set for messages that haven't been sent anywhere ... */ + /*check(info->date_received == camel_mime_message_get_date_received(msg, NULL));*/ + + /* so is messageid/references, etc */ +} + +/* check a message is present */ +void +test_folder_message(CamelFolder *folder, const char *uid) +{ + CamelMimeMessage *msg; + const CamelMessageInfo *info; + GPtrArray *s; + int i; + CamelException *ex = camel_exception_new(); + int found; + + push("uid %s is in folder", uid); + + /* first try getting info */ + info = camel_folder_get_message_info(folder, uid); + check(info != NULL); + check(strcmp(info->uid, uid) == 0); + + /* then, getting message */ + msg = camel_folder_get_message(folder, uid, ex); + check_msg(!camel_exception_is_set(ex), "%s", camel_exception_get_description(ex)); + check(msg != NULL); + + /* cross check with info */ + test_message_info(msg, info); + + camel_object_unref((CamelObject *)msg); + + /* see if it is in the summary (only once) */ + s = camel_folder_get_summary(folder); + check(s != NULL); + found = 0; + for (i=0;i<s->len;i++) { + info = s->pdata[i]; + if (strcmp(info->uid, uid) == 0) + found++; + } + check(found == 1); + camel_folder_free_summary(folder, s); + + /* check it is in the uid list */ + s = camel_folder_get_uids(folder); + check(s != NULL); + found = 0; + for (i=0;i<s->len;i++) { + if (strcmp(s->pdata[i], uid) == 0) + found++; + } + check(found == 1); + camel_folder_free_uids(folder, s); + + camel_exception_free(ex); + + pull(); +} + +/* check message not present */ +void +test_folder_not_message(CamelFolder *folder, const char *uid) +{ + CamelMimeMessage *msg; + const CamelMessageInfo *info; + GPtrArray *s; + int i; + CamelException *ex = camel_exception_new(); + int found; + + push("uid %s is not in folder", uid); + + /* first try getting info */ + info = camel_folder_get_message_info(folder, uid); + check(info == NULL); + + /* then, getting message */ + msg = camel_folder_get_message(folder, uid, ex); + check(camel_exception_is_set(ex)); + check(msg == NULL); + camel_exception_clear(ex); + + /* see if it is not in the summary (only once) */ + s = camel_folder_get_summary(folder); + check(s != NULL); + found = 0; + for (i=0;i<s->len;i++) { + info = s->pdata[i]; + if (strcmp(info->uid, uid) == 0) + found++; + } + check(found == 0); + camel_folder_free_summary(folder, s); + + /* check it is not in the uid list */ + s = camel_folder_get_uids(folder); + check(s != NULL); + found = 0; + for (i=0;i<s->len;i++) { + if (strcmp(s->pdata[i], uid) == 0) + found++; + } + check(found == 0); + camel_folder_free_uids(folder, s); + + camel_exception_free(ex); + + pull(); +} diff --git a/camel/tests/lib/folders.h b/camel/tests/lib/folders.h new file mode 100644 index 0000000000..55c80e0872 --- /dev/null +++ b/camel/tests/lib/folders.h @@ -0,0 +1,13 @@ + +#include <camel/camel-folder.h> +#include <camel/camel-folder-summary.h> +#include <camel/camel-mime-message.h> + +/* check the total/unread is what we think it should be, everywhere it can be determined */ +void test_folder_counts(CamelFolder *folder, int total, int unread); +/* cross-check info/msg */ +void test_message_info(CamelMimeMessage *msg, const CamelMessageInfo *info); +/* check a message is present everywhere it should be */ +void test_folder_message(CamelFolder *folder, const char *uid); +/* check message not present everywhere it shouldn't be */ +void test_folder_not_message(CamelFolder *folder, const char *uid); diff --git a/camel/tests/message/README b/camel/tests/message/README new file mode 100644 index 0000000000..51e519cb5c --- /dev/null +++ b/camel/tests/message/README @@ -0,0 +1,3 @@ + +test1 creating, saving, loading simple messages +test2 camelinternetaddress tests, internationalised addresses, etc. |