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