aboutsummaryrefslogblamecommitdiffstats
path: root/mail/mail-config.c
blob: 33d94de315934718ad757608625f0945f2211d56 (plain) (tree)
1
2
3
4
5
6
7
8
9
 



                                                                           
            
                                    
                                         
                                   























                                                                      
                        
 

                                






                                                                          
 

               

                                
                               
                         








                              



                                      

  



























                                          

                                     

                                   

  












































                                       
                        
                                    
                       
                                       
                       





















                                                       
                                 
 




                                                                           
                                                    





                                                                                
 

                  


                                                              
                                                           









                                                                    
        





                                                                   




                                                                              





                                                                       
        







                                                                    
        





                                    
                              
        
                                                                
                                       







                                                            
                             





                                                             
        
                                                                          
        
                           

                                         
        




                                                                        












































                                                                           
                                               








                                                                    
                                              






































                                                                                  
 















                                                

           
                                         
 









                             
 




                                                      
 


















                                                  
 


                             


           
                                                   
 
                                                    

 

                            
              
 



                                        



                                 
 
 
           
               


                       












                                                                              




                                            
              
 


                    
                       
                        
 
                        
                                                                                        
                                                         
                     
        
                        

                                                                              

                     
                                           
                                   
                                       
                            

                                                    












                                                             


                                                               

                                   
                     
                                                                           
                                       
                     

                                           
                                   
                                     
                            

                                                  
                


                                                        
                
                                                                      
         

                                   
                  

                                                                           
                     

                                           
                                   
                                     
                            

                                                  



                                                        
 

                                                                

                                   
                       
                                                          


                                                                 
                     
        
                    


                                                                    
                     

                             


           
               
 


                    
                       
 



                                                                         
                     
        
                        



                                                                              
                                           
                                          
                                   
                                       
                            


                                                                             











                                                            
         
                                   

                     



                                                                           
                                               
                                          

                                     
                            


                                                                               


                                                       
         
                                   

                  





                                                                           

                                     
                            


                                                                            


                                                       
         
                                   

                       


                                                                 
                     
        
                    


                                                                    

                     
                             
 
 








                                                                            




                                                           


                      
 



                                                                
 




                                                                             
 
                  


           







                                                                    

                                                                  
 

                              
 
 








                                                                          
                                             
        





                                                                         

                                                                




                                                                  
                                                                          
 

                                                               
                                             
                                                          
 

                                                                    
                                                          
 



                                          
                           
 

                                                   
                    


                                                                  
                              

         

                                                               
                                             
                                                          
 



                                                                            
                                                          




                                                              

                                                               
                                             
                                                          
 



                                                                    
                                                          
 

                                                               
                                                    
                                                        
 



                                                                           
                



                                                              
                                                               

                                                                                

                                     

                                                                
                                             














                                                                             

                                    
 

                    
 


                                                                            
 








                                                                
         
        
                    

 


                                                            
 








                                                         

         
                    

 

                                                  
 


                                          
 

                              
                                   











                                                                                        

                              

                                      


                                               
                                                                                            










                                                                               
        



                       
                                                                              

                      
                           




                                                 

                                    
                                               

                                                                  
                       
         
 







                                                                         
 



                                                                         
                                            

                                                                     
                    

                                                                      
         
 

                                      

                                               





                                                                                            

                                                                          
                        
                                                                        
                                                                                            

                                                                                                           
                 

         




                                  

                                                                   
 
                                       
 



                                                                           
 






                                                                
 




                                                                             
 



                                                                              
 














                                                                                      


               
                                                
 
                         

                              
 
                                          

                                    
                                   

                                                                     
                     
 


                                                                
                                                  


                                                        

                                                                   
                
                            
         
        
                                                
        
       
                                                                        
                                  
 


                     











                                                                         
 






































                                                                                           

                                                        
         


           
                                                                    
 



















                                                                             
 







                                                                          


           







                                                                        



                                           

                                                           




                                                                       




                                                                               

 

                                                                     
 

                                        

                               










                                                                      



                                                                  
                                                                        
 


                                                            
                
                                                                               
 
                                                           


                                                                                      

         
                                                           


                                                                                        

         
                                                           


                                                                                    

         




                                                                 
                                                                   
                                                                  
 




                                                               
                                           












                                                                                               

                                                                         
 
                                                                         




                         




                                                                     
                                                                          



                                                                              





                                                     
                    

 

                                                                             
 
                                          
 
                                                            
 



                                                                            
 
                                               


           

                                                                   
 

                                 

 
           







                                                                  

                                                                
 

                              


                                                             
 
 







                                                           
 

                                                 
                                             


                                                                        
 


                                                                    
 








                                                                             

                                           

















                                                                                     
 





                                                                            
 
                                         
 
                    

 


                                 
 
                                                                      

                        


                                                                     






                                                                          


                                                                      
 
                    

 


                               
 

                                                                  
 
                                                                     

                                      

                                  







                                                                          
 
                    

 


                                       
 

                                                                            
 
                                                                           











                                                                          
 
                    

 

                     







                                                                               
                                                                
 
                                                                  
 
                                                                              


           
                                                                     
 


                                                              

 

                                                                 
 
 






                                                  
 



                                                                               
 




                                                                   
 





                                                                        

                                                                 






                                                           




















                                                                               
 
                                                                     
 

                                
 

                        
 

                   







                                                                              


                                                              
 
                                                                             

 
           
                                                                  
 


                                                                     

 

                                                            
 






                                               
                                 






                                                                            
 





                                                                             
 





                                                                        

                                                                   

                                                                        






                                                         




















                                                                              
 
                                                                    
 
                    
                                       
                             
 

                            
 

                 







                                                                              


                                                              
 

                                                                             
 






                                                                     
 
















                                                                                 
 





                                                                             
 






                                                                        

                                                                        






                                                         




















                                                                              
 
                                                                    
 

                                       
 
                            
 
 
                              
               
                                                                              
 
                                                                       
 
                     


           









                                                                        
                                                                      
 
                                                           
        




















                                                                        

                                                                        


           










                                                                        
 
                                                           
 
                             

                                                                        

 
           
                                                        
 


                                                 

 


                                                            
 



                                  
 


                                                       
 





                                                                       
 
                        
        
                                                               

 

                        
 



                                      
                                            

                                                    
 
                       
                                                     
 



                                                       
 




                                                                       
 



                                                                  
 








                                                                                                


                                                   
 





                                                                 
                                                           

                                                                  
                                               
 




                                                                                                


                                                   
 





                                                              
                                                           

                                                                  
                                              
 




                                                                                                


                                                   
 





                                                                 

                                                                  
                                            
                                              
 
 


                                                                                           
 


                                                                
 
                    

 
                               
           

                                                                 
 
                            
 
 
           
                                                              
 
                               
 

















                                                                                 


           
                                                               
 
                                     
 
















                                                                           
 

                                                                                 


           
                                                                 
 
                        
        
                                

                       








                                                                  
 
                                                                         


           

                                                              
 
                           


           
                                                           
 








                                                                   
                







                                                                                 
 



                                                            
 

                             
 

                                                                          
        









                                                                                 


           
                                                              
 
                        
        
                               
                       

                                                 
 

                                               
 



                                                                 
 
                                                                         


           

                                                           
 
                           


           
                                                        
 
                                
 






                                                                       
 






                                                                                 


           
                                                         
 
                                        
 

                             
 









                                                                            
 

                                                                                 


           
                                                           
 


                               

                       
                                                     
 

                                               
 



                                                                 
 

                                                                         
 



                                                                      
 
                                                                         


           
                                                                   
 


                                                

 
           
                                                      
 
                                                                         

 


                                                                         
 




                           
 
                        
 



                                                                                       
         
 



                                                                                    

         




                                                                                                 
 
                        
 
 






                                  
                                            
                      
 
                       
                                                     
 

                                                                            
 









                                                                  
                                         












                                                                         

         
























                                                                          
                                         





                                                                                                     
 

                                                            

         
































                                                                                  
 

                                                          

         
















































                                                                             
 
 


                        
                       


                      

 

/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/* mail-config.c: Mail configuration dialogs/wizard. */

/* 
 * Authors: 
 *  Dan Winship <danw@helixcode.com>
 *  Jeffrey Stedfast <fejj@helixcode.com>
 *  JP Rosevear <jpr@helixcode.com>
 *
 * Copyright 2000 Helix Code, Inc. (http://www.helixcode.com)
 *
 * This program is free software; you can redistribute it and/or 
 * modify it under the terms of the GNU General Public License as 
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 * USA
 */

#include <config.h>
#include <pwd.h>

#include <gnome.h>
#include <gtkhtml/gtkhtml.h>
#include <glade/glade.h>

#include "e-util/e-html-utils.h"
#include "e-util/e-setup.h"
#include "mail.h"

typedef struct _MailDialogIdentityPage MailDialogIdentityPage;
typedef struct _MailDialogServicePage MailDialogServicePage;

typedef void (*IdentityPageCallback) (MailDialogIdentityPage *, gpointer);
typedef void (*ServicePageCallback) (MailDialogServicePage *, gpointer);

typedef struct 
{
    CamelProvider *provider;
    CamelService *service;
    CamelProviderType type;
    GList *authtypes;
} MailService;

struct _MailDialogIdentityPage
{
    GtkWidget *vbox;
    GtkWidget *name;
    GtkWidget *address;
    GtkWidget *org;
    GtkWidget *sig;
    IdentityPageCallback undonecb;
    gpointer undonedata;
    IdentityPageCallback donecb;
    gpointer donedata;
};

typedef struct
{
    GtkWidget *item;
    GtkWidget *vbox;
    CamelProviderType type;
    gchar *protocol;
    GtkWidget *user;
    gboolean userneed;
    GtkWidget *host;
    gboolean hostneed;
    GtkWidget *path;
    gboolean pathneed;
    GtkWidget *auth_optionmenu;
    GList *auth_items;
    GtkWidget *auth_html;
    GtkWidget *auth_detect;
    gint pnum;
} MailDialogServicePageItem;

struct _MailDialogServicePage
{
    GtkWidget *vbox;
    GtkWidget *optionmenu;
    GList *items;
    GtkWidget *notebook;
    MailDialogServicePageItem *spitem;
    ServicePageCallback changedcb;
    gpointer changeddata;
    ServicePageCallback undonecb;
    gpointer undonedata;
    ServicePageCallback donecb;
    gpointer donedata;
};

typedef struct
{
    GtkWidget *vbox;
    MailDialogServicePage *page;
} MailDialogSourcePage;

typedef struct
{
    GtkWidget *vbox;
    MailDialogServicePage *page;
} MailDialogNewsPage;

typedef struct
{
    GtkWidget *vbox;
    MailDialogServicePage *page;
} MailDialogTransportPage;

