aboutsummaryrefslogblamecommitdiffstats
path: root/mail/e-mail-shell-view-actions.c
blob: 25e7d80da3caebf31cd6f2b7a72affee1bae4572 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14













                                                                    
                                                                             







                                                        



                                                      
           



















                                                                                    



                                                                




                                   
                                                                       
 



                                                                                
                                             


                                                                     

                                                                              

                                             
                                                      
                                                

                                        
                                                              
 
                                           




                            







                                                                            

                                                       
                                                                               



                                                                   


                                                         
                                                                              





                                                            






                                                                  


           


                                                             
                     


           


                                                            









                                                                                
                                                         





                                                              









                                                                                





                                                               

                                  





                                                                  


                                                                           

                                 
                                                                 





                                                                        



































                                                                           





                                                            









                                                                                
                                                        





                                                           

                                   



                                              


                                                                  




                                                                                

                                                                     
                                             





                                                                  




















                                                                                





                                                               









                                                                                





                                                              









                                                                                

 









                                                                    



                                                                  

























                                                                            





                                                                     

                                  
 

                                                                           
 
                                                  





                                                                        

                                  
 

                                                                           
 
                                                     


           

                                                             
 








                                                                           


           

                                                          
 

                                  
 

                                                                           

                               
                             

                                                     


           

                                                              
 

                                  

                        

                                                                           
 


                                                        


           

































































































































































                                                                            






















                                                                     


                                                            

                                  
 

                                                                           
 
                                               


           





























































































































                                                                                


                                                     
                           





                                                                     

                                  
 

                                                                           
 
                                                              





                                                                   

                                  
 

                                                                           
 
                                                            





                                                                 


                                              



                                                                       


                                                               

                                                         





                                                              






                                                                  





                                                                     
                                                      





                                                                    











                                                                  


           













                                                                           
           



                                                          








                                                                    



                                                                    


                                                 























                                                                           



                                                           



                                                         






























                                                                           

 




                                                        






























                                                                           

 

                                        






                                                        





                                                             
 













                                                                             






                                                     



















































































                                                                               













                                                   













                                                                          






                                                                













                                                       




































                                                             
                                  



                                                                      
                       
 
                             
               
                        

               
                 
 






                            
                              
               
                         
               


                
 


                                                 
               


                                   
               
                               
 
                                    
               


                                   
               
                               
 
                                     
               


                                   
               
                               
 


                                  
 
                                         
               
                                     
 
                                      
               


                                     
               
                                



                                                     













                                                            
                                                   

                 



















































                                                                


























































































































                                                       
                                     






                                                                
                                     
                                     
                                     
                            
                        

                            

                         

                                                                  

                                                                  
                                                                    
 

                                           


                                                              


                                                   










                                                                     
                                                                     



                                                  




                                                                           








                                                                   


                                                                   



                                                                          















                                                                      
 



                                                             





                                                                       






                                                                              
 
 

























































































































































                                                                            


                                                                        
                      
                                     
                                       



                                     


                                 
                      



                                                                  




                                                                    





                                                            
















                                                                    































                                                                           
 
                                                                
                                                                        







                                                                        
 
/*
 * e-mail-shell-view-actions.c
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) version 3.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with the program; if not, see <http://www.gnu.org/licenses/>
 *
 *
 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 *
 */

#include "e-mail-shell-view-private.h"

#define STATE_KEY_SEARCH_FILTER     "SearchFilter"
#define STATE_KEY_SEARCH_SCOPE      "SearchScope"
#define STATE_KEY_SEARCH_TEXT       "SearchText"

static void
action_gal_save_custom_view_cb (GtkAction *action,
                                EMailShellView *mail_shell_view)
{
    EMailShellContent *mail_shell_content;
    EShellView *shell_view;
    GalViewInstance *view_instance;

    /* All shell views repond to the activation of this action,
     * which is defined by EShellWindow.  But only the currently
     * active shell view proceeds with saving the custom view. */
    shell_view = E_SHELL_VIEW (mail_shell_view);
    if (!e_shell_view_is_active (shell_view))
        return;

    mail_shell_content = mail_shell_view->priv->mail_shell_content;
    view_instance = e_mail_shell_content_get_view_instance (mail_shell_content);
    gal_view_instance_save_as (view_instance);
}

static void
action_mail_account_disable_cb (GtkAction *action,
                                EMailShellView *mail_shell_view)
{
    EMailShellSidebar *mail_shell_sidebar;
    EMFolderTree *folder_tree;
    EAccountList *account_list;
    EAccount *account;
    gchar *folder_uri;

    mail_shell_sidebar = mail_shell_view->priv->mail_shell_sidebar;

    folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
    folder_uri = em_folder_tree_get_selected_uri (folder_tree);
    g_return_if_fail (folder_uri != NULL);

    account_list = e_get_account_list ();
    account = mail_config_get_account_by_source_url (folder_uri);
    g_return_if_fail (account != NULL);

    if (e_account_list_account_has_proxies (account_list, account))
        e_account_list_remove_account_proxies (account_list, account);

    account->enabled = !account->enabled;
    e_account_list_change (account_list, account);
    e_mail_store_remove_by_uri (folder_uri);

    if (account->parent_uid != NULL)
        e_account_list_remove (account_list, account);

    e_account_list_save (account_list);

    g_free (folder_uri);
}

static void
action_mail_create_search_folder_cb (GtkAction *action,
                                     EMailShellView *mail_shell_view)
{
    /* FIXME */
    g_print ("Action: %s\n", gtk_action_get_name (GTK_ACTION (action)));
}

static void
action_mail_download_foreach_cb (CamelService *service)
{
    if (CAMEL_IS_DISCO_STORE (service) || CAMEL_IS_OFFLINE_STORE (service))
        mail_store_prepare_offline (CAMEL_STORE (service));
}

static void
action_mail_download_cb (GtkAction *action,
                         EMailShellView *mail_shell_view)
{
    e_mail_store_foreach ((GHFunc) action_mail_download_foreach_cb, NULL);
}

static void
action_mail_empty_trash_cb (GtkAction *action,
                            EMailShellView *mail_shell_view)
{
    EShellWindow *shell_window;
    EShellView *shell_view;

    shell_view = E_SHELL_VIEW (mail_shell_view);
    shell_window = e_shell_view_get_shell_window (shell_view);

    em_utils_empty_trash (GTK_WIDGET (shell_window));
}

static void
action_mail_flush_outbox_cb (GtkAction *action,
                             EMailShellView *mail_shell_view)
{
    mail_send ();
}

static void
action_mail_folder_copy_cb (GtkAction *action,
                            EMailShellView *mail_shell_view)
{
    EMailShellSidebar *mail_shell_sidebar;
    CamelFolderInfo *folder_info;
    EMFolderTree *folder_tree;

    mail_shell_sidebar = mail_shell_view->priv->mail_shell_sidebar;
    folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
    folder_info = em_folder_tree_get_selected_folder_info (folder_tree);
    g_return_if_fail (folder_info != NULL);

    /* XXX Leaking folder_info? */
    em_folder_utils_copy_folder (folder_info, FALSE);
}

static void
action_mail_folder_delete_cb (GtkAction *action,
                              EMailShellView *mail_shell_view)
{
    EMailShellSidebar *mail_shell_sidebar;
    EMFolderTree *folder_tree;
    CamelFolder *folder;

    mail_shell_sidebar = mail_shell_view->priv->mail_shell_sidebar;
    folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
    folder = em_folder_tree_get_selected_folder (folder_tree);
    g_return_if_fail (folder != NULL);

    em_folder_utils_delete_folder (folder);
}

