* modest-ui.c:
[modest] / src / modest-ui.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-ui-priv.h"
37 #include "modest-ui.h"
38 #include "modest-ui-actions.h"
39 #include "modest-icon-names.h"
40 #include "modest-tny-platform-factory.h"
41 #include "modest-account-view-window.h"
42 #include "modest-main-window.h"
43 #include "modest-mail-operation.h"
44 #include <modest-widget-memory.h>
45 #include <tny-error.h>
46 #include <tny-simple-list.h>
47 #include <tny-msg-view.h>
48
49 #define MODEST_UI_GET_PRIVATE(o)      (G_TYPE_INSTANCE_GET_PRIVATE((o), \
50                                        MODEST_TYPE_UI, \
51                                        ModestUIPrivate))
52
53 typedef struct _GetMsgAsyncHelper {
54         ModestMainWindow *main_window;
55         TnyIterator *iter;
56         GFunc func;
57         gpointer user_data;
58 } GetMsgAsyncHelper;
59
60 typedef enum _ReplyForwardAction {
61         ACTION_REPLY,
62         ACTION_REPLY_TO_ALL,
63         ACTION_FORWARD
64 } ReplyForwardAction;
65
66 typedef struct _ReplyForwardHelper {
67         guint reply_forward_type;
68         ReplyForwardAction action;
69         gchar *from;
70 } ReplyForwardHelper;
71
72 /* globals */
73 static GObjectClass *parent_class = NULL;
74
75 /* 'private'/'protected' functions */
76 static void     modest_ui_class_init   (ModestUIClass *klass);
77 static void     modest_ui_init         (ModestUI *obj);
78 static void     modest_ui_finalize     (GObject *obj);
79
80 static void     register_stock_icons   ();
81 static void     connect_signals        (ModestUI *self);
82
83 static void     reply_forward_func     (gpointer data, 
84                                         gpointer user_data);
85 static void     read_msg_func          (gpointer data, 
86                                         gpointer user_data);
87 static void     get_msg_cb             (TnyFolder *folder, 
88                                         TnyMsg *msg, 
89                                         GError **err, 
90                                         gpointer user_data);
91
92 static void     reply_forward          (GtkWidget *widget,
93                                         ReplyForwardAction action,
94                                         ModestMainWindow *main_window);
95
96 static gchar*   ask_for_folder_name    (GtkWindow *parent_window,
97                                         const gchar *title);
98
99 static void    _modest_ui_actions_on_password_requested   (ModestTnyAccountStore *account_store, 
100                                                          const gchar* account_name,
101                                                          gchar **password, 
102                                                          gboolean *cancel, 
103                                                          gboolean *remember, 
104                                                          ModestMainWindow *main_window);
105
106 GType
107 modest_ui_get_type (void)
108 {
109         static GType my_type = 0;
110         if (!my_type) {
111                 static const GTypeInfo my_info = {
112                         sizeof(ModestUIClass),
113                         NULL,           /* base init */
114                         NULL,           /* base finalize */
115                         (GClassInitFunc) modest_ui_class_init,
116                         NULL,           /* class finalize */
117                         NULL,           /* class data */
118                         sizeof(ModestUI),
119                         1,              /* n_preallocs */
120                         (GInstanceInitFunc) modest_ui_init,
121                         NULL
122                 };
123                 my_type = g_type_register_static (G_TYPE_OBJECT,
124                                                   "ModestUI",
125                                                   &my_info, 0);
126         }
127         return my_type;
128 }
129
130
131 static void
132 modest_ui_class_init (ModestUIClass *klass)
133 {
134         GObjectClass *gobject_class;
135         gobject_class = (GObjectClass*) klass;
136
137         parent_class            = g_type_class_peek_parent (klass);
138         gobject_class->finalize = modest_ui_finalize;
139
140         g_type_class_add_private (gobject_class, sizeof(ModestUIPrivate));
141
142 }
143
144
145 static void
146 modest_ui_init (ModestUI *obj)
147 {
148         ModestUIPrivate *priv;
149
150         priv = MODEST_UI_GET_PRIVATE(obj);
151
152         priv->widget_factory = NULL;
153         priv->main_window    = NULL;
154         priv->account_store  = NULL;
155 }
156
157
158 static void
159 modest_ui_finalize (GObject *obj)
160 {
161         
162         ModestUIPrivate *priv = MODEST_UI_GET_PRIVATE(obj);
163         
164         if (priv->widget_factory) {
165                 g_object_unref (G_OBJECT(priv->widget_factory));
166                 priv->widget_factory = NULL;
167         }
168
169         if (priv->ui_manager) {
170                 g_object_unref (G_OBJECT(priv->ui_manager));
171                 priv->ui_manager = NULL;
172         }
173         
174         G_OBJECT_CLASS(parent_class)->finalize (obj);
175 }
176
177
178 ModestUI*
179 modest_ui_new (TnyAccountStore *account_store)
180 {
181         GObject *obj;
182         ModestUIPrivate *priv;
183         TnyPlatformFactory *fact;
184         ModestAccountMgr *account_mgr;
185
186         obj  = g_object_new(MODEST_TYPE_UI, NULL);
187         priv = MODEST_UI_GET_PRIVATE(obj);
188
189         /* Get the platform-dependent instances */
190         fact = modest_tny_platform_factory_get_instance ();
191         
192         priv->account_store = account_store;
193
194         account_mgr = modest_tny_platform_factory_get_account_mgr_instance
195                 (MODEST_TNY_PLATFORM_FACTORY(fact));
196         if (!account_mgr) {
197                 g_printerr ("modest: could not create ModestAccountMgr instance\n");
198                 g_object_unref (obj);
199                 return NULL;
200         }
201
202         priv->widget_factory = modest_widget_factory_new ();
203         if (!priv->widget_factory) {
204                 g_printerr ("modest: could not initialize widget factory\n");
205                 return NULL;
206         }
207
208         /* Register our own icons as stock icons in order to
209            use them with the UI manager */
210         register_stock_icons ();
211                 
212         return MODEST_UI(obj);
213 }
214
215 static gboolean
216 on_main_window_destroy (GtkObject *widget, ModestUI *self)
217 {
218         /* FIXME: check if there any viewer/editing windows opened */
219         gtk_main_quit ();
220         return FALSE;
221 }
222
223
224 ModestWindow *
225 modest_ui_main_window (ModestUI *self)
226 {
227         ModestUIPrivate *priv;
228
229         g_return_val_if_fail (self, NULL);
230         priv = MODEST_UI_GET_PRIVATE(self);
231
232         if (!priv->main_window) {
233
234                 /* Create main window */
235                 priv->main_window = modest_main_window_new (priv->widget_factory,
236                                                             priv->account_store);
237
238                 connect_signals (self);
239         }
240                 
241         if (!priv->main_window)
242                 g_printerr ("modest: could not create main window\n");
243         
244         return priv->main_window;
245 }
246
247 ModestWindow *
248 modest_ui_edit_window (ModestUI *self, ModestEditType edit_type)
249 {
250         ModestUIPrivate *priv;
251         ModestWindow *edit_window;
252
253         g_return_val_if_fail (self, NULL);
254         priv = MODEST_UI_GET_PRIVATE(self);
255
256         /* Create window */
257         edit_window = modest_edit_msg_window_new (priv->widget_factory, 
258                                                   priv->account_store,
259                                                   edit_type);
260         
261         /* Connect Edit Window signals */
262 /*      connect_edit_window_signals (self); */
263                 
264         return edit_window;
265 }
266
267 /* 
268  *  This function registers our custom toolbar icons, so they can be
269  *  themed. The idea of this function was taken from the gtk-demo
270  */
271 static void
272 register_stock_icons ()
273 {
274         static gboolean registered = FALSE;
275   
276         if (!registered) {
277                 GdkPixbuf *pixbuf;
278                 GtkIconFactory *factory;
279                 gint i;
280
281                 static GtkStockItem items[] = {
282                         { MODEST_STOCK_MAIL_SEND, "send mail", 0, 0, NULL },
283                         { MODEST_STOCK_NEW_MAIL, "new mail", 0, 0, NULL },
284                         { MODEST_STOCK_SEND_RECEIVE, "send receive", 0, 0, NULL },
285                         { MODEST_STOCK_REPLY, "reply", 0, 0, NULL },
286                         { MODEST_STOCK_REPLY_ALL, "reply all", 0, 0, NULL },
287                         { MODEST_STOCK_FORWARD, "forward", 0, 0, NULL },
288                         { MODEST_STOCK_DELETE, "delete", 0, 0, NULL },
289                         { MODEST_STOCK_NEXT, "next", 0, 0, NULL },
290                         { MODEST_STOCK_PREV, "prev", 0, 0, NULL },
291                         { MODEST_STOCK_STOP, "stop", 0, 0, NULL }
292                 };
293       
294                 static gchar *items_names [] = {
295                         MODEST_TOOLBAR_ICON_MAIL_SEND,
296                         MODEST_TOOLBAR_ICON_NEW_MAIL,           
297                         MODEST_TOOLBAR_ICON_SEND_RECEIVE,
298                         MODEST_TOOLBAR_ICON_REPLY,      
299                         MODEST_TOOLBAR_ICON_REPLY_ALL,
300                         MODEST_TOOLBAR_ICON_FORWARD,
301                         MODEST_TOOLBAR_ICON_DELETE,
302                         MODEST_TOOLBAR_ICON_NEXT,
303                         MODEST_TOOLBAR_ICON_PREV,
304                         MODEST_TOOLBAR_ICON_STOP
305                 };
306
307                 registered = TRUE;
308
309                 /* Register our stock items */
310                 gtk_stock_add (items, G_N_ELEMENTS (items));
311       
312                 /* Add our custom icon factory to the list of defaults */
313                 factory = gtk_icon_factory_new ();
314                 gtk_icon_factory_add_default (factory);
315
316                 /* Register icons to accompany stock items */
317                 for (i = 0; i < G_N_ELEMENTS (items); i++) {
318                         pixbuf = NULL;
319                         pixbuf = gdk_pixbuf_new_from_file (items_names[i], NULL);
320
321                         if (pixbuf != NULL) {
322                                 GtkIconSet *icon_set;
323                                 GdkPixbuf *transparent;
324
325                                 transparent = gdk_pixbuf_add_alpha (pixbuf, TRUE, 0xff, 0xff, 0xff);
326
327                                 icon_set = gtk_icon_set_new_from_pixbuf (transparent);
328                                 gtk_icon_factory_add (factory, items[i].stock_id, icon_set);
329                                 gtk_icon_set_unref (icon_set);
330                                 g_object_unref (pixbuf);
331                                 g_object_unref (transparent);
332                         }
333                         else
334                                 g_warning ("failed to load %s icon", items_names[i]);
335                 }
336                 /* Drop our reference to the factory, GTK will hold a reference. */
337                 g_object_unref (factory);
338         }
339 }
340
341 /* FIXME: uninit these as well */
342 static void
343 connect_signals (ModestUI *self)
344 {
345         TnyDevice *device;
346         ModestUIPrivate *priv;
347         ModestFolderView *folder_view;
348         ModestHeaderView *header_view;
349         ModestMsgView *msg_view;
350         GtkWidget *toggle;
351         
352         priv = MODEST_UI_GET_PRIVATE(self);
353
354         folder_view = modest_widget_factory_get_folder_view (priv->widget_factory);
355         header_view = modest_widget_factory_get_header_view (priv->widget_factory);
356         msg_view    = modest_widget_factory_get_msg_preview (priv->widget_factory);
357         toggle      = modest_widget_factory_get_online_toggle (priv->widget_factory);
358         device      = tny_account_store_get_device (priv->account_store);
359
360         /* folder view */
361         g_signal_connect (G_OBJECT(folder_view), "folder_selection_changed",
362                           G_CALLBACK(_modest_ui_actions_on_folder_selection_changed),
363                           priv->main_window);   
364         /* header view */
365         g_signal_connect (G_OBJECT(header_view), "status_update",
366                           G_CALLBACK(_modest_ui_actions_on_header_status_update), 
367                           priv->main_window);
368         g_signal_connect (G_OBJECT(header_view), "header_selected",
369                           G_CALLBACK(_modest_ui_actions_on_header_selected), 
370                           priv->main_window);
371         g_signal_connect (G_OBJECT(header_view), "item_not_found",
372                           G_CALLBACK(_modest_ui_actions_on_item_not_found), 
373                           priv->main_window);
374         /* msg preview */
375         g_signal_connect (G_OBJECT(msg_view), "link_clicked",
376                           G_CALLBACK(_modest_ui_actions_on_msg_link_clicked), 
377                           priv->main_window);
378         g_signal_connect (G_OBJECT(msg_view), "link_hover",
379                           G_CALLBACK(_modest_ui_actions_on_msg_link_hover), 
380                           priv->main_window);
381         g_signal_connect (G_OBJECT(msg_view), "attachment_clicked",
382                           G_CALLBACK(_modest_ui_actions_on_msg_attachment_clicked), 
383                           priv->main_window);
384
385         /* Device */
386         g_signal_connect (G_OBJECT(device), "connection_changed",
387                           G_CALLBACK(_modest_ui_actions_on_connection_changed), 
388                           priv->main_window);
389         g_signal_connect (G_OBJECT(toggle), "toggled",
390                           G_CALLBACK(_modest_ui_actions_on_online_toggle_toggled),
391                           priv->main_window);
392                 
393         /* account store */
394         g_signal_connect (G_OBJECT (priv->account_store), 
395                           "password_requested",
396                           G_CALLBACK(_modest_ui_actions_on_password_requested),
397                           priv->main_window);
398
399         /* Destroy window */
400         g_signal_connect (G_OBJECT(priv->main_window), 
401                           "destroy",
402                           G_CALLBACK(on_main_window_destroy), 
403                           NULL);
404
405
406         /* Init toggle in correct state */
407         _modest_ui_actions_on_connection_changed (device,
408                                                  tny_device_is_online (device),
409                                                  MODEST_MAIN_WINDOW (priv->main_window));
410 }
411
412
413 /* ***************************************************************** */
414 /*                M O D E S T    U I    A C T I O N S                */
415 /* ***************************************************************** */
416 void   
417 _modest_ui_actions_on_about (GtkWidget *widget, 
418                              ModestMainWindow *main_window)
419 {
420         GtkWidget *about;
421         const gchar *authors[] = {
422                 "Dirk-Jan C. Binnema <dirk-jan.binnema@nokia.com>",
423                 NULL
424         };
425         about = gtk_about_dialog_new ();
426         gtk_about_dialog_set_name (GTK_ABOUT_DIALOG(about), PACKAGE_NAME);
427         gtk_about_dialog_set_version (GTK_ABOUT_DIALOG(about),PACKAGE_VERSION);
428         gtk_about_dialog_set_copyright (GTK_ABOUT_DIALOG(about),
429                                         _("Copyright (c) 2006, Nokia Corporation\n"
430                                           "All rights reserved."));
431         gtk_about_dialog_set_comments (GTK_ABOUT_DIALOG(about),
432                                        _("a modest e-mail client\n\n"
433                                          "design and implementation: Dirk-Jan C. Binnema\n"
434                                          "contributions from the fine people at KernelConcepts and Igalia\n"
435                                          "uses the tinymail email framework written by Philip van Hoof"));
436         gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG(about), authors);
437         gtk_about_dialog_set_website (GTK_ABOUT_DIALOG(about), "http://modest.garage.maemo.org");
438
439         gtk_dialog_run (GTK_DIALOG (about));
440         gtk_widget_destroy(about);
441 }
442
443 void
444 _modest_ui_actions_on_delete (GtkWidget *widget, 
445                              ModestMainWindow *main_window)
446 {
447         ModestWidgetFactory *widget_factory;
448         ModestHeaderView *header_view;
449         TnyList *header_list;
450         TnyIterator *iter;
451         GtkTreeModel *model;
452
453         widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
454         header_view = modest_widget_factory_get_header_view (widget_factory);
455         header_list = modest_header_view_get_selected_headers (header_view);
456         g_object_unref (G_OBJECT(widget_factory));
457         
458         if (header_list) {
459                 iter = tny_list_create_iterator (header_list);
460                 model = gtk_tree_view_get_model (GTK_TREE_VIEW (header_view));
461                 if (GTK_IS_TREE_MODEL_SORT (model))
462                         model = gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (model));
463                 do {
464                         TnyHeader *header;
465                         ModestMailOperation *mail_op;
466
467                         header = TNY_HEADER (tny_iterator_get_current (iter));
468                         /* TODO: thick grain mail operation involving
469                            a list of objects. Composite pattern ??? */
470                         mail_op = modest_mail_operation_new ();
471
472                         /* TODO: add confirmation dialog */
473
474                         /* Move to trash */
475                         modest_mail_operation_remove_msg (mail_op, header, TRUE);
476
477                         /* Remove from tree model */
478                         if (modest_mail_operation_get_status (mail_op) == 
479                             MODEST_MAIL_OPERATION_STATUS_SUCCESS)
480                                 tny_list_remove (TNY_LIST (model), G_OBJECT (header));
481                         else {
482                                 /* TODO: error handling management */
483                                 const GError *error;
484                                 error = modest_mail_operation_get_error (mail_op);
485                                 g_warning (error->message);
486                         }
487
488                         g_object_unref (G_OBJECT (mail_op));
489                         g_object_unref (header);
490                         tny_iterator_next (iter);
491
492                 } while (!tny_iterator_is_done (iter));
493         }
494 }
495
496 void
497 _modest_ui_actions_on_quit (GtkWidget *widget, 
498                            ModestMainWindow *main_window)
499 {
500         /* FIXME: save size of main window */
501 /*      save_sizes (main_window); */
502         gtk_widget_destroy (GTK_WIDGET (main_window));
503 }
504
505 void
506 _modest_ui_actions_on_accounts (GtkWidget *widget, 
507                                ModestMainWindow *main_window)
508 {
509         GtkWidget *account_win;
510         ModestWidgetFactory *widget_factory;
511
512         widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
513         account_win = modest_account_view_window_new (widget_factory);
514         g_object_unref (G_OBJECT(widget_factory));
515
516         gtk_window_set_transient_for (GTK_WINDOW (account_win),
517                                       GTK_WINDOW (main_window));
518                                       
519         gtk_widget_show (account_win);
520 }
521
522 void
523 _modest_ui_actions_on_new_msg (GtkWidget *widget, 
524                                ModestMainWindow *main_window)
525 {
526         ModestWindow *msg_win;
527         ModestWidgetFactory *widget_factory;
528         TnyAccountStore *account_store;
529
530         widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
531         account_store = modest_window_get_account_store (MODEST_WINDOW (main_window));
532         msg_win = modest_edit_msg_window_new (widget_factory, 
533                                               account_store,
534                                               MODEST_EDIT_TYPE_NEW);
535         g_object_unref (G_OBJECT (widget_factory));
536         g_object_unref (G_OBJECT (account_store));
537
538         gtk_widget_show (GTK_WIDGET (msg_win));
539 }
540
541 static void
542 reply_forward_func (gpointer data, gpointer user_data)
543 {
544         ModestWidgetFactory *widget_factory;
545         TnyHeader *new_header;
546         TnyMsg *msg, *new_msg;
547         TnyAccountStore *account_store;
548         GetMsgAsyncHelper *helper;
549         ReplyForwardHelper *rf_helper;
550         ModestWindow *msg_win;
551         ModestEditType edit_type;
552
553         msg = TNY_MSG (data);
554         helper = (GetMsgAsyncHelper *) user_data;
555         rf_helper = (ReplyForwardHelper *) helper->user_data;
556
557         /* Create reply mail */
558         switch (rf_helper->action) {
559         case ACTION_REPLY:
560                 new_msg = 
561                         modest_mail_operation_create_reply_mail (msg, 
562                                                                  rf_helper->from, 
563                                                                  rf_helper->reply_forward_type,
564                                                                  MODEST_MAIL_OPERATION_REPLY_MODE_SENDER);
565         case ACTION_REPLY_TO_ALL:
566                 new_msg = 
567                         modest_mail_operation_create_reply_mail (msg, rf_helper->from, rf_helper->reply_forward_type,
568                                                                  MODEST_MAIL_OPERATION_REPLY_MODE_ALL);
569                 edit_type = MODEST_EDIT_TYPE_REPLY;
570                 break;
571         case ACTION_FORWARD:
572                 new_msg = 
573                         modest_mail_operation_create_forward_mail (msg, rf_helper->from, rf_helper->reply_forward_type);
574                 edit_type = MODEST_EDIT_TYPE_FORWARD;
575                 break;
576         default:
577                 g_return_if_reached ();
578         }
579
580         /* Set from */
581         new_header = tny_msg_get_header (new_msg);
582         tny_header_set_from (new_header, rf_helper->from);
583         g_object_unref (G_OBJECT (new_header));
584                 
585         /* Show edit window */
586         widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (helper->main_window));
587         account_store = modest_window_get_account_store (MODEST_WINDOW (helper->main_window));
588         msg_win = modest_edit_msg_window_new (widget_factory, 
589                                               account_store,
590                                               MODEST_EDIT_TYPE_NEW);
591         g_object_unref (G_OBJECT (widget_factory));
592         g_object_unref (G_OBJECT (account_store));
593         modest_edit_msg_window_set_msg (MODEST_EDIT_MSG_WINDOW (msg_win),
594                                         new_msg);
595         gtk_widget_show (GTK_WIDGET (msg_win));
596         
597         /* Clean */
598         g_object_unref (G_OBJECT (new_msg));
599         g_free (rf_helper->from);
600         g_slice_free (ReplyForwardHelper, rf_helper);
601 }
602
603 /*
604  * Common code for the reply and forward actions
605  */
606 static void
607 reply_forward (GtkWidget *widget,
608                ReplyForwardAction action,
609                ModestMainWindow *main_window)
610 {
611         ModestHeaderView *header_view;
612         ModestWidgetFactory *widget_factory;
613         TnyList *header_list;
614         guint reply_forward_type;
615         ModestConf *conf;
616         TnyPlatformFactory *plat_factory;
617         TnyHeader *header;
618         TnyFolder *folder;
619         gchar *from, *key;
620         GetMsgAsyncHelper *helper;
621         ReplyForwardHelper *rf_helper;
622
623         /* Get ModestConf */
624         plat_factory = modest_tny_platform_factory_get_instance ();
625         conf = modest_tny_platform_factory_get_conf_instance
626                 (MODEST_TNY_PLATFORM_FACTORY(plat_factory));
627
628         /* Get reply or forward type */
629         key = g_strdup_printf ("%s/%s", MODEST_CONF_NAMESPACE, 
630                                (action == ACTION_FORWARD) ? MODEST_CONF_FORWARD_TYPE : MODEST_CONF_REPLY_TYPE);
631         reply_forward_type = modest_conf_get_int (conf, key, NULL);
632         g_free (key);
633
634         /* Get the list of headers */
635         widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
636         header_view = modest_widget_factory_get_header_view (widget_factory);
637         header_list = modest_header_view_get_selected_headers (header_view);
638         g_object_unref (G_OBJECT(widget_factory));
639
640         if (!header_list)
641                 return;
642
643         /* We assume that we can only select messages of the
644            same folder and that we reply all of them from the
645            same account. In fact the interface currently only
646            allows single selection */
647
648         /* TODO: get the from string from account */
649         from = g_strdup ("Invalid");
650         
651         /* Fill helpers */
652         rf_helper = g_slice_new0 (ReplyForwardHelper);
653         rf_helper->reply_forward_type = reply_forward_type;
654         rf_helper->action = action;
655         rf_helper->from = from;
656         
657         helper = g_slice_new0 (GetMsgAsyncHelper);
658         helper->main_window = main_window;
659         helper->func = reply_forward_func;
660         helper->iter = tny_list_create_iterator (header_list);
661         helper->user_data = rf_helper;
662         
663         header = TNY_HEADER (tny_iterator_get_current (helper->iter));
664         folder = tny_header_get_folder (header);
665         
666         /* The callback will call it per each header */
667         tny_folder_get_msg_async (folder, header, get_msg_cb, helper);
668         
669         /* Clean */
670         g_object_unref (G_OBJECT (folder));
671 }
672
673 void
674 _modest_ui_actions_on_reply (GtkWidget *widget,
675                             ModestMainWindow *main_window)
676 {
677         reply_forward (widget, ACTION_REPLY, main_window);
678 }
679
680 void
681 _modest_ui_actions_on_forward (GtkWidget *widget,
682                               ModestMainWindow *main_window)
683 {
684         reply_forward (widget, ACTION_FORWARD, main_window);
685 }
686
687 void
688 _modest_ui_actions_on_reply_all (GtkWidget *widget,
689                                 ModestMainWindow *main_window)
690 {
691         reply_forward (widget, ACTION_REPLY_TO_ALL, main_window);
692 }
693
694 void 
695 _modest_ui_actions_on_next (GtkWidget *widget, 
696                            ModestMainWindow *main_window)
697 {
698         ModestHeaderView *header_view;
699         ModestWidgetFactory *widget_factory;
700
701         widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
702         header_view = modest_widget_factory_get_header_view (widget_factory);
703         g_object_unref (G_OBJECT(widget_factory));
704
705         modest_header_view_select_next (header_view);
706 }
707
708 void
709 _modest_ui_actions_toggle_view (GtkWidget *widget,
710                                 ModestMainWindow *main_window)
711 {
712         ModestHeaderView *header_view;
713         ModestWidgetFactory *widget_factory;
714         ModestConf *conf;
715         TnyPlatformFactory *plat_factory;
716
717         /* Get ModestConf */
718         plat_factory = modest_tny_platform_factory_get_instance ();
719         conf = modest_tny_platform_factory_get_conf_instance
720                 (MODEST_TNY_PLATFORM_FACTORY(plat_factory));
721         widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
722         header_view = modest_widget_factory_get_header_view (widget_factory);
723         g_object_unref (G_OBJECT(widget_factory));
724
725         /* what is saved/restored is depending on the style; thus; we save with
726          * old style, then update the style, and restore for this new style*/
727         modest_widget_memory_save (conf, G_OBJECT(header_view), "header-view");
728         
729         if (modest_header_view_get_style (header_view) == MODEST_HEADER_VIEW_STYLE_DETAILS)
730                 modest_header_view_set_style (header_view, MODEST_HEADER_VIEW_STYLE_TWOLINES);
731         else
732                 modest_header_view_set_style (header_view, MODEST_HEADER_VIEW_STYLE_DETAILS);
733
734         modest_widget_memory_restore (conf, G_OBJECT(header_view), "header-view");
735 }
736
737
738
739 /*
740  * Marks a message as read and passes it to the msg preview widget
741  */
742 static void
743 read_msg_func (gpointer data, gpointer user_data)
744 {
745         ModestMsgView *msg_view;
746         ModestWidgetFactory *widget_factory;
747         TnyMsg *msg;
748         TnyHeader *header;
749         GetMsgAsyncHelper *helper;
750         TnyHeaderFlags header_flags;
751
752         msg = TNY_MSG (data);
753         helper = (GetMsgAsyncHelper *) user_data;
754
755         /* mark message as seen; _set_flags crashes, bug in tinymail? */
756         header = TNY_HEADER (tny_iterator_get_current (helper->iter));
757         header_flags = tny_header_get_flags (header);
758         tny_header_set_flags (header, header_flags | TNY_HEADER_FLAG_SEEN);
759         g_object_unref (G_OBJECT (header));
760
761         /* Set message on msg view */
762         widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (helper->main_window));
763         msg_view = modest_widget_factory_get_msg_preview (widget_factory);
764         g_object_unref (G_OBJECT(widget_factory));
765         modest_msg_view_set_message (msg_view, msg);
766 }
767
768 /*
769  * This function is a generic handler for the tny_folder_get_msg_async
770  * call. It expects as user_data a #GetMsgAsyncHelper. This helper
771  * contains a user provided function that is called inside this
772  * method. This will allow us to use this callback in many different
773  * places. This callback performs the common actions for the
774  * get_msg_async call, more specific actions will be done by the user
775  * function
776  */
777 static void
778 get_msg_cb (TnyFolder *folder, TnyMsg *msg, GError **err, gpointer user_data)
779 {
780         GetMsgAsyncHelper *helper;
781
782         helper = (GetMsgAsyncHelper *) user_data;
783
784         if (*err && ((*err)->code == TNY_FOLDER_ERROR_GET_MSG)) {
785                 ModestHeaderView *header_view;
786                 ModestWidgetFactory *widget_factory;
787
788                 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (helper->main_window));
789                 header_view = modest_widget_factory_get_header_view (widget_factory);
790                 g_object_unref (G_OBJECT (widget_factory));
791                 _modest_ui_actions_on_item_not_found (header_view, 
792                                                       MODEST_ITEM_TYPE_MESSAGE, 
793                                                       helper->main_window);
794                 return;
795         }
796
797         if (!msg)
798                 return;
799
800         /* Call user function */
801         helper->func (msg, user_data);
802
803         /* Process next element (if exists) */
804         tny_iterator_next (helper->iter);
805         if (tny_iterator_is_done (helper->iter)) {
806                 TnyList *headers;
807                 headers = tny_iterator_get_list (helper->iter);
808                 /* Free resources */
809                 g_object_unref (G_OBJECT (headers));
810                 g_object_unref (G_OBJECT (helper->iter));
811                 g_slice_free (GetMsgAsyncHelper, helper);
812         } else
813                 tny_folder_get_msg_async (folder, 
814                                           TNY_HEADER (tny_iterator_get_current (helper->iter)), 
815                                           get_msg_cb, helper);
816 }
817
818 void 
819 _modest_ui_actions_on_header_selected (ModestHeaderView *folder_view, 
820                                       TnyHeader *header,
821                                       ModestMainWindow *main_window)
822 {
823         TnyFolder *folder;
824         GetMsgAsyncHelper *helper;
825         TnyList *list;
826
827         /* when there's no header, clear the msgview */
828         if (!header) {
829                 ModestMsgView *msg_view;
830                 ModestWidgetFactory *widget_factory;
831                 widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
832                 msg_view       = modest_widget_factory_get_msg_preview (widget_factory);
833                 modest_msg_view_set_message (msg_view, NULL);
834                 return;
835         }
836
837         folder = tny_header_get_folder (TNY_HEADER(header));
838
839         /* Create list */
840         list = tny_simple_list_new ();
841         tny_list_prepend (list, G_OBJECT (header));
842
843         /* Fill helper data */
844         helper = g_slice_new0 (GetMsgAsyncHelper);
845         helper->main_window = main_window;
846         helper->iter = tny_list_create_iterator (list);
847         helper->func = read_msg_func;
848
849         tny_folder_get_msg_async (TNY_FOLDER(folder),
850                                   header, get_msg_cb,
851                                   helper);
852
853         /* Frees */
854         g_object_unref (G_OBJECT (folder));
855 }
856
857 void 
858 _modest_ui_actions_on_folder_selection_changed (ModestFolderView *folder_view,
859                                                TnyFolder *folder, 
860                                                gboolean selected,
861                                                ModestMainWindow *main_window)
862 {
863         GtkLabel *folder_info_label;
864         TnyPlatformFactory *factory;
865         gchar *txt;     
866         ModestConf *conf;
867         ModestHeaderView *header_view;
868         ModestWidgetFactory *widget_factory;
869
870         widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
871         folder_info_label = 
872                 GTK_LABEL (modest_widget_factory_get_folder_info_label (widget_factory));
873
874         if (!folder) {
875                 gtk_label_set_label (GTK_LABEL(folder_info_label), "");
876                 return;
877         }
878
879         factory = modest_tny_platform_factory_get_instance ();
880         header_view = modest_widget_factory_get_header_view (widget_factory);
881         conf = modest_tny_platform_factory_get_conf_instance
882                 (MODEST_TNY_PLATFORM_FACTORY(factory));
883         g_object_unref (G_OBJECT (widget_factory));
884
885         if (!selected) { /* the folder was unselected; save it's settings  */
886                 modest_widget_memory_save (conf, G_OBJECT (header_view),
887                                            "header-view");
888                 gtk_window_set_title (GTK_WINDOW(main_window), "Modest");
889                 modest_header_view_set_folder (header_view, NULL);
890         } else {  /* the folder was selected */
891                 if (folder) { /* folder may be NULL */
892                         guint num, unread;
893                         gchar *title;
894
895                         num    = tny_folder_get_all_count    (folder);
896                         unread = tny_folder_get_unread_count (folder);
897                         
898                         title = g_strdup_printf ("Modest: %s",
899                                                  tny_folder_get_name (folder));
900                         
901                         gtk_window_set_title (GTK_WINDOW(main_window), title);
902                         g_free (title);
903                         
904                         txt = g_strdup_printf (_("%d %s, %d unread"),
905                                        num, num==1 ? _("item") : _("items"), unread);           
906                         gtk_label_set_label (GTK_LABEL(folder_info_label), txt);
907                         g_free (txt);
908                 }
909                 modest_header_view_set_folder (header_view, folder);
910                 modest_widget_memory_restore (conf, G_OBJECT(header_view),
911                                               "header-view");
912         }
913 }
914
915 void
916 _modest_ui_actions_on_password_requested (ModestTnyAccountStore *account_store, 
917                                          const gchar* account_name,
918                                          gchar **password, 
919                                          gboolean *cancel, 
920                                          gboolean *remember, 
921                                          ModestMainWindow *main_window)
922 {
923         gchar *txt;
924         GtkWidget *dialog, *entry, *remember_pass_check;
925
926         dialog = gtk_dialog_new_with_buttons (_("Password requested"),
927                                               GTK_WINDOW (main_window),
928                                               GTK_DIALOG_MODAL,
929                                               GTK_STOCK_CANCEL,
930                                               GTK_RESPONSE_REJECT,
931                                               GTK_STOCK_OK,
932                                               GTK_RESPONSE_ACCEPT,
933                                               NULL);
934
935         txt = g_strdup_printf (_("Please enter your password for %s"), account_name);
936         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), gtk_label_new(txt),
937                             FALSE, FALSE, 0);
938         g_free (txt);
939
940         entry = gtk_entry_new_with_max_length (40);
941         gtk_entry_set_visibility (GTK_ENTRY(entry), FALSE);
942         gtk_entry_set_invisible_char (GTK_ENTRY(entry), 0x2022); /* bullet unichar */
943         
944         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), entry,
945                             TRUE, FALSE, 0);    
946
947         remember_pass_check = gtk_check_button_new_with_label (_("Remember password"));
948         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), remember_pass_check,
949                             TRUE, FALSE, 0);
950
951         gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
952         
953         if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
954                 *password = g_strdup (gtk_entry_get_text (GTK_ENTRY(entry)));
955                 *cancel   = FALSE;
956         } else {
957                 *password = NULL;
958                 *cancel   = TRUE;
959         }
960
961         if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (remember_pass_check)))
962                 *remember = TRUE;
963         else
964                 *remember = FALSE;
965
966         gtk_widget_destroy (dialog);
967
968         while (gtk_events_pending ())
969                 gtk_main_iteration ();
970 }
971
972 /****************************************************/
973 /*
974  * below some stuff to clearup statusbar messages after 1,5 seconds....
975  */
976 typedef struct {
977         GtkWidget *status_bar;
978         GtkWidget *progress_bar;
979         guint     msg_id;
980 } StatusRemoveData;
981
982 static gboolean
983 on_statusbar_remove_msg (StatusRemoveData *data)
984 {
985         /* we need to test types, as this callback maybe called after the
986          * widgets have been destroyed
987          */
988         if (GTK_IS_STATUSBAR(data->status_bar)) 
989                 gtk_statusbar_remove (GTK_STATUSBAR(data->status_bar),
990                                       0, data->msg_id);
991         if (GTK_IS_PROGRESS_BAR(data->progress_bar))
992                 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR(data->progress_bar),
993                                                1.0);
994         g_free (data);
995         return FALSE;
996 }
997
998 static void
999 statusbar_push (ModestWidgetFactory *factory, guint context_id, const gchar *msg)
1000 {
1001         guint id;
1002         StatusRemoveData *data;
1003         GtkWidget *status_bar, *progress_bar;
1004         
1005         if (!msg)
1006                 return;
1007
1008         progress_bar = modest_widget_factory_get_progress_bar (factory);
1009         status_bar   = modest_widget_factory_get_status_bar (factory);
1010         
1011         id = gtk_statusbar_push (GTK_STATUSBAR(status_bar), 0, msg);
1012
1013         data = g_new (StatusRemoveData, 1);
1014         data->status_bar   = status_bar;
1015         data->progress_bar = progress_bar;
1016         data->msg_id     = id;
1017
1018         g_timeout_add (1500, (GSourceFunc)on_statusbar_remove_msg, data);
1019 }
1020 /****************************************************************************/
1021
1022 void
1023 _modest_ui_actions_on_connection_changed (TnyDevice *device, 
1024                                          gboolean online,
1025                                          ModestMainWindow *main_window)
1026 {
1027         GtkWidget *online_toggle;
1028         ModestHeaderView *header_view;
1029         ModestWidgetFactory *widget_factory;
1030         
1031         widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
1032         header_view   = modest_widget_factory_get_header_view (widget_factory);
1033         online_toggle = modest_widget_factory_get_online_toggle (widget_factory);
1034
1035         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(online_toggle),
1036                                       online);
1037         gtk_button_set_label (GTK_BUTTON(online_toggle),
1038                               online ? _("Online") : _("Offline"));
1039
1040         statusbar_push (widget_factory, 0, 
1041                         online ? _("Modest went online") : _("Modest went offline"));
1042         g_object_unref (G_OBJECT (widget_factory));
1043
1044         /* If Modest has became online and the header view has a
1045            header selected then show it */
1046         if (online) {
1047                 GtkTreeSelection *selected;
1048
1049                 selected = gtk_tree_view_get_selection (GTK_TREE_VIEW (header_view));
1050                 _modest_header_view_change_selection (selected, header_view);
1051         }
1052 }
1053
1054 void
1055 _modest_ui_actions_on_online_toggle_toggled (GtkToggleButton *toggle,
1056                                              ModestMainWindow *main_window)
1057 {
1058         gboolean online;
1059         TnyDevice *device;
1060         TnyPlatformFactory *factory;
1061         TnyAccountStore *account_store;
1062
1063         /* Get device. Do not ask the platform factory for it, because
1064            it returns always a new one */
1065         factory = modest_tny_platform_factory_get_instance ();
1066         account_store = tny_platform_factory_new_account_store (factory);
1067         device = tny_account_store_get_device (account_store);
1068
1069         online  = gtk_toggle_button_get_active (toggle);
1070
1071         if (online)
1072                 tny_device_force_online (device);
1073         else
1074                 tny_device_force_offline (device);
1075 }
1076
1077 void 
1078 _modest_ui_actions_on_item_not_found (ModestHeaderView *header_view,
1079                                      ModestItemType type,
1080                                      ModestMainWindow *main_window)
1081 {
1082         GtkWidget *dialog;
1083         gchar *txt, *item;
1084         gboolean online;
1085         TnyDevice *device;
1086         TnyPlatformFactory *factory;
1087         TnyAccountStore *account_store;
1088
1089         item = (type == MODEST_ITEM_TYPE_FOLDER) ? "folder" : "message";
1090
1091         /* Get device. Do not ask the platform factory for it, because
1092            it returns always a new one */
1093         factory = modest_tny_platform_factory_get_instance ();
1094         account_store = tny_platform_factory_new_account_store (factory);
1095         device = tny_account_store_get_device (account_store);
1096         
1097         gdk_threads_enter ();
1098         online = tny_device_is_online (device);
1099
1100         if (online) {
1101                 /* already online -- the item is simply not there... */
1102                 dialog = gtk_message_dialog_new (GTK_WINDOW (main_window),
1103                                                  GTK_DIALOG_MODAL,
1104                                                  GTK_MESSAGE_WARNING,
1105                                                  GTK_BUTTONS_OK,
1106                                                  _("The %s you selected cannot be found"),
1107                                                  item);
1108                 gtk_dialog_run (GTK_DIALOG(dialog));
1109         } else {
1110
1111                 dialog = gtk_dialog_new_with_buttons (_("Connection requested"),
1112                                                       GTK_WINDOW (main_window),
1113                                                       GTK_DIALOG_MODAL,
1114                                                       GTK_STOCK_CANCEL,
1115                                                       GTK_RESPONSE_REJECT,
1116                                                       GTK_STOCK_OK,
1117                                                       GTK_RESPONSE_ACCEPT,
1118                                                       NULL);
1119
1120                 txt = g_strdup_printf (_("This %s is not available in offline mode.\n"
1121                                          "Do you want to get online?"), item);
1122                 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), 
1123                                     gtk_label_new (txt), FALSE, FALSE, 0);
1124                 gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
1125                 g_free (txt);
1126
1127                 gtk_window_set_default_size (GTK_WINDOW(dialog), 300, 300);
1128                 if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
1129                         tny_device_force_online (device);
1130                 }
1131         }
1132         gtk_widget_destroy (dialog);
1133         gdk_threads_leave ();
1134 }
1135
1136
1137
1138 void
1139 _modest_ui_actions_on_header_status_update (ModestHeaderView *header_view, 
1140                                             const gchar *msg,
1141                                             gint num, 
1142                                             gint total, 
1143                                             ModestMainWindow *main_window)
1144 {
1145         GtkWidget *progress_bar;
1146         ModestWidgetFactory *widget_factory;
1147
1148         widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
1149         progress_bar = modest_widget_factory_get_progress_bar (widget_factory);
1150
1151         if (total != 0)
1152                 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR(progress_bar),
1153                                                (gdouble)num/(gdouble)total);
1154         else
1155                 gtk_progress_bar_pulse (GTK_PROGRESS_BAR(progress_bar));
1156
1157         statusbar_push (widget_factory, 0, msg);
1158
1159         /* Free */
1160         g_object_unref (G_OBJECT (widget_factory));
1161 }
1162
1163
1164
1165 void
1166 _modest_ui_actions_on_msg_link_hover (ModestMsgView *msgview, 
1167                                       const gchar* link,
1168                                       ModestMainWindow *main_window)
1169 {
1170         ModestWidgetFactory *widget_factory;
1171
1172         widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
1173         statusbar_push (widget_factory, 0, link);
1174         g_object_unref (G_OBJECT (widget_factory));     
1175
1176         /* TODO: do something */
1177 }       
1178
1179
1180 void
1181 _modest_ui_actions_on_msg_link_clicked (ModestMsgView *msgview, 
1182                                         const gchar* link,
1183                                         ModestMainWindow *main_window)
1184 {
1185         gchar *msg;
1186         ModestWidgetFactory *widget_factory;
1187
1188         msg = g_strdup_printf (_("Opening %s..."), link);
1189         widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
1190         statusbar_push (widget_factory, 0, msg);
1191
1192         g_object_unref (G_OBJECT (widget_factory));     
1193
1194         g_free (msg);
1195
1196         /* TODO: do something */
1197 }
1198
1199 void
1200 _modest_ui_actions_on_msg_attachment_clicked (ModestMsgView *msgview, 
1201                                               int index,
1202                                               ModestMainWindow *main_window)
1203 {
1204         gchar *msg;
1205         ModestWidgetFactory *widget_factory;
1206         
1207         msg = g_strdup_printf (_("Opening attachment %d..."), index);
1208         widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
1209         statusbar_push (widget_factory, 0, msg);
1210         
1211         g_free (msg);
1212         g_object_unref (G_OBJECT (widget_factory));
1213         /* TODO: do something */
1214 }
1215
1216 void
1217 _modest_ui_actions_on_send (GtkWidget *widget, 
1218                             ModestEditMsgWindow *edit_window)
1219 {
1220         TnyTransportAccount *transport_account;
1221         ModestMailOperation *mail_operation;
1222         MsgData *data;
1223
1224         data = modest_edit_msg_window_get_msg_data (edit_window);
1225
1226         /* FIXME: Code added just for testing. The final version will
1227            use the send queue provided by tinymail and some
1228            classifier */
1229         {
1230                 TnyList *accounts;
1231                 TnyIterator *iter;
1232                 TnyAccountStore *account_store;
1233
1234                 accounts = TNY_LIST(tny_simple_list_new ());
1235                 account_store = modest_window_get_account_store (MODEST_WINDOW (edit_window));
1236                 tny_account_store_get_accounts (account_store, accounts,
1237                                                 TNY_ACCOUNT_STORE_TRANSPORT_ACCOUNTS);
1238                 g_object_unref (G_OBJECT (account_store));
1239
1240                 iter = tny_list_create_iterator(accounts);
1241                 tny_iterator_first (iter);
1242                 if (tny_iterator_is_done (iter)) {
1243                         /* FIXME: Add error handling through mail operation */
1244                         g_printerr("modest: no transport accounts defined\n");
1245                         modest_edit_msg_window_free_msg_data (edit_window, data);
1246                         return;
1247                 }
1248                 transport_account = TNY_TRANSPORT_ACCOUNT (tny_iterator_get_current(iter));
1249                 g_object_ref (transport_account);
1250
1251                 tny_list_foreach (accounts, (GFunc) g_object_unref, NULL);
1252                 g_object_unref (G_OBJECT (accounts));
1253                 g_object_unref (G_OBJECT (iter));
1254         }
1255
1256         mail_operation = modest_mail_operation_new ();
1257
1258         modest_mail_operation_send_new_mail (mail_operation,
1259                                              transport_account,
1260                                              data->from, 
1261                                              data->to, 
1262                                              data->cc, 
1263                                              data->bcc,
1264                                              data->subject, 
1265                                              data->body, 
1266                                              NULL);
1267         /* Frees */
1268         g_object_unref (G_OBJECT (mail_operation));
1269         g_object_unref (G_OBJECT (transport_account));
1270         modest_edit_msg_window_free_msg_data (edit_window, data);
1271
1272         /* Save settings and close the window */
1273         /* save_settings (edit_window) */
1274         gtk_widget_destroy (GTK_WIDGET (edit_window));
1275 }
1276
1277 /*
1278  * Shows a dialog with an entry that asks for some text. The returned
1279  * value must be freed by the caller. The dialog window title will be
1280  * set to @title.
1281  */
1282 static gchar *
1283 ask_for_folder_name (GtkWindow *parent_window,
1284                      const gchar *title)
1285 {
1286         GtkWidget *dialog, *entry;
1287         gchar *folder_name = NULL;
1288
1289         /* Ask for folder name */
1290         dialog = gtk_dialog_new_with_buttons (_("New Folder Name"),
1291                                               parent_window,
1292                                               GTK_DIALOG_MODAL,
1293                                               GTK_STOCK_CANCEL,
1294                                               GTK_RESPONSE_REJECT,
1295                                               GTK_STOCK_OK,
1296                                               GTK_RESPONSE_ACCEPT,
1297                                               NULL);
1298         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), 
1299                             gtk_label_new(title),
1300                             FALSE, FALSE, 0);
1301                 
1302         entry = gtk_entry_new_with_max_length (40);
1303         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), 
1304                             entry,
1305                             TRUE, FALSE, 0);    
1306         
1307         gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
1308         
1309         if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)         
1310                 folder_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
1311
1312         gtk_widget_destroy (dialog);
1313
1314         return folder_name;
1315 }
1316         
1317 void 
1318 _modest_ui_actions_on_new_folder (GtkWidget *widget,
1319                                   ModestMainWindow *main_window)
1320 {
1321         TnyFolder *parent_folder;
1322         ModestFolderView *folder_view;
1323         ModestWidgetFactory *widget_factory;
1324
1325         widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
1326         folder_view = modest_widget_factory_get_folder_view (widget_factory);
1327         parent_folder = modest_folder_view_get_selected (folder_view);
1328
1329         if (parent_folder) {
1330                 gchar *folder_name;
1331
1332                 folder_name = ask_for_folder_name (GTK_WINDOW (main_window),
1333                                                    _("Please enter a name for the new folder"));
1334
1335                 if (folder_name != NULL && strlen (folder_name) > 0) {
1336                         TnyFolder *new_folder;
1337                         ModestMailOperation *mail_op;
1338
1339                         mail_op = modest_mail_operation_new ();
1340                         new_folder = modest_mail_operation_create_folder (mail_op,
1341                                                                           TNY_FOLDER_STORE (parent_folder),
1342                                                                           (const gchar *) folder_name);
1343                         if (new_folder) {
1344                                 /* Do anything more? The model
1345                                    is automatically updated */
1346                                 g_object_unref (new_folder);
1347                         }
1348                         g_object_unref (mail_op);
1349                 }
1350                 g_object_unref (parent_folder);
1351         }
1352         g_object_unref (G_OBJECT (widget_factory));
1353 }
1354
1355 void 
1356 _modest_ui_actions_on_rename_folder (GtkWidget *widget,
1357                                      ModestMainWindow *main_window)
1358 {
1359         TnyFolder *folder;
1360         ModestFolderView *folder_view;
1361         ModestWidgetFactory *widget_factory;
1362
1363         widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
1364         folder_view = modest_widget_factory_get_folder_view (widget_factory);
1365         folder = modest_folder_view_get_selected (folder_view);
1366
1367         if (folder) {
1368                 gchar *folder_name;
1369
1370                 folder_name = ask_for_folder_name (GTK_WINDOW (main_window),
1371                                                    _("Please enter a new name for the folder"));
1372
1373                 if (folder_name != NULL && strlen (folder_name) > 0) {
1374                         ModestMailOperation *mail_op;
1375
1376                         mail_op = modest_mail_operation_new ();
1377                         modest_mail_operation_rename_folder (mail_op,
1378                                                              folder,
1379                                                              (const gchar *) folder_name);
1380                         g_object_unref (mail_op);
1381                 }
1382                 g_object_unref (folder);
1383         }
1384         g_object_unref (G_OBJECT (widget_factory));
1385 }
1386
1387 static void
1388 delete_folder (ModestMainWindow *main_window,
1389                gboolean move_to_trash) 
1390 {
1391         TnyFolder *folder;
1392         ModestFolderView *folder_view;
1393         ModestWidgetFactory *widget_factory;
1394         ModestMailOperation *mail_op;
1395                         
1396         widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
1397         folder_view = modest_widget_factory_get_folder_view (widget_factory);
1398         folder = modest_folder_view_get_selected (folder_view);
1399
1400         mail_op = modest_mail_operation_new ();
1401         modest_mail_operation_remove_folder (mail_op, folder, move_to_trash);
1402         g_object_unref (mail_op);
1403 }
1404
1405 void 
1406 _modest_ui_actions_on_delete_folder (GtkWidget *widget,
1407                                      ModestMainWindow *main_window)
1408 {
1409         delete_folder (main_window, FALSE);
1410 }
1411
1412 void 
1413 _modest_ui_actions_on_move_to_trash_folder (GtkWidget *widget,
1414                                             ModestMainWindow *main_window)
1415 {
1416         delete_folder (main_window, TRUE);
1417 }