typedef struct 
{
    GtkWidget *dialog;
    MailDialogIdentityPage *page;
    MailConfigIdentity *id;
} MailDialogIdentity;

typedef struct
{
    GtkWidget *dialog;
    MailDialogSourcePage *page;
    MailConfigService *source;
} MailDialogSource;

typedef struct
{
    GtkWidget *dialog;
    MailDialogNewsPage *page;
    MailConfigService *source;
} MailDialogNews;

typedef struct
{
    GladeXML *gui;
    GtkWidget *dialog;
    GtkWidget *druid;
    MailDialogIdentityPage *idpage;
    gboolean iddone;
    MailDialogSourcePage *spage;
    gboolean sdone;
    MailDialogTransportPage *tpage;
    gboolean tdone;
} MailDruidDialog;

typedef struct
{
    GladeXML *gui;
    GtkWidget *dialog;
    GtkWidget *notebook;
    GtkWidget *clistIdentities;
    gint idrow;
    gint maxidrow;
    GtkWidget *clistSources;
    gint srow;
    gint maxsrow;
    GtkWidget *clistNewsServers;
    gint nrow;
    gint maxnrow;
    MailDialogTransportPage *page;
    gboolean tpagedone;
    GtkWidget *chkFormat;
} MailDialog;

static const char GCONFPATH[] = "/apps/Evolution/Mail";
static MailConfig *config = NULL;

/* private prototypes - these are ugly, rename some of them? */
static void html_size_req (GtkWidget *widget, GtkRequisition *requisition);
static GtkWidget *html_new (gboolean white);
static void put_html (GtkHTML *html, char *text);
static void error_dialog (GtkWidget *parent_finder, const char *fmt, ...);
static GdkImlibImage *load_image (const char *name);
static void service_page_menuitem_activate (GtkWidget *item, 
                        MailDialogServicePage *page);
static void service_page_item_changed (GtkWidget *item, 
                       MailDialogServicePage *page);
static void service_page_item_auth_activate (GtkWidget *menuitem, 
                         MailDialogServicePageItem *spitem);


/* HTML Helpers */
static void
html_size_req (GtkWidget *widget, GtkRequisition *requisition)
{
     requisition->height = GTK_LAYOUT (widget)->height;
}

/* Returns a GtkHTML which is already inside a GtkScrolledWindow. If
 * @white is TRUE, the GtkScrolledWindow will be inside a GtkFrame.
 */
static GtkWidget *
html_new (gboolean white)
{
    GtkWidget *html, *scrolled, *frame;
    GtkStyle *style;
    
    html = gtk_html_new ();
    GTK_LAYOUT (html)->height = 0;
    gtk_signal_connect (GTK_OBJECT (html), "size_request",
                GTK_SIGNAL_FUNC (html_size_req), NULL);
    gtk_html_set_editable (GTK_HTML (html), FALSE);
    style = gtk_rc_get_style (html);
    if (style) {
        gtk_html_set_default_background_color (GTK_HTML (html),
                               white ? &style->white :
                               &style->bg[0]);
    }
    gtk_widget_set_sensitive (html, FALSE);
    scrolled = gtk_scrolled_window_new (NULL, NULL);
    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
                    GTK_POLICY_NEVER,
                    GTK_POLICY_NEVER);
    gtk_container_add (GTK_CONTAINER (scrolled), html);
    
    if (white) {
        frame = gtk_frame_new (NULL);
        gtk_frame_set_shadow_type (GTK_FRAME (frame),
                       GTK_SHADOW_ETCHED_IN);
        gtk_container_add (GTK_CONTAINER (frame), scrolled);
        gtk_widget_show_all (frame);
    } else
        gtk_widget_show_all (scrolled);
    
    return html;
}

static void
put_html (GtkHTML *html, char *text)
{
    GtkHTMLStream *handle;
    
    text = e_text_to_html (text, E_TEXT_TO_HTML_CONVERT_NL);
    handle = gtk_html_begin (html);
    gtk_html_write (html, handle, "<HTML><BODY>", 12);
    gtk_html_write (html, handle, text, strlen (text));
    gtk_html_write (html, handle, "</BODY></HTML>", 14);
    g_free (text);
    gtk_html_end (html, handle, GTK_HTML_STREAM_OK);
}


/* Standard Dialog Helpers */
static void
error_dialog (GtkWidget *parent_finder, const char *fmt, ...)
{
    GtkWidget *parent, *dialog;
    char *msg;
    va_list ap;
    
    parent = gtk_widget_get_ancestor (parent_finder, GTK_TYPE_WINDOW);
    
    va_start (ap, fmt);
    msg = g_strdup_vprintf (fmt, ap);
    va_end (ap);
    
    dialog = gnome_error_dialog_parented (msg, GTK_WINDOW (parent));
    gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
    g_free (msg);
}

static void
info_dialog (GtkWidget *parent_finder, const char *fmt, ...)
{
    GtkWidget *parent, *dialog;
    char *msg;
    va_list ap;
    
    parent = gtk_widget_get_ancestor (parent_finder, GTK_TYPE_WINDOW);
    
    va_start (ap, fmt);
    msg = g_strdup_vprintf (fmt, ap);
    va_end (ap);
    
    dialog = gnome_ok_dialog_parented (msg, GTK_WINDOW (parent));
    gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
    g_free (msg);
}

/* Provider List */
static GSList *
provider_list_add (GSList *services, CamelProviderType type, 
           CamelProvider *prov)
{
    MailService *mcs;
    CamelService *service;
    CamelException *ex;
    char *url;

    ex = camel_exception_new ();

    url = g_strdup_printf ("%s:", prov->protocol);
    service = camel_session_get_service (session, url, type, ex);
    g_free (url);
    if (!service) {
        camel_exception_free (ex);
        return services;
    }

    mcs = g_new (MailService, 1);
    mcs->provider = prov;
    mcs->service = service;
    mcs->type = type;
    mcs->authtypes = camel_service_query_auth_types (mcs->service, ex);
    camel_exception_free (ex);

    return g_slist_prepend (services, mcs);
}

static void 
provider_list (GSList **sources, GSList **news, GSList **transports)
{
    GList *providers, *p;
    
    /* Fetch list of all providers. */
    providers = camel_session_list_providers (session, TRUE);
    *sources = *transports = *news = NULL;
    for (p = providers; p; p = p->next) {
        CamelProvider *prov = p->data;
        
        if (!strcmp (prov->domain, "news")) {
            if (prov->object_types[CAMEL_PROVIDER_STORE]) {
                *news = provider_list_add (*news,
                               CAMEL_PROVIDER_STORE,
                               prov);
            }
        }
    
        if (strcmp (prov->domain, "mail"))
            continue;
        
        if (prov->object_types[CAMEL_PROVIDER_STORE]) {
            *sources = provider_list_add (*sources,
                              CAMEL_PROVIDER_STORE,
                              prov);
        } else if (prov->object_types[CAMEL_PROVIDER_TRANSPORT]) {
            *transports = provider_list_add (*transports,
                             CAMEL_PROVIDER_TRANSPORT,
                             prov);
        }
    }   
}

/* Utility routines */
static GdkImlibImage *
load_image (const char *name)
{
    char *path;
    GdkImlibImage *image;

    path = g_strdup_printf (EVOLUTION_ICONSDIR "/%s", name);
    image = gdk_imlib_load_image (path);
    g_free (path);

    return image;
}

/* Identity struct */
static MailConfigIdentity *
identity_copy (MailConfigIdentity *id) 
{
    MailConfigIdentity *newid;
    
    g_return_val_if_fail (id, NULL);
    
    newid = g_new0 (MailConfigIdentity, 1);
    newid->name = g_strdup (id->name);
    newid->address = g_strdup (id->address);
    newid->org = g_strdup (id->org);
    newid->sig = g_strdup (id->sig);
    
    return newid;
}

static void
identity_destroy (MailConfigIdentity *id)
{
    if (!id)
        return;
    
    g_free (id->name);
    g_free (id->address);
    g_free (id->org);
    g_free (id->sig);
    
    g_free (id);
}

static void
identity_destroy_each (gpointer item, gpointer data)
{
    identity_destroy ((MailConfigIdentity *)item);
}

/* Source struct */
static MailConfigService *
service_copy (MailConfigService *source) 
{
    MailConfigService *newsource;
    
    g_return_val_if_fail (source, NULL);
    
    newsource = g_new0 (MailConfigService, 1);
    newsource->url = g_strdup (source->url);
    
    return newsource;
}

static void
service_destroy (MailConfigService *source)
{
    if (!source)
        return;

    g_free (source->url);
    
    g_free (source);
}

static void
service_destroy_each (gpointer item, gpointer data)
{
    service_destroy ((MailConfigService *)item);
}

/* Config struct routines */
static void
init_config ()
{
    if (config)
        return;
    
    config = g_new0 (MailConfig, 1);

    config->ids = NULL;
    config->sources = NULL;
    config->transport = NULL;
}

static void
clear_config ()
{
    if (!config)
        return;
    
    if (config->ids) {
        g_slist_foreach (config->ids, identity_destroy_each, NULL);
        g_slist_free (config->ids);
        config->ids = NULL;
    }
    
    if (config->sources) {
        g_slist_foreach (config->sources, service_destroy_each, NULL);
        g_slist_free (config->sources);
        config->sources = NULL;
    }
    
    service_destroy (config->transport);
    config->transport = NULL;
}

