From 91822b42dc7b5eb64cad2626f9fc620a2ee6a2c8 Mon Sep 17 00:00:00 2001 From: Matthew Barnes Date: Wed, 5 Dec 2012 08:19:04 -0500 Subject: Make EMailPartList thread-safe. Exposing data members in the public struct is unwise, especially when EMailPartList is used from multiple threads. Instead keep the members private and provide a set of thread-safe functions to manipulate them. --- composer/e-msg-composer.c | 24 +- em-format/e-mail-formatter-attachment.c | 48 +-- em-format/e-mail-formatter-message-rfc822.c | 97 +++--- em-format/e-mail-formatter-print-headers.c | 33 +- em-format/e-mail-formatter-print.c | 16 +- em-format/e-mail-formatter-quote-attachment.c | 16 +- em-format/e-mail-formatter-quote-message-rfc822.c | 47 ++- em-format/e-mail-formatter-quote.c | 23 +- em-format/e-mail-formatter-text-html.c | 4 +- em-format/e-mail-formatter-text-plain.c | 4 +- em-format/e-mail-formatter-utils.c | 6 +- em-format/e-mail-formatter-utils.h | 4 +- em-format/e-mail-formatter.c | 18 +- em-format/e-mail-parser.c | 66 ++-- em-format/e-mail-part-list.c | 355 ++++++++++++++++++--- em-format/e-mail-part-list.h | 40 +-- mail/e-http-request.c | 6 +- mail/e-mail-display.c | 73 +++-- mail/e-mail-printer.c | 16 +- mail/e-mail-reader-utils.c | 18 +- mail/e-mail-reader.c | 14 +- mail/e-mail-request.c | 5 +- mail/em-utils.c | 20 +- modules/itip-formatter/e-mail-formatter-itip.c | 6 +- modules/mail/e-mail-shell-backend.c | 8 +- .../e-mail-display-popup-prefer-plain.c | 15 +- .../e-mail-formatter-text-highlight.c | 4 +- .../vcard-inline/e-mail-formatter-vcard-inline.c | 4 +- 28 files changed, 665 insertions(+), 325 deletions(-) diff --git a/composer/e-msg-composer.c b/composer/e-msg-composer.c index 76cafab99f..4fa48a717b 100644 --- a/composer/e-msg-composer.c +++ b/composer/e-msg-composer.c @@ -194,6 +194,7 @@ emcu_part_to_html (CamelSession *session, GString *part_id; EShell *shell; GtkWindow *window; + GSList *list; shell = e_shell_get_default (); window = e_shell_get_active_window (shell); @@ -202,22 +203,31 @@ emcu_part_to_html (CamelSession *session, mem = (CamelStreamMem *) camel_stream_mem_new (); camel_stream_mem_set_byte_array (mem, buf); - part_list = e_mail_part_list_new (); + part_list = e_mail_part_list_new (NULL, NULL, NULL); part_id = g_string_sized_new (0); parser = e_mail_parser_new (session); - part_list->list = e_mail_parser_parse_part (parser, part, part_id, cancellable); + list = e_mail_parser_parse_part (parser, part, part_id, cancellable); + while (list != NULL) { + if (list->data != NULL) { + e_mail_part_list_add_part (part_list, list->data); + e_mail_part_unref (list->data); + } + list = g_slist_delete_link (list, list); + } g_string_free (part_id, TRUE); g_object_unref (parser); - formatter = e_mail_formatter_quote_new (NULL, E_MAIL_FORMATTER_QUOTE_FLAG_KEEP_SIG); - e_mail_formatter_set_style (formatter, - gtk_widget_get_style (GTK_WIDGET (window)), - gtk_widget_get_state (GTK_WIDGET (window))); + formatter = e_mail_formatter_quote_new ( + NULL, E_MAIL_FORMATTER_QUOTE_FLAG_KEEP_SIG); + e_mail_formatter_set_style ( + formatter, + gtk_widget_get_style (GTK_WIDGET (window)), + gtk_widget_get_state (GTK_WIDGET (window))); e_mail_formatter_format_sync ( formatter, part_list, (CamelStream *) mem, - 0, E_MAIL_FORMATTER_MODE_PRINTING, cancellable); + 0, E_MAIL_FORMATTER_MODE_PRINTING, cancellable); g_object_unref (formatter); g_object_unref (part_list); diff --git a/em-format/e-mail-formatter-attachment.c b/em-format/e-mail-formatter-attachment.c index e8660fc0b8..8d049deddc 100644 --- a/em-format/e-mail-formatter-attachment.c +++ b/em-format/e-mail-formatter-attachment.c @@ -69,26 +69,28 @@ static const gchar *formatter_mime_types[] = { "application/vnd.evolution.attach NULL }; static EAttachmentStore * -find_attachment_store (GSList *parts, +find_attachment_store (EMailPartList *part_list, const gchar *start_id) { + EAttachmentStore *store = NULL; + GQueue queue = G_QUEUE_INIT; + GList *head, *link; gchar *tmp, *pos; EMailPart *part; gchar *id; + e_mail_part_list_queue_parts (part_list, NULL, &queue); + + head = g_queue_peek_head_link (&queue); + id = g_strconcat (start_id, ".attachment-bar", NULL); tmp = g_strdup (id); part = NULL; do { - GSList *iter; - d (printf ("Looking up attachment bar as %s\n", id)); - for (iter = parts; iter; iter = iter->next) { - EMailPart *p = iter->data; - - if (!p) - continue; + for (link = head; link != NULL; link = g_list_next (link)) { + EMailPart *p = link->data; if (g_strcmp0 (p->id, id) == 0) { part = p; @@ -110,11 +112,13 @@ find_attachment_store (GSList *parts, g_free (id); g_free (tmp); - if (part) { - return ((EMailPartAttachmentBar *) part)->store; - } + if (part != NULL) + store = ((EMailPartAttachmentBar *) part)->store; - return NULL; + while (!g_queue_is_empty (&queue)) + e_mail_part_unref (g_queue_pop_head (&queue)); + + return store; } static gboolean @@ -157,7 +161,7 @@ emfe_attachment_format (EMailFormatterExtension *extension, } } - store = find_attachment_store (context->part_list->list, part->id); + store = find_attachment_store (context->part_list, part->id); if (store) { GList *attachments = e_attachment_store_get_attachments (store); if (!g_list_find (attachments, empa->attachment)) { @@ -277,17 +281,19 @@ emfe_attachment_format (EMailFormatterExtension *extension, content_stream = camel_stream_mem_new (); ok = FALSE; if (empa->attachment_view_part_id != NULL) { + EMailPart *attachment_view_part; - GSList *att_parts; - - att_parts = e_mail_part_list_get_iter ( - context->part_list->list, + attachment_view_part = e_mail_part_list_ref_part ( + context->part_list, empa->attachment_view_part_id); - if (att_parts && att_parts->data) { + if (attachment_view_part != NULL) { ok = e_mail_formatter_format_as ( - formatter, context, att_parts->data, - content_stream, NULL, cancellable); + formatter, context, + attachment_view_part, + content_stream, NULL, + cancellable); + e_mail_part_unref (attachment_view_part); } } else { @@ -353,7 +359,7 @@ emfe_attachment_get_widget (EMailFormatterExtension *extension, g_return_val_if_fail (E_MAIL_PART_IS (part, EMailPartAttachment), NULL); empa = (EMailPartAttachment *) part; - store = find_attachment_store (context->list, part->id); + store = find_attachment_store (context, part->id); widget = e_attachment_button_new (); g_object_set_data (G_OBJECT (widget), "uri", part->id); e_attachment_button_set_attachment ( diff --git a/em-format/e-mail-formatter-message-rfc822.c b/em-format/e-mail-formatter-message-rfc822.c index 78dfe3f45d..06f7e49603 100644 --- a/em-format/e-mail-formatter-message-rfc822.c +++ b/em-format/e-mail-formatter-message-rfc822.c @@ -74,7 +74,8 @@ emfe_message_rfc822_format (EMailFormatterExtension *extension, return FALSE; if (context->mode == E_MAIL_FORMATTER_MODE_RAW) { - GSList *iter; + GQueue queue = G_QUEUE_INIT; + GList *head, *link; gchar *header, *end; header = e_mail_formatter_get_html_header (formatter); @@ -84,35 +85,36 @@ emfe_message_rfc822_format (EMailFormatterExtension *extension, /* Print content of the message normally */ context->mode = E_MAIL_FORMATTER_MODE_NORMAL; - iter = e_mail_part_list_get_iter ( - context->part_list->list, part->id); + e_mail_part_list_queue_parts ( + context->part_list, part->id, &queue); + + /* Discard the first EMailPart. */ + if (!g_queue_is_empty (&queue)) + e_mail_part_unref (g_queue_pop_head (&queue)); + + head = g_queue_peek_head_link (&queue); end = g_strconcat (part->id, ".end", NULL); - for (iter = g_slist_next (iter); iter; iter = g_slist_next (iter)) { - EMailPart * p = iter->data; - if (!p) - continue; + + for (link = head; link != NULL; link = g_list_next (link)) { + EMailPart *p = link->data; /* Check for nested rfc822 messages */ if (g_str_has_suffix (p->id, ".rfc822")) { gchar *sub_end = g_strconcat (p->id, ".end", NULL); - while (iter) { - p = iter->data; - if (!p) { - iter = iter->next; - continue; - } + while (link != NULL) { + p = link->data; - if (g_strcmp0 (p->id, sub_end) == 0) { + if (g_strcmp0 (p->id, sub_end) == 0) break; - } - iter = iter->next; + link = g_list_next (link); } g_free (sub_end); continue; } + if ((g_strcmp0 (p->id, end) == 0)) break; @@ -122,35 +124,41 @@ emfe_message_rfc822_format (EMailFormatterExtension *extension, e_mail_formatter_format_as ( formatter, context, p, stream, NULL, cancellable); - } g_free (end); + while (!g_queue_is_empty (&queue)) + e_mail_part_unref (g_queue_pop_head (&queue)); + context->mode = E_MAIL_FORMATTER_MODE_RAW; camel_stream_write_string (stream, "", cancellable, NULL); } else if (context->mode == E_MAIL_FORMATTER_MODE_PRINTING) { - - GSList *iter; + GQueue queue = G_QUEUE_INIT; + GList *head, *link; gchar *end; /* Part is EMailPartAttachment */ - iter = e_mail_part_list_get_iter ( - context->part_list->list, part->id); - iter = g_slist_next (iter); + e_mail_part_list_queue_parts ( + context->part_list, part->id, &queue); + + /* Discard the first EMailPart. */ + if (!g_queue_is_empty (&queue)) + e_mail_part_unref (g_queue_pop_head (&queue)); - if (!iter || !iter->next || !iter->data) + if (g_queue_is_empty (&queue)) return FALSE; - part = iter->data; + part = g_queue_pop_head (&queue); end = g_strconcat (part->id, ".end", NULL); + e_mail_part_unref (part); - for (iter = iter->next; iter; iter = g_slist_next (iter)) { - EMailPart * p = iter->data; - if (!p) - continue; + head = g_queue_peek_head_link (&queue); + + for (link = head; link != NULL; link = g_list_next (link)) { + EMailPart *p = link->data; /* Skip attachment bar */ if (g_str_has_suffix (part->id, ".attachment-bar")) @@ -160,18 +168,13 @@ emfe_message_rfc822_format (EMailFormatterExtension *extension, if (g_str_has_suffix (p->id, ".rfc822")) { gchar *sub_end = g_strconcat (p->id, ".end", NULL); - while (iter) { - p = iter->data; - if (!p) { - iter = iter->next; - continue; - } + while (link != NULL) { + p = link->data; - if (g_strcmp0 (p->id, sub_end) == 0) { + if (g_strcmp0 (p->id, sub_end) == 0) break; - } - iter = iter->next; + link = g_list_next (link); } g_free (sub_end); continue; @@ -190,24 +193,22 @@ emfe_message_rfc822_format (EMailFormatterExtension *extension, g_free (end); + while (!g_queue_is_empty (&queue)) + e_mail_part_unref (g_queue_pop_head (&queue)); + } else { + EMailPart *p; CamelFolder *folder; const gchar *message_uid; gchar *str; gchar *uri; - EMailPart *p; - GSList *iter; - - iter = e_mail_part_list_get_iter ( - context->part_list->list, part->id); - if (!iter || !iter->next) + p = e_mail_part_list_ref_part (context->part_list, part->id); + if (p == NULL) return FALSE; - p = iter->data; - - folder = context->part_list->folder; - message_uid = context->part_list->message_uid; + folder = e_mail_part_list_get_folder (context->part_list); + message_uid = e_mail_part_list_get_message_uid (context->part_list); uri = e_mail_part_build_uri ( folder, message_uid, @@ -235,6 +236,8 @@ emfe_message_rfc822_format (EMailFormatterExtension *extension, g_free (str); g_free (uri); + + e_mail_part_unref (p); } return TRUE; diff --git a/em-format/e-mail-formatter-print-headers.c b/em-format/e-mail-formatter-print-headers.c index 8cda0e598f..03ba7b2ccd 100644 --- a/em-format/e-mail-formatter-print-headers.c +++ b/em-format/e-mail-formatter-print-headers.c @@ -74,11 +74,11 @@ emfpe_headers_format (EMailFormatterExtension *extension, GString *str, *tmp; gchar *subject; const gchar *buf; - GSList *parts_iter; - GList *iter; gint attachments_count; gchar *part_id_prefix; const GQueue *headers; + GQueue queue = G_QUEUE_INIT; + GList *head, *link; buf = camel_medium_get_header (CAMEL_MEDIUM (part->part), "subject"); subject = camel_header_decode_string (buf, "UTF-8"); @@ -92,9 +92,8 @@ emfpe_headers_format (EMailFormatterExtension *extension, "cellpadding=\"0\" class=\"printing-header\">\n"); headers = e_mail_formatter_get_headers (formatter); - for (iter = headers->head; iter; iter = iter->next) { - - EMailFormatterHeader *header = iter->data; + for (link = headers->head; link != NULL; link = g_list_next (link)) { + EMailFormatterHeader *header = link->data; raw_header.name = header->name; /* Skip 'Subject' header, it's already displayed. */ @@ -111,7 +110,7 @@ emfpe_headers_format (EMailFormatterExtension *extension, CamelMimeMessage *message; const gchar *header_value; - message = context->part_list->message; + message = e_mail_part_list_get_message (context->part_list); header_value = camel_medium_get_header ( CAMEL_MEDIUM (message), header->name); @@ -135,12 +134,14 @@ emfpe_headers_format (EMailFormatterExtension *extension, /* Add encryption/signature header */ raw_header.name = _("Security"); tmp = g_string_new (""); - /* Find first secured part. */ - for (parts_iter = context->part_list->list; parts_iter; parts_iter = parts_iter->next) { - EMailPart *mail_part = parts_iter->data; - if (mail_part == NULL) - continue; + e_mail_part_list_queue_parts (context->part_list, NULL, &queue); + + head = g_queue_peek_head_link (&queue); + + /* Find first secured part. */ + for (link = head; link != NULL; link = g_list_next (link)) { + EMailPart *mail_part = link->data; if (!mail_part->validities) continue; @@ -185,11 +186,8 @@ emfpe_headers_format (EMailFormatterExtension *extension, /* Count attachments and display the number as a header */ attachments_count = 0; - for (parts_iter = context->part_list->list; parts_iter; parts_iter = parts_iter->next) { - - EMailPart *mail_part = parts_iter->data; - if (!mail_part) - continue; + for (link = head; link != NULL; link = g_list_next (link)) { + EMailPart *mail_part = link->data; if (!g_str_has_prefix (mail_part->id, part_id_prefix)) continue; @@ -210,6 +208,9 @@ emfpe_headers_format (EMailFormatterExtension *extension, g_free (raw_header.value); } + while (!g_queue_is_empty (&queue)) + e_mail_part_unref (g_queue_pop_head (&queue)); + g_string_append (str, ""); camel_stream_write_string (stream, str->str, cancellable, NULL); diff --git a/em-format/e-mail-formatter-print.c b/em-format/e-mail-formatter-print.c index 9a57c1f6b5..62e4693cc4 100644 --- a/em-format/e-mail-formatter-print.c +++ b/em-format/e-mail-formatter-print.c @@ -99,7 +99,8 @@ mail_formatter_print_run (EMailFormatter *formatter, CamelStream *stream, GCancellable *cancellable) { - GSList *list, *link; + GQueue queue = G_QUEUE_INIT; + GList *head, *link; GSList *attachments; context->mode = E_MAIL_FORMATTER_MODE_PRINTING; @@ -116,18 +117,18 @@ mail_formatter_print_run (EMailFormatter *formatter, cancellable, NULL); attachments = NULL; - list = context->part_list->list; - for (link = list; link != NULL ; link = g_slist_next (link)) { + e_mail_part_list_queue_parts (context->part_list, NULL, &queue); + + head = g_queue_peek_head_link (&queue); + + for (link = head; link != NULL ; link = g_list_next (link)) { EMailPart *part = link->data; gboolean ok; if (g_cancellable_is_cancelled (cancellable)) break; - if (part == NULL) - continue; - if (part->is_hidden && !part->is_error) { if (g_str_has_suffix (part->id, ".rfc822")) { link = e_mail_formatter_find_rfc822_end_iter (link); @@ -161,6 +162,9 @@ mail_formatter_print_run (EMailFormatter *formatter, } } + while (!g_queue_is_empty (&queue)) + e_mail_part_unref (g_queue_pop_head (&queue)); + write_attachments_list (formatter, context, attachments, stream, cancellable); g_slist_free (attachments); diff --git a/em-format/e-mail-formatter-quote-attachment.c b/em-format/e-mail-formatter-quote-attachment.c index 5f88d97bff..822c93fc2b 100644 --- a/em-format/e-mail-formatter-quote-attachment.c +++ b/em-format/e-mail-formatter-quote-attachment.c @@ -71,21 +71,18 @@ emfqe_attachment_format (EMailFormatterExtension *extension, gchar *text, *html; guint32 text_format_flags; EMailPartAttachment *empa; - EMailPart *att_part; - GSList *iter; + EMailPart *attachment_view_part; empa = E_MAIL_PART_ATTACHMENT (part); if (!empa->attachment_view_part_id) return FALSE; - iter = e_mail_part_list_get_iter ( - context->part_list->list, empa->attachment_view_part_id); - if (!iter || !iter->data) + attachment_view_part = e_mail_part_list_ref_part ( + context->part_list, empa->attachment_view_part_id); + if (attachment_view_part == NULL) return FALSE; - att_part = iter->data; - camel_stream_write_string (stream, "

", cancellable, NULL); text_format_flags = @@ -110,7 +107,8 @@ emfqe_attachment_format (EMailFormatterExtension *extension, "
\n", cancellable, NULL); e_mail_formatter_format_as ( - formatter, context, att_part, stream, NULL, cancellable); + formatter, context, attachment_view_part, + stream, NULL, cancellable); camel_stream_write_string ( stream, @@ -118,6 +116,8 @@ emfqe_attachment_format (EMailFormatterExtension *extension, "-->", cancellable, NULL); + e_mail_part_unref (attachment_view_part); + return TRUE; } diff --git a/em-format/e-mail-formatter-quote-message-rfc822.c b/em-format/e-mail-formatter-quote-message-rfc822.c index 037b5b4b71..2bb8de9eb2 100644 --- a/em-format/e-mail-formatter-quote-message-rfc822.c +++ b/em-format/e-mail-formatter-quote-message-rfc822.c @@ -70,7 +70,8 @@ emfqe_message_rfc822_format (EMailFormatterExtension *extension, CamelStream *stream, GCancellable *cancellable) { - GSList *iter; + GQueue queue = G_QUEUE_INIT; + GList *head, *link; gchar *header, *end; EMailFormatterQuoteContext *qc = (EMailFormatterQuoteContext *) context; @@ -81,16 +82,20 @@ emfqe_message_rfc822_format (EMailFormatterExtension *extension, camel_stream_write_string (stream, header, cancellable, NULL); g_free (header); - iter = e_mail_part_list_get_iter (context->part_list->list, part->id); - if (!iter) { + e_mail_part_list_queue_parts (context->part_list, part->id, &queue); + + if (g_queue_is_empty (&queue)) return FALSE; - } + + /* Discard the first EMailPart. */ + e_mail_part_unref (g_queue_pop_head (&queue)); + + head = g_queue_peek_head (&queue); end = g_strconcat (part->id, ".end", NULL); - for (iter = g_slist_next (iter); iter; iter = g_slist_next (iter)) { - EMailPart * p = iter->data; - if (!p) - continue; + + for (link = head; link != NULL; link = g_list_next (link)) { + EMailPart *p = link->data; /* Skip attachment bar */ if (g_str_has_suffix (p->id, ".attachment-bar")) @@ -111,28 +116,18 @@ emfqe_message_rfc822_format (EMailFormatterExtension *extension, if (g_str_has_suffix (p->id, ".rfc822")) { gchar *sub_end = g_strconcat (p->id, ".end", NULL); - while (iter) { - p = iter->data; - if (!p) { - iter = g_slist_next (iter); - if (!iter) { - break; - } - continue; - } - - if (g_strcmp0 (p->id, sub_end) == 0) { - break; - } + while (link != NULL) { + p = link->data; - iter = g_slist_next (iter); - if (!iter) { + if (g_strcmp0 (p->id, sub_end) == 0) break; - } + + link = g_list_next (link); } g_free (sub_end); continue; } + if ((g_strcmp0 (p->id, end) == 0)) break; @@ -142,11 +137,13 @@ emfqe_message_rfc822_format (EMailFormatterExtension *extension, e_mail_formatter_format_as ( formatter, context, p, stream, NULL, cancellable); - } g_free (end); + while (!g_queue_is_empty (&queue)) + e_mail_part_unref (g_queue_pop_head (&queue)); + camel_stream_write_string (stream, "", cancellable, NULL); return TRUE; diff --git a/em-format/e-mail-formatter-quote.c b/em-format/e-mail-formatter-quote.c index fcd2a06b48..3cd0121b72 100644 --- a/em-format/e-mail-formatter-quote.c +++ b/em-format/e-mail-formatter-quote.c @@ -50,7 +50,8 @@ mail_formatter_quote_run (EMailFormatter *formatter, EMailFormatterQuote *qf; EMailFormatterQuoteContext *qf_context; GSettings *settings; - GSList *list, *link; + GQueue queue = G_QUEUE_INIT; + GList *head, *link; if (g_cancellable_is_cancelled (cancellable)) return; @@ -87,13 +88,12 @@ mail_formatter_quote_run (EMailFormatter *formatter, "
\n", cancellable, NULL); } - list = context->part_list->list; + e_mail_part_list_queue_parts (context->part_list, NULL, &queue); - for (link = list; link != NULL; link = g_slist_next (link)) { - EMailPart *part = link->data; + head = g_queue_peek_head_link (&queue); - if (!part) - continue; + for (link = head; link != NULL; link = g_list_next (link)) { + EMailPart *part = link->data; if (g_str_has_suffix (part->id, ".headers") && !(qf_context->qf_flags & E_MAIL_FORMATTER_QUOTE_FLAG_HEADERS)) { @@ -105,17 +105,11 @@ mail_formatter_quote_run (EMailFormatter *formatter, while (link != NULL) { EMailPart *p = link->data; - if (p == NULL) { - link = g_slist_next (link); - if (link == NULL) - break; - continue; - } if (g_strcmp0 (p->id, end) == 0) break; - link = g_slist_next (link); + link = g_list_next (link); if (link == NULL) break; } @@ -132,6 +126,9 @@ mail_formatter_quote_run (EMailFormatter *formatter, part->mime_type, cancellable); } + while (!g_queue_is_empty (&queue)) + e_mail_part_unref (g_queue_pop_head (&queue)); + if (qf->priv->flags & E_MAIL_FORMATTER_QUOTE_FLAG_CITE) { camel_stream_write_string ( stream, "