diff options
Diffstat (limited to 'camel/camel-folder-summary.c')
-rw-r--r-- | camel/camel-folder-summary.c | 2760 |
1 files changed, 0 insertions, 2760 deletions
diff --git a/camel/camel-folder-summary.c b/camel/camel-folder-summary.c deleted file mode 100644 index 9179b63e6e..0000000000 --- a/camel/camel-folder-summary.c +++ /dev/null @@ -1,2760 +0,0 @@ -/* - * Copyright (C) 2000 Ximian Inc. - * - * Authors: Michael Zucchi <notzed@ximian.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <unistd.h> -#include <ctype.h> -#include <string.h> -#include <errno.h> -#include <stdlib.h> - -#include <gal/util/e-iconv.h> - -#include "camel-folder-summary.h" - -#include <camel/camel-file-utils.h> -#include <camel/camel-mime-filter.h> -#include <camel/camel-mime-filter-index.h> -#include <camel/camel-mime-filter-charset.h> -#include <camel/camel-mime-filter-save.h> -#include <camel/camel-mime-filter-basic.h> -#include <camel/camel-mime-filter-html.h> -#include <camel/camel-mime-message.h> -#include <camel/camel-multipart.h> -#include <camel/camel-stream-mem.h> - -#include "hash-table-utils.h" -#include "e-util/md5-utils.h" -#include "e-util/e-memory.h" - -#include "camel-private.h" - -#ifdef ENABLE_THREADS -#include <pthread.h> - -static pthread_mutex_t info_lock = PTHREAD_MUTEX_INITIALIZER; - -/* this lock is ONLY for the standalone messageinfo stuff */ -#define GLOBAL_INFO_LOCK(i) pthread_mutex_lock(&info_lock) -#define GLOBAL_INFO_UNLOCK(i) pthread_mutex_unlock(&info_lock) -#else -#define GLOBAL_INFO_LOCK(i) -#define GLOBAL_INFO_UNLOCK(i) -#endif - -/* this should probably be conditional on it existing */ -#define USE_BSEARCH - -#define d(x) -#define io(x) /* io debug */ - -#if 0 -extern int strdup_count, malloc_count, free_count; -#endif - -#define CAMEL_FOLDER_SUMMARY_VERSION (12) - -#define _PRIVATE(o) (((CamelFolderSummary *)(o))->priv) - -/* trivial lists, just because ... */ -struct _node { - struct _node *next; -}; - -static struct _node *my_list_append(struct _node **list, struct _node *n); -static int my_list_size(struct _node **list); - -static int summary_header_load(CamelFolderSummary *, FILE *); -static int summary_header_save(CamelFolderSummary *, FILE *); - -static CamelMessageInfo * message_info_new(CamelFolderSummary *, struct _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 void message_info_free(CamelFolderSummary *, CamelMessageInfo *); - -static CamelMessageContentInfo * content_info_new(CamelFolderSummary *, struct _header_raw *); -static CamelMessageContentInfo * content_info_new_from_parser(CamelFolderSummary *, CamelMimeParser *); -static CamelMessageContentInfo * content_info_new_from_message(CamelFolderSummary *s, CamelMimePart *mp); -static CamelMessageContentInfo * content_info_load(CamelFolderSummary *, FILE *); -static int content_info_save(CamelFolderSummary *, FILE *, CamelMessageContentInfo *); -static void content_info_free(CamelFolderSummary *, CamelMessageContentInfo *); - -static char *next_uid_string(CamelFolderSummary *s); - -static CamelMessageContentInfo * summary_build_content_info(CamelFolderSummary *s, CamelMessageInfo *msginfo, CamelMimeParser *mp); -static CamelMessageContentInfo * summary_build_content_info_message(CamelFolderSummary *s, CamelMessageInfo *msginfo, CamelMimePart *object); - -static void camel_folder_summary_class_init (CamelFolderSummaryClass *klass); -static void camel_folder_summary_init (CamelFolderSummary *obj); -static void camel_folder_summary_finalize (CamelObject *obj); - -static CamelObjectClass *camel_folder_summary_parent; - -static void -camel_folder_summary_class_init (CamelFolderSummaryClass *klass) -{ - camel_folder_summary_parent = camel_type_get_global_classfuncs (camel_object_get_type ()); - - klass->summary_header_load = summary_header_load; - klass->summary_header_save = summary_header_save; - - klass->message_info_new = message_info_new; - klass->message_info_new_from_parser = message_info_new_from_parser; - 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->message_info_free = message_info_free; - - klass->content_info_new = content_info_new; - klass->content_info_new_from_parser = content_info_new_from_parser; - klass->content_info_new_from_message = content_info_new_from_message; - klass->content_info_load = content_info_load; - klass->content_info_save = content_info_save; - klass->content_info_free = content_info_free; - - klass->next_uid_string = next_uid_string; -} - -static void -camel_folder_summary_init (CamelFolderSummary *s) -{ - struct _CamelFolderSummaryPrivate *p; - - p = _PRIVATE(s) = g_malloc0(sizeof(*p)); - - p->filter_charset = g_hash_table_new(g_strcase_hash, g_strcase_equal); - - s->message_info_size = sizeof(CamelMessageInfo); - s->content_info_size = sizeof(CamelMessageContentInfo); - - s->message_info_chunks = NULL; - s->content_info_chunks = NULL; - -#if defined (DOESTRV) || defined (DOEPOOLV) - s->message_info_strings = CAMEL_MESSAGE_INFO_LAST; -#endif - - s->version = CAMEL_FOLDER_SUMMARY_VERSION; - s->flags = 0; - s->time = 0; - s->nextuid = 1; - - s->messages = g_ptr_array_new(); - s->messages_uid = g_hash_table_new(g_str_hash, g_str_equal); - -#ifdef ENABLE_THREADS - p->summary_lock = g_mutex_new(); - p->io_lock = g_mutex_new(); - p->filter_lock = g_mutex_new(); - p->alloc_lock = g_mutex_new(); - p->ref_lock = g_mutex_new(); -#endif -} - -static void free_o_name(void *key, void *value, void *data) -{ - camel_object_unref((CamelObject *)value); - g_free(key); -} - -static void -camel_folder_summary_finalize (CamelObject *obj) -{ - struct _CamelFolderSummaryPrivate *p; - CamelFolderSummary *s = (CamelFolderSummary *)obj; - - p = _PRIVATE(obj); - - camel_folder_summary_clear(s); - g_ptr_array_free(s->messages, TRUE); - g_hash_table_destroy(s->messages_uid); - - g_hash_table_foreach(p->filter_charset, free_o_name, 0); - g_hash_table_destroy(p->filter_charset); - - g_free(s->summary_path); - - if (s->message_info_chunks) - e_memchunk_destroy(s->message_info_chunks); - if (s->content_info_chunks) - e_memchunk_destroy(s->content_info_chunks); - - if (p->filter_index) - camel_object_unref((CamelObject *)p->filter_index); - if (p->filter_64) - camel_object_unref((CamelObject *)p->filter_64); - if (p->filter_qp) - camel_object_unref((CamelObject *)p->filter_qp); - if (p->filter_save) - camel_object_unref((CamelObject *)p->filter_save); - if (p->filter_html) - camel_object_unref((CamelObject *)p->filter_html); - -#ifdef ENABLE_THREADS - g_mutex_free(p->summary_lock); - g_mutex_free(p->io_lock); - g_mutex_free(p->filter_lock); - g_mutex_free(p->alloc_lock); - g_mutex_free(p->ref_lock); -#endif - - g_free(p); -} - -CamelType -camel_folder_summary_get_type (void) -{ - static CamelType type = CAMEL_INVALID_TYPE; - - if (type == CAMEL_INVALID_TYPE) { - type = camel_type_register (camel_object_get_type (), "CamelFolderSummary", - sizeof (CamelFolderSummary), - sizeof (CamelFolderSummaryClass), - (CamelObjectClassInitFunc) camel_folder_summary_class_init, - NULL, - (CamelObjectInitFunc) camel_folder_summary_init, - (CamelObjectFinalizeFunc) camel_folder_summary_finalize); - } - - return type; -} - -/** - * camel_folder_summary_new: - * - * Create a new CamelFolderSummary object. - * - * Return value: A new CamelFolderSummary widget. - **/ -CamelFolderSummary * -camel_folder_summary_new (void) -{ - CamelFolderSummary *new = CAMEL_FOLDER_SUMMARY ( camel_object_new (camel_folder_summary_get_type ())); return new; -} - - -/** - * camel_folder_summary_set_filename: - * @s: - * @name: - * - * Set the filename where the summary will be loaded to/saved from. - **/ -void camel_folder_summary_set_filename(CamelFolderSummary *s, const char *name) -{ - CAMEL_SUMMARY_LOCK(s, summary_lock); - - g_free(s->summary_path); - s->summary_path = g_strdup(name); - - CAMEL_SUMMARY_UNLOCK(s, summary_lock); -} - -/** - * camel_folder_summary_set_index: - * @s: - * @index: - * - * Set the index used to index body content. If the index is NULL, or - * not set (the default), no indexing of body content will take place. - * - * Unlike earlier behaviour, build_content need not be set to perform indexing. - **/ -void camel_folder_summary_set_index(CamelFolderSummary *s, ibex *index) -{ - struct _CamelFolderSummaryPrivate *p = _PRIVATE(s); - - p->index = index; -} - -/** - * camel_folder_summary_set_build_content: - * @s: - * @state: - * - * Set a flag to tell the summary to build the content info summary - * (CamelMessageInfo.content). The default is not to build content info - * summaries. - **/ -void camel_folder_summary_set_build_content(CamelFolderSummary *s, gboolean state) -{ - s->build_content = state; -} - -/** - * camel_folder_summary_count: - * @s: - * - * Get the number of summary items stored in this summary. - * - * Return value: The number of items int he summary. - **/ -int -camel_folder_summary_count(CamelFolderSummary *s) -{ - return s->messages->len; -} - -/** - * camel_folder_summary_index: - * @s: - * @i: - * - * Retrieve a summary item by index number. - * - * A referenced to the summary item is returned, which may be - * ref'd or free'd as appropriate. - * - * Return value: The summary item, or NULL if the index @i is out - * of range. - * It must be freed using camel_folder_summary_info_free(). - **/ -CamelMessageInfo * -camel_folder_summary_index(CamelFolderSummary *s, int i) -{ - CamelMessageInfo *info = NULL; - - CAMEL_SUMMARY_LOCK(s, ref_lock); - CAMEL_SUMMARY_LOCK(s, summary_lock); - - if (i<s->messages->len) - info = g_ptr_array_index(s->messages, i); - - CAMEL_SUMMARY_UNLOCK(s, summary_lock); - - if (info) - info->refcount++; - - CAMEL_SUMMARY_UNLOCK(s, ref_lock); - - return info; -} - -/** - * camel_folder_summary_index: - * @s: - * @i: - * - * Obtain a copy of the summary array. This is done atomically, - * so cannot contain empty entries. - * - * It must be freed using camel_folder_summary_array_free(). - **/ -GPtrArray * -camel_folder_summary_array(CamelFolderSummary *s) -{ - CamelMessageInfo *info; - GPtrArray *res = g_ptr_array_new(); - int i; - - CAMEL_SUMMARY_LOCK(s, ref_lock); - CAMEL_SUMMARY_LOCK(s, summary_lock); - - g_ptr_array_set_size(res, s->messages->len); - for (i=0;i<s->messages->len;i++) { - info = res->pdata[i] = g_ptr_array_index(s->messages, i); - info->refcount++; - } - - CAMEL_SUMMARY_UNLOCK(s, summary_lock); - CAMEL_SUMMARY_UNLOCK(s, ref_lock); - - return res; -} - -/** - * camel_folder_summary_array_free: - * @s: - * @array: - * - * Free the folder summary array. - **/ -void -camel_folder_summary_array_free(CamelFolderSummary *s, GPtrArray *array) -{ - int i; - - for (i=0;i<array->len;i++) - camel_folder_summary_info_free(s, array->pdata[i]); - - g_ptr_array_free(array, TRUE); -} - -/** - * camel_folder_summary_uid: - * @s: - * @uid: - * - * Retrieve a summary item by uid. - * - * A referenced to the summary item is returned, which may be - * ref'd or free'd as appropriate. - * - * Return value: The summary item, or NULL if the uid @uid - * is not available. - * It must be freed using camel_folder_summary_info_free(). - **/ -CamelMessageInfo * -camel_folder_summary_uid(CamelFolderSummary *s, const char *uid) -{ - CamelMessageInfo *info; - - CAMEL_SUMMARY_LOCK(s, ref_lock); - CAMEL_SUMMARY_LOCK(s, summary_lock); - - info = g_hash_table_lookup(s->messages_uid, uid); - - CAMEL_SUMMARY_UNLOCK(s, summary_lock); - - if (info) - info->refcount++; - - CAMEL_SUMMARY_UNLOCK(s, ref_lock); - - return info; -} - -/** - * camel_folder_summary_next_uid: - * @s: - * - * Generate a new unique uid value as an integer. This - * may be used to create a unique sequence of numbers. - * - * Return value: The next unique uid value. - **/ -guint32 camel_folder_summary_next_uid(CamelFolderSummary *s) -{ - guint32 uid; - - - CAMEL_SUMMARY_LOCK(s, summary_lock); - - uid = s->nextuid++; - - CAMEL_SUMMARY_UNLOCK(s, summary_lock); - - /* FIXME: sync this to disk */ -/* summary_header_save(s);*/ - return uid; -} - -/** - * camel_folder_summary_set_uid: - * @s: - * @uid: The next minimum uid to assign. To avoid clashing - * uid's, set this to the uid of a given messages + 1. - * - * Set the next minimum uid available. This can be used to - * ensure new uid's do not clash with existing uid's. - **/ -void camel_folder_summary_set_uid(CamelFolderSummary *s, guint32 uid) -{ - /* TODO: sync to disk? */ - CAMEL_SUMMARY_LOCK(s, summary_lock); - - s->nextuid = MAX(s->nextuid, uid); - - CAMEL_SUMMARY_UNLOCK(s, summary_lock); -} - -/** - * camel_folder_summary_next_uid_string: - * @s: - * - * Retrieve the next uid, but as a formatted string. - * - * Return value: The next uid as an unsigned integer string. - * This string must be freed by the caller. - **/ -char * -camel_folder_summary_next_uid_string(CamelFolderSummary *s) -{ - return ((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->next_uid_string(s); -} - -/* loads the content descriptions, recursively */ -static CamelMessageContentInfo * -perform_content_info_load(CamelFolderSummary *s, FILE *in) -{ - int i; - guint32 count; - CamelMessageContentInfo *ci, *part; - - ci = ((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->content_info_load(s, in); - if (ci == NULL) - return NULL; - - if (camel_file_util_decode_uint32(in, &count) == -1 || count > 500) { - camel_folder_summary_content_info_free(s, ci); - return NULL; - } - - for (i=0;i<count;i++) { - part = perform_content_info_load(s, in); - if (part) { - my_list_append((struct _node **)&ci->childs, (struct _node *)part); - part->parent = ci; - } else { - g_warning("Summary file format messed up?"); - camel_folder_summary_content_info_free(s, ci); - return NULL; - } - } - return ci; -} - -int -camel_folder_summary_load(CamelFolderSummary *s) -{ - FILE *in; - int i; - CamelMessageInfo *mi; - - g_assert(s->summary_path); - - in = fopen(s->summary_path, "r"); - if (in == NULL) - return -1; - - CAMEL_SUMMARY_LOCK(s, io_lock); - if ( ((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->summary_header_load(s, in) == -1) - goto error; - - /* now read in each message ... */ - for (i=0;i<s->saved_count;i++) { - mi = ((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->message_info_load(s, in); - - if (mi == NULL) - goto error; - - if (s->build_content) { - mi->content = perform_content_info_load(s, in); - if (mi->content == NULL) { - camel_folder_summary_info_free(s, mi); - goto error; - } - } - - camel_folder_summary_add(s, mi); - } - - CAMEL_SUMMARY_UNLOCK(s, io_lock); - - if (fclose(in) == -1) - return -1; - - s->flags &= ~CAMEL_SUMMARY_DIRTY; - - return 0; - -error: - g_warning("Cannot load summary file: %s", strerror(ferror(in))); - CAMEL_SUMMARY_UNLOCK(s, io_lock); - fclose(in); - s->flags |= ~CAMEL_SUMMARY_DIRTY; - - return -1; -} - -/* saves the content descriptions, recursively */ -static int -perform_content_info_save(CamelFolderSummary *s, FILE *out, CamelMessageContentInfo *ci) -{ - CamelMessageContentInfo *part; - - ((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->content_info_save(s, out, ci); - camel_file_util_encode_uint32(out, my_list_size((struct _node **)&ci->childs)); - part = ci->childs; - while (part) { - perform_content_info_save(s, out, part); - part = part->next; - } - return 0; -} - -/** - * camel_folder_summary_save: - * @s: - * - * Writes the summary to disk. The summary is only written if changes - * have occured. - * - * Return value: Returns -1 on error. - **/ -int -camel_folder_summary_save(CamelFolderSummary *s) -{ - FILE *out; - int fd; - int i; - guint32 count; - CamelMessageInfo *mi; - - g_assert(s->summary_path); - - if ((s->flags & CAMEL_SUMMARY_DIRTY) == 0) - return 0; - - fd = open(s->summary_path, O_RDWR|O_CREAT, 0600); - if (fd == -1) - return -1; - out = fdopen(fd, "w"); - if ( out == NULL ) { - close(fd); - 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) { - fclose(out); - CAMEL_SUMMARY_UNLOCK(s, io_lock); - return -1; - } - - /* now write out each message ... */ - /* FIXME: check returns */ - - count = s->messages->len; - for (i=0;i<count;i++) { - mi = s->messages->pdata[i]; - ((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->message_info_save(s, out, mi); - - if (s->build_content) { - perform_content_info_save(s, out, mi->content); - } - } - - CAMEL_SUMMARY_UNLOCK(s, io_lock); - - if (fclose(out) == -1) - return -1; - - s->flags &= ~CAMEL_SUMMARY_DIRTY; - return 0; -} - -/** - * camel_folder_summary_header_load: - * @s: Summary object. - * - * Only load the header information from the summary, - * keep the rest on disk. This should only be done on - * a fresh summary object. - * - * Return value: -1 on error. - **/ -int camel_folder_summary_header_load(CamelFolderSummary *s) -{ - FILE *in; - int ret; - - g_assert(s->summary_path); - - in = fopen(s->summary_path, "r"); - if (in == NULL) - return -1; - - CAMEL_SUMMARY_LOCK(s, io_lock); - ret = ((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->summary_header_load(s, in); - CAMEL_SUMMARY_UNLOCK(s, io_lock); - - fclose(in); - s->flags &= ~CAMEL_SUMMARY_DIRTY; - return ret; -} - -static void -summary_assign_uid(CamelFolderSummary *s, CamelMessageInfo *info) -{ - const char *uid; - - uid = camel_message_info_uid(info); - if (uid == NULL || uid[0] == 0) { - camel_message_info_set_uid(info, camel_folder_summary_next_uid_string(s)); - uid = camel_message_info_uid(info); - } - - CAMEL_SUMMARY_LOCK(s, summary_lock); - - while (g_hash_table_lookup(s->messages_uid, uid)) { - g_warning("Trying to insert message with clashing uid (%s). new uid re-assigned", camel_message_info_uid(info)); - CAMEL_SUMMARY_UNLOCK(s, summary_lock); - camel_message_info_set_uid(info, camel_folder_summary_next_uid_string(s)); - uid = camel_message_info_uid(info); - info->flags |= CAMEL_MESSAGE_FOLDER_FLAGGED; - CAMEL_SUMMARY_LOCK(s, summary_lock); - } - - CAMEL_SUMMARY_UNLOCK(s, summary_lock); -} - -/** - * camel_folder_summary_add: - * @s: - * @info: - * - * Adds a new @info record to the summary. If @info->uid is NULL, then a new - * uid is automatically re-assigned by calling :next_uid_string(). - * - * The @info record should have been generated by calling one of the - * info_new_*() functions, as it will be free'd based on the summary - * class. And MUST NOT be allocated directly using malloc. - **/ -void camel_folder_summary_add(CamelFolderSummary *s, CamelMessageInfo *info) -{ - if (info == NULL) - return; - - summary_assign_uid(s, info); - - CAMEL_SUMMARY_LOCK(s, summary_lock); - -/* unnecessary for pooled vectors */ -#ifdef DOESTRV - /* this is vitally important, and also if this is ever modified, then - the hash table needs to be resynced */ - info->strings = e_strv_pack(info->strings); -#endif - - g_ptr_array_add(s->messages, info); - g_hash_table_insert(s->messages_uid, (char *)camel_message_info_uid(info), info); - s->flags |= CAMEL_SUMMARY_DIRTY; - - CAMEL_SUMMARY_UNLOCK(s, summary_lock); -} - -/** - * camel_folder_summary_add_from_header: - * @s: - * @h: - * - * Build a new info record based on a set of headers, and add it to the - * summary. - * - * Note that this function should not be used if build_content_info has - * been specified for this summary. - * - * Return value: The newly added record. - **/ -CamelMessageInfo *camel_folder_summary_add_from_header(CamelFolderSummary *s, struct _header_raw *h) -{ - CamelMessageInfo *info = camel_folder_summary_info_new_from_header(s, h); - - camel_folder_summary_add(s, info); - - return info; -} - -/** - * camel_folder_summary_add_from_parser: - * @s: - * @mp: - * - * Build a new info record based on the current position of a CamelMimeParser. - * - * The parser should be positioned before the start of the message to summarise. - * This function may be used if build_contnet_info or an index has been - * specified for the summary. - * - * Return value: The newly added record. - **/ -CamelMessageInfo *camel_folder_summary_add_from_parser(CamelFolderSummary *s, CamelMimeParser *mp) -{ - CamelMessageInfo *info = camel_folder_summary_info_new_from_parser(s, mp); - - camel_folder_summary_add(s, info); - - return info; -} - -/** - * camel_folder_summary_add_from_message: - * @s: - * @msg: - * - * Add a summary item from an existing message. - * - * Return value: - **/ -CamelMessageInfo *camel_folder_summary_add_from_message(CamelFolderSummary *s, CamelMimeMessage *msg) -{ - CamelMessageInfo *info = camel_folder_summary_info_new_from_message(s, msg); - - camel_folder_summary_add(s, info); - - return info; -} - -/** - * camel_folder_summary_info_new_from_header: - * @s: - * @h: - * - * Create a new info record from a header. - * - * Return value: Guess? This info record MUST be freed using - * camel_folder_summary_info_free(), camel_message_info_free() will not work. - **/ -CamelMessageInfo *camel_folder_summary_info_new_from_header(CamelFolderSummary *s, struct _header_raw *h) -{ - return ((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s))) -> message_info_new(s, h); -} - -/** - * camel_folder_summary_info_new_from_parser: - * @s: - * @mp: - * - * Create a new info record from a parser. If the parser cannot - * determine a uid, then none will be assigned. - - * If indexing is enabled, and the parser cannot determine a new uid, then - * one is automatically assigned. - * - * If indexing is enabled, then the content will be indexed based - * on this new uid. In this case, the message info MUST be - * added using :add(). - * - * Once complete, the parser will be positioned at the end of - * the message. - * - * Return value: Guess? This info record MUST be freed using - * camel_folder_summary_info_free(), camel_message_info_free() will not work. - **/ -CamelMessageInfo *camel_folder_summary_info_new_from_parser(CamelFolderSummary *s, CamelMimeParser *mp) -{ - CamelMessageInfo *info = NULL; - char *buffer; - int len; - struct _CamelFolderSummaryPrivate *p = _PRIVATE(s); - off_t start; - - /* should this check the parser is in the right state, or assume it is?? */ - - start = camel_mime_parser_tell(mp); - if (camel_mime_parser_step(mp, &buffer, &len) != HSCAN_EOF) { - info = ((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->message_info_new_from_parser(s, mp); - - camel_mime_parser_unstep(mp); - - /* assign a unique uid, this is slightly 'wrong' as we do not really - * know if we are going to store this in the summary, but no matter */ - if (p->index) - summary_assign_uid(s, info); - - CAMEL_SUMMARY_LOCK(s, filter_lock); - - if (p->index) { - if (p->filter_index == NULL) - p->filter_index = camel_mime_filter_index_new_ibex(p->index); - camel_mime_filter_index_set_name(p->filter_index, (char *)camel_message_info_uid(info)); - ibex_unindex(p->index, (char *)camel_message_info_uid(info)); - ibex_index_buffer(p->index, (char *)camel_message_info_uid(info), "ibexindexed", strlen("ibexindexed"), NULL); - } - - /* always scan the content info, even if we dont save it */ - info->content = summary_build_content_info(s, info, mp); - - CAMEL_SUMMARY_UNLOCK(s, filter_lock); - - info->size = camel_mime_parser_tell(mp) - start; - } - return info; -} - -/** - * camel_folder_summary_info_new_from_message: - * @: - * @: - * - * Create a summary item from a message. - * - * Return value: - **/ -CamelMessageInfo *camel_folder_summary_info_new_from_message(CamelFolderSummary *s, CamelMimeMessage *msg) -{ - CamelMessageInfo *info; - struct _CamelFolderSummaryPrivate *p = _PRIVATE(s); - - info = ((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->message_info_new_from_message(s, msg); - - /* assign a unique uid, this is slightly 'wrong' as we do not really - * know if we are going to store this in the summary, but no matter */ - summary_assign_uid(s, info); - - if (p->index) { - ibex_unindex(p->index, (char *)camel_message_info_uid(info)); - ibex_index_buffer(p->index, (char *)camel_message_info_uid(info), "ibexindexed", strlen("ibexindexed"), NULL); - } - - info->content = summary_build_content_info_message(s, info, (CamelMimePart *)msg); - - return info; -} - -/** - * camel_folder_summary_content_info_free: - * @s: - * @ci: - * - * Free the content info @ci, and all associated memory. - **/ -void -camel_folder_summary_content_info_free(CamelFolderSummary *s, CamelMessageContentInfo *ci) -{ - CamelMessageContentInfo *pw, *pn; - - pw = ci->childs; - ((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->content_info_free(s, ci); - while (pw) { - pn = pw->next; - camel_folder_summary_content_info_free(s, pw); - pw = pn; - } -} - -/** - * camel_folder_summary_info_free: - * @s: - * @mi: - * - * Unref and potentially free the message info @mi, and all associated memory. - **/ -void camel_folder_summary_info_free(CamelFolderSummary *s, CamelMessageInfo *mi) -{ - CamelMessageContentInfo *ci; - - g_assert(mi); - g_assert(s); - - CAMEL_SUMMARY_LOCK(s, ref_lock); - - g_assert(mi->refcount >= 1); - - mi->refcount--; - if (mi->refcount > 0) { - CAMEL_SUMMARY_UNLOCK(s, ref_lock); - return; - } - - CAMEL_SUMMARY_UNLOCK(s, ref_lock); - - ci = mi->content; - - ((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->message_info_free(s, mi); - if (s->build_content && ci) { - camel_folder_summary_content_info_free(s, ci); - } -} - -/** - * camel_folder_summary_info_ref: - * @s: - * @mi: - * - * Add an extra reference to @mi. - **/ -void camel_folder_summary_info_ref(CamelFolderSummary *s, CamelMessageInfo *mi) -{ - g_assert(mi); - g_assert(s); - - CAMEL_SUMMARY_LOCK(s, ref_lock); - g_assert(mi->refcount >= 1); - mi->refcount++; - CAMEL_SUMMARY_UNLOCK(s, ref_lock); -} - -/** - * camel_folder_summary_touch: - * @s: - * - * Mark the summary as changed, so that a save will save it. - **/ -void -camel_folder_summary_touch(CamelFolderSummary *s) -{ - CAMEL_SUMMARY_LOCK(s, summary_lock); - s->flags |= CAMEL_SUMMARY_DIRTY; - CAMEL_SUMMARY_UNLOCK(s, summary_lock); -} - -/** - * camel_folder_summary_clear: - * @s: - * - * Empty the summary contents. - **/ -void -camel_folder_summary_clear(CamelFolderSummary *s) -{ - int i; - - CAMEL_SUMMARY_LOCK(s, summary_lock); - if (camel_folder_summary_count(s) == 0) { - CAMEL_SUMMARY_UNLOCK(s, summary_lock); - return; - } - - for (i=0;i<s->messages->len;i++) - camel_folder_summary_info_free(s, s->messages->pdata[i]); - - g_ptr_array_set_size(s->messages, 0); - 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; - CAMEL_SUMMARY_UNLOCK(s, summary_lock); -} - -/** - * camel_folder_summary_remove: - * @s: - * @info: - * - * Remove a specific @info record from the summary. - **/ -void camel_folder_summary_remove(CamelFolderSummary *s, CamelMessageInfo *info) -{ - CAMEL_SUMMARY_LOCK(s, summary_lock); - g_hash_table_remove(s->messages_uid, camel_message_info_uid(info)); - g_ptr_array_remove(s->messages, info); - s->flags |= CAMEL_SUMMARY_DIRTY; - CAMEL_SUMMARY_UNLOCK(s, summary_lock); - - camel_folder_summary_info_free(s, info); -} - -/** - * camel_folder_summary_remove_uid: - * @s: - * @uid: - * - * Remove a specific info record from the summary, by @uid. - **/ -void camel_folder_summary_remove_uid(CamelFolderSummary *s, const char *uid) -{ - CamelMessageInfo *oldinfo; - char *olduid; - - CAMEL_SUMMARY_LOCK(s, ref_lock); - CAMEL_SUMMARY_LOCK(s, summary_lock); - if (g_hash_table_lookup_extended(s->messages_uid, uid, (void *)&olduid, (void *)&oldinfo)) { - /* make sure it doesn't vanish while we're removing it */ - oldinfo->refcount++; - CAMEL_SUMMARY_UNLOCK(s, summary_lock); - CAMEL_SUMMARY_UNLOCK(s, ref_lock); - camel_folder_summary_remove(s, oldinfo); - camel_folder_summary_info_free(s, oldinfo); - } else { - CAMEL_SUMMARY_UNLOCK(s, summary_lock); - CAMEL_SUMMARY_UNLOCK(s, ref_lock); - } -} - -/** - * camel_folder_summary_remove_index: - * @s: - * @index: - * - * Remove a specific info record from the summary, by index. - **/ -void camel_folder_summary_remove_index(CamelFolderSummary *s, int index) -{ - CAMEL_SUMMARY_LOCK(s, summary_lock); - if (index < s->messages->len) { - CamelMessageInfo *info = s->messages->pdata[index]; - - g_hash_table_remove(s->messages_uid, camel_message_info_uid(info)); - g_ptr_array_remove_index(s->messages, index); - s->flags |= CAMEL_SUMMARY_DIRTY; - - CAMEL_SUMMARY_UNLOCK(s, summary_lock); - camel_folder_summary_info_free(s, info); - } else { - CAMEL_SUMMARY_UNLOCK(s, summary_lock); - } -} - -/* should be sorted, for binary search */ -/* This is a tokenisation mechanism for strings written to the - summary - to save space. - This list can have at most 31 words. */ -static char * tokens[] = { - "7bit", - "8bit", - "alternative", - "application", - "base64", - "boundary", - "charset", - "filename", - "html", - "image", - "iso-8859-1", - "iso-8859-8", - "message", - "mixed", - "multipart", - "name", - "octet-stream", - "parallel", - "plain", - "postscript", - "quoted-printable", - "related", - "rfc822", - "text", - "us-ascii", /* 25 words */ -}; - -#define tokens_len (sizeof(tokens)/sizeof(tokens[0])) - -/* baiscally ... - 0 = null - 1-tokens_len == tokens[id-1] - >=32 string, length = n-32 -*/ - -#ifdef USE_BSEARCH -static int -token_search_cmp(char *key, char **index) -{ - d(printf("comparing '%s' to '%s'\n", key, *index)); - return strcmp(key, *index); -} -#endif - -/** - * camel_folder_summary_encode_token: - * @out: - * @str: - * - * Encode a string value, but use tokenisation and compression - * to reduce the size taken for common mailer words. This - * can still be used to encode normal strings as well. - * - * Return value: -1 on error. - **/ -int -camel_folder_summary_encode_token(FILE *out, const char *str) -{ - io(printf("Encoding token: '%s'\n", str)); - - if (str == NULL) { - return camel_file_util_encode_uint32(out, 0); - } else { - int len = strlen(str); - int i, token=-1; - - if (len <= 16) { - char lower[32]; - char **match; - - for (i=0;i<len;i++) - lower[i] = tolower(str[i]); - lower[i] = 0; -#ifdef USE_BSEARCH - match = bsearch(lower, tokens, tokens_len, sizeof(char *), (int (*)(const void *, const void *))token_search_cmp); - if (match) - token = match-tokens; -#else - for (i=0;i<tokens_len;i++) { - if (!strcmp(tokens[i], lower)) { - token = i; - break; - } - } -#endif - } - if (token != -1) { - return camel_file_util_encode_uint32(out, token+1); - } else { - if (camel_file_util_encode_uint32(out, len+32) == -1) - return -1; - if (fwrite(str, len, 1, out) != 1) - return -1; - } - } - return 0; -} - -/** - * camel_folder_summary_decode_token: - * @in: - * @str: - * - * Decode a token value. - * - * Return value: -1 on error. - **/ -int -camel_folder_summary_decode_token(FILE *in, char **str) -{ - char *ret; - guint32 len; - - io(printf("Decode token ...\n")); - - if (camel_file_util_decode_uint32(in, &len) == -1) { - g_warning("Could not decode token from file"); - *str = NULL; - return -1; - } - - if (len<32) { - if (len <= 0) { - ret = NULL; - } else if (len<= tokens_len) { - ret = g_strdup(tokens[len-1]); - } else { - g_warning("Invalid token encountered: %d", len); - *str = NULL; - return -1; - } - } else if (len > 10240) { - g_warning("Got broken string header length: %d bytes", len); - *str = NULL; - return -1; - } else { - len -= 32; - ret = g_malloc(len+1); - if (fread(ret, len, 1, in) != 1) { - g_free(ret); - *str = NULL; - return -1; - } - ret[len]=0; - } - - io(printf("Token = '%s'\n", ret)); - - *str = ret; - return 0; -} - -static struct _node * -my_list_append(struct _node **list, struct _node *n) -{ - struct _node *ln = (struct _node *)list; - while (ln->next) - ln = ln->next; - n->next = 0; - ln->next = n; - return n; -} - -static int -my_list_size(struct _node **list) -{ - int len = 0; - struct _node *ln = (struct _node *)list; - while (ln->next) { - ln = ln->next; - len++; - } - return len; -} - -static int -summary_header_load(CamelFolderSummary *s, FILE *in) -{ - gint32 version, flags, nextuid, count; - time_t time; - - fseek(in, 0, SEEK_SET); - - io(printf("Loading header\n")); - - if (camel_file_util_decode_fixed_int32(in, &version) == -1 - || camel_file_util_decode_fixed_int32(in, &flags) == -1 - || camel_file_util_decode_fixed_int32(in, &nextuid) == -1 - || camel_file_util_decode_time_t(in, &time) == -1 - || camel_file_util_decode_fixed_int32(in, &count) == -1) { - return -1; - } - - s->nextuid = nextuid; - s->flags = flags; - s->time = time; - s->saved_count = count; - if (s->version != version) { - g_warning("Summary header version mismatch"); - return -1; - } - return 0; -} - -static int -summary_header_save(CamelFolderSummary *s, FILE *out) -{ - fseek(out, 0, SEEK_SET); - - io(printf("Savining header\n")); - - camel_file_util_encode_fixed_int32(out, s->version); - camel_file_util_encode_fixed_int32(out, s->flags); - camel_file_util_encode_fixed_int32(out, s->nextuid); - camel_file_util_encode_time_t(out, s->time); - return camel_file_util_encode_fixed_int32(out, camel_folder_summary_count(s)); -} - -/* are these even useful for anything??? */ -static CamelMessageInfo * message_info_new_from_parser(CamelFolderSummary *s, CamelMimeParser *mp) -{ - CamelMessageInfo *mi = NULL; - int state; - - state = camel_mime_parser_state(mp); - switch (state) { - case HSCAN_HEADER: - case HSCAN_MESSAGE: - case HSCAN_MULTIPART: - mi = ((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->message_info_new(s, camel_mime_parser_headers_raw(mp)); - break; - default: - g_error("Invalid parser state"); - } - - return mi; -} - -static CamelMessageContentInfo * content_info_new_from_parser(CamelFolderSummary *s, CamelMimeParser *mp) -{ - CamelMessageContentInfo *ci = NULL; - - switch (camel_mime_parser_state(mp)) { - case HSCAN_HEADER: - case HSCAN_MESSAGE: - case HSCAN_MULTIPART: - ci = ((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->content_info_new(s, camel_mime_parser_headers_raw(mp)); - if (ci) { - ci->type = camel_mime_parser_content_type(mp); - header_content_type_ref(ci->type); - } - break; - default: - g_error("Invalid parser state"); - } - - return ci; -} - -static CamelMessageInfo * message_info_new_from_message(CamelFolderSummary *s, CamelMimeMessage *msg) -{ - CamelMessageInfo *mi; - - mi = ((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->message_info_new(s, ((CamelMimePart *)msg)->headers); - - return mi; -} - -static CamelMessageContentInfo * content_info_new_from_message(CamelFolderSummary *s, CamelMimePart *mp) -{ - CamelMessageContentInfo *ci; - - ci = ((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->content_info_new(s, mp->headers); - - return ci; -} - -static char * -summary_format_address(struct _header_raw *h, const char *name) -{ - struct _header_address *addr; - const char *text; - char *ret; - - text = header_raw_find (&h, name, NULL); - addr = header_address_decode (text); - if (addr) { - ret = header_address_list_format (addr); - header_address_list_clear (&addr); - } else { - ret = g_strdup (text); - } - - return ret; -} - -static char * -summary_format_string (struct _header_raw *h, const char *name, const char *charset) -{ - const char *text; - - text = header_raw_find (&h, name, NULL); - if (text) { - while (isspace ((unsigned) *text)) - text++; - return header_decode_string (text, charset); - } else { - return NULL; - } -} - -/** - * camel_folder_summary_info_new: - * @s: - * - * Allocate a new camel message info, suitable for adding - * to this summary. - * - * Return value: - **/ -CamelMessageInfo * -camel_folder_summary_info_new(CamelFolderSummary *s) -{ - CamelMessageInfo *mi; - - CAMEL_SUMMARY_LOCK(s, alloc_lock); - if (s->message_info_chunks == NULL) - s->message_info_chunks = e_memchunk_new(32, s->message_info_size); - mi = e_memchunk_alloc(s->message_info_chunks); - CAMEL_SUMMARY_UNLOCK(s, alloc_lock); - - memset(mi, 0, s->message_info_size); -#ifdef DOEPOOLV - mi->strings = e_poolv_new (s->message_info_strings); -#endif -#ifdef DOESTRV - mi->strings = e_strv_new(s->message_info_strings); -#endif - mi->refcount = 1; - return mi; -} - -/** - * camel_folder_summary_content_info_new: - * @s: - * - * Allocate a new camel message content info, suitable for adding - * to this summary. - * - * Return value: - **/ -CamelMessageContentInfo * -camel_folder_summary_content_info_new(CamelFolderSummary *s) -{ - CamelMessageContentInfo *ci; - - CAMEL_SUMMARY_LOCK(s, alloc_lock); - if (s->content_info_chunks == NULL) - s->content_info_chunks = e_memchunk_new(32, s->content_info_size); - ci = e_memchunk_alloc(s->content_info_chunks); - CAMEL_SUMMARY_UNLOCK(s, alloc_lock); - - memset(ci, 0, s->content_info_size); - return ci; -} - -static CamelMessageInfo * -message_info_new(CamelFolderSummary *s, struct _header_raw *h) -{ - CamelMessageInfo *mi; - const char *received; - guchar digest[16]; - struct _header_references *refs, *scan; - char *msgid; - int count; - char *subject, *from, *to, *cc, *mlist; - struct _header_content_type *ct = NULL; - const char *content, *charset = NULL; - - mi = camel_folder_summary_info_new(s); - - if ((content = header_raw_find(&h, "Content-Type", NULL)) - && (ct = header_content_type_decode(content)) - && (charset = header_content_type_param(ct, "charset")) - && (strcasecmp(charset, "us-ascii") == 0)) - charset = NULL; - - charset = e_iconv_charset_name(charset); - - subject = summary_format_string(h, "subject", charset); - from = summary_format_address(h, "from"); - to = summary_format_address(h, "to"); - cc = summary_format_address(h, "cc"); - mlist = header_raw_check_mailing_list(&h); - - if (ct) - header_content_type_unref(ct); - -#ifdef DOEPOOLV - e_poolv_set(mi->strings, CAMEL_MESSAGE_INFO_SUBJECT, subject, TRUE); - e_poolv_set(mi->strings, CAMEL_MESSAGE_INFO_FROM, from, TRUE); - e_poolv_set(mi->strings, CAMEL_MESSAGE_INFO_TO, to, TRUE); - e_poolv_set(mi->strings, CAMEL_MESSAGE_INFO_CC, cc, TRUE); - e_poolv_set(mi->strings, CAMEL_MESSAGE_INFO_MLIST, mlist, TRUE); -#elif defined (DOESTRV) - e_strv_set_ref_free(mi->strings, CAMEL_MESSAGE_INFO_SUBJECT, subject); - e_strv_set_ref_free(mi->strings, CAMEL_MESSAGE_INFO_FROM, from); - e_strv_set_ref_free(mi->strings, CAMEL_MESSAGE_INFO_TO, to); - e_strv_set_ref_free(mi->strings, CAMEL_MESSAGE_INFO_CC, cc); - e_strv_set_ref_free(mi->strings, CAMEL_MESSAGE_INFO_MLIST, mlist); -#else - mi->subject = subject; - mi->from = from; - mi->to = to; - mi->cc = cc; - mi->mlist = mlist; -#endif - - mi->user_flags = NULL; - mi->user_tags = NULL; - mi->date_sent = header_decode_date(header_raw_find(&h, "date", NULL), NULL); - received = header_raw_find(&h, "received", NULL); - if (received) - received = strrchr(received, ';'); - if (received) - mi->date_received = header_decode_date(received + 1, NULL); - else - mi->date_received = 0; - - msgid = header_msgid_decode(header_raw_find(&h, "message-id", NULL)); - if (msgid) { - md5_get_digest(msgid, strlen(msgid), digest); - memcpy(mi->message_id.id.hash, digest, sizeof(mi->message_id.id.hash)); - g_free(msgid); - } - /* if we have a references, use that, otherwise, see if we have an in-reply-to - header, with parsable content, otherwise *shrug* */ - if ((refs = header_references_decode(header_raw_find(&h, "references", NULL))) != NULL - || (refs = header_references_decode(header_raw_find(&h, "in-reply-to", NULL))) != NULL) { - count = header_references_list_size(&refs); - mi->references = g_malloc(sizeof(*mi->references) + ((count-1) * sizeof(mi->references->references[0]))); - count = 0; - scan = refs; - while (scan) { - /* FIXME: the id might be NULL because of a small bug in camel-mime-utils */ - if (scan->id) { - md5_get_digest(scan->id, strlen(scan->id), digest); - memcpy(mi->references->references[count].id.hash, digest, sizeof(mi->message_id.id.hash)); - count++; - } - scan = scan->next; - } - mi->references->size = count; - header_references_list_clear(&refs); - } - - return mi; -} - - -static CamelMessageInfo * -message_info_load(CamelFolderSummary *s, FILE *in) -{ - CamelMessageInfo *mi; - guint count; - int i; - char *subject, *from, *to, *cc, *mlist, *uid;; - - mi = camel_folder_summary_info_new(s); - - io(printf("Loading message info\n")); - - camel_file_util_decode_string(in, &uid); - camel_file_util_decode_uint32(in, &mi->flags); - camel_file_util_decode_uint32(in, &mi->size); - camel_file_util_decode_time_t(in, &mi->date_sent); - camel_file_util_decode_time_t(in, &mi->date_received); - camel_file_util_decode_string(in, &subject); - camel_file_util_decode_string(in, &from); - camel_file_util_decode_string(in, &to); - camel_file_util_decode_string(in, &cc); - camel_file_util_decode_string(in, &mlist); - -#ifdef DOEPOOLV - e_poolv_set(mi->strings, CAMEL_MESSAGE_INFO_UID, uid, TRUE); - e_poolv_set(mi->strings, CAMEL_MESSAGE_INFO_SUBJECT, subject, TRUE); - e_poolv_set(mi->strings, CAMEL_MESSAGE_INFO_FROM, from, TRUE); - e_poolv_set(mi->strings, CAMEL_MESSAGE_INFO_TO, to, TRUE); - e_poolv_set(mi->strings, CAMEL_MESSAGE_INFO_CC, cc, TRUE); - e_poolv_set(mi->strings, CAMEL_MESSAGE_INFO_MLIST, mlist, TRUE); -#elif defined (DOESTRV) - e_strv_set_ref_free(mi->strings, CAMEL_MESSAGE_INFO_UID, uid); - e_strv_set_ref_free(mi->strings, CAMEL_MESSAGE_INFO_SUBJECT, subject); - e_strv_set_ref_free(mi->strings, CAMEL_MESSAGE_INFO_FROM, from); - e_strv_set_ref_free(mi->strings, CAMEL_MESSAGE_INFO_TO, to); - e_strv_set_ref_free(mi->strings, CAMEL_MESSAGE_INFO_CC, cc); - e_strv_set_ref_free(mi->strings, CAMEL_MESSAGE_INFO_MLIST, mlist); -#else - mi->uid = uid; - mi->subject = subject; - mi->from = from; - mi->to = to; - mi->cc = cc; - mi->mlist = mlist; -#endif - - mi->content = NULL; - - camel_file_util_decode_fixed_int32(in, &mi->message_id.id.part.hi); - camel_file_util_decode_fixed_int32(in, &mi->message_id.id.part.lo); - - if (camel_file_util_decode_uint32(in, &count) == -1 || count > 500) - goto error; - - if (count > 0) { - mi->references = g_malloc(sizeof(*mi->references) + ((count-1) * sizeof(mi->references->references[0]))); - mi->references->size = count; - for (i=0;i<count;i++) { - camel_file_util_decode_fixed_int32(in, &mi->references->references[i].id.part.hi); - camel_file_util_decode_fixed_int32(in, &mi->references->references[i].id.part.lo); - } - } - - if (camel_file_util_decode_uint32(in, &count) == -1 || count > 500) - goto error; - - for (i=0;i<count;i++) { - char *name; - camel_file_util_decode_string(in, &name); - camel_flag_set(&mi->user_flags, name, TRUE); - g_free(name); - } - - if (camel_file_util_decode_uint32(in, &count) == -1 || count > 500) - goto error; - - for (i=0;i<count;i++) { - char *name, *value; - camel_file_util_decode_string(in, &name); - camel_file_util_decode_string(in, &value); - camel_tag_set(&mi->user_tags, name, value); - g_free(name); - g_free(value); - } - - if (!ferror(in)) - return mi; - -error: - camel_folder_summary_info_free(s, mi); - - return NULL; -} - -static int -message_info_save(CamelFolderSummary *s, FILE *out, CamelMessageInfo *mi) -{ - guint32 count; - CamelFlag *flag; - CamelTag *tag; - int i; - - io(printf("Saving message info\n")); - - camel_file_util_encode_string(out, camel_message_info_uid(mi)); - camel_file_util_encode_uint32(out, mi->flags); - camel_file_util_encode_uint32(out, mi->size); - camel_file_util_encode_time_t(out, mi->date_sent); - camel_file_util_encode_time_t(out, mi->date_received); - camel_file_util_encode_string(out, camel_message_info_subject(mi)); - camel_file_util_encode_string(out, camel_message_info_from(mi)); - camel_file_util_encode_string(out, camel_message_info_to(mi)); - camel_file_util_encode_string(out, camel_message_info_cc(mi)); - camel_file_util_encode_string(out, camel_message_info_mlist(mi)); - - camel_file_util_encode_fixed_int32(out, mi->message_id.id.part.hi); - camel_file_util_encode_fixed_int32(out, mi->message_id.id.part.lo); - - if (mi->references) { - camel_file_util_encode_uint32(out, mi->references->size); - for (i=0;i<mi->references->size;i++) { - camel_file_util_encode_fixed_int32(out, mi->references->references[i].id.part.hi); - camel_file_util_encode_fixed_int32(out, mi->references->references[i].id.part.lo); - } - } else { - camel_file_util_encode_uint32(out, 0); - } - - count = camel_flag_list_size(&mi->user_flags); - camel_file_util_encode_uint32(out, count); - flag = mi->user_flags; - while (flag) { - camel_file_util_encode_string(out, flag->name); - flag = flag->next; - } - - count = camel_tag_list_size(&mi->user_tags); - camel_file_util_encode_uint32(out, count); - tag = mi->user_tags; - while (tag) { - camel_file_util_encode_string(out, tag->name); - camel_file_util_encode_string(out, tag->value); - tag = tag->next; - } - - return ferror(out); -} - -static void -message_info_free(CamelFolderSummary *s, CamelMessageInfo *mi) -{ -#ifdef DOEPOOLV - e_poolv_destroy(mi->strings); -#elif defined (DOESTRV) - e_strv_destroy(mi->strings); -#else - g_free(mi->uid); - g_free(mi->subject); - g_free(mi->from); - g_free(mi->to); - g_free(mi->cc); - g_free(mi->mlist); -#endif - g_free(mi->references); - camel_flag_list_free(&mi->user_flags); - camel_tag_list_free(&mi->user_tags); - e_memchunk_free(s->message_info_chunks, mi); -} - -static CamelMessageContentInfo * -content_info_new (CamelFolderSummary *s, struct _header_raw *h) -{ - CamelMessageContentInfo *ci; - const char *charset; - - ci = camel_folder_summary_content_info_new (s); - - charset = e_iconv_locale_charset(); - ci->id = header_msgid_decode (header_raw_find (&h, "content-id", NULL)); - ci->description = header_decode_string (header_raw_find (&h, "content-description", NULL), NULL); - ci->encoding = header_content_encoding_decode (header_raw_find (&h, "content-transfer-encoding", NULL)); - - return ci; -} - -static CamelMessageContentInfo * -content_info_load(CamelFolderSummary *s, FILE *in) -{ - CamelMessageContentInfo *ci; - char *type, *subtype; - guint32 count, i; - struct _header_content_type *ct; - - io(printf("Loading content info\n")); - - ci = camel_folder_summary_content_info_new(s); - - camel_folder_summary_decode_token(in, &type); - camel_folder_summary_decode_token(in, &subtype); - ct = header_content_type_new(type, subtype); - g_free(type); /* can this be removed? */ - g_free(subtype); - if (camel_file_util_decode_uint32(in, &count) == -1 || count > 500) - goto error; - - for (i=0;i<count;i++) { - char *name, *value; - camel_folder_summary_decode_token(in, &name); - camel_folder_summary_decode_token(in, &value); - header_content_type_set_param(ct, name, value); - /* TODO: do this so we dont have to double alloc/free */ - g_free(name); - g_free(value); - } - ci->type = ct; - - camel_folder_summary_decode_token(in, &ci->id); - camel_folder_summary_decode_token(in, &ci->description); - camel_folder_summary_decode_token(in, &ci->encoding); - - camel_file_util_decode_uint32(in, &ci->size); - - ci->childs = NULL; - - if (!ferror(in)) - return ci; - -error: - camel_folder_summary_content_info_free(s, ci); - return NULL; -} - -static int -content_info_save(CamelFolderSummary *s, FILE *out, CamelMessageContentInfo *ci) -{ - struct _header_content_type *ct; - struct _header_param *hp; - - io(printf("Saving content info\n")); - - ct = ci->type; - if (ct) { - camel_folder_summary_encode_token(out, ct->type); - camel_folder_summary_encode_token(out, ct->subtype); - camel_file_util_encode_uint32(out, my_list_size((struct _node **)&ct->params)); - hp = ct->params; - while (hp) { - camel_folder_summary_encode_token(out, hp->name); - camel_folder_summary_encode_token(out, hp->value); - hp = hp->next; - } - } else { - camel_folder_summary_encode_token(out, NULL); - camel_folder_summary_encode_token(out, NULL); - camel_file_util_encode_uint32(out, 0); - } - camel_folder_summary_encode_token(out, ci->id); - camel_folder_summary_encode_token(out, ci->description); - camel_folder_summary_encode_token(out, ci->encoding); - return camel_file_util_encode_uint32(out, ci->size); -} - -static void -content_info_free(CamelFolderSummary *s, CamelMessageContentInfo *ci) -{ - header_content_type_unref(ci->type); - g_free(ci->id); - g_free(ci->description); - g_free(ci->encoding); - e_memchunk_free(s->content_info_chunks, ci); -} - -static char * -next_uid_string(CamelFolderSummary *s) -{ - return g_strdup_printf("%u", camel_folder_summary_next_uid(s)); -} - -/* - OK - Now this is where all the "smarts" happen, where the content info is built, - and any indexing and what not is performed -*/ - -/* must have filter_lock before calling this function */ -static CamelMessageContentInfo * -summary_build_content_info(CamelFolderSummary *s, CamelMessageInfo *msginfo, CamelMimeParser *mp) -{ - int state, len; - char *buffer; - CamelMessageContentInfo *info = NULL; - struct _header_content_type *ct; - int body; - int enc_id = -1, chr_id = -1, html_id = -1, idx_id = -1; - struct _CamelFolderSummaryPrivate *p = _PRIVATE(s); - CamelMimeFilterCharset *mfc; - CamelMessageContentInfo *part; - - d(printf("building content info\n")); - - /* start of this part */ - state = camel_mime_parser_step(mp, &buffer, &len); - body = camel_mime_parser_tell(mp); - - if (s->build_content) - info = ((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->content_info_new_from_parser(s, mp); - - switch(state) { - case HSCAN_HEADER: - /* check content type for indexing, then read body */ - ct = camel_mime_parser_content_type(mp); - /* update attachments flag as we go */ - if (!header_content_type_is(ct, "text", "*")) - msginfo->flags |= CAMEL_MESSAGE_ATTACHMENTS; - - if (p->index && header_content_type_is(ct, "text", "*")) { - char *encoding; - const char *charset; - - d(printf("generating index:\n")); - - encoding = header_content_encoding_decode(camel_mime_parser_header(mp, "content-transfer-encoding", NULL)); - if (encoding) { - if (!strcasecmp(encoding, "base64")) { - d(printf(" decoding base64\n")); - if (p->filter_64 == NULL) - p->filter_64 = camel_mime_filter_basic_new_type(CAMEL_MIME_FILTER_BASIC_BASE64_DEC); - else - camel_mime_filter_reset((CamelMimeFilter *)p->filter_64); - enc_id = camel_mime_parser_filter_add(mp, (CamelMimeFilter *)p->filter_64); - } else if (!strcasecmp(encoding, "quoted-printable")) { - d(printf(" decoding quoted-printable\n")); - if (p->filter_qp == NULL) - p->filter_qp = camel_mime_filter_basic_new_type(CAMEL_MIME_FILTER_BASIC_QP_DEC); - else - camel_mime_filter_reset((CamelMimeFilter *)p->filter_qp); - enc_id = camel_mime_parser_filter_add(mp, (CamelMimeFilter *)p->filter_qp); - } else { - d(printf(" ignoring encoding %s\n", encoding)); - } - g_free(encoding); - } - - charset = header_content_type_param(ct, "charset"); - if (charset!=NULL - && !(strcasecmp(charset, "us-ascii")==0 - || strcasecmp(charset, "utf-8")==0)) { - d(printf(" Adding conversion filter from %s to UTF-8\n", charset)); - mfc = g_hash_table_lookup(p->filter_charset, charset); - if (mfc == NULL) { - mfc = camel_mime_filter_charset_new_convert(charset, "UTF-8"); - if (mfc) - g_hash_table_insert(p->filter_charset, g_strdup(charset), mfc); - } else { - camel_mime_filter_reset((CamelMimeFilter *)mfc); - } - if (mfc) { - chr_id = camel_mime_parser_filter_add(mp, (CamelMimeFilter *)mfc); - } else { - g_warning("Cannot convert '%s' to 'UTF-8', message index may be corrupt", charset); - } - } - - /* we do charset conversions before this filter, which isn't strictly correct, - but works in most cases */ - if (header_content_type_is(ct, "text", "html")) { - if (p->filter_html == NULL) - p->filter_html = camel_mime_filter_html_new(); - else - camel_mime_filter_reset((CamelMimeFilter *)p->filter_html); - html_id = camel_mime_parser_filter_add(mp, (CamelMimeFilter *)p->filter_html); - } - - /* and this filter actually does the indexing */ - idx_id = camel_mime_parser_filter_add(mp, (CamelMimeFilter *)p->filter_index); - } - /* and scan/index everything */ - while (camel_mime_parser_step(mp, &buffer, &len) != HSCAN_BODY_END) - ; - /* and remove the filters */ - camel_mime_parser_filter_remove(mp, enc_id); - camel_mime_parser_filter_remove(mp, chr_id); - camel_mime_parser_filter_remove(mp, html_id); - camel_mime_parser_filter_remove(mp, idx_id); - break; - case HSCAN_MULTIPART: - d(printf("Summarising multipart\n")); - /* update attachments flag as we go */ - ct = camel_mime_parser_content_type(mp); - if (header_content_type_is(ct, "multipart", "mixed")) - msginfo->flags |= CAMEL_MESSAGE_ATTACHMENTS; - - while (camel_mime_parser_step(mp, &buffer, &len) != HSCAN_MULTIPART_END) { - camel_mime_parser_unstep(mp); - part = summary_build_content_info(s, msginfo, mp); - if (part) { - part->parent = info; - my_list_append((struct _node **)&info->childs, (struct _node *)part); - } - } - break; - case HSCAN_MESSAGE: - d(printf("Summarising message\n")); - /* update attachments flag as we go */ - msginfo->flags |= CAMEL_MESSAGE_ATTACHMENTS; - - part = summary_build_content_info(s, msginfo, mp); - if (part) { - part->parent = info; - my_list_append((struct _node **)&info->childs, (struct _node *)part); - } - state = camel_mime_parser_step(mp, &buffer, &len); - if (state != HSCAN_MESSAGE_END) { - g_error("Bad parser state: Expecing MESSAGE_END or MESSAGE_EOF, got: %d", state); - camel_mime_parser_unstep(mp); - } - break; - } - - d(printf("finished building content info\n")); - - return info; -} - -/* build the content-info, from a message */ -/* this needs no lock, as we copy all data, and ibex is threadsafe */ -static CamelMessageContentInfo * -summary_build_content_info_message(CamelFolderSummary *s, CamelMessageInfo *msginfo, CamelMimePart *object) -{ - CamelDataWrapper *containee; - int parts, i; - struct _CamelFolderSummaryPrivate *p = _PRIVATE(s); - CamelMessageContentInfo *info = NULL, *child; - - if (s->build_content) - info = ((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->content_info_new_from_message(s, object); - - containee = camel_medium_get_content_object(CAMEL_MEDIUM(object)); - - if (containee == NULL) - return info; - - /* TODO: I find it odd that get_part and get_content_object do not - add a reference, probably need fixing for multithreading */ - - /* check for attachments */ - if (header_content_type_is(CAMEL_DATA_WRAPPER(containee)->mime_type, "multipart", "*")) { - if (header_content_type_is(CAMEL_DATA_WRAPPER(containee)->mime_type, "multipart", "mixed")) - msginfo->flags |= CAMEL_MESSAGE_ATTACHMENTS; - } else if (!header_content_type_is(CAMEL_DATA_WRAPPER(containee)->mime_type, "text", "*")) - msginfo->flags |= CAMEL_MESSAGE_ATTACHMENTS; - - /* using the object types is more accurate than using the mime/types */ - if (CAMEL_IS_MULTIPART(containee)) { - parts = camel_multipart_get_number(CAMEL_MULTIPART(containee)); - for (i=0;i<parts;i++) { - CamelMimePart *part = camel_multipart_get_part(CAMEL_MULTIPART(containee), i); - g_assert(part); - child = summary_build_content_info_message(s, msginfo, part); - if (child) { - child->parent = info; - my_list_append((struct _node **)&info->childs, (struct _node *)child); - } - } - } else if (CAMEL_IS_MIME_MESSAGE(containee)) { - /* for messages we only look at its contents */ - child = summary_build_content_info_message(s, msginfo, (CamelMimePart *)containee); - if (child) { - child->parent = info; - my_list_append((struct _node **)&info->childs, (struct _node *)child); - } - } else if (p->index - && header_content_type_is(CAMEL_DATA_WRAPPER(containee)->mime_type, "text", "*")) { - /* index all text parts if we're indexing */ - CamelStreamMem *mem = (CamelStreamMem *)camel_stream_mem_new(); - - camel_data_wrapper_write_to_stream(containee, (CamelStream *)mem); - ibex_index_buffer(p->index, (char *)camel_message_info_uid(msginfo), mem->buffer->data, mem->buffer->len, NULL); - camel_object_unref((CamelObject *)mem); - } - - return info; -} - -/** - * camel_flag_get: - * @list: - * @name: - * - * Find the state of the flag @name in @list. - * - * Return value: The state of the flag (TRUE or FALSE). - **/ -gboolean -camel_flag_get(CamelFlag **list, const char *name) -{ - CamelFlag *flag; - flag = *list; - while (flag) { - if (!strcmp(flag->name, name)) - return TRUE; - flag = flag->next; - } - return FALSE; -} - -/** - * camel_flag_set: - * @list: - * @name: - * @value: - * - * Set the state of a flag @name in the list @list to @value. - * - * Return value: Whether or not it changed. - **/ -gboolean -camel_flag_set(CamelFlag **list, const char *name, gboolean value) -{ - CamelFlag *flag, *tmp; - - /* this 'trick' works because flag->next is the first element */ - flag = (CamelFlag *)list; - while (flag->next) { - tmp = flag->next; - if (!strcmp(flag->next->name, name)) { - if (!value) { - flag->next = tmp->next; - g_free(tmp); - } - return !value; - } - flag = tmp; - } - - if (value) { - tmp = g_malloc(sizeof(*tmp) + strlen(name)); - strcpy(tmp->name, name); - tmp->next = 0; - flag->next = tmp; - } - return value; -} - -/** - * camel_flag_list_size: - * @list: - * - * Get the length of the flag list. - * - * Return value: The number of TRUE flags in the list. - **/ -int -camel_flag_list_size(CamelFlag **list) -{ - int count=0; - CamelFlag *flag; - - flag = *list; - while (flag) { - count++; - flag = flag->next; - } - return count; -} - -/** - * camel_flag_list_free: - * @list: - * - * Free the memory associated with the flag list @list. - **/ -void -camel_flag_list_free(CamelFlag **list) -{ - CamelFlag *flag, *tmp; - flag = *list; - while (flag) { - tmp = flag->next; - g_free(flag); - flag = tmp; - } - *list = NULL; -} - -/** - * camel_flag_list_copy: - * @to: - * @from: - * - * Copy a flag list, return true if the destination list @to changed. - * - * Return value: - **/ -gboolean -camel_flag_list_copy(CamelFlag **to, CamelFlag **from) -{ - CamelFlag *flag, *tmp; - int changed = FALSE; - - if (*to == NULL && from == NULL) - return FALSE; - - /* Remove any now-missing flags */ - flag = (CamelFlag *)to; - while (flag->next) { - tmp = flag->next; - if (!camel_flag_get(from, tmp->name)) { - flag->next = tmp->next; - g_free(tmp); - changed = TRUE; - } else { - flag = tmp; - } - } - - /* Add any new flags */ - flag = *from; - while (flag) { - changed |= camel_flag_set(to, flag->name, TRUE); - flag = flag->next; - } - - return changed; -} - -const char * -camel_tag_get(CamelTag **list, const char *name) -{ - CamelTag *tag; - - tag = *list; - while (tag) { - if (!strcmp(tag->name, name)) - return (const char *)tag->value; - tag = tag->next; - } - return NULL; -} - -/** - * camel_tag_set: - * @list: - * @name: - * @value: - * - * Set the tag @name in the tag list @list to @value. - * - * Return value: whether or not it changed - **/ -gboolean -camel_tag_set(CamelTag **list, const char *name, const char *value) -{ - CamelTag *tag, *tmp; - - /* this 'trick' works because tag->next is the first element */ - tag = (CamelTag *)list; - while (tag->next) { - tmp = tag->next; - if (!strcmp(tmp->name, name)) { - if (value == NULL) { /* clear it? */ - tag->next = tmp->next; - g_free(tmp->value); - g_free(tmp); - return TRUE; - } else if (strcmp(tmp->value, value)) { /* has it changed? */ - g_free(tmp->value); - tmp->value = g_strdup(value); - return TRUE; - } - return FALSE; - } - tag = tmp; - } - - if (value) { - tmp = g_malloc(sizeof(*tmp)+strlen(name)); - strcpy(tmp->name, name); - tmp->value = g_strdup(value); - tmp->next = 0; - tag->next = tmp; - return TRUE; - } - return FALSE; -} - -/** - * camel_tag_list_size: - * @list: - * - * Get the number of tags present in the tag list @list. - * - * Return value: The number of tags. - **/ -int camel_tag_list_size(CamelTag **list) -{ - int count=0; - CamelTag *tag; - - tag = *list; - while (tag) { - count++; - tag = tag->next; - } - return count; -} - -static void -rem_tag(char *key, char *value, CamelTag **to) -{ - camel_tag_set(to, key, NULL); -} - -/** - * camel_tag_list_copy: - * @to: - * @from: - * - * Copy a list of tags. - * - * Return value: - **/ -gboolean -camel_tag_list_copy(CamelTag **to, CamelTag **from) -{ - int changed = FALSE; - CamelTag *tag; - GHashTable *left; - - if (*to == NULL && from == NULL) - return FALSE; - - left = g_hash_table_new(g_str_hash, g_str_equal); - tag = *to; - while (tag) { - g_hash_table_insert(left, tag->name, tag); - tag = tag->next; - } - - tag = *from; - while (tag) { - changed |= camel_tag_set(to, tag->name, tag->value); - g_hash_table_remove(left, tag->name); - tag = tag->next; - } - - if (g_hash_table_size(left)>0) { - g_hash_table_foreach(left, (GHFunc)rem_tag, to); - changed = TRUE; - } - g_hash_table_destroy(left); - - return changed; -} - -/** - * camel_tag_list_free: - * @list: - * - * Free the tag list @list. - **/ -void camel_tag_list_free(CamelTag **list) -{ - CamelTag *tag, *tmp; - tag = *list; - while (tag) { - tmp = tag->next; - g_free(tag->value); - g_free(tag); - tag = tmp; - } - *list = NULL; -} - -struct flag_names_t { - char *name; - guint32 value; -} flag_names[] = { - { "answered", CAMEL_MESSAGE_ANSWERED }, - { "deleted", CAMEL_MESSAGE_DELETED }, - { "draft", CAMEL_MESSAGE_DELETED }, - { "flagged", CAMEL_MESSAGE_FLAGGED }, - { "seen", CAMEL_MESSAGE_SEEN }, - { "attachments", CAMEL_MESSAGE_ATTACHMENTS }, - { NULL, 0 } -}; - -/** - * camel_system_flag: - * @name: - * - * Returns the integer value of the flag string. - **/ -guint32 -camel_system_flag (const char *name) -{ - struct flag_names_t *flag; - - g_return_val_if_fail (name != NULL, 0); - - for (flag = flag_names; *flag->name; flag++) - if (!g_strcasecmp (name, flag->name)) - return flag->value; - - return 0; -} - -/** - * camel_system_flag_get: - * @flags: - * @name: - * - * Find the state of the flag @name in @flags. - * - * Return value: The state of the flag (TRUE or FALSE). - **/ -gboolean -camel_system_flag_get (guint32 flags, const char *name) -{ - g_return_val_if_fail (name != NULL, FALSE); - - return flags & camel_system_flag (name); -} - - -/** - * camel_message_info_new: - * - * Returns a new CamelMessageInfo structure. - **/ -CamelMessageInfo * -camel_message_info_new (void) -{ - CamelMessageInfo *info; - - info = g_malloc0(sizeof(*info)); -#ifdef DOEPOOLV - info->strings = e_poolv_new(CAMEL_MESSAGE_INFO_LAST); -#endif -#ifdef DOESTRV - info->strings = e_strv_new (CAMEL_MESSAGE_INFO_LAST); -#endif - info->refcount = 1; - - return info; -} - -/** - * camel_message_info_ref: - * @info: - * - * Reference an info. - * - * NOTE: This interface is not MT-SAFE, like the others. - **/ -void camel_message_info_ref(CamelMessageInfo *info) -{ - GLOBAL_INFO_LOCK(info); - info->refcount++; - GLOBAL_INFO_UNLOCK(info); -} - -/** - * camel_message_info_new_from_header: - * @header: raw header - * - * Returns a new CamelMessageInfo structure populated by the header. - **/ -CamelMessageInfo * -camel_message_info_new_from_header (struct _header_raw *header) -{ - CamelMessageInfo *info; - char *subject, *from, *to, *cc, *mlist; - struct _header_content_type *ct = NULL; - const char *content, *charset = NULL; - - if ((content = header_raw_find(&header, "Content-Type", NULL)) - && (ct = header_content_type_decode(content)) - && (charset = header_content_type_param(ct, "charset")) - && (strcasecmp(charset, "us-ascii") == 0)) - charset = NULL; - - charset = e_iconv_charset_name(charset); - - subject = summary_format_string(header, "subject", charset); - from = summary_format_address(header, "from"); - to = summary_format_address(header, "to"); - cc = summary_format_address(header, "cc"); - mlist = header_raw_check_mailing_list(&header); - - if (ct) - header_content_type_unref(ct); - - info = camel_message_info_new(); - - camel_message_info_set_subject(info, subject); - camel_message_info_set_from(info, from); - camel_message_info_set_to(info, to); - camel_message_info_set_cc(info, cc); - camel_message_info_set_mlist(info, mlist); - - return info; -} - -/** - * camel_message_info_dup_to: - * @from: source message info - * @to: destination message info - * - * Duplicates the contents of one CamelMessageInfo structure into another. - * (The destination is assumed to be empty: its contents are not freed.) - * The slightly odd interface is to allow this to be used to initialize - * "subclasses" of CamelMessageInfo. - **/ -void -camel_message_info_dup_to(const CamelMessageInfo *from, CamelMessageInfo *to) -{ - CamelFlag *flag; - CamelTag *tag; - - /* Copy numbers */ - to->flags = from->flags; - to->size = from->size; - to->date_sent = from->date_sent; - to->date_received = from->date_received; - to->refcount = 1; - - /* Copy strings */ -#ifdef DOEPOOLV - to->strings = e_poolv_cpy (to->strings, from->strings); -#elif defined (DOESTRV) - /* to->strings = e_strv_new(CAMEL_MESSAGE_INFO_LAST); */ - e_strv_set(to->strings, CAMEL_MESSAGE_INFO_SUBJECT, camel_message_info_subject(from)); - e_strv_set(to->strings, CAMEL_MESSAGE_INFO_FROM, camel_message_info_from(from)); - e_strv_set(to->strings, CAMEL_MESSAGE_INFO_TO, camel_message_info_to(from)); - e_strv_set(to->strings, CAMEL_MESSAGE_INFO_CC, camel_message_info_cc(from)); - e_strv_set(to->strings, CAMEL_MESSAGE_INFO_UID, camel_message_info_uid(from)); - e_strv_set(to->strings, CAMEL_MESSAGE_INFO_UID, camel_message_info_mlist(from)); -#else - to->subject = g_strdup(from->subject); - to->from = g_strdup(from->from); - to->to = g_strdup(from->to); - to->cc = g_strdup(from->cc); - to->uid = g_strdup(from->uid); - to->mlist = g_strdup(from->mlist); -#endif - memcpy(&to->message_id, &from->message_id, sizeof(from->message_id)); - - /* Copy structures */ - if (from->references) { - int len = sizeof(*from->references) + ((from->references->size-1) * sizeof(from->references->references[0])); - - to->references = g_malloc(len); - memcpy(to->references, from->references, len); - } else { - to->references = NULL; - } - - flag = from->user_flags; - while (flag) { - camel_flag_set(&to->user_flags, flag->name, TRUE); - flag = flag->next; - } - - tag = from->user_tags; - while (tag) { - camel_tag_set(&to->user_tags, tag->name, tag->value); - tag = tag->next; - } - - /* No, this is impossible without knowing the class of summary we came from */ - /* FIXME some day */ - to->content = NULL; -} - -/** - * camel_message_info_free: - * @mi: the message info - * - * Unref's and potentially frees a CamelMessageInfo and its contents. - * - * Can only be used to free CamelMessageInfo's created with - * camel_message_info_dup_to. - * - * NOTE: This interface is not MT-SAFE, like the others. - * - **/ -void -camel_message_info_free(CamelMessageInfo *mi) -{ - g_return_if_fail(mi != NULL); - - GLOBAL_INFO_LOCK(info); - mi->refcount--; - if (mi->refcount > 0) { - GLOBAL_INFO_UNLOCK(info); - return; - } - GLOBAL_INFO_UNLOCK(info); - -#ifdef DOEPOOLV - e_poolv_destroy(mi->strings); -#elif defined (DOESTRV) - e_strv_destroy(mi->strings); -#else - g_free(mi->uid); - g_free(mi->subject); - g_free(mi->from); - g_free(mi->to); - g_free(mi->cc); - g_free(mi->mlist); -#endif - g_free(mi->references); - camel_flag_list_free(&mi->user_flags); - camel_tag_list_free(&mi->user_tags); - /* FIXME: content info? */ - g_free(mi); -} - -#if defined (DOEPOOLV) || defined (DOESTRV) -const char * -camel_message_info_string (const CamelMessageInfo *mi, int type) -{ - g_assert (mi != NULL); - - if (mi->strings == NULL) - return ""; -#ifdef DOEPOOLV - return e_poolv_get (mi->strings, type); -#else - return e_strv_get (mi->strings, type); -#endif -} - -void -camel_message_info_set_string (CamelMessageInfo *mi, int type, char *str) -{ - g_assert (mi != NULL); - g_assert (mi->strings != NULL); -#ifdef DOEPOOLV - e_poolv_set (mi->strings, type, str, TRUE); -#else - mi->strings = e_strv_set_ref_free (mi->strings, type, str); -#endif -} -#endif - -#if 0 -static void -content_info_dump(CamelMessageContentInfo *ci, int depth) -{ - char *p; - - p = alloca(depth*4+1); - memset(p, ' ', depth*4); - p[depth*4] = 0; - - if (ci == NULL) { - printf("%s<empty>\n", p); - return; - } - - printf("%scontent-type: %s/%s\n", p, ci->type->type, ci->type->subtype); - printf("%scontent-transfer-encoding: %s\n", p, ci->encoding); - printf("%scontent-description: %s\n", p, ci->description); - printf("%ssize: %lu\n", p, (unsigned long)ci->size); - ci = ci->childs; - while (ci) { - content_info_dump(ci, depth+1); - ci = ci->next; - } -} - -void -message_info_dump(CamelMessageInfo *mi) -{ - if (mi == NULL) { - printf("No message?\n"); - return; - } - - printf("Subject: %s\n", camel_message_info_subject(mi)); - printf("To: %s\n", camel_message_info_to(mi)); - printf("Cc: %s\n", camel_message_info_cc(mi)); - printf("mailing list: %s\n", camel_message_info_mlist(mi)); - printf("From: %s\n", camel_message_info_from(mi)); - printf("UID: %s\n", camel_message_info_uid(mi)); - printf("Flags: %04x\n", mi->flags & 0xffff); - content_info_dump(mi->content, 0); -} - -int main(int argc, char **argv) -{ - CamelMimeParser *mp; - int fd; - CamelFolderSummary *s; - char *buffer; - int len; - int i; - ibex *index; - - /*g_tk_init(&argc, &argv);*/ - -#if 0 - { - int i; - char *s; - char buf[1024]; - - for (i=0;i<434712;i++) { - memcpy(buf, " ", 50); - buf[50] = 0; -#if 0 - s = g_strdup(buf); - g_free(s); -#endif - } - return 0; - } -#endif - - if (argc < 2 ) { - printf("usage: %s mbox\n", argv[0]); - return 1; - } - - fd = open(argv[1], O_RDONLY); - - index = ibex_open("index.ibex", O_CREAT|O_RDWR, 0600); - - mp = camel_mime_parser_new(); - camel_mime_parser_scan_from(mp, TRUE); -/* camel_mime_parser_set_header_regex(mp, "^(content-[^:]*|subject|from|to|date):");*/ - camel_mime_parser_init_with_fd(mp, fd); - - s = camel_folder_summary_new(); - camel_folder_summary_set_build_content(s, TRUE); -/* camel_folder_summary_set_index(s, index);*/ - - while (camel_mime_parser_step(mp, &buffer, &len) == HSCAN_FROM) { - /*printf("Parsing message ...\n");*/ - camel_folder_summary_add_from_parser(s, mp); - if (camel_mime_parser_step(mp, &buffer, &len) != HSCAN_FROM_END) { - g_warning("Uknown state encountered, excpecting %d, got %d\n", HSCAN_FROM_END, camel_mime_parser_state(mp)); - break; - } - } - - printf("Printing summary\n"); - for (i=0;i<camel_folder_summary_count(s);i++) { - CamelMessageInfo *info = camel_folder_summary_index(s, i); - message_info_dump(info); - camel_folder_summary_info_free(info); - } - - printf("Saivng summary\n"); - camel_folder_summary_set_filename(s, "index.summary"); - camel_folder_summary_save(s); - - { - CamelFolderSummary *n; - - printf("\nLoading summary\n"); - n = camel_folder_summary_new(); - camel_folder_summary_set_build_content(n, TRUE); - camel_folder_summary_set_filename(n, "index.summary"); - camel_folder_summary_load(n); - - printf("Printing summary\n"); - for (i=0;i<camel_folder_summary_count(n);i++) { - CamelMessageInfo *info = camel_folder_summary_index(s, i); - message_info_dump(info); - camel_folder_summary_info_free(info); - } - camel_object_unref(n); - } - - - camel_object_unref(mp); - camel_object_unref(s); - - printf("summarised %d messages\n", camel_folder_summary_count(s)); -#if 0 - printf("g_strdup count = %d\n", strdup_count); - printf("g_malloc count = %d\n", malloc_count); - printf("g_free count = %d\n", free_count); -#endif - return 0; -} - -#endif |