static void
read_config ()
{
    gchar *str;
    gint len, i;
    
    init_config ();
    clear_config ();

    /* Configured */
    str = g_strdup_printf ("=%s/config/General=/General/configured", evolution_dir);
    config->configured = gnome_config_get_bool (str);
    g_free (str);
    
    /* Identities */
    str = g_strdup_printf ("=%s/config/Mail=/Identities/", evolution_dir);
    gnome_config_push_prefix (str);
    g_free (str);

    len = gnome_config_get_int ("num");
    for (i = 0; i < len; i++) {
        MailConfigIdentity *id;
        gchar *path;
        
        id = g_new0 (MailConfigIdentity, 1);

        path = g_strdup_printf ("name_%d", i);
        id->name = gnome_config_get_string (path);
        g_free (path);
        path = g_strdup_printf ("address_%d", i);
        id->address = gnome_config_get_string (path);
        g_free (path);
        path = g_strdup_printf ("org_%d", i);
        id->org = gnome_config_get_string (path);
        g_free (path);
        path = g_strdup_printf ("sig_%d", i);
        id->sig = gnome_config_get_string (path);
        g_free (path);

        config->ids = g_slist_append (config->ids, id);
    }
    gnome_config_pop_prefix ();

    /* Sources */
    str = g_strdup_printf ("=%s/config/Mail=/Sources/", evolution_dir);
    gnome_config_push_prefix (str);
    g_free (str);

    len = gnome_config_get_int ("num");
    for (i = 0; i < len; i++) {
        MailConfigService *s;
        gchar *path;
        
        s = g_new0 (MailConfigService, 1);
        
        path = g_strdup_printf ("url_%d", i);
        s->url = gnome_config_get_string (path);
        g_free (path);
        
        config->sources = g_slist_append (config->sources, s);
    }
    gnome_config_pop_prefix ();
    
    /* News */
    str = g_strdup_printf ("=%s/config/News=/Sources/", evolution_dir);
    gnome_config_push_prefix (str);
    g_free (str);

    len = gnome_config_get_int ("num");
    for (i = 0; i < len; i++) {
        MailConfigService *n;
        gchar *path;
        
        n = g_new0 (MailConfigService, 1);

        path = g_strdup_printf ("url_%d", i);
        n->url = gnome_config_get_string (path);
        g_free (path);

        config->news = g_slist_append (config->news, n);
    }
    gnome_config_pop_prefix ();
    
    /* Transport */
    config->transport = g_new0 (MailConfigService, 1);
    str = g_strdup_printf ("=%s/config/Mail=/Transport/url", 
                   evolution_dir);
    config->transport->url = gnome_config_get_string (str);
    g_free (str);
    
    /* Format */
    str = g_strdup_printf ("=%s/config/Mail=/Format/send_html", 
                   evolution_dir);
    config->send_html = gnome_config_get_bool (str);
    g_free (str);
    
    gnome_config_sync ();
}

static void
write_config ()
{
    gchar *str;
    gint len, i;
    
    init_config ();

    /* Configured switch */
    str = g_strdup_printf ("=%s/config/General=/General/configured", 
                   evolution_dir);
    gnome_config_set_bool (str, TRUE);
    g_free (str);
    
    /* Identities */
    str = g_strdup_printf ("=%s/config/Mail=/Identities/", evolution_dir);
    gnome_config_push_prefix (str);
    g_free (str);

    len = g_slist_length (config->ids);
    gnome_config_set_int ("num", len);
    for (i = 0; i < len; i++) {
        MailConfigIdentity *id;
        gchar *path;
        
        id = (MailConfigIdentity *)g_slist_nth_data (config->ids, i);
        
        path = g_strdup_printf ("name_%d", i);
        gnome_config_set_string (path, id->name);
        g_free (path);
        path = g_strdup_printf ("address_%d", i);
        gnome_config_set_string (path, id->address);
        g_free (path);
        path = g_strdup_printf ("org_%d", i);
        gnome_config_set_string (path, id->org);
        g_free (path);
        path = g_strdup_printf ("sig_%d", i);
        gnome_config_set_string (path, id->sig);
        g_free (path);
    }
    gnome_config_pop_prefix ();
    
    /* Sources */
    str = g_strdup_printf ("=%s/config/Mail=/Sources/", evolution_dir);
    gnome_config_push_prefix (str);
    g_free (str);

    len = g_slist_length (config->sources);
    gnome_config_set_int ("num", len);
    for (i=0; i<len; i++) {
        MailConfigService *s;
        gchar *path;
        
        s = (MailConfigService *)g_slist_nth_data (config->sources, i);
        
        path = g_strdup_printf ("url_%d", i);
        gnome_config_set_string (path, s->url);
        g_free (path);
    }
    gnome_config_pop_prefix ();

    /* News */
    str = g_strdup_printf ("=%s/config/News=/Sources/", evolution_dir);
    gnome_config_push_prefix (str);
    g_free (str);

    len = g_slist_length (config->news);
    gnome_config_set_int ("num", len);
    for (i=0; i<len; i++) {
        MailConfigService *n;
        gchar *path;
        
        n = (MailConfigService *)g_slist_nth_data (config->news, i);
        
        path = g_strdup_printf ("url_%d", i);
        gnome_config_set_string (path, n->url);
        g_free (path);
    }
    gnome_config_pop_prefix ();

    /* Transport */
    str = g_strdup_printf ("=%s/config/Mail=/Transport/url", 
                   evolution_dir);
    gnome_config_set_string (str, config->transport->url);
    g_free (str);
    
    /* Format */
    str = g_strdup_printf ("=%s/config/Mail=/Format/send_html", 
                   evolution_dir);
    gnome_config_set_bool (str, config->send_html);
    g_free (str);
    
    gnome_config_sync ();
}

/* Identity Page */
static void
identity_page_changed (GtkWidget *widget, MailDialogIdentityPage *page)
{
    gchar *name, *addr;
    
    name = gtk_editable_get_chars (GTK_EDITABLE (page->name), 0, -1);
    addr = gtk_editable_get_chars (GTK_EDITABLE (page->address), 0, -1);
    
    if (addr && *addr && name && *name && page->donecb)
        page->donecb (page, page->donedata);
    else if (page->undonecb)
        page->undonecb (page, page->undonedata);

    g_free (name);
    g_free (addr);
}

static MailConfigIdentity *
identity_page_extract (MailDialogIdentityPage *page)
{
    MailConfigIdentity *id = g_new0 (MailConfigIdentity, 1);

    id->name = gtk_editable_get_chars (GTK_EDITABLE (page->name), 0, -1);
    id->address = 
        gtk_editable_get_chars (GTK_EDITABLE (page->address), 0, -1);
    id->org = gtk_editable_get_chars (GTK_EDITABLE (page->org), 0, -1);
    id->sig = gtk_editable_get_chars (GTK_EDITABLE (page->sig), 0, -1);

    return id;
}

static void
identity_page_set_undone_cb (MailDialogIdentityPage *page, 
                 IdentityPageCallback cb, gpointer data)
{
    page->undonecb = cb;
    page->undonedata = data;
}

static void
identity_page_set_done_cb (MailDialogIdentityPage *page, 
               IdentityPageCallback cb, gpointer data)
{
    page->donecb = cb;
    page->donedata = data;
}

static MailDialogIdentityPage *
identity_page_new (const MailConfigIdentity *id)
{
    MailDialogIdentityPage *page = g_new0 (MailDialogIdentityPage, 1);
    GtkWidget *html, *table;
    GtkWidget *label, *fentry, *hsep;
    gchar *user = NULL;
    gboolean new = !id;
    
    page->vbox = gtk_vbox_new (FALSE, 5);
    
    html = html_new (FALSE);
    put_html (GTK_HTML (html),
          _("Enter your name and email address to be used in "
            "outgoing mail. You may also, optionally, enter the "
            "name of your organization, and the name of a file "
            "to read your signature from."));
    gtk_box_pack_start (GTK_BOX (page->vbox), html->parent, 
                FALSE, TRUE, 0);

    table = gtk_table_new (5, 2, FALSE);
    gtk_table_set_row_spacings (GTK_TABLE (table), 10);
    gtk_table_set_col_spacings (GTK_TABLE (table), 6);
    gtk_container_set_border_width (GTK_CONTAINER (table), 8);
    gtk_box_pack_start (GTK_BOX (page->vbox), table, FALSE, FALSE, 0);

    label = gtk_label_new (_("Full name:"));
    gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1,
              GTK_FILL, 0, 0, 0);
    gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5);

    page->name = gtk_entry_new ();
    gtk_table_attach (GTK_TABLE (table), page->name, 1, 2, 0, 1,
              GTK_EXPAND | GTK_FILL, 0, 0, 0);

    if (!id || !id->name)
        user = g_get_real_name ();

    if ((id && id->name) || user) {
        char *name;

        if (id && id->name)
            name = g_strdup (id->name);
        else
            name = g_strdup (user);

        gtk_entry_set_text (GTK_ENTRY (page->name), name);
        g_free (name);
    }

    label = gtk_label_new (_("Email address:"));
    gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2,
              GTK_FILL, 0, 0, 0);
    gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5);

    page->address = gtk_entry_new ();
    if (id && id->address)
        gtk_entry_set_text (GTK_ENTRY (page->address), id->address);
    gtk_table_attach (GTK_TABLE (table), page->address, 1, 2, 1, 2,
              GTK_EXPAND | GTK_FILL, 0, 0, 0);

    hsep = gtk_hseparator_new ();
    gtk_table_attach (GTK_TABLE (table), hsep, 0, 2, 2, 3,
              GTK_FILL, 0, 0, 8);

    label = gtk_label_new (_("Organization:"));
    gtk_table_attach (GTK_TABLE (table), label, 0, 1, 3, 4,
              GTK_FILL, 0, 0, 0);
    gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5);

    page->org = gtk_entry_new ();
    if (id && id->org)
        gtk_entry_set_text (GTK_ENTRY (page->org), id->org);
    gtk_table_attach (GTK_TABLE (table), page->org, 1, 2, 3, 4,
              GTK_EXPAND | GTK_FILL, 0, 0, 0);

    label = gtk_label_new (_("Signature file:"));
    gtk_table_attach (GTK_TABLE (table), label, 0, 1, 4, 5,
              GTK_FILL, GTK_FILL, 0, 0);
    gtk_misc_set_alignment (GTK_MISC (label), 1, 0);

    fentry = gnome_file_entry_new (NULL, _("Signature File"));
    page->sig = gnome_file_entry_gtk_entry (GNOME_FILE_ENTRY (fentry));
    if (id && id->sig) {
        gtk_entry_set_text (GTK_ENTRY (page->sig), id->sig);
    } else {
        gchar *default_sig;
        
        default_sig = g_strconcat (g_get_home_dir (), 
                       G_DIR_SEPARATOR_S,
                       ".signature", NULL);
        if (g_file_exists (default_sig))
            gtk_entry_set_text (GTK_ENTRY (page->sig), default_sig);
        g_free (default_sig);
    }
    
    gtk_table_attach (GTK_TABLE (table), fentry, 1, 2, 4, 5,
              GTK_FILL, 0, 0, 0);
    gnome_file_entry_set_default_path (GNOME_FILE_ENTRY (fentry),
                       g_get_home_dir ());
    
    gtk_signal_connect (GTK_OBJECT (page->name), "changed",
                GTK_SIGNAL_FUNC (identity_page_changed), page);
    gtk_signal_connect (GTK_OBJECT (page->address), "changed",
                GTK_SIGNAL_FUNC (identity_page_changed), page);
    if (!new) {
        gtk_signal_connect (GTK_OBJECT (page->org), "changed",
                    GTK_SIGNAL_FUNC (identity_page_changed), 
                    page);
        gtk_signal_connect (GTK_OBJECT (page->sig), "changed",
                    GTK_SIGNAL_FUNC (identity_page_changed), 
                    page);
    }

    gtk_widget_show_all (table);

    return page;
}

