implement PERSISTENT_PROPERTIES, for index mode.
2003-08-27 Not Zed <NotZed@Ximian.com> * 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 <NotZed@Ximian.com> * 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 <NotZed@Ximian.com> * 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
This commit is contained in:
@ -1,3 +1,36 @@
|
||||
2003-08-27 Not Zed <NotZed@Ximian.com>
|
||||
|
||||
* 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 <NotZed@Ximian.com>
|
||||
|
||||
* 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 <NotZed@Ximian.com>
|
||||
|
||||
* 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 <fejj@ximian.com>
|
||||
|
||||
* camel-filter-driver.c (pipe_to_system): Added some more error
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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;i<args->argc;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);
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -30,6 +30,7 @@
|
||||
#include <semaphore.h>
|
||||
|
||||
#include "camel-object.h"
|
||||
#include "camel-file-utils.h"
|
||||
|
||||
#include <e-util/e-memory.h>
|
||||
#include <e-util/e-msgport.h>
|
||||
@ -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;i<args->argc;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<count;i++) {
|
||||
char *name = NULL, *value = NULL;
|
||||
|
||||
if (camel_file_util_decode_string(fp, &name) == 0
|
||||
&& camel_file_util_decode_string(fp, &value) == 0) {
|
||||
camel_object_meta_set(obj, name, value);
|
||||
g_free(name);
|
||||
g_free(value);
|
||||
} else {
|
||||
g_free(name);
|
||||
g_free(value);
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (version > 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;i<count;i++) {
|
||||
if (camel_file_util_decode_uint32(fp, &argv->argv[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;i<argv->argc;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;i<argv->argc;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)
|
||||
{
|
||||
|
||||
@ -33,6 +33,7 @@ extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#include <glib.h>
|
||||
#include <stdio.h> /* FILE */
|
||||
#include <stdlib.h> /* size_t */
|
||||
#include <stdarg.h>
|
||||
#include <pthread.h>
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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;i<sizeof(local_property_list)/sizeof(local_property_list[0]);i++) {
|
||||
local_property_list[i].description = _(local_property_list[i].description);
|
||||
local_folder_properties = g_slist_prepend(local_folder_properties, &local_property_list[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return camel_local_folder_type;
|
||||
@ -192,7 +205,7 @@ camel_local_folder_construct(CamelLocalFolder *lf, CamelStore *parent_store, con
|
||||
CamelFolderInfo *fi;
|
||||
CamelFolder *folder;
|
||||
const char *root_dir_path, *name;
|
||||
char *tmp;
|
||||
char *tmp, *statepath;
|
||||
char folder_path[PATH_MAX];
|
||||
struct stat st;
|
||||
int forceindex, len;
|
||||
@ -223,12 +236,20 @@ camel_local_folder_construct(CamelLocalFolder *lf, CamelStore *parent_store, con
|
||||
/* not really sure to do with these for now? */
|
||||
lf->summary_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;i<args->argc;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;i<args->argc;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
|
||||
|
||||
@ -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;
|
||||
|
||||
Reference in New Issue
Block a user