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