* modest-ui-actions:
[modest] / src / modest-ui-actions.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-runtime.h>
37 #include "modest-ui-actions.h"
38 #include "modest-tny-platform-factory.h"
39
40 #include <widgets/modest-main-window.h>
41 #include "modest-account-view-window.h"
42 #include <widgets/modest-msg-view-window.h>
43
44 #include "modest-account-mgr-helpers.h"
45 #include "modest-mail-operation.h"
46 #include <modest-widget-memory.h>
47 #include <tny-error.h>
48 #include <tny-simple-list.h>
49 #include <tny-msg-view.h>
50 #include <tny-device.h>
51
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
73 static void     reply_forward_func     (gpointer data, gpointer user_data);
74 static void     read_msg_func          (gpointer data, gpointer user_data);
75 static void     get_msg_cb             (TnyFolder *folder, TnyMsg *msg, GError **err, 
76                                         gpointer user_data);
77
78 static void     reply_forward          (GtkWidget *widget, ReplyForwardAction action,
79                                         ModestMainWindow *main_window);
80
81 static gchar*   ask_for_folder_name    (GtkWindow *parent_window, const gchar *title);
82
83
84 void   
85 modest_ui_actions_on_about (GtkWidget *widget, ModestWindow *win)
86 {
87         GtkWidget *about;
88         const gchar *authors[] = {
89                 "Dirk-Jan C. Binnema <dirk-jan.binnema@nokia.com>",
90                 NULL
91         };
92         about = gtk_about_dialog_new ();
93         gtk_about_dialog_set_name (GTK_ABOUT_DIALOG(about), PACKAGE_NAME);
94         gtk_about_dialog_set_version (GTK_ABOUT_DIALOG(about),PACKAGE_VERSION);
95         gtk_about_dialog_set_copyright (GTK_ABOUT_DIALOG(about),
96                                         _("Copyright (c) 2006, Nokia Corporation\n"
97                                           "All rights reserved."));
98         gtk_about_dialog_set_comments (GTK_ABOUT_DIALOG(about),
99                                        _("a modest e-mail client\n\n"
100                                          "design and implementation: Dirk-Jan C. Binnema\n"
101                                          "contributions from the fine people at KernelConcepts and Igalia\n"
102                                          "uses the tinymail email framework written by Philip van Hoof"));
103         gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG(about), authors);
104         gtk_about_dialog_set_website (GTK_ABOUT_DIALOG(about), "http://modest.garage.maemo.org");
105         
106         gtk_dialog_run (GTK_DIALOG (about));
107         gtk_widget_destroy(about);
108 }
109
110 void
111 modest_ui_actions_on_delete (GtkWidget *widget, ModestMainWindow *main_window)
112 {
113         TnyList *header_list;
114         TnyIterator *iter;
115         GtkTreeModel *model;
116
117         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
118         
119         if (!main_window->header_view)
120                 return;
121         
122         header_list = modest_header_view_get_selected_headers (main_window->header_view);
123         
124         if (header_list) {
125                 iter = tny_list_create_iterator (header_list);
126                 model = gtk_tree_view_get_model (GTK_TREE_VIEW (main_window->header_view));
127                 if (GTK_IS_TREE_MODEL_SORT (model))
128                         model = gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (model));
129                 do {
130                         TnyHeader *header;
131                         ModestMailOperation *mail_op;
132
133                         header = TNY_HEADER (tny_iterator_get_current (iter));
134                         /* TODO: thick grain mail operation involving
135                            a list of objects. Composite pattern ??? */
136                         mail_op = modest_mail_operation_new ();
137
138                         /* TODO: add confirmation dialog */
139
140                         /* Move to trash */
141                         modest_mail_operation_remove_msg (mail_op, header, TRUE);
142
143                         /* Remove from tree model */
144                         if (modest_mail_operation_get_status (mail_op) == 
145                             MODEST_MAIL_OPERATION_STATUS_SUCCESS)
146                                 tny_list_remove (TNY_LIST (model), G_OBJECT (header));
147                         else {
148                                 /* TODO: error handling management */
149                                 const GError *error;
150                                 error = modest_mail_operation_get_error (mail_op);
151                                 g_warning (error->message);
152                         }
153
154                         g_object_unref (G_OBJECT (mail_op));
155                         g_object_unref (header);
156                         tny_iterator_next (iter);
157
158                 } while (!tny_iterator_is_done (iter));
159         }
160 }
161
162
163 void
164 modest_ui_actions_on_quit (GtkWidget *widget, ModestWindow *win)
165 {
166         /* FIXME: save size of main window */
167 /*      save_sizes (main_window); */
168         gtk_widget_destroy (GTK_WIDGET (win));
169 }
170
171 void
172 modest_ui_actions_on_accounts (GtkWidget *widget, ModestWindow *win)
173 {
174         GtkWidget *account_win;
175         account_win = modest_account_view_window_new ();
176
177         if (win)
178                 gtk_window_set_transient_for (GTK_WINDOW (account_win), GTK_WINDOW (win));
179
180         gtk_widget_show (account_win);
181 }
182
183 void
184 modest_ui_actions_on_new_msg (GtkWidget *widget, ModestWindow *win)
185 {
186         ModestWindow *msg_win;
187         msg_win = modest_msg_edit_window_new (MODEST_EDIT_TYPE_NEW);
188         if (win)
189                 gtk_window_set_transient_for (GTK_WINDOW (msg_win),
190                                               GTK_WINDOW (win));
191         
192         gtk_widget_show_all (GTK_WIDGET (msg_win));
193 }
194
195
196 void
197 modest_ui_actions_on_open (GtkWidget *widget, ModestWindow *win)
198 {
199         /* FIXME */
200         
201 }
202
203
204 static void
205 reply_forward_func (gpointer data, gpointer user_data)
206 {
207         TnyMsg *msg, *new_msg;
208         GetMsgAsyncHelper *helper;
209         ReplyForwardHelper *rf_helper;
210         ModestWindow *msg_win;
211         ModestEditType edit_type;
212
213         msg = TNY_MSG (data);
214         helper = (GetMsgAsyncHelper *) user_data;
215         rf_helper = (ReplyForwardHelper *) helper->user_data;
216
217         /* Create reply mail */
218         switch (rf_helper->action) {
219         case ACTION_REPLY:
220                 new_msg = 
221                         modest_mail_operation_create_reply_mail (msg, 
222                                                                  rf_helper->from, 
223                                                                  rf_helper->reply_forward_type,
224                                                                  MODEST_MAIL_OPERATION_REPLY_MODE_SENDER);
225                 break;
226         case ACTION_REPLY_TO_ALL:
227                 new_msg = 
228                         modest_mail_operation_create_reply_mail (msg, rf_helper->from, rf_helper->reply_forward_type,
229                                                                  MODEST_MAIL_OPERATION_REPLY_MODE_ALL);
230                 edit_type = MODEST_EDIT_TYPE_REPLY;
231                 break;
232         case ACTION_FORWARD:
233                 new_msg = 
234                         modest_mail_operation_create_forward_mail (msg, rf_helper->from, rf_helper->reply_forward_type);
235                 edit_type = MODEST_EDIT_TYPE_FORWARD;
236                 break;
237         default:
238                 g_return_if_reached ();
239         }
240
241         if (!new_msg) {
242                 g_warning ("Unable to create a message");
243                 goto cleanup;
244         }
245                 
246         /* Show edit window */
247         msg_win = modest_msg_edit_window_new (MODEST_EDIT_TYPE_NEW);
248         modest_msg_edit_window_set_msg (MODEST_MSG_EDIT_WINDOW (msg_win),
249                                         new_msg);
250         gtk_widget_show_all (GTK_WIDGET (msg_win));
251         
252         /* Clean */
253         g_object_unref (G_OBJECT (new_msg));
254
255  cleanup:
256         g_free (rf_helper->from);
257         g_slice_free (ReplyForwardHelper, rf_helper);
258 }
259
260 /*
261  * Common code for the reply and forward actions
262  */
263 static void
264 reply_forward (GtkWidget *widget, ReplyForwardAction action,
265                ModestMainWindow *main_window)
266 {
267         ModestAccountMgr *account_mgr;
268         TnyList *header_list;
269         guint reply_forward_type;
270         ModestConf *conf;       
271         ModestAccountData *default_account_data;
272         TnyHeader *header;
273         TnyFolder *folder;
274         gchar *from, *key, *default_account_name;
275         GetMsgAsyncHelper *helper;
276         ReplyForwardHelper *rf_helper;
277
278         if (!main_window->header_view)
279                 return;
280
281         header_list = modest_header_view_get_selected_headers (main_window->header_view);       
282         if (!header_list)
283                 return;
284
285         conf = modest_runtime_get_conf ();
286         
287         /* Get reply or forward type */
288         key = g_strdup_printf ("%s/%s", MODEST_CONF_NAMESPACE, 
289                                (action == ACTION_FORWARD) ? MODEST_CONF_FORWARD_TYPE : MODEST_CONF_REPLY_TYPE);
290         reply_forward_type = modest_conf_get_int (conf, key, NULL);
291         g_free (key);
292
293         /* We assume that we can only select messages of the
294            same folder and that we reply all of them from the
295            same account. In fact the interface currently only
296            allows single selection */
297         account_mgr = modest_runtime_get_account_mgr();
298         default_account_name = modest_account_mgr_get_default_account (account_mgr);
299         default_account_data = 
300                 modest_account_mgr_get_account_data (account_mgr,
301                                                      (const gchar*) default_account_name);
302         from = g_strdup (default_account_data->email);
303         modest_account_mgr_free_account_data (account_mgr, default_account_data);
304         g_free (default_account_name);
305         
306         /* Fill helpers */
307         rf_helper = g_slice_new0 (ReplyForwardHelper);
308         rf_helper->reply_forward_type = reply_forward_type;
309         rf_helper->action = action;
310         rf_helper->from = from;
311         
312         helper = g_slice_new0 (GetMsgAsyncHelper);
313         helper->main_window = main_window;
314         helper->func = reply_forward_func;
315         helper->iter = tny_list_create_iterator (header_list);
316         helper->user_data = rf_helper;
317         
318         header = TNY_HEADER (tny_iterator_get_current (helper->iter));
319         folder = tny_header_get_folder (header);
320         
321         /* The callback will call it per each header */
322         tny_folder_get_msg_async (folder, header, get_msg_cb, helper);
323         
324         /* Clean */
325         g_object_unref (G_OBJECT (header));
326         g_object_unref (G_OBJECT (folder));
327 }
328
329 void
330 modest_ui_actions_on_reply (GtkWidget *widget, ModestMainWindow *main_window)
331 {
332         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
333
334         reply_forward (widget, ACTION_REPLY, main_window);
335 }
336
337 void
338 modest_ui_actions_on_forward (GtkWidget *widget, ModestMainWindow *main_window)
339 {
340         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
341
342         reply_forward (widget, ACTION_FORWARD, main_window);
343 }
344
345 void
346 modest_ui_actions_on_reply_all (GtkWidget *widget,ModestMainWindow *main_window)
347 {
348         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
349
350         reply_forward (widget, ACTION_REPLY_TO_ALL, main_window);
351 }
352
353 void 
354 modest_ui_actions_on_next (GtkWidget *widget, 
355                            ModestMainWindow *main_window)
356 {
357         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
358
359         if (main_window->header_view)
360                 modest_header_view_select_next (main_window->header_view); 
361 }
362
363 void
364 modest_ui_actions_toggle_view (GtkWidget *widget, ModestMainWindow *main_window)
365 {
366         ModestConf *conf;
367         
368         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
369         
370         if (!main_window->header_view)
371                 return;
372         conf = modest_runtime_get_conf ();
373         
374         /* what is saved/restored is depending on the style; thus; we save with
375          * old style, then update the style, and restore for this new style*/
376         modest_widget_memory_save (conf, G_OBJECT(main_window->header_view), "header-view");
377         
378         if (modest_header_view_get_style (main_window->header_view) == MODEST_HEADER_VIEW_STYLE_DETAILS)
379                 modest_header_view_set_style (main_window->header_view,
380                                               MODEST_HEADER_VIEW_STYLE_TWOLINES);
381         else
382                 modest_header_view_set_style (main_window->header_view,
383                                               MODEST_HEADER_VIEW_STYLE_DETAILS);
384
385         modest_widget_memory_restore (conf, G_OBJECT(main_window->header_view),
386                                       "header-view");
387 }
388
389
390
391 /*
392  * Marks a message as read and passes it to the msg preview widget
393  */
394 static void
395 read_msg_func (gpointer data, gpointer user_data)
396 {
397         TnyMsg *msg;
398         TnyHeader *header;
399         GetMsgAsyncHelper *helper;
400         TnyHeaderFlags header_flags;
401
402         msg = TNY_MSG (data);
403         helper = (GetMsgAsyncHelper *) user_data;
404
405         if (!helper->main_window->msg_preview)
406                 return;
407         
408         /* mark message as seen; _set_flags crashes, bug in tinymail? */
409         header = TNY_HEADER (tny_iterator_get_current (helper->iter));
410         header_flags = tny_header_get_flags (header);
411         tny_header_set_flags (header, header_flags | TNY_HEADER_FLAG_SEEN);
412         g_object_unref (G_OBJECT (header));
413
414         /* Set message on msg view */
415         modest_msg_view_set_message (helper->main_window->msg_preview,
416                                      msg);
417 }
418
419 /*
420  * This function is a generic handler for the tny_folder_get_msg_async
421  * call. It expects as user_data a #GetMsgAsyncHelper. This helper
422  * contains a user provided function that is called inside this
423  * method. This will allow us to use this callback in many different
424  * places. This callback performs the common actions for the
425  * get_msg_async call, more specific actions will be done by the user
426  * function
427  */
428 static void
429 get_msg_cb (TnyFolder *folder, TnyMsg *msg, GError **err, gpointer user_data)
430 {
431         GetMsgAsyncHelper *helper;
432
433         helper = (GetMsgAsyncHelper *) user_data;
434
435         if ((*err && ((*err)->code == TNY_FOLDER_ERROR_GET_MSG)) || !msg) {
436                 ModestHeaderView *header_view =
437                         helper->main_window->header_view;
438                 if (header_view)
439                         modest_ui_actions_on_item_not_found (header_view,
440                                                              MODEST_ITEM_TYPE_MESSAGE,
441                                                              MODEST_WINDOW(helper->main_window));
442                 return;
443         }
444
445         /* Call user function */
446         helper->func (msg, user_data);
447
448         /* Process next element (if exists) */
449         tny_iterator_next (helper->iter);
450         if (tny_iterator_is_done (helper->iter)) {
451                 TnyList *headers;
452                 headers = tny_iterator_get_list (helper->iter);
453                 /* Free resources */
454                 g_object_unref (G_OBJECT (headers));
455                 g_object_unref (G_OBJECT (helper->iter));
456                 g_slice_free (GetMsgAsyncHelper, helper);
457         } else {
458                 TnyHeader *header;
459                 header = TNY_HEADER (tny_iterator_get_current (helper->iter)); 
460                 tny_folder_get_msg_async (folder, header,                         
461                                           get_msg_cb, helper);
462                 g_object_unref (G_OBJECT(header));
463         }
464 }
465
466 void 
467 modest_ui_actions_on_header_selected (ModestHeaderView *folder_view,     TnyHeader *header,
468                                       ModestMainWindow *main_window)
469 {
470         TnyFolder *folder;
471         GetMsgAsyncHelper *helper;
472         TnyList *list;
473
474         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
475
476         if (!main_window->msg_preview)
477                 return;
478         
479         /* when there's no header, clear the msgview */
480         if (!header) {
481                 modest_msg_view_set_message (main_window->msg_preview, NULL);
482                 return;
483         }
484
485         folder = tny_header_get_folder (TNY_HEADER(header));
486
487         /* Create list */
488         list = tny_simple_list_new ();
489         tny_list_prepend (list, G_OBJECT (header));
490
491         /* Fill helper data */
492         helper = g_slice_new0 (GetMsgAsyncHelper);
493         helper->main_window = main_window;
494         helper->iter = tny_list_create_iterator (list);
495         helper->func = read_msg_func;
496
497         tny_folder_get_msg_async (TNY_FOLDER(folder),
498                                   header, get_msg_cb,
499                                   helper);
500
501         /* Frees */
502         g_object_unref (G_OBJECT (folder));
503 }
504
505
506
507 void 
508 modest_ui_actions_on_header_activated (ModestHeaderView *folder_view, TnyHeader *header,
509                                         ModestMainWindow *main_window)
510 {
511         ModestWindow *win;
512         TnyFolder *folder = NULL;
513         TnyMsg    *msg    = NULL;
514
515         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
516         
517         if (!header)
518                 return;
519
520         folder = tny_header_get_folder (header);
521         if (!folder) {
522                 g_printerr ("modest: cannot get folder for header\n");
523                 goto cleanup;
524         }
525
526         /* FIXME: make async?; check error  */
527         msg = tny_folder_get_msg (folder, header, NULL);
528         if (!msg) {
529                 g_printerr ("modest: cannot get msg for header\n");
530                 goto cleanup;
531         }
532
533         win = modest_msg_view_window_new (msg);
534         gtk_window_set_transient_for (GTK_WINDOW (win),
535                                       GTK_WINDOW (main_window));
536
537         gtk_widget_show_all (GTK_WIDGET(win));
538         
539 cleanup:
540         if (folder)
541                 g_object_unref (G_OBJECT (folder));
542         if (msg)
543                 g_object_unref (G_OBJECT (folder));
544 }
545
546
547
548
549
550 void 
551 modest_ui_actions_on_folder_selection_changed (ModestFolderView *folder_view,
552                                                TnyFolder *folder, 
553                                                gboolean selected,
554                                                ModestMainWindow *main_window)
555 {
556 //      GtkLabel *folder_info_label;
557         gchar *txt;     
558         ModestConf *conf;
559
560 /*      folder_info_label =  */
561 /*              GTK_LABEL (modest_widget_factory_get_folder_info_label */
562 /*                         (modest_runtime_get_widget_factory())); */
563
564 /*      if (!folder) { */
565 /*              gtk_label_set_label (GTK_LABEL(folder_info_label), ""); */
566 /*              return; */
567 /*      } */
568         
569         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
570         
571         if (!main_window->header_view)
572                 return;
573
574         conf = modest_runtime_get_conf ();
575
576         if (!selected) { /* the folder was unselected; save it's settings  */
577                 modest_widget_memory_save (conf, G_OBJECT (main_window->header_view),
578                                            "header-view");
579                 gtk_window_set_title (GTK_WINDOW(main_window), "Modest");
580                 modest_header_view_set_folder (main_window->header_view, NULL);
581         } else {  /* the folder was selected */
582                 if (folder) { /* folder may be NULL */
583                         guint num, unread;
584                         gchar *title;
585
586                         num    = tny_folder_get_all_count    (folder);
587                         unread = tny_folder_get_unread_count (folder);
588                         
589                         title = g_strdup_printf ("Modest: %s",
590                                                  tny_folder_get_name (folder));
591                         
592                         gtk_window_set_title (GTK_WINDOW(main_window), title);
593                         g_free (title);
594                         
595                         txt = g_strdup_printf (_("%d %s, %d unread"),
596                                                num, num==1 ? _("item") : _("items"), unread);           
597                         //gtk_label_set_label (GTK_LABEL(folder_info_label), txt);
598                         g_free (txt);
599                 }
600                 modest_header_view_set_folder (main_window->header_view, folder);
601                 modest_widget_memory_restore (conf, G_OBJECT(main_window->header_view),
602                                               "header-view");
603         }
604 }
605
606
607 /****************************************************/
608 /*
609  * below some stuff to clearup statusbar messages after 1,5 seconds....
610  */
611 static gboolean
612 progress_bar_clean (GtkWidget *bar)
613 {
614         if (GTK_IS_PROGRESS_BAR(bar)) {
615                 gtk_progress_bar_set_text     (GTK_PROGRESS_BAR(bar), "");
616                 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR(bar), 1.0);
617         }
618         return FALSE;
619 }
620
621 static gboolean
622 statusbar_clean (GtkWidget *bar)
623 {
624         if (GTK_IS_STATUSBAR(bar))
625                 gtk_statusbar_push (GTK_STATUSBAR(bar), 0, "");
626         return FALSE;
627 }
628
629
630 static void
631 statusbar_push (ModestMainWindow *main_window, guint context_id, const gchar *msg)
632 {
633         if (!msg)
634                 return;
635
636         if (main_window->progress_bar) {
637                 gtk_widget_show (main_window->progress_bar);
638                 g_timeout_add (3000, (GSourceFunc)progress_bar_clean,
639                                main_window->progress_bar);
640         }
641         
642         if (main_window->status_bar) {
643                 gtk_widget_show (main_window->status_bar);
644                 gtk_statusbar_push (GTK_STATUSBAR(main_window->status_bar), 0, msg);
645                 g_timeout_add (1500, (GSourceFunc)statusbar_clean, main_window->status_bar);
646         }
647
648 }
649 /****************************************************************************/
650
651 void 
652 modest_ui_actions_on_item_not_found (ModestHeaderView *header_view,ModestItemType type,
653                                      ModestWindow *win)
654 {
655         GtkWidget *dialog;
656         gchar *txt, *item;
657         gboolean online;
658         TnyDevice *device;
659         TnyAccountStore *account_store;
660
661         item = (type == MODEST_ITEM_TYPE_FOLDER) ? "folder" : "message";
662         
663         /* Get device. Do not ask the platform factory for it, because
664            it returns always a new one */
665         account_store = TNY_ACCOUNT_STORE (modest_runtime_get_account_store ());
666         device = tny_account_store_get_device (account_store);
667
668         if (g_main_depth > 0)   
669                 gdk_threads_enter ();
670         online = tny_device_is_online (device);
671
672         if (online) {
673                 /* already online -- the item is simply not there... */
674                 dialog = gtk_message_dialog_new (GTK_WINDOW (win),
675                                                  GTK_DIALOG_MODAL,
676                                                  GTK_MESSAGE_WARNING,
677                                                  GTK_BUTTONS_OK,
678                                                  _("The %s you selected cannot be found"),
679                                                  item);
680                 gtk_dialog_run (GTK_DIALOG(dialog));
681         } else {
682
683                 dialog = gtk_dialog_new_with_buttons (_("Connection requested"),
684                                                       GTK_WINDOW (win),
685                                                       GTK_DIALOG_MODAL,
686                                                       GTK_STOCK_CANCEL,
687                                                       GTK_RESPONSE_REJECT,
688                                                       GTK_STOCK_OK,
689                                                       GTK_RESPONSE_ACCEPT,
690                                                       NULL);
691
692                 txt = g_strdup_printf (_("This %s is not available in offline mode.\n"
693                                          "Do you want to get online?"), item);
694                 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), 
695                                     gtk_label_new (txt), FALSE, FALSE, 0);
696                 gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
697                 g_free (txt);
698
699                 gtk_window_set_default_size (GTK_WINDOW(dialog), 300, 300);
700                 if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
701                         tny_device_force_online (device);
702                 }
703         }
704         gtk_widget_destroy (dialog);
705         if (g_main_depth > 0)   
706                 gdk_threads_leave ();
707 }
708
709
710
711 void
712 modest_ui_actions_on_header_status_update (ModestHeaderView *header_view, 
713                                             const gchar *msg, gint num, 
714                                             gint total,  ModestMainWindow *main_window)
715 {
716         char* txt;
717
718         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
719         
720         if (!main_window->progress_bar)
721                 return;
722
723         if (total != 0)
724                 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR(main_window->progress_bar),
725                                                (gdouble)num/(gdouble)total);
726         else
727                 gtk_progress_bar_pulse (GTK_PROGRESS_BAR(main_window->progress_bar));
728
729         txt = g_strdup_printf (_("Downloading %d of %d"), num, total);
730         gtk_progress_bar_set_text (GTK_PROGRESS_BAR(main_window->progress_bar), txt);
731         g_free (txt);
732         
733         statusbar_push (main_window, 0, msg);
734 }
735
736
737 void
738 modest_ui_actions_on_msg_link_hover (ModestMsgView *msgview, const gchar* link,
739                                      ModestWindow *win)
740 {
741         g_warning (__FUNCTION__);
742 }       
743
744
745 void
746 modest_ui_actions_on_msg_link_clicked (ModestMsgView *msgview, const gchar* link,
747                                         ModestWindow *win)
748 {
749         g_warning (__FUNCTION__);
750 }
751
752 void
753 modest_ui_actions_on_msg_attachment_clicked (ModestMsgView *msgview, int index,
754                                              ModestWindow *win)
755 {
756         g_warning (__FUNCTION__);
757         
758 }
759
760 void
761 modest_ui_actions_on_send (GtkWidget *widget, ModestMsgEditWindow *edit_window)
762 {
763         TnyTransportAccount *transport_account;
764         ModestMailOperation *mail_operation;
765         MsgData *data;
766         gchar *account_name, *from;
767         ModestAccountMgr *account_mgr;
768
769         g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW(edit_window));
770         
771         data = modest_msg_edit_window_get_msg_data (edit_window);
772
773         /* FIXME: Code added just for testing. The final version will
774            use the send queue provided by tinymail and some
775            classifier */
776         account_mgr = modest_runtime_get_account_mgr();
777         account_name = modest_account_mgr_get_default_account (account_mgr);
778         if (!account_name) {
779                 g_printerr ("modest: no default account found\n");
780                 modest_msg_edit_window_free_msg_data (edit_window, data);
781                 return;
782         }
783         transport_account =
784                 TNY_TRANSPORT_ACCOUNT(modest_tny_account_store_get_tny_account_by_account
785                                       (modest_runtime_get_account_store(),
786                                        account_name,
787                                        TNY_ACCOUNT_TYPE_TRANSPORT));
788         if (!transport_account) {
789                 g_printerr ("modest: no transport account found for '%s'\n", account_name);
790                 g_free (account_name);
791                 modest_msg_edit_window_free_msg_data (edit_window, data);
792                 return;
793         }
794         from = modest_account_mgr_get_from_string (account_mgr, account_name);
795                 
796         mail_operation = modest_mail_operation_new ();
797         modest_mail_operation_send_new_mail (mail_operation,
798                                              transport_account,
799                                              from,
800                                              data->to, 
801                                              data->cc, 
802                                              data->bcc,
803                                              data->subject, 
804                                              data->body, 
805                                              NULL);
806         /* Frees */
807         g_free (from);
808         g_free (account_name);
809         g_object_unref (G_OBJECT (mail_operation));
810         g_object_unref (G_OBJECT (transport_account));
811
812         modest_msg_edit_window_free_msg_data (edit_window, data);
813
814         /* Save settings and close the window */
815         /* save_settings (edit_window) */
816         gtk_widget_destroy (GTK_WIDGET (edit_window));
817 }
818
819 /*
820  * Shows a dialog with an entry that asks for some text. The returned
821  * value must be freed by the caller. The dialog window title will be
822  * set to @title.
823  */
824 static gchar *
825 ask_for_folder_name (GtkWindow *parent_window,
826                      const gchar *title)
827 {
828         GtkWidget *dialog, *entry;
829         gchar *folder_name = NULL;
830
831         /* Ask for folder name */
832         dialog = gtk_dialog_new_with_buttons (_("New Folder Name"),
833                                               parent_window,
834                                               GTK_DIALOG_MODAL,
835                                               GTK_STOCK_CANCEL,
836                                               GTK_RESPONSE_REJECT,
837                                               GTK_STOCK_OK,
838                                               GTK_RESPONSE_ACCEPT,
839                                               NULL);
840         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), 
841                             gtk_label_new(title),
842                             FALSE, FALSE, 0);
843                 
844         entry = gtk_entry_new_with_max_length (40);
845         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), 
846                             entry,
847                             TRUE, FALSE, 0);    
848         
849         gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
850         
851         if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)         
852                 folder_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
853
854         gtk_widget_destroy (dialog);
855
856         return folder_name;
857 }
858         
859 void 
860 modest_ui_actions_on_new_folder (GtkWidget *widget, ModestMainWindow *main_window)
861 {
862         TnyFolder *parent_folder;
863
864         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
865         
866         if (!main_window->folder_view)
867                 return;
868
869         parent_folder = modest_folder_view_get_selected (main_window->folder_view);
870         
871         if (parent_folder) {
872                 gchar *folder_name;
873
874                 folder_name = ask_for_folder_name (GTK_WINDOW (main_window),
875                                                    _("Please enter a name for the new folder"));
876
877                 if (folder_name != NULL && strlen (folder_name) > 0) {
878                         TnyFolder *new_folder;
879                         ModestMailOperation *mail_op;
880
881                         mail_op = modest_mail_operation_new ();
882                         new_folder = modest_mail_operation_create_folder (mail_op,
883                                                                           TNY_FOLDER_STORE (parent_folder),
884                                                                           (const gchar *) folder_name);
885                         if (new_folder) {
886                                 /* TODO: tinymail should do this. 
887                                    Update view */
888                                 modest_folder_view_add_subfolder (main_window->folder_view, new_folder);
889
890                                 /* Free new folder */
891                                 g_object_unref (new_folder);
892                         }
893                         g_object_unref (mail_op);
894                 }
895                 g_object_unref (parent_folder);
896         }
897 }
898
899 void 
900 modest_ui_actions_on_rename_folder (GtkWidget *widget,
901                                      ModestMainWindow *main_window)
902 {
903         TnyFolder *folder;
904
905         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
906
907         if (!main_window->folder_view)
908                 return;
909         
910         folder = modest_folder_view_get_selected (main_window->folder_view);
911
912         if (folder) {
913                 gchar *folder_name;
914
915                 folder_name = ask_for_folder_name (GTK_WINDOW (main_window),
916                                                    _("Please enter a new name for the folder"));
917
918                 if (folder_name != NULL && strlen (folder_name) > 0) {
919                         ModestMailOperation *mail_op;
920                         const GError *error;
921
922                         mail_op = modest_mail_operation_new ();
923                         modest_mail_operation_rename_folder (mail_op,
924                                                              folder,
925                                                              (const gchar *) folder_name);
926
927                         error = modest_mail_operation_get_error (mail_op);
928                         if (!error)
929                                 /* TODO: tinymail should do this. 
930                                    Update view */
931                                 modest_folder_view_rename (main_window->folder_view);
932
933                         /* TODO: else ? notify error ? */
934
935                         g_object_unref (mail_op);
936                 }
937                 g_object_unref (folder);
938         }
939 }
940
941 static void
942 delete_folder (ModestMainWindow *main_window, gboolean move_to_trash) 
943 {
944         TnyFolder *folder;
945         ModestMailOperation *mail_op;
946         
947         if (!main_window->folder_view)
948                 return;
949
950         folder = modest_folder_view_get_selected (main_window->folder_view);
951
952         mail_op = modest_mail_operation_new ();
953         modest_mail_operation_remove_folder (mail_op, folder, move_to_trash);
954         g_object_unref (mail_op);
955 }
956
957 void 
958 modest_ui_actions_on_delete_folder (GtkWidget *widget,
959                                      ModestMainWindow *main_window)
960 {
961         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
962
963         delete_folder (main_window, FALSE);
964 }
965
966 void 
967 modest_ui_actions_on_move_folder_to_trash_folder (GtkWidget *widget, ModestMainWindow *main_window)
968 {
969         g_return_if_fail (MODEST_IS_MAIN_WINDOW(main_window));
970         
971         delete_folder (main_window, TRUE);
972 }
973
974 void
975 modest_ui_actions_on_accounts_reloaded (TnyAccountStore *store, gpointer user_data)
976 {
977         /* FIXME */
978         /* ModestFolderView *folder_view; */
979         
980 /*      folder_view = modest_widget_factory_get_folder_view (modest_runtime_get_widget_factory()); */
981 /*      modest_folder_view_update_model (folder_view, store); */
982 }
983
984 void 
985 modest_ui_actions_on_folder_moved (ModestFolderView *folder_view,  TnyFolder *folder, 
986                                     TnyFolderStore *parent,  gboolean *done,
987                                     gpointer user_data)
988 {
989         ModestMailOperation *mail_op;
990         const GError *error;
991
992         *done = TRUE;
993
994         /* Try to move the folder */    
995         mail_op = modest_mail_operation_new ();
996         modest_mail_operation_move_folder (mail_op, folder, parent);
997
998         error = modest_mail_operation_get_error (mail_op);
999         if (error)
1000                 *done = FALSE;
1001
1002         g_object_unref (G_OBJECT (mail_op));
1003 }