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