aboutsummaryrefslogblamecommitdiffstats
path: root/mail/mail-send-recv.c
blob: fa0b9d2ec7f0802aca52b777f96e863415739cb2 (plain) (tree)
1
2
3
4
5
6
7
8
9
  
                                                                


                                                               
  


                                                                    


                                                                   
                                                                             
  




                                                        

   
 


                    
 


                   
                       
 
                                          
 
                          

                                   
 
                         
                           

                           



                              
                       
 



                                          
 


                                        


                                                         

                        




                                                                               
                     
                   

                            
                                                                                                       




                     
                      
                       
 
                                                                                                 



                            

                                                        

  



                                                                         
                    
              






                       
                   
                                                                 
                              
                                  
                   
                                
                           


                                 
 
                                                            
 


                        
 
                                      
                        
 
                          


                                




                                                                      
 
                                           
                                          
 
           
                                            

                                                  
                                                    
                                      

                           


           
                                        
 

                                               

                                                   
                           
                                  

                                                   
                                
                      

 
                          
                      

                                
 
                                

                                                              



                                                           
                                                       
                                                         
                                           



                                                         



                         
           
                                                           
 
                                         
                                                                             
                                       

                                                               
                                                   

                                             
                                
                                                                      


           
                     
 

                                            
                                                                 
 
                          
                                                           
                                                                  
                                             
         
 




                                             


                         
           
                                                                       
 
                                                                

 
           
                                                                     
 


                                   

                                    
                                                   




                                     
                                                              
 

                                                                           
                                


           
                                                                     
 
                         
                                 
                                                     

                                               
                                                                                            
                 
                                                                                   
                      
                
                                             
                                                                                  
                                
                                                        



                      


                                                                                
           
                                        



                                       

                                                   



                                                              

                                                               
                                            
                                                                 
                                                                       












                                                                     






                            
                                                                     
 

                                           

                                     
                      




                                             
                                                                    






                                                



                                



                                          
 
                                         
 
 
              
                                                                 

                      
                                 
 

                                                 

                                            


                                                                        
                                   


                                                                        
                    




                                                             
                                            


                                                          
                                   


                                                          
                    

                                                            
         

                
                                     
 
                          

 
                  
                                   
 

                                

                                                                                   
                                         

                                    
                                                  
 

                                    
 







                                                                      
 
                            

 
                          
                                
                                    

                                     

                                       
 
                      
                         
                              

                                
                             

                             
                                   



                                 
                                
                          

                          

                                         



                                                        
                                                       
 



                                                      
                                                  





                                                                      
 






                                                                              
 
                                                                        
 
                        
 


                                                             
 
                                         
                                      
 
                                       
         
 
                              
 

                                                                   
                                 

                                                                      

                              



                                                                  
 
                                                               

                                                    

                                                      
                                                        
 
                                                     


                                                              
                                                                     
                                          
 
                                                                                         
                                  
 
                


                                                        
 
                                                             
 
                                         

                                                        

                                 
 
                                                                   
                                                                       
                                   
                                         
 
                                                              
                                                                        
                                                       

                                         
 
                                                          
                                          
                                                               
 
                                                                     
 
                                                           
                                                                      
                                                                   
                                                                               
                                                                                                          
 
                                          
                                                            

                                                                     

                                                                            
                                                        
                                                                        
                                               
                                 
                                                 
                                                                                                          
 

                                                                   
                                                                     
                                             

                                                                
                                                                     
                                    
 
                                                       
 
                                                                             
 
                                              
                                                     


                                                                       
 
                                                                    

                                                                        
 
                                  
                                                     
                                                      




                                                                          
                                                      

                                                         
                                                      


                                                                            
 


                                                    
                                  
 


                                                           
                                       
                              
         
 
                              
 

                                                                           
                                                   
                                                                           


                                                                
 
                                                                                              
                                               

                                                                        
                                                                        
                                   
                                                          
                                               
                                                                   
 
                                                           
                                                     
                                                                   
                                                  
                                                                                                          
 
                                          
                                                            

                                                                     
                                                                                          
                                                           
                                                 
                                                                                                          
 

                                                                    
                                                            
                                             

                                                                
                                                                     
 
                                    
 

                                                                             
 


                                                                       
 

                                                                        
 

                                                     
                                                      




                                                                          
                                                      

                                                         
                                                      


                                                                            
 

                                                    
                                  
                                                  
                                                 
 


                                                           
         
 
                                    

                           
                                                  
 
                                                                              
 
                                                                                  
 
                           
 



                    
                                                                     


                                       
                                                                 



                                                                 
                                                               
                                                  
                                                       




                                   
           




                                                  

                                       
                                 

                                                                        
                                                                                 

                                                                     
                                                  
                                                        
                                                       
                                                            







                                                                               

                                       
                                                 
                      


                                              




                      
                                   
           
                                              


                                       

                                                                                   
                                          
 
                                                                                    
 
                                







                                                 


                       

                                  
 
                                               




                                                                    
                                              
                                                    
                 
 
                                                                          
         
 

                                                                      
 
                                              
                                                            
                                    
                                                                      
            

                                                                    
 
                                                          
                                   

                                                                         
         
 
                              






                                                                                       



                                         

                                       

                                     
                                    
 


                                                                 
                      
                                               
                                       
         
                                                    

                                                    


                            
                                                                                    
                                                                                   
                                        
 

                                                                                            
                                                 

                                         
                                                          
                                                        
                                         

                                                                                 
         
 
                              
 
                                          
 


                      

                                                                            


                                                                          
                      
                                                                         

                                                                        


                                                                             




                                                                                





                                                          
                             
                     



                                
                               

  

                                                     




                                                           


                                                     
 
                            
               
                                   
 

                                                     
                                         

                                                            
                                                
                                                   
                             
                                                              
                                                       

                                                                                   
                                                


                                                                                          
                 
 
                                                                      




                              
                                                     
 



                                  
                                                     
 
               

                                       

                                              

                                                          
                                  

 





                                               

  
               



                                                             
 
                   
                                                        


                                                
                                                         
                                 
                                     

                                     
                                
 
                                            


                                                                    


                                        

                    


           
                                                                       
 
                                      
                                       
 

                                                                       
                    
                                              
                                     
                                                      
                                                 
                                                             
                
                                       


         

                                                                            
 
                                  



                                
 
                                       
                                                                                   
                                                                           
                 
                                        
         
 
                                                                
                                        
 
                                           
                                                 
                                        
 
                                         
 
                                                                            
                             
                                          
                                                                   
                           

                                                     
 
                                     
                                  
                                         
                                                   





                                                         


                                                             
                                         
                                                                 




                                                         

                                 
                                        
                                                                      
                                                                
                              
                        
                              
                 
                                  
         
 
                                

 











                                                            
                   
                          
                              

                                                




                               
                            


                                       
                                                                       

                                        
 



                                                                        
                                                                      
         



                    
           
                                                                      
 

                                                                                       
                                        

                               
                                                   

                                     

 
           
                                                
 

                                               
                             

                                                   

 
           
                                             
 
                           

                                      



                                                                                        



                                             
                                                   



                                           
                                                                                            


           


                                          


                                
                                          
                           
                                               



                                                         


           
                                                                      


                                                                                       
                                        
 
                                   

 
           
                           



                                
                                
 
                                        

                       


                                                                                                                        
                                         


                                                            




                                                                       
                                          
                                           
                                            
                                                                 
                                            
         


                                      

 

                                                                     
    
                                             
 

                                     
                               
                        

                      
                                                       
 


                        
                                         
                                                                 
 

                                                       

                                          
                                                          





                                                         
 
                                                            

                                        
                                    

                                                        
 
                                                  
                                                          
 






                                                                                                       



                                                

 

                                                           
    


                                          
 
                                
                                
                                  
                         
 

                                                       
                           
                                                                     
                       
         
 
                                                                      
 
                                      
                                                        


                                                                
 
                                          
                          
                                               

                                  
                                   
                                              
                                                   
                                   

                                  
                             
 
                          
                                            

                                                     
                                                
 
                                                            
 
                             
                          
                                 

                                                 




                                                 


                                                     
                                                                                    
                                 
                                      





                                                 

                         
                                
                                      

                                                        
                      
                
                                       
         
 

    
                                 
 
                                  
                                   


                                
 
                                               
                                          
                       
 
                                  
                                                                
                           
                              


                                                                            
 
                                                                             
 




                                                                           
 

                                          
                                               

                                  
                                              
                                     
                                 
                                   


                                  
 
                                                
 
                                                                          
 
                                             
                                                                            







                                         
 
