339162db353bdd49c2f5ab16cdab59e9b4792991
[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         ModestMainWindow *main_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 /*
373  * Common code for the reply and forward actions
374  */
375 static void
376 reply_forward (GtkWidget *widget, ReplyForwardAction action, ModestWindow *win)
377 {
378         TnyList *header_list;
379         guint reply_forward_type;
380         TnyHeader *header;
381         TnyFolder *folder;
382         GetMsgAsyncHelper *helper;
383         ReplyForwardHelper *rf_helper;
384         
385         g_return_if_fail (MODEST_IS_WINDOW(win));
386
387         header_list = get_selected_headers (win);       
388         if (!header_list)
389                 return;
390         
391         reply_forward_type = modest_conf_get_int (modest_runtime_get_conf (),
392                                                   (action == ACTION_FORWARD) ? MODEST_CONF_FORWARD_TYPE : MODEST_CONF_REPLY_TYPE,
393                                                   NULL);
394         /* We assume that we can only select messages of the
395            same folder and that we reply all of them from the
396            same account. In fact the interface currently only
397            allows single selection */
398         
399         /* Fill helpers */
400         rf_helper = g_slice_new0 (ReplyForwardHelper);
401         rf_helper->reply_forward_type = reply_forward_type;
402         rf_helper->action = action;
403
404         rf_helper->account_name = g_strdup (modest_window_get_active_account (win));
405         if (!rf_helper->account_name)
406                 rf_helper->account_name = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr());
407
408         helper = g_slice_new0 (GetMsgAsyncHelper);
409         //helper->main_window = NULL;
410         helper->func = reply_forward_func;
411         helper->iter = tny_list_create_iterator (header_list);
412         helper->user_data = rf_helper;
413         
414         header = TNY_HEADER (tny_iterator_get_current (helper->iter));
415         folder = tny_header_get_folder (header);
416         if (folder) {
417                 /* The callback will call it per each header */
418                 tny_folder_get_msg_async (folder, header, get_msg_cb, helper);
419                 g_object_unref (G_OBJECT (folder));
420         } else
421                 g_printerr ("modest: no folder for header\n");
422         
423         /* Clean */
424         g_object_unref (G_OBJECT (header));
425 }
426
427 void
428 modest_ui_actions_on_reply (GtkWidget *widget, ModestWindow *win)
429 {
430         g_return_if_fail (MODEST_IS_WINDOW(win));
431
432         reply_forward (widget, ACTION_REPLY, win);
433 }
434
435 void
436 modest_ui_actions_on_forward (GtkWidget *widget, ModestWindow *win)
437 {
438         g_return_if_fail (MODEST_IS_WINDOW(win));
439
440         reply_forward (widget, ACTION_FORWARD, win);
441 }
442
443 void
444 modest_ui_actions_on_reply_all (GtkWidget *widget,ModestWindow *win)
445 {
446         g_return_if_fail (MODEST_IS_WINDOW(win));
447
448         reply_forward (widget, ACTION_REPLY_TO_ALL, win);
449 }
450
451 void 
452 modest_ui_actions_on_next (GtkWidget *widget, 
453                            ModestMainWindow *main_window)
454 {
455         GtkWidget *header_view;
456         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
457
458         header_view = modest_main_window_get_child_widget (main_window,
459                                                            MODEST_WIDGET_TYPE_HEADER_VIEW);
460         if (!header_view)
461                 return;
462         
463         modest_header_view_select_next (MODEST_HEADER_VIEW(header_view)); 
464 }
465
466 void 
467 modest_ui_actions_on_prev (GtkWidget *widget, 
468                            ModestMainWindow *main_window)
469 {
470         GtkWidget *header_view;
471         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
472
473         header_view = modest_main_window_get_child_widget (main_window,
474                                                            MODEST_WIDGET_TYPE_HEADER_VIEW);
475         if (!header_view)
476                 return;
477         
478         modest_header_view_select_prev (MODEST_HEADER_VIEW(header_view)); 
479 }
480
481
482 void
483 modest_ui_actions_on_send_receive (GtkWidget *widget,  ModestWindow *win)
484 {
485         gchar *account_name;
486         TnyAccount *tny_account;
487         ModestTnySendQueue *send_queue;
488         
489         account_name =
490                 g_strdup(modest_window_get_active_account(MODEST_WINDOW(win)));
491         if (!account_name)
492                 account_name  = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr());
493         if (!account_name) {
494                 g_printerr ("modest: cannot get account\n");
495                 return;
496         }
497         
498         tny_account = 
499                 modest_tny_account_store_get_tny_account_by_account (modest_runtime_get_account_store(),
500                                                                      account_name,
501                                                                      TNY_ACCOUNT_TYPE_TRANSPORT);
502         if (!tny_account) {
503                 g_printerr ("modest: cannot get tny transport account\n");
504                 return;
505         }
506
507         send_queue = modest_tny_send_queue_new (TNY_CAMEL_TRANSPORT_ACCOUNT(tny_account));
508         modest_tny_send_queue_flush (send_queue);
509
510         g_object_unref (G_OBJECT(send_queue));
511         g_object_unref (G_OBJECT(tny_account));
512 }
513
514
515
516 void
517 modest_ui_actions_toggle_view (GtkWidget *widget, ModestMainWindow *main_window)
518 {
519         ModestConf *conf;
520         GtkWidget *header_view;
521         
522         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
523
524         header_view = modest_main_window_get_child_widget (main_window,
525                                                            MODEST_WIDGET_TYPE_HEADER_VIEW);
526         if (!header_view)
527                 return;
528
529         conf = modest_runtime_get_conf ();
530         
531         /* what is saved/restored is depending on the style; thus; we save with
532          * old style, then update the style, and restore for this new style*/
533         modest_widget_memory_save (conf, G_OBJECT(header_view), "header-view");
534         
535         if (modest_header_view_get_style
536             (MODEST_HEADER_VIEW(header_view)) == MODEST_HEADER_VIEW_STYLE_DETAILS)
537                 modest_header_view_set_style (MODEST_HEADER_VIEW(header_view),
538                                               MODEST_HEADER_VIEW_STYLE_TWOLINES);
539         else
540                 modest_header_view_set_style (MODEST_HEADER_VIEW(header_view),
541                                               MODEST_HEADER_VIEW_STYLE_DETAILS);
542
543         modest_widget_memory_restore (conf, G_OBJECT(header_view),
544                                       "header-view");
545 }
546
547
548
549 /*
550  * Marks a message as read and passes it to the msg preview widget
551  */
552 static void
553 read_msg_func (gpointer data, gpointer user_data)
554 {
555         TnyMsg *msg;
556         TnyHeader *header;
557         GetMsgAsyncHelper *helper;
558         TnyHeaderFlags header_flags;
559         GtkWidget *msg_preview;
560         
561         msg = TNY_MSG (data);
562         helper = (GetMsgAsyncHelper *) user_data;
563
564         msg_preview = modest_main_window_get_child_widget (helper->main_window,
565                                                            MODEST_WIDGET_TYPE_MSG_PREVIEW);
566         if (!msg_preview)
567                 return;
568         
569         /* mark message as seen; _set_flags crashes, bug in tinymail? */
570         header = TNY_HEADER (tny_iterator_get_current (helper->iter));
571         header_flags = tny_header_get_flags (header);
572         tny_header_set_flags (header, header_flags | TNY_HEADER_FLAG_SEEN);
573         g_object_unref (G_OBJECT (header));
574
575         /* Set message on msg view */
576         modest_msg_view_set_message (MODEST_MSG_VIEW(msg_preview), msg);
577 }
578
579 /*
580  * This function is a generic handler for the tny_folder_get_msg_async
581  * call. It expects as user_data a #GetMsgAsyncHelper. This helper
582  * contains a user provided function that is called inside this
583  * method. This will allow us to use this callback in many different
584  * places. This callback performs the common actions for the
585  * get_msg_async call, more specific actions will be done by the user
586  * function
587  */
588 static void
589 get_msg_cb (TnyFolder *folder, TnyMsg *msg, GError **err, gpointer user_data)
590 {
591         GetMsgAsyncHelper *helper;
592
593         helper = (GetMsgAsyncHelper *) user_data;
594
595         if ((*err && ((*err)->code == TNY_FOLDER_ERROR_GET_MSG)) || !msg) {
596                 GtkWidget *header_view =
597                         modest_main_window_get_child_widget(helper->main_window,
598                                                             MODEST_WIDGET_TYPE_HEADER_VIEW);
599                 if (header_view)
600                         modest_ui_actions_on_item_not_found (MODEST_HEADER_VIEW(header_view),
601                                                              MODEST_ITEM_TYPE_MESSAGE,
602                                                              MODEST_WINDOW(helper->main_window));
603                 return;
604         }
605
606         /* Call user function */
607         helper->func (msg, user_data);
608
609         /* Process next element (if exists) */
610         tny_iterator_next (helper->iter);
611         if (tny_iterator_is_done (helper->iter)) {
612                 TnyList *headers;
613                 headers = tny_iterator_get_list (helper->iter);
614                 /* Free resources */
615                 g_object_unref (G_OBJECT (headers));
616                 g_object_unref (G_OBJECT (helper->iter));
617                 g_slice_free (GetMsgAsyncHelper, helper);
618         } else {
619                 TnyHeader *header;
620                 header = TNY_HEADER (tny_iterator_get_current (helper->iter)); 
621                 tny_folder_get_msg_async (folder, header,                         
622                                           get_msg_cb, helper);
623                 g_object_unref (G_OBJECT(header));
624         }
625 }
626
627 void 
628 modest_ui_actions_on_header_selected (ModestHeaderView *folder_view, 
629                                       TnyHeader *header,
630                                       ModestMainWindow *main_window)
631 {
632         GtkWidget *msg_preview;
633         TnyFolder *folder;
634         GetMsgAsyncHelper *helper;
635         TnyList *list;
636
637         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
638         
639         msg_preview = modest_main_window_get_child_widget(main_window,
640                                                           MODEST_WIDGET_TYPE_MSG_PREVIEW);
641         if (!msg_preview)
642                 return;
643         
644         /* when there's no header, clear the msgview */
645         if (!header) {
646                 modest_msg_view_set_message (MODEST_MSG_VIEW(msg_preview), NULL);
647                 return;
648         }
649
650         folder = tny_header_get_folder (TNY_HEADER(header));
651
652         /* Create list */
653         list = tny_simple_list_new ();
654         tny_list_prepend (list, G_OBJECT (header));
655
656         /* Fill helper data */
657         helper = g_slice_new0 (GetMsgAsyncHelper);
658         helper->main_window = main_window;
659         helper->iter = tny_list_create_iterator (list);
660         helper->func = read_msg_func;
661
662         tny_folder_get_msg_async (TNY_FOLDER(folder),
663                                   header, get_msg_cb,
664                                   helper);
665
666         /* Frees */
667         g_object_unref (G_OBJECT (folder));
668 }
669
670
671
672 void 
673 modest_ui_actions_on_header_activated (ModestHeaderView *folder_view, TnyHeader *header,
674                                        ModestMainWindow *main_window)
675 {
676         ModestWindow *win;
677         TnyFolder *folder = NULL;
678         TnyMsg    *msg    = NULL;
679         gchar *account    = NULL;
680         
681         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
682         
683         if (!header)
684                 return;
685
686         folder = tny_header_get_folder (header);
687         if (!folder) {
688                 g_printerr ("modest: cannot get folder for header\n");
689                 goto cleanup;
690         }
691
692         /* FIXME: make async?; check error  */
693         msg = tny_folder_get_msg (folder, header, NULL);
694         if (!msg) {
695                 g_printerr ("modest: cannot get msg for header\n");
696                 goto cleanup;
697         }
698
699         account =  g_strdup(modest_window_get_active_account(MODEST_WINDOW(main_window)));
700         if (!account)
701                 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr());
702         
703         win = modest_msg_view_window_new (msg, account);
704         gtk_window_set_transient_for (GTK_WINDOW (win),
705                                       GTK_WINDOW (main_window));
706
707         gtk_widget_show_all (GTK_WIDGET(win));
708         
709 cleanup:
710         g_free (account);
711         
712         if (folder)
713                 g_object_unref (G_OBJECT (folder));
714         if (msg)
715                 g_object_unref (G_OBJECT (folder));
716 }
717
718
719
720
721
722 void 
723 modest_ui_actions_on_folder_selection_changed (ModestFolderView *folder_view,
724                                                TnyFolder *folder, 
725                                                gboolean selected,
726                                                ModestMainWindow *main_window)
727 {
728 //      GtkLabel *folder_info_label;
729         gchar *txt;     
730         ModestConf *conf;
731         GtkWidget *header_view;
732         
733 /*      folder_info_label =  */
734 /*              GTK_LABEL (modest_widget_factory_get_folder_info_label */
735 /*                         (modest_runtime_get_widget_factory())); */
736
737 /*      if (!folder) { */
738 /*              gtk_label_set_label (GTK_LABEL(folder_info_label), ""); */
739 /*              return; */
740 /*      } */
741         
742         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
743
744         header_view = modest_main_window_get_child_widget(main_window,
745                                                           MODEST_WIDGET_TYPE_HEADER_VIEW);
746         if (!header_view)
747                 return;
748         
749         conf = modest_runtime_get_conf ();
750
751         if (!selected) { /* the folder was unselected; save it's settings  */
752                 modest_widget_memory_save (conf, G_OBJECT (header_view), "header-view");
753                 gtk_window_set_title (GTK_WINDOW(main_window), "Modest");
754                 modest_header_view_set_folder (MODEST_HEADER_VIEW(header_view), NULL);
755         } else {  /* the folder was selected */
756                 if (folder) { /* folder may be NULL */
757                         guint num, unread;
758                         gchar *title;
759
760                         num    = tny_folder_get_all_count    (folder);
761                         unread = tny_folder_get_unread_count (folder);
762                         
763                         title = g_strdup_printf ("Modest: %s",
764                                                  tny_folder_get_name (folder));
765                         
766                         gtk_window_set_title (GTK_WINDOW(main_window), title);
767                         g_free (title);
768                         
769                         txt = g_strdup_printf (_("%d %s, %d unread"),
770                                                num, num==1 ? _("item") : _("items"), unread);           
771                         //gtk_label_set_label (GTK_LABEL(folder_info_label), txt);
772                         g_free (txt);
773                 }
774                 modest_header_view_set_folder (MODEST_HEADER_VIEW(header_view), folder);
775                 modest_widget_memory_restore (conf, G_OBJECT(header_view),
776                                               "header-view");
777         }
778 }
779
780
781 /****************************************************/
782 /*
783  * below some stuff to clearup statusbar messages after 1,5 seconds....
784  */
785 static gboolean
786 progress_bar_clean (GtkWidget *bar)
787 {
788         if (GTK_IS_PROGRESS_BAR(bar)) {
789                 gtk_progress_bar_set_text     (GTK_PROGRESS_BAR(bar), "");
790                 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR(bar), 1.0);
791         }
792         return FALSE;
793 }
794
795 static gboolean
796 statusbar_clean (GtkWidget *bar)
797 {
798         if (GTK_IS_STATUSBAR(bar))
799                 gtk_statusbar_push (GTK_STATUSBAR(bar), 0, "");
800         return FALSE;
801 }
802
803
804 static void
805 statusbar_push (ModestMainWindow *main_window, guint context_id, const gchar *msg)
806 {
807         if (!msg)
808                 return;
809
810         GtkWidget *progress_bar, *status_bar;
811
812         progress_bar = modest_main_window_get_child_widget (main_window,
813                                                             MODEST_WIDGET_TYPE_PROGRESS_BAR);
814         status_bar = modest_main_window_get_child_widget (main_window,
815                                                           MODEST_WIDGET_TYPE_STATUS_BAR);
816         if (progress_bar) {
817                 gtk_widget_show (progress_bar);
818                 g_timeout_add (3000, (GSourceFunc)progress_bar_clean, progress_bar);
819         }
820         
821         if (status_bar) {
822                 gtk_widget_show (status_bar);
823                 gtk_statusbar_push (GTK_STATUSBAR(status_bar), 0, msg);
824                 g_timeout_add (1500, (GSourceFunc)statusbar_clean, status_bar);
825         }
826
827 }
828 /****************************************************************************/
829
830 void 
831 modest_ui_actions_on_item_not_found (ModestHeaderView *header_view,ModestItemType type,
832                                      ModestWindow *win)
833 {
834         GtkWidget *dialog;
835         gchar *txt, *item;
836         gboolean online;
837
838         item = (type == MODEST_ITEM_TYPE_FOLDER) ? "folder" : "message";
839         
840         if (g_main_depth > 0)   
841                 gdk_threads_enter ();
842         online = tny_device_is_online (modest_runtime_get_device());
843
844         if (online) {
845                 /* already online -- the item is simply not there... */
846                 dialog = gtk_message_dialog_new (GTK_WINDOW (win),
847                                                  GTK_DIALOG_MODAL,
848                                                  GTK_MESSAGE_WARNING,
849                                                  GTK_BUTTONS_OK,
850                                                  _("The %s you selected cannot be found"),
851                                                  item);
852                 gtk_dialog_run (GTK_DIALOG(dialog));
853         } else {
854                 dialog = gtk_dialog_new_with_buttons (_("Connection requested"),
855                                                       GTK_WINDOW (win),
856                                                       GTK_DIALOG_MODAL,
857                                                       GTK_STOCK_CANCEL,
858                                                       GTK_RESPONSE_REJECT,
859                                                       GTK_STOCK_OK,
860                                                       GTK_RESPONSE_ACCEPT,
861                                                       NULL);
862                 txt = g_strdup_printf (_("This %s is not available in offline mode.\n"
863                                          "Do you want to get online?"), item);
864                 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), 
865                                     gtk_label_new (txt), FALSE, FALSE, 0);
866                 gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
867                 g_free (txt);
868
869                 gtk_window_set_default_size (GTK_WINDOW(dialog), 300, 300);
870                 if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
871                         tny_device_force_online (modest_runtime_get_device());
872                 }
873         }
874         gtk_widget_destroy (dialog);
875         if (g_main_depth > 0)   
876                 gdk_threads_leave ();
877 }
878
879
880
881 void
882 modest_ui_actions_on_header_status_update (ModestHeaderView *header_view, 
883                                             const gchar *msg, gint num, 
884                                             gint total,  ModestMainWindow *main_window)
885 {
886         char* txt;
887         GtkWidget *progress_bar;
888
889         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
890
891         progress_bar = modest_main_window_get_child_widget (main_window, 
892                                                             MODEST_WIDGET_TYPE_PROGRESS_BAR);   
893         if (!progress_bar)
894                 return;
895         
896         if (total != 0)
897                 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR(progress_bar),
898                                                (gdouble)num/(gdouble)total);
899         else
900                 gtk_progress_bar_pulse (GTK_PROGRESS_BAR(progress_bar));
901
902         txt = g_strdup_printf (_("Downloading %d of %d"), num, total);
903         gtk_progress_bar_set_text (GTK_PROGRESS_BAR(progress_bar), txt);
904         g_free (txt);
905         
906         statusbar_push (main_window, 0, msg);
907 }
908
909
910 void
911 modest_ui_actions_on_msg_link_hover (ModestMsgView *msgview, const gchar* link,
912                                      ModestWindow *win)
913 {
914         g_message (__FUNCTION__);
915 }       
916
917
918 void
919 modest_ui_actions_on_msg_link_clicked (ModestMsgView *msgview, const gchar* link,
920                                         ModestWindow *win)
921 {
922         g_message (__FUNCTION__);
923 }
924
925 void
926 modest_ui_actions_on_msg_attachment_clicked (ModestMsgView *msgview, int index,
927                                              ModestWindow *win)
928 {
929         g_message (__FUNCTION__);
930         
931 }
932
933 void
934 modest_ui_actions_on_send (GtkWidget *widget, ModestMsgEditWindow *edit_window)
935 {
936         TnyTransportAccount *transport_account;
937         ModestMailOperation *mail_operation;
938         MsgData *data;
939         gchar *account_name, *from;
940         ModestAccountMgr *account_mgr;
941
942         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(edit_window));
943         
944         data = modest_msg_edit_window_get_msg_data (edit_window);
945
946         /* FIXME: Code added just for testing. The final version will
947            use the send queue provided by tinymail and some
948            classifier */
949         account_mgr = modest_runtime_get_account_mgr();
950         account_name = g_strdup(modest_window_get_active_account (MODEST_WINDOW(edit_window)));
951         if (!account_name) 
952                 account_name = modest_account_mgr_get_default_account (account_mgr);
953         if (!account_name) {
954                 g_printerr ("modest: no account found\n");
955                 modest_msg_edit_window_free_msg_data (edit_window, data);
956                 return;
957         }
958         transport_account =
959                 TNY_TRANSPORT_ACCOUNT(modest_tny_account_store_get_tny_account_by_account
960                                       (modest_runtime_get_account_store(),
961                                        account_name,
962                                        TNY_ACCOUNT_TYPE_TRANSPORT));
963         if (!transport_account) {
964                 g_printerr ("modest: no transport account found for '%s'\n", account_name);
965                 g_free (account_name);
966                 modest_msg_edit_window_free_msg_data (edit_window, data);
967                 return;
968         }
969         from = modest_account_mgr_get_from_string (account_mgr, account_name);
970                 
971         mail_operation = modest_mail_operation_new ();
972         modest_mail_operation_send_new_mail (mail_operation,
973                                              transport_account,
974                                              from,
975                                              data->to, 
976                                              data->cc, 
977                                              data->bcc,
978                                              data->subject, 
979                                              data->body, 
980                                              NULL);
981         /* Frees */
982         g_free (from);
983         g_free (account_name);
984         g_object_unref (G_OBJECT (mail_operation));
985         g_object_unref (G_OBJECT (transport_account));
986
987         modest_msg_edit_window_free_msg_data (edit_window, data);
988
989         /* Save settings and close the window */
990         /* save_settings (edit_window) */
991         gtk_widget_destroy (GTK_WIDGET (edit_window));
992 }
993
994 /*
995  * Shows a dialog with an entry that asks for some text. The returned
996  * value must be freed by the caller. The dialog window title will be
997  * set to @title.
998  */
999 static gchar *
1000 ask_for_folder_name (GtkWindow *parent_window,
1001                      const gchar *title)
1002 {
1003         GtkWidget *dialog, *entry;
1004         gchar *folder_name = NULL;
1005
1006         /* Ask for folder name */
1007         dialog = gtk_dialog_new_with_buttons (_("New Folder Name"),
1008                                               parent_window,
1009                                               GTK_DIALOG_MODAL,
1010                                               GTK_STOCK_CANCEL,
1011                                               GTK_RESPONSE_REJECT,
1012                                               GTK_STOCK_OK,
1013                                               GTK_RESPONSE_ACCEPT,
1014                                               NULL);
1015         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), 
1016                             gtk_label_new(title),
1017                             FALSE, FALSE, 0);
1018                 
1019         entry = gtk_entry_new_with_max_length (40);
1020         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), 
1021                             entry,
1022                             TRUE, FALSE, 0);    
1023         
1024         gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
1025         
1026         if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)         
1027                 folder_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
1028
1029         gtk_widget_destroy (dialog);
1030
1031         return folder_name;
1032 }
1033
1034 void 
1035 modest_ui_actions_on_new_folder (GtkWidget *widget, ModestMainWindow *main_window)
1036 {
1037         TnyFolder *parent_folder;
1038         GtkWidget *folder_view;
1039         
1040         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
1041
1042         folder_view = modest_main_window_get_child_widget (main_window,
1043                                                            MODEST_WIDGET_TYPE_FOLDER_VIEW);
1044         if (!folder_view)
1045                 return;
1046
1047         parent_folder = modest_folder_view_get_selected (MODEST_FOLDER_VIEW(folder_view));
1048         
1049         if (parent_folder) {
1050                 gchar *folder_name;
1051
1052                 folder_name = ask_for_folder_name (GTK_WINDOW (main_window),
1053                                                    _("Please enter a name for the new folder"));
1054
1055                 if (folder_name != NULL && strlen (folder_name) > 0) {
1056                         TnyFolder *new_folder;
1057                         ModestMailOperation *mail_op;
1058
1059                         mail_op = modest_mail_operation_new ();
1060                         new_folder = modest_mail_operation_create_folder (mail_op,
1061                                                                           TNY_FOLDER_STORE (parent_folder),
1062                                                                           (const gchar *) folder_name);
1063                         if (new_folder) {
1064                                 /* TODO: tinymail should do this. 
1065                                    Update view */
1066                                 modest_folder_view_add_subfolder (MODEST_FOLDER_VIEW(folder_view),
1067                                                                   new_folder);
1068
1069                                 /* Free new folder */
1070                                 g_object_unref (new_folder);
1071                         }
1072                         g_object_unref (mail_op);
1073                 }
1074                 g_object_unref (parent_folder);
1075         }
1076 }
1077
1078 void 
1079 modest_ui_actions_on_rename_folder (GtkWidget *widget,
1080                                      ModestMainWindow *main_window)
1081 {
1082         TnyFolder *folder;
1083         GtkWidget *folder_view;
1084         
1085         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
1086
1087         folder_view = modest_main_window_get_child_widget (main_window,
1088                                                            MODEST_WIDGET_TYPE_FOLDER_VIEW);
1089         if (!folder_view)
1090                 return;
1091         
1092         folder = modest_folder_view_get_selected (MODEST_FOLDER_VIEW(folder_view));
1093         
1094         if (folder) {
1095                 gchar *folder_name;
1096                 folder_name = ask_for_folder_name (GTK_WINDOW (main_window),
1097                                                    _("Please enter a new name for the folder"));
1098
1099                 if (folder_name != NULL && strlen (folder_name) > 0) {
1100                         ModestMailOperation *mail_op;
1101                         const GError *error;
1102
1103                         mail_op = modest_mail_operation_new ();
1104                         modest_mail_operation_rename_folder (mail_op,
1105                                                              folder,
1106                                                              (const gchar *) folder_name);
1107
1108                         error = modest_mail_operation_get_error (mail_op);
1109                         if (!error)
1110                                 /* TODO: tinymail should do this. 
1111                                    Update view */
1112                                 modest_folder_view_rename (MODEST_FOLDER_VIEW(folder_view));
1113
1114                         /* TODO: else ? notify error ? */
1115
1116                         g_object_unref (mail_op);
1117                 }
1118                 g_object_unref (folder);
1119         }
1120 }
1121
1122 static void
1123 delete_folder (ModestMainWindow *main_window, gboolean move_to_trash) 
1124 {
1125         TnyFolder *folder;
1126         ModestMailOperation *mail_op;
1127         GtkWidget *folder_view;
1128         
1129         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
1130
1131         folder_view = modest_main_window_get_child_widget (main_window,
1132                                                            MODEST_WIDGET_TYPE_FOLDER_VIEW);
1133         if (!folder_view)
1134                 return;
1135
1136         folder = modest_folder_view_get_selected (MODEST_FOLDER_VIEW(folder_view));
1137         
1138         mail_op = modest_mail_operation_new ();
1139         modest_mail_operation_remove_folder (mail_op, folder, move_to_trash);
1140         g_object_unref (mail_op);
1141 }
1142
1143 void 
1144 modest_ui_actions_on_delete_folder (GtkWidget *widget,
1145                                      ModestMainWindow *main_window)
1146 {
1147         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
1148
1149         delete_folder (main_window, FALSE);
1150 }
1151
1152 void 
1153 modest_ui_actions_on_move_folder_to_trash_folder (GtkWidget *widget, ModestMainWindow *main_window)
1154 {
1155         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
1156         
1157         delete_folder (main_window, TRUE);
1158 }
1159
1160 void
1161 modest_ui_actions_on_accounts_reloaded (TnyAccountStore *store, gpointer user_data)
1162 {
1163         /* FIXME */
1164         /* ModestFolderView *folder_view; */
1165         
1166 /*      folder_view = modest_widget_factory_get_folder_view (modest_runtime_get_widget_factory()); */
1167 /*      modest_folder_view_update_model (folder_view, store); */
1168 }
1169
1170 void 
1171 modest_ui_actions_on_folder_moved (ModestFolderView *folder_view,  TnyFolder *folder, 
1172                                     TnyFolderStore *parent,  gboolean *done,
1173                                     gpointer user_data)
1174 {
1175         ModestMailOperation *mail_op;
1176         const GError *error;
1177
1178         *done = TRUE;
1179
1180         /* Try to move the folder */    
1181         mail_op = modest_mail_operation_new ();
1182         modest_mail_operation_move_folder (mail_op, folder, parent);
1183
1184         error = modest_mail_operation_get_error (mail_op);
1185         if (error)
1186                 *done = FALSE;
1187
1188         g_object_unref (G_OBJECT (mail_op));
1189 }
1190
1191
1192
1193 void
1194 modest_ui_actions_on_password_requested (TnyAccountStore *account_store, 
1195                                          const gchar* account_name,
1196                                          gchar **password, 
1197                                          gboolean *cancel, 
1198                                          gboolean *remember,
1199                                          ModestMainWindow *main_window)
1200 {
1201         gchar *txt;
1202         GtkWidget *dialog, *entry, *remember_pass_check;
1203
1204         dialog = gtk_dialog_new_with_buttons (_("Password requested"),
1205                                               NULL,
1206                                               GTK_DIALOG_MODAL,
1207                                               GTK_STOCK_CANCEL,
1208                                               GTK_RESPONSE_REJECT,
1209                                               GTK_STOCK_OK,
1210                                               GTK_RESPONSE_ACCEPT,
1211                                               NULL);
1212         gtk_window_set_transient_for (GTK_WINDOW(dialog), GTK_WINDOW(main_window));
1213         
1214         txt = g_strdup_printf (_("Please enter your password for %s"), account_name);
1215         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), gtk_label_new(txt),
1216                             FALSE, FALSE, 0);
1217         g_free (txt);
1218
1219         entry = gtk_entry_new_with_max_length (40);
1220         gtk_entry_set_visibility (GTK_ENTRY(entry), FALSE);
1221         gtk_entry_set_invisible_char (GTK_ENTRY(entry), 0x2022); /* bullet unichar */
1222         
1223         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), entry,
1224                             TRUE, FALSE, 0);    
1225
1226         remember_pass_check = gtk_check_button_new_with_label (_("Remember password"));
1227         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), remember_pass_check,
1228                             TRUE, FALSE, 0);
1229
1230         gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
1231         
1232         if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
1233                 *password = g_strdup (gtk_entry_get_text (GTK_ENTRY(entry)));
1234                 *cancel   = FALSE;
1235         } else {
1236                 *password = NULL;
1237                 *cancel   = TRUE;
1238         }
1239
1240         if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (remember_pass_check)))
1241                 *remember = TRUE;
1242         else
1243                 *remember = FALSE;
1244
1245         gtk_widget_destroy (dialog);
1246 }