/* Service page */
static MailDialogServicePageItem *
service_page_item_by_protocol (MailDialogServicePage *page, gchar *protocol)
{
    MailDialogServicePageItem *spitem;
    gint len, i;
    
    len = g_list_length (page->items);
    for (i = 0; i < len; i++) {
        spitem = (MailDialogServicePageItem *)
            g_list_nth_data (page->items, i);
        if (!g_strcasecmp (spitem->protocol, protocol)) 
            return spitem;
    }
    
    return NULL;
}

static MailDialogServicePageItem *
service_page_item_by_menuitem (MailDialogServicePage *page, 
                   GtkWidget *menuitem)
{
    MailDialogServicePageItem *spitem;
    gint len, i;
    
    len = g_list_length (page->items);
    for (i = 0; i < len; i++) {
        spitem = (MailDialogServicePageItem *)
            g_list_nth_data (page->items, i);
        if (spitem->item == menuitem) 
            return spitem;
    }

    return NULL;
}

static char *
service_page_get_url (MailDialogServicePage *page)
{
    MailDialogServicePageItem *spitem;
    CamelURL *url;
    char *url_str;

    spitem = page->spitem;
    
    url = g_new0 (CamelURL, 1);
    url->protocol = g_strdup (spitem->protocol);

    if (spitem->user)
        url->user = gtk_editable_get_chars (GTK_EDITABLE (spitem->user), 0, -1);
    if (spitem->host)
        url->host = gtk_editable_get_chars (GTK_EDITABLE (spitem->host), 0, -1);
    if (spitem->path) {
        gchar *path;
        path = gtk_editable_get_chars (GTK_EDITABLE (spitem->path),
                           0, -1);
        url->path = g_strdup_printf ("%s%s", url->host ? "/" : "", 
                         path);
        g_free (path);
    }
    
    if (spitem->auth_optionmenu) {
        GtkWidget *menu, *item;
        CamelServiceAuthType *authtype;

        menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (spitem->auth_optionmenu));
        if (menu) {
            item = gtk_menu_get_active (GTK_MENU (menu));
            authtype = gtk_object_get_data (GTK_OBJECT (item),
                            "authtype");
            if (*authtype->authproto)
                url->authmech = g_strdup (authtype->authproto);
        }
    }

    url_str = camel_url_to_string (url, FALSE);
    camel_url_free (url);
    
    return url_str;
}

static void
service_page_set_url (MailDialogServicePage *page, MailConfigService *service)
{
    CamelURL *url;
    CamelException *ex;
    MailDialogServicePageItem *spitem = NULL;
    
    if (!service || !service->url)
        return;
    
    ex = camel_exception_new ();
    
    url = camel_url_new (service->url, ex);
    if (camel_exception_get_id (ex) != CAMEL_EXCEPTION_NONE) {
        camel_exception_free (ex);
        return;
    }

    /* Find the right protocol */
    spitem = service_page_item_by_protocol (page, url->protocol);
    service_page_menuitem_activate (spitem->item, page);
    gtk_option_menu_set_history (GTK_OPTION_MENU (page->optionmenu), 
                     spitem->pnum);
    
    if (spitem->user && url && url->user)
        gtk_entry_set_text (GTK_ENTRY (spitem->user), url->user);

    if (spitem->host && url && url->host)
        gtk_entry_set_text (GTK_ENTRY (spitem->host), url->host);
    
    if (spitem->path && url && url->path) {
        if (url->host && *url->path)
            gtk_entry_set_text (GTK_ENTRY (spitem->path),
                        url->path + 1);
        else
            gtk_entry_set_text (GTK_ENTRY (spitem->path), 
                        url->path);
    }

    /* Set the auth menu */
    if (spitem->auth_optionmenu) {
        GtkWidget *menu, *item;
        CamelServiceAuthType *authtype;
        gint len, i;
        
        menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (spitem->auth_optionmenu));
        len = g_list_length (spitem->auth_items);
        for (i = 0; i < len; i++) {
            item = g_list_nth_data (spitem->auth_items, i);
            authtype = gtk_object_get_data (GTK_OBJECT (item),
                            "authtype");
            
            if ((!url->authmech && !*authtype->authproto) ||
                (url->authmech && !strcmp (authtype->authproto, url->authmech)))
                service_page_item_auth_activate (item, spitem);
                gtk_option_menu_set_history (GTK_OPTION_MENU (spitem->auth_optionmenu), i);
        }
    }

    camel_exception_free (ex);
    camel_url_free (url);
}

static void
service_page_item_auth_activate (GtkWidget *menuitem, 
                 MailDialogServicePageItem *spitem)
{
    CamelServiceAuthType *authtype;

    authtype = gtk_object_get_data (GTK_OBJECT (menuitem), "authtype");
    put_html (GTK_HTML (spitem->auth_html), 
          authtype->description);
}

static void
service_page_item_auth_fill (MailDialogServicePage *page,
                 MailDialogServicePageItem *spitem, 
                 GList *authtypes)
{
    CamelServiceAuthType *authtype;
    GtkWidget *menu, *item, *firstitem = NULL;

    menu = gtk_menu_new ();
    gtk_option_menu_set_menu (GTK_OPTION_MENU (spitem->auth_optionmenu), 
                  menu);
    for (; authtypes; authtypes = authtypes->next) {
        authtype = authtypes->data;

        item = gtk_menu_item_new_with_label (_(authtype->name));
        if (!firstitem)
            firstitem = item;
        spitem->auth_items = g_list_append (spitem->auth_items, item);

        gtk_menu_append (GTK_MENU (menu), item);
        gtk_object_set_data (GTK_OBJECT (item), "authtype", authtype);

        gtk_signal_connect (GTK_OBJECT (item), "activate",
                    GTK_SIGNAL_FUNC (service_page_item_auth_activate),
                    spitem);
        gtk_signal_connect (GTK_OBJECT (item), "activate",
                    GTK_SIGNAL_FUNC (service_page_item_changed),
                    page);
    }
    gtk_widget_show_all (menu);

    gtk_option_menu_set_history (GTK_OPTION_MENU (spitem->auth_optionmenu), 0);
    if (firstitem)
        service_page_item_auth_activate (firstitem, spitem);
}

static gboolean
service_acceptable (MailDialogServicePage *page)
{
    char *url = NULL;
    CamelService *service;
    CamelException *ex;

    url = service_page_get_url (page);

    ex = camel_exception_new ();
    camel_exception_clear (ex);
    service = camel_session_get_service (session, url, 
                         page->spitem->type, ex);
    g_free (url);

    if (camel_exception_get_id (ex) != CAMEL_EXCEPTION_NONE)
        goto error;

    if (camel_service_connect (service, ex)) {
        camel_service_disconnect (service, ex);
        gtk_object_unref (GTK_OBJECT (service));
        camel_exception_free (ex);
        
        info_dialog (page->vbox, "Connection successful!");
        
        return TRUE;
    }
    
    gtk_object_unref (GTK_OBJECT (service));
    
 error:
    error_dialog (page->vbox, camel_exception_get_description (ex));
    camel_exception_free (ex);

    return FALSE;
}

static MailConfigService *
service_page_extract (MailDialogServicePage *page)
{
    MailConfigService *source = g_new0 (MailConfigService, 1);

    source->url = service_page_get_url (page);

    return source;
}

static void
service_page_item_changed (GtkWidget *item, MailDialogServicePage *page) 
{
    MailDialogServicePageItem *spitem;
    char *data;
    gboolean complete = TRUE;

    spitem = page->spitem;

    if (complete && page->changedcb) {
        page->changedcb (page, page->changeddata);
    }
    
    if (spitem->host && spitem->hostneed) {
        data = gtk_editable_get_chars (GTK_EDITABLE (spitem->host), 0, -1);
        if (!data || !*data)
            complete = FALSE;
        g_free (data);
    }

    if (complete) {
        if (spitem->user && spitem->userneed) {
            data = gtk_editable_get_chars (GTK_EDITABLE (spitem->user), 0, -1);
            if (!data || !*data)
                complete = FALSE;
            g_free (data);
        }
    }

    if (complete) {
        if (spitem->path && spitem->pathneed) {
            data = gtk_editable_get_chars (GTK_EDITABLE (spitem->path), 0, -1);
            if (!data || !*data)
                complete = FALSE;
        }
    }

    if (spitem->auth_detect)
        gtk_widget_set_sensitive (spitem->auth_detect, complete);

    if (complete && page->donecb) {
        page->donecb (page, page->donedata);
    } else if (!complete && page->undonecb) {
        page->undonecb (page, page->undonedata);
    }
}

static void
service_page_detect (GtkWidget *button, MailDialogServicePage *page)
{
    MailDialogServicePageItem *spitem;
    char *url = NULL;
    CamelException *ex;
    CamelService *service;
    GList *authtypes;

    spitem = page->spitem;
    url = service_page_get_url (page);

    ex = camel_exception_new ();
    service = camel_session_get_service (session, url, spitem->type, ex);
    g_free (url);
    if (camel_exception_get_id (ex) != CAMEL_EXCEPTION_NONE)
        goto error;

    authtypes = camel_service_query_auth_types (service, ex);
    if (camel_exception_get_id (ex) != CAMEL_EXCEPTION_NONE)
        goto error;

    service_page_item_auth_fill (page, spitem, authtypes);

    camel_exception_free (ex);

    return;

 error:
    error_dialog (button, "Could not detect supported authentication "
              "types:\n%s", camel_exception_get_description (ex));
    camel_exception_free (ex);
}

static void
service_page_item_test (GtkWidget *button, MailDialogServicePage *page) 
{
    service_acceptable (page);
}

static GtkWidget *
service_page_add_elem (MailDialogServicePage *page, GtkWidget *table, 
               int row, const char *label_text)
{
    GtkWidget *label, *entry;

    label = gtk_label_new (label_text);
    gtk_table_attach (GTK_TABLE (table), label, 0, 1, 
              row, row + 1, GTK_FILL, 0, 0, 0);
    gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5);

    entry = gtk_entry_new ();
    gtk_table_attach (GTK_TABLE (table), entry, 1, 3, row, row + 1,
              GTK_EXPAND | GTK_FILL, 0, 0, 0);

    gtk_signal_connect (GTK_OBJECT (entry), "changed",
                GTK_SIGNAL_FUNC (service_page_item_changed), page);

    return entry;
}