/*
 * 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/>
 *
 *
 * Authors:
 *      Michael Zucchi <NotZed@ximian.com>
 *
 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 *
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdio.h>
#include <string.h>

#include <glib/gi18n.h>

#include "libedataserver/e-account-list.h"

#include "shell/e-shell.h"
#include "e-util/e-account-utils.h"
#include "e-util/gconf-bridge.h"

#include "e-mail-local.h"
#include "e-mail-session.h"
#include "em-event.h"
#include "em-filter-rule.h"
#include "mail-folder-cache.h"
#include "mail-mt.h"
#include "mail-ops.h"
#include "mail-send-recv.h"
#include "mail-tools.h"

#define d(x)

/* ms between status updates to the gui */
#define STATUS_TIMEOUT (250)

/* pseudo-uri to key the send task on */
#define SEND_URI_KEY "send-task:"

/* Prefix for window size GConf keys */
#define GCONF_KEY_PREFIX "/apps/evolution/mail/send_recv"

/* send/receive email */

/* ********************************************************************** */
/*  This stuff below is independent of the stuff above */

/* this stuff is used to keep track of which folders filters have accessed, and
   what not. the thaw/refreeze thing doesn't really seem to work though */
struct _folder_info {
    gchar *uri;
    CamelFolder *folder;
    time_t update;
    gint count;     /* how many times updated, to slow it down as we go, if we have lots */
};

struct _send_data {
    GList *infos;

    GtkDialog *gd;
    gint cancelled;

    CamelFolder *inbox; /* since we're never asked to update this one, do it ourselves */
    time_t inbox_update;

    GMutex *lock;
    GHashTable *folders;

    GHashTable *active; /* send_info's by uri */
};

typedef enum {
    SEND_RECEIVE,       /* receiver */
    SEND_SEND,      /* sender */
    SEND_UPDATE,        /* imap-like 'just update folder info' */
    SEND_INVALID
} send_info_t;

typedef enum {
    SEND_ACTIVE,
    SEND_CANCELLED,
    SEND_COMPLETE
} send_state_t;

struct _send_info {
    send_info_t type;       /* 0 = fetch, 1 = send */
    EMailSession *session;
    GCancellable *cancellable;
    gchar *uri;
    gboolean keep_on_server;
    send_state_t state;
    GtkWidget *progress_bar;
    GtkWidget *cancel_button;
    GtkWidget *status_label;

    gint again;     /* need to run send again */

    gint timeout_id;
    gchar *what;
    gint pc;

    GtkWidget *send_account_label;
    gchar *send_url;

    /*time_t update;*/
    struct _send_data *data;
};

static CamelFolder *
        receive_get_folder      (CamelFilterDriver *d,
                         const gchar *uri,
                         gpointer data,
                         GError **error);

static struct _send_data *send_data = NULL;
static GtkWidget *send_recv_dialog = NULL;

static void
free_folder_info (struct _folder_info *info)
{
    /*camel_folder_thaw (info->folder); */
    mail_sync_folder (info->folder, NULL, NULL);
    g_object_unref (info->folder);
    g_free (info->uri);
    g_free (info);
}

static void
free_send_info (struct _send_info *info)
{
    if (info->session)
        g_object_unref (info->session);
    if (info->cancellable)
        g_object_unref (info->cancellable);
    g_free (info->uri);
    if (info->timeout_id != 0)
        g_source_remove (info->timeout_id);
    g_free (info->what);
    g_free (info->send_url);
    g_free (info);
}

static struct _send_data *
setup_send_data (void)
{
    struct _send_data *data;

    if (send_data == NULL) {
        send_data = data = g_malloc0 (sizeof (*data));
        data->lock = g_mutex_new ();
        data->folders = g_hash_table_new_full (
            g_str_hash, g_str_equal,
            (GDestroyNotify) NULL,
            (GDestroyNotify) free_folder_info);
        data->inbox = e_mail_local_get_folder (
            E_MAIL_LOCAL_FOLDER_LOCAL_INBOX);
        g_object_ref (data->inbox);
        data->active = g_hash_table_new_full (
            g_str_hash, g_str_equal,
            (GDestroyNotify) NULL,
            (GDestroyNotify) free_send_info);
    }
    return send_data;
}

