Skip to content

Commit

Permalink
Optimize parsing of messages with lots of address headers
Browse files Browse the repository at this point in the history
Fixes issue #126
  • Loading branch information
jstedfast committed Aug 17, 2022
1 parent d0d4d6c commit 4a80ae5
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 13 deletions.
9 changes: 5 additions & 4 deletions gmime/gmime-header.c
Expand Up @@ -1151,6 +1151,7 @@ g_mime_header_list_prepend (GMimeHeaderList *headers, const char *name, const ch
g_hash_table_replace (headers->hash, header->name, header);

if (headers->array->len > 0) {
args.action = GMIME_HEADER_LIST_CHANGED_ACTION_INSERTED;
g_ptr_array_set_size (headers->array, headers->array->len + 1);

dest = ((unsigned char *) headers->array->pdata) + sizeof (void *);
Expand All @@ -1160,10 +1161,10 @@ g_mime_header_list_prepend (GMimeHeaderList *headers, const char *name, const ch
memmove (dest, src, (sizeof (void *) * n));
headers->array->pdata[0] = header;
} else {
args.action = GMIME_HEADER_LIST_CHANGED_ACTION_ADDED;
g_ptr_array_add (headers->array, header);
}

args.action = GMIME_HEADER_LIST_CHANGED_ACTION_ADDED;
args.header = header;

g_mime_event_emit (headers->changed, &args);
Expand Down Expand Up @@ -1388,6 +1389,9 @@ g_mime_header_list_remove (GMimeHeaderList *headers, const char *name)
g_mime_event_remove (header->changed, (GMimeEventCallback) header_changed, headers);
g_ptr_array_remove_index (headers->array, i);
g_hash_table_remove (headers->hash, name);

args.action = GMIME_HEADER_LIST_CHANGED_ACTION_REMOVED;
args.header = header;

/* look for another header with the same name... */
while (i < headers->array->len) {
Expand All @@ -1402,9 +1406,6 @@ g_mime_header_list_remove (GMimeHeaderList *headers, const char *name)
i++;
}

args.action = GMIME_HEADER_LIST_CHANGED_ACTION_REMOVED;
args.header = header;

g_mime_event_emit (headers->changed, &args);
g_object_unref (header);

Expand Down
1 change: 1 addition & 0 deletions gmime/gmime-internal.h
Expand Up @@ -32,6 +32,7 @@ G_BEGIN_DECLS

typedef enum {
GMIME_HEADER_LIST_CHANGED_ACTION_ADDED,
GMIME_HEADER_LIST_CHANGED_ACTION_INSERTED,
GMIME_HEADER_LIST_CHANGED_ACTION_CHANGED,
GMIME_HEADER_LIST_CHANGED_ACTION_REMOVED,
GMIME_HEADER_LIST_CHANGED_ACTION_CLEARED
Expand Down
67 changes: 58 additions & 9 deletions gmime/gmime-message.c
Expand Up @@ -259,6 +259,24 @@ static const char *message_headers[] = {
"MIME-Version"
};

static void
message_add_addresses (GMimeMessage *message, GMimeParserOptions *options, GMimeHeader *header, GMimeAddressType type)
{
InternetAddressList *addrlist;
const char *value;

block_changed_event (message, type);

addrlist = message->addrlists[type];

internet_address_list_clear (addrlist);

if ((value = g_mime_header_get_raw_value (header)))
_internet_address_list_append_parse (addrlist, options, value, header->offset);

unblock_changed_event (message, type);
}

static void
message_update_addresses (GMimeMessage *message, GMimeParserOptions *options, GMimeAddressType type)
{
Expand Down Expand Up @@ -289,8 +307,21 @@ message_update_addresses (GMimeMessage *message, GMimeParserOptions *options, GM
unblock_changed_event (message, type);
}

static gboolean
header_was_appended (GMimeObject *object, GMimeHeaderListChangedAction action, GMimeHeader *header)
{
// Note: This is a hack until we can have a message_header_inserted() API.
if (action == GMIME_HEADER_LIST_CHANGED_ACTION_ADDED) {
int count = g_mime_header_list_get_count (object->headers);
GMimeHeader *last = g_mime_header_list_get_header_at (object->headers, count - 1);
return header == last;
}

return FALSE;
}

static void
process_header (GMimeObject *object, GMimeHeader *header)
process_header (GMimeObject *object, GMimeHeaderListChangedAction action, GMimeHeader *header)
{
GMimeParserOptions *options = _g_mime_header_list_get_options (object->headers);
GMimeMessage *message = (GMimeMessage *) object;
Expand All @@ -306,22 +337,40 @@ process_header (GMimeObject *object, GMimeHeader *header)

switch (i) {
case HEADER_SENDER:
message_update_addresses (message, options, GMIME_ADDRESS_TYPE_SENDER);
if (header_was_appended (object, action, header))
message_add_addresses (message, options, header, GMIME_ADDRESS_TYPE_SENDER);
else
message_update_addresses (message, options, GMIME_ADDRESS_TYPE_SENDER);
break;
case HEADER_FROM:
message_update_addresses (message, options, GMIME_ADDRESS_TYPE_FROM);
if (header_was_appended (object, action, header))
message_add_addresses (message, options, header, GMIME_ADDRESS_TYPE_FROM);
else
message_update_addresses (message, options, GMIME_ADDRESS_TYPE_FROM);
break;
case HEADER_REPLY_TO:
message_update_addresses (message, options, GMIME_ADDRESS_TYPE_REPLY_TO);
if (header_was_appended (object, action, header))
message_add_addresses (message, options, header, GMIME_ADDRESS_TYPE_REPLY_TO);
else
message_update_addresses (message, options, GMIME_ADDRESS_TYPE_REPLY_TO);
break;
case HEADER_TO:
message_update_addresses (message, options, GMIME_ADDRESS_TYPE_TO);
if (header_was_appended (object, action, header))
message_add_addresses (message, options, header, GMIME_ADDRESS_TYPE_TO);
else
message_update_addresses (message, options, GMIME_ADDRESS_TYPE_TO);
break;
case HEADER_CC:
message_update_addresses (message, options, GMIME_ADDRESS_TYPE_CC);
if (header_was_appended (object, action, header))
message_add_addresses (message, options, header, GMIME_ADDRESS_TYPE_CC);
else
message_update_addresses (message, options, GMIME_ADDRESS_TYPE_CC);
break;
case HEADER_BCC:
message_update_addresses (message, options, GMIME_ADDRESS_TYPE_BCC);
if (header_was_appended (object, action, header))
message_add_addresses (message, options, header, GMIME_ADDRESS_TYPE_BCC);
else
message_update_addresses (message, options, GMIME_ADDRESS_TYPE_BCC);
break;
case HEADER_SUBJECT:
g_free (message->subject);
Expand Down Expand Up @@ -353,15 +402,15 @@ process_header (GMimeObject *object, GMimeHeader *header)
static void
message_header_added (GMimeObject *object, GMimeHeader *header)
{
process_header (object, header);
process_header (object, GMIME_HEADER_LIST_CHANGED_ACTION_ADDED, header);

GMIME_OBJECT_CLASS (parent_class)->header_added (object, header);
}

static void
message_header_changed (GMimeObject *object, GMimeHeader *header)
{
process_header (object, header);
process_header (object, GMIME_HEADER_LIST_CHANGED_ACTION_CHANGED, header);

GMIME_OBJECT_CLASS (parent_class)->header_changed (object, header);
}
Expand Down
2 changes: 2 additions & 0 deletions gmime/gmime-object.c
Expand Up @@ -291,8 +291,10 @@ object_headers_cleared (GMimeObject *object)
static void
header_list_changed (GMimeHeaderList *headers, GMimeHeaderListChangedEventArgs *args, GMimeObject *object)
{
// FIXME: add a header_inserted() API so that header_added() can be better optimized. See gmime-message.c:message_header_added()/process_header().
switch (args->action) {
case GMIME_HEADER_LIST_CHANGED_ACTION_ADDED:
case GMIME_HEADER_LIST_CHANGED_ACTION_INSERTED:
GMIME_OBJECT_GET_CLASS (object)->header_added (object, args->header);
break;
case GMIME_HEADER_LIST_CHANGED_ACTION_CHANGED:
Expand Down

0 comments on commit 4a80ae5

Please sign in to comment.