static MailDialogServicePageItem *
service_page_item_new (MailDialogServicePage *page, MailService *mcs)
{
    MailDialogServicePageItem *item;
    GtkWidget *table, *description;
    int row, service_flags;

    item = g_new0 (MailDialogServicePageItem, 1);
    
    item->vbox = gtk_vbox_new (FALSE, 0);

    /* Description */
    description = html_new (TRUE);
    put_html (GTK_HTML (description), mcs->provider->description);
    gtk_box_pack_start (GTK_BOX (item->vbox),
                description->parent->parent,
                TRUE, TRUE, 0);
    
    table = gtk_table_new (5, 3, FALSE);
    gtk_table_set_row_spacings (GTK_TABLE (table), 2);
    gtk_table_set_col_spacings (GTK_TABLE (table), 10);
    gtk_container_set_border_width (GTK_CONTAINER (table), 8);
    gtk_box_pack_start (GTK_BOX (item->vbox), table, TRUE, TRUE, 0);

    item->protocol = g_strdup (mcs->provider->protocol);
    item->type = mcs->type;
    
    row = 0;
    service_flags = mcs->service->url_flags & ~CAMEL_SERVICE_URL_NEED_AUTH;

    if (service_flags & CAMEL_SERVICE_URL_ALLOW_HOST) {
        item->host = service_page_add_elem (page, table, row++, _("Server:"));
        item->hostneed = ((service_flags & CAMEL_SERVICE_URL_NEED_HOST)
                  == CAMEL_SERVICE_URL_NEED_HOST);
    }

    if (service_flags & CAMEL_SERVICE_URL_ALLOW_USER) {
        item->user = service_page_add_elem (page, table, row++, _("Username:"));
        item->userneed = ((service_flags & CAMEL_SERVICE_URL_NEED_USER)
                  == CAMEL_SERVICE_URL_NEED_USER);
    }

    if (service_flags & CAMEL_SERVICE_URL_ALLOW_PATH) {
        item->path = service_page_add_elem (page, table, row++, _("Path:"));
        item->pathneed = ((service_flags & CAMEL_SERVICE_URL_NEED_PATH)
                  == CAMEL_SERVICE_URL_NEED_PATH);
    }

    if (mcs->authtypes) {
        GtkWidget *label;

        label = gtk_label_new (_("Authentication:"));
        gtk_table_attach (GTK_TABLE (table), label, 0, 1,
                  row, row + 1, GTK_FILL, 0, 0, 0);
        gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5);

        item->auth_optionmenu = gtk_option_menu_new ();
        gtk_table_attach (GTK_TABLE (table), 
                  item->auth_optionmenu, 
                  1, 2, row, row + 1, 
                  GTK_FILL | GTK_EXPAND,
                  0, 0, 0);

        item->auth_detect = gtk_button_new_with_label (_("Detect supported types..."));
        gtk_table_attach (GTK_TABLE (table), item->auth_detect, 
                  2, 3, row, row + 1, 0, 0, 0, 0);
        gtk_widget_set_sensitive (item->auth_detect, FALSE);
        gtk_signal_connect (GTK_OBJECT (item->auth_detect), 
                    "clicked",
                    GTK_SIGNAL_FUNC (service_page_detect), 
                    page);

        item->auth_html = html_new (TRUE);
        gtk_table_attach (GTK_TABLE (table), 
                  item->auth_html->parent->parent,
                  0, 3, row + 1, row + 2,
                  GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);

        service_page_item_auth_fill (page, item, mcs->authtypes);

        row += 2;
    }

    if (row != 0) {
        GtkWidget *btn;

        btn = gtk_button_new_with_label (_("Test Settings"));

        gtk_table_attach (GTK_TABLE (table), btn, 2, 3,
                  row, row + 1, GTK_FILL, GTK_FILL, 0, 0);

        gtk_signal_connect (GTK_OBJECT (btn), "clicked",
                    GTK_SIGNAL_FUNC (service_page_item_test), 
                    page);
        row += 1;
    }

    gtk_table_resize (GTK_TABLE (table), row, 3);
    gtk_widget_show_all (table);

    return item;
}

static void
service_page_menuitem_activate (GtkWidget *item, MailDialogServicePage *page)
{
    MailDialogServicePageItem *spitem;

    spitem = service_page_item_by_menuitem (page, item);

    g_return_if_fail (spitem);
    
    gtk_notebook_set_page (GTK_NOTEBOOK (page->notebook), spitem->pnum);
    page->spitem = spitem;

    service_page_item_changed (item, page);
}

static void
service_page_set_changed_cb (MailDialogServicePage *page, 
                 ServicePageCallback cb, gpointer data)
{
    page->changedcb = cb;
    page->changeddata = data;
}

static void
service_page_set_undone_cb (MailDialogServicePage *page, 
                ServicePageCallback cb, gpointer data)
{
    page->undonecb = cb;
    page->undonedata = data;
}

static void
service_page_set_done_cb (MailDialogServicePage *page, 
              ServicePageCallback cb, gpointer data)
{
    page->donecb = cb;
    page->donedata = data;

    /* In case its already done */
    service_page_item_changed (page->spitem->item, page);
}

static MailDialogServicePage *
service_page_new (const char *label_text, GSList *services)
{
    MailDialogServicePage *page;
    GtkWidget *hbox, *label, *menu;
    GtkWidget *first_item = NULL;
    int pnum;
    GSList *s;

    page = g_new0 (MailDialogServicePage, 1);
    
    page->vbox = gtk_vbox_new (FALSE, 5);
    
    hbox = gtk_hbox_new (FALSE, 8);
    gtk_box_pack_start (GTK_BOX (page->vbox), hbox, FALSE, TRUE, 0);

    label = gtk_label_new (label_text);
    gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
    gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5);

    page->optionmenu = gtk_option_menu_new ();
    menu = gtk_menu_new ();
    gtk_option_menu_set_menu (GTK_OPTION_MENU (page->optionmenu), menu);
    gtk_box_pack_start (GTK_BOX (hbox), page->optionmenu, TRUE, TRUE, 0);
    
    /* Notebook */
    page->notebook = gtk_notebook_new ();
    gtk_notebook_set_show_tabs (GTK_NOTEBOOK (page->notebook), FALSE);
    gtk_box_pack_start (GTK_BOX (page->vbox), page->notebook, 
                TRUE, TRUE, 0);

    /* Build the list of services and the service item pages */
    for (s = services, pnum = 0; s; s = s->next, pnum++) {
        MailService *mcs = s->data;
        MailDialogServicePageItem *spitem;
        
        spitem = service_page_item_new (page, mcs);
        spitem->pnum = pnum;
        
        gtk_notebook_append_page (GTK_NOTEBOOK (page->notebook), 
                      spitem->vbox, NULL);

        spitem->item = gtk_menu_item_new_with_label (_(mcs->provider->name));
        if (!first_item)
            first_item = spitem->item;

        gtk_signal_connect (GTK_OBJECT (spitem->item), "activate",
                    GTK_SIGNAL_FUNC (service_page_menuitem_activate),
                    page);

        gtk_menu_append (GTK_MENU (menu), spitem->item);
        page->items = g_list_append (page->items, spitem);
    }
    
    service_page_menuitem_activate (first_item, page);
    gtk_option_menu_set_history (GTK_OPTION_MENU (page->optionmenu), 0);

    gtk_widget_show_all (page->vbox);

    return page;
}

/* Source Page */
static MailDialogSourcePage *
source_page_new (GSList *sources)
{
    MailDialogSourcePage *page = g_new0 (MailDialogSourcePage, 1);
    GtkWidget *html;

    page->page = service_page_new ("Mail source type:", sources);
    page->vbox = page->page->vbox;
    
    html = html_new (FALSE);
    put_html (GTK_HTML (html),
          _("Select the kind of mail server you have, and enter "
            "the relevant information about it.\n\nIf the server "
            "requires authentication, you can click the "
            "\"Detect supported types...\" button after entering "
            "the other information."));
    gtk_box_pack_start (GTK_BOX (page->vbox), html->parent, 
                FALSE, TRUE, 0);
    gtk_box_reorder_child (GTK_BOX (page->vbox), html->parent, 0);

    return page;
}

/* News Page */
static MailDialogNewsPage *
news_page_new (GSList *sources)
{
    MailDialogNewsPage *page = g_new0 (MailDialogNewsPage, 1);
    GtkWidget *html;

    page->page = service_page_new ("News source type:", sources);
    page->vbox = page->page->vbox;
    
    html = html_new (FALSE);
    put_html (GTK_HTML (html),
          _("Select the kind of news server you have, and enter "
            "the relevant information about it.\n\nIf the server "
            "requires authentication, you can click the "
            "\"Detect supported types...\" button after entering "
            "the other information."));
    gtk_box_pack_start (GTK_BOX (page->vbox), html->parent, 
                FALSE, TRUE, 0);
    gtk_box_reorder_child (GTK_BOX (page->vbox), html->parent, 0);

    return page;
}

/* Transport page */
static MailDialogTransportPage *
transport_page_new (GSList *transports)
{
    MailDialogTransportPage *page = g_new0 (MailDialogTransportPage, 1);
    GtkWidget *html;

    page->page = service_page_new ("Mail transport type:", transports);
    page->vbox = page->page->vbox;
    
    html = html_new (FALSE);
    put_html (GTK_HTML (html),
          _("Select the kind of mail server you have, and enter "
            "the relevant information about it.\n\nIf the server "
            "requires authentication, you can click the "
            "\"Detect supported types...\" button after entering "
            "the other information."));
    gtk_box_pack_start (GTK_BOX (page->vbox), html->parent, 
                FALSE, TRUE, 0);
    gtk_box_reorder_child (GTK_BOX (page->vbox), html->parent, 0);

    return page;
}

/* Identity dialog */
static void
iddialog_page_undone (MailDialogIdentityPage *page, gpointer data)
{
    MailDialogIdentity *iddialog = (MailDialogIdentity *)data;

    gnome_dialog_set_sensitive (GNOME_DIALOG (iddialog->dialog), 0, FALSE);
}

static void
iddialog_page_done (MailDialogIdentityPage *page, gpointer data)
{
    MailDialogIdentity *iddialog = (MailDialogIdentity *)data;

    gnome_dialog_set_sensitive (GNOME_DIALOG (iddialog->dialog), 0, TRUE);
}

static void
iddialog_ok_clicked (GtkWidget *dialog, MailDialogIdentity *iddialog)
{
    g_return_if_fail (iddialog);
    
    iddialog->id = identity_page_extract (iddialog->page);
}

static MailConfigIdentity *
identity_dialog (const MailConfigIdentity *id, GtkWidget *parent)