static void
receive_cancel (GtkButton *button, struct _send_info *info)
{
    if (info->state == SEND_ACTIVE) {
        camel_operation_cancel (CAMEL_OPERATION (info->cancellable));
        if (info->status_label)
            gtk_label_set_text (
                GTK_LABEL (info->status_label),
                _("Canceling..."));
        info->state = SEND_CANCELLED;
    }
    if (info->cancel_button)
        gtk_widget_set_sensitive (info->cancel_button, FALSE);
}

static void
free_send_data (void)
{
    struct _send_data *data = send_data;

    g_return_if_fail (g_hash_table_size (data->active) == 0);

    if (data->inbox) {
        mail_sync_folder (data->inbox, NULL, NULL);
        /*camel_folder_thaw (data->inbox);      */
        g_object_unref (data->inbox);
    }

    g_list_free (data->infos);
    g_hash_table_destroy (data->active);
    g_hash_table_destroy (data->folders);
    g_mutex_free (data->lock);
    g_free (data);
    send_data = NULL;
}

static void
cancel_send_info (gpointer key, struct _send_info *info, gpointer data)
{
    receive_cancel (GTK_BUTTON (info->cancel_button), info);
}

static void
hide_send_info (gpointer key, struct _send_info *info, gpointer data)
{
    info->cancel_button = NULL;
    info->progress_bar = NULL;
    info->status_label = NULL;

    if (info->timeout_id != 0) {
        g_source_remove (info->timeout_id);
        info->timeout_id = 0;
    }
}

static void
dialog_destroy_cb (struct _send_data *data, GObject *deadbeef)
{
    g_hash_table_foreach (data->active, (GHFunc) hide_send_info, NULL);
    data->gd = NULL;
    send_recv_dialog = NULL;
}

static void
dialog_response (GtkDialog *gd, gint button, struct _send_data *data)
{
    switch (button) {
    case GTK_RESPONSE_CANCEL:
        d(printf("cancelled whole thing\n"));
        if (!data->cancelled) {
            data->cancelled = TRUE;
            g_hash_table_foreach (data->active, (GHFunc)cancel_send_info, NULL);
        }
        gtk_dialog_set_response_sensitive (gd, GTK_RESPONSE_CANCEL, FALSE);
        break;
    default:
        d(printf("hiding dialog\n"));
        g_hash_table_foreach (data->active, (GHFunc)hide_send_info, NULL);
        data->gd = NULL;
        /*gtk_widget_destroy((GtkWidget *)gd);*/
        break;
    }
}

static GStaticMutex status_lock = G_STATIC_MUTEX_INIT;
static gchar *format_url (const gchar *internal_url, const gchar *account_name);

static gint
operation_status_timeout (gpointer data)
{
    struct _send_info *info = data;

    if (info->progress_bar) {
        g_static_mutex_lock (&status_lock);

        gtk_progress_bar_set_fraction (
            GTK_PROGRESS_BAR (info->progress_bar),
            info->pc / 100.0);
        if (info->what)
            gtk_label_set_text (
                GTK_LABEL (info->status_label),
                info->what);
        if (info->send_url && info->send_account_label) {
            gchar *tmp = format_url (info->send_url, NULL);

            g_free (info->send_url);
            info->send_url = NULL;

            gtk_label_set_markup (
                GTK_LABEL (info->send_account_label),
                tmp);

            g_free (tmp);
        }

        g_static_mutex_unlock (&status_lock);

        return TRUE;
    }

    return FALSE;
}

static void
set_send_status (struct _send_info *info, const gchar *desc, gint pc)
{
    g_static_mutex_lock (&status_lock);

    g_free (info->what);
    info->what = g_strdup (desc);
    info->pc = pc;

    g_static_mutex_unlock (&status_lock);
}

static void
set_send_account (struct _send_info *info, const gchar *account_url)
{
    g_static_mutex_lock (&status_lock);

    g_free (info->send_url);
    info->send_url = g_strdup (account_url);

    g_static_mutex_unlock (&status_lock);
}

/* for camel operation status */
static void
operation_status (CamelOperation *op,
                  const gchar *what,
                  gint pc,
                  struct _send_info *info)
{
    set_send_status (info, what, pc);
}

static gchar *
format_url (const gchar *internal_url, const gchar *account_name)
{
    CamelURL *url;
    gchar *pretty_url = NULL;

    url = camel_url_new (internal_url, NULL);

    if (account_name) {
        if (url->host && *url->host)
            pretty_url = g_strdup_printf (
                "<b>%s (%s)</b>: %s",
                account_name, url->protocol, url->host);
        else if (url->path)
            pretty_url = g_strdup_printf (
                "<b>%s (%s)</b>: %s",
                account_name, url->protocol, url->path);
        else
            pretty_url = g_strdup_printf (
                "<b>%s (%s)</b>",
                account_name, url->protocol);

    } else if (url) {
        if (url->host && *url->host)
            pretty_url = g_strdup_printf (
                "<b>%s</b>: %s",
                url->protocol, url->host);
        else if (url->path)
            pretty_url = g_strdup_printf (
                "<b>%s</b>: %s",
                url->protocol, url->path);
        else
            pretty_url = g_strdup_printf (
                "<b>%s</b>", url->protocol);
    }

    if (url)
        camel_url_free (url);

    return pretty_url;
}

static send_info_t
get_receive_type (const gchar *url)
{
    CamelProvider *provider;

    /* HACK: since mbox is ALSO used for native evolution trees now, we need to
       fudge this to treat it as a special 'movemail' source */
    if (!strncmp(url, "maildir:", 5))
        return SEND_RECEIVE;

    provider = camel_provider_get (url, NULL);

    if (!provider)
        return SEND_INVALID;

    if (provider->object_types[CAMEL_PROVIDER_STORE]) {
        if (provider->flags & CAMEL_PROVIDER_IS_STORAGE)
            return SEND_UPDATE;
        else
            return SEND_RECEIVE;
    } else if (provider->object_types[CAMEL_PROVIDER_TRANSPORT]) {
        return SEND_SEND;
    }

    return SEND_INVALID;
}