static void
action_mail_folder_expunge_cb (GtkAction *action,
                               EMailShellView *mail_shell_view)
{
    EMailReader *reader;
    MessageList *message_list;
    EShellWindow *shell_window;
    EShellView *shell_view;

    shell_view = E_SHELL_VIEW (mail_shell_view);
    shell_window = e_shell_view_get_shell_window (shell_view);

    reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
    message_list = e_mail_reader_get_message_list (reader);
    g_return_if_fail (message_list->folder != NULL);

    em_utils_expunge_folder (
        GTK_WIDGET (shell_window), message_list->folder);
}

static void
action_mail_folder_mark_all_as_read_cb (GtkAction *action,
                                        EMailShellView *mail_shell_view)
{
    EMailReader *reader;
    MessageList *message_list;
    EShellWindow *shell_window;
    EShellView *shell_view;
    CamelFolder *folder;
    GtkWindow *parent;
    GPtrArray *uids;
    const gchar *key;
    const gchar *prompt;
    guint ii;

    shell_view = E_SHELL_VIEW (mail_shell_view);
    shell_window = e_shell_view_get_shell_window (shell_view);
    parent = GTK_WINDOW (shell_window);

    reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
    message_list = e_mail_reader_get_message_list (reader);
    folder = message_list->folder;
    g_return_if_fail (folder != NULL);

    key = "/apps/evolution/mail/prompts/mark_all_read";
    prompt = "mail:ask-mark-all-read";

    if (!em_utils_prompt_user (parent, key, prompt, NULL))
        return;

    uids = message_list_get_uids (message_list);

    camel_folder_freeze (folder);
    for (ii = 0; ii < uids->len; ii++)
        camel_folder_set_message_flags (
            folder, uids->pdata[ii],
            CAMEL_MESSAGE_SEEN, CAMEL_MESSAGE_SEEN);
    camel_folder_thaw (folder);

    message_list_free_uids (message_list, uids);
}

static void
action_mail_folder_move_cb (GtkAction *action,
                            EMailShellView *mail_shell_view)
{
    EMailShellSidebar *mail_shell_sidebar;
    CamelFolderInfo *folder_info;
    EMFolderTree *folder_tree;

    mail_shell_sidebar = mail_shell_view->priv->mail_shell_sidebar;
    folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
    folder_info = em_folder_tree_get_selected_folder_info (folder_tree);
    g_return_if_fail (folder_info != NULL);

    /* XXX Leaking folder_info? */
    em_folder_utils_copy_folder (folder_info, TRUE);
}

static void
action_mail_folder_new_cb (GtkAction *action,
                           EMailShellView *mail_shell_view)
{
    EShellView *shell_view;
    EShellWindow *shell_window;
    EMailShellSidebar *mail_shell_sidebar;
    CamelFolderInfo *folder_info;
    EMFolderTree *folder_tree;

    shell_view = E_SHELL_VIEW (mail_shell_view);
    shell_window = e_shell_view_get_shell_window (shell_view);

    mail_shell_sidebar = mail_shell_view->priv->mail_shell_sidebar;
    folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
    folder_info = em_folder_tree_get_selected_folder_info (folder_tree);
    g_return_if_fail (folder_info != NULL);

    em_folder_utils_create_folder (
        folder_info, folder_tree, GTK_WINDOW (shell_window));
    camel_folder_info_free (folder_info);
}

static void
action_mail_folder_properties_cb (GtkAction *action,
                                  EMailShellView *mail_shell_view)
{
    EMailShellSidebar *mail_shell_sidebar;
    EMFolderTree *folder_tree;
    EShellView *shell_view;
    GtkTreeSelection *selection;
    GtkTreeView *tree_view;
    GtkTreeModel *model;
    GtkTreeIter iter;
    gchar *uri;

    shell_view = E_SHELL_VIEW (mail_shell_view);
    mail_shell_sidebar = mail_shell_view->priv->mail_shell_sidebar;
    folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);

    tree_view = GTK_TREE_VIEW (folder_tree);
    selection = gtk_tree_view_get_selection (tree_view);
    if (!gtk_tree_selection_get_selected (selection, &model, &iter))
        return;

    gtk_tree_model_get (model, &iter, COL_STRING_URI, &uri, -1);
    em_folder_properties_show (shell_view, NULL, uri);
    g_free (uri);
}

static void
action_mail_folder_refresh_cb (GtkAction *action,
                               EMailShellView *mail_shell_view)
{
    EMailShellSidebar *mail_shell_sidebar;
    EMFolderTree *folder_tree;
    CamelFolder *folder;

    mail_shell_sidebar = mail_shell_view->priv->mail_shell_sidebar;
    folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
    folder = em_folder_tree_get_selected_folder (folder_tree);
    g_return_if_fail (folder != NULL);

    mail_refresh_folder (folder, NULL, NULL);
}

static void
action_mail_folder_rename_cb (GtkAction *action,
                              EMailShellView *mail_shell_view)
{
    EMailShellSidebar *mail_shell_sidebar;
    EMFolderTree *folder_tree;
    CamelFolder *folder;

    mail_shell_sidebar = mail_shell_view->priv->mail_shell_sidebar;
    folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
    folder = em_folder_tree_get_selected_folder (folder_tree);
    g_return_if_fail (folder != NULL);

    em_folder_utils_rename_folder (folder);
}

/* Helper for action_mail_folder_select_all_cb() */
static gboolean
action_mail_folder_select_all_timeout_cb (MessageList *message_list)
{
    message_list_select_all (message_list);
    gtk_widget_grab_focus (GTK_WIDGET (message_list));

    return FALSE;
}

static void
action_mail_folder_select_all_cb (GtkAction *action,
                                  EMailShellView *mail_shell_view)
{
    EMailReader *reader;
    MessageList *message_list;
    EShellWindow *shell_window;
    EShellView *shell_view;

    shell_view = E_SHELL_VIEW (mail_shell_view);
    shell_window = e_shell_view_get_shell_window (shell_view);

    reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
    message_list = e_mail_reader_get_message_list (reader);

    if (message_list->threaded) {
        gtk_action_activate (ACTION (MAIL_THREADS_EXPAND_ALL));

        /* XXX The timeout below is added so that the execution
         *     thread to expand all conversation threads would
         *     have completed.  The timeout 505 is just to ensure
         *     that the value is a small delta more than the
         *     timeout value in mail_regen_list(). */
        g_timeout_add (
            505, (GSourceFunc)
            action_mail_folder_select_all_timeout_cb,
            message_list);
    } else
        /* If there is no threading, just select all immediately. */
        action_mail_folder_select_all_timeout_cb (message_list);
}

static void
action_mail_folder_select_thread_cb (GtkAction *action,
                                     EMailShellView *mail_shell_view)
{
    MessageList *message_list;
    EMailReader *reader;

    reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
    message_list = e_mail_reader_get_message_list (reader);

    message_list_select_thread (message_list);
}

static void
action_mail_folder_select_subthread_cb (GtkAction *action,
                                        EMailShellView *mail_shell_view)
{
    MessageList *message_list;
    EMailReader *reader;

    reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
    message_list = e_mail_reader_get_message_list (reader);

    message_list_select_subthread (message_list);
}