{
    MailDialogIdentity *iddialog;
    MailConfigIdentity *returnid;
    GtkWidget *dialog_vbox;
    GtkWidget *area;
    gboolean new = !id;
    
    iddialog = g_new0 (MailDialogIdentity, 1);

    if (new)
        iddialog->dialog = gnome_dialog_new (_("Edit Identity"), NULL);
    else
        iddialog->dialog = gnome_dialog_new (_("Add Identity"), NULL);

    gtk_window_set_modal (GTK_WINDOW (iddialog->dialog), TRUE);
    gtk_window_set_policy (GTK_WINDOW (iddialog->dialog), 
                   TRUE, TRUE, FALSE);
    gnome_dialog_set_parent (GNOME_DIALOG (iddialog->dialog),
                 GTK_WINDOW (parent));

    /* Create the vbox that we will pack the identity widget into */
    dialog_vbox = GNOME_DIALOG (iddialog->dialog)->vbox;
    gtk_widget_show (dialog_vbox);

        /* Get the identity widget */
    iddialog->page = identity_page_new (id);
    gtk_box_pack_start (GTK_BOX (dialog_vbox), 
                iddialog->page->vbox, TRUE, TRUE, 0);

    identity_page_set_undone_cb (iddialog->page, 
                     iddialog_page_undone, 
                     iddialog);
    identity_page_set_done_cb (iddialog->page, 
                   iddialog_page_done, 
                   iddialog);
    gtk_widget_show (iddialog->page->vbox);

    /* Buttons */
    area = GNOME_DIALOG (iddialog->dialog)->action_area;
    gtk_widget_show (area);
    gtk_button_box_set_layout (GTK_BUTTON_BOX (area), GTK_BUTTONBOX_END);
    gtk_button_box_set_spacing (GTK_BUTTON_BOX (area), 8);

    gnome_dialog_append_button (GNOME_DIALOG (iddialog->dialog), 
                    GNOME_STOCK_BUTTON_OK);
    gnome_dialog_append_button (GNOME_DIALOG (iddialog->dialog), 
                    GNOME_STOCK_BUTTON_CANCEL); 

    gnome_dialog_set_default (GNOME_DIALOG (iddialog->dialog), 0);
    gnome_dialog_set_default (GNOME_DIALOG (iddialog->dialog), 1);
    
    gnome_dialog_set_sensitive (GNOME_DIALOG (iddialog->dialog), 0, FALSE);
    
    gnome_dialog_button_connect( GNOME_DIALOG (iddialog->dialog), 0,
                     GTK_SIGNAL_FUNC (iddialog_ok_clicked),
                     iddialog);

    gnome_dialog_run_and_close (GNOME_DIALOG (iddialog->dialog));

    returnid = iddialog->id;
    g_free (iddialog);

    return returnid;
}

/* Source Dialog */
static void
sdialog_page_undone (MailDialogServicePage *page, gpointer data)
{
    MailDialogSource *sdialog = (MailDialogSource *)data;

    gnome_dialog_set_sensitive (GNOME_DIALOG (sdialog->dialog), 0, FALSE);
}

static void
sdialog_page_done (MailDialogServicePage *page, gpointer data)
{
    MailDialogSource *sdialog = (MailDialogSource *)data;

    gnome_dialog_set_sensitive (GNOME_DIALOG (sdialog->dialog), 0, TRUE);
}

static void
sdialog_ok_clicked (GtkWidget *widget, MailDialogSource *sdialog) 
{
    g_return_if_fail (sdialog);
    
    sdialog->source = service_page_extract (sdialog->page->page);
}

static MailConfigService *
source_dialog (MailConfigService *source, GtkWidget *parent)
{
    MailDialogSource *sdialog;
    MailConfigService *returnsource;
    GtkWidget *dialog_vbox, *area;
    GSList *sources, *news, *transports;
    gboolean new = !source;
    
    sdialog = g_new0 (MailDialogSource, 1);
    sdialog->source = source;
    
    provider_list (&sources, &news, &transports);
    
    if (new)
        sdialog->dialog = gnome_dialog_new (_("Edit Source"), NULL);
    else
        sdialog->dialog = gnome_dialog_new (_("Add Source"), NULL);

    gtk_window_set_modal (GTK_WINDOW (sdialog->dialog), TRUE);
    gtk_window_set_policy (GTK_WINDOW (sdialog->dialog), 
                   TRUE, TRUE, FALSE);
    gtk_window_set_default_size (GTK_WINDOW (sdialog->dialog), 380, 450);
    gnome_dialog_set_parent (GNOME_DIALOG (sdialog->dialog),
                 GTK_WINDOW (parent));

    /* Create the vbox that we will pack the identity widget into */
    dialog_vbox = GNOME_DIALOG (sdialog->dialog)->vbox;
    gtk_widget_show (dialog_vbox);

        /* Get the identity widget */
    sdialog->page = source_page_new (sources);
    if (!new)
        service_page_set_url (sdialog->page->page, source);
    gtk_box_pack_start (GTK_BOX (dialog_vbox), sdialog->page->vbox, 
                TRUE, TRUE, 0);

    service_page_set_undone_cb (sdialog->page->page, 
                    sdialog_page_undone, 
                    sdialog);
    service_page_set_done_cb (sdialog->page->page, 
                  sdialog_page_done, 
                  sdialog);
    gtk_widget_show (sdialog->page->vbox);
    
    /* Buttons */
    area = GNOME_DIALOG (sdialog->dialog)->action_area;
    gtk_widget_show (area);
    gtk_button_box_set_layout (GTK_BUTTON_BOX (area), GTK_BUTTONBOX_END);
    gtk_button_box_set_spacing (GTK_BUTTON_BOX (area), 8);

    gnome_dialog_append_button (GNOME_DIALOG (sdialog->dialog), 
                    GNOME_STOCK_BUTTON_OK);
    gnome_dialog_append_button (GNOME_DIALOG (sdialog->dialog), 
                    GNOME_STOCK_BUTTON_CANCEL); 

    gnome_dialog_set_default (GNOME_DIALOG (sdialog->dialog), 0);
    gnome_dialog_set_default (GNOME_DIALOG (sdialog->dialog), 1);
    
    gnome_dialog_set_sensitive (GNOME_DIALOG (sdialog->dialog), 0, FALSE);
    
    gnome_dialog_button_connect(GNOME_DIALOG (sdialog->dialog), 0,
                    GTK_SIGNAL_FUNC (sdialog_ok_clicked),
                    sdialog);

    gnome_dialog_run_and_close (GNOME_DIALOG (sdialog->dialog));

    /* FIXME: */
    returnsource = sdialog->source;
    /*g_free (sdialog);*/

    return returnsource;
}

/* News Dialog */
static void
ndialog_page_undone (MailDialogServicePage *page, gpointer data)
{
    MailDialogNews *ndialog = (MailDialogNews *)data;

    gnome_dialog_set_sensitive (GNOME_DIALOG (ndialog->dialog), 0, FALSE);
}

static void
ndialog_page_done (MailDialogServicePage *page, gpointer data)
{
    MailDialogNews *ndialog = (MailDialogNews *)data;

    gnome_dialog_set_sensitive (GNOME_DIALOG (ndialog->dialog), 0, TRUE);
}

static void
ndialog_ok_clicked (GtkWidget *widget, MailDialogNews *ndialog) 
{
    g_return_if_fail (ndialog);
    
    ndialog->source = service_page_extract (ndialog->page->page);
}

static MailConfigService *
news_dialog (MailConfigService *source, GtkWidget *parent)
{
    MailDialogNews *ndialog;
    MailConfigService *returnsource;
    GtkWidget *dialog_vbox, *area;
    GSList *sources, *news, *transports;
    gboolean new = !source;
    
    ndialog = g_new0 (MailDialogNews, 1);
    
    provider_list (&sources, &news, &transports);
    
    if (new)
        ndialog->dialog = gnome_dialog_new (_("Edit News Server"), NULL);
    else
        ndialog->dialog = gnome_dialog_new (_("Add News Server"), NULL);

    gtk_window_set_modal (GTK_WINDOW (ndialog->dialog), TRUE);
    gtk_window_set_policy (GTK_WINDOW (ndialog->dialog), 
                   TRUE, TRUE, FALSE);
    gtk_window_set_default_size (GTK_WINDOW (ndialog->dialog), 380, 450);
    gnome_dialog_set_parent (GNOME_DIALOG (ndialog->dialog),
                 GTK_WINDOW (parent));

    /* Create the vbox that we will pack the identity widget into */
    dialog_vbox = GNOME_DIALOG (ndialog->dialog)->vbox;
    gtk_widget_show (dialog_vbox);

        /* Get the identity widget */
    ndialog->page = news_page_new (news);
    service_page_set_url (ndialog->page->page, source);
    gtk_box_pack_start (GTK_BOX (dialog_vbox), ndialog->page->vbox, 
                TRUE, TRUE, 0);

    service_page_set_undone_cb (ndialog->page->page, 
                    ndialog_page_undone, 
                    ndialog);
    service_page_set_done_cb (ndialog->page->page, 
                  ndialog_page_done, 
                  ndialog);
    gtk_widget_show (ndialog->page->vbox);
    
    /* Buttons */
    area = GNOME_DIALOG (ndialog->dialog)->action_area;
    gtk_widget_show (area);
    gtk_button_box_set_layout (GTK_BUTTON_BOX (area), GTK_BUTTONBOX_END);
    gtk_button_box_set_spacing (GTK_BUTTON_BOX (area), 8);

    gnome_dialog_append_button (GNOME_DIALOG (ndialog->dialog), 
                    GNOME_STOCK_BUTTON_OK);
    gnome_dialog_append_button (GNOME_DIALOG (ndialog->dialog), 
                    GNOME_STOCK_BUTTON_CANCEL); 

    gnome_dialog_set_default (GNOME_DIALOG (ndialog->dialog), 0);
    gnome_dialog_set_default (GNOME_DIALOG (ndialog->dialog), 1);
    
    gnome_dialog_set_sensitive (GNOME_DIALOG (ndialog->dialog), 0, FALSE);
    
    gnome_dialog_button_connect(GNOME_DIALOG (ndialog->dialog), 0,
                    GTK_SIGNAL_FUNC (ndialog_ok_clicked),
                    ndialog);

    gnome_dialog_run_and_close (GNOME_DIALOG (ndialog->dialog));

    returnsource = ndialog->source;
    g_free (ndialog);

    return returnsource;
}

/* Mail configuration druid */
static gboolean
mail_druid_prepare (GnomeDruidPage *page, GnomeDruid *druid, gboolean *active)
{
    gnome_druid_set_buttons_sensitive (druid, TRUE, *active, TRUE);

    return FALSE;
}

static void
mail_druid_identity_undone (MailDialogIdentityPage *page, gpointer data)
{
    MailDruidDialog *dialog = (MailDruidDialog *) data;
    
    dialog->iddone = FALSE;
    gnome_druid_set_buttons_sensitive (GNOME_DRUID (dialog->druid), 
                       TRUE, FALSE, TRUE);
}

static void
mail_druid_identity_done (MailDialogIdentityPage *page, gpointer data)
{
    MailDruidDialog *dialog = (MailDruidDialog *) data;
    
    dialog->iddone = TRUE;
    gnome_druid_set_buttons_sensitive (GNOME_DRUID (dialog->druid), 
                       TRUE, TRUE, TRUE);
}

