diff options
-rw-r--r-- | camel/ChangeLog | 106 | ||||
-rw-r--r-- | camel/camel-folder.c | 334 | ||||
-rw-r--r-- | camel/camel-folder.h | 33 | ||||
-rw-r--r-- | camel/camel-mime-parser.c | 9 | ||||
-rw-r--r-- | camel/camel-mime-utils.c | 62 | ||||
-rw-r--r-- | camel/providers/mbox/camel-mbox-folder.c | 25 | ||||
-rw-r--r-- | camel/providers/mbox/camel-mbox-folder.h | 1 | ||||
-rw-r--r-- | camel/providers/mbox/camel-mbox-summary.c | 33 | ||||
-rw-r--r-- | camel/providers/mbox/camel-mbox-summary.h | 5 | ||||
-rw-r--r-- | camel/providers/mh/camel-mh-folder.c | 22 | ||||
-rw-r--r-- | camel/providers/mh/camel-mh-folder.h | 1 | ||||
-rw-r--r-- | camel/providers/mh/camel-mh-summary.c | 5 | ||||
-rw-r--r-- | camel/providers/mh/camel-mh-summary.h | 3 |
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 */ |