static void
action_mail_hide_deleted_cb (GtkToggleAction *action,
                             EMailShellView *mail_shell_view)
{
    MessageList *message_list;
    EMailReader *reader;
    gboolean active;

    reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
    message_list = e_mail_reader_get_message_list (reader);

    active = gtk_toggle_action_get_active (action);
    message_list_set_hidedeleted (message_list, active);
}

static void
action_mail_hide_read_cb (GtkAction *action,
                          EMailShellView *mail_shell_view)
{
    MessageList *message_list;
    EMailReader *reader;

    reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
    message_list = e_mail_reader_get_message_list (reader);

    message_list_hide_add (
        message_list,
        "(match-all (system-flag \"seen\"))",
        ML_HIDE_SAME, ML_HIDE_SAME);
}

static void
action_mail_hide_selected_cb (GtkAction *action,
                              EMailShellView *mail_shell_view)
{
    MessageList *message_list;
    EMailReader *reader;
    GPtrArray *uids;

    reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
    message_list = e_mail_reader_get_message_list (reader);

    uids = message_list_get_selected (message_list);
    message_list_hide_uids (message_list, uids);
    message_list_free_uids (message_list, uids);
}

static void
action_mail_label_cb (GtkToggleAction *action,
                      EMailShellView *mail_shell_view)
{
    EMailReader *reader;
    MessageList *message_list;
    CamelFolder *folder;
    GPtrArray *uids;
    const gchar *tag;
    gint ii;

    tag = g_object_get_data (G_OBJECT (action), "tag");
    g_return_if_fail (tag != NULL);

    reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
    message_list = e_mail_reader_get_message_list (reader);
    folder = message_list->folder;

    uids = message_list_get_selected (message_list);

    for (ii = 0; ii < uids->len; ii++) {
        if (gtk_toggle_action_get_active (action))
            camel_folder_set_message_user_flag (
                folder, uids->pdata[ii], tag, TRUE);
        else {
            camel_folder_set_message_user_flag (
                folder, uids->pdata[ii], tag, FALSE);
            camel_folder_set_message_user_tag (
                folder, uids->pdata[ii], "label", NULL);
        }
    }

    message_list_free_uids (message_list, uids);
}

static void
action_mail_label_new_cb (GtkAction *action,
                          EMailShellView *mail_shell_view)
{
    EShell *shell;
    EShellSettings *shell_settings;
    EShellWindow *shell_window;
    EShellView *shell_view;
    EMailLabelDialog *label_dialog;
    EMailLabelListStore *store;
    EMailReader *reader;
    MessageList *message_list;
    CamelFolder *folder;
    GtkTreeModel *model;
    GtkTreeIter iter;
    GtkWidget *dialog;
    GPtrArray *uids;
    GdkColor label_color;
    const gchar *property_name;
    const gchar *label_name;
    gchar *label_tag;
    gint n_children;
    guint ii;

    shell_view = E_SHELL_VIEW (mail_shell_view);
    shell_window = e_shell_view_get_shell_window (shell_view);

    dialog = e_mail_label_dialog_new (GTK_WINDOW (shell_window));

    gtk_window_set_title (GTK_WINDOW (dialog), _("Add Label"));

    if (gtk_dialog_run (GTK_DIALOG (dialog)) != GTK_RESPONSE_OK)
        goto exit;

    shell = e_shell_window_get_shell (shell_window);
    shell_settings = e_shell_get_shell_settings (shell);

    label_dialog = E_MAIL_LABEL_DIALOG (dialog);
    label_name = e_mail_label_dialog_get_label_name (label_dialog);
    e_mail_label_dialog_get_label_color (label_dialog, &label_color);

    property_name = "mail-label-list-store";
    store = e_shell_settings_get_object (shell_settings, property_name);
    e_mail_label_list_store_set (store, NULL, label_name, &label_color);
    g_object_unref (store);

    /* XXX This is awkward.  We've added a new label to the list store
     *     but we don't have the new label's tag nor an iterator to use
     *     to fetch it.  We know the label was appended to the store,
     *     so we have to dig it out manually.  EMailLabelListStore API
     *     probably needs some rethinking. */
    model = GTK_TREE_MODEL (store);
    n_children = gtk_tree_model_iter_n_children (model, NULL);
    gtk_tree_model_iter_nth_child (model, &iter, NULL, n_children - 1);
    label_tag = e_mail_label_list_store_get_tag (store, &iter);

    reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
    message_list = e_mail_reader_get_message_list (reader);
    folder = message_list->folder;

    uids = message_list_get_selected (message_list);

    for (ii = 0; ii < uids->len; ii++)
        camel_folder_set_message_user_flag (
            folder, uids->pdata[ii], label_tag, TRUE);

    message_list_free_uids (message_list, uids);

    g_free (label_tag);

exit:
    gtk_widget_destroy (dialog);
}

static void
action_mail_label_none_cb (GtkAction *action,
                           EMailShellView *mail_shell_view)
{
    EShell *shell;
    EShellView *shell_view;
    EShellSettings *shell_settings;
    EShellWindow *shell_window;
    EMailReader *reader;
    MessageList *message_list;
    GtkTreeModel *tree_model;
    CamelFolder *folder;
    GtkTreeIter iter;
    GPtrArray *uids;
    gboolean valid;
    guint ii;

    shell_view = E_SHELL_VIEW (mail_shell_view);
    shell_window = e_shell_view_get_shell_window (shell_view);
    shell = e_shell_window_get_shell (shell_window);
    shell_settings = e_shell_get_shell_settings (shell);

    tree_model = e_shell_settings_get_object (
        shell_settings, "mail-label-list-store");

    reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
    message_list = e_mail_reader_get_message_list (reader);
    uids = message_list_get_selected (message_list);
    folder = message_list->folder;

    valid = gtk_tree_model_get_iter_first (tree_model, &iter);

    while (valid) {
        gchar *tag;

        tag = e_mail_label_list_store_get_tag (
            E_MAIL_LABEL_LIST_STORE (tree_model), &iter);

        for (ii = 0; ii < uids->len; ii++) {
            camel_folder_set_message_user_flag (
                folder, uids->pdata[ii], tag, FALSE);
            camel_folder_set_message_user_tag (
                folder, uids->pdata[ii], "label", NULL);
        }

        g_free (tag);

        valid = gtk_tree_model_iter_next (tree_model, &iter);
    }

    message_list_free_uids (message_list, uids);
}

static void
action_mail_search_cb (GtkRadioAction *action,
                       GtkRadioAction *current,
                       EMailShellView *mail_shell_view)
{
    EShellView *shell_view;
    EShellContent *shell_content;
    const gchar *search_hint;

    /* XXX Figure out a way to handle this in EShellContent
     *     instead of every shell view having to handle it.
     *     The problem is EShellContent does not know what
     *     the search option actions are for this view.  It
     *     would have to dig up the popup menu and retrieve
     *     the action for each menu item.  Seems messy. */

    shell_view = E_SHELL_VIEW (mail_shell_view);
    shell_content = e_shell_view_get_shell_content (shell_view);

    search_hint = gtk_action_get_label (GTK_ACTION (current));
    e_shell_content_set_search_hint (shell_content, search_hint);
}

static void
action_mail_show_hidden_cb (GtkAction *action,
                            EMailShellView *mail_shell_view)
{
    MessageList *message_list;
    EMailReader *reader;

    reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
    message_list = e_mail_reader_get_message_list (reader);

    message_list_hide_clear (message_list);
}