static void
mail_druid_source_undone (MailDialogServicePage *page, gpointer data)
{
    MailDruidDialog *dialog = (MailDruidDialog *) data;

    dialog->sdone = FALSE;
    gnome_druid_set_buttons_sensitive (GNOME_DRUID (dialog->druid), 
                       TRUE, FALSE, TRUE);
}

static void
mail_druid_source_done (MailDialogServicePage *page, gpointer data)
{
    MailDruidDialog *dialog = (MailDruidDialog *) data;

    dialog->sdone = TRUE;
    gnome_druid_set_buttons_sensitive (GNOME_DRUID (dialog->druid), 
                       TRUE, TRUE, TRUE);
}

static void
mail_druid_transport_undone (MailDialogServicePage *page, gpointer data)
{
    MailDruidDialog *dialog = (MailDruidDialog *) data;

    dialog->tdone = FALSE;
    gnome_druid_set_buttons_sensitive (GNOME_DRUID (dialog->druid), 
                       TRUE, FALSE, TRUE);
}

static void
mail_druid_transport_done (MailDialogServicePage *page, gpointer data)
{
    MailDruidDialog *dialog = (MailDruidDialog *) data;

    dialog->tdone = TRUE;
    gnome_druid_set_buttons_sensitive (GNOME_DRUID (dialog->druid), 
                       TRUE, TRUE, TRUE);
}

static void
mail_druid_cancel (GnomeDruid *druid, GtkWindow *window)
{
    gtk_window_set_modal (window, FALSE);
    gtk_widget_destroy (GTK_WIDGET (window));
    gtk_main_quit ();
}

static void
mail_druid_finish (GnomeDruidPage *page, GnomeDruid *druid, 
           MailDruidDialog *dialog)
{
    MailConfigIdentity *id;
    MailConfigService *source;
    
    clear_config ();

    /* Identity */
    id = identity_page_extract (dialog->idpage);
    config->ids = g_slist_append (config->ids, id);

    /* Source */
    source = service_page_extract (dialog->spage->page);
    config->sources = g_slist_append (config->sources, source);
    
    /* Transport */
    config->transport = service_page_extract (dialog->tpage->page);

    write_config ();
    
    mail_druid_cancel (druid, GTK_WINDOW (dialog->dialog));
}

void
mail_config_druid (void)
{
    MailDruidDialog *dialog;
    GnomeDruidPageStart *spage;
    GnomeDruidPageFinish *fpage;
    GnomeDruidPageStandard *dpage;
    GSList *sources, *news, *transports;
    GdkImlibImage *mail_logo, *identity_logo;
    GdkImlibImage *source_logo, *transport_logo;

    read_config ();
    provider_list (&sources, &news, &transports);

    mail_logo = load_image ("evolution-inbox.png");
    identity_logo = load_image ("malehead.png");
    source_logo = mail_logo;
    transport_logo = load_image ("envelope.png");

    dialog = g_new0 (MailDruidDialog, 1);
    dialog->gui = glade_xml_new (EVOLUTION_GLADEDIR 
                     "/mail-config-druid.glade", NULL);
    dialog->dialog = glade_xml_get_widget (dialog->gui, "dialog");
    dialog->druid = glade_xml_get_widget (dialog->gui, "druid");

    /* Cancel button */
    gtk_signal_connect (GTK_OBJECT (dialog->druid), "cancel", 
                GTK_SIGNAL_FUNC (mail_druid_cancel), 
                dialog->dialog);

    /* Start page */
    spage = GNOME_DRUID_PAGE_START (glade_xml_get_widget (dialog->gui, "startpage"));
    gnome_druid_page_start_set_logo (spage, mail_logo);
    
    /* Identity page */
    dpage = GNOME_DRUID_PAGE_STANDARD (glade_xml_get_widget (dialog->gui, "standardpage1"));
    gnome_druid_page_standard_set_logo (dpage, identity_logo);

    dialog->idpage = identity_page_new (NULL);
    gtk_box_pack_start (GTK_BOX (dpage->vbox), 
                dialog->idpage->vbox, 
                TRUE, TRUE, 0);

    identity_page_set_undone_cb (dialog->idpage, 
                     mail_druid_identity_undone, 
                     dialog);
    identity_page_set_done_cb (dialog->idpage, 
                   mail_druid_identity_done, 
                   dialog);
    gtk_signal_connect (GTK_OBJECT (dpage), "prepare", 
                GTK_SIGNAL_FUNC (mail_druid_prepare), 
                &dialog->iddone);
    gtk_widget_show (dialog->idpage->vbox);

    /* Source page */
    dpage = GNOME_DRUID_PAGE_STANDARD (glade_xml_get_widget (dialog->gui, "standardpage2"));
    gnome_druid_page_standard_set_logo (dpage, source_logo);

    dialog->spage = source_page_new (sources);
    gtk_box_pack_start (GTK_BOX (dpage->vbox), 
                dialog->spage->vbox, 
                TRUE, TRUE, 0);

    service_page_set_done_cb (dialog->spage->page, 
                  mail_druid_source_done, 
                  dialog);
    service_page_set_undone_cb (dialog->spage->page, 
                    mail_druid_source_undone, 
                    dialog);
    gtk_signal_connect (GTK_OBJECT (dpage), "prepare", 
                GTK_SIGNAL_FUNC (mail_druid_prepare), 
                &dialog->sdone);
    gtk_widget_show (dialog->spage->vbox);

    /* Transport page */
    dpage = GNOME_DRUID_PAGE_STANDARD (glade_xml_get_widget (dialog->gui, "standardpage3"));
    gnome_druid_page_standard_set_logo (dpage, transport_logo);

    dialog->tpage = transport_page_new (transports);
    gtk_box_pack_start (GTK_BOX (dpage->vbox), 
                dialog->tpage->vbox, 
                TRUE, TRUE, 0);

    service_page_set_undone_cb (dialog->tpage->page, 
                    mail_druid_transport_undone, 
                    dialog);
    service_page_set_done_cb (dialog->tpage->page, 
                  mail_druid_transport_done, 
                  dialog);
    gtk_signal_connect (GTK_OBJECT (dpage), "prepare", 
                GTK_SIGNAL_FUNC (mail_druid_prepare), 
                &dialog->tdone);
    gtk_widget_show (dialog->tpage->vbox);


    /* Finish page */
    fpage = GNOME_DRUID_PAGE_FINISH (glade_xml_get_widget (dialog->gui, "finishpage"));
    gnome_druid_page_finish_set_logo (fpage, mail_logo);

    gtk_signal_connect (GTK_OBJECT (fpage), "finish",
                GTK_SIGNAL_FUNC (mail_druid_finish),
                dialog);

    gtk_main ();
}

/* Main configuration dialog */
static void
identities_select_row (GtkWidget *widget, gint row, gint column,
               GdkEventButton *event, MailDialog *dialog)
{
    dialog->idrow = row;
}

static void
identities_add_clicked (GtkWidget *widget, MailDialog *dialog)
{
    MailConfigIdentity *id;

    id = identity_dialog (NULL, dialog->dialog);
    if (id) {
        GtkWidget *clist = dialog->clistIdentities;
        gchar *text[4];
        gint row = 0;
        
        text[0] = id->name;
        text[1] = id->address;
        text[2] = id->org;
        text[3] = id->sig;

        row = gtk_clist_append (GTK_CLIST (clist), text);
        gtk_clist_set_row_data (GTK_CLIST (clist), row, id);
        gtk_clist_select_row (GTK_CLIST (clist), row, 0);
        dialog->maxidrow++;

        gnome_property_box_changed (GNOME_PROPERTY_BOX (dialog->dialog));
    }
}

static void
identities_edit_clicked (GtkWidget *widget, MailDialog *dialog)
{
    MailConfigIdentity *id, *id2;

    if (dialog->idrow < 0)
        return;
    
    id = gtk_clist_get_row_data (GTK_CLIST (dialog->clistIdentities), 
                     dialog->idrow);
    
    id2 = identity_dialog (id, dialog->dialog);
    if (id2) {
        GtkCList *clist = GTK_CLIST (dialog->clistIdentities);
    
        gtk_clist_set_text (clist, dialog->idrow, 0, id2->name);
        gtk_clist_set_text (clist, dialog->idrow, 1, id2->address);
        gtk_clist_set_text (clist, dialog->idrow, 2, id2->org);
        gtk_clist_set_text (clist, dialog->idrow, 3, id2->sig);
    
        gtk_clist_set_row_data (clist, dialog->idrow, id2);
        identity_destroy (id);

        gnome_property_box_changed (GNOME_PROPERTY_BOX (dialog->dialog));
    }
}

static void
identities_delete_clicked (GtkWidget *widget, MailDialog *dialog)
{
    GtkCList *clist;
    
    if (dialog->idrow == -1)
        return;

    clist = GTK_CLIST (dialog->clistIdentities);
    
    gtk_clist_remove (clist, dialog->idrow);
    dialog->maxidrow--;

    if (dialog->idrow > dialog->maxidrow)
        gtk_clist_select_row (clist, dialog->maxidrow, 0);
    else
        gtk_clist_select_row (clist, dialog->idrow, 0);

    gnome_property_box_changed (GNOME_PROPERTY_BOX (dialog->dialog));
}

static void
sources_select_row (GtkWidget *widget, gint row, gint column,
            GdkEventButton *event, MailDialog *dialog)
{
    dialog->srow = row;
}

static void
sources_add_clicked (GtkWidget *widget, MailDialog *dialog)
{
    MailConfigService *source;

    source = source_dialog (NULL, dialog->dialog);
    if (source) {
        GtkCList *clist = GTK_CLIST (dialog->clistSources);
        gchar *text[1];
        gint row = 0;
        
        text[0] = source->url;
        
        row = gtk_clist_append (clist, text);
        gtk_clist_set_row_data (clist, row, source);
        gtk_clist_select_row (clist, row, 0);
        dialog->maxsrow++;
        
        gnome_property_box_changed (GNOME_PROPERTY_BOX (dialog->dialog));
    }
}

static void
sources_edit_clicked (GtkWidget *widget, MailDialog *dialog)
{
    MailConfigService *source, *source2;

    if (dialog->srow < 0)
        return;

    source = gtk_clist_get_row_data (GTK_CLIST (dialog->clistSources),
                     dialog->srow);
    
    source2 = source_dialog (source, dialog->dialog);
    if (source2) {
        GtkCList *clist = GTK_CLIST (dialog->clistSources);
        
        gtk_clist_set_text (clist, dialog->srow, 0, source2->url);
        gtk_clist_set_row_data (clist, dialog->srow, source2);
        service_destroy (source);

        gnome_property_box_changed (GNOME_PROPERTY_BOX (dialog->dialog));
    }
}

