diff options
-rw-r--r-- | mail/ChangeLog | 15 | ||||
-rw-r--r-- | mail/folder-browser-factory.c | 43 | ||||
-rw-r--r-- | mail/mail-format.c | 251 | ||||
-rw-r--r-- | mail/mail-format.h | 10 | ||||
-rw-r--r-- | mail/mail-ops.c | 61 | ||||
-rw-r--r-- | mail/mail-ops.h | 4 |
6 files changed, 328 insertions, 56 deletions
diff --git a/mail/ChangeLog b/mail/ChangeLog index b7afba2070..64ca3a6b9d 100644 --- a/mail/ChangeLog +++ b/mail/ChangeLog @@ -1,3 +1,18 @@ +2000-04-22 Dan Winship <danw@helixcode.com> + + * folder-browser-factory.c: move msg_composer_cb and + msg_composer_send_cb to mail-ops. Attach send, reply, and "reply + to all" buttons. + + * mail-ops.c (composer_send_cb, send): moved from + folder-browser-factory.c. + (reply_to_sender, reply_to_all): new functions to do replies. + + * mail-format.c (text_to_html): Add an "add_pre" flag, to make + it wrap the output in <pre></pre>. + (mail_generate_reply): New function to create a composer and build + a reply in it. + 2000-04-21 Dan Winship <danw@helixcode.com> * mail-display.c (on_url_requested): deal with cid: URLs. diff --git a/mail/folder-browser-factory.c b/mail/folder-browser-factory.c index db828514c7..e86fddd9e9 100644 --- a/mail/folder-browser-factory.c +++ b/mail/folder-browser-factory.c @@ -100,41 +100,6 @@ development_warning () } static void -msg_composer_send_cb (EMsgComposer *composer, - gpointer data) -{ - CamelMimeMessage *message; - CamelStream *stream; - gint stdout_dup; - - message = e_msg_composer_get_message (composer); - - stdout_dup = dup (1); - stream = camel_stream_fs_new_with_fd (stdout_dup); - camel_data_wrapper_write_to_stream (CAMEL_DATA_WRAPPER (message), - stream); - camel_stream_close (stream); - - gtk_object_unref (GTK_OBJECT (message)); - -#if 0 - gtk_widget_destroy (GTK_WIDGET (composer)); - gtk_main_quit (); -#endif -} - - -static void -msg_composer_cb (BonoboUIHandler *uih, void *user_data, const char *path) -{ - GtkWidget *composer; - - composer = e_msg_composer_new (); - gtk_signal_connect (GTK_OBJECT (composer), "send", GTK_SIGNAL_FUNC (msg_composer_send_cb), NULL); - gtk_widget_show (composer); -} - -static void random_cb (GtkWidget *button, gpointer user_data) { printf ("Yow! I am called back!\n"); @@ -142,13 +107,13 @@ random_cb (GtkWidget *button, gpointer user_data) static GnomeUIInfo gnome_toolbar [] = { GNOMEUIINFO_ITEM_STOCK (N_("New mail"), N_("Check for new mail"), fetch_mail, GNOME_STOCK_PIXMAP_MAIL_RCV), - GNOMEUIINFO_ITEM_STOCK (N_("Send"), N_("Send a new message"), random_cb, GNOME_STOCK_PIXMAP_MAIL_SND), + GNOMEUIINFO_ITEM_STOCK (N_("Send"), N_("Send a new message"), send, GNOME_STOCK_PIXMAP_MAIL_SND), GNOMEUIINFO_ITEM_STOCK (N_("Find"), N_("Find messages"), random_cb, GNOME_STOCK_PIXMAP_SEARCH), GNOMEUIINFO_SEPARATOR, - GNOMEUIINFO_ITEM_STOCK (N_("Reply"), N_("Reply to the sender of this message"), random_cb, GNOME_STOCK_PIXMAP_SEARCH), - GNOMEUIINFO_ITEM_STOCK (N_("Reply to All"), N_("Reply to all recipients of this message"), random_cb, GNOME_STOCK_PIXMAP_MAIL_RPL), + GNOMEUIINFO_ITEM_STOCK (N_("Reply"), N_("Reply to the sender of this message"), reply_to_sender, GNOME_STOCK_PIXMAP_MAIL_RPL), + GNOMEUIINFO_ITEM_STOCK (N_("Reply to All"), N_("Reply to all recipients of this message"), reply_to_all, GNOME_STOCK_PIXMAP_MAIL_RPL), GNOMEUIINFO_ITEM_STOCK (N_("Forward"), N_("Forward this message"), random_cb, GNOME_STOCK_PIXMAP_MAIL_FWD), @@ -174,7 +139,7 @@ control_activate (BonoboControl *control, BonoboUIHandler *uih) bonobo_ui_handler_menu_new_item (uih, "/File/Mail", N_("_Mail"), NULL, -1, BONOBO_UI_HANDLER_PIXMAP_NONE, NULL, - 0, 0, msg_composer_cb, NULL); + 0, 0, send, NULL); folder_browser = bonobo_control_get_widget (control); diff --git a/mail/mail-format.c b/mail/mail-format.c index 328f2af638..5fdf3b2d79 100644 --- a/mail/mail-format.c +++ b/mail/mail-format.c @@ -30,12 +30,6 @@ #include <ctype.h> /* for isprint */ #include <string.h> /* for strstr */ -/* We shouldn't be doing this, but I don't feel like fixing it right - * now. (It's for gtk_html_stream_write.) When gtkhtml has nicer - * interfaces, we can fix it. - */ -#include <gtkhtml/gtkhtml-private.h> - static void handle_text_plain (CamelDataWrapper *wrapper, GtkHTMLStreamHandle *stream, CamelDataWrapper *root); @@ -69,6 +63,7 @@ static void handle_unknown_type (CamelDataWrapper *wrapper, static gchar *text_to_html (const guchar *input, guint len, guint *encoded_len_return, + gboolean add_pre, gboolean convert_newlines_to_br); /* writes the header info for a mime message into an html stream */ @@ -325,21 +320,21 @@ call_handler_function (CamelDataWrapper *wrapper, /* Convert plain text in equivalent-looking valid HTML. */ static gchar * text_to_html (const guchar *input, guint len, - guint *encoded_len_return, + guint *encoded_len_return, gboolean add_pre, gboolean convert_newlines_to_br) { const guchar *cur = input; guchar *buffer = NULL; guchar *out = NULL; gint buffer_size = 0; - guint count; /* Allocate a translation buffer. */ - buffer_size = len * 2; + buffer_size = len * 2 + 5; buffer = g_malloc (buffer_size); out = buffer; - count = 0; + if (add_pre) + out += sprintf (out, "<PRE>\n"); while (len--) { if (out - buffer > buffer_size - 100) { @@ -392,7 +387,10 @@ text_to_html (const guchar *input, guint len, cur++; } - *out = '\0'; + if (add_pre) + strcpy (out, "</PRE>"); + else + *out = '\0'; if (encoded_len_return) *encoded_len_return = out - buffer; @@ -411,7 +409,7 @@ write_field_to_stream (const gchar *description, const gchar *value, unsigned char *p; encoded_value = text_to_html (value, strlen(value), - NULL, TRUE); + NULL, FALSE, TRUE); for (p = (unsigned char *)encoded_value; *p; p++) { if (!isprint (*p)) *p = '?'; @@ -543,7 +541,7 @@ handle_text_plain (CamelDataWrapper *wrapper, GtkHTMLStreamHandle *stream, text = text_to_html (tmp_buffer, nb_bytes_read, &returned_strlen, - FALSE); + FALSE, FALSE); mail_write_html (stream, text); g_free (text); } @@ -835,3 +833,230 @@ mail_write_html (GtkHTMLStreamHandle *stream, const char *data) { gtk_html_stream_write (stream, data, strlen (data)); } + +static char * +get_data_wrapper_text (CamelDataWrapper *data) +{ + CamelStream *memstream; + GByteArray *ba; + char *text; + + ba = g_byte_array_new (); + memstream = camel_stream_mem_new_with_byte_array (ba, CAMEL_STREAM_MEM_WRITE); + + camel_data_wrapper_write_to_stream (data, memstream); + text = g_malloc (ba->len + 1); + memcpy (text, ba->data, ba->len); + text[ba->len] = '\0'; + + camel_stream_close (memstream); + return text; +} + +static char * +reply_body (CamelDataWrapper *data, gboolean *html) +{ + CamelMultipart *mp; + CamelMimePart *subpart; + int i, nparts; + char *subtext, *old; + const char *boundary, *disp; + char *text = NULL; + GMimeContentField *mime_type; + + /* We only include text, message, and multipart bodies. */ + mime_type = camel_data_wrapper_get_mime_type_field (data); + + if (strcasecmp (mime_type->type, "message") == 0) + return get_data_wrapper_text (data); + + if (strcasecmp (mime_type->type, "text") == 0) { + *html = !strcasecmp (mime_type->subtype, "html"); + return get_data_wrapper_text (data); + } + + /* If it's not message and it's not text, and it's not + * multipart, we don't want to deal with it. + */ + if (strcasecmp (mime_type->type, "multipart") != 0) + return NULL; + + mp = CAMEL_MULTIPART (data); + + if (strcasecmp (mime_type->subtype, "alternative") == 0) { + /* Pick our favorite alternative and reply to it. */ + + subpart = find_preferred_alternative (mp); + if (!subpart) + return NULL; + + return reply_body (camel_medium_get_content_object (CAMEL_MEDIUM (subpart)), html); + } + + nparts = camel_multipart_get_number (mp); + + /* If any subpart is HTML, pull it out and reply to it by itself. + * (If we supported any other non-plain text types, we'd do the + * same for them here.) + */ + for (i = 0; i < nparts; i++) { + subpart = CAMEL_MIME_PART (camel_multipart_get_part (mp, i)); + + if (strcasecmp (MIME_TYPE_SUB (subpart), "html") == 0) + return reply_body (camel_medium_get_content_object (CAMEL_MEDIUM (subpart)), html); + } + + /* Otherwise, concatenate all the parts that: + * - are text/plain or message + * - are not explicitly tagged with non-inline disposition + */ + boundary = camel_multipart_get_boundary (mp); + for (i = 0; i < nparts; i++) { + subpart = CAMEL_MIME_PART (camel_multipart_get_part (mp, i)); + + disp = camel_mime_part_get_disposition (subpart); + if (disp && strcasecmp (disp, "inline") != 0) + continue; + + subtext = get_data_wrapper_text (data); + if (text) { + old = text; + text = g_strdup_printf ("%s\n--%s\n%s", text, + boundary, subtext); + g_free (subtext); + g_free (old); + } else + text = subtext; + } + + if (!text) + return NULL; + + old = text; + text = g_strdup_printf ("%s\n--%s--\n", text, boundary); + g_free (old); + + return text; +} + +EMsgComposer * +mail_generate_reply (CamelMimeMessage *message, gboolean to_all) +{ + CamelDataWrapper *contents; + char *text, *subject; + EMsgComposer *composer; + gboolean html; + const char *repl_to, *message_id, *references; + GList *to, *cc; + + contents = camel_medium_get_content_object (CAMEL_MEDIUM (message)); + text = reply_body (contents, &html); + + composer = E_MSG_COMPOSER (e_msg_composer_new ()); + + /* Set the quoted reply text. */ + if (text) { + char *repl_text; + + if (html) { + repl_text = g_strdup_printf ("<blockquote><i>\n%s\n" + "</i></blockquote>\n", + text); + } else { + char *s, *d, *quoted_text; + int lines, len; + + /* Count the number of lines in the body. If + * the text ends with a \n, this will be one + * too high, but that's ok. Allocate enough + * space for the text and the "> "s. + */ + for (s = text, lines = 0; s; s = strchr (s + 1, '\n')) + lines++; + quoted_text = g_malloc (strlen (text) + lines * 2); + + s = text; + d = quoted_text; + + /* Copy text to quoted_text line by line, + * prepending "> ". + */ + while (1) { + len = strcspn (s, "\n"); + if (len == 0 && !*s) + break; + sprintf (d, "> %.*s\n", len, s); + s += len; + if (!*s++) + break; + d += len + 3; + } + + /* Now convert that to HTML. */ + repl_text = text_to_html (quoted_text, + strlen (quoted_text), + &len, TRUE, FALSE); + g_free (quoted_text); + } + e_msg_composer_set_body_text (composer, repl_text); + g_free (repl_text); + g_free (text); + } + + /* Set the recipients */ + repl_to = camel_mime_message_get_reply_to (message); + if (!repl_to) + repl_to = camel_mime_message_get_from (message); + to = g_list_append (NULL, repl_to); + + if (to_all) { + const GList *recip; + + recip = camel_mime_message_get_recipients (message, + CAMEL_RECIPIENT_TYPE_TO); + cc = g_list_copy (recip); + + recip = camel_mime_message_get_recipients (message, + CAMEL_RECIPIENT_TYPE_CC); + while (recip) { + cc = g_list_append (cc, recip->data); + recip = recip->next; + } + } else + cc = NULL; + + /* Set the subject of the new message. */ + subject = camel_mime_message_get_subject (message); + if (!subject) + subject = g_strdup (""); + else if (!strncasecmp (subject, "Re: ", 4)) + subject = g_strdup (subject); + else + subject = g_strdup_printf ("Re: %s", subject); + + e_msg_composer_set_headers (composer, to, cc, NULL, subject); + g_list_free (to); + g_list_free (cc); + g_free (subject); + + /* Add In-Reply-To and References. */ + message_id = camel_medium_get_header (CAMEL_MEDIUM (message), + "Message-Id"); + references = camel_medium_get_header (CAMEL_MEDIUM (message), + "References"); + if (message_id) { + e_msg_composer_add_header (composer, "In-Reply-To", + message_id); + if (references) { + char *reply_refs; + reply_refs = g_strdup_printf ("%s %s", references, + message_id); + e_msg_composer_add_header (composer, "References", + reply_refs); + g_free (reply_refs); + } + } else if (references) + e_msg_composer_add_header (composer, "References", references); + + return composer; +} diff --git a/mail/mail-format.h b/mail/mail-format.h index 87c16a2049..22c5f9deb2 100644 --- a/mail/mail-format.h +++ b/mail/mail-format.h @@ -32,6 +32,7 @@ extern "C" { #include <gtkhtml/gtkhtml.h> #include "camel/camel.h" +#include "composer/e-msg-composer.h" void mail_format_mime_message (CamelMimeMessage *mime_message, GtkHTMLStreamHandle *header_stream, @@ -39,11 +40,12 @@ void mail_format_mime_message (CamelMimeMessage *mime_message, void mail_write_html (GtkHTMLStreamHandle *stream, const char *data); -CamelMimeMessage *mail_generate_reply (CamelMimeMessage *mime_message); +EMsgComposer *mail_generate_reply (CamelMimeMessage *mime_message, + gboolean to_all); -CamelMimeMessage *mail_generate_forward (CamelMimeMessage *mime_message, - gboolean forward_as_attachment, - gboolean keep_attachments); +EMsgComposer *mail_generate_forward (CamelMimeMessage *mime_message, + gboolean forward_as_attachment, + gboolean keep_attachments); #ifdef __cplusplus } diff --git a/mail/mail-ops.c b/mail/mail-ops.c index 9a076c5856..9653b50fc6 100644 --- a/mail/mail-ops.c +++ b/mail/mail-ops.c @@ -31,6 +31,7 @@ #include "folder-browser.h" #include "session.h" #include "e-util/e-setup.h" +#include "composer/e-msg-composer.h" #ifndef HAVE_MKSTEMP #include <fcntl.h> @@ -250,3 +251,63 @@ fetch_mail (GtkWidget *button, gpointer user_data) if (msg) gtk_object_unref (GTK_OBJECT (msg)); } + + +static void +composer_send_cb (EMsgComposer *composer, gpointer data) +{ + CamelMimeMessage *message; + CamelStream *stream; + int stdout_dup; + + message = e_msg_composer_get_message (composer); + + stdout_dup = dup (1); + stream = camel_stream_fs_new_with_fd (stdout_dup); + camel_data_wrapper_write_to_stream (CAMEL_DATA_WRAPPER (message), + stream); + camel_stream_close (stream); + + gtk_object_unref (GTK_OBJECT (message)); + gtk_object_destroy (GTK_OBJECT (composer)); +} + + +void +send (GtkWidget *widget, gpointer user_data) +{ + GtkWidget *composer; + + composer = e_msg_composer_new (); + + gtk_signal_connect (GTK_OBJECT (composer), "send", + GTK_SIGNAL_FUNC (composer_send_cb), NULL); + gtk_widget_show (composer); +} + + +static void +reply (FolderBrowser *fb, gboolean to_all) +{ + EMsgComposer *composer; + + composer = mail_generate_reply (fb->mail_display->current_message, + to_all); + + gtk_signal_connect (GTK_OBJECT (composer), "send", + GTK_SIGNAL_FUNC (composer_send_cb), NULL); + + gtk_widget_show (GTK_WIDGET (composer)); +} + +void +reply_to_sender (GtkWidget *button, gpointer user_data) +{ + reply (FOLDER_BROWSER (user_data), FALSE); +} + +void +reply_to_all (GtkWidget *button, gpointer user_data) +{ + reply (FOLDER_BROWSER (user_data), TRUE); +} diff --git a/mail/mail-ops.h b/mail/mail-ops.h index ed85f4d5a0..f7f3d3e0c7 100644 --- a/mail/mail-ops.h +++ b/mail/mail-ops.h @@ -1 +1,5 @@ void fetch_mail (GtkWidget *button, gpointer user_data); +void send (GtkWidget *button, gpointer user_data); +void forward_msg (GtkWidget *button, gpointer user_data); +void reply_to_sender (GtkWidget *button, gpointer user_data); +void reply_to_all (GtkWidget *button, gpointer user_data); |