Delete message does not copy it to the Trash, still unimplemented
[modest] / src / modest-ui-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 #ifdef HAVE_CONFIG_H
31 #include <config.h>
32 #endif /*HAVE_CONFIG_H*/
33
34 #include <glib/gi18n.h>
35 #include <string.h>
36 #include <modest-runtime.h>
37 #include <modest-tny-msg.h>
38 #include <modest-tny-account.h>
39
40 #include "modest-ui-actions.h"
41
42 #include "modest-tny-platform-factory.h"
43
44 #include <widgets/modest-main-window.h>
45 #include <widgets/modest-msg-view-window.h>
46 #include <widgets/modest-account-view-window.h>
47
48 #include "modest-account-mgr-helpers.h"
49 #include "modest-mail-operation.h"
50 #include <modest-widget-memory.h>
51 #include <tny-error.h>
52 #include <tny-simple-list.h>
53 #include <tny-msg-view.h>
54 #include <tny-device.h>
55
56
57 typedef struct _GetMsgAsyncHelper {
58         ModestWindow *window;
59         TnyIterator *iter;
60         GFunc func;
61         gpointer user_data;
62 } GetMsgAsyncHelper;
63
64 typedef enum _ReplyForwardAction {
65         ACTION_REPLY,
66         ACTION_REPLY_TO_ALL,
67         ACTION_FORWARD
68 } ReplyForwardAction;
69
70 typedef struct _ReplyForwardHelper {
71 guint reply_forward_type;
72         ReplyForwardAction action;
73         gchar *account_name;
74 } ReplyForwardHelper;
75
76
77 static void     reply_forward_func     (gpointer data, gpointer user_data);
78 static void     read_msg_func          (gpointer data, gpointer user_data);
79 static void     get_msg_cb             (TnyFolder *folder, TnyMsg *msg, GError **err, 
80                                         gpointer user_data);
81 static void     reply_forward          (GtkWidget *widget, ReplyForwardAction action,
82                                         ModestWindow *win);
83 static gchar*   ask_for_folder_name    (GtkWindow *parent_window, const gchar *title);
84
85
86 void   
87 modest_ui_actions_on_about (GtkWidget *widget, ModestWindow *win)
88 {
89         GtkWidget *about;
90         const gchar *authors[] = {
91                 "Dirk-Jan C. Binnema <dirk-jan.binnema@nokia.com>",
92                 NULL
93         };
94         about = gtk_about_dialog_new ();
95         gtk_about_dialog_set_name (GTK_ABOUT_DIALOG(about), PACKAGE_NAME);
96         gtk_about_dialog_set_version (GTK_ABOUT_DIALOG(about),PACKAGE_VERSION);
97         gtk_about_dialog_set_copyright (GTK_ABOUT_DIALOG(about),
98                                         _("Copyright (c) 2006, Nokia Corporation\n"
99                                           "All rights reserved."));
100         gtk_about_dialog_set_comments (GTK_ABOUT_DIALOG(about),
101                                        _("a modest e-mail client\n\n"
102                                          "design and implementation: Dirk-Jan C. Binnema\n"
103                                          "contributions from the fine people at KernelConcepts and Igalia\n"
104                                          "uses the tinymail email framework written by Philip van Hoof"));
105         gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG(about), authors);
106         gtk_about_dialog_set_website (GTK_ABOUT_DIALOG(about), "http://modest.garage.maemo.org");
107         
108         gtk_dialog_run (GTK_DIALOG (about));
109         gtk_widget_destroy(about);
110 }
111
112
113 static TnyList *
114 get_selected_headers (ModestWindow *win)
115 {
116         if (MODEST_IS_MAIN_WINDOW(win)) {
117                 GtkWidget *header_view;         
118                 
119                 header_view = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW(win),
120                                                                    MODEST_WIDGET_TYPE_HEADER_VIEW);
121                 return modest_header_view_get_selected_headers (MODEST_HEADER_VIEW(header_view));
122                 
123         } else if (MODEST_IS_MSG_VIEW_WINDOW (win)) {
124                 /* for MsgViewWindows, we simply return a list with one element */
125                 TnyMsg *msg;
126                 TnyHeader *header;
127                 TnyList *list = NULL;
128                 
129                 msg  = modest_msg_view_window_get_message (MODEST_MSG_VIEW_WINDOW(win));
130                 if (msg) {
131                         header = tny_msg_get_header (msg);
132                         list = tny_simple_list_new ();
133                         tny_list_prepend (list, G_OBJECT(header));
134                         g_object_unref (G_OBJECT(header));
135                 }
136                 return list;
137
138         } else
139                 return NULL;
140 }
141
142 void
143 modest_ui_actions_on_delete (GtkWidget *widget, ModestWindow *win)
144 {
145         TnyList *header_list;
146         TnyIterator *iter;
147
148         g_return_if_fail (MODEST_IS_WINDOW(win));
149                 
150         header_list = get_selected_headers (win);
151         
152         if (header_list) {
153                 iter = tny_list_create_iterator (header_list);
154                 do {
155                         TnyHeader *header;
156                         ModestMailOperation *mail_op;
157
158                         header = TNY_HEADER (tny_iterator_get_current (iter));
159                         /* TODO: thick grain mail operation involving
160                            a list of objects. Composite pattern ??? */
161                         mail_op = modest_mail_operation_new ();
162
163                         /* TODO: add confirmation dialog */
164
165                         /* Move to trash. TODO: Still not supported */
166                         modest_mail_operation_remove_msg (mail_op, header, FALSE);
167
168                         if (modest_mail_operation_get_status (mail_op) !=
169                             MODEST_MAIL_OPERATION_STATUS_SUCCESS) {
170                                 const GError *error;
171                                 error = modest_mail_operation_get_error (mail_op);
172                                 if (error)
173                                         g_warning (error->message);
174                         }
175
176                         g_object_unref (G_OBJECT (mail_op));
177                         g_object_unref (header);
178                         tny_iterator_next (iter);
179
180                 } while (!tny_iterator_is_done (iter));
181         }
182 }
183
184
185 void
186 modest_ui_actions_on_quit (GtkWidget *widget, ModestWindow *win)
187 {
188         /* FIXME: save size of main window */
189 /*      save_sizes (main_window); */
190         gtk_widget_destroy (GTK_WIDGET (win));
191 }
192
193 void
194 modest_ui_actions_on_accounts (GtkWidget *widget, ModestWindow *win)
195 {
196         GtkWidget *account_win;
197         account_win = modest_account_view_window_new ();
198
199         if (win)
200                 gtk_window_set_transient_for (GTK_WINDOW (account_win), GTK_WINDOW (win));
201
202         gtk_widget_show (account_win);
203 }
204
205 void
206 modest_ui_actions_on_new_msg (GtkWidget *widget, ModestWindow *win)
207 {
208         ModestWindow *msg_win;
209         TnyMsg *msg = NULL;
210         TnyFolder *folder = NULL;
211         gchar *account_name = NULL;
212         gchar *from_str = NULL;
213         GError *err = NULL;
214         TnyAccount *account;
215         
216         account_name = g_strdup(modest_window_get_active_account (win));
217         if (!account_name)
218                 account_name = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr());
219         
220         account = modest_tny_account_store_get_tny_account_by_account (modest_runtime_get_account_store(),
221                                                                        account_name,
222                                                                        TNY_ACCOUNT_TYPE_STORE);
223         if (!account) {
224                 g_printerr ("modest: failed to get tnyaccount for '%s'\n", account_name);
225                 goto cleanup;
226         }
227
228         from_str = modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(), account_name);
229
230         msg    = modest_tny_msg_new ("", from_str, "", "", "", "", NULL);
231         if (!msg) {
232                 g_printerr ("modest: failed to create new msg\n");
233                 goto cleanup;
234         }
235         
236         folder = modest_tny_account_get_special_folder (account, TNY_FOLDER_TYPE_DRAFTS);
237         if (!folder) {
238                 g_printerr ("modest: failed to find Drafts folder\n");
239                 goto cleanup;
240         }
241         
242         tny_folder_add_msg (folder, msg, &err);
243         if (err) {
244                 g_printerr ("modest: error adding msg to Drafts folder: %s",
245                             err->message);
246                 g_error_free (err);
247                 goto cleanup;
248         }
249
250         msg_win = modest_msg_edit_window_new (msg, account_name);
251         if (win)
252                 gtk_window_set_transient_for (GTK_WINDOW (msg_win),
253                                               GTK_WINDOW (win));        
254         gtk_widget_show_all (GTK_WIDGET (msg_win));
255
256 cleanup:
257         g_free (account_name);
258         g_free (from_str);
259         if (account)
260                 g_object_unref (G_OBJECT(account));
261         if (msg)
262                 g_object_unref (G_OBJECT(msg));
263         if (folder)
264                 g_object_unref (G_OBJECT(folder));
265 }
266
267
268 void
269 modest_ui_actions_on_open (GtkWidget *widget, ModestWindow *win)
270 {
271         modest_runtime_not_implemented (GTK_WINDOW(win)); /* FIXME */
272 }
273
274
275
276 static void
277 reply_forward_func (gpointer data, gpointer user_data)
278 {
279         TnyMsg *msg, *new_msg;
280         GetMsgAsyncHelper *helper;
281         ReplyForwardHelper *rf_helper;
282         ModestWindow *msg_win;
283         ModestEditType edit_type;
284         gchar *from;
285         GError *err = NULL;
286         TnyFolder *folder = NULL;
287         TnyAccount *account = NULL;
288         
289         msg = TNY_MSG (data);
290         helper = (GetMsgAsyncHelper *) user_data;
291         rf_helper = (ReplyForwardHelper *) helper->user_data;
292
293         from = modest_account_mgr_get_from_string (modest_runtime_get_account_mgr(),
294                                                    rf_helper->account_name);
295         /* Create reply mail */
296         switch (rf_helper->action) {
297         case ACTION_REPLY:
298                 new_msg = 
299                         modest_mail_operation_create_reply_mail (msg,  from, 
300                                                                  rf_helper->reply_forward_type,
301                                                                  MODEST_MAIL_OPERATION_REPLY_MODE_SENDER);
302                 break;
303         case ACTION_REPLY_TO_ALL:
304                 new_msg = 
305                         modest_mail_operation_create_reply_mail (msg, from, rf_helper->reply_forward_type,
306                                                                  MODEST_MAIL_OPERATION_REPLY_MODE_ALL);
307                 edit_type = MODEST_EDIT_TYPE_REPLY;
308                 break;
309         case ACTION_FORWARD:
310                 new_msg = 
311                         modest_mail_operation_create_forward_mail (msg, from, rf_helper->reply_forward_type);
312                 edit_type = MODEST_EDIT_TYPE_FORWARD;
313                 break;
314         default:
315                 g_return_if_reached ();
316                 return;
317         }
318
319         if (!new_msg) {
320                 g_printerr ("modest: failed to create message\n");
321                 goto cleanup;
322         }
323
324         account = modest_tny_account_store_get_tny_account_by_account (modest_runtime_get_account_store(),
325                                                                        rf_helper->account_name,
326                                                                        TNY_ACCOUNT_TYPE_STORE);
327         if (!account) {
328                 g_printerr ("modest: failed to get tnyaccount for '%s'\n", rf_helper->account_name);
329                 goto cleanup;
330         }
331
332         folder = modest_tny_account_get_special_folder (account, TNY_FOLDER_TYPE_DRAFTS);
333         if (!folder) {
334                 g_printerr ("modest: failed to find Drafts folder\n");
335                 goto cleanup;
336         }
337         
338         tny_folder_add_msg (folder, msg, &err);
339         if (err) {
340                 g_printerr ("modest: error adding msg to Drafts folder: %s",
341                             err->message);
342                 g_error_free (err);
343                 goto cleanup;
344         }       
345                         
346         /* Show edit window */
347         msg_win = modest_msg_edit_window_new (new_msg, rf_helper->account_name);
348         gtk_widget_show_all (GTK_WIDGET (msg_win));
349
350 cleanup:
351         if (new_msg)
352                 g_object_unref (G_OBJECT (new_msg));
353         if (folder)
354                 g_object_unref (G_OBJECT (folder));
355         if (account)
356                 g_object_unref (G_OBJECT (account));
357         
358         g_free (rf_helper->account_name);
359         g_slice_free (ReplyForwardHelper, rf_helper);
360 }
361 /*
362  * Common code for the reply and forward actions
363  */
364 static void
365 reply_forward (GtkWidget *widget, ReplyForwardAction action, ModestWindow *win)
366 {
367         TnyList *header_list;
368         guint reply_forward_type;
369         TnyHeader *header;
370         TnyFolder *folder;
371         GetMsgAsyncHelper *helper;
372         ReplyForwardHelper *rf_helper;
373         
374         g_return_if_fail (MODEST_IS_WINDOW(win));
375
376         header_list = get_selected_headers (win);
377         if (!header_list)
378                 return;
379         
380         reply_forward_type = modest_conf_get_int (modest_runtime_get_conf (),
381                                                   (action == ACTION_FORWARD) ? MODEST_CONF_FORWARD_TYPE : MODEST_CONF_REPLY_TYPE,
382                                                   NULL);
383         /* We assume that we can only select messages of the
384            same folder and that we reply all of them from the
385            same account. In fact the interface currently only
386            allows single selection */
387         
388         /* Fill helpers */
389         rf_helper = g_slice_new0 (ReplyForwardHelper);
390         rf_helper->reply_forward_type = reply_forward_type;
391         rf_helper->action = action;
392
393         rf_helper->account_name = g_strdup (modest_window_get_active_account (win));
394         if (!rf_helper->account_name)
395                 rf_helper->account_name =
396                         modest_account_mgr_get_default_account (modest_runtime_get_account_mgr());
397
398         helper = g_slice_new0 (GetMsgAsyncHelper);
399         helper->window = win;
400         helper->func = reply_forward_func;
401         helper->iter = tny_list_create_iterator (header_list);
402         helper->user_data = rf_helper;
403
404         if (MODEST_IS_MSG_VIEW_WINDOW(win)) {
405                 TnyMsg *msg;
406                 msg = modest_msg_view_window_get_message(MODEST_MSG_VIEW_WINDOW(win));
407                 if (!msg) {
408                         g_printerr ("modest: no message found\n");
409                         return;
410                 } else
411                         reply_forward_func (msg, helper);
412         } else {
413                 header = TNY_HEADER (tny_iterator_get_current (helper->iter));
414                 folder = tny_header_get_folder (header);
415                 if (folder) {
416                         /* The callback will call it per each header */
417                         tny_folder_get_msg_async (folder, header, get_msg_cb, helper);
418                         g_object_unref (G_OBJECT (folder));
419                 } else 
420                         g_printerr ("modest: no folder for header\n");
421                 
422                 /* Clean */
423                 g_object_unref (G_OBJECT (header));
424         }
425 }
426
427
428 void
429 modest_ui_actions_on_reply (GtkWidget *widget, ModestWindow *win)
430 {
431         g_return_if_fail (MODEST_IS_WINDOW(win));
432
433         reply_forward (widget, ACTION_REPLY, win);
434 }
435
436 void
437 modest_ui_actions_on_forward (GtkWidget *widget, ModestWindow *win)
438 {
439         g_return_if_fail (MODEST_IS_WINDOW(win));
440
441         reply_forward (widget, ACTION_FORWARD, win);
442 }
443
444 void
445 modest_ui_actions_on_reply_all (GtkWidget *widget,ModestWindow *win)
446 {
447         g_return_if_fail (MODEST_IS_WINDOW(win));
448
449         reply_forward (widget, ACTION_REPLY_TO_ALL, win);
450 }
451
452 void 
453 modest_ui_actions_on_next (GtkWidget *widget, 
454                            ModestMainWindow *main_window)
455 {
456         GtkWidget *header_view;
457         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
458
459         header_view = modest_main_window_get_child_widget (main_window,
460                                                            MODEST_WIDGET_TYPE_HEADER_VIEW);
461         if (!header_view)
462                 return;
463         
464         modest_header_view_select_next (MODEST_HEADER_VIEW(header_view)); 
465 }
466
467 void 
468 modest_ui_actions_on_prev (GtkWidget *widget, 
469                            ModestMainWindow *main_window)
470 {
471         GtkWidget *header_view;
472         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
473
474         header_view = modest_main_window_get_child_widget (main_window,
475                                                            MODEST_WIDGET_TYPE_HEADER_VIEW);
476         if (!header_view)
477                 return;
478         
479         modest_header_view_select_prev (MODEST_HEADER_VIEW(header_view)); 
480 }
481
482
483 void
484 modest_ui_actions_on_send_receive (GtkWidget *widget,  ModestWindow *win)
485 {
486         gchar *account_name;
487         TnyAccount *tny_account;
488         ModestTnySendQueue *send_queue;
489         
490         account_name =
491                 g_strdup(modest_window_get_active_account(MODEST_WINDOW(win)));
492         if (!account_name)
493                 account_name  = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr());
494         if (!account_name) {
495                 g_printerr ("modest: cannot get account\n");
496                 return;
497         }
498         
499         tny_account = 
500                 modest_tny_account_store_get_tny_account_by_account (modest_runtime_get_account_store(),
501                                                                      account_name,
502                                                                      TNY_ACCOUNT_TYPE_TRANSPORT);
503         if (!tny_account) {
504                 g_printerr ("modest: cannot get tny transport account\n");
505                 return;
506         }
507
508         send_queue = modest_tny_send_queue_new (TNY_CAMEL_TRANSPORT_ACCOUNT(tny_account));
509         modest_tny_send_queue_flush (send_queue);
510
511         g_object_unref (G_OBJECT(send_queue));
512         g_object_unref (G_OBJECT(tny_account));
513 }
514
515
516
517 void
518 modest_ui_actions_toggle_view (GtkWidget *widget, ModestMainWindow *main_window)
519 {
520         ModestConf *conf;
521         GtkWidget *header_view;
522         
523         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
524
525         header_view = modest_main_window_get_child_widget (main_window,
526                                                            MODEST_WIDGET_TYPE_HEADER_VIEW);
527         if (!header_view)
528                 return;
529
530         conf = modest_runtime_get_conf ();
531         
532         /* what is saved/restored is depending on the style; thus; we save with
533          * old style, then update the style, and restore for this new style*/
534         modest_widget_memory_save (conf, G_OBJECT(header_view), "header-view");
535         
536         if (modest_header_view_get_style
537             (MODEST_HEADER_VIEW(header_view)) == MODEST_HEADER_VIEW_STYLE_DETAILS)
538                 modest_header_view_set_style (MODEST_HEADER_VIEW(header_view),
539                                               MODEST_HEADER_VIEW_STYLE_TWOLINES);
540         else
541                 modest_header_view_set_style (MODEST_HEADER_VIEW(header_view),
542                                               MODEST_HEADER_VIEW_STYLE_DETAILS);
543
544         modest_widget_memory_restore (conf, G_OBJECT(header_view),
545                                       "header-view");
546 }
547
548
549
550 /*
551  * Marks a message as read and passes it to the msg preview widget
552  */
553 static void
554 read_msg_func (gpointer data, gpointer user_data)
555 {
556         TnyMsg *msg;
557         TnyHeader *header;
558         GetMsgAsyncHelper *helper;
559         TnyHeaderFlags header_flags;
560         GtkWidget *msg_preview;
561         
562         msg = TNY_MSG (data);
563         helper = (GetMsgAsyncHelper *) user_data;
564
565         msg_preview = modest_main_window_get_child_widget (MODEST_MAIN_WINDOW (helper->window),
566                                                            MODEST_WIDGET_TYPE_MSG_PREVIEW);
567         if (!msg_preview)
568                 return;
569         
570         /* mark message as seen; _set_flags crashes, bug in tinymail? */
571         header = TNY_HEADER (tny_iterator_get_current (helper->iter));
572         header_flags = tny_header_get_flags (header);
573         tny_header_set_flags (header, header_flags | TNY_HEADER_FLAG_SEEN);
574         g_object_unref (G_OBJECT (header));
575
576         /* Set message on msg view */
577         modest_msg_view_set_message (MODEST_MSG_VIEW(msg_preview), msg);
578 }
579
580 /*
581  * This function is a generic handler for the tny_folder_get_msg_async
582  * call. It expects as user_data a #GetMsgAsyncHelper. This helper
583  * contains a user provided function that is called inside this
584  * method. This will allow us to use this callback in many different
585  * places. This callback performs the common actions for the
586  * get_msg_async call, more specific actions will be done by the user
587  * function
588  */
589 static void
590 get_msg_cb (TnyFolder *folder, TnyMsg *msg, GError **err, gpointer user_data)
591 {
592         GetMsgAsyncHelper *helper;
593
594         helper = (GetMsgAsyncHelper *) user_data;
595
596         if ((*err && ((*err)->code == TNY_FOLDER_ERROR_GET_MSG)) || !msg) {
597                 modest_ui_actions_on_item_not_found (NULL,
598                                                      MODEST_ITEM_TYPE_MESSAGE,
599                                                      helper->window);
600                 return;
601         }
602
603         /* Call user function */
604         helper->func (msg, user_data);
605
606         /* Process next element (if exists) */
607         tny_iterator_next (helper->iter);
608         if (tny_iterator_is_done (helper->iter)) {
609                 TnyList *headers;
610                 headers = tny_iterator_get_list (helper->iter);
611                 /* Free resources */
612                 g_object_unref (G_OBJECT (headers));
613                 g_object_unref (G_OBJECT (helper->iter));
614                 g_slice_free (GetMsgAsyncHelper, helper);
615         } else {
616                 TnyHeader *header;
617                 header = TNY_HEADER (tny_iterator_get_current (helper->iter)); 
618                 tny_folder_get_msg_async (folder, header,                         
619                                           get_msg_cb, helper);
620                 g_object_unref (G_OBJECT(header));
621         }
622 }
623
624 void 
625 modest_ui_actions_on_header_selected (ModestHeaderView *folder_view, 
626                                       TnyHeader *header,
627                                       ModestMainWindow *main_window)
628 {
629         GtkWidget *msg_preview;
630         TnyFolder *folder;
631         GetMsgAsyncHelper *helper;
632         TnyList *list;
633
634         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
635         
636         msg_preview = modest_main_window_get_child_widget(main_window,
637                                                           MODEST_WIDGET_TYPE_MSG_PREVIEW);
638         if (!msg_preview)
639                 return;
640         
641         /* when there's no header, clear the msgview */
642         if (!header) {
643                 modest_msg_view_set_message (MODEST_MSG_VIEW(msg_preview), NULL);
644                 return;
645         }
646
647         folder = tny_header_get_folder (TNY_HEADER(header));
648
649         /* Create list */
650         list = tny_simple_list_new ();
651         tny_list_prepend (list, G_OBJECT (header));
652
653         /* Fill helper data */
654         helper = g_slice_new0 (GetMsgAsyncHelper);
655         helper->window = MODEST_WINDOW (main_window);
656         helper->iter = tny_list_create_iterator (list);
657         helper->func = read_msg_func;
658
659         tny_folder_get_msg_async (TNY_FOLDER(folder),
660                                   header, get_msg_cb,
661                                   helper);
662
663         /* Frees */
664         g_object_unref (G_OBJECT (folder));
665 }
666
667
668
669 void 
670 modest_ui_actions_on_header_activated (ModestHeaderView *folder_view, TnyHeader *header,
671                                        ModestMainWindow *main_window)
672 {
673         ModestWindow *win;
674         TnyFolder *folder = NULL;
675         TnyMsg    *msg    = NULL;
676         gchar *account    = NULL;
677         
678         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
679         
680         if (!header)
681                 return;
682
683         folder = tny_header_get_folder (header);
684         if (!folder) {
685                 g_printerr ("modest: cannot get folder for header\n");
686                 goto cleanup;
687         }
688
689         /* FIXME: make async?; check error  */
690         msg = tny_folder_get_msg (folder, header, NULL);
691         if (!msg) {
692                 g_printerr ("modest: cannot get msg for header\n");
693                 goto cleanup;
694         }
695
696         account =  g_strdup(modest_window_get_active_account(MODEST_WINDOW(main_window)));
697         if (!account)
698                 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr());
699         
700         win = modest_msg_view_window_new (msg, account);
701         gtk_window_set_transient_for (GTK_WINDOW (win),
702                                       GTK_WINDOW (main_window));
703
704         gtk_widget_show_all (GTK_WIDGET(win));
705         
706 cleanup:
707         g_free (account);
708         
709         if (folder)
710                 g_object_unref (G_OBJECT (folder));
711         if (msg)
712                 g_object_unref (G_OBJECT (msg));
713 }
714
715 void 
716 modest_ui_actions_on_folder_selection_changed (ModestFolderView *folder_view,
717                                                TnyFolder *folder, 
718                                                gboolean selected,
719                                                ModestMainWindow *main_window)
720 {
721 //      GtkLabel *folder_info_label;
722         gchar *txt;     
723         ModestConf *conf;
724         GtkWidget *header_view;
725         
726 /*      folder_info_label =  */
727 /*              GTK_LABEL (modest_widget_factory_get_folder_info_label */
728 /*                         (modest_runtime_get_widget_factory())); */
729
730 /*      if (!folder) { */
731 /*              gtk_label_set_label (GTK_LABEL(folder_info_label), ""); */
732 /*              return; */
733 /*      } */
734         
735         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
736
737         header_view = modest_main_window_get_child_widget(main_window,
738                                                           MODEST_WIDGET_TYPE_HEADER_VIEW);
739         if (!header_view)
740                 return;
741         
742         conf = modest_runtime_get_conf ();
743
744         if (!selected) { /* the folder was unselected; save it's settings  */
745                 modest_widget_memory_save (conf, G_OBJECT (header_view), "header-view");
746                 gtk_window_set_title (GTK_WINDOW(main_window), "Modest");
747                 modest_header_view_set_folder (MODEST_HEADER_VIEW(header_view), NULL);
748         } else {  /* the folder was selected */
749                 if (folder) { /* folder may be NULL */
750                         guint num, unread;
751                         gchar *title;
752
753                         num    = tny_folder_get_all_count    (folder);
754                         unread = tny_folder_get_unread_count (folder);
755                         
756                         title = g_strdup_printf ("Modest: %s",
757                                                  tny_folder_get_name (folder));
758                         
759                         gtk_window_set_title (GTK_WINDOW(main_window), title);
760                         g_free (title);
761                         
762                         txt = g_strdup_printf (_("%d %s, %d unread"),
763                                                num, num==1 ? _("item") : _("items"), unread);           
764                         //gtk_label_set_label (GTK_LABEL(folder_info_label), txt);
765                         g_free (txt);
766                 }
767                 modest_header_view_set_folder (MODEST_HEADER_VIEW(header_view), folder);
768                 modest_widget_memory_restore (conf, G_OBJECT(header_view),
769                                               "header-view");
770         }
771 }
772
773
774 /****************************************************/
775 /*
776  * below some stuff to clearup statusbar messages after 1,5 seconds....
777  */
778 static gboolean
779 progress_bar_clean (GtkWidget *bar)
780 {
781         if (GTK_IS_PROGRESS_BAR(bar)) {
782                 gtk_progress_bar_set_text     (GTK_PROGRESS_BAR(bar), "");
783                 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR(bar), 1.0);
784         }
785         return FALSE;
786 }
787
788 static gboolean
789 statusbar_clean (GtkWidget *bar)
790 {
791         if (GTK_IS_STATUSBAR(bar))
792                 gtk_statusbar_push (GTK_STATUSBAR(bar), 0, "");
793         return FALSE;
794 }
795
796
797 static void
798 statusbar_push (ModestMainWindow *main_window, guint context_id, const gchar *msg)
799 {
800         if (!msg)
801                 return;
802
803         GtkWidget *progress_bar, *status_bar;
804
805         progress_bar = modest_main_window_get_child_widget (main_window,
806                                                             MODEST_WIDGET_TYPE_PROGRESS_BAR);
807         status_bar = modest_main_window_get_child_widget (main_window,
808                                                           MODEST_WIDGET_TYPE_STATUS_BAR);
809         if (progress_bar) {
810                 gtk_widget_show (progress_bar);
811                 g_timeout_add (3000, (GSourceFunc)progress_bar_clean, progress_bar);
812         }
813         
814         if (status_bar) {
815                 gtk_widget_show (status_bar);
816                 gtk_statusbar_push (GTK_STATUSBAR(status_bar), 0, msg);
817                 g_timeout_add (2500, (GSourceFunc)statusbar_clean, status_bar);
818         }
819
820 }
821 /****************************************************************************/
822
823 void 
824 modest_ui_actions_on_item_not_found (ModestHeaderView *header_view,ModestItemType type,
825                                      ModestWindow *win)
826 {
827         GtkWidget *dialog;
828         gchar *txt, *item;
829         gboolean online;
830
831         item = (type == MODEST_ITEM_TYPE_FOLDER) ? "folder" : "message";
832         
833         if (g_main_depth > 0)   
834                 gdk_threads_enter ();
835         online = tny_device_is_online (modest_runtime_get_device());
836
837         if (online) {
838                 /* already online -- the item is simply not there... */
839                 dialog = gtk_message_dialog_new (GTK_WINDOW (win),
840                                                  GTK_DIALOG_MODAL,
841                                                  GTK_MESSAGE_WARNING,
842                                                  GTK_BUTTONS_OK,
843                                                  _("The %s you selected cannot be found"),
844                                                  item);
845                 gtk_dialog_run (GTK_DIALOG(dialog));
846         } else {
847                 dialog = gtk_dialog_new_with_buttons (_("Connection requested"),
848                                                       GTK_WINDOW (win),
849                                                       GTK_DIALOG_MODAL,
850                                                       GTK_STOCK_CANCEL,
851                                                       GTK_RESPONSE_REJECT,
852                                                       GTK_STOCK_OK,
853                                                       GTK_RESPONSE_ACCEPT,
854                                                       NULL);
855                 txt = g_strdup_printf (_("This %s is not available in offline mode.\n"
856                                          "Do you want to get online?"), item);
857                 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), 
858                                     gtk_label_new (txt), FALSE, FALSE, 0);
859                 gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
860                 g_free (txt);
861
862                 gtk_window_set_default_size (GTK_WINDOW(dialog), 300, 300);
863                 if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
864                         tny_device_force_online (modest_runtime_get_device());
865                 }
866         }
867         gtk_widget_destroy (dialog);
868         if (g_main_depth > 0)   
869                 gdk_threads_leave ();
870 }
871
872
873
874 void
875 modest_ui_actions_on_header_status_update (ModestHeaderView *header_view, 
876                                             const gchar *msg, gint num, 
877                                             gint total,  ModestMainWindow *main_window)
878 {
879         char* txt;
880         GtkWidget *progress_bar;
881
882         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
883
884         progress_bar = modest_main_window_get_child_widget (main_window, 
885                                                             MODEST_WIDGET_TYPE_PROGRESS_BAR);   
886         if (!progress_bar)
887                 return;
888         
889         if (total != 0)
890                 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR(progress_bar),
891                                                (gdouble)num/(gdouble)total);
892         else
893                 gtk_progress_bar_pulse (GTK_PROGRESS_BAR(progress_bar));
894
895         txt = g_strdup_printf (_("Downloading %d of %d"), num, total);
896         gtk_progress_bar_set_text (GTK_PROGRESS_BAR(progress_bar), txt);
897         g_free (txt);
898         
899         statusbar_push (main_window, 0, msg);
900 }
901
902
903 void
904 modest_ui_actions_on_msg_link_hover (ModestMsgView *msgview, const gchar* link,
905                                      ModestWindow *win)
906 {
907         g_message (__FUNCTION__);
908 }       
909
910
911 void
912 modest_ui_actions_on_msg_link_clicked (ModestMsgView *msgview, const gchar* link,
913                                         ModestWindow *win)
914 {
915         g_message (__FUNCTION__);
916 }
917
918 void
919 modest_ui_actions_on_msg_attachment_clicked (ModestMsgView *msgview, int index,
920                                              ModestWindow *win)
921 {
922         g_message (__FUNCTION__);
923         
924 }
925
926 void
927 modest_ui_actions_on_send (GtkWidget *widget, ModestMsgEditWindow *edit_window)
928 {
929         TnyTransportAccount *transport_account;
930         ModestMailOperation *mail_operation;
931         MsgData *data;
932         gchar *account_name, *from;
933         ModestAccountMgr *account_mgr;
934
935         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(edit_window));
936         
937         data = modest_msg_edit_window_get_msg_data (edit_window);
938
939         /* FIXME: Code added just for testing. The final version will
940            use the send queue provided by tinymail and some
941            classifier */
942         account_mgr = modest_runtime_get_account_mgr();
943         account_name = g_strdup(modest_window_get_active_account (MODEST_WINDOW(edit_window)));
944         if (!account_name) 
945                 account_name = modest_account_mgr_get_default_account (account_mgr);
946         if (!account_name) {
947                 g_printerr ("modest: no account found\n");
948                 modest_msg_edit_window_free_msg_data (edit_window, data);
949                 return;
950         }
951         transport_account =
952                 TNY_TRANSPORT_ACCOUNT(modest_tny_account_store_get_tny_account_by_account
953                                       (modest_runtime_get_account_store(),
954                                        account_name,
955                                        TNY_ACCOUNT_TYPE_TRANSPORT));
956         if (!transport_account) {
957                 g_printerr ("modest: no transport account found for '%s'\n", account_name);
958                 g_free (account_name);
959                 modest_msg_edit_window_free_msg_data (edit_window, data);
960                 return;
961         }
962         from = modest_account_mgr_get_from_string (account_mgr, account_name);
963                 
964         mail_operation = modest_mail_operation_new ();
965         modest_mail_operation_send_new_mail (mail_operation,
966                                              transport_account,
967                                              from,
968                                              data->to, 
969                                              data->cc, 
970                                              data->bcc,
971                                              data->subject, 
972                                              data->body, 
973                                              NULL);
974         /* Frees */
975         g_free (from);
976         g_free (account_name);
977         g_object_unref (G_OBJECT (mail_operation));
978         g_object_unref (G_OBJECT (transport_account));
979
980         modest_msg_edit_window_free_msg_data (edit_window, data);
981
982         /* Save settings and close the window */
983         /* save_settings (edit_window) */
984         gtk_widget_destroy (GTK_WIDGET (edit_window));
985 }
986
987 /*
988  * Shows a dialog with an entry that asks for some text. The returned
989  * value must be freed by the caller. The dialog window title will be
990  * set to @title.
991  */
992 static gchar *
993 ask_for_folder_name (GtkWindow *parent_window,
994                      const gchar *title)
995 {
996         GtkWidget *dialog, *entry;
997         gchar *folder_name = NULL;
998
999         /* Ask for folder name */
1000         dialog = gtk_dialog_new_with_buttons (_("New Folder Name"),
1001                                               parent_window,
1002                                               GTK_DIALOG_MODAL,
1003                                               GTK_STOCK_CANCEL,
1004                                               GTK_RESPONSE_REJECT,
1005                                               GTK_STOCK_OK,
1006                                               GTK_RESPONSE_ACCEPT,
1007                                               NULL);
1008         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), 
1009                             gtk_label_new(title),
1010                             FALSE, FALSE, 0);
1011                 
1012         entry = gtk_entry_new_with_max_length (40);
1013         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), 
1014                             entry,
1015                             TRUE, FALSE, 0);    
1016         
1017         gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
1018         
1019         if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)         
1020                 folder_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
1021
1022         gtk_widget_destroy (dialog);
1023
1024         return folder_name;
1025 }
1026
1027 void 
1028 modest_ui_actions_on_new_folder (GtkWidget *widget, ModestMainWindow *main_window)
1029 {
1030         TnyFolder *parent_folder;
1031         GtkWidget *folder_view;
1032         
1033         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
1034
1035         folder_view = modest_main_window_get_child_widget (main_window,
1036                                                            MODEST_WIDGET_TYPE_FOLDER_VIEW);
1037         if (!folder_view)
1038                 return;
1039
1040         parent_folder = modest_folder_view_get_selected (MODEST_FOLDER_VIEW(folder_view));
1041         
1042         if (parent_folder) {
1043                 gchar *folder_name;
1044
1045                 folder_name = ask_for_folder_name (GTK_WINDOW (main_window),
1046                                                    _("Please enter a name for the new folder"));
1047
1048                 if (folder_name != NULL && strlen (folder_name) > 0) {
1049                         TnyFolder *new_folder;
1050                         ModestMailOperation *mail_op;
1051
1052                         mail_op = modest_mail_operation_new ();
1053                         new_folder = modest_mail_operation_create_folder (mail_op,
1054                                                                           TNY_FOLDER_STORE (parent_folder),
1055                                                                           (const gchar *) folder_name);
1056                         if (new_folder) {
1057                                 g_object_unref (new_folder);
1058                         } else {
1059                                 const GError *error;
1060                                 error = modest_mail_operation_get_error (mail_op);
1061                                 if (error)
1062                                         g_warning ("Error adding a subfolder: %s\n", error->message);
1063                         }
1064                         g_object_unref (mail_op);
1065                 }
1066                 g_object_unref (parent_folder);
1067         }
1068 }
1069
1070 void 
1071 modest_ui_actions_on_rename_folder (GtkWidget *widget,
1072                                      ModestMainWindow *main_window)
1073 {
1074         TnyFolder *folder;
1075         GtkWidget *folder_view;
1076         
1077         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
1078
1079         folder_view = modest_main_window_get_child_widget (main_window,
1080                                                            MODEST_WIDGET_TYPE_FOLDER_VIEW);
1081         if (!folder_view)
1082                 return;
1083         
1084         folder = modest_folder_view_get_selected (MODEST_FOLDER_VIEW(folder_view));
1085         
1086         if (folder) {
1087                 gchar *folder_name;
1088                 folder_name = ask_for_folder_name (GTK_WINDOW (main_window),
1089                                                    _("Please enter a new name for the folder"));
1090
1091                 if (folder_name != NULL && strlen (folder_name) > 0) {
1092                         ModestMailOperation *mail_op;
1093                         const GError *error;
1094
1095                         mail_op = modest_mail_operation_new ();
1096                         modest_mail_operation_rename_folder (mail_op,
1097                                                              folder,
1098                                                              (const gchar *) folder_name);
1099
1100                         error = modest_mail_operation_get_error (mail_op);
1101                         if (error)
1102                                 /* TODO: notify error ? */
1103                                 g_warning ("Could not rename a folder: %s\n", error->message);
1104
1105                         g_object_unref (mail_op);
1106                 }
1107                 g_object_unref (folder);
1108         }
1109 }
1110
1111 static void
1112 delete_folder (ModestMainWindow *main_window, gboolean move_to_trash) 
1113 {
1114         TnyFolder *folder;
1115         ModestMailOperation *mail_op;
1116         GtkWidget *folder_view;
1117         const GError *error;
1118         
1119         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
1120
1121         folder_view = modest_main_window_get_child_widget (main_window,
1122                                                            MODEST_WIDGET_TYPE_FOLDER_VIEW);
1123         if (!folder_view)
1124                 return;
1125
1126         folder = modest_folder_view_get_selected (MODEST_FOLDER_VIEW(folder_view));
1127         
1128         mail_op = modest_mail_operation_new ();
1129         modest_mail_operation_remove_folder (mail_op, folder, move_to_trash);
1130
1131         error = modest_mail_operation_get_error (mail_op);
1132         if (error)
1133                 g_warning ("%s\n", error->message);
1134
1135         g_object_unref (mail_op);
1136 }
1137
1138 void 
1139 modest_ui_actions_on_delete_folder (GtkWidget *widget,
1140                                      ModestMainWindow *main_window)
1141 {
1142         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
1143
1144         delete_folder (main_window, FALSE);
1145 }
1146
1147 void 
1148 modest_ui_actions_on_move_folder_to_trash_folder (GtkWidget *widget, ModestMainWindow *main_window)
1149 {
1150         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
1151         
1152         delete_folder (main_window, TRUE);
1153 }
1154
1155 void
1156 modest_ui_actions_on_password_requested (TnyAccountStore *account_store, 
1157                                          const gchar* account_name,
1158                                          gchar **password, 
1159                                          gboolean *cancel, 
1160                                          gboolean *remember,
1161                                          ModestMainWindow *main_window)
1162 {
1163         gchar *txt;
1164         GtkWidget *dialog, *entry, *remember_pass_check;
1165
1166         dialog = gtk_dialog_new_with_buttons (_("Password requested"),
1167                                               NULL,
1168                                               GTK_DIALOG_MODAL,
1169                                               GTK_STOCK_CANCEL,
1170                                               GTK_RESPONSE_REJECT,
1171                                               GTK_STOCK_OK,
1172                                               GTK_RESPONSE_ACCEPT,
1173                                               NULL);
1174         gtk_window_set_transient_for (GTK_WINDOW(dialog), GTK_WINDOW(main_window));
1175         
1176         txt = g_strdup_printf (_("Please enter your password for %s"), account_name);
1177         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), gtk_label_new(txt),
1178                             FALSE, FALSE, 0);
1179         g_free (txt);
1180
1181         entry = gtk_entry_new_with_max_length (40);
1182         gtk_entry_set_visibility (GTK_ENTRY(entry), FALSE);
1183         gtk_entry_set_invisible_char (GTK_ENTRY(entry), 0x2022); /* bullet unichar */
1184         
1185         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), entry,
1186                             TRUE, FALSE, 0);    
1187
1188         remember_pass_check = gtk_check_button_new_with_label (_("Remember password"));
1189         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), remember_pass_check,
1190                             TRUE, FALSE, 0);
1191
1192         gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
1193         
1194         if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
1195                 *password = g_strdup (gtk_entry_get_text (GTK_ENTRY(entry)));
1196                 *cancel   = FALSE;
1197         } else {
1198                 *password = NULL;
1199                 *cancel   = TRUE;
1200         }
1201
1202         if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (remember_pass_check)))
1203                 *remember = TRUE;
1204         else
1205                 *remember = FALSE;
1206
1207         gtk_widget_destroy (dialog);
1208 }