aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--camel/ChangeLog106
-rw-r--r--camel/camel-folder.c334
-rw-r--r--camel/camel-folder.h33
-rw-r--r--camel/camel-mime-parser.c9
-rw-r--r--camel/camel-mime-utils.c62
-rw-r--r--camel/providers/mbox/camel-mbox-folder.c25
-rw-r--r--camel/providers/mbox/camel-mbox-folder.h1
-rw-r--r--camel/providers/mbox/camel-mbox-summary.c33
-rw-r--r--camel/providers/mbox/camel-mbox-summary.h5
-rw-r--r--camel/providers/mh/camel-mh-folder.c22
-rw-r--r--camel/providers/mh/camel-mh-folder.h1
-rw-r--r--camel/providers/mh/camel-mh-summary.c5
-rw-r--r--camel/providers/mh/camel-mh-summary.h3
13 files changed, 532 insertions, 107 deletions
diff --git a/camel/ChangeLog b/camel/ChangeLog
index 6e02a11ca6..bed9e12de9 100644
--- a/camel/ChangeLog
+++ b/camel/ChangeLog
@@ -1,3 +1,7 @@
+2000-11-02 Not Zed <NotZed@HelixCode.com>
+
+ * Merged in camel-incremental-branch.
+
2000-11-01 Dan Winship <danw@helixcode.com>
* providers/imap/camel-imap-store.c (get_folder_info): Remove old
@@ -270,6 +274,108 @@
fix this time - the description should be encoded here and not in
the camel-medium layer.
+2000-10-30 Not Zed <NotZed@HelixCode.com>
+
+ * camel-folder.c (camel_folder_change_info_add_update): Fixed the
+ changeset logic, which was completely wrong.
+
+2000-10-27 Not Zed <NotZed@HelixCode.com>
+
+ * camel-mime-utils.c (quoted_encode_step): Removed is_blank() stuff.
+ (header_decode_init): When we set the 'space' bit, dont clear all
+ the others.
+ (quoted_encode): Put back the safemask. Yes we totally need it,
+ see rfc 2047 section 5, parts (1) and (3).
+ (CHARS_PSPECIAL): Remove '=' and '_' from the list of allowed
+ characters (this is an allowed list, not a not-allowed list, like
+ the ESPECIAL).
+ (camel_mime_special_table): Updated for fixes to definitions.
+ (CHARS_ESPECIAL): Added '_' to list of characters that should be
+ encoded.
+
+2000-10-26 Not Zed <NotZed@HelixCode.com>
+
+ * providers/mbox/camel-mbox-summary.c (camel_mbox_summary_update):
+ Use the new camel_folder_change_info_* stuff to build the update
+ diff, rather than doing it ourselves.
+
+ * camel-folder.c (camel_folder_change_info_add_source): Add a
+ 'source' list, used to create change lists.
+ (camel_folder_change_info_add_source_list): Add a list of uid's,
+ convenience function.
+ (camel_folder_change_info_add_update): Add a uid to the list of
+ uid's in the new updated list.
+ (camel_folder_change_info_add_update_list): Add a bunch of uid's
+ at once for the same purpose.
+ (camel_folder_change_info_build_diff): Take the source list, the
+ update list, and find the differences, building on the added or
+ removed list as appropriate.
+
+2000-10-20 Not Zed <NotZed@HelixCode.com>
+
+ * providers/mbox/camel-mbox-summary.c (removed_uids): REnamed from
+ add_uid.
+ (camel_mbox_summary_update): Oops, fix the reversed logic for
+ determining the uid changesets.
+
+ * camel-folder.c (message_changed): Oops, we want to change the
+ uid, not add it.
+
+2000-10-19 Not Zed <NotZed@HelixCode.com>
+
+ * providers/mh/camel-mh-summary.c (camel_mh_summary_sync): Added a
+ change list argument, and add expunged uid's to it.
+
+ * providers/mh/camel-mh-folder.c (mh_init): Setup the change list.
+ (mh_finalize): And free it.
+ (mh_sync): Track changes, and send a folder_changed signal as
+ appropriate.
+ (mh_expunge): Likewise.
+ (mh_append_message): Add the new uid to the change list and
+ trigger a folder_changed event.
+
+ * providers/mbox/camel-mbox-folder.c (camel_mbox_folder_new):
+ Setup a mbox list of changes structure.
+ (mbox_finalize): And free it.
+ (mbox_expunge): Include the change list with the folder_changed
+ event, and clear it off.
+ (mbox_sync): And the same for when we are just syncing the folder.
+ (mbox_append_message): And do the same here, after we've updated
+ the folder.
+
+ * providers/mbox/camel-mbox-summary.c
+ (camel_mbox_summary_build_from): Use gmtime_r to get the time
+ thread-safely.
+ (camel_mbox_summary_sync): Added a changeinfo argument. Add any
+ removed or changed messages to the changelists as appropriate.
+ (camel_mbox_summary_update): Added a changeinfo argument.
+ Genereate a list of added/removed uid's based on the difference
+ before and after rebuilding the summary.
+
+ * camel-folder.c (camel_folder_change_info_new):
+ (camel_folder_change_info_add_uid):
+ (change_info_add_uid):
+ (camel_folder_change_info_remove_uid):
+ (camel_folder_change_info_change_uid):
+ (change_info_clear):
+ (camel_folder_change_info_clear):
+ (camel_folder_change_info_free):
+ (change_info_cat):
+ (camel_folder_change_info_cat): Bunch of utility functions for
+ working with change info lists.
+ (camel_folder_init): Init the change info list.
+ (camel_folder_finalize): And free it.
+ (thaw): Changed to pass through a list of changes, or to get the
+ changed message uids from the camelfolderchangeinfo struct, and
+ reset it.
+ (folder_changed): Add the changed lists to the frozen change list
+ if we are frozen.
+ (message_changed): Add the message to the changed list if we are
+ in the frozen state.
+
+ * camel-folder.h (CamelFolderChangeInfo): New structure to hold
+ information for the folder_changed event.
+
2000-10-18 Ettore Perazzoli <ettore@helixcode.com>
* camel-mime-filter-charset.c (complete): Put a zero at the start
diff --git a/camel/camel-folder.c b/camel/camel-folder.c
index 792d3c5d01..1d929fb4f0 100644
--- a/camel/camel-folder.c
+++ b/camel/camel-folder.c
@@ -157,15 +157,13 @@ camel_folder_init (gpointer object, gpointer klass)
CamelFolder *folder = object;
folder->frozen = 0;
- folder->folder_changed = FALSE;
- folder->messages_changed = NULL;
+ folder->changed_frozen = camel_folder_change_info_new();
}
static void
camel_folder_finalize (CamelObject *object)
{
CamelFolder *camel_folder = CAMEL_FOLDER (object);
- GList *m;
g_free (camel_folder->name);
g_free (camel_folder->full_name);
@@ -173,9 +171,7 @@ camel_folder_finalize (CamelObject *object)
if (camel_folder->parent_store)
camel_object_unref (CAMEL_OBJECT (camel_folder->parent_store));
- for (m = camel_folder->messages_changed; m; m = m->next)
- g_free (m->data);
- g_list_free (camel_folder->messages_changed);
+ camel_folder_change_info_free(camel_folder->changed_frozen);
}
CamelType
@@ -979,45 +975,26 @@ camel_folder_freeze (CamelFolder * folder)
static void
thaw (CamelFolder * folder)
{
- GList *messages, *m;
+ int i;
+ CamelFolderChangeInfo *info;
folder->frozen--;
if (folder->frozen != 0)
return;
- /* Clear messages_changed now in case the signal handler ends
- * up calling freeze and thaw itself.
- */
- messages = folder->messages_changed;
- folder->messages_changed = NULL;
-
- /* If the folder changed, emit that and ignore the individual
- * messages (since the UIDs may no longer be valid).
- */
- if (folder->folder_changed) {
- folder->folder_changed = FALSE;
-
- camel_object_trigger_event (CAMEL_OBJECT (folder),
- "folder_changed", NULL);
- } else if (messages) {
- /* FIXME: would be nice to not emit more than once for
- * a given message
- */
- for (m = messages; m; m = m->next) {
- camel_object_trigger_event (CAMEL_OBJECT (folder),
- "message_changed",
- m->data);
- g_free (m->data);
+ /* If we have more or less messages, do a folder changed, otherwise just
+ do a message changed for each one.
+ TODO: message_changed is now probably irrelevant and not required */
+ info = folder->changed_frozen;
+ if (info->uid_added->len > 0 || info->uid_removed->len > 0) {
+ camel_object_trigger_event(CAMEL_OBJECT(folder), "folder_changed", info);
+ } else if (info->uid_changed->len > 0) {
+ for (i=0;i<info->uid_changed->len;i++) {
+ camel_object_trigger_event(CAMEL_OBJECT(folder), "message_changed", info->uid_changed->pdata[i]);
}
- g_list_free (messages);
- return;
}
- if (messages) {
- for (m = messages; m; m = m->next)
- g_free (m->data);
- g_list_free (messages);
- }
+ camel_folder_change_info_clear(info);
}
/**
@@ -1042,12 +1019,16 @@ static gboolean
folder_changed (CamelObject *obj, gpointer event_data)
{
CamelFolder *folder = CAMEL_FOLDER (obj);
+ CamelFolderChangeInfo *changed = event_data;
if (folder->frozen) {
- folder->folder_changed = TRUE;
+ if (changed != NULL)
+ camel_folder_change_info_cat(folder->changed_frozen, changed);
+ else
+ g_warning("Class %s is passing NULL to folder_changed event",
+ camel_type_to_name (CAMEL_OBJECT_GET_TYPE (folder)));
return FALSE;
}
-
return TRUE;
}
@@ -1057,17 +1038,7 @@ message_changed (CamelObject *obj, /*const char *uid*/gpointer event_data)
CamelFolder *folder = CAMEL_FOLDER (obj);
if (folder->frozen) {
- /* FIXME: if there are no hooks attached, we can just
- * return here.
- */
-
- /* Only record the UID if it will be useful later. */
- if (!folder->folder_changed) {
- folder->messages_changed =
- g_list_prepend (folder->messages_changed,
- g_strdup ((gchar *)event_data));
- }
-
+ camel_folder_change_info_change_uid(folder->changed_frozen, (char *)event_data);
return FALSE;
}
@@ -1124,3 +1095,266 @@ camel_folder_free_deep (CamelFolder *folder, GPtrArray *array)
g_free (array->pdata[i]);
g_ptr_array_free (array, TRUE);
}
+
+/**
+ * camel_folder_change_info_new:
+ * @void:
+ *
+ * Create a new folder change info structure.
+ *
+ * Return value:
+ **/
+CamelFolderChangeInfo *
+camel_folder_change_info_new(void)
+{
+ CamelFolderChangeInfo *info;
+
+ info = g_malloc(sizeof(*info));
+ info->uid_added = g_ptr_array_new();
+ info->uid_removed = g_ptr_array_new();
+ info->uid_changed = g_ptr_array_new();
+ info->uid_source = NULL;
+
+ return info;
+}
+
+/**
+ * camel_folder_change_info_add_source:
+ * @info:
+ * @uid:
+ *
+ * Add a source uid for generating a changeset.
+ **/
+void
+camel_folder_change_info_add_source(CamelFolderChangeInfo *info, const char *uid)
+{
+ if (info->uid_source == NULL)
+ 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);
+}
+
+/**
+ * camel_folder_change_info_add_source_list:
+ * @info:
+ * @list:
+ *
+ * Add a list of source uid's for generating a changeset.
+ **/
+void
+camel_folder_change_info_add_source_list(CamelFolderChangeInfo *info, const GPtrArray *list)
+{
+ int i;
+
+ if (info->uid_source == NULL)
+ info->uid_source = g_hash_table_new(g_str_hash, g_str_equal);
+
+ for (i=0;i<list->len;i++) {
+ 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);
+ }
+}
+
+/**
+ * camel_folder_change_info_add_update:
+ * @info:
+ * @uid:
+ *
+ * Add a uid from the updated list, used to generate a changeset diff.
+ **/
+void
+camel_folder_change_info_add_update(CamelFolderChangeInfo *info, const char *uid)
+{
+ char *key;
+ int value;
+
+ if (info->uid_source == NULL) {
+ camel_folder_change_info_add_uid(info, uid);
+ 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);
+ }
+}
+
+/**
+ * camel_folder_change_info_add_update_list:
+ * @info:
+ * @list:
+ *
+ * Add a list of uid's from the updated list.
+ **/
+void
+camel_folder_change_info_add_update_list(CamelFolderChangeInfo *info, const GPtrArray *list)
+{
+ int i;
+
+ for (i=0;i<list->len;i++) {
+ camel_folder_change_info_add_update(info, list->pdata[i]);
+ }
+}
+
+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);
+}
+
+/**
+ * camel_folder_change_info_build_diff:
+ * @info:
+ *
+ * Compare the source uid set to the updated uid set and generate the differences
+ * into the added and removed lists.
+ **/
+void
+camel_folder_change_info_build_diff(CamelFolderChangeInfo *info)
+{
+ if (info->uid_source) {
+ g_hash_table_foreach(info->uid_source, (GHFunc)change_info_remove, info);
+ g_hash_table_destroy(info->uid_source);
+ info->uid_source = NULL;
+ }
+}
+
+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:
+ * @source:
+ *
+ * Concatenate one change info onto antoher. Can be used to copy
+ * them too.
+ **/
+void
+camel_folder_change_info_cat(CamelFolderChangeInfo *info, CamelFolderChangeInfo *source)
+{
+ change_info_cat(info, info->uid_added, source->uid_added);
+ change_info_cat(info, info->uid_removed, source->uid_removed);
+ change_info_cat(info, info->uid_changed, source->uid_changed);
+}
+
+/**
+ * camel_folder_change_info_add_uid:
+ * @info:
+ * @uid:
+ *
+ * Add a new uid to the changeinfo.
+ **/
+void
+camel_folder_change_info_add_uid(CamelFolderChangeInfo *info, const char *uid)
+{
+ change_info_add_uid(info, info->uid_added, uid);
+}
+
+/**
+ * camel_folder_change_info_remove_uid:
+ * @info:
+ * @uid:
+ *
+ * Add a uid to the removed uid list.
+ **/
+void
+camel_folder_change_info_remove_uid(CamelFolderChangeInfo *info, const char *uid)
+{
+ change_info_add_uid(info, info->uid_removed, uid);
+}
+
+/**
+ * camel_folder_change_info_change_uid:
+ * @info:
+ * @uid:
+ *
+ * Add a uid to the changed uid list.
+ **/
+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);
+}
+
+/**
+ * camel_folder_change_info_clear:
+ * @info:
+ *
+ * Empty out the change info; called after changes have been processed.
+ **/
+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);
+}
+
+/**
+ * camel_folder_change_info_free:
+ * @info:
+ *
+ * Free memory associated with the folder change info lists.
+ **/
+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);
+ g_hash_table_destroy(info->uid_source);
+ }
+
+ camel_folder_change_info_clear(info);
+
+ g_ptr_array_free(info->uid_added, TRUE);
+ g_ptr_array_free(info->uid_removed, TRUE);
+ g_ptr_array_free(info->uid_changed, TRUE);
+ g_free(info);
+}
+
+
+
diff --git a/camel/camel-folder.h b/camel/camel-folder.h
index 8e307cbe1b..12fe86f4b8 100644
--- a/camel/camel-folder.h
+++ b/camel/camel-folder.h
@@ -41,13 +41,22 @@ extern "C" {
#define CAMEL_FOLDER_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), CAMEL_FOLDER_TYPE, CamelFolderClass))
#define CAMEL_IS_FOLDER(o) (CAMEL_CHECK_TYPE((o), CAMEL_FOLDER_TYPE))
+typedef struct _CamelFolderChangeInfo CamelFolderChangeInfo;
+
+struct _CamelFolderChangeInfo {
+ GPtrArray *uid_added;
+ GPtrArray *uid_removed;
+ GPtrArray *uid_changed;
+
+ GHashTable *uid_source; /* used to create unique lists */
+};
+
struct _CamelFolder
{
CamelObject parent_object;
int frozen;
- gboolean folder_changed;
- GList *messages_changed;
+ CamelFolderChangeInfo *changed_frozen; /* queues changed events */
char *name;
char *full_name;
@@ -143,8 +152,6 @@ typedef struct {
void (*thaw) (CamelFolder *folder);
} CamelFolderClass;
-
-
/* Standard Camel function */
CamelType camel_folder_get_type (void);
@@ -264,6 +271,24 @@ void camel_folder_free_nop (CamelFolder *folder, GPtrArray *array);
void camel_folder_free_shallow (CamelFolder *folder, GPtrArray *array);
void camel_folder_free_deep (CamelFolder *folder, GPtrArray *array);
+/* update functions for change info */
+CamelFolderChangeInfo * camel_folder_change_info_new (void);
+void camel_folder_change_info_clear (CamelFolderChangeInfo *info);
+void camel_folder_change_info_free (CamelFolderChangeInfo *info);
+
+/* for building diff's automatically */
+void camel_folder_change_info_add_source (CamelFolderChangeInfo *info, const char *uid);
+void camel_folder_change_info_add_source_list(CamelFolderChangeInfo *info, const GPtrArray *list);
+void camel_folder_change_info_add_update (CamelFolderChangeInfo *info, const char *uid);
+void camel_folder_change_info_add_update_list(CamelFolderChangeInfo *info, const GPtrArray *list);
+void camel_folder_change_info_build_diff (CamelFolderChangeInfo *info);
+
+/* for manipulating diff's directly */
+void camel_folder_change_info_cat (CamelFolderChangeInfo *info, CamelFolderChangeInfo *s);
+void camel_folder_change_info_add_uid (CamelFolderChangeInfo *info, const char *uid);
+void camel_folder_change_info_remove_uid (CamelFolderChangeInfo *info, const char *uid);
+void camel_folder_change_info_change_uid (CamelFolderChangeInfo *info, const char *uid);
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
diff --git a/camel/camel-mime-parser.c b/camel/camel-mime-parser.c
index b1c4338760..17d24867f0 100644
--- a/camel/camel-mime-parser.c
+++ b/camel/camel-mime-parser.c
@@ -1576,12 +1576,19 @@ tail_recurse:
do {
hb = folder_scan_content (s, &state, databuffer, datalength);
- d(printf ("Content raw: '%.*s'\n", *datalength, *databuffer));
+
+ d(printf ("\n\nOriginal content: '"));
+ d(fwrite(*databuffer, sizeof(char), *datalength, stdout));
+ d(printf("'\n"));
if (*datalength > 0) {
while (f) {
camel_mime_filter_filter(f->filter, *databuffer, *datalength, presize,
databuffer, datalength, &presize);
+ d(printf ("Filtered content (%s): '",
+ camel_type_to_name(((CamelObject *)f->filter)->s.type)));
+ d(fwrite(*databuffer, sizeof(char), *datalength, stdout));
+ d(printf("'\n"));
f = f->next;
}
return;
diff --git a/camel/camel-mime-utils.c b/camel/camel-mime-utils.c
index cc5fa813dd..40a81a11f6 100644
--- a/camel/camel-mime-utils.c
+++ b/camel/camel-mime-utils.c
@@ -75,12 +75,12 @@ static unsigned char tohex[16] = {
static unsigned short camel_mime_special_table[256] = {
5, 5, 5, 5, 5, 5, 5, 5, 5,231, 7, 5, 5, 39, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 50,192, 76,192,192,192,192,192, 76, 76,192,192, 76,192, 72, 68,
- 192,192,192,192,192,192,192,192,192,192, 76, 76, 76, 4, 76, 68,
- 76,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,
- 192,192,192,192,192,192,192,192,192,192,192,108,236,108,192,192,
- 192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,
- 192,192,192,192,192,192,192,192,192,192,192,192,192,192,192, 5,
+ 242,448, 76,192,192,192,192,192, 76, 76,448,448, 76,448, 72,324,
+ 448,448,448,448,448,448,448,448,448,448, 76, 76, 76, 4, 76, 68,
+ 76,448,448,448,448,448,448,448,448,448,448,448,448,448,448,448,
+ 448,448,448,448,448,448,448,448,448,448,448,108,236,108,192, 64,
+ 192,448,448,448,448,448,448,448,448,448,448,448,448,448,448,448,
+ 448,448,448,448,448,448,448,448,448,448,448,192,192,192,192, 5,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -114,7 +114,7 @@ static unsigned char camel_mime_base64_rank[256] = {
if any of these change, then the tables above should be regenerated
by compiling this with -DBUILD_TABLE, and running.
- gcc -DCLEAN_DATE -o buildtable -I.. `glib-config --cflags --libs` -lunicode -DBUILD_TABLE camel-mime-utils.c
+ gcc -DCLEAN_DATE -o buildtable -I.. `glib-config --cflags --libs` -lunicode -DBUILD_TABLE camel-mime-utils.c camel-charset-map.c
./buildtable
*/
@@ -141,7 +141,6 @@ enum {
#define is_qpsafe(x) ((camel_mime_special_table[(unsigned char)(x)] & IS_QPSAFE) != 0)
#define is_especial(x) ((camel_mime_special_table[(unsigned char)(x)] & IS_ESPECIAL) != 0)
#define is_psafe(x) ((camel_mime_special_table[(unsigned char)(x)] & IS_PSAFE) != 0)
-#define is_blank(c) ((c) == ' ' || (c) == '\t')
/* only needs to be run to rebuild the tables above */
#ifdef BUILD_TABLE
@@ -151,8 +150,10 @@ enum {
#define CHARS_SPECIAL "()<>@,;:\\\".[]"
#define CHARS_CSPECIAL "()\\\r" /* not in comments */
#define CHARS_DSPECIAL "[]\\\r \t" /* not in domains */
-#define CHARS_ESPECIAL "()<>@,;:\"/[]?.=" /* encoded word specials */
-#define CHARS_PSPECIAL "!*+-/=_" /* encoded word specials */
+#define CHARS_ESPECIAL "()<>@,;:\"/[]?.=_" /* list of characters that must be encoded.
+ encoded word in text specials: rfc 2047 5(1)*/
+#define CHARS_PSPECIAL "!*+-/" /* list of additional characters that can be left unencoded.
+ encoded word in phrase specials: rfc 2047 5(3) */
static void
header_remove_bits(unsigned short bit, unsigned char *vals)
@@ -204,12 +205,12 @@ header_decode_init(void)
if (i<32)
camel_mime_special_table[i] |= IS_CTRL;
if ((i>=33 && i<=60) || (i>=62 && i<=126) || i==32 || i==9)
- camel_mime_special_table[i] |= IS_QPSAFE|IS_ESAFE;
+ camel_mime_special_table[i] |= (IS_QPSAFE|IS_ESAFE);
if ((i>='0' && i<='9') || (i>='a' && i<='z') || (i>='A' && i<= 'Z'))
camel_mime_special_table[i] |= IS_PSAFE;
}
- camel_mime_special_table[127] = IS_CTRL;
- camel_mime_special_table[' '] = IS_SPACE;
+ camel_mime_special_table[127] |= IS_CTRL;
+ camel_mime_special_table[' '] |= IS_SPACE;
header_init_bits(IS_LWSP, 0, 0, CHARS_LWSP);
header_init_bits(IS_TSPECIAL, IS_CTRL, 0, CHARS_TSPECIAL);
header_init_bits(IS_SPECIAL, 0, 0, CHARS_SPECIAL);
@@ -390,7 +391,7 @@ base64_encode_step(unsigned char *in, int len, gboolean break_lines, unsigned ch
/**
* base64_decode_step: decode a chunk of base64 encoded data
* @in: input stream
- * @len: max length of data to decode ( normally strlen(in) ??)
+ * @len: max length of data to decode
* @out: output stream
* @state: holds the number of bits that are stored in @save
* @save: leftover bits that have not yet been decoded
@@ -534,6 +535,7 @@ uudecode_step (unsigned char *in, int len, unsigned char *out, int *state, guint
return outptr - out;
}
+/* complete qp encoding */
int
quoted_encode_close(unsigned char *in, int len, unsigned char *out, int *state, int *save)
{
@@ -566,6 +568,7 @@ quoted_encode_close(unsigned char *in, int len, unsigned char *out, int *state,
return outptr-out;
}
+/* perform qp encoding, initialise state to -1 and save to 0 on first invocation */
int
quoted_encode_step (unsigned char *in, int len, unsigned char *out, int *statep, int *save)
{
@@ -598,7 +601,7 @@ quoted_encode_step (unsigned char *in, int len, unsigned char *out, int *statep,
last = -1;
} else {
if (last != -1) {
- if (is_qpsafe (last) || is_blank (last)) {
+ if (is_qpsafe(last)) {
*outptr++ = last;
sofar++;
} else {
@@ -609,7 +612,7 @@ quoted_encode_step (unsigned char *in, int len, unsigned char *out, int *statep,
}
}
- if (is_qpsafe (c) || is_blank (c)) {
+ if (is_qpsafe(c)) {
if (sofar > 74) {
*outptr++ = '=';
*outptr++ = '\n';
@@ -617,7 +620,7 @@ quoted_encode_step (unsigned char *in, int len, unsigned char *out, int *statep,
}
/* delay output of space char */
- if (is_blank (c)) {
+ if (c==' ' || c=='\t') {
last = c;
} else {
*outptr++ = c;
@@ -743,7 +746,7 @@ quoted_decode_step(unsigned char *in, int len, unsigned char *out, int *savestat
/*
this is for the "Q" encoding of international words,
- which is slightly different than plain quoted-printable
+ which is slightly different than plain quoted-printable (mainly by allowing 0x20 <> _)
*/
static int
quoted_decode(const unsigned char *in, int len, unsigned char *out)
@@ -792,7 +795,6 @@ quoted_decode(const unsigned char *in, int len, unsigned char *out)
/* rfc2047 version of quoted-printable */
/* safemask is the mask to apply to the camel_mime_special_table to determine what
characters can safely be included without encoding */
-/* Why do we need a 'safemask'? we always want to encode the same. */
static int
quoted_encode(const unsigned char *in, int len, unsigned char *out, unsigned short safemask)
{
@@ -805,9 +807,8 @@ quoted_encode(const unsigned char *in, int len, unsigned char *out, unsigned sho
outptr = out;
while (inptr < inend) {
c = *inptr++;
- if ((is_qpsafe (c) || c == ' ') && !(c == '_' || c == '?')) {
- /*if (camel_mime_special_table[c] & safemask) {*/
- if (c == ' ')
+ if (camel_mime_special_table[c] & safemask) {
+ if (c==' ')
c = '_';
*outptr++ = c;
} else {
@@ -3027,7 +3028,7 @@ void run_test(void)
test_phrase(buffer);
outlen = 256;
- inbuf = "Tomasz Kłoczko";
+ inbuf = "This is an encoded phrase Tomasz Kłoczko";
inlen = strlen(inbuf);
outbuf = buffer;
ic = unicode_iconv_open("UTF-8", "ISO-8859-2");
@@ -3035,6 +3036,21 @@ void run_test(void)
test_phrase(buffer);
}
+
+ {
+ char *str = "Blah blah\n\t = ? =? ?= This is a TEST For quoted-printable-encoding-encoding-of
+ long lines, and lines that end in spaces
+ and line sthat end in tabs
+ And lines that just end.";
+
+ char encoded[256];
+ int state=-1,save=0;
+ int len;
+
+ len = quoted_encode_step(str, strlen(str), encoded, &state, &save);
+ len += quoted_encode_close("", 0, encoded+len, &state, &save);
+ printf("encoded = '%.*s'\n", len, encoded);
+ }
}
#endif /* BUILD_TABLE */
diff --git a/camel/providers/mbox/camel-mbox-folder.c b/camel/providers/mbox/camel-mbox-folder.c
index b7d97ca56b..3b1f0a5030 100644
--- a/camel/providers/mbox/camel-mbox-folder.c
+++ b/camel/providers/mbox/camel-mbox-folder.c
@@ -149,6 +149,7 @@ mbox_finalize(CamelObject * object)
g_free(mbox_folder->folder_dir_path);
g_free(mbox_folder->index_file_path);
+ camel_folder_change_info_free(mbox_folder->changes);
}
CamelType camel_mbox_folder_get_type(void)
@@ -195,6 +196,8 @@ camel_mbox_folder_new(CamelStore *parent_store, const char *full_name, guint32 f
mbox_folder->folder_dir_path = g_strdup_printf("%s/%s.sdb", root_dir_path, full_name);
mbox_folder->index_file_path = g_strdup_printf("%s/%s.ibex", root_dir_path, full_name);
+ mbox_folder->changes = camel_folder_change_info_new();
+
/* if we have no index file, force it */
forceindex = stat(mbox_folder->index_file_path, &st) == -1;
if (flags & CAMEL_STORE_FOLDER_BODY_INDEX) {
@@ -232,8 +235,11 @@ mbox_sync(CamelFolder *folder, gboolean expunge, CamelException *ex)
if (expunge)
mbox_expunge(folder, ex);
- else
- camel_mbox_summary_sync(mbox_folder->summary, FALSE, ex);
+ else {
+ camel_mbox_summary_sync(mbox_folder->summary, FALSE, mbox_folder->changes, ex);
+ camel_object_trigger_event(CAMEL_OBJECT(folder), "folder_changed", mbox_folder->changes);
+ camel_folder_change_info_clear(mbox_folder->changes);
+ }
/* save index */
if (mbox_folder->index)
@@ -245,12 +251,11 @@ mbox_sync(CamelFolder *folder, gboolean expunge, CamelException *ex)
static void
mbox_expunge(CamelFolder *folder, CamelException *ex)
{
- CamelMboxFolder *mbox = CAMEL_MBOX_FOLDER(folder);
-
- camel_mbox_summary_sync(mbox->summary, TRUE, ex);
+ CamelMboxFolder *mbox_folder = CAMEL_MBOX_FOLDER(folder);
- /* TODO: check it actually changed */
- camel_object_trigger_event(CAMEL_OBJECT(folder), "folder_changed", GINT_TO_POINTER(0));
+ camel_mbox_summary_sync(mbox_folder->summary, TRUE, mbox_folder->changes, ex);
+ camel_object_trigger_event(CAMEL_OBJECT(folder), "folder_changed", mbox_folder->changes);
+ camel_folder_change_info_clear(mbox_folder->changes);
}
static gint
@@ -352,7 +357,7 @@ mbox_append_message(CamelFolder *folder, CamelMimeMessage * message, const Camel
g_free(fromline);
/* force a summary update - will only update from the new position, if it can */
- if (camel_mbox_summary_update(mbox_folder->summary, seek) == 0) {
+ if (camel_mbox_summary_update(mbox_folder->summary, seek, mbox_folder->changes) == 0) {
char uidstr[16];
sprintf(uidstr, "%u", uid);
@@ -372,7 +377,8 @@ mbox_append_message(CamelFolder *folder, CamelMimeMessage * message, const Camel
tag = tag->next;
}
}
- camel_object_trigger_event(CAMEL_OBJECT(folder), "folder_changed", GINT_TO_POINTER(0));
+ camel_object_trigger_event(CAMEL_OBJECT(folder), "folder_changed", mbox_folder->changes);
+ camel_folder_change_info_clear(mbox_folder->changes);
}
return;
@@ -469,6 +475,7 @@ mbox_get_message(CamelFolder *folder, const gchar * uid, CamelException *ex)
}
if (camel_mime_parser_tell_start_from(parser) != info->frompos) {
+ /* TODO: This should probably perform a re-sync/etc, and try again? */
g_warning("Summary doesn't match the folder contents! eek!\n"
" expecting offset %ld got %ld", (long int)info->frompos,
(long int)camel_mime_parser_tell_start_from(parser));
diff --git a/camel/providers/mbox/camel-mbox-folder.h b/camel/providers/mbox/camel-mbox-folder.h
index d6e8b0682c..73f51a6d85 100644
--- a/camel/providers/mbox/camel-mbox-folder.h
+++ b/camel/providers/mbox/camel-mbox-folder.h
@@ -56,6 +56,7 @@ typedef struct {
ibex *index; /* index for this folder */
CamelMboxSummary *summary;
CamelFolderSearch *search; /* used to run searches, we just use the real thing (tm) */
+ CamelFolderChangeInfo *changes; /* used to store changes to the folder during processing */
} CamelMboxFolder;
diff --git a/camel/providers/mbox/camel-mbox-summary.c b/camel/providers/mbox/camel-mbox-summary.c
index 93e634084a..8856d37ee8 100644
--- a/camel/providers/mbox/camel-mbox-summary.c
+++ b/camel/providers/mbox/camel-mbox-summary.c
@@ -338,13 +338,29 @@ summary_rebuild(CamelMboxSummary *mbs, off_t offset)
}
int
-camel_mbox_summary_update(CamelMboxSummary *mbs, off_t offset)
+camel_mbox_summary_update(CamelMboxSummary *mbs, off_t offset, CamelFolderChangeInfo *changeinfo)
{
- int ret;
+ int ret, i, count;
+ CamelFolderSummary *s = (CamelFolderSummary *)mbs;
+ /* we use the diff function of the change_info to build the update list. */
+ for (i = 0; i < camel_folder_summary_count(s); i++) {
+ CamelMessageInfo *mi = camel_folder_summary_index(s, i);
+
+ camel_folder_change_info_add_source(changeinfo, mi->uid);
+ }
+
+ /* do the actual work */
mbs->index_force = FALSE;
ret = summary_rebuild(mbs, offset);
+ count = camel_folder_summary_count(s);
+ for (i = 0; i < count; i++) {
+ CamelMessageInfo *mi = camel_folder_summary_index(s, i);
+ camel_folder_change_info_add_update(changeinfo, mi->uid);
+ }
+ camel_folder_change_info_build_diff(changeinfo);
+
#if 0
#warning "Saving full summary and index after every summarisation is slow ..."
if (ret != -1) {
@@ -590,7 +606,8 @@ camel_mbox_summary_build_from(struct _header_raw *header)
thetime += ((offset / 100) * (60 * 60)) + (offset % 100) * 60;
/* a pseudo, but still bogus attempt at thread safing the function */
- memcpy(&tm, gmtime(&thetime), sizeof(tm));
+ /*memcpy(&tm, gmtime(&thetime), sizeof(tm));*/
+ gmtime_r(&thetime, &tm);
g_string_sprintfa(out, " %s %s %d %02d:%02d:%02d %4d\n",
tz_days[tm.tm_wday],
@@ -602,7 +619,7 @@ camel_mbox_summary_build_from(struct _header_raw *header)
}
int
-camel_mbox_summary_sync(CamelMboxSummary *mbs, gboolean expunge, CamelException *ex)
+camel_mbox_summary_sync(CamelMboxSummary *mbs, gboolean expunge, CamelFolderChangeInfo *changeinfo, CamelException *ex)
{
CamelMimeParser *mp = NULL;
int i, count;
@@ -619,13 +636,13 @@ camel_mbox_summary_sync(CamelMboxSummary *mbs, gboolean expunge, CamelException
struct stat st;
char *fromline;
- /* make sure we're in sync */
+ /* make sure we're in sync, after this point we at least have a complete list of id's */
count = camel_folder_summary_count (s);
if (count > 0) {
CamelMessageInfo *mi = camel_folder_summary_index(s, count - 1);
- camel_mbox_summary_update(mbs, mi->content->endpos);
+ camel_mbox_summary_update(mbs, mi->content->endpos, changeinfo);
} else {
- camel_mbox_summary_update(mbs, 0);
+ camel_mbox_summary_update(mbs, 0, changeinfo);
}
/* check if we have any work to do */
@@ -693,6 +710,8 @@ camel_mbox_summary_sync(CamelMboxSummary *mbs, gboolean expunge, CamelException
offset -= (info->info.content->endpos - info->frompos);
if (mbs->index)
ibex_unindex(mbs->index, info->info.uid);
+ /* remove it from teh change list */
+ camel_folder_change_info_remove_uid(changeinfo, info->info.uid);
camel_folder_summary_remove(s, (CamelMessageInfo *)info);
count--;
i--;
diff --git a/camel/providers/mbox/camel-mbox-summary.h b/camel/providers/mbox/camel-mbox-summary.h
index 2462b72078..f90acc4f35 100644
--- a/camel/providers/mbox/camel-mbox-summary.h
+++ b/camel/providers/mbox/camel-mbox-summary.h
@@ -23,6 +23,7 @@
#define _CAMEL_MBOX_SUMMARY_H
#include <camel/camel-folder-summary.h>
+#include <camel/camel-folder.h>
#include <camel/camel-exception.h>
#include <libibex/ibex.h>
@@ -70,9 +71,9 @@ CamelMboxSummary *camel_mbox_summary_new (const char *filename, const char
/* load/check the summary */
int camel_mbox_summary_load(CamelMboxSummary *mbs, int forceindex);
/* incremental update */
-int camel_mbox_summary_update(CamelMboxSummary *mbs, off_t offset);
+int camel_mbox_summary_update(CamelMboxSummary *mbs, off_t offset, CamelFolderChangeInfo *changeinfo);
/* perform a folder sync or expunge, if needed */
-int camel_mbox_summary_sync (CamelMboxSummary *mbs, gboolean expunge, CamelException *ex);
+int camel_mbox_summary_sync (CamelMboxSummary *mbs, gboolean expunge, CamelFolderChangeInfo *changeinfo, CamelException *ex);
/* generate a From line from headers */
char *camel_mbox_summary_build_from(struct _header_raw *header);
diff --git a/camel/providers/mh/camel-mh-folder.c b/camel/providers/mh/camel-mh-folder.c
index 5b5c6688d7..a56de4a9c1 100644
--- a/camel/providers/mh/camel-mh-folder.c
+++ b/camel/providers/mh/camel-mh-folder.c
@@ -125,6 +125,7 @@ static void mh_init(gpointer object, gpointer klass)
mh_folder->summary = NULL;
mh_folder->search = NULL;
+ mh_folder->changes = camel_folder_change_info_new();
}
static void mh_finalize(CamelObject * object)
@@ -138,6 +139,7 @@ static void mh_finalize(CamelObject * object)
g_free(mh_folder->summary_file_path);
g_free(mh_folder->folder_dir_path);
g_free(mh_folder->index_file_path);
+ camel_folder_change_info_free(mh_folder->changes);
}
CamelType camel_mh_folder_get_type(void)
@@ -222,8 +224,11 @@ static void mh_sync(CamelFolder * folder, gboolean expunge, CamelException * ex)
if (expunge)
mh_expunge(folder, ex);
- else
- camel_mh_summary_sync(mh_folder->summary, FALSE, ex);
+ else {
+ camel_mh_summary_sync(mh_folder->summary, FALSE, mh_folder->changes, ex);
+ camel_object_trigger_event(CAMEL_OBJECT(folder), "folder_changed", mh_folder->changes);
+ camel_folder_change_info_clear(mh_folder->changes);
+ }
/* save index */
if (mh_folder->index)
@@ -234,12 +239,11 @@ static void mh_sync(CamelFolder * folder, gboolean expunge, CamelException * ex)
static void mh_expunge(CamelFolder * folder, CamelException * ex)
{
- CamelMhFolder *mh = CAMEL_MH_FOLDER(folder);
-
- camel_mh_summary_sync(mh->summary, TRUE, ex);
+ CamelMhFolder *mh_folder = CAMEL_MH_FOLDER(folder);
- /* TODO: check it actually changed */
- camel_object_trigger_event(CAMEL_OBJECT(folder), "folder_changed", GINT_TO_POINTER (0));
+ camel_mh_summary_sync(mh_folder->summary, TRUE, mh_folder->changes, ex);
+ camel_object_trigger_event(CAMEL_OBJECT(folder), "folder_changed", mh_folder->changes);
+ camel_folder_change_info_clear(mh_folder->changes);
}
static gint mh_get_message_count(CamelFolder * folder)
@@ -319,7 +323,9 @@ static void mh_append_message(CamelFolder * folder, CamelMimeMessage * message,
}
}
- camel_object_trigger_event(CAMEL_OBJECT(folder), "folder_changed", GPOINTER_TO_INT (0));
+ camel_folder_change_info_add_uid(mh_folder->changes, uid);
+ camel_object_trigger_event(CAMEL_OBJECT(folder), "folder_changed", mh_folder->changes);
+ camel_folder_change_info_clear(mh_folder->changes);
g_free(name);
g_free(uid);
return;
diff --git a/camel/providers/mh/camel-mh-folder.h b/camel/providers/mh/camel-mh-folder.h
index bdb1588811..ddfdf2b4aa 100644
--- a/camel/providers/mh/camel-mh-folder.h
+++ b/camel/providers/mh/camel-mh-folder.h
@@ -52,6 +52,7 @@ typedef struct {
ibex *index; /* index for this folder */
CamelMhSummary *summary;
CamelFolderSearch *search; /* used to run searches, we just use the real thing (tm) */
+ CamelFolderChangeInfo *changes; /* mass changes to the folder */
} CamelMhFolder;
typedef struct {
diff --git a/camel/providers/mh/camel-mh-summary.c b/camel/providers/mh/camel-mh-summary.c
index ce1d597012..c757a9a0a9 100644
--- a/camel/providers/mh/camel-mh-summary.c
+++ b/camel/providers/mh/camel-mh-summary.c
@@ -248,7 +248,7 @@ int camel_mh_summary_check(CamelMhSummary * mhs, int forceindex)
/* sync the summary with the ondisk files.
It doesnt store the state in the file, the summary only, == MUCH faster */
-int camel_mh_summary_sync(CamelMhSummary * mhs, int expunge, CamelException *ex)
+int camel_mh_summary_sync(CamelMhSummary * mhs, int expunge, CamelFolderChangeInfo *changes, CamelException *ex)
{
int count, i;
CamelMessageInfo *info;
@@ -267,8 +267,9 @@ int camel_mh_summary_sync(CamelMhSummary * mhs, int expunge, CamelException *ex
info = camel_folder_summary_index((CamelFolderSummary *)mhs, i);
if (info && info->flags & CAMEL_MESSAGE_DELETED) {
name = g_strdup_printf("%s/%s", mhs->mh_path, info->uid);
- (printf("deleting %s\n", name));
+ d(printf("deleting %s\n", name));
if (unlink(name) == 0 || errno==ENOENT) {
+ camel_folder_change_info_remove_uid(changes, info->uid);
camel_folder_summary_remove((CamelFolderSummary *)mhs, info);
}
}
diff --git a/camel/providers/mh/camel-mh-summary.h b/camel/providers/mh/camel-mh-summary.h
index 28376c5d9b..81aa91b418 100644
--- a/camel/providers/mh/camel-mh-summary.h
+++ b/camel/providers/mh/camel-mh-summary.h
@@ -22,6 +22,7 @@
#define _CAMEL_MH_SUMMARY_H
#include <camel/camel-folder-summary.h>
+#include <camel/camel-folder.h>
#include <camel/camel-exception.h>
#include <libibex/ibex.h>
@@ -55,7 +56,7 @@ CamelMhSummary *camel_mh_summary_new (const char *filename, const char *mhdir, i
int camel_mh_summary_load(CamelMhSummary * mhs, int forceindex);
int camel_mh_summary_check(CamelMhSummary * mhs, int forceindex);
int camel_mh_summary_add(CamelMhSummary * mhs, const char *name, int forceindex);
-int camel_mh_summary_sync(CamelMhSummary * mhs, int expunge, CamelException *ex);
+int camel_mh_summary_sync(CamelMhSummary * mhs, int expunge, CamelFolderChangeInfo *changes, CamelException *ex);
#endif /* ! _CAMEL_MH_SUMMARY_H */