static void
action_mail_smart_backward_cb (GtkAction *action,
                               EMailShellView *mail_shell_view)
{
    EShell *shell;
    EShellView *shell_view;
    EShellWindow *shell_window;
    EShellSettings *shell_settings;
    EMailShellSidebar *mail_shell_sidebar;
    EMFolderTree *folder_tree;
    EMFormatHTMLDisplay *html_display;
    EMailReader *reader;
    MessageList *message_list;
    GtkToggleAction *toggle_action;
    GtkHTML *html;
    gboolean caret_mode;
    gboolean magic_spacebar;

    /* This implements the so-called "Magic Backspace". */

    shell_view = E_SHELL_VIEW (mail_shell_view);
    shell_window = e_shell_view_get_shell_window (shell_view);
    shell = e_shell_window_get_shell (shell_window);
    shell_settings = e_shell_get_shell_settings (shell);

    mail_shell_sidebar = mail_shell_view->priv->mail_shell_sidebar;
    folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);

    reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
    html_display = e_mail_reader_get_html_display (reader);
    message_list = e_mail_reader_get_message_list (reader);

    magic_spacebar = e_shell_settings_get_boolean (
        shell_settings, "mail-magic-spacebar");

    toggle_action = GTK_TOGGLE_ACTION (ACTION (MAIL_CARET_MODE));
    caret_mode = gtk_toggle_action_get_active (toggle_action);

    html = EM_FORMAT_HTML (html_display)->html;

    if (gtk_html_command (html, "scroll-backward"))
        return;

    if (caret_mode || !magic_spacebar)
        return;

    /* XXX Are two separate calls really necessary? */

    if (message_list_select (
        message_list, MESSAGE_LIST_SELECT_PREVIOUS,
        0, CAMEL_MESSAGE_SEEN))
        return;

    if (message_list_select (
        message_list, MESSAGE_LIST_SELECT_PREVIOUS |
        MESSAGE_LIST_SELECT_WRAP, 0, CAMEL_MESSAGE_SEEN))
        return;

    em_folder_tree_select_prev_path (folder_tree, TRUE);

    gtk_widget_grab_focus (GTK_WIDGET (message_list));
}

static void
action_mail_smart_forward_cb (GtkAction *action,
                              EMailShellView *mail_shell_view)
{
    EShell *shell;
    EShellView *shell_view;
    EShellWindow *shell_window;
    EShellSettings *shell_settings;
    EMailShellSidebar *mail_shell_sidebar;
    EMFolderTree *folder_tree;
    EMFormatHTMLDisplay *html_display;
    EMailReader *reader;
    MessageList *message_list;
    GtkToggleAction *toggle_action;
    GtkHTML *html;
    gboolean caret_mode;
    gboolean magic_spacebar;

    /* This implements the so-called "Magic Spacebar". */

    shell_view = E_SHELL_VIEW (mail_shell_view);
    shell_window = e_shell_view_get_shell_window (shell_view);
    shell = e_shell_window_get_shell (shell_window);
    shell_settings = e_shell_get_shell_settings (shell);

    mail_shell_sidebar = mail_shell_view->priv->mail_shell_sidebar;
    folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);

    reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
    html_display = e_mail_reader_get_html_display (reader);
    message_list = e_mail_reader_get_message_list (reader);

    magic_spacebar = e_shell_settings_get_boolean (
        shell_settings, "mail-magic-spacebar");

    toggle_action = GTK_TOGGLE_ACTION (ACTION (MAIL_CARET_MODE));
    caret_mode = gtk_toggle_action_get_active (toggle_action);

    html = EM_FORMAT_HTML (html_display)->html;

    if (gtk_html_command (html, "scroll-forward"))
        return;

    if (caret_mode || !magic_spacebar)
        return;

    /* XXX Are two separate calls really necessary? */

    if (message_list_select (
        message_list, MESSAGE_LIST_SELECT_NEXT,
        0, CAMEL_MESSAGE_SEEN))
        return;

    if (message_list_select (
        message_list, MESSAGE_LIST_SELECT_NEXT |
        MESSAGE_LIST_SELECT_WRAP, 0, CAMEL_MESSAGE_SEEN))
        return;

    em_folder_tree_select_next_path (folder_tree, TRUE);

    gtk_widget_grab_focus (GTK_WIDGET (message_list));
}

static void
action_mail_stop_cb (GtkAction *action,
                     EMailShellView *mail_shell_view)
{
    mail_cancel_all ();
}

static void
action_mail_threads_collapse_all_cb (GtkAction *action,
                                     EMailShellView *mail_shell_view)
{
    MessageList *message_list;
    EMailReader *reader;

    reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
    message_list = e_mail_reader_get_message_list (reader);

    message_list_set_threaded_collapse_all (message_list);
}

static void
action_mail_threads_expand_all_cb (GtkAction *action,
                                   EMailShellView *mail_shell_view)
{
    MessageList *message_list;
    EMailReader *reader;

    reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
    message_list = e_mail_reader_get_message_list (reader);

    message_list_set_threaded_expand_all (message_list);
}

static void
action_mail_threads_group_by_cb (GtkToggleAction *action,
                                 EMailShellView *mail_shell_view)
{
    EMailShellContent *mail_shell_content;
    MessageList *message_list;
    EMailReader *reader;
    gboolean active;

    mail_shell_content = mail_shell_view->priv->mail_shell_content;
    active = gtk_toggle_action_get_active (action);

    reader = E_MAIL_READER (mail_shell_content);
    message_list = e_mail_reader_get_message_list (reader);

    message_list_set_threaded (message_list, active);
}

static void
action_mail_tools_filters_cb (GtkAction *action,
                              EMailShellView *mail_shell_view)
{
    EShellWindow *shell_window;
    EShellView *shell_view;

    shell_view = E_SHELL_VIEW (mail_shell_view);
    shell_window = e_shell_view_get_shell_window (shell_view);

    em_utils_edit_filters (GTK_WIDGET (shell_window));
}

static void
action_mail_tools_search_folders_cb (GtkAction *action,
                                     EMailShellView *mail_shell_view)
{
    vfolder_edit (E_SHELL_VIEW (mail_shell_view));
}

static void
action_mail_tools_subscriptions_cb (GtkAction *action,
                                    EMailShellView *mail_shell_view)
{
    EShellWindow *shell_window;
    EShellView *shell_view;
    GtkWidget *dialog;

    shell_view = E_SHELL_VIEW (mail_shell_view);
    shell_window = e_shell_view_get_shell_window (shell_view);

    dialog = em_subscribe_editor_new ();
    gtk_window_set_transient_for (
        GTK_WINDOW (dialog), GTK_WINDOW (shell_window));
    gtk_dialog_run (GTK_DIALOG (dialog));
    /* XXX Dialog destroys itself. */
}

static void
action_mail_view_cb (GtkRadioAction *action,
                     GtkRadioAction *current,
                     EMailShellView *mail_shell_view)
{
    EMailShellContent *mail_shell_content;
    gboolean vertical_view;

    mail_shell_content = mail_shell_view->priv->mail_shell_content;
    vertical_view = (gtk_radio_action_get_current_value (action) == 1);

    e_mail_shell_content_set_vertical_view (
        mail_shell_content, vertical_view);
}