static struct _send_data *
build_dialog (GtkWindow *parent,
              EMailSession *session,
              EAccountList *accounts,
              CamelFolder *outbox,
              const gchar *destination,
          gboolean allow_send)
{
    GtkDialog *gd;
    GtkWidget *table;
    gint row, num_sources;
    GList *list = NULL;
    struct _send_data *data;
    GtkWidget *container;
        GtkWidget *send_icon;
    GtkWidget *recv_icon;
    GtkWidget *scrolled_window;
    GtkWidget *label;
    GtkWidget *status_label;
    GtkWidget *progress_bar;
    GtkWidget *cancel_button;
    struct _send_info *info;
    gchar *pretty_url;
    EAccount *account;
    EIterator *iter;
    EMEventTargetSendReceive *target;

    send_recv_dialog = gtk_dialog_new_with_buttons (
        _("Send & Receive Mail"), parent,
        GTK_DIALOG_NO_SEPARATOR, NULL);
    gd = GTK_DIALOG (send_recv_dialog);
    gtk_window_set_modal ((GtkWindow *) gd, FALSE);

    gconf_bridge_bind_window_size (
        gconf_bridge_get (), GCONF_KEY_PREFIX,
        GTK_WINDOW (send_recv_dialog));

    gtk_widget_ensure_style ((GtkWidget *)gd);

    container = gtk_dialog_get_action_area (gd);
    gtk_container_set_border_width (GTK_CONTAINER (container), 6);

    container = gtk_dialog_get_content_area (gd);
    gtk_container_set_border_width (GTK_CONTAINER (container), 0);

    cancel_button = gtk_button_new_with_mnemonic (_("Cancel _All"));
    gtk_button_set_image (
        GTK_BUTTON (cancel_button),
        gtk_image_new_from_stock (
            GTK_STOCK_CANCEL, GTK_ICON_SIZE_BUTTON));
    gtk_widget_show (cancel_button);
    gtk_dialog_add_action_widget (gd, cancel_button, GTK_RESPONSE_CANCEL);

    gtk_window_set_icon_name (GTK_WINDOW (gd), "mail-send-receive");

    num_sources = 0;

    iter = e_list_get_iterator ((EList *) accounts);
    while (e_iterator_is_valid (iter)) {
        account = (EAccount *) e_iterator_get (iter);

        if (account->source->url)
            num_sources++;

        e_iterator_next (iter);
    }

    g_object_unref (iter);

    /* Check to see if we have to send any mails.
     * If we don't, don't display the SMTP row in the table. */
    if (outbox && destination
     && (camel_folder_get_message_count (outbox) -
        camel_folder_get_deleted_message_count (outbox)) == 0)
        num_sources--;

    table = gtk_table_new (num_sources, 4, FALSE);
    gtk_container_set_border_width (GTK_CONTAINER (table), 6);
    gtk_table_set_row_spacings (GTK_TABLE (table), 6);
    gtk_table_set_col_spacings (GTK_TABLE (table), 6);

    scrolled_window = gtk_scrolled_window_new (NULL, NULL);
    gtk_container_set_border_width (
        GTK_CONTAINER (scrolled_window), 6);
    gtk_scrolled_window_set_policy (
        GTK_SCROLLED_WINDOW (scrolled_window),
        GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);

    container = gtk_dialog_get_content_area (gd);
    gtk_scrolled_window_add_with_viewport (
        GTK_SCROLLED_WINDOW (scrolled_window), table);
    gtk_box_pack_start (
        GTK_BOX (container), scrolled_window, TRUE, TRUE, 0);
    gtk_widget_show (scrolled_window);

    /* must bet setup after send_recv_dialog as it may re-trigger send-recv button */
    data = setup_send_data ();

    row = 0;
    iter = e_list_get_iterator ((EList *) accounts);
    while (e_iterator_is_valid (iter)) {
        EAccountService *source;

        account = (EAccount *) e_iterator_get (iter);

        source = account->source;
        if (!account->enabled || !source->url) {
            e_iterator_next (iter);
            continue;
        }

        /* see if we have an outstanding download active */
        info = g_hash_table_lookup (data->active, source->url);
        if (info == NULL) {
            send_info_t type;

            type = get_receive_type (source->url);
            if (type == SEND_INVALID || type == SEND_SEND) {
                e_iterator_next (iter);
                continue;
            }

            info = g_malloc0 (sizeof (*info));
            info->type = type;
            info->session = g_object_ref (session);

            d(printf("adding source %s\n", source->url));

            info->uri = g_strdup (source->url);
            info->keep_on_server = source->keep_on_server;
            info->cancellable = camel_operation_new ();
            info->state = allow_send ? SEND_ACTIVE : SEND_COMPLETE;
            info->timeout_id = g_timeout_add (STATUS_TIMEOUT, operation_status_timeout, info);

            g_signal_connect (
                info->cancellable, "status",
                G_CALLBACK (operation_status), info);

            g_hash_table_insert (data->active, info->uri, info);
            list = g_list_prepend (list, info);
        } else if (info->progress_bar != NULL) {
            /* incase we get the same source pop up again */
            e_iterator_next (iter);
            continue;
        } else if (info->timeout_id == 0)
            info->timeout_id = g_timeout_add (STATUS_TIMEOUT, operation_status_timeout, info);

        recv_icon = gtk_image_new_from_icon_name (
            "mail-inbox", GTK_ICON_SIZE_LARGE_TOOLBAR);
        pretty_url = format_url (source->url, account->name);
        label = gtk_label_new (NULL);
        gtk_label_set_ellipsize (
            GTK_LABEL (label), PANGO_ELLIPSIZE_END);
        gtk_label_set_markup (GTK_LABEL (label), pretty_url);
        g_free (pretty_url);

        progress_bar = gtk_progress_bar_new ();

        cancel_button = gtk_button_new_from_stock (GTK_STOCK_CANCEL);

        status_label = gtk_label_new (
            (info->type == SEND_UPDATE) ?
            _("Updating...") : _("Waiting..."));
        gtk_label_set_ellipsize (
            GTK_LABEL (status_label), PANGO_ELLIPSIZE_END);

        /* g_object_set(data->label, "bold", TRUE, NULL); */
        gtk_misc_set_alignment (GTK_MISC (label), 0, .5);
        gtk_misc_set_alignment (GTK_MISC (status_label), 0, .5);

        gtk_table_attach (
            GTK_TABLE (table), recv_icon,
            0, 1, row, row+2, 0, 0, 0, 0);
        gtk_table_attach (
            GTK_TABLE (table), label,
            1, 2, row, row+1, GTK_EXPAND | GTK_FILL, 0, 0, 0);
        gtk_table_attach (
            GTK_TABLE (table), progress_bar,
            2, 3, row, row+2, 0, 0, 0, 0);
        gtk_table_attach (
            GTK_TABLE (table), cancel_button,
            3, 4, row, row+2, 0, 0, 0, 0);
        gtk_table_attach (
            GTK_TABLE (table), status_label,
            1, 2, row+1, row+2, GTK_EXPAND | GTK_FILL, 0, 0, 0);

        info->progress_bar = progress_bar;
        info->status_label = status_label;
        info->cancel_button = cancel_button;
        info->data = data;

        g_signal_connect (
            cancel_button, "clicked",
            G_CALLBACK (receive_cancel), info);
        e_iterator_next (iter);
        row = row + 2;
    }

    g_object_unref (iter);

    /* we also need gd during emition to be able to catch Cancel All */
    data->gd = gd;
    target = em_event_target_new_send_receive (
        em_event_peek (), table, data, row, EM_EVENT_SEND_RECEIVE);
    e_event_emit (
        (EEvent *) em_event_peek (), "mail.sendreceive",
        (EEventTarget *) target);

    /* Skip displaying the SMTP row if we've got no outbox, destination or unsent mails */
    if (allow_send && outbox && destination
     && (camel_folder_get_message_count (outbox) -
        camel_folder_get_deleted_message_count (outbox)) != 0) {
        info = g_hash_table_lookup (data->active, SEND_URI_KEY);
        if (info == NULL) {
            info = g_malloc0 (sizeof (*info));
            info->type = SEND_SEND;
            d(printf("adding dest %s\n", destination));

            info->uri = g_strdup (destination);
            info->keep_on_server = FALSE;
            info->cancellable = camel_operation_new ();
            info->state = SEND_ACTIVE;
            info->timeout_id = g_timeout_add (STATUS_TIMEOUT, operation_status_timeout, info);

            g_signal_connect (
                info->cancellable, "status",
                G_CALLBACK (operation_status), info);

            g_hash_table_insert (data->active, (gpointer) SEND_URI_KEY, info);
            list = g_list_prepend (list, info);
        } else if (info->timeout_id == 0)
            info->timeout_id = g_timeout_add (STATUS_TIMEOUT, operation_status_timeout, info);

        send_icon = gtk_image_new_from_icon_name (
            "mail-outbox", GTK_ICON_SIZE_LARGE_TOOLBAR);
        pretty_url = format_url (destination, NULL);
        label = gtk_label_new (NULL);
        gtk_label_set_ellipsize (
            GTK_LABEL (label), PANGO_ELLIPSIZE_END);
        gtk_label_set_markup (GTK_LABEL (label), pretty_url);

        g_free (pretty_url);

        progress_bar = gtk_progress_bar_new ();
        cancel_button = gtk_button_new_from_stock (GTK_STOCK_CANCEL);

        status_label = gtk_label_new (_("Waiting..."));
        gtk_label_set_ellipsize (
            GTK_LABEL (status_label), PANGO_ELLIPSIZE_END);

        gtk_misc_set_alignment (GTK_MISC (label), 0, .5);
        gtk_misc_set_alignment (GTK_MISC (status_label), 0, .5);

        gtk_table_attach (
            GTK_TABLE (table), send_icon,
            0, 1, row, row+2, 0, 0, 0, 0);
        gtk_table_attach (
            GTK_TABLE (table), label,
            1, 2, row, row+1, GTK_EXPAND | GTK_FILL, 0, 0, 0);
        gtk_table_attach (
            GTK_TABLE (table), progress_bar,
            2, 3, row, row+2, 0, 0, 0, 0);
        gtk_table_attach (
            GTK_TABLE (table), cancel_button,
            3, 4, row, row+2, 0, 0, 0, 0);
        gtk_table_attach (
            GTK_TABLE (table), status_label,
            1, 2, row+1, row+2, GTK_EXPAND | GTK_FILL, 0, 0, 0);

        info->progress_bar = progress_bar;
        info->cancel_button = cancel_button;
        info->data = data;
        info->status_label = status_label;
        info->send_account_label = label;

        g_signal_connect (
            cancel_button, "clicked",
            G_CALLBACK (receive_cancel), info);
    }

    gtk_widget_show_all (table);

    if (parent != NULL)
        gtk_widget_show (GTK_WIDGET (gd));

    g_signal_connect (gd, "response", G_CALLBACK (dialog_response), data);

    g_object_weak_ref ((GObject *) gd, (GWeakNotify) dialog_destroy_cb, data);

    data->infos = list;

    return data;
}

