08c4631712be38751ca10473a69821c352033fc8
[modest] / src / gtk-glade / modest-ui-message-editor.c
1 #include <gtk/gtk.h>
2 #include <glade/glade.h>
3 #include <glib/gi18n.h>
4 #include <string.h>
5
6 #ifdef HAVE_CONFIG_H
7 #include <config.h>
8 #endif /*HAVE_CONFIG_H*/
9
10 /* TODO: put in auto* */
11 #include <tny-text-buffer-stream.h>
12 #include <tny-msg-folder.h>
13
14 #include "../modest-ui.h"
15 #include "../modest-window-mgr.h"
16 #include "../modest-account-mgr.h"
17 #include "../modest-account-mgr.h"
18 #include "../modest-identity-mgr.h"
19
20 #include "../modest-tny-account-store.h"
21 #include "../modest-tny-folder-tree-view.h"
22 #include "../modest-tny-header-tree-view.h"
23 #include "../modest-tny-msg-view.h"
24 #include "../modest-tny-transport-actions.h"
25 #include "../modest-tny-store-actions.h"
26
27 #include "../modest-text-utils.h"
28 #include "../modest-tny-msg-actions.h"
29
30 #include "../modest-editor-window.h"
31
32 #include "modest-ui-glade.h"
33 #include "modest-ui-wizard.h"
34
35 #include "modest-ui-message-editor.h"
36
37
38 static void on_attach_button_clicked (GtkWidget *widget, ModestEditorWindow *modest_editwin);
39
40 static void on_send_button_clicked (GtkWidget *widget, ModestEditorWindow *modest_editwin);
41
42
43 typedef struct {
44         ModestUI *modest_ui;
45         ModestEditorWindow *edit_win;
46         GladeXML *glade_xml;
47         GList *attachments;
48 } EditWinData;
49
50
51 static gboolean close_edit_confirm_dialog(ModestEditorWindow *edit_win)
52 {
53         GtkWidget *mdialog;
54         gint res;
55
56         mdialog = gtk_message_dialog_new(GTK_WINDOW(edit_win),
57                         GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
58                         GTK_MESSAGE_QUESTION,
59                         GTK_BUTTONS_YES_NO,
60                         _("Message was modified.\nDiscard Changes?"));
61         gtk_widget_show_all (mdialog);
62
63         res=gtk_dialog_run(GTK_DIALOG(mdialog));
64         gtk_widget_destroy (mdialog);
65         if (res == GTK_RESPONSE_YES)
66                 return TRUE;
67         else
68                 return FALSE;
69 }
70
71 static void
72 close_edit_window (GtkWidget *win, GdkEvent *event, gpointer data)
73 {
74         ModestEditorWindow *edit_win;
75         ModestUIPrivate *priv;
76         EditWinData *win_data;
77
78         edit_win = (ModestEditorWindow *)data;
79         win_data = modest_editor_window_get_data(edit_win);
80         priv = MODEST_UI_GET_PRIVATE(win_data->modest_ui);
81
82         // g_message("window was %s modified", modest_editor_window_get_modified(edit_win) ? "" : "not");
83
84         if (modest_editor_window_get_modified(edit_win)) {
85                 if (close_edit_confirm_dialog(edit_win)) {
86                         gtk_widget_hide (GTK_WIDGET(edit_win));
87                         modest_window_mgr_unregister(priv->modest_window_mgr, G_OBJECT(edit_win));
88                         gtk_widget_destroy(GTK_WIDGET(edit_win));
89                         g_message("closing window");
90                 } else {
91                         g_message("not closing window");
92                 }
93         } else {
94                 gtk_widget_hide (GTK_WIDGET(edit_win));
95                 modest_window_mgr_unregister(priv->modest_window_mgr, G_OBJECT(edit_win));
96                 gtk_widget_destroy(GTK_WIDGET(edit_win));
97                 g_message("closing window");
98         }
99 }
100
101
102 GtkContainer
103 *modest_ui_new_editor_window (ModestUI *modest_ui, gpointer *user_data)
104 {
105         GtkWidget       *top_container;
106         GladeXML                *glade_xml;
107         EditWinData             *win_data;
108
109         glade_xml = glade_xml_new(MODEST_GLADE, "new_mail_top_container", NULL);
110         if (!glade_xml)
111                 return NULL;
112
113         win_data = g_malloc(sizeof(EditWinData));
114         win_data->modest_ui = modest_ui;
115         win_data->glade_xml = glade_xml;
116         win_data->attachments = NULL;
117
118         *user_data = win_data;
119
120         top_container = glade_xml_get_widget(glade_xml, "new_mail_top_container");
121         if (!top_container) {
122                 g_object_unref(G_OBJECT(glade_xml));
123                 return NULL;
124         }
125         
126         return GTK_CONTAINER(top_container);
127 }
128
129
130 gboolean
131 modest_ui_editor_window_set_to_header(const gchar *to, gpointer window_data)
132 {
133         GladeXML *glade_xml;
134         GtkWidget *w;
135         EditWinData *win_data;
136
137         win_data = (EditWinData *)window_data;
138         glade_xml = win_data->glade_xml;
139         w = glade_xml_get_widget(glade_xml, "to_entry");
140         gtk_entry_set_text(GTK_ENTRY(w), to);
141
142         return TRUE;
143 }
144
145
146 gboolean
147 modest_ui_editor_window_set_cc_header(const gchar *cc, gpointer window_data)
148 {
149         GladeXML *glade_xml;
150         // GtkWidget *w;
151         EditWinData *win_data;
152
153         win_data = (EditWinData *)window_data;
154         glade_xml = win_data->glade_xml;
155 /*
156         w = glade_xml_get_widget(glade_xml, "cc_entry");
157         gtk_entry_set_text(GTK_ENTRY(w), cc);
158 */
159         return TRUE;
160 }
161
162
163 gboolean
164 modest_ui_editor_window_set_bcc_header(const gchar *bcc, gpointer window_data)
165 {
166         GladeXML *glade_xml;
167         // GtkWidget *w;
168         EditWinData *win_data;
169
170         win_data = (EditWinData *)window_data;
171         glade_xml = win_data->glade_xml;
172 /*
173         w = glade_xml_get_widget(glade_xml, "bcc_entry");
174         gtk_entry_set_text(GTK_ENTRY(w), bcc);
175 */
176         return TRUE;
177 }
178
179
180 gboolean
181 modest_ui_editor_window_set_subject_header(const gchar *subject, gpointer window_data)
182 {
183         GladeXML *glade_xml;
184         GtkWidget *w;
185         EditWinData *win_data;
186
187         win_data = (EditWinData *)window_data;
188         glade_xml = win_data->glade_xml;
189
190         w = glade_xml_get_widget(glade_xml, "subject_entry");
191         gtk_entry_set_text(GTK_ENTRY(w), subject);
192
193         return TRUE;
194 }
195
196
197 gboolean
198 modest_ui_editor_window_set_body(const gchar *body, gpointer window_data)
199 {
200         GladeXML *glade_xml;
201         GtkWidget *body_view;
202         GtkTextBuffer *buf;
203         EditWinData *win_data;
204
205         win_data = (EditWinData *)window_data;
206         glade_xml = win_data->glade_xml;
207
208         body_view = glade_xml_get_widget(glade_xml, "body_view");
209         buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(body_view));
210
211         gtk_text_buffer_set_text(GTK_TEXT_BUFFER(buf), body, -1);
212
213         return TRUE;
214 }
215
216
217 gboolean
218 modest_ui_editor_window_update_attachments(gpointer window_data)
219 {
220         GladeXML *glade_xml;
221         
222         glade_xml = ((EditWinData *) window_data)->glade_xml;
223
224         //body_view = glade_xml_get_widget(glade_xml, "body_view");
225         
226         return TRUE;
227 }
228
229
230 static void on_editor_entry_changed(GtkEditable *editable,
231                                             gpointer     user_data)
232 {
233         GtkWidget *edit_win;
234         EditWinData *windata;
235
236         edit_win = (GtkWidget *)user_data;
237         windata = (EditWinData *)modest_editor_window_get_data(MODEST_EDITOR_WINDOW(edit_win));
238
239         modest_editor_window_set_modified(MODEST_EDITOR_WINDOW(edit_win), TRUE);
240 }
241
242
243 static void on_editor_buffer_changed (GtkTextBuffer *textbuffer,
244                                             gpointer       user_data)
245 {
246         GtkWidget *edit_win;
247         
248         edit_win = (GtkWidget *)user_data;
249         modest_editor_window_set_modified(MODEST_EDITOR_WINDOW(edit_win), TRUE);
250 }
251
252
253 static void
254 new_editor_with_presets (ModestUI *modest_ui, const gchar *to_header,
255                                                         const gchar *cc_header, const gchar *bcc_header,
256                                                         const gchar *subject_header, const gchar *body)
257 {
258         GtkWidget *edit_win;
259         GladeXML *glade_xml;
260         GtkWidget *btn, *w;
261         GtkTextBuffer *buf;
262         EditWinData *windata;
263         ModestUIPrivate *priv;
264         gint height, width;
265
266         g_return_if_fail (modest_ui);
267
268         edit_win = modest_editor_window_new(modest_ui);
269         windata = (EditWinData *)modest_editor_window_get_data(MODEST_EDITOR_WINDOW(edit_win));
270         g_return_if_fail(windata);
271
272         glade_xml = windata->glade_xml;
273         btn = glade_xml_get_widget (glade_xml, "toolb_send");
274         g_signal_connect (btn, "clicked", G_CALLBACK(on_send_button_clicked),
275                           edit_win);
276         btn = glade_xml_get_widget (glade_xml, "toolb_attach");
277         g_signal_connect (btn, "clicked", G_CALLBACK(on_attach_button_clicked),
278                           edit_win);
279
280         w = glade_xml_get_widget (glade_xml, "to_entry");
281         g_signal_connect(w, "changed", G_CALLBACK(on_editor_entry_changed), edit_win);
282         w = glade_xml_get_widget (glade_xml, "subject_entry");
283         g_signal_connect(w, "changed", G_CALLBACK(on_editor_entry_changed), edit_win);
284         w = glade_xml_get_widget (glade_xml, "body_view");
285         buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(w));
286         g_signal_connect(buf, "changed", G_CALLBACK(on_editor_buffer_changed), edit_win);
287
288         g_signal_connect (edit_win, "destroy-event", G_CALLBACK(close_edit_window),
289                           edit_win);
290         g_signal_connect (edit_win, "delete-event", G_CALLBACK(close_edit_window),
291                           edit_win);
292
293         priv = MODEST_UI_GET_PRIVATE(modest_ui);
294         height = modest_conf_get_int (priv->modest_conf,
295                                           MODEST_CONF_EDIT_WINDOW_HEIGHT, NULL);
296         width  = modest_conf_get_int (priv->modest_conf,
297                                           MODEST_CONF_EDIT_WINDOW_WIDTH, NULL);
298
299         // g_message("new editor win@%dx%d", width, height);
300
301         gtk_widget_set_usize (GTK_WIDGET(edit_win), width, height);
302         if (strlen(subject_header) > 0)
303                 gtk_window_set_title (GTK_WINDOW(edit_win), subject_header);
304         else
305                 gtk_window_set_title (GTK_WINDOW(edit_win), _("Untitled"));
306
307         modest_window_mgr_register(priv->modest_window_mgr, G_OBJECT(edit_win), MODEST_EDIT_WINDOW, 0);
308
309         modest_editor_window_set_to_header(MODEST_EDITOR_WINDOW(edit_win), to_header);
310         modest_editor_window_set_cc_header(MODEST_EDITOR_WINDOW(edit_win), cc_header);
311         modest_editor_window_set_bcc_header(MODEST_EDITOR_WINDOW(edit_win), bcc_header);
312         modest_editor_window_set_subject_header(MODEST_EDITOR_WINDOW(edit_win), subject_header);
313         modest_editor_window_set_body(MODEST_EDITOR_WINDOW(edit_win), body);
314
315         modest_editor_window_set_modified(MODEST_EDITOR_WINDOW(edit_win), FALSE);
316
317         gtk_widget_show(edit_win);
318 }
319
320 #if 1
321 void
322 on_new_mail_clicked (GtkWidget *widget, ModestUI *modest_ui)
323 {
324         new_editor_with_presets(modest_ui, "", "", "", "", "");
325 }
326 #else
327 void
328 on_new_mail_clicked (GtkWidget *widget, ModestUI *modest_ui)
329 {
330         GtkWidget *edit_win;
331         GladeXML *glade_xml;
332         GtkWidget *btn, *w;
333         GtkTextBuffer *buf;
334         EditWinData *windata;
335         ModestUIPrivate *priv;
336         gint height, width;
337
338         g_return_if_fail (modest_ui);
339         //modest_ui_new_edit_window (modest_ui, "", "", "", "", "", NULL);
340
341         edit_win = modest_editor_window_new(modest_ui);
342         windata = (EditWinData *)modest_editor_window_get_data(MODEST_EDITOR_WINDOW(edit_win));
343         g_return_if_fail(windata);
344
345         windata->edit_win = MODEST_EDITOR_WINDOW(edit_win);
346         glade_xml = windata->glade_xml;
347         btn = glade_xml_get_widget (glade_xml, "toolb_send");
348         g_signal_connect (btn, "clicked", G_CALLBACK(on_send_button_clicked),
349                           edit_win);
350         btn = glade_xml_get_widget (glade_xml, "toolb_attach");
351         g_signal_connect (btn, "clicked", G_CALLBACK(on_attach_button_clicked),
352                           edit_win);
353
354         w = glade_xml_get_widget (glade_xml, "to_entry");
355         g_signal_connect(w, "changed", G_CALLBACK(on_editor_entry_changed), edit_win);
356         w = glade_xml_get_widget (glade_xml, "subject_entry");
357         g_signal_connect(w, "changed", G_CALLBACK(on_editor_entry_changed), edit_win);
358         w = glade_xml_get_widget (glade_xml, "body_view");
359         buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(w));
360         gtk_text_buffer_set_text(buf, "", -1);
361         g_signal_connect(buf, "changed", G_CALLBACK(on_editor_buffer_changed), edit_win);
362
363         g_signal_connect (edit_win, "destroy-event", G_CALLBACK(close_edit_window),
364                           edit_win);
365         g_signal_connect (edit_win, "delete-event", G_CALLBACK(close_edit_window),
366                           edit_win);
367
368         priv = MODEST_UI_GET_PRIVATE(windata->modest_ui);
369         height = modest_conf_get_int (priv->modest_conf,
370                                           MODEST_CONF_EDIT_WINDOW_HEIGHT, NULL);
371         width  = modest_conf_get_int (priv->modest_conf,
372                                           MODEST_CONF_EDIT_WINDOW_WIDTH, NULL);
373
374         // g_message("new editor win@%dx%d", width, height);
375
376         gtk_widget_set_usize (GTK_WIDGET(edit_win), width, height);
377         gtk_window_set_title (GTK_WINDOW(edit_win), _("Untitled"));
378         modest_window_mgr_register(priv->modest_window_mgr, G_OBJECT(edit_win), MODEST_EDIT_WINDOW, 0);
379         gtk_widget_show(edit_win);
380 }
381 #endif
382
383 void
384 quoted_send_msg (ModestUI *modest_ui, quoted_send_type qstype)
385 {
386         GtkTreeSelection *sel;
387         GtkWidget *paned;
388         GtkTreeModel *model;
389         GtkTreeIter iter;
390         GtkScrolledWindow *scroll;
391
392         TnyMsgHeaderIface *header;
393
394         ModestTnyHeaderTreeView *header_view;
395         ModestTnyMsgView *msg_view;
396         ModestUIPrivate *priv;
397
398         const TnyMsgIface *msg;
399         const TnyMsgFolderIface *folder;
400         GString *re_sub;
401         const gchar *subject, *from;
402         gchar *unquoted, *quoted;
403         time_t sent_date;
404         gint line_limit = 76;
405
406         g_return_if_fail (modest_ui);
407
408         priv = MODEST_UI_GET_PRIVATE(modest_ui);
409
410         paned = glade_xml_get_widget (priv->glade_xml,"mail_paned");
411         g_return_if_fail (paned);
412
413         scroll = GTK_SCROLLED_WINDOW(gtk_paned_get_child1 (GTK_PANED(paned)));
414         g_return_if_fail (scroll);
415
416         msg_view = MODEST_TNY_MSG_VIEW(gtk_paned_get_child2 (GTK_PANED(paned)));
417         g_return_if_fail (msg_view);
418
419         header_view = MODEST_TNY_HEADER_TREE_VIEW(gtk_bin_get_child (GTK_BIN(scroll)));
420         g_return_if_fail (header_view);
421
422         sel = gtk_tree_view_get_selection (GTK_TREE_VIEW(header_view));
423         g_return_if_fail (sel);
424
425         if (!gtk_tree_selection_get_selected (sel, &model, &iter)) {
426                 g_warning("nothing to reply to");
427                 return;
428         }
429
430         gtk_tree_model_get (model, &iter,
431                             TNY_MSG_HEADER_LIST_MODEL_INSTANCE_COLUMN,
432                             &header, -1);
433
434         if (!header) {
435                 g_warning("no header");
436                 return;
437         }
438
439         folder = tny_msg_header_iface_get_folder (TNY_MSG_HEADER_IFACE(header));
440         if (!folder) {
441                 g_warning ("cannot find folder");
442                 return;
443         }
444
445         msg = tny_msg_folder_iface_get_message (TNY_MSG_FOLDER_IFACE(folder), header);
446         if (!msg) {
447                 g_warning ("cannot find msg");
448                 return;
449         }
450
451         subject = tny_msg_header_iface_get_subject(header);
452         re_sub = g_string_new(subject);
453         /* FIXME: honor replyto, cc */
454         from = tny_msg_header_iface_get_from(header);
455         sent_date = tny_msg_header_iface_get_date_sent(header);
456
457         unquoted = modest_tny_msg_view_get_selected_text(msg_view);
458         quoted = modest_tny_msg_actions_quote(msg, from, sent_date, line_limit, unquoted);
459
460         switch (qstype) {
461                 case QUOTED_SEND_REPLY:
462                         g_string_prepend(re_sub, _("Re: "));
463                         new_editor_with_presets(modest_ui, from, /* cc */ "", /* bcc */ "", re_sub->str, quoted);
464                         break;
465                 case QUOTED_SEND_FORWARD:
466                         g_string_prepend(re_sub, _("Fwd: "));
467                         new_editor_with_presets(modest_ui, /* from */ "", /* cc */ "", /* bcc */ "", re_sub->str, quoted);
468                         break;
469                 default:
470                         break;
471         }
472         g_free(quoted);
473         g_free(unquoted);
474         g_string_free(re_sub, TRUE);
475 }
476
477
478 static void
479 on_attach_button_clicked (GtkWidget *widget, ModestEditorWindow *modest_editwin)
480 {
481         /* open file selector */
482         GtkWidget *dialog;
483         gchar *mime_type;
484         gchar *filename = NULL;
485         
486         dialog = gtk_file_chooser_dialog_new ("Open File",
487                                                                                   GTK_WINDOW(modest_editwin),
488                                                                                   GTK_FILE_CHOOSER_ACTION_OPEN,
489                                                                                   GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
490                                                                                   GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
491                                                                                   NULL);
492
493         if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
494         {
495
496                 filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
497                 printf ("file:%s\n", filename);
498         }
499         gtk_widget_destroy (dialog);
500       
501         /* check file */
502         if (!filename)
503                 return;
504         
505         g_return_if_fail(g_str_has_suffix(filename, ".jpg")); /* for now... */
506         
507         /* get mime type */
508         mime_type = "image/jpeg";
509         
510         /* attach file */
511         
512         modest_editor_window_attach_file(modest_editwin, filename);
513         
514         g_free (filename);
515 }
516
517
518 static void
519 on_send_button_clicked (GtkWidget *widget, ModestEditorWindow *modest_editwin)
520 {
521         ModestTnyTransportActions *actions;
522         ModestUI *modest_ui;
523         ModestUIPrivate *priv;
524         GtkWidget *to_entry, *subject_entry, *body_view;
525         const gchar *to, *subject, *email_from;
526         gchar *body;
527         GtkTextIter start, end;
528         GtkTextBuffer *buf;
529         TnyAccountStoreIface *account_store;
530         const GList *transport_accounts;
531         TnyTransportAccountIface *transport_account;
532         ModestIdentityMgr *id_mgr;
533         EditWinData *win_data;
534         GList * attachments;
535
536
537         win_data = modest_editor_window_get_data(modest_editwin);
538         modest_ui = win_data->modest_ui;
539
540         g_return_if_fail (modest_ui);
541
542         actions = MODEST_TNY_TRANSPORT_ACTIONS
543                 (modest_tny_transport_actions_new ());
544
545         priv = MODEST_UI_GET_PRIVATE(modest_ui);
546
547         account_store = priv->account_store;
548         transport_accounts =
549                 tny_account_store_iface_get_transport_accounts (account_store);
550         if (!transport_accounts) {
551                 g_message ("cannot send message: no transport account defined");
552                 return;
553         } else /* take the first one! */
554                 transport_account =
555                         TNY_TRANSPORT_ACCOUNT_IFACE(transport_accounts->data);
556
557         to_entry      = glade_xml_get_widget (win_data->glade_xml, "to_entry");
558         subject_entry = glade_xml_get_widget (win_data->glade_xml, "subject_entry");
559         body_view     = glade_xml_get_widget (win_data->glade_xml, "body_view");
560
561         to      = gtk_entry_get_text (GTK_ENTRY(to_entry));
562         subject = gtk_entry_get_text (GTK_ENTRY(subject_entry));
563
564         buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(body_view));
565         gtk_text_buffer_get_bounds (buf, &start, &end);
566         body    = gtk_text_buffer_get_text (buf, &start, &end, FALSE);
567
568         id_mgr = priv->modest_id_mgr;
569         email_from = modest_identity_mgr_get_identity_string(id_mgr,
570                                                              MODEST_IDENTITY_DEFAULT_IDENTITY,
571                                                              MODEST_IDENTITY_EMAIL, NULL);
572         attachments = modest_editor_window_get_attachments(modest_editwin);
573         /* while (attachments) {
574                 printf("att: %s\n", (gchar *) attachments->data);
575                 attachments = attachments->next;
576         } */
577         if (!email_from)
578                 email_from = "";
579         
580         g_message("sending \"%s\" %s ==> %s", subject, email_from, to);
581
582         modest_tny_transport_actions_send_message (actions,
583                                                    transport_account,
584                                                    email_from,
585                                                    to, "", "", subject,
586                                                    body,
587                                                    attachments);
588
589         g_free (body);
590         g_object_unref (G_OBJECT(actions));
591
592         gtk_widget_hide (GTK_WIDGET(modest_editwin));
593         modest_window_mgr_unregister(priv->modest_window_mgr, G_OBJECT(modest_editwin));
594         if (GTK_IS_WIDGET(modest_editwin)) {
595                 gtk_widget_destroy(GTK_WIDGET(modest_editwin));
596         } else
597                 g_warning("editor window has vanished!");
598 }