static void
action_search_execute_cb (GtkAction *action,
                          EMailShellView *mail_shell_view)
{
    EShellView *shell_view;
    EShellContent *shell_content;
    EMailReader *reader;
    MessageList *message_list;
    GKeyFile *key_file;
    const gchar *folder_uri;

    shell_view = E_SHELL_VIEW (mail_shell_view);
    shell_content = e_shell_view_get_shell_content (shell_view);
    key_file = e_shell_view_get_state_key_file (shell_view);

    /* All shell views respond to the activation of this action,
     * which is defined by EShellWindow.  But only the currently
     * active shell view proceeds with executing the search. */
    if (!e_shell_view_is_active (shell_view))
        return;

    reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
    message_list = e_mail_reader_get_message_list (reader);
    folder_uri = message_list->folder_uri;

    if (folder_uri != NULL) {
        const gchar *key;
        const gchar *string;
        gchar *group_name;

        key = STATE_KEY_SEARCH_TEXT;
        string = e_shell_content_get_search_text (shell_content);
        group_name = g_strdup_printf ("Folder %s", folder_uri);

        if (string != NULL && *string != '\0')
            g_key_file_set_string (
                key_file, group_name, key, string);
        else
            g_key_file_remove_key (
                key_file, group_name, key, NULL);
        e_shell_view_set_state_dirty (shell_view);

        g_free (group_name);
    }

    e_mail_shell_view_execute_search (mail_shell_view);
}

static void
action_search_filter_cb (GtkRadioAction *action,
                         GtkRadioAction *current,
                         EMailShellView *mail_shell_view)
{
    EShellView *shell_view;
    EShellWindow *shell_window;
    EMailReader *reader;
    MessageList *message_list;
    GKeyFile *key_file;
    const gchar *folder_uri;

    shell_view = E_SHELL_VIEW (mail_shell_view);
    shell_window = e_shell_view_get_shell_window (shell_view);
    key_file = e_shell_view_get_state_key_file (shell_view);

    reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
    message_list = e_mail_reader_get_message_list (reader);
    folder_uri = message_list->folder_uri;

    if (folder_uri != NULL) {
        const gchar *key;
        const gchar *string;
        gchar *group_name;

        key = STATE_KEY_SEARCH_FILTER;
        string = gtk_action_get_name (GTK_ACTION (current));
        group_name = g_strdup_printf ("Folder %s", folder_uri);

        g_key_file_set_string (key_file, group_name, key, string);
        e_shell_view_set_state_dirty (shell_view);

        g_free (group_name);
    }

    gtk_action_activate (ACTION (SEARCH_EXECUTE));
}

static void
action_search_scope_cb (GtkRadioAction *action,
                        GtkRadioAction *current,
                        EMailShellView *mail_shell_view)
{
    EShellView *shell_view;
    EShellWindow *shell_window;
    EMailReader *reader;
    MessageList *message_list;
    GKeyFile *key_file;
    const gchar *folder_uri;

    shell_view = E_SHELL_VIEW (mail_shell_view);
    shell_window = e_shell_view_get_shell_window (shell_view);
    key_file = e_shell_view_get_state_key_file (shell_view);

    reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
    message_list = e_mail_reader_get_message_list (reader);
    folder_uri = message_list->folder_uri;

    if (folder_uri != NULL) {
        const gchar *key;
        const gchar *string;
        gchar *group_name;

        key = STATE_KEY_SEARCH_SCOPE;
        string = gtk_action_get_name (GTK_ACTION (current));
        group_name = g_strdup_printf ("Folder %s", folder_uri);

        g_key_file_set_string (key_file, group_name, key, string);
        e_shell_view_set_state_dirty (shell_view);

        g_free (group_name);
    }

    gtk_action_activate (ACTION (SEARCH_EXECUTE));
}

static GtkActionEntry mail_entries[] = {

    { "mail-account-disable",
      NULL,
      N_("_Disable Account"),
      NULL,
      N_("Disable this account"),
      G_CALLBACK (action_mail_account_disable_cb) },

    { "mail-create-search-folder",
      NULL,
      N_("C_reate Search Folder From Search..."),
      NULL,
      NULL,  /* XXX Add a tooltip! */
      G_CALLBACK (action_mail_create_search_folder_cb) },

    { "mail-download",
      NULL,
      N_("_Download Messages for Offline Usage"),
      NULL,
      N_("Download messages of accounts and folders marked for offline"),
      G_CALLBACK (action_mail_download_cb) },

    { "mail-empty-trash",
      NULL,
      N_("Empty _Trash"),
      NULL,
      N_("Permanently remove all the deleted messages from all folders"),
      G_CALLBACK (action_mail_empty_trash_cb) },

    { "mail-flush-outbox",
      "mail-send",
      N_("Fl_ush Outbox"),
      NULL,
      NULL,  /* XXX Add a tooltip! */
      G_CALLBACK (action_mail_flush_outbox_cb) },

    { "mail-folder-copy",
      "folder-copy",
      N_("_Copy Folder To..."),
      NULL,
      N_("Copy the selected folder into another folder"),
      G_CALLBACK (action_mail_folder_copy_cb) },

    { "mail-folder-delete",
      GTK_STOCK_DELETE,
      NULL,
      NULL,
      N_("Permanently remove this folder"),
      G_CALLBACK (action_mail_folder_delete_cb) },

    { "mail-folder-expunge",
      NULL,
      N_("E_xpunge"),
      "<Control>e",
      N_("Permanently remove all deleted messages from this folder"),
      G_CALLBACK (action_mail_folder_expunge_cb) },

    { "mail-folder-mark-all-as-read",
      "mail-read",
      N_("Mar_k All Messages as Read"),
      NULL,
      N_("Mark all messages in the folder as read"),
      G_CALLBACK (action_mail_folder_mark_all_as_read_cb) },

    { "mail-folder-move",
      "folder-move",
      N_("_Move Folder To..."),
      NULL,
      N_("Move the selected folder into another folder"),
      G_CALLBACK (action_mail_folder_move_cb) },

    { "mail-folder-new",
      "folder-new",
      N_("_New..."),
      NULL,
      N_("Create a new folder for storing mail"),
      G_CALLBACK (action_mail_folder_new_cb) },

    { "mail-folder-properties",
      GTK_STOCK_PROPERTIES,
      NULL,
      NULL,
      N_("Change the properties of this folder"),
      G_CALLBACK (action_mail_folder_properties_cb) },

    { "mail-folder-refresh",
      GTK_STOCK_REFRESH,
      NULL,
      "F5",
      N_("Refresh the folder"),
      G_CALLBACK (action_mail_folder_refresh_cb) },

    { "mail-folder-rename",
      NULL,
      N_("_Rename..."),
      "F2",
      N_("Change the name of this folder"),
      G_CALLBACK (action_mail_folder_rename_cb) },

    { "mail-folder-select-all",
      NULL,
      N_("Select _All Messages"),
      "<Control>a",
      N_("Select all visible messages"),
      G_CALLBACK (action_mail_folder_select_all_cb) },

    { "mail-folder-select-thread",
      NULL,
      N_("Select Message _Thread"),
      "<Control>h",
      N_("Select all messages in the same thread as the selected message"),
      G_CALLBACK (action_mail_folder_select_thread_cb) },

    { "mail-folder-select-subthread",
      NULL,
      N_("Select Message S_ubthread"),
      "<Shift><Control>h",
      N_("Select all replies to the currently selected message"),
      G_CALLBACK (action_mail_folder_select_subthread_cb) },

    { "mail-label-new",
      NULL,
      N_("_New Label"),
      NULL,
      NULL,  /* XXX Add a tooltip! */
      G_CALLBACK (action_mail_label_new_cb) },

    { "mail-label-none",
      NULL,
      N_("N_one"),
      NULL,
      NULL,  /* XXX Add a tooltip! */
      G_CALLBACK (action_mail_label_none_cb) },

    { "mail-hide-read",
      NULL,
      N_("Hide _Read Messages"),
      NULL,
      N_("Temporarily hide all messages that have already been read"),
      G_CALLBACK (action_mail_hide_read_cb) },

    { "mail-hide-selected",
      NULL,
      N_("Hide S_elected Messages"),
      NULL,
      N_("Temporarily hide the selected messages"),
      G_CALLBACK (action_mail_hide_selected_cb) },

    { "mail-show-hidden",
      NULL,
      N_("Show Hidde_n Messages"),
      NULL,
      N_("Show messages that have been temporarily hidden"),
      G_CALLBACK (action_mail_show_hidden_cb) },

    { "mail-smart-backward",
      NULL,
      NULL,  /* No menu item; key press only */
      NULL,
      NULL,
      G_CALLBACK (action_mail_smart_backward_cb) },

    { "mail-smart-forward",
      NULL,
      NULL,  /* No menu item; key press only */
      NULL,
      NULL,
      G_CALLBACK (action_mail_smart_forward_cb) },

    { "mail-stop",
      GTK_STOCK_STOP,
      N_("Cancel"),
      NULL,
      N_("Cancel the current mail operation"),
      G_CALLBACK (action_mail_stop_cb) },

    { "mail-threads-collapse-all",
      NULL,
      N_("Collapse All _Threads"),
      "<Shift><Control>b",
      N_("Collapse all message threads"),
      G_CALLBACK (action_mail_threads_collapse_all_cb) },

    { "mail-threads-expand-all",
      NULL,
      N_("E_xpand All Threads"),
      NULL,
      N_("Expand all message threads"),
      G_CALLBACK (action_mail_threads_expand_all_cb) },

    { "mail-tools-filters",
      NULL,
      N_("_Message Filters"),
      NULL,
      N_("Create or edit rules for filtering new mail"),
      G_CALLBACK (action_mail_tools_filters_cb) },

    { "mail-tools-search-folders",
      NULL,
      N_("Search F_olders"),
      NULL,
      N_("Create or edit search folder definitions"),
      G_CALLBACK (action_mail_tools_search_folders_cb) },

    { "mail-tools-subscriptions",
      NULL,
      N_("_Subscriptions..."),
      NULL,
      N_("Subscribe or unsubscribe to folders on remote servers"),
      G_CALLBACK (action_mail_tools_subscriptions_cb) },

    /*** Menus ***/

    { "mail-folder-menu",
      NULL,
      N_("F_older"),
      NULL,
      NULL,
      NULL },

    { "mail-label-menu",
      NULL,
      N_("_Label"),
      NULL,
      NULL,
      NULL },

    { "mail-preview-menu",
      NULL,
      N_("_Preview"),
      NULL,
      NULL,
      NULL }
};