static void
update_folders (gchar *uri, struct _folder_info *info, gpointer data)
{
    time_t now = *((time_t *)data);

    d(printf("checking update for folder: %s\n", info->uri));

    /* let it flow through to the folders every 10 seconds */
    /* we back off slowly as we progress */
    if (now > info->update+10+info->count*5) {
        d(printf("upating a folder: %s\n", info->uri));
        /*camel_folder_thaw(info->folder);
          camel_folder_freeze (info->folder);*/
        info->update = now;
        info->count++;
    }
}

static void
receive_status (CamelFilterDriver *driver,
                enum camel_filter_status_t status,
                gint pc,
                const gchar *desc,
                gpointer data)
{
    struct _send_info *info = data;
    time_t now = time (NULL);

    /* let it flow through to the folder, every now and then too? */
    g_hash_table_foreach (info->data->folders, (GHFunc)update_folders, &now);

    if (info->data->inbox && now > info->data->inbox_update+20) {
        d(printf("updating inbox too\n"));
        /* this doesn't seem to work right :( */
        /*camel_folder_thaw(info->data->inbox);
          camel_folder_freeze (info->data->inbox);*/
        info->data->inbox_update = now;
    }

    /* we just pile them onto the port, assuming it can handle it.
       We could also have a receiver port and see if they've been processed
       yet, so if this is necessary its not too hard to add */
    /* the mail_gui_port receiver will free everything for us */
    switch (status) {
    case CAMEL_FILTER_STATUS_START:
    case CAMEL_FILTER_STATUS_END:
        set_send_status (info, desc, pc);
        break;
    case CAMEL_FILTER_STATUS_ACTION:
        set_send_account (info, desc);
        break;
    default:
        break;
    }
}

