From 7dea6c9dc22d7be2f2069bb2372d2df9df2abdd5 Mon Sep 17 00:00:00 2001 From: Not Zed Date: Wed, 27 Aug 2003 19:50:25 +0000 Subject: implement PERSISTENT_PROPERTIES, for index mode. 2003-08-27 Not Zed * providers/local/camel-local-folder.c (local_getv): implement PERSISTENT_PROPERTIES, for index mode. * camel-object.c (cobject_state_read): Also add property reading, and bump version to 1. (cobject_state_write): add persistent property writing. 2003-08-26 Not Zed * camel-folder.c (folder_getv): chain up properly. * camel-file-utils.c (camel_file_util_savename): helper to create a .#filename filename. * providers/local/camel-local-folder.c (camel_local_folder_construct): init meta-data for local folders. (local_getv): chain up properly, if args are not processed, rather than don't if they aren't. 2003-08-23 Not Zed * camel-object.c (cobject_class_init): added a new event, meta_changed. (camel_object_meta_set, camel_object_meta_get): meta-data api. (camel_object_free_hooks): Free meta-data if it is set on the object. * providers/local/camel-local-folder.c (camel_local_folder_get_type): setup a property list for local folders, just 'index_body' at present. svn path=/trunk/; revision=22388 --- camel/ChangeLog | 33 ++ camel/camel-arg.h | 9 + camel/camel-file-utils.c | 30 ++ camel/camel-file-utils.h | 2 + camel/camel-folder.c | 16 +- camel/camel-folder.h | 5 + camel/camel-object.c | 545 ++++++++++++++++++++++++++++- camel/camel-object.h | 40 ++- camel/providers/local/camel-local-folder.c | 84 ++++- camel/providers/local/camel-local-folder.h | 10 + 10 files changed, 752 insertions(+), 22 deletions(-) diff --git a/camel/ChangeLog b/camel/ChangeLog index 717c3938b9..5e081058d0 100644 --- a/camel/ChangeLog +++ b/camel/ChangeLog @@ -1,3 +1,36 @@ +2003-08-27 Not Zed + + * providers/local/camel-local-folder.c (local_getv): implement + PERSISTENT_PROPERTIES, for index mode. + + * camel-object.c (cobject_state_read): Also add property reading, + and bump version to 1. + (cobject_state_write): add persistent property writing. + +2003-08-26 Not Zed + + * camel-folder.c (folder_getv): chain up properly. + + * camel-file-utils.c (camel_file_util_savename): helper to create + a .#filename filename. + + * providers/local/camel-local-folder.c + (camel_local_folder_construct): init meta-data for local folders. + (local_getv): chain up properly, if args are not processed, rather + than don't if they aren't. + +2003-08-23 Not Zed + + * camel-object.c (cobject_class_init): added a new event, + meta_changed. + (camel_object_meta_set, camel_object_meta_get): meta-data api. + (camel_object_free_hooks): Free meta-data if it is set on the + object. + + * providers/local/camel-local-folder.c + (camel_local_folder_get_type): setup a property list for local + folders, just 'index_body' at present. + 2003-08-25 Jeffrey Stedfast * camel-filter-driver.c (pipe_to_system): Added some more error diff --git a/camel/camel-arg.h b/camel/camel-arg.h index 4c13b25559..1213596457 100644 --- a/camel/camel-arg.h +++ b/camel/camel-arg.h @@ -102,6 +102,15 @@ int camel_arggetv_build(CamelArgGetV *tv); /* set an arg ignored */ #define camel_argv_ignore(tv, i) ((tv)->argv[i].tag = ((tv)->argv[i].tag & CAMEL_ARG_TYPE) | CAMEL_ARG_IGNORE) +/* 'self-describing' property list */ +typedef struct _CamelProperty CamelProperty; + +struct _CamelProperty { + guint32 tag; + char *name; + char *description; +}; + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/camel/camel-file-utils.c b/camel/camel-file-utils.c index c6e2a0fea2..540fef2739 100644 --- a/camel/camel-file-utils.c +++ b/camel/camel-file-utils.c @@ -514,3 +514,33 @@ camel_write (int fd, const char *buf, size_t n) return written; } + +/** + * camel_file_util_savename: + * @filename: + * + * Builds a filename of the form ".#" + @filename, used to create + * a two-stage commit file write. + * + * Return value: ".#" + filename. It must be free'd with g_free(). + **/ +char * +camel_file_util_savename(const char *filename) +{ + char *name, *slash; + int off; + + name = g_malloc(strlen(filename)+3); + slash = strrchr(filename, '/'); + if (slash) { + off = slash-filename; + + memcpy(name, filename, off+1); + memcpy(name + off+1, ".#", 2); + strcpy(name + off+3, filename+off+1); + } else { + sprintf(name, ".#%s", filename); + } + + return name; +} diff --git a/camel/camel-file-utils.h b/camel/camel-file-utils.h index f1c3079b67..15022d99b3 100644 --- a/camel/camel-file-utils.h +++ b/camel/camel-file-utils.h @@ -54,6 +54,8 @@ char *camel_file_util_safe_filename (const char *name); ssize_t camel_read (int fd, char *buf, size_t n); ssize_t camel_write (int fd, const char *buf, size_t n); +char *camel_file_util_savename(const char *filename); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/camel/camel-folder.c b/camel/camel-folder.c index 9a20e81ffd..00106ca86a 100644 --- a/camel/camel-folder.c +++ b/camel/camel-folder.c @@ -245,7 +245,7 @@ camel_folder_construct (CamelFolder *folder, CamelStore *parent_store, folder->parent_store = parent_store; if (parent_store) - camel_object_ref (CAMEL_OBJECT (parent_store)); + camel_object_ref(parent_store); folder->name = g_strdup (name); folder->full_name = g_strdup (full_name); @@ -311,7 +311,7 @@ static int folder_getv(CamelObject *object, CamelException *ex, CamelArgGetV *args) { CamelFolder *folder = (CamelFolder *)object; - int i, count=args->argc; + int i; guint32 tag; for (i=0;iargc;i++) { @@ -377,18 +377,17 @@ folder_getv(CamelObject *object, CamelException *ex, CamelArgGetV *args) case CAMEL_FOLDER_ARG_INFO_ARRAY: *arg->ca_ptr = camel_folder_summary_array(folder->summary); break; + case CAMEL_FOLDER_ARG_PROPERTIES: + *arg->ca_ptr = NULL; + break; default: - count--; continue; } arg->tag = (tag & CAMEL_ARG_TYPE) | CAMEL_ARG_IGNORE; } - if (count) - return parent_class->getv(object, ex, args); - - return 0; + return parent_class->getv(object, ex, args); } static void @@ -408,6 +407,9 @@ folder_free(CamelObject *o, guint32 tag, void *val) case CAMEL_FOLDER_ARG_INFO_ARRAY: camel_folder_summary_array_free(folder->summary, val); break; + case CAMEL_FOLDER_ARG_PROPERTIES: + g_slist_free(val); + break; default: parent_class->free(o, tag, val); } diff --git a/camel/camel-folder.h b/camel/camel-folder.h index a1bb7baf66..f1fe9bfb63 100644 --- a/camel/camel-folder.h +++ b/camel/camel-folder.h @@ -52,6 +52,8 @@ enum { CAMEL_FOLDER_ARG_UNREAD, CAMEL_FOLDER_ARG_UID_ARRAY, CAMEL_FOLDER_ARG_INFO_ARRAY, + CAMEL_FOLDER_ARG_PROPERTIES, + CAMEL_FOLDER_ARG_LAST = CAMEL_ARG_FIRST + 0x2000, }; enum { @@ -64,6 +66,9 @@ enum { /* should we only get static data? not stuff that needs to be free'd? */ CAMEL_FOLDER_UID_ARRAY = CAMEL_FOLDER_ARG_UID_ARRAY | CAMEL_ARG_PTR, CAMEL_FOLDER_INFO_ARRAY = CAMEL_FOLDER_ARG_INFO_ARRAY | CAMEL_ARG_PTR, + + /* GSList of settable folder properties */ + CAMEL_FOLDER_PROPERTIES = CAMEL_FOLDER_ARG_PROPERTIES | CAMEL_ARG_PTR, }; struct _CamelFolderChangeInfo { diff --git a/camel/camel-object.c b/camel/camel-object.c index e5dbbb463f..02fd3861bf 100644 --- a/camel/camel-object.c +++ b/camel/camel-object.c @@ -30,6 +30,7 @@ #include #include "camel-object.h" +#include "camel-file-utils.h" #include #include @@ -74,6 +75,7 @@ typedef struct _CamelHookPair union { CamelObjectEventHookFunc event; CamelObjectEventPrepFunc prep; + char *filename; } func; void *data; } CamelHookPair; @@ -90,6 +92,14 @@ struct _CamelObjectBag { /* used to tag a bag hookpair */ static const char *bag_name = "object:bag"; +/* meta-data stuff */ +static void co_metadata_free(CamelObject *obj, CamelObjectMeta *meta); +static CamelObjectMeta *co_metadata_get(CamelObject *obj); +static CamelHookPair *co_metadata_pair(CamelObject *obj, int create); + +static const char *meta_name = "object:meta"; +#define CAMEL_OBJECT_STATE_FILE_MAGIC "CLMD" + /* ********************************************************************** */ static CamelHookList *camel_object_get_hooks(CamelObject *o); @@ -226,6 +236,19 @@ cobject_getv(CamelObject *o, CamelException *ex, CamelArgGetV *args) case CAMEL_OBJECT_ARG_DESCRIPTION: *arg->ca_str = (char *)o->klass->name; break; + case CAMEL_OBJECT_ARG_METADATA: + *arg->ca_ptr = co_metadata_get(o); + break; + case CAMEL_OBJECT_ARG_STATE_FILE: { + CamelHookPair *pair = co_metadata_pair(o, FALSE); + + printf("getting state file\n"); + if (pair) { + printf(" -> '%s'\n", pair->func.filename); + *arg->ca_str = g_strdup(pair->func.filename); + camel_object_unget_hooks(o); + } + break; } } } @@ -236,6 +259,29 @@ cobject_getv(CamelObject *o, CamelException *ex, CamelArgGetV *args) static int cobject_setv(CamelObject *o, CamelException *ex, CamelArgV *args) { + int i; + guint32 tag; + + for (i=0;iargc;i++) { + CamelArg *arg = &args->argv[i]; + + tag = arg->tag; + + switch (tag & CAMEL_ARG_TAG) { + case CAMEL_OBJECT_ARG_STATE_FILE: { + CamelHookPair *pair; + + printf("setting state file to '%s'\n", arg->ca_str); + + /* We store the filename on the meta-data hook-pair */ + pair = co_metadata_pair(o, TRUE); + g_free(pair->func.filename); + pair->func.filename = g_strdup(arg->ca_str); + camel_object_unget_hooks(o); + break; } + } + } + /* could have flags or stuff here? */ return 0; } @@ -243,9 +289,287 @@ cobject_setv(CamelObject *o, CamelException *ex, CamelArgV *args) static void cobject_free(CamelObject *o, guint32 tag, void *value) { - /* do nothing */ + switch(tag & CAMEL_ARG_TAG) { + case CAMEL_OBJECT_ARG_METADATA: + co_metadata_free(o, value); + break; + case CAMEL_OBJECT_ARG_STATE_FILE: + g_free(value); + break; + case CAMEL_OBJECT_ARG_PERSISTENT_PROPERTIES: + g_slist_free((GSList *)value); + break; + } +} + +static char * +cobject_meta_get(CamelObject *obj, const char * name) +{ + CamelHookPair *pair; + CamelObjectMeta *meta; + char *res = NULL; + + g_return_val_if_fail(CAMEL_IS_OBJECT (obj), 0); + g_return_val_if_fail(name != NULL, 0); + + pair = co_metadata_pair(obj, FALSE); + if (pair) { + meta = pair->data; + while (meta) { + if (!strcmp(meta->name, name)) { + res = g_strdup(meta->value); + break; + } + meta = meta->next; + } + camel_object_unget_hooks(obj); + } + + return res; +} + +static gboolean +cobject_meta_set(CamelObject *obj, const char * name, const char *value) +{ + CamelHookPair *pair; + int changed = FALSE; + CamelObjectMeta *meta, *metap; + + g_return_val_if_fail(CAMEL_IS_OBJECT (obj), FALSE); + g_return_val_if_fail(name != NULL, FALSE); + + if (obj->hooks == NULL && value == NULL) + return FALSE; + + pair = co_metadata_pair(obj, TRUE); + meta = pair->data; + metap = (CamelObjectMeta *)&pair->data; + while (meta) { + if (!strcmp(meta->name, name)) + break; + metap = meta; + meta = meta->next; + } + + /* TODO: The camelobjectmeta structure is identical to + CamelTag, they could be merged or share common code */ + if (meta == NULL) { + if (value == NULL) + goto done; + meta = g_malloc(sizeof(*meta) + strlen(name)); + meta->next = pair->data; + pair->data = meta; + strcpy(meta->name, name); + meta->value = g_strdup(value); + changed = TRUE; + } else if (value == NULL) { + metap->next = meta->next; + g_free(meta->value); + g_free(meta); + changed = TRUE; + } else if (strcmp(meta->value, value) != 0) { + g_free(meta->value); + meta->value = g_strdup(value); + changed = TRUE; + } + +done: + camel_object_unget_hooks(obj); + + return changed; +} + +/* State file for CamelObject data. Any later versions should only append data. + + version:uint32 + + Version 0 of the file: + + version:uint32 = 0 + count:uint32 -- count of meta-data items + ( name:string value:string ) *count -- meta-data items + + Version 1 of the file adds: + count:uint32 -- count of persistent properties + ( tag:uing32 value:tagtype ) *count -- persistent properties + +*/ + +static int +cobject_state_read(CamelObject *obj, FILE *fp) +{ + guint32 i, count, version; + + /* NB: for later versions, just check the version is 1 .. known version */ + if (camel_file_util_decode_uint32(fp, &version) == -1 + || version > 1 + || camel_file_util_decode_uint32(fp, &count) == -1) + return -1; + + printf("loading persistent meta-data\n"); + + for (i=0;i 0) { + CamelArgV *argv; + + printf("loading persistent properties\n"); + + if (camel_file_util_decode_uint32(fp, &count) == -1 + || count == 0) { + /* maybe it was just version 0 afterall */ + return 0; + } + + /* we batch up the properties and set them in one go */ + argv = g_malloc(sizeof(*argv) + (count - CAMEL_ARGV_MAX) * sizeof(argv->argv[0])); + argv->argc = 0; + for (i=0;iargv[argv->argc].tag) == -1) + goto cleanup; + + /* so far,only do strings and ints, doubles could be added, + object's would require a serialisation interface */ + + switch(argv->argv[argv->argc].tag & CAMEL_ARG_TYPE) { + case CAMEL_ARG_INT: + if (camel_file_util_decode_uint32(fp, &argv->argv[argv->argc].ca_int) == -1) + goto cleanup; + break; + case CAMEL_ARG_STR: + if (camel_file_util_decode_string(fp, &argv->argv[argv->argc].ca_str) == -1) + goto cleanup; + break; + default: + goto cleanup; + } + + argv->argc++; + } + + camel_object_setv(obj, NULL, argv); + cleanup: + for (i=0;iargc;i++) { + if ((argv->argv[i].tag & CAMEL_ARG_TYPE) == CAMEL_ARG_STR) + g_free(argv->argv[i].ca_str); + } + g_free(argv); + } + + return 0; } +/* TODO: should pass exception around */ +static int +cobject_state_write(CamelObject *obj, FILE *fp) +{ + gint32 count, i; + CamelObjectMeta *meta = NULL, *scan; + int res = -1; + GSList *props = NULL, *l; + CamelArgGetV *arggetv = NULL; + CamelArgV *argv = NULL; + + camel_object_get(obj, NULL, CAMEL_OBJECT_METADATA, &meta, NULL); + + count = 0; + scan = meta; + while (scan) { + count++; + scan = scan->next; + } + + /* current version is 1 */ + if (camel_file_util_encode_uint32(fp, 1) == -1 + || camel_file_util_encode_uint32(fp, count) == -1) + goto abort; + + scan = meta; + while (scan) { + if (camel_file_util_encode_string(fp, meta->name) == -1 + || camel_file_util_encode_string(fp, meta->value) == -1) + goto abort; + scan = scan->next; + } + + camel_object_get(obj, NULL, CAMEL_OBJECT_PERSISTENT_PROPERTIES, &props, NULL); + + /* we build an arggetv to query the object atomically, + we also need an argv to store the results - bit messy */ + + count = g_slist_length(props); + + printf("saving persistent properties, count = %d\n", count); + + arggetv = g_malloc0(sizeof(*arggetv) + (count - CAMEL_ARGV_MAX) * sizeof(arggetv->argv[0])); + argv = g_malloc0(sizeof(*argv) + (count - CAMEL_ARGV_MAX) * sizeof(argv->argv[0])); + l = props; + i = 0; + while (l) { + CamelProperty *prop = l->data; + + argv->argv[i].tag = prop->tag; + arggetv->argv[i].tag = prop->tag; + arggetv->argv[i].ca_ptr = &argv->argv[i].ca_ptr; + + i++; + l = l->next; + } + arggetv->argc = i; + argv->argc = i; + + camel_object_getv(obj, NULL, arggetv); + + if (camel_file_util_encode_uint32(fp, count) == -1) + goto abort; + + for (i=0;iargc;i++) { + CamelArg *arg = &argv->argv[i]; + + if (camel_file_util_encode_uint32(fp, arg->tag) == -1) + goto abort; + + switch (arg->tag & CAMEL_ARG_TYPE) { + case CAMEL_ARG_INT: + if (camel_file_util_encode_uint32(fp, arg->ca_int) == -1) + goto abort; + break; + case CAMEL_ARG_STR: + if (camel_file_util_encode_string(fp, arg->ca_str) == -1) + goto abort; + break; + } + } + + res = 0; +abort: + g_free(argv); + g_free(arggetv); + + if (props) + camel_object_free(obj, CAMEL_OBJECT_PERSISTENT_PROPERTIES, props); + + if (meta) + camel_object_free(obj, CAMEL_OBJECT_METADATA, meta); + + return res; +} + + static void cobject_class_init(CamelObjectClass *klass) { @@ -255,7 +579,13 @@ cobject_class_init(CamelObjectClass *klass) klass->setv = cobject_setv; klass->free = cobject_free; + klass->meta_get = cobject_meta_get; + klass->meta_set = cobject_meta_set; + klass->state_read = cobject_state_read; + klass->state_write = cobject_state_write; + camel_object_class_add_event(klass, "finalize", NULL); + camel_object_class_add_event(klass, "meta_changed", NULL); } static void @@ -675,6 +1005,12 @@ camel_object_free_hooks (CamelObject *o) pair = o->hooks->list; while (pair) { next = pair->next; + + if (pair->name == meta_name) { + co_metadata_free(o, pair->data); + g_free(pair->func.filename); + } + pair_free(pair); pair = next; } @@ -981,6 +1317,213 @@ int camel_object_getv(void *vo, CamelException *ex, CamelArgGetV *args) return ((CamelObject *)vo)->klass->getv(vo, ex, args); } +/* NB: If this doesn't return NULL, then you must unget_hooks when done */ +static CamelHookPair * +co_metadata_pair(CamelObject *obj, int create) +{ + CamelHookPair *pair; + CamelHookList *hooks; + + if (obj->hooks == NULL && !create) + return NULL; + + hooks = camel_object_get_hooks(obj); + pair = hooks->list; + while (pair) { + if (pair->name == meta_name) + return pair; + + pair = pair->next; + } + + if (create) { + pair = pair_alloc(); + pair->name = meta_name; + pair->data = NULL; + pair->flags = 0; + pair->func.filename = NULL; + pair->next = hooks->list; + hooks->list = pair; + hooks->list_length++; + } else { + camel_object_unget_hooks(obj); + } + + return pair; +} + +static CamelObjectMeta * +co_metadata_get(CamelObject *obj) +{ + CamelHookPair *pair; + CamelObjectMeta *meta = NULL, *metaout = NULL, *metalast; + + pair = co_metadata_pair(obj, FALSE); + if (pair) { + meta = pair->data; + + while (meta) { + CamelObjectMeta *m; + + m = g_malloc(sizeof(*metalast) + strlen(meta->name)); + m->next = NULL; + strcpy(m->name, meta->name); + m->value = g_strdup(meta->value); + if (metaout == NULL) + metalast = metaout = m; + else { + metalast->next = m; + metalast = m; + } + meta = meta->next; + } + + camel_object_unget_hooks(obj); + } + + return metaout; +} + +static void +co_metadata_free(CamelObject *obj, CamelObjectMeta *meta) +{ + while (meta) { + CamelObjectMeta *metan = meta->next; + + g_free(meta->value); + g_free(meta); + meta = metan; + } +} + +/** + * camel_object_meta_get: + * @vo: + * @name: + * + * Get a meta-data on an object. + * + * Return value: NULL if the meta-data is not set. + **/ +char * +camel_object_meta_get(void *vo, const char * name) +{ + CamelObject *obj = vo; + + g_return_val_if_fail(CAMEL_IS_OBJECT (obj), 0); + g_return_val_if_fail(name != NULL, 0); + + return obj->klass->meta_get(obj, name); +} + +/** + * camel_object_meta_set: + * @vo: + * @name: Name of meta-data. Should be prefixed with class of setter. + * @value: Value to set. If NULL, then the meta-data is removed. + * + * Set a meta-data item on an object. If the object supports persistent + * data, then the meta-data will be persistent across sessions. + * + * If the meta-data changes, is added, or removed, then a + * "meta_changed" event will be triggered with the name of the changed + * data. + * + * Return Value: TRUE if the setting caused a change to the object's + * metadata. + **/ +gboolean +camel_object_meta_set(void *vo, const char * name, const char *value) +{ + CamelObject *obj = vo; + + g_return_val_if_fail(CAMEL_IS_OBJECT (obj), FALSE); + g_return_val_if_fail(name != NULL, FALSE); + + if (obj->klass->meta_set(obj, name, value)) { + camel_object_trigger_event(obj, "meta_changed", (void *)name); + return TRUE; + } + + return FALSE; +} + +/** + * camel_object_state_read: + * @vo: + * + * Read persistent object state from object_set(CAMEL_OBJECT_STATE_FILE). + * + * Return value: -1 on error. + **/ +int camel_object_state_read(void *vo) +{ + CamelObject *obj = vo; + int res = -1; + char *file; + FILE *fp; + char magic[4]; + + camel_object_get(vo, NULL, CAMEL_OBJECT_STATE_FILE, &file, NULL); + if (file == NULL) + return 0; + + fp = fopen(file, "r"); + if (fp != NULL) { + if (fread(magic, 4, 1, fp) == 1 + && memcmp(magic, CAMEL_OBJECT_STATE_FILE_MAGIC, 4) == 0) + res = obj->klass->state_read(obj, fp); + else + res = -1; + fclose(fp); + } + + camel_object_free(vo, CAMEL_OBJECT_STATE_FILE, file); + + return res; +} + +/** + * camel_object_state_write: + * @vo: + * + * Write persistent state to the file as set by object_set(CAMEL_OBJECT_STATE_FILE). + * + * Return value: -1 on error. + **/ +int camel_object_state_write(void *vo) +{ + CamelObject *obj = vo; + int res = -1; + char *file, *savename; + FILE *fp; + + camel_object_get(vo, NULL, CAMEL_OBJECT_STATE_FILE, &file, NULL); + if (file == NULL) + return 0; + + printf("camel_object_state_write -> '%s'\n", file); + + savename = camel_file_util_savename(file); + fp = fopen(savename, "w"); + if (fp != NULL) { + if (fwrite(CAMEL_OBJECT_STATE_FILE_MAGIC, 4, 1, fp) == 1 + && obj->klass->state_write(obj, fp) == 0) { + if (fclose(fp) == 0) { + res = 0; + rename(savename, file); + } + } else { + fclose(fp); + } + } + + g_free(savename); + camel_object_free(vo, CAMEL_OBJECT_STATE_FILE, file); + + return res; +} + /* free an arg object, you can only free objects 1 at a time */ void camel_object_free(void *vo, guint32 tag, void *value) { diff --git a/camel/camel-object.h b/camel/camel-object.h index 0bcdeaef0f..a13cf69325 100644 --- a/camel/camel-object.h +++ b/camel/camel-object.h @@ -33,6 +33,7 @@ extern "C" { #endif /* __cplusplus */ #include +#include /* FILE */ #include /* size_t */ #include #include @@ -74,6 +75,7 @@ extern CamelType camel_object_type; typedef struct _CamelObjectClass CamelObjectClass; typedef struct _CamelObject CamelObject; typedef unsigned int CamelObjectHookID; +typedef struct _CamelObjectMeta CamelObjectMeta; typedef void (*CamelObjectClassInitFunc) (CamelObjectClass *); typedef void (*CamelObjectClassFinalizeFunc) (CamelObjectClass *); @@ -85,19 +87,37 @@ typedef void (*CamelObjectEventHookFunc) (CamelObject *, gpointer, gpointer); #define CAMEL_INVALID_TYPE (NULL) -/* camel object args */ +/* camel object args. */ enum { - CAMEL_OBJECT_ARG_DESCRIPTION = CAMEL_ARG_FIRST, + /* Get a description of the object. */ + CAMEL_OBJECT_ARG_DESCRIPTION = CAMEL_ARG_FIRST, /* Get a copy of the meta-data list (should be freed) */ + CAMEL_OBJECT_ARG_METADATA, + CAMEL_OBJECT_ARG_STATE_FILE, + CAMEL_OBJECT_ARG_PERSISTENT_PROPERTIES, }; enum { CAMEL_OBJECT_DESCRIPTION = CAMEL_OBJECT_ARG_DESCRIPTION | CAMEL_ARG_STR, + /* Returns a CamelObjectMeta list */ + CAMEL_OBJECT_METADATA = CAMEL_OBJECT_ARG_METADATA | CAMEL_ARG_PTR, + /* sets where the persistent data should reside, otherwise it isn't persistent */ + CAMEL_OBJECT_STATE_FILE = CAMEL_OBJECT_ARG_STATE_FILE | CAMEL_ARG_STR, + /* returns a GSList CamelProperties of persistent properties */ + CAMEL_OBJECT_PERSISTENT_PROPERTIES = CAMEL_OBJECT_ARG_PERSISTENT_PROPERTIES | CAMEL_ARG_PTR, }; enum _CamelObjectFlags { CAMEL_OBJECT_DESTROY = (1<<0), }; +/* returned by get::CAMEL_OBJECT_METADATA */ +struct _CamelObjectMeta { + struct _CamelObjectMeta *next; + + char *value; + char name[1]; /* allocated as part of structure */ +}; + /* TODO: create a simpleobject which has no events on it, or an interface for events */ struct _CamelObject { struct _CamelObjectClass *klass; @@ -155,6 +175,14 @@ struct _CamelObjectClass int (*getv)(struct _CamelObject *, struct _CamelException *ex, CamelArgGetV *args); /* we only free 1 at a time, and only pointer types, obviously */ void (*free)(struct _CamelObject *, guint32 tag, void *ptr); + + /* get/set meta-data interface */ + char *(*meta_get)(struct _CamelObject *, const char * name); + gboolean (*meta_set)(struct _CamelObject *, const char * name, const char *value); + + /* persistence stuff */ + int (*state_read)(struct _CamelObject *, FILE *fp); + int (*state_write)(struct _CamelObject *, FILE *fp); }; /* The type system .... it's pretty simple..... */ @@ -209,6 +237,14 @@ int camel_object_setv(void *obj, struct _CamelException *ex, CamelArgV *); int camel_object_get(void *obj, struct _CamelException *ex, ...); int camel_object_getv(void *obj, struct _CamelException *ex, CamelArgGetV *); +/* meta-data for user-specific data */ +char *camel_object_meta_get(void *vo, const char * name); +gboolean camel_object_meta_set(void *vo, const char * name, const char *value); + +/* reads/writes the state from/to the CAMEL_OBJECT_STATE_FILE */ +int camel_object_state_read(void *vo); +int camel_object_state_write(void *vo); + /* free a bunch of objects, list must be 0 terminated */ void camel_object_free(void *vo, guint32 tag, void *value); diff --git a/camel/providers/local/camel-local-folder.c b/camel/providers/local/camel-local-folder.c index 0945f92370..91d001ccfc 100644 --- a/camel/providers/local/camel-local-folder.c +++ b/camel/providers/local/camel-local-folder.c @@ -59,7 +59,8 @@ #define PATH_MAX _POSIX_PATH_MAX #endif -static CamelFolderClass *parent_class = NULL; +static CamelFolderClass *parent_class; +static GSList *local_folder_properties; /* Returns the class for a CamelLocalFolder */ #define CLOCALF_CLASS(so) CAMEL_LOCAL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(so)) @@ -67,6 +68,7 @@ static CamelFolderClass *parent_class = NULL; #define CLOCALS_CLASS(so) CAMEL_STORE_CLASS (CAMEL_OBJECT_GET_CLASS(so)) static int local_getv(CamelObject *object, CamelException *ex, CamelArgGetV *args); +static int local_setv(CamelObject *object, CamelException *ex, CamelArgV *args); static int local_lock(CamelLocalFolder *lf, CamelLockType type, CamelException *ex); static void local_unlock(CamelLocalFolder *lf); @@ -91,12 +93,11 @@ camel_local_folder_class_init(CamelLocalFolderClass * camel_local_folder_class) CamelFolderClass *camel_folder_class = CAMEL_FOLDER_CLASS(camel_local_folder_class); CamelObjectClass *oklass = (CamelObjectClass *)camel_local_folder_class; - parent_class = CAMEL_FOLDER_CLASS(camel_type_get_global_classfuncs(camel_folder_get_type())); - /* virtual method definition */ /* virtual method overload */ oklass->getv = local_getv; + oklass->setv = local_setv; camel_folder_class->refresh_info = local_refresh_info; camel_folder_class->sync = local_sync; @@ -168,19 +169,31 @@ local_finalize(CamelObject * object) g_free(local_folder->priv); } +static CamelProperty local_property_list[] = { + { CAMEL_LOCAL_FOLDER_INDEX_BODY, "index_body", N_("Index message body data") }, +}; + CamelType camel_local_folder_get_type(void) { static CamelType camel_local_folder_type = CAMEL_INVALID_TYPE; if (camel_local_folder_type == CAMEL_INVALID_TYPE) { - camel_local_folder_type = camel_type_register(CAMEL_FOLDER_TYPE, "CamelLocalFolder", + int i; + + parent_class = (CamelFolderClass *)camel_folder_get_type(); + camel_local_folder_type = camel_type_register(camel_folder_get_type(), "CamelLocalFolder", sizeof(CamelLocalFolder), sizeof(CamelLocalFolderClass), (CamelObjectClassInitFunc) camel_local_folder_class_init, NULL, (CamelObjectInitFunc) local_init, (CamelObjectFinalizeFunc) local_finalize); + + for (i=0;isummary_path = g_strdup_printf("%s.ev-summary", tmp); lf->index_path = g_strdup_printf("%s.ibex", tmp); + statepath = alloca(strlen(tmp)+7); + sprintf(statepath, "%s.cmeta", tmp); } else { lf->folder_path = g_strdup_printf("%s/%s", root_dir_path, full_name); lf->summary_path = g_strdup_printf("%s/%s.ev-summary", root_dir_path, full_name); lf->index_path = g_strdup_printf("%s/%s.ibex", root_dir_path, full_name); + statepath = alloca(strlen(full_name)+strlen(root_dir_path)+8); + sprintf(statepath, "%s/%s.cmeta", root_dir_path, full_name); } - + camel_object_set(lf, NULL, CAMEL_OBJECT_STATE_FILE, statepath, NULL); + if (camel_object_state_read(lf) == -1) { + /* FIXME: load defaults? */ + } + /* follow any symlinks to the mailbox */ if (lstat (lf->folder_path, &st) != -1 && S_ISLNK (st.st_mode) && realpath (lf->folder_path, folder_path) != NULL) { @@ -326,7 +347,7 @@ static int local_getv(CamelObject *object, CamelException *ex, CamelArgGetV *args) { CamelFolder *folder = (CamelFolder *)object; - int i, count=args->argc; + int i; guint32 tag; for (i=0;iargc;i++) { @@ -335,7 +356,6 @@ local_getv(CamelObject *object, CamelException *ex, CamelArgGetV *args) tag = arg->tag; switch (tag & CAMEL_ARG_TAG) { - /* CamelObject args */ case CAMEL_OBJECT_ARG_DESCRIPTION: if (folder->description == NULL) { char *tmp, *path; @@ -366,18 +386,58 @@ local_getv(CamelObject *object, CamelException *ex, CamelArgGetV *args) } *arg->ca_str = folder->description; break; + + case CAMEL_OBJECT_ARG_PERSISTENT_PROPERTIES: + case CAMEL_FOLDER_ARG_PROPERTIES: { + CamelArgGetV props; + + props.argc = 1; + props.argv[0] = *arg; + ((CamelObjectClass *)parent_class)->getv(object, ex, &props); + *arg->ca_ptr = g_slist_concat(*arg->ca_ptr, local_folder_properties); + + break; } + + case CAMEL_LOCAL_FOLDER_INDEX_BODY: + /* FIXME: remove this from sotre flags */ + *arg->ca_int = (((CamelLocalFolder *)folder)->flags & CAMEL_STORE_FOLDER_BODY_INDEX) != 0; + break; + default: skip: - count--; continue; } arg->tag = (tag & CAMEL_ARG_TYPE) | CAMEL_ARG_IGNORE; } - if (count) - return ((CamelObjectClass *)parent_class)->getv(object, ex, args); + return ((CamelObjectClass *)parent_class)->getv(object, ex, args); +} - return 0; +static int +local_setv(CamelObject *object, CamelException *ex, CamelArgV *args) +{ + CamelFolder *folder = (CamelFolder *)object; + int i; + guint32 tag; + + for (i=0;iargc;i++) { + CamelArg *arg = &args->argv[i]; + + tag = arg->tag; + + switch (tag & CAMEL_ARG_TAG) { + case CAMEL_LOCAL_FOLDER_INDEX_BODY: + /* FIXME: implement */ + printf("setting folder indexing %s\n", arg->ca_int?"on":"off"); + break; + default: + continue; + } + + arg->tag = (tag & CAMEL_ARG_TYPE) | CAMEL_ARG_IGNORE; + } + + return ((CamelObjectClass *)parent_class)->setv(object, ex, args); } static int diff --git a/camel/providers/local/camel-local-folder.h b/camel/providers/local/camel-local-folder.h index c958bde835..63a6870793 100644 --- a/camel/providers/local/camel-local-folder.h +++ b/camel/providers/local/camel-local-folder.h @@ -40,6 +40,16 @@ extern "C" { #define CAMEL_LOCAL_FOLDER_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), CAMEL_LOCAL_FOLDER_TYPE, CamelLocalFolderClass)) #define CAMEL_IS_LOCAL_FOLDER(o) (CAMEL_CHECK_TYPE((o), CAMEL_LOCAL_FOLDER_TYPE)) +enum { + CAMEL_LOCAL_FOLDER_ARG_INDEX_BODY = CAMEL_FOLDER_ARG_LAST, + + CAMEL_LOCAL_FOLDER_ARG_LAST = CAMEL_FOLDER_ARG_LAST + 0x100 +}; + +enum { + CAMEL_LOCAL_FOLDER_INDEX_BODY = CAMEL_LOCAL_FOLDER_ARG_INDEX_BODY | CAMEL_ARG_INT, +}; + typedef struct { CamelFolder parent_object; struct _CamelLocalFolderPrivate *priv; -- cgit v1.2.3