static EPopupActionEntry mail_popup_entries[] = {

    { "mail-popup-account-disable",
      NULL,
      "mail-account-disable" },

    { "mail-popup-empty-trash",
      NULL,
      "mail-empty-trash" },

    { "mail-popup-flush-outbox",
      NULL,
      "mail-flush-outbox" },

    { "mail-popup-folder-copy",
      NULL,
      "mail-folder-copy" },

    { "mail-popup-folder-delete",
      NULL,
      "mail-folder-delete" },

    { "mail-popup-folder-move",
      NULL,
      "mail-folder-move" },

    { "mail-popup-folder-new",
      N_("_New Folder..."),
      "mail-folder-new" },

    { "mail-popup-folder-properties",
      NULL,
      "mail-folder-properties" },

    { "mail-popup-folder-refresh",
      NULL,
      "mail-folder-refresh" },

    { "mail-popup-folder-rename",
      NULL,
      "mail-folder-rename" }
};

static GtkToggleActionEntry mail_toggle_entries[] = {

    { "mail-hide-deleted",
      NULL,
      N_("Hide _Deleted Messages"),
      NULL,
      N_("Hide deleted messages rather than displaying "
         "them with a line through them"),
      G_CALLBACK (action_mail_hide_deleted_cb),
      TRUE },

    { "mail-preview",
      NULL,
      N_("Show Message _Preview"),
      "<Control>m",
      N_("Show message preview pane"),
      NULL,  /* Handled by property bindings */
      TRUE },

    { "mail-threads-group-by",
      NULL,
      N_("_Group By Threads"),
      "<Control>t",
      N_("Threaded message list"),
      G_CALLBACK (action_mail_threads_group_by_cb),
      FALSE }
};

static GtkRadioActionEntry mail_view_entries[] = {

    /* This action represents the initial active mail view.
     * It should not be visible in the UI, nor should it be
     * possible to switch to it from another shell view. */
    { "mail-view-internal",
      NULL,
      NULL,
      NULL,
      NULL,
      -1 },

    { "mail-view-classic",
      NULL,
      N_("_Classic View"),
      NULL,
      N_("Show message preview below the message list"),
      0 },

    { "mail-view-vertical",
      NULL,
      N_("_Vertical View"),
      NULL,
      N_("Show message preview alongside the message list"),
      1 }
};

static GtkRadioActionEntry mail_filter_entries[] = {

    { "mail-filter-all-messages",
      NULL,
      N_("All Messages"),
      NULL,
      NULL,  /* XXX Add a tooltip! */
      MAIL_FILTER_ALL_MESSAGES },

    { "mail-filter-important-messages",
      "emblem-important",
      N_("Important Messages"),
      NULL,
      NULL,  /* XXX Add a tooltip! */
      MAIL_FILTER_IMPORTANT_MESSAGES },

    { "mail-filter-last-5-days-messages",
      NULL,
      N_("Last 5 Days' Messages"),
      NULL,
      NULL,  /* XXX Add a tooltip! */
      MAIL_FILTER_LAST_5_DAYS_MESSAGES },

    { "mail-filter-messages-not-junk",
      "mail-mark-notjunk",
      N_("Messages Not Junk"),
      NULL,
      NULL,  /* XXX Add a tooltip! */
      MAIL_FILTER_MESSAGES_NOT_JUNK },

    { "mail-filter-messages-with-attachments",
      "mail-attachment",
      N_("Messages with Attachments"),
      NULL,
      NULL,  /* XXX Add a tooltip! */
      MAIL_FILTER_MESSAGES_WITH_ATTACHMENTS },

    { "mail-filter-no-label",
      NULL,
      N_("No Label"),
      NULL,
      NULL,  /* XXX Add a tooltip! */
      MAIL_FILTER_NO_LABEL },

    { "mail-filter-read-messages",
      "mail-read",
      N_("Read Messages"),
      NULL,
      NULL,  /* XXX Add a tooltip! */
      MAIL_FILTER_READ_MESSAGES },

    { "mail-filter-recent-messages",
      NULL,
      N_("Recent Messages"),
      NULL,
      NULL,  /* XXX Add a tooltip! */
      MAIL_FILTER_RECENT_MESSAGES },

    { "mail-filter-unread-messages",
      "mail-unread",
      N_("Unread Messages"),
      NULL,
      NULL,  /* XXX Add a tooltip! */
      MAIL_FILTER_UNREAD_MESSAGES }
};

