Index: camel/camel-file-utils.c =================================================================== RCS file: /cvs/gnome/evolution-data-server/camel/camel-file-utils.c,v retrieving revision 1.16 diff -u -p -r1.16 camel-file-utils.c --- camel/camel-file-utils.c 10 Jan 2006 07:56:46 -0000 1.16 +++ camel/camel-file-utils.c 12 Mar 2006 20:49:46 -0000 @@ -316,6 +316,72 @@ camel_file_util_decode_string (FILE *in, return 0; } +/** + * camel_file_util_encode_fixed_string: + * @out: file to output to + * @str: value to output + * @len: total-len of str to store + * + * Encode a normal string and save it in the output file. + * Unlike @camel_file_util_encode_string, it pads the + * @str with "NULL" bytes, if @len is > strlen(str) + * + * Return value: 0 on success, -1 on error. + **/ +int +camel_file_util_encode_fixed_string (FILE *out, const char *str, size_t len) +{ + char buf[len]; + + /* Don't allow empty strings to be written */ + if (len < 1) + return -1; + + /* Max size is 64K */ + if (len > 65536) + len = 65536; + + memset(buf, 0x00, len); + g_strlcpy(buf, str, len); + + if (fwrite (buf, len, 1, out) == len) + return 0; + + return -1; +} + + +/** + * camel_file_util_decode_fixed_string: + * @in: file to read from + * @str: pointer to a variable to store the value in + * @len: total-len to decode. + * + * Decode a normal string from the input file. + * + * Return value: 0 on success, -1 on error. + **/ +int +camel_file_util_decode_fixed_string (FILE *in, char **str, size_t len) +{ + register char *ret; + + if (len > 65536) { + *str = NULL; + return -1; + } + + ret = g_malloc (len+1); + if (len > 0 && fread (ret, len, 1, in) != 1) { + g_free (ret); + *str = NULL; + return -1; + } + + ret[len] = 0; + *str = ret; + return 0; +} /** * camel_file_util_safe_filename: Index: camel/camel-file-utils.h =================================================================== RCS file: /cvs/gnome/evolution-data-server/camel/camel-file-utils.h,v retrieving revision 1.11 diff -u -p -r1.11 camel-file-utils.h --- camel/camel-file-utils.h 10 Jan 2006 07:56:46 -0000 1.11 +++ camel/camel-file-utils.h 12 Mar 2006 20:49:46 -0000 @@ -54,6 +54,9 @@ int camel_file_util_encode_size_t (FILE int camel_file_util_decode_size_t (FILE *in, size_t *); int camel_file_util_encode_string (FILE *out, const char *); int camel_file_util_decode_string (FILE *in, char **); +int camel_file_util_encode_fixed_string (FILE *out, const char *str, size_t len); +int camel_file_util_decode_fixed_string (FILE *in, char **str, size_t len); + char *camel_file_util_safe_filename (const char *name); Index: camel/camel-folder-summary.c =================================================================== RCS file: /cvs/gnome/evolution-data-server/camel/camel-folder-summary.c,v retrieving revision 1.147 diff -u -p -r1.147 camel-folder-summary.c --- camel/camel-folder-summary.c 2 Feb 2006 05:38:25 -0000 1.147 +++ camel/camel-folder-summary.c 12 Mar 2006 20:49:47 -0000 @@ -78,6 +78,8 @@ extern int strdup_count, malloc_count, f #define _PRIVATE(o) (((CamelFolderSummary *)(o))->priv) +#define META_SUMMARY_SUFFIX_LEN 5 /* strlen("-meta") */ + /* trivial lists, just because ... */ struct _node { struct _node *next; @@ -88,12 +90,15 @@ static int my_list_size(struct _node **l static int summary_header_load(CamelFolderSummary *, FILE *); static int summary_header_save(CamelFolderSummary *, FILE *); +static int summary_meta_header_load(CamelFolderSummary *, FILE *); +static int summary_meta_header_save(CamelFolderSummary *, FILE *); static CamelMessageInfo * message_info_new_from_header(CamelFolderSummary *, struct _camel_header_raw *); static CamelMessageInfo * message_info_new_from_parser(CamelFolderSummary *, CamelMimeParser *); static CamelMessageInfo * message_info_new_from_message(CamelFolderSummary *s, CamelMimeMessage *msg); static CamelMessageInfo * message_info_load(CamelFolderSummary *, FILE *); static int message_info_save(CamelFolderSummary *, FILE *, CamelMessageInfo *); +static int meta_message_info_save(CamelFolderSummary *s, FILE *out_meta, FILE *out, CamelMessageInfo *info); static void message_info_free(CamelFolderSummary *, CamelMessageInfo *); static CamelMessageContentInfo * content_info_new_from_header(CamelFolderSummary *, struct _camel_header_raw *); @@ -146,6 +151,13 @@ camel_folder_summary_init (CamelFolderSu p->filter_lock = g_mutex_new(); p->alloc_lock = g_mutex_new(); p->ref_lock = g_mutex_new(); + + s->meta_summary = g_malloc0(sizeof(CamelFolderMetaSummary)); + + /* Default is 20, any implementor having UIDs that has length + exceeding 20, has to override this value + */ + s->meta_summary->uid_len = 20; } static void free_o_name(void *key, void *value, void *data) @@ -193,6 +205,10 @@ camel_folder_summary_finalize (CamelObje camel_object_unref((CamelObject *)p->filter_stream); if (p->index) camel_object_unref((CamelObject *)p->index); + + /* Freeing memory occupied by meta-summary-header */ + g_free(s->meta_summary->path); + g_free(s->meta_summary); g_mutex_free(p->summary_lock); g_mutex_free(p->io_lock); @@ -256,6 +272,9 @@ camel_folder_summary_set_filename(CamelF g_free(s->summary_path); s->summary_path = g_strdup(name); + g_free(s->meta_summary->path); + s->meta_summary->path = g_strconcat(name, "-meta", NULL); + CAMEL_SUMMARY_UNLOCK(s, summary_lock); } @@ -544,7 +563,8 @@ camel_folder_summary_load(CamelFolderSum int i; CamelMessageInfo *mi; - if (s->summary_path == NULL) + if (s->summary_path == NULL || + s->meta_summary->path == NULL) return 0; in = g_fopen(s->summary_path, "rb"); @@ -630,14 +650,17 @@ int camel_folder_summary_save(CamelFolderSummary *s) { FILE *out; - int fd, i; + FILE *out_meta; + int fd, i, fd_meta; guint32 count; CamelMessageInfo *mi; char *path; + char *path_meta; g_assert(s->message_info_size >= sizeof(CamelMessageInfoBase)); - if (s->summary_path == NULL + if (s->summary_path == NULL + || s->meta_summary->path == NULL || (s->flags & CAMEL_SUMMARY_DIRTY) == 0) return 0; @@ -655,32 +678,65 @@ camel_folder_summary_save(CamelFolderSum return -1; } + /* Meta summary code */ + /* This meta summary will be used by beagle in order to + quickly pass through the actual summary file, which + is quite time consuming otherwise. + */ + /* FIXME: Merge meta-summary and summary */ + path_meta = alloca(strlen(s->meta_summary->path)+4); + sprintf(path_meta, "%s~", s->meta_summary->path); + fd_meta = g_open(path_meta, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0600); + if (fd_meta == -1) + return -1; + out_meta = fdopen(fd_meta, "wb"); + if (out_meta == NULL) { + i = errno; + g_unlink(path); + g_unlink(path_meta); + close(fd); + close(fd_meta); + errno = i; + return -1; + } + io(printf("saving header\n")); CAMEL_SUMMARY_LOCK(s, io_lock); if (((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->summary_header_save(s, out) == -1) goto exception; - + + if (summary_meta_header_save(s, out_meta) == -1) + goto exception; + /* now write out each message ... */ /* we check ferorr when done for i/o errors */ count = s->messages->len; for (i = 0; i < count; i++) { mi = s->messages->pdata[i]; - if (((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS (s)))->message_info_save (s, out, mi) == -1) + if (((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS (s)))->meta_message_info_save (s, out_meta, out, mi) == -1) goto exception; + if (((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS (s)))->message_info_save (s, out, mi) == -1) + goto exception; + if (s->build_content) { if (perform_content_info_save (s, out, ((CamelMessageInfoBase *)mi)->content) == -1) goto exception; } } + /* FIXME: Can't we use the above "fd" variables, instead of fileno()? */ if (fflush (out) != 0 || fsync (fileno (out)) == -1) goto exception; + if (fflush (out_meta) != 0 || fsync (fileno (out_meta)) == -1) + goto exception; + fclose (out); - + fclose (out_meta); + CAMEL_SUMMARY_UNLOCK(s, io_lock); #ifdef G_OS_WIN32 @@ -692,6 +748,13 @@ camel_folder_summary_save(CamelFolderSum errno = i; return -1; } + + if (g_rename(path_meta, s->meta_summary->path) == -1) { + i = errno; + g_unlink(path_meta); + errno = i; + return -1; + } s->flags &= ~CAMEL_SUMMARY_DIRTY; return 0; @@ -701,10 +764,12 @@ camel_folder_summary_save(CamelFolderSum i = errno; fclose (out); + fclose (out_meta); CAMEL_SUMMARY_UNLOCK(s, io_lock); g_unlink (path); + g_unlink (path_meta); errno = i; return -1; @@ -725,20 +790,30 @@ int camel_folder_summary_header_load(CamelFolderSummary *s) { FILE *in; + FILE *in_meta; int ret; - if (s->summary_path == NULL) + if (s->summary_path == NULL || + s->meta_summary->path == NULL) return 0; in = g_fopen(s->summary_path, "rb"); if (in == NULL) return -1; + in_meta = g_fopen(s->meta_summary->path, "rb"); + if (in_meta == NULL) { + fclose(in); + return -1; + } + CAMEL_SUMMARY_LOCK(s, io_lock); ret = ((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->summary_header_load(s, in); + ret = summary_meta_header_load(s, in_meta); CAMEL_SUMMARY_UNLOCK(s, io_lock); fclose(in); + fclose(in_meta); s->flags &= ~CAMEL_SUMMARY_DIRTY; return ret; } @@ -1086,6 +1161,7 @@ camel_folder_summary_clear(CamelFolderSu g_hash_table_destroy(s->messages_uid); s->messages_uid = g_hash_table_new(g_str_hash, g_str_equal); s->flags |= CAMEL_SUMMARY_DIRTY; + s->meta_summary->msg_expunged = TRUE; CAMEL_SUMMARY_UNLOCK(s, summary_lock); } @@ -1104,8 +1180,9 @@ camel_folder_summary_remove(CamelFolderS g_hash_table_remove(s->messages_uid, camel_message_info_uid(info)); g_ptr_array_remove(s->messages, info); s->flags |= CAMEL_SUMMARY_DIRTY; + s->meta_summary->msg_expunged = TRUE; CAMEL_SUMMARY_UNLOCK(s, summary_lock); - + camel_message_info_free(info); } @@ -1390,8 +1467,30 @@ my_list_size(struct _node **list) } static int +summary_meta_header_load(CamelFolderSummary *s, FILE *in) +{ + if (!s->meta_summary->path) + return -1; + + fseek(in, 0, SEEK_SET); + + io(printf("Loading meta-header\n")); + + if (camel_file_util_decode_uint32(in, &s->meta_summary->major) == -1 + || camel_file_util_decode_uint32(in, &s->meta_summary->minor) == -1 + || camel_file_util_decode_uint32(in, &s->meta_summary->uid_len) == -1) { + return -1; + } + + return 0; +} + +static int summary_header_load(CamelFolderSummary *s, FILE *in) { + if (!s->summary_path) + return -1; + fseek(in, 0, SEEK_SET); io(printf("Loading header\n")); @@ -1471,6 +1570,25 @@ summary_header_save(CamelFolderSummary * return camel_file_util_encode_fixed_int32(out, junk); } +static int +summary_meta_header_save(CamelFolderSummary *s, FILE *out_meta) +{ + fseek(out_meta, 0, SEEK_SET); + + /* Save meta-summary header */ + if (s->meta_summary->msg_expunged) { + s->meta_summary->msg_expunged = FALSE; + camel_file_util_encode_uint32(out_meta, ++s->meta_summary->major); + camel_file_util_encode_uint32(out_meta, (s->meta_summary->minor=0)); + } else { + camel_file_util_encode_uint32(out_meta, s->meta_summary->major); + camel_file_util_encode_uint32(out_meta, ++s->meta_summary->minor); + } + camel_file_util_encode_uint32(out_meta, s->meta_summary->uid_len); + + return ferror(out_meta); +} + /* are these even useful for anything??? */ static CamelMessageInfo * message_info_new_from_parser(CamelFolderSummary *s, CamelMimeParser *mp) @@ -1774,6 +1892,25 @@ error: } static int +meta_message_info_save(CamelFolderSummary *s, FILE *out_meta, FILE *out, CamelMessageInfo *info) +{ + time_t timestamp; + off_t offset; + CamelMessageInfoBase *mi = (CamelMessageInfoBase *)info; + + time (×tamp); + offset = ftell (out); + /* FIXME: errno check after ftell */ + + camel_file_util_encode_time_t(out_meta, timestamp); + camel_file_util_encode_fixed_string(out_meta, camel_message_info_uid(mi), s->meta_summary->uid_len); + camel_file_util_encode_uint32(out_meta, mi->flags); + camel_file_util_encode_off_t(out_meta, offset); + + return ferror(out); +} + +static int message_info_save(CamelFolderSummary *s, FILE *out, CamelMessageInfo *info) { guint32 count; @@ -3115,6 +3252,7 @@ camel_folder_summary_class_init (CamelFo klass->message_info_new_from_message = message_info_new_from_message; klass->message_info_load = message_info_load; klass->message_info_save = message_info_save; + klass->meta_message_info_save = meta_message_info_save; klass->message_info_free = message_info_free; klass->message_info_clone = message_info_clone; Index: camel/camel-folder-summary.h =================================================================== RCS file: /cvs/gnome/evolution-data-server/camel/camel-folder-summary.h,v retrieving revision 1.86 diff -u -p -r1.86 camel-folder-summary.h --- camel/camel-folder-summary.h 31 Aug 2005 04:21:56 -0000 1.86 +++ camel/camel-folder-summary.h 12 Mar 2006 20:49:47 -0000 @@ -46,6 +46,8 @@ typedef struct _CamelFolderSummaryClass typedef struct _CamelMessageInfo CamelMessageInfo; typedef struct _CamelMessageInfoBase CamelMessageInfoBase; +typedef struct _CamelFolderMetaSummary CamelFolderMetaSummary; + /* A tree of message content info structures describe the content structure of the message (if it has any) */ struct _CamelMessageContentInfo { @@ -224,6 +226,7 @@ struct _CamelFolderSummary { GHashTable *messages_uid; /* CamelMessageInfo's by uid */ struct _CamelFolder *folder; /* parent folder, for events */ + struct _CamelFolderMetaSummary *meta_summary; /* Meta summary */ }; struct _CamelFolderSummaryClass { @@ -238,7 +241,8 @@ struct _CamelFolderSummaryClass { CamelMessageInfo * (*message_info_new_from_parser)(CamelFolderSummary *, CamelMimeParser *); CamelMessageInfo * (*message_info_new_from_message)(CamelFolderSummary *, CamelMimeMessage *); CamelMessageInfo * (*message_info_load)(CamelFolderSummary *, FILE *); - int (*message_info_save)(CamelFolderSummary *, FILE *, CamelMessageInfo *); + int (*message_info_save)(CamelFolderSummary *, FILE *, CamelMessageInfo *); + int (*meta_message_info_save)(CamelFolderSummary *, FILE *, FILE *, CamelMessageInfo *); void (*message_info_free)(CamelFolderSummary *, CamelMessageInfo *); CamelMessageInfo * (*message_info_clone)(CamelFolderSummary *, const CamelMessageInfo *); @@ -272,6 +276,15 @@ struct _CamelFolderSummaryClass { gboolean (*info_set_user_flag)(CamelMessageInfo *mi, const char *id, gboolean state); gboolean (*info_set_user_tag)(CamelMessageInfo *mi, const char *id, const char *val); gboolean (*info_set_flags)(CamelMessageInfo *mi, guint32 mask, guint32 set); +}; + +/* Meta-summary info */ +struct _CamelFolderMetaSummary { + guint32 major; /* Major version of meta-summary */ + guint32 minor; /* Minor version of meta-summary */ + guint32 uid_len; /* Length of UID (for implementors to use) */ + gboolean msg_expunged; /* Whether any message is expunged or not */ + char *path; /* Path to meta-summary-file */ }; CamelType camel_folder_summary_get_type (void); Index: camel/providers/groupwise/camel-groupwise-summary.c =================================================================== RCS file: /cvs/gnome/evolution-data-server/camel/providers/groupwise/camel-groupwise-summary.c,v retrieving revision 1.10 diff -u -p -r1.10 camel-groupwise-summary.c --- camel/providers/groupwise/camel-groupwise-summary.c 9 Nov 2005 14:23:44 -0000 1.10 +++ camel/providers/groupwise/camel-groupwise-summary.c 12 Mar 2006 20:49:47 -0000 @@ -122,6 +122,9 @@ camel_groupwise_summary_init (CamelGroup /* subclasses need to set the right instance data sizes */ s->message_info_size = sizeof(CamelGroupwiseMessageInfo); s->content_info_size = sizeof(CamelGroupwiseMessageContentInfo); + + /* Meta-summary - Overriding UID len */ + s->meta_summary->uid_len = 2048; } Index: camel/providers/local/camel-mbox-summary.c =================================================================== RCS file: /cvs/gnome/evolution-data-server/camel/providers/local/camel-mbox-summary.c,v retrieving revision 1.56 diff -u -p -r1.56 camel-mbox-summary.c --- camel/providers/local/camel-mbox-summary.c 8 Dec 2005 11:28:47 -0000 1.56 +++ camel/providers/local/camel-mbox-summary.c 12 Mar 2006 20:49:47 -0000 @@ -54,6 +54,7 @@ static CamelMessageInfo * message_info_n static CamelMessageInfo * message_info_new_from_parser(CamelFolderSummary *, CamelMimeParser *); static CamelMessageInfo * message_info_load (CamelFolderSummary *, FILE *); static int message_info_save (CamelFolderSummary *, FILE *, CamelMessageInfo *); +static int meta_message_info_save(CamelFolderSummary *s, FILE *out_meta, FILE *out, CamelMessageInfo *mi); /*static void message_info_free (CamelFolderSummary *, CamelMessageInfo *);*/ static char *mbox_summary_encode_x_evolution (CamelLocalSummary *cls, const CamelLocalMessageInfo *mi); @@ -153,6 +154,7 @@ camel_mbox_summary_class_init(CamelMboxS sklass->message_info_new_from_parser = message_info_new_from_parser; sklass->message_info_load = message_info_load; sklass->message_info_save = message_info_save; + sklass->meta_message_info_save = meta_message_info_save; /*sklass->message_info_free = message_info_free;*/ sklass->info_set_user_flag = mbox_info_set_user_flag; @@ -378,6 +380,20 @@ message_info_load(CamelFolderSummary *s, error: camel_message_info_free(mi); return NULL; +} + +static int +meta_message_info_save(CamelFolderSummary *s, FILE *out_meta, FILE *out, CamelMessageInfo *mi) +{ + CamelMboxMessageInfo *mbi = (CamelMboxMessageInfo *)mi; + + io(printf("saving mbox message info\n")); + + if (((CamelFolderSummaryClass *)camel_mbox_summary_parent)->meta_message_info_save(s, out_meta, out, mi) == -1 + || camel_file_util_encode_off_t(out_meta, mbi->frompos) == -1) + return -1; + + return 0; } static int Index: camel/providers/local/camel-mbox-store.c =================================================================== RCS file: /cvs/gnome/evolution-data-server/camel/providers/local/camel-mbox-store.c,v retrieving revision 1.44 diff -u -p -r1.44 camel-mbox-store.c --- camel/providers/local/camel-mbox-store.c 10 Jan 2006 07:56:48 -0000 1.44 +++ camel/providers/local/camel-mbox-store.c 13 Mar 2006 13:33:37 -0000 @@ -99,7 +99,7 @@ camel_mbox_store_get_type(void) } static char *extensions[] = { - ".msf", ".ev-summary", ".ibex.index", ".ibex.index.data", ".cmeta", ".lock" + ".msf", ".ev-summary", ".ibex.index", ".ibex.index.data", ".cmeta", ".lock", ".ev-summary-meta" }; static gboolean