From b39cda14b7678b925a6e3e645b60fb9858fdfaf6 Mon Sep 17 00:00:00 2001 From: bertrand Date: Thu, 17 Feb 2000 15:19:04 +0000 Subject: revamped so that it uses the output stream of the data wrapper 2000-02-17 bertrand * camel/camel-formatter.c (handle_text_plain): revamped so that it uses the output stream of the data wrapper (handle_text_html): ditto. * camel/camel-simple-data-wrapper.h: * camel/camel-simple-data-wrapper.c (camel_simple_data_wrapper_new): use (void) instead of (). (_get_output_stream): simple implementation. A lot of small fixes so that the new parser scheme works properly. Simple implementation of the stream though. Changed vette-formatter files so that they work with the new scheme. The new parser is now in a usable state. Still needs some work but the infrastructure is here. /me is happy. svn path=/trunk/; revision=1822 --- ChangeLog | 39 ++++ camel/camel-data-wrapper.c | 10 + camel/camel-formatter.c | 380 ++++++++++++++++++++++++++------------ camel/camel-formatter.h | 12 +- camel/camel-mime-message.c | 6 +- camel/camel-mime-part.c | 20 ++ camel/camel-multipart.c | 9 + camel/camel-seekable-substream.c | 10 +- camel/camel-simple-data-wrapper.c | 27 ++- camel/camel-simple-data-wrapper.h | 2 +- camel/providers/mbox/Makefile.am | 3 +- tests/ui-tests/message-browser.c | 106 ++++++++--- 12 files changed, 464 insertions(+), 160 deletions(-) diff --git a/ChangeLog b/ChangeLog index 43061e1915..225367aa40 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,22 @@ +2000-02-17 bertrand + + * camel/camel-formatter.c (handle_text_plain): + revamped so that it uses the output stream + of the data wrapper + (handle_text_html): ditto. + + + * camel/camel-simple-data-wrapper.h: + * camel/camel-simple-data-wrapper.c (camel_simple_data_wrapper_new): + use (void) instead of (). + (_get_output_stream): simple implementation. + 2000-02-16 bertrand + * camel/camel-data-wrapper.c (_set_input_stream): ref input stream + (_set_output_stream): ref output stream + (_finalize): unref input and output streams + * camel/camel-seekable-substream.c (_set_bounds): don't seek the begining of the substream. (_eos): fix eos condition testing. @@ -109,6 +126,28 @@ New function. Allows to get the current position of a seekable stream. + +2000-02-16 Matt Loper + + * tests/ui-tests/message-browser.c (tree_selection_changed): New + callback function, which will later change the main html window to + reflect the newly-selected tree item. + (get_gtk_html_contents_window): New function. Gets the content + part of a message. + (get_gtk_html_header_window): New function. Will get the header + part of a message, when applicable. + + * camel/camel-formatter.c (str_tolower): Now returns a new string, + rather than changing it in place. + (initialize_camel_formatter): New function; gives a root + CamelDataWrapper and a stream to a CamelFormatter. + (camel_formatter_wrapper_to_html): New function. Translates any + CamelDataWrapper into html. + (lookup_unique_id): Allows the root object to be a + CamelDataWrapper, which is more general than the previously + required CamelMimeMessage. + + 2000-02-14 NotZed * configure.in (EXTRA_GNOME_CFLAGS): Add libunicode to CFLAGS/LIBS. diff --git a/camel/camel-data-wrapper.c b/camel/camel-data-wrapper.c index 1ec70c6b37..fdc9aac45b 100644 --- a/camel/camel-data-wrapper.c +++ b/camel/camel-data-wrapper.c @@ -126,6 +126,12 @@ _finalize (GtkObject *object) if (camel_data_wrapper->mime_type) gmime_content_field_unref (camel_data_wrapper->mime_type); + if (camel_data_wrapper->input_stream) + gtk_object_unref (GTK_OBJECT (camel_data_wrapper->input_stream)); + + if (camel_data_wrapper->output_stream) + gtk_object_unref (GTK_OBJECT (camel_data_wrapper->output_stream)); + parent_class->finalize (object); CAMEL_LOG_FULL_DEBUG ("Leaving CamelDataWrapper::finalize\n"); } @@ -140,6 +146,8 @@ _set_input_stream (CamelDataWrapper *data_wrapper, CamelStream *stream) { g_assert (data_wrapper); data_wrapper->input_stream = stream; + if (stream) + gtk_object_ref (GTK_OBJECT (stream)); } @@ -176,6 +184,8 @@ _set_output_stream (CamelDataWrapper *data_wrapper, CamelStream *stream) { g_assert (data_wrapper); data_wrapper->output_stream = stream; + if (stream) + gtk_object_ref (GTK_OBJECT (stream)); } void diff --git a/camel/camel-formatter.c b/camel/camel-formatter.c index 50d1d2da6f..bcdb490faa 100644 --- a/camel/camel-formatter.c +++ b/camel/camel-formatter.c @@ -1,4 +1,5 @@ - + /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ + /*--------------------------------*-C-*---------------------------------* * * Author : @@ -27,8 +28,8 @@ #include "camel-log.h" #include -#include // for isprint -#include // for strstr +#include /* for isprint */ +#include /* for strstr */ /* * The CamelFormatter takes a mime message, and produces html from it, @@ -38,9 +39,6 @@ * camel_formatter_mime_message_to_html() * | * V - * handle_mime_message() - * | - * V * call_handler_function() * * Then, 'call_handler_function' acts as a dispatcher, using a @@ -57,7 +55,7 @@ static void handle_image (CamelFormatter *formatter, CamelDataWrapper *wrapper); static void handle_vcard (CamelFormatter *formatter, CamelDataWrapper *wrapper); -static void handle_mime_message (CamelFormatter *formatter, +static void handle_mime_part (CamelFormatter *formatter, CamelDataWrapper *wrapper); static void handle_multipart_mixed (CamelFormatter *formatter, CamelDataWrapper *wrapper); @@ -76,16 +74,22 @@ static gchar* text_to_html (const guchar *input, /* compares strings case-insensitively */ static gint strcase_equal (gconstpointer v, gconstpointer v2); -static void str_tolower (gchar* str); +static gchar* str_tolower (gchar* str); /* writes the header info for a mime message into a stream */ static void write_header_info_to_stream (CamelMimeMessage* mime_message, CamelStream* stream); +/* dispatch html printing via mimetype */ +static void call_handler_function (CamelFormatter* formatter, + CamelDataWrapper* wrapper, + gchar* mimetype_whole, + gchar* mimetype_main); + static GtkObjectClass *parent_class = NULL; struct _CamelFormatterPrivate { - CamelMimeMessage *current_root; + CamelDataWrapper *current_root; CamelStream *stream; GHashTable *attachments; }; @@ -109,12 +113,73 @@ debug (const gchar *format, ...) g_free (string); } +static void +initialize_camel_formatter (CamelFormatter* formatter, + CamelDataWrapper* data_wrapper, + CamelStream* stream) +{ + CamelFormatterPrivate* fmt = formatter->priv; + + /* initialize members of our formatter */ + fmt->current_root = data_wrapper; + fmt->stream = stream; + if (fmt->attachments) + g_hash_table_destroy (fmt->attachments); + fmt->attachments = g_hash_table_new (g_str_hash, strcase_equal); +} + + +/** + * camel_formatter_wrapper_to_html: + * @formatter: the camel formatter object + * @data_wrapper: the data wrapper + * @stream: byte stream where data will be written + * + * Writes a CamelDataWrapper out, as html, into a stream passed in as + * a parameter. + **/ +void camel_formatter_wrapper_to_html (CamelFormatter* formatter, + CamelDataWrapper* data_wrapper, + CamelStream* stream_out) +{ + CamelFormatterPrivate* fmt = formatter->priv; + gchar *mimetype_whole = + g_strdup_printf ("%s/%s", + data_wrapper->mime_type->type, + data_wrapper->mime_type->subtype); + + g_print ("camel_formatter_wrapper_to_html: entered\n"); + g_assert (formatter && data_wrapper && stream_out); + + /* give the root CamelDataWrapper and the stream to the formatter */ + initialize_camel_formatter (formatter, data_wrapper, stream_out); + + if (stream_out) { + + /* write everything to the stream */ + camel_stream_write_string ( + fmt->stream, "\n"); + call_handler_function ( + formatter, + data_wrapper, + mimetype_whole, + data_wrapper->mime_type->type); + + camel_stream_write_string (fmt->stream, "\n\n"); + } + + + g_free (mimetype_whole); +} + /** * camel_formatter_mime_message_to_html: * @formatter: the camel formatter object * @mime_message: the input mime message - * @stream: byte stream where data will be written + * @header_stream: byte stream where data will be written (can be + * NULL) + * @body_stream: byte stream where data will be written (required) * * Writes a CamelMimeMessage out, as html, into a stream passed in as * a parameter. @@ -125,41 +190,37 @@ camel_formatter_mime_message_to_html (CamelFormatter* formatter, CamelStream* header_stream, CamelStream* body_stream) { - CamelFormatterPrivate* fmt = formatter->priv; - g_print ("camel_formatter_mime_message_to_html: entered\n"); - g_assert (mime_message); + + g_assert (formatter != NULL); + g_assert (CAMEL_IS_FORMATTER (formatter)); + g_assert (mime_message != NULL); + g_assert (CAMEL_IS_MIME_MESSAGE (mime_message)); - /* initialize members of our formatter */ - fmt->current_root = mime_message; - fmt->stream = body_stream; - if (fmt->attachments) - g_hash_table_destroy (fmt->attachments); - fmt->attachments = g_hash_table_new (g_str_hash, strcase_equal); + g_assert (header_stream || body_stream); + + /* give the root CamelDataWrapper and the stream to the + formatter */ + initialize_camel_formatter (formatter, + CAMEL_DATA_WRAPPER (mime_message), + body_stream); + + if (body_stream) { + /* Write the contents of the mime message to the stream */ + camel_stream_write_string (body_stream, "\n"); + call_handler_function ( + formatter, + CAMEL_DATA_WRAPPER (mime_message), + "message/rfc822", + "message"); + camel_stream_write_string (body_stream, "\n\n"); + } /* write the subj:, to:, from: etc. fields out as html to the header stream */ if (header_stream) write_header_info_to_stream (mime_message, header_stream); - - /* write everything to the stream */ - if (body_stream) { - - camel_stream_write_string (fmt->stream, "\n"); - - handle_mime_message ( - formatter, - CAMEL_DATA_WRAPPER (mime_message)); - - camel_stream_write_string (fmt->stream, - "\n\n"); - } - else { - g_print ("camel-formatter.c: "); - g_print ("camel_formatter_mime_message_to_html: "); - g_print ("you don't want the body??\n"); - } } /* we're maintaining a hashtable of mimetypes -> functions; @@ -168,7 +229,7 @@ typedef void (*mime_handler_fn) (CamelFormatter *formatter, CamelDataWrapper *data_wrapper); static gchar* -lookup_unique_id (CamelMimeMessage* root, CamelDataWrapper* child) +lookup_unique_id (CamelDataWrapper* root, CamelDataWrapper* child) { /* TODO: assert our return value != NULL */ @@ -186,7 +247,7 @@ get_bonobo_tag_for_object (CamelFormatter* formatter, gchar* mimetype) { - CamelMimeMessage* root = formatter->priv->current_root; + CamelDataWrapper* root = formatter->priv->current_root; char* uid = lookup_unique_id (root, wrapper); const char* goad_id = gnome_mime_get_value ( mimetype, "bonobo-goad_id"); @@ -218,24 +279,29 @@ get_bonobo_tag_for_object (CamelFormatter* formatter, static void call_handler_function (CamelFormatter* formatter, CamelDataWrapper* wrapper, - gchar* mimetype_whole, /* ex. "image/jpeg" */ - gchar* mimetype_main) /* ex. "image" */ + gchar* mimetype_whole_in, /* ex. "image/jpeg" */ + gchar* mimetype_main_in) /* ex. "image" */ { mime_handler_fn handler_function = NULL; + gchar* mimetype_whole = NULL; + gchar* mimetype_main = NULL; g_assert (formatter); - g_assert (mimetype_whole || mimetype_main); + g_assert (mimetype_whole_in || mimetype_main_in); g_assert (wrapper); /* * Try to find a handler function in our own lookup table */ - str_tolower (mimetype_whole); - str_tolower (mimetype_main); - - if (mimetype_whole) + if (mimetype_whole_in) { + mimetype_whole = str_tolower (mimetype_whole_in); + handler_function = g_hash_table_lookup ( mime_function_table, mimetype_whole); + } + + if (mimetype_main_in) + mimetype_main = str_tolower (mimetype_main_in); if (mimetype_main && !handler_function) handler_function = g_hash_table_lookup ( @@ -261,7 +327,9 @@ call_handler_function (CamelFormatter* formatter, camel_stream_write_string ( formatter->priv->stream, bonobo_tag); g_free (bonobo_tag); - + if (mimetype_whole) g_free (mimetype_whole); + if (mimetype_main) g_free (mimetype_main); + return; } } @@ -275,6 +343,8 @@ call_handler_function (CamelFormatter* formatter, debug ("no function or bonobo object found for mimetype \"%s\"\n", mimetype_whole?mimetype_whole:mimetype_main); } + if (mimetype_whole) g_free (mimetype_whole); + if (mimetype_main) g_free (mimetype_main); } @@ -313,7 +383,8 @@ text_to_html (const guchar *input, out = &buffer[index]; } - /* By default one has to encode at least '<', '>', '"' and '&'. */ + /* By default one has to encode at least '<', '>', '"' + and '&'. */ if (*cur == '<') { *out++ = '&'; *out++ = 'l'; @@ -373,7 +444,7 @@ text_to_html (const guchar *input, static void write_field_to_stream (const gchar* description, const gchar* value, - CamelStream *stream) + CamelStream *stream, gboolean as_table_row) { gchar *s; guint ev_length; @@ -386,8 +457,12 @@ write_field_to_stream (const gchar* description, const gchar* value, g_assert (description && value); - s = g_strdup_printf ("%s: %s
\n", - description, encoded_value); + s = g_strdup_printf ("%s%s%s%s%s\n", + as_table_row?"":"", + description, + as_table_row?"":" ", + encoded_value, + as_table_row?"":"
"); camel_stream_write_string (stream, s); g_free (encoded_value); @@ -398,7 +473,8 @@ write_field_to_stream (const gchar* description, const gchar* value, static void write_recipients_to_stream (const gchar* recipient_type, const GList* recipients, - CamelStream* stream) + CamelStream* stream, + gboolean as_table_row) { /* list of recipients, like "elvis@graceland; bart@springfield" */ gchar *recipients_string = NULL; @@ -417,10 +493,10 @@ write_recipients_to_stream (const gchar* recipient_type, recipients = recipients->next; } - write_field_to_stream (recipient_type, recipients_string, stream); + write_field_to_stream (recipient_type, recipients_string, stream, + as_table_row); g_free (recipients_string); - camel_stream_write_string (stream, "

\n"); } @@ -434,23 +510,25 @@ write_header_info_to_stream (CamelMimeMessage* mime_message, g_assert (mime_message && stream); + camel_stream_write_string (stream, ""); + /* A few fields will probably be available from the mime_message; for each one that's available, write it to the output stream with a helper function, 'write_field_to_stream'. */ if ((s = (gchar*)camel_mime_message_get_subject (mime_message))) { - write_field_to_stream ("Subject: ", s, stream); + write_field_to_stream ("Subject: ", s, stream, TRUE); } if ((s = (gchar*)camel_mime_message_get_from (mime_message))) { - write_field_to_stream ("From: ", s, stream); + write_field_to_stream ("From: ", s, stream, TRUE); } if ((s = (gchar*)camel_mime_message_get_received_date (mime_message))) { - write_field_to_stream ("Received Date: ", s, stream); + write_field_to_stream ("Received Date: ", s, stream, TRUE); } if ((s = (gchar*)camel_mime_message_get_sent_date (mime_message))) { - write_field_to_stream ("Sent Date: ", s, stream); + write_field_to_stream ("Sent Date: ", s, stream, TRUE); } /* Fill out the "To:" recipients line */ @@ -458,19 +536,21 @@ write_header_info_to_stream (CamelMimeMessage* mime_message, mime_message, CAMEL_RECIPIENT_TYPE_TO); if (recipients) - write_recipients_to_stream ("To:", recipients, stream); + write_recipients_to_stream ("To:", recipients, stream, TRUE); /* Fill out the "CC:" recipients line */ recipients = camel_mime_message_get_recipients ( mime_message, CAMEL_RECIPIENT_TYPE_CC); if (recipients) - write_recipients_to_stream ("CC:", recipients, stream); + write_recipients_to_stream ("CC:", recipients, stream, TRUE); /* Fill out the "BCC:" recipients line */ recipients = camel_mime_message_get_recipients ( mime_message, CAMEL_RECIPIENT_TYPE_BCC); if (recipients) - write_recipients_to_stream ("BCC:", recipients, stream); + write_recipients_to_stream ("BCC:", recipients, stream, TRUE); + + camel_stream_write_string (stream, "
"); } /* case-insensitive string comparison */ @@ -480,15 +560,17 @@ strcase_equal (gconstpointer v, gconstpointer v2) return g_strcasecmp ((const gchar*) v, (const gchar*)v2) == 0; } -static void +static gchar* str_tolower (gchar* str) { int i; int len = strlen (str); + gchar* new_str = g_strdup (str); for (i = 0; i < len; i++) { - str[i] = tolower (str[i]); + new_str[i] = tolower (str[i]); } + return new_str; } @@ -505,70 +587,120 @@ str_tolower (gchar* str) static void handle_text_plain (CamelFormatter *formatter, CamelDataWrapper *wrapper) { - CamelSimpleDataWrapper* simple_data_wrapper; gchar* text; + CamelStream *wrapper_output_stream; + gchar tmp_buffer[4096]; + gint nb_bytes_read; + gboolean empty_text = TRUE; debug ("handle_text_plain: entered\n"); - - /* Plain text is embodied in a CamelSimpleDataWrapper */ - g_assert (CAMEL_IS_SIMPLE_DATA_WRAPPER (wrapper)); - simple_data_wrapper = CAMEL_SIMPLE_DATA_WRAPPER (wrapper); - + camel_stream_write_string (formatter->priv->stream, "\n\n"); - /* If there's any text, write it to the stream */ - if (simple_data_wrapper->byte_array->len != 0) { + if (strcmp (wrapper->mime_type->subtype, "richtext") == 0) { - int returned_strlen; + camel_stream_write_string ( + formatter->priv->stream, + "
Warning: the following richtext may not"); + camel_stream_write_string ( + formatter->priv->stream, + " be formatted correctly.

"); + } - g_assert (simple_data_wrapper->byte_array->data); + /* get the output stream of the data wrapper */ + wrapper_output_stream = camel_data_wrapper_get_output_stream (wrapper); + + if (CAMEL_IS_SEEKABLE_STREAM (wrapper_output_stream)) + camel_seekable_stream_seek (CAMEL_SEEKABLE_STREAM (wrapper_output_stream), + 0, + CAMEL_STREAM_SET); + + + do { + + /* read next chunk of text */ + nb_bytes_read = camel_stream_read (wrapper_output_stream, + tmp_buffer, + 4096); + printf ("after camel_stream_read, nb_bytes_read=%d\n", nb_bytes_read); + /* If there's any text, write it to the stream */ + if (nb_bytes_read > 0) { + + int returned_strlen; + + empty_text = FALSE; + + /* replace '<' with '<', etc. */ + text = text_to_html (tmp_buffer, + nb_bytes_read, + &returned_strlen); + + camel_stream_write_string (formatter->priv->stream, text); + g_free (text); + } + + + } while (!camel_stream_eos (wrapper_output_stream)); - /* replace '<' with '<', etc. */ - text = text_to_html (simple_data_wrapper->byte_array->data, - simple_data_wrapper->byte_array->len, - &returned_strlen); - - camel_stream_write_string (formatter->priv->stream, text); - g_free (text); - } - else - debug ("Warning: handle_text_plain: length of byte array is zero!\n"); + if (empty_text) { + debug ("Warning: handle_text_plain: text part is empty!\n"); + camel_stream_write_string (formatter->priv->stream, + "(empty)"); + } + debug ("handle_text_plain: exiting\n"); } static void handle_text_html (CamelFormatter *formatter, CamelDataWrapper *wrapper) { - CamelSimpleDataWrapper* simple_data_wrapper; - gchar* text; + CamelStream *wrapper_output_stream; + gchar tmp_buffer[4096]; + gint nb_bytes_read; + gboolean empty_text = TRUE; + debug ("handle_text_html: entered\n"); - /* text is embodied in a CamelSimpleDataWrapper */ - g_assert (CAMEL_IS_SIMPLE_DATA_WRAPPER (wrapper)); - simple_data_wrapper = CAMEL_SIMPLE_DATA_WRAPPER (wrapper); + /* get the output stream of the data wrapper */ + wrapper_output_stream = camel_data_wrapper_get_output_stream (wrapper); + + if (CAMEL_IS_SEEKABLE_STREAM (wrapper_output_stream)) + camel_seekable_stream_seek (CAMEL_SEEKABLE_STREAM (wrapper_output_stream), + 0, + CAMEL_STREAM_SET); - /* If there's any text, write it to the stream */ - if (simple_data_wrapper->byte_array->len != 0) { + /* write the header */ + camel_stream_write_string (formatter->priv->stream, + "\n\n"); - int returned_strlen; + do { - g_assert (simple_data_wrapper->byte_array->data); + /* read next chunk of text */ + nb_bytes_read = camel_stream_read (wrapper_output_stream, + tmp_buffer, + 4096); - /* replace '<' with '<', etc. */ - text = g_strndup (simple_data_wrapper->byte_array->data, - simple_data_wrapper->byte_array->len); + /* If there's any text, write it to the stream */ + if (nb_bytes_read > 0) { + + empty_text = FALSE; + + /* write the buffer to the formater output stream */ + camel_stream_write (formatter->priv->stream, tmp_buffer, nb_bytes_read); + } + + + } while (!camel_stream_eos (wrapper_output_stream)); - camel_stream_write_string (formatter->priv->stream, - "\n\n"); - camel_stream_write_string (formatter->priv->stream, text); - g_free (text); + if (empty_text) { + debug ("Warning: handle_text_html: html part is empty!\n"); + camel_stream_write_string (formatter->priv->stream, + "(empty)"); } - else - debug ("Warning: handle_text_html: length of byte array is zero!\n"); debug ("handle_text_html: exiting\n"); } @@ -595,7 +727,7 @@ handle_image (CamelFormatter *formatter, CamelDataWrapper *wrapper) static void handle_vcard (CamelFormatter *formatter, CamelDataWrapper *wrapper) { - gchar* vcard; + gchar* vcard = NULL; debug ("handle_vcard: entered\n"); camel_stream_write_string (formatter->priv->stream, @@ -607,23 +739,23 @@ handle_vcard (CamelFormatter *formatter, CamelDataWrapper *wrapper) } static void -handle_mime_message (CamelFormatter *formatter, - CamelDataWrapper *wrapper) +handle_mime_part (CamelFormatter *formatter, + CamelDataWrapper *wrapper) { - CamelMimeMessage* mime_message; + CamelMimePart* mime_part; CamelDataWrapper* message_contents; g_assert (formatter); g_assert (wrapper); - g_assert (CAMEL_IS_MIME_MESSAGE (wrapper)); + g_assert (CAMEL_IS_MIME_PART (wrapper)); - mime_message = CAMEL_MIME_MESSAGE (wrapper); + mime_part = CAMEL_MIME_PART (wrapper); message_contents = - camel_medium_get_content_object (CAMEL_MEDIUM (mime_message)); + camel_medium_get_content_object (CAMEL_MEDIUM (mime_part)); g_assert (message_contents); - debug ("handle_mime_message: entered\n"); + debug ("handle_mime_part: entered\n"); camel_stream_write_string (formatter->priv->stream, "\n\n"); @@ -632,14 +764,14 @@ handle_mime_message (CamelFormatter *formatter, /* dispatch the correct handler function for the mime type */ call_handler_function (formatter, message_contents, - MIME_TYPE_WHOLE (mime_message), - MIME_TYPE_MAIN (mime_message)); + MIME_TYPE_WHOLE (mime_part), + MIME_TYPE_MAIN (mime_part)); /* close up the table we opened */ // camel_stream_write_string (formatter->priv->stream, // "\n\n\n\n"); - debug ("handle_mime_message: exiting\n"); + debug ("handle_mime_part: exiting\n"); } @@ -661,7 +793,8 @@ find_preferred_displayable_body_part_in_multipart_alternative ( /* TODO: DO LEAF-LOOKUP HERE FOR OTHER MIME-TYPES!!! */ for (i = 0; i < max_multiparts; i++) { - CamelMimeBodyPart* body_part = camel_multipart_get_part (multipart, i); + CamelMimeBodyPart* body_part = + camel_multipart_get_part (multipart, i); if (!strcase_equal (MIME_TYPE_MAIN (body_part), "text")) continue; @@ -774,12 +907,14 @@ handle_multipart_alternative (CamelFormatter *formatter, debug ("handle_multipart_alternative: entered\n"); - mime_part = find_preferred_displayable_body_part_in_multipart_alternative( + mime_part = + find_preferred_displayable_body_part_in_multipart_alternative( multipart); if (mime_part) { CamelDataWrapper* contents = - camel_medium_get_content_object (CAMEL_MEDIUM (mime_part)); + camel_medium_get_content_object ( + CAMEL_MEDIUM (mime_part)); call_handler_function (formatter, contents, MIME_TYPE_WHOLE (mime_part), @@ -794,7 +929,7 @@ handle_unknown_type (CamelFormatter *formatter, CamelDataWrapper *wrapper) { gchar* tag; - CamelMimeMessage* root = formatter->priv->current_root; + CamelDataWrapper* root = formatter->priv->current_root; char* uid = lookup_unique_id (root, wrapper); debug ("handle_unknown_type: entered\n"); @@ -846,14 +981,19 @@ camel_formatter_class_init (CamelFormatterClass *camel_formatter_class) /* hook up mime types to functions that handle them */ ADD_HANDLER ("text/plain", handle_text_plain); + ADD_HANDLER ("text/richtext", handle_text_plain); ADD_HANDLER ("text/html", handle_text_html); ADD_HANDLER ("multipart/alternative", handle_multipart_alternative); ADD_HANDLER ("multipart/related", handle_multipart_related); ADD_HANDLER ("multipart/mixed", handle_multipart_mixed); - ADD_HANDLER ("message/rfc822", handle_mime_message); + ADD_HANDLER ("message/rfc822", handle_mime_part); ADD_HANDLER ("image/", handle_image); ADD_HANDLER ("vcard/", handle_vcard); + /* body parts don't have mime parts per se, so camel + sticks on the following one */ + ADD_HANDLER ("mime/body-part", handle_mime_part); + /* virtual method overload */ gtk_object_class->finalize = _finalize; } @@ -893,9 +1033,3 @@ camel_formatter_get_type (void) return camel_formatter_type; } - - - - - - diff --git a/camel/camel-formatter.h b/camel/camel-formatter.h index 186ce6b1e2..95c974f01c 100644 --- a/camel/camel-formatter.h +++ b/camel/camel-formatter.h @@ -1,3 +1,6 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ + + /*--------------------------------*-C-*---------------------------------* * * Author : @@ -19,7 +22,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA. * - * *----------------------------------------------------------------------*/ #ifndef CAMEL_FORMATTER_H @@ -36,7 +38,7 @@ extern "C" { #define CAMEL_FORMATTER_TYPE (camel_formatter_get_type ()) #define CAMEL_FORMATTER(obj) (GTK_CHECK_CAST((obj), CAMEL_FORMATTER_TYPE, CamelFormatter)) #define CAMEL_FORMATTER_CLASS(k) (GTK_CHECK_CLASS_CAST ((k), CAMEL_FORMATTER_TYPE, CamelFormatterClass)) -#define CAMEL_IS_CAMEL_FORMATTER(o) (GTK_CHECK_TYPE((o), CAMEL_FORMATTER_TYPE)) +#define CAMEL_IS_FORMATTER(o) (GTK_CHECK_TYPE((o), CAMEL_FORMATTER_TYPE)) typedef struct _CamelFormatterPrivate CamelFormatterPrivate; @@ -59,13 +61,15 @@ GtkType camel_formatter_get_type (void); /* Public functions */ CamelFormatter* camel_formatter_new (void); -/* The main job of CamelFormatter is to take a mime message, and - produce html from it. */ void camel_formatter_mime_message_to_html (CamelFormatter* formatter, CamelMimeMessage* mime_message, CamelStream* header_stream, CamelStream* body_stream); +void camel_formatter_wrapper_to_html (CamelFormatter* formatter, + CamelDataWrapper* data_wrapper, + CamelStream* header_stream); + #ifdef __cplusplus } diff --git a/camel/camel-mime-message.c b/camel/camel-mime-message.c index ea7a983331..ffb94a0fb3 100644 --- a/camel/camel-mime-message.c +++ b/camel/camel-mime-message.c @@ -144,10 +144,12 @@ camel_mime_message_init (gpointer object, gpointer klass) { CamelMimeMessage *camel_mime_message = CAMEL_MIME_MESSAGE (object); - camel_data_wrapper_set_mime_type (CAMEL_DATA_WRAPPER (object), "mime/message"); + camel_data_wrapper_set_mime_type (CAMEL_DATA_WRAPPER (object), + "message/rfc822"); camel_mime_message->recipients = camel_recipient_table_new (); - camel_mime_message->flags = g_hash_table_new (g_strcase_hash, g_strcase_equal); + camel_mime_message->flags = + g_hash_table_new (g_strcase_hash, g_strcase_equal); camel_mime_message->received_date = NULL; camel_mime_message->sent_date = NULL; diff --git a/camel/camel-mime-part.c b/camel/camel-mime-part.c index 2e52f8312f..082f62fab0 100644 --- a/camel/camel-mime-part.c +++ b/camel/camel-mime-part.c @@ -63,6 +63,7 @@ static CamelMediumClass *parent_class=NULL; /* Returns the class for a CamelMimePart */ #define CMP_CLASS(so) CAMEL_MIME_PART_CLASS (GTK_OBJECT(so)->klass) +#define CDW_CLASS(so) CAMEL_DATA_WRAPPER_CLASS (GTK_OBJECT(so)->klass) /* from GtkObject */ static void _finalize (GtkObject *object); @@ -74,6 +75,7 @@ static void _construct_from_stream (CamelDataWrapper *data_wra CamelStream *stream); static void _set_input_stream (CamelDataWrapper *data_wrapper, CamelStream *stream); +static CamelStream * _get_output_stream (CamelDataWrapper *data_wrapper); /* from CamelMedia */ @@ -178,6 +180,7 @@ camel_mime_part_class_init (CamelMimePartClass *camel_mime_part_class) camel_data_wrapper_class->write_to_stream = _write_to_stream; camel_data_wrapper_class->construct_from_stream = _construct_from_stream; camel_data_wrapper_class->set_input_stream = _set_input_stream; + camel_data_wrapper_class->get_output_stream = _get_output_stream; gtk_object_class->finalize = _finalize; } @@ -823,6 +826,10 @@ _set_input_stream (CamelDataWrapper *data_wrapper, CamelStream *stream) g_assert (CAMEL_IS_SEEKABLE_STREAM (stream)); seekable_stream = CAMEL_SEEKABLE_STREAM (stream); + /* call parent class implementation */ + CAMEL_DATA_WRAPPER_CLASS (parent_class)->set_input_stream (data_wrapper, stream); + + camel_mime_part_construct_headers_from_stream (mime_part, stream); /* set the input stream for the content object */ @@ -831,11 +838,24 @@ _set_input_stream (CamelDataWrapper *data_wrapper, CamelStream *stream) camel_seekable_substream_new_with_seekable_stream_and_bounds (seekable_stream, content_stream_inf_bound, -1); + + CAMEL_LOG_FULL_DEBUG ("CamelMimePart::set_input_stream leaving\n"); } +static CamelStream * +_get_output_stream (CamelDataWrapper *data_wrapper) +{ + + CAMEL_LOG_FULL_DEBUG ("CamelMimePart::get_output_stream leaving\n"); + return camel_data_wrapper_get_input_stream (data_wrapper); + CAMEL_LOG_FULL_DEBUG ("CamelMimePart::get_output_stream leaving\n"); + +} + + const gchar * camel_mime_part_encoding_to_string (CamelMimePartEncodingType encoding) { diff --git a/camel/camel-multipart.c b/camel/camel-multipart.c index 0a2f488f31..ce22128835 100644 --- a/camel/camel-multipart.c +++ b/camel/camel-multipart.c @@ -503,6 +503,10 @@ _set_input_stream (CamelDataWrapper *data_wrapper, CamelStream *stream) CAMEL_LOG_FULL_DEBUG ("Entering CamelMultipart::_set_input_stream\n"); + + /* call parent class implementation */ + parent_class->set_input_stream (data_wrapper, stream); + boundary = camel_multipart_get_boundary (multipart); g_return_if_fail (boundary); @@ -535,6 +539,9 @@ _set_input_stream (CamelDataWrapper *data_wrapper, CamelStream *stream) camel_seekable_substream_new_with_seekable_stream_and_bounds (seekable_stream, part_begining, part_end); + CAMEL_LOG_FULL_DEBUG ("CamelMultipart::set_input_stream, use a substream,\n" + "\tbegining = %d\n" + "\tend = %d\n",part_begining, part_end); /* the seekable substream may change the position of the stream so we must save it before calling set_input_stream */ @@ -542,6 +549,8 @@ _set_input_stream (CamelDataWrapper *data_wrapper, CamelStream *stream) camel_data_wrapper_set_input_stream (CAMEL_DATA_WRAPPER (body_part), CAMEL_STREAM (body_part_input_stream)); + CAMEL_LOG_FULL_DEBUG ("CamelMultipart::set_input_stream," + "new body part has input stream : %p\n", body_part_input_stream); /* restore the stream position */ camel_seekable_stream_seek (seekable_stream, saved_stream_pos, CAMEL_STREAM_SET); diff --git a/camel/camel-seekable-substream.c b/camel/camel-seekable-substream.c index 6d59d8994c..2b4b7d2917 100644 --- a/camel/camel-seekable-substream.c +++ b/camel/camel-seekable-substream.c @@ -143,12 +143,14 @@ static void _finalize (GtkObject *object) { CamelSeekableStream *seekable_stream; + CamelSeekableSubstream *seekable_substream; CAMEL_LOG_FULL_DEBUG ("Entering CamelSeekableSubstream::finalize\n"); seekable_stream = CAMEL_SEEKABLE_STREAM (object); + seekable_substream = CAMEL_SEEKABLE_SUBSTREAM (object); - if (seekable_stream->parent_stream) - gtk_object_unref (seekable_stream->parent_stream); + if (seekable_substream->parent_stream) + gtk_object_unref (GTK_OBJECT (seekable_substream->parent_stream)); GTK_OBJECT_CLASS (parent_class)->finalize (object); CAMEL_LOG_FULL_DEBUG ("Leaving CamelSeekableSubstream::finalize\n"); @@ -195,7 +197,7 @@ _init_with_seekable_stream_and_bounds (CamelSeekableSubstream *seekable_substre /* store the parent stream */ seekable_substream->parent_stream = parent_stream; - gtk_object_ref (parent_stream); + gtk_object_ref (GTK_OBJECT (parent_stream)); /* set the bound of the substream */ _set_bounds (seekable_substream, inf_bound, sup_bound); @@ -446,11 +448,13 @@ _seek (CamelSeekableStream *stream, gint offset, CamelStreamSeekPolicy policy) default: return -1; } + if (!seek_done) { if (real_offset > 0) { seekable_stream->cur_pos = MIN (real_offset, substream_len); } else seekable_stream->cur_pos = 0; + printf ("** set in substream %p, offset=%d\n", stream, real_offset); } diff --git a/camel/camel-simple-data-wrapper.c b/camel/camel-simple-data-wrapper.c index 943d8e902d..f4b7afd5f9 100644 --- a/camel/camel-simple-data-wrapper.c +++ b/camel/camel-simple-data-wrapper.c @@ -35,10 +35,15 @@ static CamelDataWrapperClass *parent_class=NULL; /* Returns the class for a CamelDataWrapper */ #define CSDW_CLASS(so) CAMEL_SIMPLE_DATA_WRAPPER_CLASS (GTK_OBJECT(so)->klass) -static void _construct_from_stream (CamelDataWrapper *data_wrapper, CamelStream *stream); -static void _write_to_stream (CamelDataWrapper *data_wrapper, CamelStream *stream); -static void _finalize (GtkObject *object); -static CamelStream *_get_stream (CamelDataWrapper *data_wrapper); +static void _construct_from_stream (CamelDataWrapper *data_wrapper, + CamelStream *stream); +static void _write_to_stream (CamelDataWrapper *data_wrapper, + CamelStream *stream); +static void _finalize (GtkObject *object); +static CamelStream * _get_stream (CamelDataWrapper *data_wrapper); +static CamelStream * _get_output_stream (CamelDataWrapper *data_wrapper); + + static void camel_simple_data_wrapper_class_init (CamelSimpleDataWrapperClass *camel_simple_data_wrapper_class) @@ -52,6 +57,7 @@ camel_simple_data_wrapper_class_init (CamelSimpleDataWrapperClass *camel_simple_ /* virtual method overload */ camel_data_wrapper_class->write_to_stream = _write_to_stream; camel_data_wrapper_class->construct_from_stream = _construct_from_stream; + camel_data_wrapper_class->get_output_stream = _get_output_stream; camel_data_wrapper_class->get_stream = _get_stream; @@ -111,7 +117,7 @@ _finalize (GtkObject *object) * Return value: **/ CamelSimpleDataWrapper * -camel_simple_data_wrapper_new () +camel_simple_data_wrapper_new (void) { CamelSimpleDataWrapper *simple_data_wrapper; CAMEL_LOG_FULL_DEBUG ("CamelSimpleDataWrapper:: Entering new()\n"); @@ -228,3 +234,14 @@ _get_stream (CamelDataWrapper *data_wrapper) return simple_data_wrapper->stream; } + + +static CamelStream * +_get_output_stream (CamelDataWrapper *data_wrapper) +{ + + CAMEL_LOG_FULL_DEBUG ("CamelSimpleDataWrapper::get_output_stream leaving\n"); + return camel_data_wrapper_get_input_stream (data_wrapper); + CAMEL_LOG_FULL_DEBUG ("CamelSimpleDataWrapper::get_output_stream leaving\n"); + +} diff --git a/camel/camel-simple-data-wrapper.h b/camel/camel-simple-data-wrapper.h index 1a511b96c4..097b59385f 100644 --- a/camel/camel-simple-data-wrapper.h +++ b/camel/camel-simple-data-wrapper.h @@ -72,7 +72,7 @@ GtkType camel_simple_data_wrapper_get_type (void); /* public methods */ -CamelSimpleDataWrapper *camel_simple_data_wrapper_new (); +CamelSimpleDataWrapper *camel_simple_data_wrapper_new (void); void camel_simple_data_wrapper_set_text (CamelSimpleDataWrapper *simple_data_wrapper, const gchar *text); #ifdef __cplusplus diff --git a/camel/providers/mbox/Makefile.am b/camel/providers/mbox/Makefile.am index c258f3d747..62cfeaba22 100644 --- a/camel/providers/mbox/Makefile.am +++ b/camel/providers/mbox/Makefile.am @@ -4,8 +4,9 @@ SUBDIRS = libcamelmboxincludedir = $(includedir)/camel +lib_LTLIBRARIES = libcamelmbox.la -provider_LTLIBRARIES = libcamelmbox.la +#provider_LTLIBRARIES = libcamelmbox.la INCLUDES = -I.. -I$(srcdir)/.. -I$(includedir) \ -I$(top_srcdir)/intl \ diff --git a/tests/ui-tests/message-browser.c b/tests/ui-tests/message-browser.c index e7d808801a..fb981814d8 100644 --- a/tests/ui-tests/message-browser.c +++ b/tests/ui-tests/message-browser.c @@ -115,6 +115,27 @@ handle_tree_item (CamelDataWrapper* object, GtkWidget* tree_ctrl) } } +static void +tree_selection_changed( GtkWidget *tree ) +{ + GList *i; + + i = GTK_TREE_SELECTION(tree); + while (i){ + gchar *name; + GtkLabel *label; + GtkWidget *item; + + /* Get a GtkWidget pointer from the list node */ + item = GTK_WIDGET (i->data); + label = GTK_LABEL (GTK_BIN (item)->child); + gtk_label_get (label, &name); + g_print ("\t%s on level %d\n", name, GTK_TREE + (item->parent)->level); + i = i->next; + } +} + static GtkWidget* get_message_tree_ctrl (CamelMimeMessage* message) { @@ -125,6 +146,12 @@ get_message_tree_ctrl (CamelMimeMessage* message) if (!tree_ctrl) { tree_ctrl = gtk_tree_new (); + + gtk_signal_connect (GTK_OBJECT(tree_ctrl), + "selection_changed", + GTK_SIGNAL_FUNC(tree_selection_changed), + tree_ctrl); + scroll_wnd = gtk_scrolled_window_new (NULL,NULL); gtk_scrolled_window_add_with_viewport ( @@ -164,10 +191,11 @@ filename_to_camel_msg (gchar* filename) message = camel_mime_message_new_with_session ( (CamelSession *)NULL); - camel_data_wrapper_construct_from_stream ( - CAMEL_DATA_WRAPPER (message), input_stream); + //camel_data_wrapper_construct_from_stream ( + // CAMEL_DATA_WRAPPER (message), input_stream); - camel_stream_close (input_stream); + camel_data_wrapper_set_input_stream ( + CAMEL_DATA_WRAPPER (message), input_stream); return message; } @@ -177,36 +205,30 @@ filename_to_camel_msg (gchar* filename) *----------------------------------------------------------------------*/ static void -mime_message_to_html (CamelMimeMessage *msg, gchar** header_string, - gchar** body_string) +mime_message_to_html (CamelDataWrapper *msg, gchar** body_string) { CamelFormatter* cmf = camel_formatter_new(); - CamelStream* header_stream = - camel_stream_mem_new (CAMEL_STREAM_FS_WRITE); CamelStream* body_stream = camel_stream_mem_new (CAMEL_STREAM_FS_WRITE); - g_assert (header_string && body_string); + g_assert (body_string); - camel_formatter_mime_message_to_html ( - cmf, msg, header_stream, body_stream); + camel_formatter_wrapper_to_html ( + cmf, msg, body_stream); - *header_string = g_strndup ( - CAMEL_STREAM_MEM (header_stream)->buffer->data, - CAMEL_STREAM_MEM (header_stream)->buffer->len); *body_string = g_strndup ( CAMEL_STREAM_MEM (body_stream)->buffer->data, CAMEL_STREAM_MEM (body_stream)->buffer->len); } + static GtkWidget* -get_gtk_html_window (CamelMimeMessage* mime_message) +get_gtk_html_contents_window (CamelDataWrapper* data) { static GtkWidget* scroll_wnd = NULL; static GtkWidget* html_widget = NULL; HTMLStream* html_stream; gchar *body_string; - gchar *header_string; /* create the html widget and scroll window, if they haven't already been created */ @@ -216,13 +238,14 @@ get_gtk_html_window (CamelMimeMessage* mime_message) gtk_container_add (GTK_CONTAINER (scroll_wnd), html_widget); } - if (mime_message) { + if (data) { - html_stream = HTML_STREAM (html_stream_new (GTK_HTML (html_widget))); + html_stream = + HTML_STREAM (html_stream_new (GTK_HTML (html_widget))); /* turn the mime message into html, and write it to the html stream */ - mime_message_to_html (mime_message, &header_string, &body_string); + mime_message_to_html (data, &body_string); camel_stream_write (CAMEL_STREAM (html_stream), body_string, @@ -230,7 +253,6 @@ get_gtk_html_window (CamelMimeMessage* mime_message) camel_stream_close (CAMEL_STREAM (html_stream)); - g_free (header_string); g_free (body_string); } @@ -243,6 +265,49 @@ get_gtk_html_window (CamelMimeMessage* mime_message) } +static GtkWidget* +get_gtk_html_header_window (CamelMimeMessage* mime_message) +{ + static GtkWidget* hbox = NULL; + gchar* subj_string = NULL; + gchar* to_string = NULL; + gchar* from_string = NULL; + + if (!hbox) { + hbox = gtk_hbox_new (FALSE, 0); + gtk_box_pack_start (GTK_BOX (hbox), + gtk_button_new_with_label("hello"), + FALSE, TRUE, 5); + } + + return hbox; +} + +static GtkWidget* +get_gtk_html_window (CamelDataWrapper* data) +{ + static GtkWidget* vbox = NULL; + CamelMimeMessage* msg = NULL; + + if (CAMEL_IS_MIME_MESSAGE (data)) + msg = CAMEL_MIME_MESSAGE (data); + + if (!vbox) vbox = gtk_vbox_new (FALSE, 0); + if (msg) + gtk_box_pack_start ( + GTK_BOX (vbox), + get_gtk_html_header_window(msg), + FALSE, TRUE, 5); + + gtk_box_pack_start (GTK_BOX (vbox), + get_gtk_html_contents_window(data), + FALSE, TRUE, 5); + + return vbox; +} + + + /*----------------------------------------------------------------------* * Menu callbacks and information *----------------------------------------------------------------------*/ @@ -277,7 +342,7 @@ open_ok (GtkWidget *widget, GtkFileSelection *fs) if (message) { fileselection_prev_file = g_strdup (filename); get_message_tree_ctrl (message); - get_gtk_html_window (message); + get_gtk_html_window (CAMEL_DATA_WRAPPER (message)); } else gnome_message_box_new ("Couldn't load message.", @@ -363,7 +428,6 @@ main (int argc, char *argv[]) g_print ("Couldn't load message."); } } - hpane = gtk_hpaned_new(); -- cgit v1.2.3