/* when receive/send is complete */
static void
receive_done (const gchar *uri, gpointer data)
{
    struct _send_info *info = data;

    /* if we've been called to run again - run again */
    if (info->type == SEND_SEND && info->state == SEND_ACTIVE && info->again) {
        CamelFolder *local_outbox;

        local_outbox = e_mail_local_get_folder (E_MAIL_LOCAL_FOLDER_OUTBOX);

        info->again = 0;
        mail_send_queue (
            info->session,
            local_outbox, info->uri,
            E_FILTER_SOURCE_OUTGOING,
            info->cancellable,
            receive_get_folder, info,
            receive_status, info,
            receive_done, info);
        return;
    }

    if (info->progress_bar) {
        const gchar *text;

        gtk_progress_bar_set_fraction (
            GTK_PROGRESS_BAR (info->progress_bar), 1.0);

        if (info->state == SEND_CANCELLED)
            text = _("Canceled.");
        else {
            text = _("Complete.");
            info->state = SEND_COMPLETE;
        }

        gtk_label_set_text (GTK_LABEL (info->status_label), text);
    }

    if (info->cancel_button)
        gtk_widget_set_sensitive (info->cancel_button, FALSE);

    /* remove/free this active download */
    d(printf("%s: freeing info %p\n", G_STRFUNC, info));
    if (info->type == SEND_SEND)
        g_hash_table_steal (info->data->active, SEND_URI_KEY);
    else
        g_hash_table_steal (info->data->active, info->uri);
    info->data->infos = g_list_remove (info->data->infos, info);

    if (g_hash_table_size (info->data->active) == 0) {
        if (info->data->gd)
            gtk_widget_destroy ((GtkWidget *)info->data->gd);
        free_send_data ();
    }

    free_send_info (info);
}

/* although we dont do anythign smart here yet, there is no need for this interface to
   be available to anyone else.
   This can also be used to hook into which folders are being updated, and occasionally
   let them refresh */
static CamelFolder *
receive_get_folder (CamelFilterDriver *d,
                    const gchar *uri,
                    gpointer data,
                    GError **error)
{
    struct _send_info *info = data;
    CamelFolder *folder;
    struct _folder_info *oldinfo;
    gpointer oldkey, oldinfoptr;

    g_mutex_lock (info->data->lock);
    oldinfo = g_hash_table_lookup (info->data->folders, uri);
    g_mutex_unlock (info->data->lock);
    if (oldinfo) {
        g_object_ref (oldinfo->folder);
        return oldinfo->folder;
    }
    /* FIXME Not passing a GCancellable here. */
    folder = e_mail_session_uri_to_folder_sync (
        info->session, uri, 0, NULL, error);
    if (!folder)
        return NULL;

    /* we recheck that the folder hasn't snuck in while we were loading it... */
    /* and we assume the newer one is the same, but unref the old one anyway */
    g_mutex_lock (info->data->lock);

    if (g_hash_table_lookup_extended (info->data->folders, uri, &oldkey, &oldinfoptr)) {
        oldinfo = (struct _folder_info *) oldinfoptr;
        g_object_unref (oldinfo->folder);
        oldinfo->folder = folder;
    } else {
        /*camel_folder_freeze (folder);     */
        oldinfo = g_malloc0 (sizeof (*oldinfo));
        oldinfo->folder = folder;
        oldinfo->uri = g_strdup (uri);
        g_hash_table_insert (info->data->folders, oldinfo->uri, oldinfo);
    }

    g_object_ref (folder);

    g_mutex_unlock (info->data->lock);

    return folder;
}

/* ********************************************************************** */

static void
get_folders (CamelStore *store, GPtrArray *folders, CamelFolderInfo *info)
{
    while (info) {
        if (camel_store_can_refresh_folder (store, info, NULL)) {
            CamelURL *url = camel_url_new (info->uri, NULL);

            if (url && (!camel_url_get_param (url, "noselect") ||
                !g_str_equal (camel_url_get_param (
                url, "noselect"), "yes")))
                g_ptr_array_add (folders, g_strdup (info->uri));

            if (url)
                camel_url_free (url);
        }

        get_folders (store, folders, info->child);
        info = info->next;
    }
}

struct _refresh_folders_msg {
    MailMsg base;

    struct _send_info *info;
    GPtrArray *folders;
    CamelStore *store;
    CamelFolderInfo *finfo;
};

static gchar *
refresh_folders_desc (struct _refresh_folders_msg *m)
{
    return g_strdup_printf(_("Checking for new mail"));
}

static void
refresh_folders_exec (struct _refresh_folders_msg *m,
                      GCancellable *cancellable,
                      GError **error)
{
    CamelFolder *folder;
    gint i;
    GError *local_error = NULL;

    get_folders (m->store, m->folders, m->finfo);

    for (i=0;i<m->folders->len;i++) {
        folder = e_mail_session_uri_to_folder_sync (
            m->info->session,
            m->folders->pdata[i], 0,
            cancellable, &local_error);
        if (folder) {
            /* FIXME Not passing a GError here. */
            camel_folder_synchronize_sync (
                folder, FALSE, cancellable, NULL);
            camel_folder_refresh_info_sync (folder, cancellable, NULL);
            g_object_unref (folder);
        } else if (local_error != NULL) {
            g_warning ("Failed to refresh folders: %s", local_error->message);
            g_clear_error (&local_error);
        }

        if (g_cancellable_is_cancelled (m->info->cancellable))
            break;
    }
}

static void
refresh_folders_done (struct _refresh_folders_msg *m)
{
    receive_done("", m->info);
}

static void
refresh_folders_free (struct _refresh_folders_msg *m)
{
    gint i;

    for (i=0;i<m->folders->len;i++)
        g_free (m->folders->pdata[i]);
    g_ptr_array_free (m->folders, TRUE);

    camel_store_free_folder_info (m->store, m->finfo);
    g_object_unref (m->store);
}

static MailMsgInfo refresh_folders_info = {
    sizeof (struct _refresh_folders_msg),
    (MailMsgDescFunc) refresh_folders_desc,
    (MailMsgExecFunc) refresh_folders_exec,
    (MailMsgDoneFunc) refresh_folders_done,
    (MailMsgFreeFunc) refresh_folders_free
};

