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