a64626250da591cbefe847322619c5a09284357f
[modest] / src / modest-tny-msg-actions.c
1 /* Copyright (c) 2006, Nokia Corporation
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  *   notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  *   notice, this list of conditions and the following disclaimer in the
12  *   documentation and/or other materials provided with the distribution.
13  * * Neither the name of the Nokia Corporation nor the names of its
14  *   contributors may be used to endorse or promote products derived from
15  *   this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30
31 /* modest-ui.c */
32
33 #include <gtk/gtk.h>
34 #include <gtkhtml/gtkhtml.h>
35
36 /* TODO: put in auto* */
37 #include <tny-text-buffer-stream.h>
38 #include <tny-msg-mime-part-iface.h>
39 #include <tny-msg-iface.h>
40
41 #ifdef HAVE_CONFIG_H
42 #include <config.h>
43 #endif /*HAVE_CONFIG_H */
44
45 #include "modest-tny-msg-actions.h"
46 #include "modest-text-utils.h"
47
48
49 /* private */
50 static gchar *quote_msg (const TnyMsgIface * src, const gchar * from,
51                          time_t sent_date, gint limit, gboolean textorhtml);
52 static GtkTextBuffer *htmltotext (TnyMsgMimePartIface * body);
53
54
55 static GtkTextBuffer *
56 htmltotext (TnyMsgMimePartIface * body)
57 {
58         GtkTextBuffer *buf;
59
60 #ifdef ACTIVATE_HACKS /* it still doesn't work, don't bother! */
61         GtkWidget *html, *win;
62         TnyStreamIface *stream;
63         GtkClipboard *clip;
64         gchar *text;
65
66         win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
67         html = gtk_html_new ();
68         gtk_container_add (GTK_CONTAINER (win), html);
69
70         gtk_html_set_editable (GTK_HTML (html), FALSE);
71         gtk_html_allow_selection (GTK_HTML (html), TRUE);
72         stream = TNY_STREAM_IFACE (modest_tny_stream_gtkhtml_new
73                                    (gtk_html_begin (GTK_HTML (html))));
74
75         tny_stream_iface_reset (stream);
76         tny_msg_mime_part_iface_decode_to_stream (body, stream);
77         tny_stream_iface_reset (stream);
78         g_object_unref (G_OBJECT (stream));
79
80         gtk_widget_show_all (win);
81         gtk_html_select_all (GTK_HTML (html));
82         clip = gtk_widget_get_clipboard (html, GDK_SELECTION_PRIMARY);
83         /*clip = gtk_widget_get_clipboard(html, GDK_SELECTION_CLIPBOARD);*/
84         text = gtk_clipboard_wait_for_text (clip);
85
86         buf = gtk_text_buffer_new (NULL);
87         gtk_text_buffer_set_text (buf, text, -1);
88         g_free (text);
89         /* destroy win & html */
90 #else
91         buf = gtk_text_buffer_new (NULL);
92 #endif
93         return buf;
94 }
95
96 gchar *
97 modest_tny_msg_actions_quote (const TnyMsgIface * self, const gchar * from,
98                               time_t sent_date, gint limit,
99                               const gchar * to_quote)
100 {
101         gchar *quoted;
102
103         /* 3 cases: */
104
105         /* a) quote text from selection */
106         if (to_quote != NULL) 
107                 return modest_text_utils_quote (to_quote, from, sent_date,
108                                                 limit);
109         
110         /* b) try to find a text/plain part in the msg and quote it */
111         quoted = quote_msg (self, from, sent_date, limit, FALSE);
112         if (quoted)
113                 return quoted;
114         
115         /* c) if that fails, try text/html */
116         return quote_msg (self, from, sent_date, limit, TRUE);
117 }
118
119
120 static gchar *
121 quote_msg (const TnyMsgIface * src, const gchar * from, time_t sent_date,
122            gint limit, gboolean want_html)
123 {
124         TnyStreamIface *stream;
125         TnyMsgMimePartIface *body;
126         GtkTextBuffer *buf;
127         GtkTextIter start, end;
128         const gchar *to_quote;
129         gchar *quoted;
130
131         /* the cast makes me uneasy... */
132         body = modest_tny_msg_actions_find_body_part((TnyMsgIface *) src, want_html);
133         if (!body)
134                 return NULL;
135
136         if (want_html) 
137                 buf = htmltotext (body);
138         else {
139                 buf = gtk_text_buffer_new (NULL);
140                 stream = TNY_STREAM_IFACE (tny_text_buffer_stream_new (buf));
141                 tny_stream_iface_reset (stream);
142                 tny_msg_mime_part_iface_decode_to_stream (body, stream);
143                 tny_stream_iface_reset (stream);
144                 g_object_unref (stream);
145         }
146         
147         gtk_text_buffer_get_bounds (buf, &start, &end);
148         to_quote = gtk_text_buffer_get_text (buf, &start, &end, FALSE);
149         quoted = modest_text_utils_quote (to_quote, from, sent_date, limit);
150         g_object_unref (buf);
151
152         return quoted;
153 }
154
155
156 TnyMsgMimePartIface *
157 modest_tny_msg_actions_find_body_part (TnyMsgIface *self, gboolean want_html)
158 {
159         const gchar *mime_type = want_html ? "text/html" : "text/plain";
160         TnyMsgMimePartIface *part = NULL;
161         GList *parts;
162         
163         g_return_val_if_fail (self, NULL);
164         g_return_val_if_fail (mime_type, NULL);
165
166         parts  = (GList*) tny_msg_iface_get_parts (self);
167         while (parts && !part) {
168
169                 part = TNY_MSG_MIME_PART_IFACE(parts->data);
170
171                 if (!tny_msg_mime_part_iface_content_type_is (part, mime_type)
172                     ||tny_msg_mime_part_iface_is_attachment (part))
173                         part = NULL;
174                 parts = parts->next;
175         }
176
177         /* if were trying to find an HTML part and could find it,
178          * try to find a text/plain part instead
179          */
180         if (!part && want_html) 
181                 return modest_tny_msg_actions_find_body_part (self, FALSE);
182         else
183                 return part;
184 }