static void
sources_delete_clicked (GtkWidget *widget, MailDialog *dialog)
{
    GtkCList *clist;
    
    if (dialog->srow == -1)
        return;
    
    clist = GTK_CLIST (dialog->clistSources);

    gtk_clist_remove (clist, dialog->srow);
    dialog->maxsrow--;

    if (dialog->srow > dialog->maxsrow)
        gtk_clist_select_row (clist, dialog->maxsrow, 0);
    else
        gtk_clist_select_row (clist, dialog->srow, 0);

    gnome_property_box_changed (GNOME_PROPERTY_BOX (dialog->dialog));
}

static void
news_select_row (GtkWidget *widget, gint row, gint column,
         GdkEventButton *event, MailDialog *dialog)
{
    dialog->nrow = row;
}

static void
news_add_clicked (GtkWidget *widget, MailDialog *dialog)
{
    MailConfigService *news;

    news = news_dialog (NULL, dialog->dialog);
    if (news) {
        GtkCList *clist = GTK_CLIST (dialog->clistNewsServers);
        gchar *text[1];
        gint row = 0;
        
        text[0] = news->url;

        row = gtk_clist_append (clist, text);
        gtk_clist_set_row_data (clist, row, news);
        gtk_clist_select_row (clist, row, 0);
        dialog->maxsrow++;
        
        gnome_property_box_changed (GNOME_PROPERTY_BOX (dialog->dialog));
    }
}

static void
news_edit_clicked (GtkWidget *widget, MailDialog *dialog)
{
    MailConfigService *news, *news2;

    if (dialog->srow < 0)
        return;

    news = gtk_clist_get_row_data (GTK_CLIST (dialog->clistNewsServers),
                       dialog->srow);
    
    news2 = source_dialog (news, dialog->dialog);
    if (news2) {
        GtkCList *clist = GTK_CLIST (dialog->clistNewsServers);
        
        gtk_clist_set_text (clist, dialog->nrow, 0, news2->url);
        gtk_clist_set_row_data (clist, dialog->nrow, news2);
        service_destroy (news);

        gnome_property_box_changed (GNOME_PROPERTY_BOX (dialog->dialog));
    }
}

static void
news_delete_clicked (GtkWidget *widget, MailDialog *dialog)
{
    GtkCList *clist;
    
    if (dialog->nrow == -1)
        return;
    
    clist = GTK_CLIST (dialog->clistNewsServers);

    gtk_clist_remove (clist, dialog->nrow);
    dialog->maxnrow--;

    if (dialog->nrow > dialog->maxnrow)
        gtk_clist_select_row (clist, dialog->maxnrow, 0);
    else
        gtk_clist_select_row (clist, dialog->nrow, 0);

    gnome_property_box_changed (GNOME_PROPERTY_BOX (dialog->dialog));
}

static void
mail_config_tpage_changed (MailDialogServicePage *page, gpointer data)
{
    MailDialog *dialog = (MailDialog *)data;

    gnome_property_box_changed (GNOME_PROPERTY_BOX (dialog->dialog));
}

static void
mail_config_tpage_done (MailDialogServicePage *page, gpointer data)
{
    MailDialog *dialog = (MailDialog *)data;
    
    dialog->tpagedone = TRUE;
}

static void
format_toggled (GtkWidget *widget, MailDialog *dialog)
{
    gnome_property_box_changed (GNOME_PROPERTY_BOX (dialog->dialog));
}

static void
mail_config_apply_clicked (GnomePropertyBox *property_box, gint page_num,
               MailDialog *dialog)
{
    gpointer data;
    int i;
    
    if (page_num != -1)
        return;

    clear_config ();

    /* Identities */
    for (i = 0; i <= dialog->maxidrow; i++) {   
        data = gtk_clist_get_row_data (GTK_CLIST (dialog->clistIdentities), i);
        config->ids = g_slist_append (config->ids, data);
    }

    /* Sources */
    for (i = 0; i <= dialog->maxsrow; i++) {    
        data = gtk_clist_get_row_data (GTK_CLIST (dialog->clistSources), i);
        config->sources = g_slist_append (config->sources, data);
    }

    /* Transport */
    config->transport = service_page_extract (dialog->page->page);
    
    /* Format */
    config->send_html = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->chkFormat));

    write_config ();
}

void
mail_config (void)
{
    MailDialog *dialog;
    GladeXML *gui;
    GtkCList *clist;
    GtkWidget *button, *tvbox;
    GSList *sources, *news, *transports;
    gint len, row;

    read_config ();
    provider_list (&sources, &news, &transports);

    dialog = g_new0 (MailDialog, 1);    
    gui = glade_xml_new (EVOLUTION_GLADEDIR "/mail-config.glade", NULL);

    dialog->dialog = glade_xml_get_widget (gui, "dialog");
    dialog->notebook = glade_xml_get_widget (gui, "notebook");
    
    /* Identities Page */
    dialog->clistIdentities = 
        glade_xml_get_widget (gui, "clistIdentities");
    clist = GTK_CLIST (dialog->clistIdentities);
    gtk_clist_set_column_width (clist, 0, 80);

    len = g_slist_length (config->ids); 
    for (row = 0; row < len; row++) {
        MailConfigIdentity *id;
        gchar *text[4];
        
        id = identity_copy ((MailConfigIdentity *)
                    g_slist_nth_data (config->ids, row));
        
        text[0] = id->name;
        text[1] = id->address;
        text[2] = id->org;
        text[3] = id->sig;
        
        gtk_clist_append (clist, text);
        gtk_clist_set_row_data (clist, row, id);
    }

    dialog->maxidrow = len - 1;
    dialog->idrow = -1;
    gtk_signal_connect (GTK_OBJECT (clist), "select_row",
                GTK_SIGNAL_FUNC (identities_select_row),
                dialog);

    button = glade_xml_get_widget (gui, "cmdIdentitiesAdd");
    gtk_signal_connect (GTK_OBJECT (button), "clicked",
                GTK_SIGNAL_FUNC (identities_add_clicked),
                dialog);
    button = glade_xml_get_widget (gui, "cmdIdentitiesEdit");
    gtk_signal_connect (GTK_OBJECT (button), "clicked",
                GTK_SIGNAL_FUNC (identities_edit_clicked),
                dialog);
    button = glade_xml_get_widget (gui, "cmdIdentitiesDelete");
    gtk_signal_connect (GTK_OBJECT (button), "clicked",
                GTK_SIGNAL_FUNC (identities_delete_clicked),
                dialog);

    /* Sources Page */
    dialog->clistSources = glade_xml_get_widget (gui, "clistSources");
    clist = GTK_CLIST (dialog->clistSources);
    gtk_clist_set_column_width (clist, 0, 80);

    len = g_slist_length (config->sources); 
    for (row = 0; row < len; row++) {
        MailConfigService *source;
        gchar *text[1];
        
        source = service_copy ((MailConfigService *)g_slist_nth_data (config->sources, row));
        
        text[0] = source->url;

        gtk_clist_append (clist, text);
        gtk_clist_set_row_data (clist, row, source);
    }

    dialog->maxsrow = len - 1;
    dialog->srow = -1;
    gtk_signal_connect (GTK_OBJECT (clist), "select_row",
                GTK_SIGNAL_FUNC (sources_select_row),
                dialog);

    button = glade_xml_get_widget (gui, "cmdSourcesAdd");
    gtk_signal_connect (GTK_OBJECT (button), "clicked",
                GTK_SIGNAL_FUNC (sources_add_clicked),
                dialog);
    button = glade_xml_get_widget (gui, "cmdSourcesEdit");
    gtk_signal_connect (GTK_OBJECT (button), "clicked",
                GTK_SIGNAL_FUNC (sources_edit_clicked),
                dialog);
    button = glade_xml_get_widget (gui, "cmdSourcesDelete");
    gtk_signal_connect (GTK_OBJECT (button), "clicked",
                GTK_SIGNAL_FUNC (sources_delete_clicked),
                dialog);

    /* News Page */
    dialog->clistNewsServers = glade_xml_get_widget (gui, "clistNewsServers");
    clist = GTK_CLIST (dialog->clistNewsServers);
    gtk_clist_set_column_width (clist, 0, 80);

    len = g_slist_length (config->news);    
    for (row=0; row<len; row++) {
        MailConfigService *news;
        gchar *text[1];
        
        news = service_copy ((MailConfigService *)
                     g_slist_nth_data (config->news, row));
        
        text[0] = news->url;

        gtk_clist_append (clist, text);
        gtk_clist_set_row_data (clist, row, news);
    }

    dialog->maxnrow = len - 1;
    dialog->nrow = -1;
    gtk_signal_connect (GTK_OBJECT (clist), "select_row",
                GTK_SIGNAL_FUNC (news_select_row),
                dialog);

    button = glade_xml_get_widget (gui, "cmdNewsServersAdd");
    gtk_signal_connect (GTK_OBJECT (button), "clicked",
                GTK_SIGNAL_FUNC (news_add_clicked),
                dialog);
    button = glade_xml_get_widget (gui, "cmdNewsServersEdit");
    gtk_signal_connect (GTK_OBJECT (button), "clicked",
                GTK_SIGNAL_FUNC (news_edit_clicked),
                dialog);
    button = glade_xml_get_widget (gui, "cmdNewsServersDelete");
    gtk_signal_connect (GTK_OBJECT (button), "clicked",
                GTK_SIGNAL_FUNC (news_delete_clicked),
                dialog);

    /* Transport Page */
    tvbox = glade_xml_get_widget (gui, "transport_vbox");
    dialog->page = transport_page_new (transports);
    service_page_set_url (dialog->page->page, config->transport);
    service_page_set_changed_cb (dialog->page->page,
                     mail_config_tpage_changed, dialog);
    service_page_set_done_cb (dialog->page->page, 
                  mail_config_tpage_done, dialog);
    gtk_box_pack_start (GTK_BOX (tvbox), 
                dialog->page->vbox, TRUE, TRUE, 0);
    gtk_widget_show (dialog->page->vbox);
    
    /* Other Page */
    dialog->chkFormat = glade_xml_get_widget (gui, "chkFormat");
    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->chkFormat), 
                      config->send_html);
    gtk_signal_connect (GTK_OBJECT (dialog->chkFormat), "toggled",
                GTK_SIGNAL_FUNC (format_toggled),
                dialog);

    /* Listen for apply signal */
    gtk_signal_connect (GTK_OBJECT (dialog->dialog), "apply",
                GTK_SIGNAL_FUNC (mail_config_apply_clicked),
                dialog);

    gnome_dialog_run (GNOME_DIALOG (dialog->dialog));

    /* Clean up */
    gtk_object_unref (GTK_OBJECT (gui));
    g_free (dialog);
}

const MailConfig *
mail_config_fetch (void)
{
    read_config ();
    
    return config;
}