static gboolean
receive_update_got_folderinfo (MailFolderCache *folder_cache,
                               CamelStore *store,
                               CamelFolderInfo *info,
                               gpointer data)
{
    if (info) {
        GPtrArray *folders = g_ptr_array_new ();
        struct _refresh_folders_msg *m;
        struct _send_info *sinfo = data;

        m = mail_msg_new (&refresh_folders_info);
        m->store = store;
        g_object_ref (store);
        m->folders = folders;
        m->info = sinfo;
        m->finfo = info;

        mail_msg_unordered_push (m);

        /* do not free folder info, we will free it later */
        return FALSE;
    } else {
        receive_done ("", data);
    }

    return TRUE;
}

static void
receive_update_got_store (gchar *uri, CamelStore *store, gpointer data)
{
    MailFolderCache *folder_cache;
    struct _send_info *info = data;

    folder_cache = e_mail_session_get_folder_cache (info->session);

    if (store) {
        mail_folder_cache_note_store (
            folder_cache,
            CAMEL_SESSION (info->session),
            store, info->cancellable,
            receive_update_got_folderinfo, info);
    } else {
        receive_done("", info);
    }
}

static GtkWidget *
send_receive (GtkWindow *parent, EMailSession *session, gboolean allow_send)
{
    CamelFolder *local_outbox;
    struct _send_data *data;
    EAccountList *accounts;
    EAccount *account;
    GList *scan;

    if (send_recv_dialog != NULL) {
        if (parent != NULL && gtk_widget_get_realized (send_recv_dialog)) {
            gtk_window_present (GTK_WINDOW (send_recv_dialog));
        }
        return send_recv_dialog;
    }

    if (!camel_session_get_online (CAMEL_SESSION (session)))
        return send_recv_dialog;

    account = e_get_default_account ();
    if (!account || !account->transport->url)
        return send_recv_dialog;

    accounts = e_get_account_list ();

    local_outbox = e_mail_local_get_folder (E_MAIL_LOCAL_FOLDER_OUTBOX);
    data = build_dialog (
        parent, session, accounts,
        local_outbox, account->transport->url, allow_send);
    scan = data->infos;
    while (scan) {
        struct _send_info *info = scan->data;

        switch (info->type) {
        case SEND_RECEIVE:
            mail_fetch_mail (
                session, info->uri,
                info->keep_on_server,
                E_FILTER_SOURCE_INCOMING,
                info->cancellable,
                receive_get_folder, info,
                receive_status, info,
                receive_done, info);
            break;
        case SEND_SEND:
            /* todo, store the folder in info? */
            mail_send_queue (
                session, local_outbox, info->uri,
                E_FILTER_SOURCE_OUTGOING,
                info->cancellable,
                receive_get_folder, info,
                receive_status, info,
                receive_done, info);
            break;
        case SEND_UPDATE:
            mail_get_store (
                session, info->uri, info->cancellable,
                receive_update_got_store, info);
            break;
        default:
            break;
        }
        scan = scan->next;
    }

    return send_recv_dialog;
}

GtkWidget *
mail_send_receive (GtkWindow *parent, EMailSession *session)
{
    return send_receive (parent, session, TRUE);
}

GtkWidget *
mail_receive (GtkWindow *parent, EMailSession *session)
{
    return send_receive (parent, session, FALSE);
}

struct _auto_data {
    EAccount *account;
    EMailSession *session;
    gint period;        /* in seconds */
    gint timeout_id;
};

static GHashTable *auto_active;

static gboolean
auto_timeout (gpointer data)
{
    struct _auto_data *info = data;

    if (camel_session_get_online (CAMEL_SESSION (info->session))) {
        const gchar *uri;
        gboolean keep_on_server;

        uri = e_account_get_string (
            info->account, E_ACCOUNT_SOURCE_URL);
        keep_on_server = e_account_get_bool (
            info->account, E_ACCOUNT_SOURCE_KEEP_ON_SERVER);
        mail_receive_uri (info->session, uri, keep_on_server);
    }

    return TRUE;
}

static void
auto_account_removed (EAccountList *eal, EAccount *ea, gpointer dummy)
{
    struct _auto_data *info = g_object_get_data((GObject *)ea, "mail-autoreceive");

    g_return_if_fail (info != NULL);

    if (info->timeout_id) {
        g_source_remove (info->timeout_id);
        info->timeout_id = 0;
    }
}

static void
auto_account_finalised (struct _auto_data *info)
{
    if (info->session != NULL)
        g_object_unref (info->session);
    if (info->timeout_id)
        g_source_remove (info->timeout_id);
    g_free (info);
}

static void
auto_account_commit (struct _auto_data *info)
{
    gint period, check;

    check = info->account->enabled
        && e_account_get_bool (info->account, E_ACCOUNT_SOURCE_AUTO_CHECK)
        && e_account_get_string (info->account, E_ACCOUNT_SOURCE_URL);
    period = e_account_get_int (info->account, E_ACCOUNT_SOURCE_AUTO_CHECK_TIME)*60;
    period = MAX (60, period);

    if (info->timeout_id
        && (!check
        || period != info->period)) {
        g_source_remove (info->timeout_id);
        info->timeout_id = 0;
    }
    info->period = period;
    if (check && info->timeout_id == 0)
        info->timeout_id = g_timeout_add_seconds (info->period, auto_timeout, info);
}

static void
auto_account_added (EAccountList *eal,
                    EAccount *ea,
                    EMailSession *session)
{
    struct _auto_data *info;

    info = g_malloc0 (sizeof (*info));
    info->account = ea;
    info->session = g_object_ref (session);
    g_object_set_data_full (
        G_OBJECT (ea), "mail-autoreceive", info,
        (GDestroyNotify) auto_account_finalised);
    auto_account_commit (info);
}

static void
auto_account_changed (EAccountList *eal, EAccount *ea, gpointer dummy)
{
    struct _auto_data *info = g_object_get_data((GObject *)ea, "mail-autoreceive");

    g_return_if_fail (info != NULL);

    auto_account_commit (info);
}

