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