* 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         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_all (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_all (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                 if (folder) { /* folder may be NULL */
891                         guint num, unread;
892                         gchar *title;
893
894                         num    = tny_folder_get_all_count    (folder);
895                         unread = tny_folder_get_unread_count (folder);
896                         
897                         title = g_strdup_printf ("Modest: %s",
898                                                  tny_folder_get_name (folder));
899                         
900                         gtk_window_set_title (GTK_WINDOW(main_window), title);
901                         g_free (title);
902                         
903                         txt = g_strdup_printf (_("%d %s, %d unread"),
904                                        num, num==1 ? _("item") : _("items"), unread);           
905                         gtk_label_set_label (GTK_LABEL(folder_info_label), txt);
906                         g_free (txt);
907                 }
908                 modest_header_view_set_folder (header_view, folder);
909                 modest_widget_memory_restore (conf, G_OBJECT(header_view),
910                                               "header-view");
911         }
912 }
913
914 void
915 _modest_ui_actions_on_password_requested (ModestTnyAccountStore *account_store, 
916                                          const gchar* account_name,
917                                          gchar **password, 
918                                          gboolean *cancel, 
919                                          gboolean *remember, 
920                                          ModestMainWindow *main_window)
921 {
922         gchar *txt;
923         GtkWidget *dialog, *entry, *remember_pass_check;
924
925         dialog = gtk_dialog_new_with_buttons (_("Password requested"),
926                                               GTK_WINDOW (main_window),
927                                               GTK_DIALOG_MODAL,
928                                               GTK_STOCK_CANCEL,
929                                               GTK_RESPONSE_REJECT,
930                                               GTK_STOCK_OK,
931                                               GTK_RESPONSE_ACCEPT,
932                                               NULL);
933
934         txt = g_strdup_printf (_("Please enter your password for %s"), account_name);
935         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), gtk_label_new(txt),
936                             FALSE, FALSE, 0);
937         g_free (txt);
938
939         entry = gtk_entry_new_with_max_length (40);
940         gtk_entry_set_visibility (GTK_ENTRY(entry), FALSE);
941         gtk_entry_set_invisible_char (GTK_ENTRY(entry), 0x2022); /* bullet unichar */
942         
943         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), entry,
944                             TRUE, FALSE, 0);    
945
946         remember_pass_check = gtk_check_button_new_with_label (_("Remember password"));
947         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), remember_pass_check,
948                             TRUE, FALSE, 0);
949
950         gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
951         
952         if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
953                 *password = g_strdup (gtk_entry_get_text (GTK_ENTRY(entry)));
954                 *cancel   = FALSE;
955         } else {
956                 *password = NULL;
957                 *cancel   = TRUE;
958         }
959
960         if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (remember_pass_check)))
961                 *remember = TRUE;
962         else
963                 *remember = FALSE;
964
965         gtk_widget_destroy (dialog);
966
967         while (gtk_events_pending ())
968                 gtk_main_iteration ();
969 }
970
971
972 static gboolean
973 progress_bar_clean (GtkWidget *bar)
974 {
975         if (GTK_IS_PROGRESS_BAR(bar)) {
976                 gtk_progress_bar_set_text     (GTK_PROGRESS_BAR(bar), "");
977                 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR(bar), 1.0);
978         }
979         return FALSE;
980 }
981 static gboolean
982 statusbar_clean (GtkWidget *bar)
983 {
984         if (GTK_IS_STATUSBAR(bar))
985                 gtk_statusbar_push (GTK_STATUSBAR(bar), 0, "");
986         return FALSE;
987 }
988
989
990 static void
991 statusbar_push (ModestWidgetFactory *factory, guint context_id, const gchar *msg)
992 {
993         GtkWidget *status_bar, *progress_bar;
994         
995         if (!msg)
996                 return;
997
998         progress_bar = modest_widget_factory_get_progress_bar (factory);
999         status_bar   = modest_widget_factory_get_status_bar (factory);
1000
1001         gtk_widget_show (GTK_WIDGET(status_bar));
1002         gtk_widget_show (GTK_WIDGET(progress_bar));
1003
1004         gtk_statusbar_push (GTK_STATUSBAR(status_bar), 0, msg);
1005
1006         g_timeout_add (2000, (GSourceFunc)statusbar_clean, status_bar);
1007         g_timeout_add (1000, (GSourceFunc)progress_bar_clean, progress_bar);
1008 }
1009 /****************************************************************************/
1010
1011 void
1012 _modest_ui_actions_on_connection_changed (TnyDevice *device, 
1013                                          gboolean online,
1014                                          ModestMainWindow *main_window)
1015 {
1016         GtkWidget *online_toggle;
1017         ModestHeaderView *header_view;
1018         ModestWidgetFactory *widget_factory;
1019         
1020         widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
1021         header_view   = modest_widget_factory_get_header_view (widget_factory);
1022         online_toggle = modest_widget_factory_get_online_toggle (widget_factory);
1023
1024         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(online_toggle),
1025                                       online);
1026         gtk_button_set_label (GTK_BUTTON(online_toggle),
1027                               online ? _("Online") : _("Offline"));
1028
1029         statusbar_push (widget_factory, 0, 
1030                         online ? _("Modest went online") : _("Modest went offline"));
1031         g_object_unref (G_OBJECT (widget_factory));
1032
1033         /* If Modest has became online and the header view has a
1034            header selected then show it */
1035         if (online) {
1036                 GtkTreeSelection *selected;
1037
1038                 selected = gtk_tree_view_get_selection (GTK_TREE_VIEW (header_view));
1039                 _modest_header_view_change_selection (selected, header_view);
1040         }
1041 }
1042
1043 void
1044 _modest_ui_actions_on_online_toggle_toggled (GtkToggleButton *toggle,
1045                                              ModestMainWindow *main_window)
1046 {
1047         gboolean online;
1048         TnyDevice *device;
1049         TnyPlatformFactory *factory;
1050         TnyAccountStore *account_store;
1051
1052         /* Get device. Do not ask the platform factory for it, because
1053            it returns always a new one */
1054         factory = modest_tny_platform_factory_get_instance ();
1055         account_store = tny_platform_factory_new_account_store (factory);
1056         device = tny_account_store_get_device (account_store);
1057
1058         online  = gtk_toggle_button_get_active (toggle);
1059
1060         if (online)
1061                 tny_device_force_online (device);
1062         else
1063                 tny_device_force_offline (device);
1064 }
1065
1066 void 
1067 _modest_ui_actions_on_item_not_found (ModestHeaderView *header_view,
1068                                      ModestItemType type,
1069                                      ModestMainWindow *main_window)
1070 {
1071         GtkWidget *dialog;
1072         gchar *txt, *item;
1073         gboolean online;
1074         TnyDevice *device;
1075         TnyPlatformFactory *factory;
1076         TnyAccountStore *account_store;
1077
1078         item = (type == MODEST_ITEM_TYPE_FOLDER) ? "folder" : "message";
1079
1080         /* Get device. Do not ask the platform factory for it, because
1081            it returns always a new one */
1082         factory = modest_tny_platform_factory_get_instance ();
1083         account_store = tny_platform_factory_new_account_store (factory);
1084         device = tny_account_store_get_device (account_store);
1085         
1086         gdk_threads_enter ();
1087         online = tny_device_is_online (device);
1088
1089         if (online) {
1090                 /* already online -- the item is simply not there... */
1091                 dialog = gtk_message_dialog_new (GTK_WINDOW (main_window),
1092                                                  GTK_DIALOG_MODAL,
1093                                                  GTK_MESSAGE_WARNING,
1094                                                  GTK_BUTTONS_OK,
1095                                                  _("The %s you selected cannot be found"),
1096                                                  item);
1097                 gtk_dialog_run (GTK_DIALOG(dialog));
1098         } else {
1099
1100                 dialog = gtk_dialog_new_with_buttons (_("Connection requested"),
1101                                                       GTK_WINDOW (main_window),
1102                                                       GTK_DIALOG_MODAL,
1103                                                       GTK_STOCK_CANCEL,
1104                                                       GTK_RESPONSE_REJECT,
1105                                                       GTK_STOCK_OK,
1106                                                       GTK_RESPONSE_ACCEPT,
1107                                                       NULL);
1108
1109                 txt = g_strdup_printf (_("This %s is not available in offline mode.\n"
1110                                          "Do you want to get online?"), item);
1111                 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), 
1112                                     gtk_label_new (txt), FALSE, FALSE, 0);
1113                 gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
1114                 g_free (txt);
1115
1116                 gtk_window_set_default_size (GTK_WINDOW(dialog), 300, 300);
1117                 if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
1118                         tny_device_force_online (device);
1119                 }
1120         }
1121         gtk_widget_destroy (dialog);
1122         gdk_threads_leave ();
1123 }
1124
1125
1126
1127 void
1128 _modest_ui_actions_on_header_status_update (ModestHeaderView *header_view, 
1129                                             const gchar *msg,
1130                                             gint num, 
1131                                             gint total, 
1132                                             ModestMainWindow *main_window)
1133 {
1134         GtkWidget *progress_bar;
1135         ModestWidgetFactory *widget_factory;
1136         char* txt;
1137         
1138         widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
1139         progress_bar = modest_widget_factory_get_progress_bar (widget_factory);
1140
1141         if (total != 0)
1142                 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR(progress_bar),
1143                                                (gdouble)num/(gdouble)total);
1144         else
1145                 gtk_progress_bar_pulse (GTK_PROGRESS_BAR(progress_bar));
1146
1147         txt = g_strdup_printf (_("Downloading %d of %d"), num, total);
1148         gtk_progress_bar_set_text (GTK_PROGRESS_BAR(progress_bar), txt);
1149         g_free (txt);
1150         
1151         statusbar_push (widget_factory, 0, msg);
1152         
1153         /* Free */
1154         g_object_unref (G_OBJECT (widget_factory));
1155 }
1156
1157
1158
1159 void
1160 _modest_ui_actions_on_msg_link_hover (ModestMsgView *msgview, 
1161                                       const gchar* link,
1162                                       ModestMainWindow *main_window)
1163 {
1164         ModestWidgetFactory *widget_factory;
1165
1166         widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
1167         statusbar_push (widget_factory, 0, link);
1168         g_object_unref (G_OBJECT (widget_factory));     
1169
1170         /* TODO: do something */
1171 }       
1172
1173
1174 void
1175 _modest_ui_actions_on_msg_link_clicked (ModestMsgView *msgview, 
1176                                         const gchar* link,
1177                                         ModestMainWindow *main_window)
1178 {
1179         gchar *msg;
1180         ModestWidgetFactory *widget_factory;
1181
1182         msg = g_strdup_printf (_("Opening %s..."), link);
1183         widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
1184         statusbar_push (widget_factory, 0, msg);
1185
1186         g_object_unref (G_OBJECT (widget_factory));     
1187
1188         g_free (msg);
1189
1190         /* TODO: do something */
1191 }
1192
1193 void
1194 _modest_ui_actions_on_msg_attachment_clicked (ModestMsgView *msgview, 
1195                                               int index,
1196                                               ModestMainWindow *main_window)
1197 {
1198         gchar *msg;
1199         ModestWidgetFactory *widget_factory;
1200         
1201         msg = g_strdup_printf (_("Opening attachment %d..."), index);
1202         widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
1203         statusbar_push (widget_factory, 0, msg);
1204         
1205         g_free (msg);
1206         g_object_unref (G_OBJECT (widget_factory));
1207         /* TODO: do something */
1208 }
1209
1210 void
1211 _modest_ui_actions_on_send (GtkWidget *widget, 
1212                             ModestEditMsgWindow *edit_window)
1213 {
1214         TnyTransportAccount *transport_account;
1215         ModestMailOperation *mail_operation;
1216         MsgData *data;
1217
1218         data = modest_edit_msg_window_get_msg_data (edit_window);
1219
1220         /* FIXME: Code added just for testing. The final version will
1221            use the send queue provided by tinymail and some
1222            classifier */
1223         {
1224                 TnyList *accounts;
1225                 TnyIterator *iter;
1226                 TnyAccountStore *account_store;
1227
1228                 accounts = TNY_LIST(tny_simple_list_new ());
1229                 account_store = modest_window_get_account_store (MODEST_WINDOW (edit_window));
1230                 tny_account_store_get_accounts (account_store, accounts,
1231                                                 TNY_ACCOUNT_STORE_TRANSPORT_ACCOUNTS);
1232                 g_object_unref (G_OBJECT (account_store));
1233
1234                 iter = tny_list_create_iterator(accounts);
1235                 tny_iterator_first (iter);
1236                 if (tny_iterator_is_done (iter)) {
1237                         /* FIXME: Add error handling through mail operation */
1238                         g_printerr("modest: no transport accounts defined\n");
1239                         modest_edit_msg_window_free_msg_data (edit_window, data);
1240                         return;
1241                 }
1242                 transport_account = TNY_TRANSPORT_ACCOUNT (tny_iterator_get_current(iter));
1243                 g_object_ref (transport_account);
1244
1245                 tny_list_foreach (accounts, (GFunc) g_object_unref, NULL);
1246                 g_object_unref (G_OBJECT (accounts));
1247                 g_object_unref (G_OBJECT (iter));
1248         }
1249
1250         mail_operation = modest_mail_operation_new ();
1251
1252         modest_mail_operation_send_new_mail (mail_operation,
1253                                              transport_account,
1254                                              data->from, 
1255                                              data->to, 
1256                                              data->cc, 
1257                                              data->bcc,
1258                                              data->subject, 
1259                                              data->body, 
1260                                              NULL);
1261         /* Frees */
1262         g_object_unref (G_OBJECT (mail_operation));
1263         g_object_unref (G_OBJECT (transport_account));
1264         modest_edit_msg_window_free_msg_data (edit_window, data);
1265
1266         /* Save settings and close the window */
1267         /* save_settings (edit_window) */
1268         gtk_widget_destroy (GTK_WIDGET (edit_window));
1269 }
1270
1271 /*
1272  * Shows a dialog with an entry that asks for some text. The returned
1273  * value must be freed by the caller. The dialog window title will be
1274  * set to @title.
1275  */
1276 static gchar *
1277 ask_for_folder_name (GtkWindow *parent_window,
1278                      const gchar *title)
1279 {
1280         GtkWidget *dialog, *entry;
1281         gchar *folder_name = NULL;
1282
1283         /* Ask for folder name */
1284         dialog = gtk_dialog_new_with_buttons (_("New Folder Name"),
1285                                               parent_window,
1286                                               GTK_DIALOG_MODAL,
1287                                               GTK_STOCK_CANCEL,
1288                                               GTK_RESPONSE_REJECT,
1289                                               GTK_STOCK_OK,
1290                                               GTK_RESPONSE_ACCEPT,
1291                                               NULL);
1292         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), 
1293                             gtk_label_new(title),
1294                             FALSE, FALSE, 0);
1295                 
1296         entry = gtk_entry_new_with_max_length (40);
1297         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), 
1298                             entry,
1299                             TRUE, FALSE, 0);    
1300         
1301         gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
1302         
1303         if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)         
1304                 folder_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
1305
1306         gtk_widget_destroy (dialog);
1307
1308         return folder_name;
1309 }
1310         
1311 void 
1312 _modest_ui_actions_on_new_folder (GtkWidget *widget,
1313                                   ModestMainWindow *main_window)
1314 {
1315         TnyFolder *parent_folder;
1316         ModestFolderView *folder_view;
1317         ModestWidgetFactory *widget_factory;
1318
1319         widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
1320         folder_view = modest_widget_factory_get_folder_view (widget_factory);
1321         parent_folder = modest_folder_view_get_selected (folder_view);
1322
1323         if (parent_folder) {
1324                 gchar *folder_name;
1325
1326                 folder_name = ask_for_folder_name (GTK_WINDOW (main_window),
1327                                                    _("Please enter a name for the new folder"));
1328
1329                 if (folder_name != NULL && strlen (folder_name) > 0) {
1330                         TnyFolder *new_folder;
1331                         ModestMailOperation *mail_op;
1332
1333                         mail_op = modest_mail_operation_new ();
1334                         new_folder = modest_mail_operation_create_folder (mail_op,
1335                                                                           TNY_FOLDER_STORE (parent_folder),
1336                                                                           (const gchar *) folder_name);
1337                         if (new_folder) {
1338                                 /* Do anything more? The model
1339                                    is automatically updated */
1340                                 g_object_unref (new_folder);
1341                         }
1342                         g_object_unref (mail_op);
1343                 }
1344                 g_object_unref (parent_folder);
1345         }
1346         g_object_unref (G_OBJECT (widget_factory));
1347 }
1348
1349 void 
1350 _modest_ui_actions_on_rename_folder (GtkWidget *widget,
1351                                      ModestMainWindow *main_window)
1352 {
1353         TnyFolder *folder;
1354         ModestFolderView *folder_view;
1355         ModestWidgetFactory *widget_factory;
1356
1357         widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
1358         folder_view = modest_widget_factory_get_folder_view (widget_factory);
1359         folder = modest_folder_view_get_selected (folder_view);
1360
1361         if (folder) {
1362                 gchar *folder_name;
1363
1364                 folder_name = ask_for_folder_name (GTK_WINDOW (main_window),
1365                                                    _("Please enter a new name for the folder"));
1366
1367                 if (folder_name != NULL && strlen (folder_name) > 0) {
1368                         ModestMailOperation *mail_op;
1369
1370                         mail_op = modest_mail_operation_new ();
1371                         modest_mail_operation_rename_folder (mail_op,
1372                                                              folder,
1373                                                              (const gchar *) folder_name);
1374                         g_object_unref (mail_op);
1375                 }
1376                 g_object_unref (folder);
1377         }
1378         g_object_unref (G_OBJECT (widget_factory));
1379 }
1380
1381 static void
1382 delete_folder (ModestMainWindow *main_window,
1383                gboolean move_to_trash) 
1384 {
1385         TnyFolder *folder;
1386         ModestFolderView *folder_view;
1387         ModestWidgetFactory *widget_factory;
1388         ModestMailOperation *mail_op;
1389                         
1390         widget_factory = modest_window_get_widget_factory (MODEST_WINDOW (main_window));
1391         folder_view = modest_widget_factory_get_folder_view (widget_factory);
1392         folder = modest_folder_view_get_selected (folder_view);
1393
1394         mail_op = modest_mail_operation_new ();
1395         modest_mail_operation_remove_folder (mail_op, folder, move_to_trash);
1396         g_object_unref (mail_op);
1397 }
1398
1399 void 
1400 _modest_ui_actions_on_delete_folder (GtkWidget *widget,
1401                                      ModestMainWindow *main_window)
1402 {
1403         delete_folder (main_window, FALSE);
1404 }
1405
1406 void 
1407 _modest_ui_actions_on_move_to_trash_folder (GtkWidget *widget,
1408                                             ModestMainWindow *main_window)
1409 {
1410         delete_folder (main_window, TRUE);
1411 }