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