From f5ec554c152ece6b2cac94f030760df4b53bb1c7 Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Sat, 22 Apr 2000 18:07:14 +0000 Subject: move msg_composer_cb and msg_composer_send_cb to mail-ops. Attach send, * 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
.
	(mail_generate_reply): New function to create a composer and build
	a reply in it.

svn path=/trunk/; revision=2554
---
 mail/ChangeLog                |  15 +++
 mail/folder-browser-factory.c |  43 +-------
 mail/mail-format.c            | 251 +++++++++++++++++++++++++++++++++++++++---
 mail/mail-format.h            |  10 +-
 mail/mail-ops.c               |  61 ++++++++++
 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  
+
+	* 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 
.
+	(mail_generate_reply): New function to create a composer and build
+	a reply in it.
+
 2000-04-21  Dan Winship  
 
 	* 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
@@ -99,41 +99,6 @@ development_warning ()
 	return result;
 } 
 
-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)
 {
@@ -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     /* for isprint */
 #include    /* 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 
-
 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, "
\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, "
"); + 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 ("
\n%s\n" + "
\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 #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 @@ -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); -- cgit