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