Improved d&d support. Fixed several reference leaks
[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
714
715
716
717 void 
718 modest_ui_actions_on_folder_selection_changed (ModestFolderView *folder_view,
719                                                TnyFolder *folder, 
720                                                gboolean selected,
721                                                ModestMainWindow *main_window)
722 {
723 //      GtkLabel *folder_info_label;
724         gchar *txt;     
725         ModestConf *conf;
726         GtkWidget *header_view;
727         
728 /*      folder_info_label =  */
729 /*              GTK_LABEL (modest_widget_factory_get_folder_info_label */
730 /*                         (modest_runtime_get_widget_factory())); */
731
732 /*      if (!folder) { */
733 /*              gtk_label_set_label (GTK_LABEL(folder_info_label), ""); */
734 /*              return; */
735 /*      } */
736         
737         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
738
739         header_view = modest_main_window_get_child_widget(main_window,
740                                                           MODEST_WIDGET_TYPE_HEADER_VIEW);
741         if (!header_view)
742                 return;
743         
744         conf = modest_runtime_get_conf ();
745
746         if (!selected) { /* the folder was unselected; save it's settings  */
747                 modest_widget_memory_save (conf, G_OBJECT (header_view), "header-view");
748                 gtk_window_set_title (GTK_WINDOW(main_window), "Modest");
749                 modest_header_view_set_folder (MODEST_HEADER_VIEW(header_view), NULL);
750         } else {  /* the folder was selected */
751                 if (folder) { /* folder may be NULL */
752                         guint num, unread;
753                         gchar *title;
754
755                         num    = tny_folder_get_all_count    (folder);
756                         unread = tny_folder_get_unread_count (folder);
757                         
758                         title = g_strdup_printf ("Modest: %s",
759                                                  tny_folder_get_name (folder));
760                         
761                         gtk_window_set_title (GTK_WINDOW(main_window), title);
762                         g_free (title);
763                         
764                         txt = g_strdup_printf (_("%d %s, %d unread"),
765                                                num, num==1 ? _("item") : _("items"), unread);           
766                         //gtk_label_set_label (GTK_LABEL(folder_info_label), txt);
767                         g_free (txt);
768                 }
769                 modest_header_view_set_folder (MODEST_HEADER_VIEW(header_view), folder);
770                 modest_widget_memory_restore (conf, G_OBJECT(header_view),
771                                               "header-view");
772         }
773 }
774
775
776 /****************************************************/
777 /*
778  * below some stuff to clearup statusbar messages after 1,5 seconds....
779  */
780 static gboolean
781 progress_bar_clean (GtkWidget *bar)
782 {
783         if (GTK_IS_PROGRESS_BAR(bar)) {
784                 gtk_progress_bar_set_text     (GTK_PROGRESS_BAR(bar), "");
785                 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR(bar), 1.0);
786         }
787         return FALSE;
788 }
789
790 static gboolean
791 statusbar_clean (GtkWidget *bar)
792 {
793         if (GTK_IS_STATUSBAR(bar))
794                 gtk_statusbar_push (GTK_STATUSBAR(bar), 0, "");
795         return FALSE;
796 }
797
798
799 static void
800 statusbar_push (ModestMainWindow *main_window, guint context_id, const gchar *msg)
801 {
802         if (!msg)
803                 return;
804
805         GtkWidget *progress_bar, *status_bar;
806
807         progress_bar = modest_main_window_get_child_widget (main_window,
808                                                             MODEST_WIDGET_TYPE_PROGRESS_BAR);
809         status_bar = modest_main_window_get_child_widget (main_window,
810                                                           MODEST_WIDGET_TYPE_STATUS_BAR);
811         if (progress_bar) {
812                 gtk_widget_show (progress_bar);
813                 g_timeout_add (3000, (GSourceFunc)progress_bar_clean, progress_bar);
814         }
815         
816         if (status_bar) {
817                 gtk_widget_show (status_bar);
818                 gtk_statusbar_push (GTK_STATUSBAR(status_bar), 0, msg);
819                 g_timeout_add (1500, (GSourceFunc)statusbar_clean, status_bar);
820         }
821
822 }
823 /****************************************************************************/
824
825 void 
826 modest_ui_actions_on_item_not_found (ModestHeaderView *header_view,ModestItemType type,
827                                      ModestWindow *win)
828 {
829         GtkWidget *dialog;
830         gchar *txt, *item;
831         gboolean online;
832
833         item = (type == MODEST_ITEM_TYPE_FOLDER) ? "folder" : "message";
834         
835         if (g_main_depth > 0)   
836                 gdk_threads_enter ();
837         online = tny_device_is_online (modest_runtime_get_device());
838
839         if (online) {
840                 /* already online -- the item is simply not there... */
841                 dialog = gtk_message_dialog_new (GTK_WINDOW (win),
842                                                  GTK_DIALOG_MODAL,
843                                                  GTK_MESSAGE_WARNING,
844                                                  GTK_BUTTONS_OK,
845                                                  _("The %s you selected cannot be found"),
846                                                  item);
847                 gtk_dialog_run (GTK_DIALOG(dialog));
848         } else {
849                 dialog = gtk_dialog_new_with_buttons (_("Connection requested"),
850                                                       GTK_WINDOW (win),
851                                                       GTK_DIALOG_MODAL,
852                                                       GTK_STOCK_CANCEL,
853                                                       GTK_RESPONSE_REJECT,
854                                                       GTK_STOCK_OK,
855                                                       GTK_RESPONSE_ACCEPT,
856                                                       NULL);
857                 txt = g_strdup_printf (_("This %s is not available in offline mode.\n"
858                                          "Do you want to get online?"), item);
859                 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), 
860                                     gtk_label_new (txt), FALSE, FALSE, 0);
861                 gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
862                 g_free (txt);
863
864                 gtk_window_set_default_size (GTK_WINDOW(dialog), 300, 300);
865                 if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
866                         tny_device_force_online (modest_runtime_get_device());
867                 }
868         }
869         gtk_widget_destroy (dialog);
870         if (g_main_depth > 0)   
871                 gdk_threads_leave ();
872 }
873
874
875
876 void
877 modest_ui_actions_on_header_status_update (ModestHeaderView *header_view, 
878                                             const gchar *msg, gint num, 
879                                             gint total,  ModestMainWindow *main_window)
880 {
881         char* txt;
882         GtkWidget *progress_bar;
883
884         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
885
886         progress_bar = modest_main_window_get_child_widget (main_window, 
887                                                             MODEST_WIDGET_TYPE_PROGRESS_BAR);   
888         if (!progress_bar)
889                 return;
890         
891         if (total != 0)
892                 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR(progress_bar),
893                                                (gdouble)num/(gdouble)total);
894         else
895                 gtk_progress_bar_pulse (GTK_PROGRESS_BAR(progress_bar));
896
897         txt = g_strdup_printf (_("Downloading %d of %d"), num, total);
898         gtk_progress_bar_set_text (GTK_PROGRESS_BAR(progress_bar), txt);
899         g_free (txt);
900         
901         statusbar_push (main_window, 0, msg);
902 }
903
904
905 void
906 modest_ui_actions_on_msg_link_hover (ModestMsgView *msgview, const gchar* link,
907                                      ModestWindow *win)
908 {
909         g_message (__FUNCTION__);
910 }       
911
912
913 void
914 modest_ui_actions_on_msg_link_clicked (ModestMsgView *msgview, const gchar* link,
915                                         ModestWindow *win)
916 {
917         g_message (__FUNCTION__);
918 }
919
920 void
921 modest_ui_actions_on_msg_attachment_clicked (ModestMsgView *msgview, int index,
922                                              ModestWindow *win)
923 {
924         g_message (__FUNCTION__);
925         
926 }
927
928 void
929 modest_ui_actions_on_send (GtkWidget *widget, ModestMsgEditWindow *edit_window)
930 {
931         TnyTransportAccount *transport_account;
932         ModestMailOperation *mail_operation;
933         MsgData *data;
934         gchar *account_name, *from;
935         ModestAccountMgr *account_mgr;
936
937         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(edit_window));
938         
939         data = modest_msg_edit_window_get_msg_data (edit_window);
940
941         /* FIXME: Code added just for testing. The final version will
942            use the send queue provided by tinymail and some
943            classifier */
944         account_mgr = modest_runtime_get_account_mgr();
945         account_name = g_strdup(modest_window_get_active_account (MODEST_WINDOW(edit_window)));
946         if (!account_name) 
947                 account_name = modest_account_mgr_get_default_account (account_mgr);
948         if (!account_name) {
949                 g_printerr ("modest: no account found\n");
950                 modest_msg_edit_window_free_msg_data (edit_window, data);
951                 return;
952         }
953         transport_account =
954                 TNY_TRANSPORT_ACCOUNT(modest_tny_account_store_get_tny_account_by_account
955                                       (modest_runtime_get_account_store(),
956                                        account_name,
957                                        TNY_ACCOUNT_TYPE_TRANSPORT));
958         if (!transport_account) {
959                 g_printerr ("modest: no transport account found for '%s'\n", account_name);
960                 g_free (account_name);
961                 modest_msg_edit_window_free_msg_data (edit_window, data);
962                 return;
963         }
964         from = modest_account_mgr_get_from_string (account_mgr, account_name);
965                 
966         mail_operation = modest_mail_operation_new ();
967         modest_mail_operation_send_new_mail (mail_operation,
968                                              transport_account,
969                                              from,
970                                              data->to, 
971                                              data->cc, 
972                                              data->bcc,
973                                              data->subject, 
974                                              data->body, 
975                                              NULL);
976         /* Frees */
977         g_free (from);
978         g_free (account_name);
979         g_object_unref (G_OBJECT (mail_operation));
980         g_object_unref (G_OBJECT (transport_account));
981
982         modest_msg_edit_window_free_msg_data (edit_window, data);
983
984         /* Save settings and close the window */
985         /* save_settings (edit_window) */
986         gtk_widget_destroy (GTK_WIDGET (edit_window));
987 }
988
989 /*
990  * Shows a dialog with an entry that asks for some text. The returned
991  * value must be freed by the caller. The dialog window title will be
992  * set to @title.
993  */
994 static gchar *
995 ask_for_folder_name (GtkWindow *parent_window,
996                      const gchar *title)
997 {
998         GtkWidget *dialog, *entry;
999         gchar *folder_name = NULL;
1000
1001         /* Ask for folder name */
1002         dialog = gtk_dialog_new_with_buttons (_("New Folder Name"),
1003                                               parent_window,
1004                                               GTK_DIALOG_MODAL,
1005                                               GTK_STOCK_CANCEL,
1006                                               GTK_RESPONSE_REJECT,
1007                                               GTK_STOCK_OK,
1008                                               GTK_RESPONSE_ACCEPT,
1009                                               NULL);
1010         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), 
1011                             gtk_label_new(title),
1012                             FALSE, FALSE, 0);
1013                 
1014         entry = gtk_entry_new_with_max_length (40);
1015         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), 
1016                             entry,
1017                             TRUE, FALSE, 0);    
1018         
1019         gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
1020         
1021         if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)         
1022                 folder_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
1023
1024         gtk_widget_destroy (dialog);
1025
1026         return folder_name;
1027 }
1028
1029 void 
1030 modest_ui_actions_on_new_folder (GtkWidget *widget, ModestMainWindow *main_window)
1031 {
1032         TnyFolder *parent_folder;
1033         GtkWidget *folder_view;
1034         
1035         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
1036
1037         folder_view = modest_main_window_get_child_widget (main_window,
1038                                                            MODEST_WIDGET_TYPE_FOLDER_VIEW);
1039         if (!folder_view)
1040                 return;
1041
1042         parent_folder = modest_folder_view_get_selected (MODEST_FOLDER_VIEW(folder_view));
1043         
1044         if (parent_folder) {
1045                 gchar *folder_name;
1046
1047                 folder_name = ask_for_folder_name (GTK_WINDOW (main_window),
1048                                                    _("Please enter a name for the new folder"));
1049
1050                 if (folder_name != NULL && strlen (folder_name) > 0) {
1051                         TnyFolder *new_folder;
1052                         ModestMailOperation *mail_op;
1053
1054                         mail_op = modest_mail_operation_new ();
1055                         new_folder = modest_mail_operation_create_folder (mail_op,
1056                                                                           TNY_FOLDER_STORE (parent_folder),
1057                                                                           (const gchar *) folder_name);
1058                         if (new_folder) {
1059                                 /* TODO: tinymail should do this. 
1060                                    Update view */
1061                                 modest_folder_view_add_subfolder (MODEST_FOLDER_VIEW(folder_view),
1062                                                                   new_folder);
1063
1064                                 /* Free new folder */
1065                                 g_object_unref (new_folder);
1066                         }
1067                         g_object_unref (mail_op);
1068                 }
1069                 g_object_unref (parent_folder);
1070         }
1071 }
1072
1073 void 
1074 modest_ui_actions_on_rename_folder (GtkWidget *widget,
1075                                      ModestMainWindow *main_window)
1076 {
1077         TnyFolder *folder;
1078         GtkWidget *folder_view;
1079         
1080         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
1081
1082         folder_view = modest_main_window_get_child_widget (main_window,
1083                                                            MODEST_WIDGET_TYPE_FOLDER_VIEW);
1084         if (!folder_view)
1085                 return;
1086         
1087         folder = modest_folder_view_get_selected (MODEST_FOLDER_VIEW(folder_view));
1088         
1089         if (folder) {
1090                 gchar *folder_name;
1091                 folder_name = ask_for_folder_name (GTK_WINDOW (main_window),
1092                                                    _("Please enter a new name for the folder"));
1093
1094                 if (folder_name != NULL && strlen (folder_name) > 0) {
1095                         ModestMailOperation *mail_op;
1096                         const GError *error;
1097
1098                         mail_op = modest_mail_operation_new ();
1099                         modest_mail_operation_rename_folder (mail_op,
1100                                                              folder,
1101                                                              (const gchar *) folder_name);
1102
1103                         error = modest_mail_operation_get_error (mail_op);
1104                         if (!error)
1105                                 /* TODO: tinymail should do this. 
1106                                    Update view */
1107                                 modest_folder_view_rename (MODEST_FOLDER_VIEW(folder_view));
1108                         else
1109                                 /* TODO: notify error ? */
1110                                 g_warning ("Could not rename a folder: %s\n", error->message);
1111
1112                         g_object_unref (mail_op);
1113                 }
1114                 g_object_unref (folder);
1115         }
1116 }
1117
1118 static void
1119 delete_folder (ModestMainWindow *main_window, gboolean move_to_trash) 
1120 {
1121         TnyFolder *folder;
1122         ModestMailOperation *mail_op;
1123         GtkWidget *folder_view;
1124         const GError *error;
1125         
1126         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
1127
1128         folder_view = modest_main_window_get_child_widget (main_window,
1129                                                            MODEST_WIDGET_TYPE_FOLDER_VIEW);
1130         if (!folder_view)
1131                 return;
1132
1133         folder = modest_folder_view_get_selected (MODEST_FOLDER_VIEW(folder_view));
1134         
1135         mail_op = modest_mail_operation_new ();
1136         modest_mail_operation_remove_folder (mail_op, folder, move_to_trash);
1137
1138         error = modest_mail_operation_get_error (mail_op);
1139         if (error)
1140                 g_warning ("%s\n", error->message);
1141
1142         g_object_unref (mail_op);
1143 }
1144
1145 void 
1146 modest_ui_actions_on_delete_folder (GtkWidget *widget,
1147                                      ModestMainWindow *main_window)
1148 {
1149         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
1150
1151         delete_folder (main_window, FALSE);
1152 }
1153
1154 void 
1155 modest_ui_actions_on_move_folder_to_trash_folder (GtkWidget *widget, ModestMainWindow *main_window)
1156 {
1157         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
1158         
1159         delete_folder (main_window, TRUE);
1160 }
1161
1162 void 
1163 modest_ui_actions_on_folder_xfer (ModestFolderView *folder_view,  
1164                                   TnyFolder        *folder, 
1165                                   TnyFolderStore   *parent,
1166                                   gboolean          delete_source,
1167                                   TnyFolder        **new_folder,
1168                                   gpointer          user_data)
1169 {
1170         ModestMailOperation *mail_op;
1171         const GError *error;
1172
1173         /* Try to move the folder */
1174         mail_op = modest_mail_operation_new ();
1175         *new_folder = modest_mail_operation_xfer_folder (mail_op, folder, parent, delete_source);
1176
1177         error = modest_mail_operation_get_error (mail_op);
1178         if (error)
1179                 g_warning ("Error transferring folder: %s\n", error->message);
1180
1181         g_object_unref (G_OBJECT (mail_op));
1182 }
1183
1184
1185
1186 void
1187 modest_ui_actions_on_password_requested (TnyAccountStore *account_store, 
1188                                          const gchar* account_name,
1189                                          gchar **password, 
1190                                          gboolean *cancel, 
1191                                          gboolean *remember,
1192                                          ModestMainWindow *main_window)
1193 {
1194         gchar *txt;
1195         GtkWidget *dialog, *entry, *remember_pass_check;
1196
1197         dialog = gtk_dialog_new_with_buttons (_("Password requested"),
1198                                               NULL,
1199                                               GTK_DIALOG_MODAL,
1200                                               GTK_STOCK_CANCEL,
1201                                               GTK_RESPONSE_REJECT,
1202                                               GTK_STOCK_OK,
1203                                               GTK_RESPONSE_ACCEPT,
1204                                               NULL);
1205         gtk_window_set_transient_for (GTK_WINDOW(dialog), GTK_WINDOW(main_window));
1206         
1207         txt = g_strdup_printf (_("Please enter your password for %s"), account_name);
1208         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), gtk_label_new(txt),
1209                             FALSE, FALSE, 0);
1210         g_free (txt);
1211
1212         entry = gtk_entry_new_with_max_length (40);
1213         gtk_entry_set_visibility (GTK_ENTRY(entry), FALSE);
1214         gtk_entry_set_invisible_char (GTK_ENTRY(entry), 0x2022); /* bullet unichar */
1215         
1216         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), entry,
1217                             TRUE, FALSE, 0);    
1218
1219         remember_pass_check = gtk_check_button_new_with_label (_("Remember password"));
1220         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), remember_pass_check,
1221                             TRUE, FALSE, 0);
1222
1223         gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
1224         
1225         if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
1226                 *password = g_strdup (gtk_entry_get_text (GTK_ENTRY(entry)));
1227                 *cancel   = FALSE;
1228         } else {
1229                 *password = NULL;
1230                 *cancel   = TRUE;
1231         }
1232
1233         if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (remember_pass_check)))
1234                 *remember = TRUE;
1235         else
1236                 *remember = FALSE;
1237
1238         gtk_widget_destroy (dialog);
1239 }