static GtkRadioActionEntry mail_search_entries[] = {

    { "mail-search-body-contains",
      NULL,
      N_("Body contains"),
      NULL,
      NULL,  /* XXX Add a tooltip! */
      MAIL_SEARCH_BODY_CONTAINS },

    { "mail-search-message-contains",
      NULL,
      N_("Message contains"),
      NULL,
      NULL,  /* XXX Add a tooltip! */
      MAIL_SEARCH_MESSAGE_CONTAINS },

    { "mail-search-recipients-contain",
      NULL,
      N_("Recipients contain"),
      NULL,
      NULL,  /* XXX Add a tooltip! */
      MAIL_SEARCH_RECIPIENTS_CONTAIN },

    { "mail-search-sender-contains",
      NULL,
      N_("Sender contains"),
      NULL,
      NULL,  /* XXX Add a tooltip! */
      MAIL_SEARCH_SENDER_CONTAINS },

    { "mail-search-subject-contains",
      NULL,
      N_("Subject contains"),
      NULL,
      NULL,  /* XXX Add a tooltip! */
      MAIL_SEARCH_SUBJECT_CONTAINS },

    { "mail-search-subject-or-recipients-contains",
      NULL,
      N_("Subject or Recipients contains"),
      NULL,
      NULL,  /* XXX Add a tooltip! */
      MAIL_SEARCH_SUBJECT_OR_RECIPIENTS_CONTAINS },

    { "mail-search-subject-or-sender-contains",
      NULL,
      N_("Subject or Sender contains"),
      NULL,
      NULL,  /* XXX Add a tooltip! */
      MAIL_SEARCH_SUBJECT_OR_SENDER_CONTAINS }
};

static GtkRadioActionEntry mail_scope_entries[] = {

    { "mail-scope-all-accounts",
      NULL,
      N_("All Accounts"),
      NULL,
      NULL,  /* XXX Add a tooltip! */
      MAIL_SCOPE_ALL_ACCOUNTS },

    { "mail-scope-current-account",
      NULL,
      N_("Current Account"),
      NULL,
      NULL,  /* XXX Add a tooltip! */
      MAIL_SCOPE_CURRENT_ACCOUNT },

    { "mail-scope-current-folder",
      NULL,
      N_("Current Folder"),
      NULL,
      NULL,  /* XXX Add a tooltip! */
      MAIL_SCOPE_CURRENT_FOLDER }
};

void
e_mail_shell_view_actions_init (EMailShellView *mail_shell_view)
{
    EShellView *shell_view;
    EShellWindow *shell_window;
    EShellContent *shell_content;
    GtkActionGroup *action_group;
    GtkRadioAction *radio_action;
    GConfBridge *bridge;
    GObject *object;
    GObject *src_object;
    GObject *dst_object;
    const gchar *key;

    g_return_if_fail (E_IS_MAIL_SHELL_VIEW (mail_shell_view));

    shell_view = E_SHELL_VIEW (mail_shell_view);
    shell_window = e_shell_view_get_shell_window (shell_view);
    shell_content = e_shell_view_get_shell_content (shell_view);

    /* Mail Actions */
    action_group = ACTION_GROUP (MAIL);
    gtk_action_group_add_actions (
        action_group, mail_entries,
        G_N_ELEMENTS (mail_entries), mail_shell_view);
    e_action_group_add_popup_actions (
        action_group, mail_popup_entries,
        G_N_ELEMENTS (mail_popup_entries));
    gtk_action_group_add_toggle_actions (
        action_group, mail_toggle_entries,
        G_N_ELEMENTS (mail_toggle_entries), mail_shell_view);
    gtk_action_group_add_radio_actions (
        action_group, mail_view_entries,
        G_N_ELEMENTS (mail_view_entries), -1,
        G_CALLBACK (action_mail_view_cb), mail_shell_view);
    gtk_action_group_add_radio_actions (
        action_group, mail_search_entries,
        G_N_ELEMENTS (mail_search_entries),
        MAIL_SEARCH_SUBJECT_OR_SENDER_CONTAINS,
        G_CALLBACK (action_mail_search_cb), mail_shell_view);
    gtk_action_group_add_radio_actions (
        action_group, mail_scope_entries,
        G_N_ELEMENTS (mail_scope_entries),
        MAIL_SCOPE_CURRENT_FOLDER,
        G_CALLBACK (action_search_scope_cb), mail_shell_view);

    radio_action = GTK_RADIO_ACTION (ACTION (MAIL_SCOPE_ALL_ACCOUNTS));
    e_shell_content_set_scope_action (shell_content, radio_action);
    e_shell_content_set_scope_visible (shell_content, TRUE);

    /* Bind GObject properties for GConf keys. */

    bridge = gconf_bridge_get ();

    object = G_OBJECT (ACTION (MAIL_PREVIEW));
    key = "/apps/evolution/mail/display/show_preview";
    gconf_bridge_bind_property (bridge, key, object, "active");

    object = G_OBJECT (ACTION (MAIL_THREADS_GROUP_BY));
    key = "/apps/evolution/mail/display/thread_list";
    gconf_bridge_bind_property (bridge, key, object, "active");

    object = G_OBJECT (ACTION (MAIL_VIEW_VERTICAL));
    key = "/apps/evolution/mail/display/layout";
    gconf_bridge_bind_property (bridge, key, object, "current-value");

    /* Fine tuning. */

    src_object = G_OBJECT (ACTION (MAIL_THREADS_GROUP_BY));

    dst_object = G_OBJECT (ACTION (MAIL_FOLDER_SELECT_THREAD));
    e_binding_new (src_object, "active", dst_object, "sensitive");

    dst_object = G_OBJECT (ACTION (MAIL_FOLDER_SELECT_SUBTHREAD));
    e_binding_new (src_object, "active", dst_object, "sensitive");

    dst_object = G_OBJECT (ACTION (MAIL_THREADS_COLLAPSE_ALL));
    e_binding_new (src_object, "active", dst_object, "sensitive");

    dst_object = G_OBJECT (ACTION (MAIL_THREADS_EXPAND_ALL));
    e_binding_new (src_object, "active", dst_object, "sensitive");

    e_mutual_binding_new (
        G_OBJECT (ACTION (MAIL_PREVIEW)), "active",
        G_OBJECT (shell_content), "preview-visible");

    /* XXX The boolean sense of the GConf key is the inverse of
     *     the menu item, so we have to maintain two properties. */
    e_mutual_binding_new_with_negation (
        G_OBJECT (shell_content), "show-deleted",
        G_OBJECT (ACTION (MAIL_HIDE_DELETED)), "active");

    g_signal_connect (
        ACTION (GAL_SAVE_CUSTOM_VIEW), "activate",
        G_CALLBACK (action_gal_save_custom_view_cb), mail_shell_view);

    g_signal_connect (
        ACTION (SEARCH_EXECUTE), "activate",
        G_CALLBACK (action_search_execute_cb), mail_shell_view);
}

