Shite, -1 on error, >=0 on success. So i've just been truncating all the

2000-11-21  Not Zed  <NotZed@HelixCode.com>

	* providers/local/camel-mh-summary.c (mh_summary_sync_message):
	Shite, -1 on error, >=0 on success.  So i've just been truncating
	all the messages I touched, good one zed.
	(mh_summary_sync_message): Sigh, and write to the right damn fd as
	well.
	(mh_summary_sync_message): Argh, and we need to compare the length
	of the old xev -1 to the new xev, to check if we can optimise it.

	* camel-folder.c (camel_folder_change_info_new): Init the pool.
	(camel_folder_change_info_add_source): Allocate string in the
	pool.
	(camel_folder_change_info_add_source_list):
	(camel_folder_change_info_add_update): No longer free the key, as
	it cannot be yet.
	(change_info_add_uid): Add a new arg, copy, telling it whether to
	copy the uid argument or not, and copy using mempool_strdup.
	(change_info_cat): Tell add_uid to copy the string.
	(camel_folder_change_info_add_update): Call add_uid directly.
	(change_info_remove): Call add_uid directly, with no copy, and
	dont free the key.
	(change_info_free_update): No longer required since we dont malloc
	the keys.
	(camel_folder_change_info_add_uid): Fix for add_uid change.
	(camel_folder_change_info_remove_uid):
	(camel_folder_change_info_change_uid):
	(change_info_clear): No longer needed, just set the size to 0 on
	the array directly.
	(camel_folder_change_info_clear): Empty the arrays directly, and
	flush the mempool too, and also clear uid_source, incase anyone
	was silly enough to call us in the wrong order.
	(camel_folder_change_info_free): Dont bother clearing the array's
	contents, just free the pool and throw away all the indexes.

	* camel-folder.h: Added a mempool to CamelFolderChangeInfo to
	store the uid's we get.

	* camel-folder-search.c (search_match_all): If we are only
	matching a single info, just use that/do the search.
	(camel_folder_search_match_expression): New function.  Matches a
	single message info against an expression.
	(camel_folder_search_init): Init a hash table used to map the
	returned gptrarrays' to mempools.
	(camel_folder_search_execute_expression): Store all of the string
	data in a mempool, slightly faster, less wasted space (usually),.
	(camel_folder_search_free_result): Check for the mempool that
	stores the data for the list, and free that if we have it,
	otherwise assume we need to use g_free() (which should only happen
	if the list is empty at the moment).
	: commented out the debugging prints.  Got sick of 'executing
	header search' crap.

	* providers/vee/camel-vee-folder.c (camel_vee_folder_init): Init
	changes.
	(camel_vee_folder_finalise): Free changes.
	(vfolder_add_match): Simple helper to add a new matching info
	record.
	(camel_vee_folder_add_folder): Only trigger a changed event if we
	have changes.
	(vfolder_change_match): New function, changes our local vfolder
	info to match the source.
	(vfolder_add_match): Add a new info to the vfolder list.
	(vfolder_remove_match): Remove a no-longer matching info from the
	vfolder summary.
	(message_changed): check if the message still matches, and
	remove/etc as required.
	(camel_vee_folder_finalise, init): init/free search object.
	(vee_folder_build_folder): Build the changes to the folder into
	the changes data, as we go.
	(folder_changed): If the folder gave us an explicit list of
	changes, then process each one separately (unless there's a lot
	added/changed).

	* providers/vee/camel-vee-folder.h: Added a changes field to the
	folder.

svn path=/trunk/; revision=6628
This commit is contained in:
Not Zed
2000-11-21 13:38:53 +00:00
committed by Michael Zucci
parent c657e20b4c
commit a34a4b15b8
11 changed files with 462 additions and 95 deletions

View File