static void
auto_online (EShell *shell)
{
    EIterator *iter;
    EAccountList *accounts;
    struct _auto_data *info;
    gboolean can_update_all;

    if (!e_shell_get_online (shell))
        return;

    can_update_all = e_shell_settings_get_boolean (e_shell_get_shell_settings (shell), "mail-check-on-start")
            && e_shell_settings_get_boolean (e_shell_get_shell_settings (shell), "mail-check-all-on-start");

    accounts = e_get_account_list ();
    for (iter = e_list_get_iterator ((EList *)accounts);
         e_iterator_is_valid (iter);
         e_iterator_next (iter)) {
        EAccount *account = (EAccount *) e_iterator_get (iter);

        if (!account || !account->enabled)
            continue;

        info = g_object_get_data (
            G_OBJECT (account),
            "mail-autoreceive");
        if (info && (info->timeout_id || can_update_all))
            auto_timeout (info);
    }

    if (iter)
        g_object_unref (iter);
}

/* call to setup initial, and after changes are made to the config */
/* FIXME: Need a cleanup funciton for when object is deactivated */
void
mail_autoreceive_init (EMailBackend *backend)
{
    EShellBackend *shell_backend;
    EMailSession *session;
    EAccountList *accounts;
    EIterator *iter;
    EShell *shell;

    g_return_if_fail (E_IS_MAIL_BACKEND (backend));

    if (auto_active)
        return;

    accounts = e_get_account_list ();
    auto_active = g_hash_table_new (g_str_hash, g_str_equal);

    session = e_mail_backend_get_session (backend);

    g_signal_connect (
        accounts, "account-added",
        G_CALLBACK (auto_account_added), session);
    g_signal_connect (
        accounts, "account-removed",
        G_CALLBACK (auto_account_removed), NULL);
    g_signal_connect (
        accounts, "account-changed",
        G_CALLBACK (auto_account_changed), NULL);

    for (iter = e_list_get_iterator ((EList *)accounts);
         e_iterator_is_valid (iter);
         e_iterator_next (iter))
        auto_account_added (
            accounts, (EAccount *)
            e_iterator_get (iter), session);

    shell_backend = E_SHELL_BACKEND (backend);
    shell = e_shell_backend_get_shell (shell_backend);

    if (e_shell_settings_get_boolean (e_shell_get_shell_settings (shell), "mail-check-on-start")) {
        auto_online (shell);

        /* also flush outbox on start */
        if (e_shell_get_online (shell))
            mail_send (session);
    }

    g_signal_connect (
        shell, "notify::online",
        G_CALLBACK (auto_online), NULL);
}

/* We setup the download info's in a hashtable, if we later
 * need to build the gui, we insert them in to add them. */
void
mail_receive_uri (EMailSession *session,
                  const gchar *uri,
                  gboolean keep_on_server)
{
    struct _send_info *info;
    struct _send_data *data;
    CamelFolder *local_outbox;
    send_info_t type;

    data = setup_send_data ();
    info = g_hash_table_lookup (data->active, uri);
    if (info != NULL) {
        d(printf("download of %s still in progress\n", uri));
        return;
    }

    d(printf("starting non-interactive download of '%s'\n", uri));

    type = get_receive_type (uri);
    if (type == SEND_INVALID || type == SEND_SEND) {
        d(printf ("unsupported provider: '%s'\n", uri));
        return;
    }

    info = g_malloc0 (sizeof (*info));
    info->type = type;
    info->session = g_object_ref (session);
    info->progress_bar = NULL;
    info->status_label = NULL;
    info->uri = g_strdup (uri);
    info->keep_on_server = keep_on_server;
    info->cancellable = camel_operation_new ();
    info->cancel_button = NULL;
    info->data = data;
    info->state = SEND_ACTIVE;
    info->timeout_id = 0;

    g_signal_connect (
        info->cancellable, "status",
        G_CALLBACK (operation_status), info);

    d(printf("Adding new info %p\n", info));

    g_hash_table_insert (data->active, info->uri, info);

    switch (info->type) {
    case SEND_RECEIVE:
        mail_fetch_mail (
            info->session, info->uri,
            info->keep_on_server,
            E_FILTER_SOURCE_INCOMING,
            info->cancellable,
            receive_get_folder, info,
            receive_status, info,
            receive_done, info);
        break;
    case SEND_SEND:
        /* todo, store the folder in info? */
        local_outbox = e_mail_local_get_folder (E_MAIL_LOCAL_FOLDER_OUTBOX);
        mail_send_queue (
            info->session,
            local_outbox, info->uri,
            E_FILTER_SOURCE_OUTGOING,
            info->cancellable,
            receive_get_folder, info,
            receive_status, info,
            receive_done, info);
        break;
    case SEND_UPDATE:
        mail_get_store (
            info->session,
            info->uri, info->cancellable,
            receive_update_got_store, info);
        break;
    default:
        g_return_if_reached ();
    }
}

void
mail_send (EMailSession *session)
{
    CamelFolder *local_outbox;
    EAccountService *transport;
    struct _send_info *info;
    struct _send_data *data;
    send_info_t type;

    transport = e_get_default_transport ();
    if (!transport || !transport->url)
        return;

    data = setup_send_data ();
    info = g_hash_table_lookup (data->active, SEND_URI_KEY);
    if (info != NULL) {
        info->again++;
        d(printf("send of %s still in progress\n", transport->url));
        return;
    }

    d(printf("starting non-interactive send of '%s'\n", transport->url));

    type = get_receive_type (transport->url);
    if (type == SEND_INVALID) {
        d(printf ("unsupported provider: '%s'\n", transport->url));
        return;
    }

    info = g_malloc0 (sizeof (*info));
    info->type = SEND_SEND;
    info->session = g_object_ref (session);
    info->progress_bar = NULL;
    info->status_label = NULL;
    info->uri = g_strdup (transport->url);
    info->keep_on_server = FALSE;
    info->cancellable = NULL;
    info->cancel_button = NULL;
    info->data = data;
    info->state = SEND_ACTIVE;
    info->timeout_id = 0;

    d(printf("Adding new info %p\n", info));

    g_hash_table_insert (data->active, (gpointer) SEND_URI_KEY, info);

    /* todo, store the folder in info? */
    local_outbox = e_mail_local_get_folder (E_MAIL_LOCAL_FOLDER_OUTBOX);
    mail_send_queue (
        session,
        local_outbox, info->uri,
        E_FILTER_SOURCE_OUTGOING,
        info->cancellable,
        receive_get_folder, info,
        receive_status, info,
        receive_done, info);
}