/* Helper for e_mail_shell_view_update_popup_labels() */
static void
mail_shell_view_update_label_action (GtkToggleAction *action,
                                     MessageList *message_list,
                                     GPtrArray *uids,
                                     const gchar *label_tag)
{
    CamelFolder *folder;
    gboolean exists = FALSE;
    gboolean not_exists = FALSE;
    gboolean sensitive;
    guint ii;

    folder = message_list->folder;

    /* Figure out the proper label action state for the selected
     * messages.  If all the selected messages have the given label,
     * make the toggle action active.  If all the selected message
     * DO NOT have the given label, make the toggle action inactive.
     * If some do and some don't, make the action insensitive. */

    for (ii = 0; ii < uids->len && (!exists || !not_exists); ii++) {
        const gchar *old_label;
        gchar *new_label;

        /* Check for new-style labels. */
        if (camel_folder_get_message_user_flag (
            folder, uids->pdata[ii], label_tag)) {
            exists = TRUE;
            continue;
        }

        /* Check for old-style labels. */
        old_label = camel_folder_get_message_user_tag (
            folder, uids->pdata[ii], "label");
        if (old_label == NULL) {
            not_exists = TRUE;
            continue;
        }

        /* Convert old-style labels ("<name>") to "$Label<name>". */
        new_label = g_alloca (strlen (old_label) + 10);
        g_stpcpy (g_stpcpy (new_label, "$Label"), old_label);

        if (strcmp (new_label, label_tag) == 0)
            exists = TRUE;
        else
            not_exists = TRUE;
    }

    sensitive = !(exists && not_exists);
    gtk_toggle_action_set_active (action, exists);
    gtk_action_set_sensitive (GTK_ACTION (action), sensitive);
}

void
e_mail_shell_view_update_popup_labels (EMailShellView *mail_shell_view)
{
    EShell *shell;
    EShellSettings *shell_settings;
    EShellWindow *shell_window;
    EShellView *shell_view;
    EMailReader *reader;
    MessageList *message_list;
    GtkUIManager *ui_manager;
    GtkActionGroup *action_group;
    GtkTreeModel *tree_model;
    GtkTreeIter iter;
    GPtrArray *uids;
    const gchar *path;
    gboolean valid;
    guint merge_id;
    gint ii = 0;

    g_return_if_fail (E_IS_MAIL_SHELL_VIEW (mail_shell_view));

    shell_view = E_SHELL_VIEW (mail_shell_view);
    shell_window = e_shell_view_get_shell_window (shell_view);
    ui_manager = e_shell_window_get_ui_manager (shell_window);

    shell = e_shell_window_get_shell (shell_window);
    shell_settings = e_shell_get_shell_settings (shell);

    tree_model = e_shell_settings_get_object (
        shell_settings, "mail-label-list-store");

    action_group = ACTION_GROUP (MAIL_LABEL);
    merge_id = mail_shell_view->priv->label_merge_id;
    path = "/mail-message-popup/mail-label-menu/mail-label-actions";

    /* Unmerge the previous menu items. */
    gtk_ui_manager_remove_ui (ui_manager, merge_id);
    e_action_group_remove_all_actions (action_group);

    reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
    message_list = e_mail_reader_get_message_list (reader);
    uids = message_list_get_selected (message_list);

    valid = gtk_tree_model_get_iter_first (tree_model, &iter);

    while (valid) {
        GtkToggleAction *toggle_action;
        GtkAction *action;
        gchar *action_name;
        gchar *stock_id;
        gchar *label;
        gchar *tag;

        label = e_mail_label_list_store_get_name (
            E_MAIL_LABEL_LIST_STORE (tree_model), &iter);
        stock_id = e_mail_label_list_store_get_stock_id (
            E_MAIL_LABEL_LIST_STORE (tree_model), &iter);
        tag = e_mail_label_list_store_get_tag (
            E_MAIL_LABEL_LIST_STORE (tree_model), &iter);
        action_name = g_strdup_printf ("mail-label-%d", ii);

        /* XXX Add a tooltip! */
        toggle_action = gtk_toggle_action_new (
            action_name, label, NULL, stock_id);

        g_object_set_data_full (
            G_OBJECT (toggle_action), "tag",
            tag, (GDestroyNotify) g_free);

        /* Configure the action before we connect to signals. */
        mail_shell_view_update_label_action (
            toggle_action, message_list, uids, tag);

        g_signal_connect (
            toggle_action, "toggled",
            G_CALLBACK (action_mail_label_cb), mail_shell_view);

        /* The action group takes ownership of the action. */
        action = GTK_ACTION (toggle_action);
        gtk_action_group_add_action (action_group, action);
        g_object_unref (toggle_action);

        gtk_ui_manager_add_ui (
            ui_manager, merge_id, path, action_name,
            action_name, GTK_UI_MANAGER_AUTO, FALSE);

        g_free (label);
        g_free (stock_id);
        g_free (action_name);

        valid = gtk_tree_model_iter_next (tree_model, &iter);
        ii++;
    }

    message_list_free_uids (message_list, uids);

    g_object_unref (tree_model);
}

void
e_mail_shell_view_update_search_filter (EMailShellView *mail_shell_view)
{
    EShell *shell;
    EShellContent *shell_content;
    EShellSettings *shell_settings;
    EShellWindow *shell_window;
    EShellView *shell_view;
    GtkActionGroup *action_group;
    GtkRadioAction *radio_action;
    GtkTreeModel *tree_model;
    GtkTreeIter iter;
    GList *list;
    GSList *group;
    gboolean valid;
    gint ii = 0;

    g_return_if_fail (E_IS_MAIL_SHELL_VIEW (mail_shell_view));

    shell_view = E_SHELL_VIEW (mail_shell_view);
    shell_content = e_shell_view_get_shell_content (shell_view);
    shell_window = e_shell_view_get_shell_window (shell_view);

    shell = e_shell_window_get_shell (shell_window);
    shell_settings = e_shell_get_shell_settings (shell);

    tree_model = e_shell_settings_get_object (
        shell_settings, "mail-label-list-store");

    action_group = ACTION_GROUP (MAIL_FILTER);
    e_action_group_remove_all_actions (action_group);

    /* Add the standard filter actions. */
    gtk_action_group_add_radio_actions (
        action_group, mail_filter_entries,
        G_N_ELEMENTS (mail_filter_entries),
        MAIL_FILTER_ALL_MESSAGES,
        G_CALLBACK (action_search_filter_cb),
        mail_shell_view);

    /* Retrieve the radio group from an action we just added. */
    list = gtk_action_group_list_actions (action_group);
    radio_action = GTK_RADIO_ACTION (list->data);
    group = gtk_radio_action_get_group (radio_action);
    g_list_free (list);

    valid = gtk_tree_model_get_iter_first (tree_model, &iter);

    while (valid) {
        GtkAction *action;
        gchar *action_name;
        gchar *stock_id;
        gchar *label;

        label = e_mail_label_list_store_get_name (
            E_MAIL_LABEL_LIST_STORE (tree_model), &iter);
        stock_id = e_mail_label_list_store_get_stock_id (
            E_MAIL_LABEL_LIST_STORE (tree_model), &iter);

        action_name = g_strdup_printf ("mail-filter-label-%d", ii);
        radio_action = gtk_radio_action_new (
            action_name, label, NULL, stock_id, ii);
        g_free (action_name);

        gtk_radio_action_set_group (radio_action, group);
        group = gtk_radio_action_get_group (radio_action);

        /* The action group takes ownership of the action. */
        action = GTK_ACTION (radio_action);
        gtk_action_group_add_action (action_group, action);
        g_object_unref (radio_action);

        g_free (label);
        g_free (stock_id);

        valid = gtk_tree_model_iter_next (tree_model, &iter);
        ii++;
    }

    /* Use any action in the group; doesn't matter which. */
    e_shell_content_set_filter_action (shell_content, radio_action);

    ii = MAIL_FILTER_UNREAD_MESSAGES;
    e_shell_content_add_filter_separator_after (shell_content, ii);

    ii = MAIL_FILTER_READ_MESSAGES;
    e_shell_content_add_filter_separator_before (shell_content, ii);

    g_object_unref (tree_model);
}