@ -1,5 +1,80 @@
2000-11-21 Not Zed <NotZed@HelixCode.com>
* providers/local/camel-mh-summary.c (mh_summary_sync_message):
Shite, -1 on error, >=0 on success. So i've just been truncating
all the messages I touched, good one zed.
(mh_summary_sync_message): Sigh, and write to the right damn fd as
well.
(mh_summary_sync_message): Argh, and we need to compare the length
of the old xev -1 to the new xev, to check if we can optimise it.
* camel-folder.c (camel_folder_change_info_new): Init the pool.
(camel_folder_change_info_add_source): Allocate string in the
pool.
(camel_folder_change_info_add_source_list):
(camel_folder_change_info_add_update): No longer free the key, as
it cannot be yet.
(change_info_add_uid): Add a new arg, copy, telling it whether to
copy the uid argument or not, and copy using mempool_strdup.
(change_info_cat): Tell add_uid to copy the string.
(camel_folder_change_info_add_update): Call add_uid directly.
(change_info_remove): Call add_uid directly, with no copy, and
dont free the key.
(change_info_free_update): No longer required since we dont malloc
the keys.
(camel_folder_change_info_add_uid): Fix for add_uid change.
(camel_folder_change_info_remove_uid):
(camel_folder_change_info_change_uid):
(change_info_clear): No longer needed, just set the size to 0 on
the array directly.
(camel_folder_change_info_clear): Empty the arrays directly, and
flush the mempool too, and also clear uid_source, incase anyone
was silly enough to call us in the wrong order.
(camel_folder_change_info_free): Dont bother clearing the array's
contents, just free the pool and throw away all the indexes.
* camel-folder.h: Added a mempool to CamelFolderChangeInfo to
store the uid's we get.
* camel-folder-search.c (search_match_all): If we are only
matching a single info, just use that/do the search.
(camel_folder_search_match_expression): New function. Matches a
single message info against an expression.
(camel_folder_search_init): Init a hash table used to map the
returned gptrarrays' to mempools.
(camel_folder_search_execute_expression): Store all of the string
data in a mempool, slightly faster, less wasted space (usually),.
(camel_folder_search_free_result): Check for the mempool that
stores the data for the list, and free that if we have it,
otherwise assume we need to use g_free() (which should only happen
if the list is empty at the moment).
: commented out the debugging prints. Got sick of 'executing
header search' crap.
* providers/vee/camel-vee-folder.c (camel_vee_folder_init): Init
changes.
(camel_vee_folder_finalise): Free changes.
(vfolder_add_match): Simple helper to add a new matching info
record.
(camel_vee_folder_add_folder): Only trigger a changed event if we
have changes.
(vfolder_change_match): New function, changes our local vfolder
info to match the source.
(vfolder_add_match): Add a new info to the vfolder list.
(vfolder_remove_match): Remove a no-longer matching info from the
vfolder summary.
(message_changed): check if the message still matches, and
remove/etc as required.
(camel_vee_folder_finalise, init): init/free search object.
(vee_folder_build_folder): Build the changes to the folder into
the changes data, as we go.
(folder_changed): If the folder gave us an explicit list of
changes, then process each one separately (unless there's a lot
added/changed).
* providers/vee/camel-vee-folder.h: Added a changes field to the
folder.
* Makefile.am (libcamel_la_SOURCES): Added
camel-folder-thread.[ch].

View File

@ -39,11 +39,13 @@
#include "camel-mime-message.h"
#include "gmime-content-field.h"
#include "camel-stream-mem.h"
#include "e-util/e-memory.h"
#define d(x) x
#define r(x) x
#define d(x)
#define r(x)
struct _CamelFolderSearchPrivate {
GHashTable *mempool_hash;
};
#define _PRIVATE(o) (((CamelFolderSearch *)(o))->priv)
@ -88,16 +90,39 @@ camel_folder_search_init (CamelFolderSearch *obj)
p = _PRIVATE(obj) = g_malloc0(sizeof(*p));
obj->sexp = e_sexp_new();
/* use a hash of mempools to associate the returned uid lists with
the backing mempool. yes pretty weird, but i didn't want to change
the api just yet */
p->mempool_hash = g_hash_table_new(0, 0);
}
static void
free_mempool(void *key, void *value, void *data)
{
GPtrArray *uids = key;
EMemPool *pool = value;
g_warning("Search closed with outstanding result unfreed: %p", uids);
g_ptr_array_free(uids, TRUE);
e_mempool_destroy(pool);
}
static void
camel_folder_search_finalize (CamelObject *obj)
{
CamelFolderSearch *search = (CamelFolderSearch *)obj;
struct _CamelFolderSearchPrivate *p = _PRIVATE(obj);
if (search->sexp)
camel_object_unref((CamelObject *)search->sexp);
g_free(search->last_search);
g_hash_table_foreach(p->mempool_hash, free_mempool, obj);
g_hash_table_destroy(p->mempool_hash);
g_free(p);
}
CamelType
@ -266,6 +291,8 @@ camel_folder_search_execute_expression(CamelFolderSearch *search, const char *ex
GPtrArray *matches = g_ptr_array_new ();
int i;
GHashTable *results;
EMemPool *pool;
struct _CamelFolderSearchPrivate *p = _PRIVATE(search);
/* only re-parse if the search has changed */
if (search->last_search == NULL
@ -281,6 +308,11 @@ camel_folder_search_execute_expression(CamelFolderSearch *search, const char *ex
if (r
&& r->type == ESEXP_RES_ARRAY_PTR) {
d(printf("got result ...\n"));
/* we use a mempool to store the strings, packed in tight as possible, and freed together */
/* because the strings are often short (like <8 bytes long), we would be wasting appx 50%
of memory just storing the size tag that malloc assigns us and alignment padding, so this
gets around that (and is faster to allocate and free as a bonus) */
pool = e_mempool_new(512, 256, E_MEMPOOL_ALIGN_BYTE);
if (search->summary) {
/* reorder result in summary order */
results = g_hash_table_new(g_str_hash, g_str_equal);
@ -291,17 +323,25 @@ camel_folder_search_execute_expression(CamelFolderSearch *search, const char *ex
for (i=0;i<search->summary->len;i++) {
CamelMessageInfo *info = g_ptr_array_index(search->summary, i);
if (g_hash_table_lookup(results, info->uid)) {
g_ptr_array_add(matches, g_strdup(info->uid));
char *s = e_mempool_alloc(pool, strlen(info->uid) + 1);
strcpy(s, info->uid);
g_ptr_array_add(matches, s);
}
}
g_hash_table_destroy(results);
} else {
for (i=0;i<r->value.ptrarray->len;i++) {
char *s = e_mempool_alloc(pool, strlen(g_ptr_array_index(r->value.ptrarray, i)) + 1);
d(printf("adding match: %s\n", (char *)g_ptr_array_index(r->value.ptrarray, i)));
g_ptr_array_add(matches, g_strdup(g_ptr_array_index(r->value.ptrarray, i)));
strcpy(s, g_ptr_array_index(r->value.ptrarray, i));
g_ptr_array_add(matches, s);
}
}
e_sexp_result_free(r);
/* instead of putting the mempool_hash in the structure, we keep the api clean by
putting a reference to it in a hashtable. Lets us do some debugging and catch
unfree'd results as well. */
g_hash_table_insert(p->mempool_hash, matches, pool);
} else {
printf("no result!\n");
}
@ -314,12 +354,52 @@ camel_folder_search_execute_expression(CamelFolderSearch *search, const char *ex
return matches;
}
/**
* camel_folder_search_match_expression:
* @search:
* @expr:
* @info:
* @ex:
*
* Returns #TRUE if the expression matches the specific message info @info.
* Note that the folder and index may need to be set for body searches to
* operate as well.
*
* Return value:
**/
gboolean
camel_folder_search_match_expression(CamelFolderSearch *search, const char *expr, const CamelMessageInfo *info, CamelException *ex)
{
GPtrArray *uids;
int ret = FALSE;
search->match1 = (CamelMessageInfo *)info;
uids = camel_folder_search_execute_expression(search, expr, ex);
if (uids) {
if (uids->len == 1)
ret = TRUE;
camel_folder_search_free_result(search, uids);
}
search->match1 = NULL;
return ret;
}
void camel_folder_search_free_result(CamelFolderSearch *search, GPtrArray *result)
{
int i;
struct _CamelFolderSearchPrivate *p = _PRIVATE(search);
EMemPool *pool;
for (i=0;i<result->len;i++)
g_free(g_ptr_array_index(result, i));
pool = g_hash_table_lookup(p->mempool_hash, result);
if (pool) {
e_mempool_destroy(pool);
g_hash_table_remove(p->mempool_hash, result);
} else {
for (i=0;i<result->len;i++)
g_free(g_ptr_array_index(result, i));
}
g_ptr_array_free(result, TRUE);
}
@ -352,6 +432,27 @@ search_match_all(struct _ESExp *f, int argc, struct _ESExpTerm **argv, CamelFold
r = e_sexp_result_new(ESEXP_RES_ARRAY_PTR);
r->value.ptrarray = g_ptr_array_new();
/* we are only matching a single message? */
if (search->match1) {
search->current = search->match1;
if (argc>0) {
r1 = e_sexp_term_eval(f, argv[0]);
if (r1->type == ESEXP_RES_BOOL) {
if (r1->value.bool)
g_ptr_array_add(r->value.ptrarray, search->current->uid);
} else {
g_warning("invalid syntax, matches require a single bool result");
}
e_sexp_result_free(r1);
} else {
g_ptr_array_add(r->value.ptrarray, search->current->uid);
}
search->current = NULL;
return r;
}
if (search->summary == NULL) {
/* TODO: make it work - e.g. use the folder and so forth for a slower search */
g_warning("No summary supplied, match-all doesn't work with no summary");

View File

@ -46,6 +46,7 @@ struct _CamelFolderSearch {
CamelFolder *folder; /* folder for current search */
GPtrArray *summary; /* summary array for current search */
CamelMessageInfo *current; /* current message info, when searching one by one */
CamelMessageInfo *match1; /* message info, when searching a single message only */
CamelMimeMessage *current_message; /* cache of current message, if required */
ibex *body_index;
};
@ -95,6 +96,8 @@ void camel_folder_search_set_folder(CamelFolderSearch *search, CamelFolder *fold
void camel_folder_search_set_summary(CamelFolderSearch *search, GPtrArray *summary);
void camel_folder_search_set_body_index(CamelFolderSearch *search, ibex *index);
GPtrArray *camel_folder_search_execute_expression(CamelFolderSearch *search, const char *expr, CamelException *ex);
gboolean camel_folder_search_match_expression(CamelFolderSearch *search, const char *expr,
const CamelMessageInfo *info, CamelException *ex);
void camel_folder_search_free_result(CamelFolderSearch *search, GPtrArray *);
#endif /* ! _CAMEL_FOLDER_SEARCH_H */

View File

@ -30,6 +30,7 @@
#include "camel-store.h"
#include "camel-mime-message.h"
#include "string-utils.h"
#include "e-util/e-memory.h"
static CamelObjectClass *parent_class = NULL;
@ -1114,10 +1115,37 @@ camel_folder_change_info_new(void)
info->uid_removed = g_ptr_array_new();
info->uid_changed = g_ptr_array_new();
info->uid_source = NULL;
info->uid_pool = e_mempool_new(512, 256, E_MEMPOOL_ALIGN_BYTE);
return info;
}
static void
change_info_add_uid(CamelFolderChangeInfo *info, GPtrArray *uids, const char *uid, int copy)
{
int i;
/* TODO: Check that it is in the other arrays and remove it from them/etc? */
for (i=0;i<uids->len;i++) {
if (!strcmp(uids->pdata[i], uid))
return;
}
if (copy)
g_ptr_array_add(uids, e_mempool_strdup(info->uid_pool, uid));
else
g_ptr_array_add(uids, uid);
}
static void
change_info_cat(CamelFolderChangeInfo *info, GPtrArray *uids, GPtrArray *source)
{
int i;
for (i=0;i<source->len;i++) {
change_info_add_uid(info, uids, source->pdata[i], TRUE);
}
}
/**
* camel_folder_change_info_add_source:
* @info:
@ -1132,7 +1160,7 @@ camel_folder_change_info_add_source(CamelFolderChangeInfo *info, const char *uid
info->uid_source = g_hash_table_new(g_str_hash, g_str_equal);
if (g_hash_table_lookup(info->uid_source, uid) == NULL)
g_hash_table_insert(info->uid_source, g_strdup(uid), (void *)1);
g_hash_table_insert(info->uid_source, e_mempool_strdup(info->uid_pool, uid), (void *)1);
}
/**
@ -1154,7 +1182,7 @@ camel_folder_change_info_add_source_list(CamelFolderChangeInfo *info, const GPtr
char *uid = list->pdata[i];
if (g_hash_table_lookup(info->uid_source, uid) == NULL)
g_hash_table_insert(info->uid_source, g_strdup(uid), (void *)1);
g_hash_table_insert(info->uid_source, e_mempool_strdup(info->uid_pool, uid), (void *)1);
}
}
@ -1172,15 +1200,14 @@ camel_folder_change_info_add_update(CamelFolderChangeInfo *info, const char *uid
int value;
if (info->uid_source == NULL) {
camel_folder_change_info_add_uid(info, uid);
change_info_add_uid(info, info->uid_added, uid, TRUE);
return;
}
if (g_hash_table_lookup_extended(info->uid_source, uid, (void **)&key, (void **)&value)) {
g_hash_table_remove(info->uid_source, key);
g_free(key);
} else {
camel_folder_change_info_add_uid(info, uid);
change_info_add_uid(info, info->uid_added, uid, TRUE);
}
}
@ -1204,14 +1231,8 @@ camel_folder_change_info_add_update_list(CamelFolderChangeInfo *info, const GPtr
static void
change_info_remove(char *key, void *value, CamelFolderChangeInfo *info)
{
camel_folder_change_info_remove_uid(info, key);
g_free(key);
}
static void
change_info_free_update(char *key, void *value, CamelFolderChangeInfo *info)
{
g_free(key);
/* we dont need to copy this, as they've already been copied into our pool */
change_info_add_uid(info, info->uid_removed, key, FALSE);
}
/**
@ -1231,29 +1252,6 @@ camel_folder_change_info_build_diff(CamelFolderChangeInfo *info)
}
}
static void
change_info_add_uid(CamelFolderChangeInfo *info, GPtrArray *uids, const char *uid)
{
int i;
/* TODO: Check that it is in the other arrays and remove it from them/etc? */
for (i=0;i<uids->len;i++) {
if (!strcmp(uids->pdata[i], uid))
return;
}
g_ptr_array_add(uids, g_strdup(uid));
}
static void
change_info_cat(CamelFolderChangeInfo *info, GPtrArray *uids, GPtrArray *source)
{
int i;
for (i=0;i<source->len;i++) {
change_info_add_uid(info, uids, source->pdata[i]);
}
}
/**
* camel_folder_change_info_cat:
* @info:
@ -1280,7 +1278,7 @@ camel_folder_change_info_cat(CamelFolderChangeInfo *info, CamelFolderChangeInfo
void
camel_folder_change_info_add_uid(CamelFolderChangeInfo *info, const char *uid)
{
change_info_add_uid(info, info->uid_added, uid);
change_info_add_uid(info, info->uid_added, uid, TRUE);
}
/**
@ -1293,7 +1291,7 @@ camel_folder_change_info_add_uid(CamelFolderChangeInfo *info, const char *uid)
void
camel_folder_change_info_remove_uid(CamelFolderChangeInfo *info, const char *uid)
{
change_info_add_uid(info, info->uid_removed, uid);
change_info_add_uid(info, info->uid_removed, uid, TRUE);
}
/**
@ -1306,18 +1304,7 @@ camel_folder_change_info_remove_uid(CamelFolderChangeInfo *info, const char *uid
void
camel_folder_change_info_change_uid(CamelFolderChangeInfo *info, const char *uid)
{
change_info_add_uid(info, info->uid_changed, uid);
}
static void
change_info_clear(GPtrArray *uids)
{
int i;
for (i=0;i<uids->len;i++) {
g_free(uids->pdata[i]);
}
g_ptr_array_set_size(uids, 0);
change_info_add_uid(info, info->uid_changed, uid, TRUE);
}
/**
@ -1343,9 +1330,14 @@ camel_folder_change_info_changed(CamelFolderChangeInfo *info)
void
camel_folder_change_info_clear(CamelFolderChangeInfo *info)
{
change_info_clear(info->uid_added);
change_info_clear(info->uid_removed);
change_info_clear(info->uid_changed);
g_ptr_array_set_size(info->uid_added, 0);
g_ptr_array_set_size(info->uid_removed, 0);
g_ptr_array_set_size(info->uid_changed, 0);
if (info->uid_source) {
g_hash_table_destroy(info->uid_source);
info->uid_source = NULL;
}
e_mempool_flush(info->uid_pool, TRUE);
}
/**
@ -1357,12 +1349,10 @@ camel_folder_change_info_clear(CamelFolderChangeInfo *info)
void
camel_folder_change_info_free(CamelFolderChangeInfo *info)
{
if (info->uid_source) {
g_hash_table_foreach(info->uid_source, (GHFunc)change_info_free_update, info);
if (info->uid_source)
g_hash_table_destroy(info->uid_source);
}
camel_folder_change_info_clear(info);
e_mempool_destroy(info->uid_pool);
g_ptr_array_free(info->uid_added, TRUE);
g_ptr_array_free(info->uid_removed, TRUE);

View File

@ -49,6 +49,7 @@ struct _CamelFolderChangeInfo {
GPtrArray *uid_changed;
GHashTable *uid_source; /* used to create unique lists */
struct _EMemPool *uid_pool; /* pool used to store copies of uid strings */
};
struct _CamelFolder

View File

@ -784,7 +784,10 @@ camel_mime_parser_read(CamelMimeParser *m, const char **databuffer, int len)
if (len == 0)
return 0;
d(printf("parser::read() reading %d bytes\n", len));
there = MIN(s->inend - s->inptr, len);
d(printf("parser::read() there = %d bytes\n", there));
if (there > 0) {
*databuffer = s->inptr;
s->inptr += there;
@ -795,6 +798,8 @@ camel_mime_parser_read(CamelMimeParser *m, const char **databuffer, int len)
return -1;
there = MIN(s->inend - s->inptr, len);
d(printf("parser::read() had to re-read, now there = %d bytes\n", there));
*databuffer = s->inptr;
s->inptr += there;

View File

@ -35,7 +35,7 @@
#include "camel-mime-filter-charset.h"
#include "camel-mime-filter-crlf.h"
#define d(x)
#define d(x) /*(printf("%s(%d): ", __FILE__, __LINE__),(x))*/
/* simple data wrapper */
static void
@ -114,6 +114,7 @@ simple_data_wrapper_construct_from_parser(CamelDataWrapper *dw, CamelMimeParser
start = camel_mime_parser_tell(mp) + seekable_source->bound_start;
}
while ( camel_mime_parser_step(mp, &buf, &len) != HSCAN_BODY_END ) {
d(printf("appending o/p data: %.*s\n", len, buf));
if (buffer) {
if (buffer->len > 20480 && seekable_source) {
/* is this a 'big' message? Yes? We dont want to convert it all then.*/

View File

@ -40,7 +40,7 @@
#include "camel-mime-filter-charset.h"
#include "camel-exception.h"
#define d(x)
#define d(x) /*(printf("%s(%d): ", __FILE__, __LINE__),(x))*/
typedef enum {
HEADER_UNKNOWN,

View File

@ -297,23 +297,32 @@ mh_summary_sync_message(CamelLocalSummary *cls, CamelMessageInfo *info, CamelExc
camel_mime_parser_init_with_fd(mp, fd);
if (camel_mime_parser_step(mp, 0, 0) != HSCAN_EOF) {
xev = camel_mime_parser_header(mp, "X-Evolution", &xevoffset);
d(printf("xev = '%s'\n", xev));
xevnew = camel_local_summary_encode_x_evolution(cls, info);
if (xev == NULL
|| camel_local_summary_decode_x_evolution(cls, xev, NULL) == -1
|| strlen(xev)+1 != strlen(xevnew)) {
|| strlen(xev)-1 != strlen(xevnew)) {
d(printf("camel local summary_decode_xev = %d\n", camel_local_summary_decode_x_evolution(cls, xev, NULL)));
/* need to write a new copy/unlink old */
tmpname = g_strdup_printf("%s/.tmp.%d.%s", cls->folder_path, getpid(), info->uid);
d(printf("old xev was %d %s new xev is %d %s\n", strlen(xev), xev, strlen(xevnew), xevnew));
d(printf("creating new message %s\n", tmpname));
outfd = open(tmpname, O_CREAT|O_WRONLY|O_TRUNC, 0600);
if (outfd != -1) {
outlen = 0;
if ( (len = camel_local_summary_write_headers(outfd, camel_mime_parser_headers_raw(mp), xevnew)) == 0) {
len = camel_local_summary_write_headers(outfd, camel_mime_parser_headers_raw(mp), xevnew);
if (len != -1) {
while (outlen != -1 && (len = camel_mime_parser_read(mp, &buffer, 10240)) > 0) {
d(printf("camel mime parser read, read %d bytes: %.*s\n", len, len, buffer));
do {
outlen = write(fd, buffer, len);
outlen = write(outfd, buffer, len);
} while (outlen == -1 && errno == EINTR);
}
}
d(printf("len = %d outlen = %d, renaming/finishing\n", len, outlen));
if (close(outfd) == -1
|| len == -1
|| outlen == -1
@ -326,6 +335,7 @@ mh_summary_sync_message(CamelLocalSummary *cls, CamelMessageInfo *info, CamelExc
}
g_free(tmpname);
} else {
d(printf("stamping in updated X-EV at %d\n", (int)xevoffset));
/* else, we can just update the flags field */
lseek(fd, xevoffset+strlen("X-Evolution: "), SEEK_SET);
do {

View File

@ -24,6 +24,9 @@
#include "camel-vee-folder.h"
#include "camel-folder-summary.h"
#include "camel-mime-message.h"
#ifdef DYNAMIC
#include "camel-folder-search.h"
#endif
#include <string.h>
@ -128,6 +131,11 @@ camel_vee_folder_init (CamelVeeFolder *obj)
CAMEL_MESSAGE_DRAFT |
CAMEL_MESSAGE_FLAGGED |
CAMEL_MESSAGE_SEEN;
obj->changes = camel_folder_change_info_new();
#ifdef DYNAMIC
obj->search = camel_folder_search_new();
#endif
}
static void
@ -137,12 +145,19 @@ camel_vee_folder_finalise (CamelObject *obj)
struct _CamelVeeFolderPrivate *p = _PRIVATE(vf);
GList *node;
/* FIXME: some leaks here, summary etc */
node = p->folders;
while (node) {
CamelFolder *f = node->data;
camel_object_unref((CamelObject *)f);
node = g_list_next(node);
}
camel_folder_change_info_free(vf->changes);
#ifdef DYNAMIC
camel_object_unref((CamelObject *)vf->search);
#endif
}
/**
@ -156,8 +171,7 @@ camel_vee_folder_finalise (CamelObject *obj)
* Return value: A new CamelVeeFolder widget.
**/
CamelFolder *
camel_vee_folder_new (CamelStore *parent_store, const char *name,
CamelException *ex)
camel_vee_folder_new (CamelStore *parent_store, const char *name, CamelException *ex)
{
CamelFolder *folder;
CamelVeeFolder *vf;
@ -192,16 +206,136 @@ camel_vee_folder_new (CamelStore *parent_store, const char *name,
return folder;
}
#ifdef DYNAMIC
static void
vfolder_remove_match(CamelVeeFolder *vf, CamelVeeMessageInfo *vinfo)
{
printf("removing match %s\n", vinfo->info.uid);
g_hash_table_remove(vf->messages_uid, vinfo->info.uid);
g_ptr_array_remove_fast(vf->messages, vinfo);
camel_folder_change_info_remove_uid(vf->changes, vinfo->info.uid);
camel_message_info_free((CamelMessageInfo *)vinfo);
}
static CamelVeeMessageInfo *
vfolder_add_match(CamelVeeFolder *vf, CamelFolder *f, const CamelMessageInfo *info)
{
CamelVeeMessageInfo *mi;
mi = g_malloc0(sizeof(*mi));
camel_message_info_dup_to(info, (CamelMessageInfo*)mi);
g_free (mi->info.uid);
mi->info.uid = g_strdup_printf("%p:%s", f, info->uid);
mi->folder = f;
g_ptr_array_add(vf->messages, mi);
g_hash_table_insert(vf->messages_uid, mi->info.uid, mi);
printf("adding match %s\n", mi->info.uid);
camel_folder_change_info_add_uid(vf->changes, mi->info.uid);
return mi;
}
#endif
static void
vfolder_change_match(CamelVeeFolder *vf, CamelVeeMessageInfo *vinfo, const CamelMessageInfo *info)
{
CamelFlag *flag;
CamelTag *tag;
printf("changing match %s\n", vinfo->info.uid);
vinfo->info.flags = info->flags;
camel_flag_list_free(&vinfo->info.user_flags);
flag = info->user_flags;
while (flag) {
camel_flag_set(&vinfo->info.user_flags, flag->name, TRUE);
flag = flag->next;
}
camel_tag_list_free(&vinfo->info.user_tags);
tag = info->user_tags;
while (tag) {
camel_tag_set(&vinfo->info.user_tags, tag->name, tag->value);
tag = tag->next;
}
camel_folder_change_info_change_uid(vf->changes, vinfo->info.uid);
}
static void
folder_changed(CamelFolder *sub, gpointer type, CamelVeeFolder *vf)
{
CamelException *ex;
ex = camel_exception_new();
vee_folder_build_folder(vf, sub, ex);
camel_exception_free(ex);
/* FIXME: should only raise follow-on event if the result changed */
camel_object_trigger_event( CAMEL_OBJECT(vf), "folder_changed", GINT_TO_POINTER(0));
#ifdef DYNAMIC
CamelFolderChangeInfo *changes = type;
/* assume its faster to search a long list in whole, than by part */
if (changes && (changes->uid_added->len + changes->uid_changed->len) < 500) {
int i;
char *vuid;
CamelVeeMessageInfo *vinfo;
gboolean match;
const CamelMessageInfo *info;
ex = camel_exception_new();
/* see if added ones now match us */
for (i=0;i<changes->uid_added->len;i++) {
info = camel_folder_get_message_info(sub, changes->uid_added->pdata[i]);
if (info) {
camel_folder_search_set_folder(vf->search, sub);
match = camel_folder_search_match_expression(vf->search, vf->expression, info, ex);
if (match)
vinfo = vfolder_add_match(vf, sub, info);
}
}
/* check if changed ones still match */
for (i=0;i<changes->uid_changed->len;i++) {
info = camel_folder_get_message_info(sub, changes->uid_changed->pdata[i]);
vuid = g_strdup_printf("%p:%s", sub, (char *)changes->uid_changed->pdata[i]);
vinfo = (CamelVeeMessageInfo *)vee_get_message_info((CamelFolder *)vf, vuid);
if (info) {
camel_folder_search_set_folder(vf->search, sub);
match = camel_folder_search_match_expression(vf->search, vf->expression, info, ex);
if (vinfo) {
if (match)
vfolder_change_match(vf, vinfo, info);
else
vfolder_remove_match(vf, vinfo);
} else if (match)
vfolder_add_match(vf, sub, info);
} else if (vinfo)
vfolder_remove_match(vf, vinfo);
g_free(vuid);
}
camel_exception_free(ex);
/* mirror removes directly, if they used to match */
for (i=0;i<changes->uid_removed->len;i++) {
vuid = g_strdup_printf("%p:%s", sub, (char *)changes->uid_removed->pdata[i]);
vinfo = (CamelVeeMessageInfo *)vee_get_message_info((CamelFolder *)vf, vuid);
if (vinfo)
vfolder_remove_match(vf, vinfo);
g_free(vuid);
}
} else {
#endif
ex = camel_exception_new();
vee_folder_build_folder(vf, sub, ex);
camel_exception_free(ex);
#ifdef DYNAMIC
}
#endif
/* cascade up, if we need to */
if (camel_folder_change_info_changed(vf->changes)) {
camel_object_trigger_event( CAMEL_OBJECT(vf), "folder_changed", vf->changes);
camel_folder_change_info_clear(vf->changes);
}
}
/* track flag changes in the summary */
@ -209,24 +343,49 @@ static void
message_changed(CamelFolder *f, const char *uid, CamelVeeFolder *mf)
{
const CamelMessageInfo *info;
CamelMessageInfo *vinfo;
CamelFlag *flag;
CamelVeeMessageInfo *vinfo;
char *vuid;
#ifdef DYNAMIC
gboolean match;
CamelException *ex;
#endif
info = camel_folder_get_message_info(f, uid);
vuid = g_strdup_printf("%p:%s", f, uid);
vinfo = (CamelMessageInfo *)vee_get_message_info((CamelFolder *)mf, vuid);
if (info && vinfo) {
vinfo->flags = info->flags;
camel_flag_list_free(&vinfo->user_flags);
flag = info->user_flags;
while (flag) {
camel_flag_set(&vinfo->user_flags, flag->name, TRUE);
flag = flag->next;
}
camel_object_trigger_event( CAMEL_OBJECT(mf), "message_changed", vinfo->uid);
vinfo = (CamelVeeMessageInfo *)vee_get_message_info((CamelFolder *)mf, vuid);
/* see if this message now matches/doesn't match anymore */
/* Hmm, this might not work if the folder uses some weird search thing,
and/or can be slow since it wont use any index index, hmmm. */
#ifdef DYNAMIC
camel_folder_search_set_folder(mf->search, f);
ex = camel_exception_new();
match = camel_folder_search_match_expression(mf->search, mf->expression, info, ex);
camel_exception_free(ex);
if (info) {
if (vinfo) {
if (match)
vfolder_change_match(mf, vinfo, info);
else
vfolder_remove_match(mf, vinfo);
} else if (match)
vfolder_add_match(mf, f, info);
} else if (vinfo)
vfolder_remove_match(mf, vinfo);
#else
if (info && vinfo)
vfolder_change_match(mf, vinfo, info);
#endif
/* cascade up, if required. This could probably be delayed,
but doesn't matter really, that is what freeze is for. */
if (camel_folder_change_info_changed(mf->changes)) {
camel_object_trigger_event( CAMEL_OBJECT(mf), "folder_changed", mf->changes);
camel_folder_change_info_clear(mf->changes);
}
g_free(vuid);
}
@ -245,8 +404,18 @@ camel_vee_folder_add_folder(CamelVeeFolder *vf, CamelFolder *sub)
ex = camel_exception_new();
vee_folder_build_folder(vf, sub, ex);
camel_exception_free(ex);
/* FIXME: should only raise follow-on event if the result changed */
camel_object_trigger_event( CAMEL_OBJECT(vf), "folder_changed", GINT_TO_POINTER(0));
/* we'll assume the caller is going to update the whole list after they do this
this may or may not be the right thing to do, but it should be close enough */
#if 0
if (camel_folder_change_info_changed(vf->changes)) {
camel_object_trigger_event( CAMEL_OBJECT(vf), "folder_changed", vf->changes);
camel_folder_change_info_clear(vf->changes);
}
#else
camel_folder_change_info_clear(vf->changes);
#endif
}
@ -441,6 +610,11 @@ vee_folder_build(CamelVeeFolder *vf, CamelException *ex)
messages = g_ptr_array_new();
messages_uid = g_hash_table_new(g_str_hash, g_str_equal);
g_ptr_array_free(vf->messages, TRUE);
vf->messages = messages;
g_hash_table_destroy(vf->messages_uid);
vf->messages_uid = messages_uid;
node = p->folders;
while (node) {
GPtrArray *matches;
@ -465,11 +639,6 @@ vee_folder_build(CamelVeeFolder *vf, CamelException *ex)
camel_folder_search_free(f, matches);
node = g_list_next(node);
}
g_ptr_array_free(vf->messages, TRUE);
vf->messages = messages;
g_hash_table_destroy(vf->messages_uid);
vf->messages_uid = messages_uid;
}
@ -489,6 +658,7 @@ vee_folder_build_folder(CamelVeeFolder *vf, CamelFolder *source, CamelException
for (i=0;i<vf->messages->len;i++) {
CamelVeeMessageInfo *mi = g_ptr_array_index(vf->messages, i);
if (mi->folder == source) {
camel_folder_change_info_add_source(vf->changes, mi->info.uid);
g_hash_table_remove(vf->messages_uid, mi->info.uid);
g_ptr_array_remove_index_fast(vf->messages, i);
@ -511,9 +681,13 @@ vee_folder_build_folder(CamelVeeFolder *vf, CamelFolder *source, CamelException
mi->folder = f;
g_ptr_array_add(messages, mi);
g_hash_table_insert(messages_uid, mi->info.uid, mi);
camel_folder_change_info_add_update(vf->changes, mi->info.uid);
}
}
camel_folder_search_free(f, matches);
camel_folder_change_info_build_diff(vf->changes);
}

View File

@ -24,6 +24,9 @@
#include <camel/camel-folder.h>
/* try the dynamic update version */
#define DYNAMIC
#define CAMEL_VEE_FOLDER(obj) CAMEL_CHECK_CAST (obj, camel_vee_folder_get_type (), CamelVeeFolder)
#define CAMEL_VEE_FOLDER_CLASS(klass) CAMEL_CHECK_CLASS_CAST (klass, camel_vee_folder_get_type (), CamelVeeFolderClass)
#define IS_CAMEL_VEE_FOLDER(obj) CAMEL_CHECK_TYPE (obj, camel_vee_folder_get_type ())
@ -43,6 +46,10 @@ struct _CamelVeeFolder {
/* FIXME: Move this to a summary object??? */
GPtrArray *messages; /* message info's */
GHashTable *messages_uid;
CamelFolderChangeInfo *changes;
#ifdef DYNAMIC
CamelFolderSearch *search;
#endif
};
struct _CamelVeeFolderClass {