Logo Search packages:      
Sourcecode: balsa version File versions

identity.c

/* -*-mode:c; c-style:k&r; c-basic-offset:4; -*- */
/* Balsa E-Mail Client
 * Copyright (C) 1997-2002 Stuart Parmenter and others,
 *                         See the file AUTHORS for a list.
 *
 * 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, 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"

#ifdef HAVE_GNOME
#include <libgnome/gnome-help.h>
#endif

#ifdef HAVE_GPGME
#  include "rfc3156.h"
#endif
#include "identity.h"
#include "information.h"
#include "libbalsa-conf.h"
#include "i18n.h"

/*
 * The class.
 */

static GtkObjectClass* parent_class;

/* Forward references. */
static void libbalsa_identity_class_init(LibBalsaIdentityClass* klass);
static void libbalsa_identity_init(LibBalsaIdentity* ident);
static void libbalsa_identity_finalize(GObject* object);

GType
libbalsa_identity_get_type()
{
    static GType libbalsa_identity_type = 0;

    if (!libbalsa_identity_type) {
        static const GTypeInfo libbalsa_identity_info = {
            sizeof(LibBalsaIdentityClass),
            NULL,               /* base_init */
            NULL,               /* base_finalize */
            (GClassInitFunc) libbalsa_identity_class_init,
            NULL,               /* class_finalize */
            NULL,               /* class_data */
            sizeof(LibBalsaIdentity),
            0,                  /* n_preallocs */
            (GInstanceInitFunc) libbalsa_identity_init,
        };

        libbalsa_identity_type =
            g_type_register_static(G_TYPE_OBJECT,
                                   "LibBalsaIdentity",
                                   &libbalsa_identity_info, 0);
    }
    
    return libbalsa_identity_type;
}

static void
libbalsa_identity_class_init(LibBalsaIdentityClass* klass)
{
    GObjectClass* object_class;

    parent_class = g_type_class_peek_parent(klass);

    object_class = G_OBJECT_CLASS(klass);
    object_class->finalize = libbalsa_identity_finalize;
}

/* 
 * Instance inititialization function: set defaults for new objects.
 */
static void
libbalsa_identity_init(LibBalsaIdentity* ident)
{
    ident->identity_name = NULL;
    ident->ia = internet_address_new();
    ident->replyto = NULL;
    ident->domain = NULL;
    ident->bcc = NULL;
    ident->reply_string = g_strdup(_("Re:"));
    ident->forward_string = g_strdup(_("Fwd:"));
    ident->signature_path = NULL;
    ident->sig_executable = FALSE;
    ident->sig_sending = TRUE;
    ident->sig_whenforward = TRUE;
    ident->sig_whenreply = TRUE;
    ident->sig_separator = TRUE;
    ident->sig_prepend = FALSE;
#ifdef HAVE_GPGME
    ident->gpg_sign = FALSE;
    ident->gpg_encrypt = FALSE;
    ident->crypt_protocol = LIBBALSA_PROTECT_OPENPGP;
#endif
}

/* 
 * Destroy the object, freeing all the values in the process.
 */
static void
libbalsa_identity_finalize(GObject * object)
{
    LibBalsaIdentity *ident = LIBBALSA_IDENTITY(object);

    internet_address_unref(ident->ia);
    g_free(ident->identity_name);
    g_free(ident->replyto);
    g_free(ident->domain);
    g_free(ident->bcc);
    g_free(ident->reply_string);
    g_free(ident->forward_string);
    g_free(ident->signature_path);

    G_OBJECT_CLASS(parent_class)->finalize(object);
}

/*
 * Public methods.
 */

/* 
 * Create a new object with the default identity name.  Does not add
 * it to the list of identities for the application.
 */
GObject* 
libbalsa_identity_new(void) 
{
    return libbalsa_identity_new_with_name(_("New Identity"));
}


/*
 * Create a new object with the specified identity name.  Does not add
 * it to the list of identities for the application.
 */
GObject*
libbalsa_identity_new_with_name(const gchar* ident_name)
{
    LibBalsaIdentity* ident;
    
    ident = LIBBALSA_IDENTITY(g_object_new(LIBBALSA_TYPE_IDENTITY, NULL));
    libbalsa_identity_set_identity_name(ident, ident_name);

    return G_OBJECT(ident);
}


void
libbalsa_identity_set_identity_name(LibBalsaIdentity* ident, const gchar* name)
{
    g_return_if_fail(ident != NULL);
    
    g_free(ident->identity_name);
    ident->identity_name = g_strdup(name);
}


void
libbalsa_identity_set_address(LibBalsaIdentity * ident,
                              InternetAddress * ia)
{
    g_return_if_fail(ident != NULL);

    internet_address_unref(ident->ia);
    ident->ia = ia;
}


void
libbalsa_identity_set_replyto(LibBalsaIdentity* ident, const gchar* address)
{
    g_return_if_fail(ident != NULL);
    
    g_free(ident->replyto);
    ident->replyto = g_strdup(address);
}


void
libbalsa_identity_set_domain(LibBalsaIdentity* ident, const gchar* dom)
{
    g_return_if_fail(ident != NULL);
    
    g_free(ident->domain);
    ident->domain = g_strdup(dom);
}


void 
libbalsa_identity_set_bcc(LibBalsaIdentity* ident, const gchar* bcc)
{
    g_return_if_fail(ident != NULL);
    
    g_free(ident->bcc);
    ident->bcc = g_strdup(bcc);
}


void 
libbalsa_identity_set_reply_string(LibBalsaIdentity* ident, const gchar* reply)
{
    g_return_if_fail(ident != NULL);

    g_free(ident->reply_string);
    ident->reply_string = g_strdup(reply);
}


void 
libbalsa_identity_set_forward_string(LibBalsaIdentity* ident, const gchar* forward)
{
    g_return_if_fail(ident != NULL);
    
    g_free(ident->forward_string);
    ident->forward_string = g_strdup(forward);
}


void
libbalsa_identity_set_signature_path(LibBalsaIdentity* ident, const gchar* path)
{
    g_return_if_fail(ident != NULL);
    
    g_free(ident->signature_path);
    ident->signature_path = g_strdup(path);
}


void
libbalsa_identity_set_sig_executable(LibBalsaIdentity* ident, gboolean sig_executable)
{
    g_return_if_fail(ident != NULL);
    ident->sig_executable = sig_executable;
}


void
libbalsa_identity_set_sig_sending(LibBalsaIdentity* ident, gboolean sig_sending)
{
    g_return_if_fail(ident != NULL);
    ident->sig_sending = sig_sending;
}


void
libbalsa_identity_set_sig_whenforward(LibBalsaIdentity* ident, gboolean forward)
{
    g_return_if_fail(ident != NULL);
    ident->sig_whenforward = forward;
}


void 
libbalsa_identity_set_sig_whenreply(LibBalsaIdentity* ident, gboolean reply)
{
    g_return_if_fail(ident != NULL);
    ident->sig_whenreply = reply;
}


void
libbalsa_identity_set_sig_separator(LibBalsaIdentity* ident, gboolean separator)
{
    g_return_if_fail(ident != NULL);
    ident->sig_separator = separator;
}


void 
libbalsa_identity_set_sig_prepend(LibBalsaIdentity* ident, gboolean prepend)
{
    g_return_if_fail(ident != NULL);
    ident->sig_prepend = prepend;
}


/* Used by both dialogs: */

/* Widget padding: */
static const guint padding = 4;

/* Forward references: */
static void identity_list_update_real(GtkTreeView * tree,
                                      GList * identities,
                                      LibBalsaIdentity * default_id);
static GtkWidget *libbalsa_identity_tree(GCallback toggled_cb,
                                         gpointer toggled_data,
                                         gchar * toggled_title);

/*
 * The Select Identity dialog; called from compose window.
 */

/* Info passed to callbacks: */
struct SelectDialogInfo_ {
    LibBalsaIdentityCallback update;
    gpointer data;
    GtkWidget *tree;
    GtkWidget *dialog;
    GtkWindow *parent;
    guint idle_handler_id;
};
typedef struct SelectDialogInfo_ SelectDialogInfo;

/* Forward references: */
static void sd_destroy_notify(SelectDialogInfo * sdi);
static void sd_response_cb(GtkWidget * dialog, gint response,
                           SelectDialogInfo * sdi);
static void sd_idle_add_response_ok(SelectDialogInfo * sdi);
static gboolean sd_response_ok(SelectDialogInfo * sdi);

/* Tree columns: */
enum {
    DEFAULT_COLUMN,
    NAME_COLUMN,
    IDENT_COLUMN,
    N_COLUMNS
};

/* 
 * Public method: create and show the dialog.
 */
#define LIBBALSA_IDENTITY_SELECT_DIALOG_KEY "libbalsa-identity-select-dialog"
void
libbalsa_identity_select_dialog(GtkWindow * parent,
                                const gchar * prompt,
                                GList * identities,
                                LibBalsaIdentity * initial_id,
                                LibBalsaIdentityCallback update,
                                gpointer data)
{
    GtkWidget *dialog;
    GtkWidget *tree;
    SelectDialogInfo *sdi;
    GtkWidget *frame;

    /* Show only one dialog at a time. */
    sdi = g_object_get_data(G_OBJECT(parent),
                            LIBBALSA_IDENTITY_SELECT_DIALOG_KEY);
    if (sdi) {
        gdk_window_raise(sdi->dialog->window);
        return;
    }

    sdi = g_new(SelectDialogInfo, 1);
    sdi->parent = parent;
    g_object_set_data_full(G_OBJECT(parent),
                           LIBBALSA_IDENTITY_SELECT_DIALOG_KEY,
                           sdi, (GDestroyNotify) sd_destroy_notify);
    sdi->update = update;
    sdi->data = data;
    sdi->idle_handler_id = 0;
    sdi->dialog = dialog =
        gtk_dialog_new_with_buttons(prompt, parent,
                                    GTK_DIALOG_DESTROY_WITH_PARENT,
                                    GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
                                    GTK_STOCK_OK, GTK_RESPONSE_OK,
                                    NULL);
    g_signal_connect(G_OBJECT(dialog), "response",
                     G_CALLBACK(sd_response_cb), sdi);
    gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK);

    sdi->tree = tree =
        libbalsa_identity_tree(G_CALLBACK(sd_idle_add_response_ok), sdi,
                               _("Current"));
    g_signal_connect_swapped(G_OBJECT(tree), "row-activated",
                             G_CALLBACK(sd_idle_add_response_ok), sdi);
    identity_list_update_real(GTK_TREE_VIEW(tree), identities, initial_id);

    frame = gtk_frame_new(NULL);
    gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
                       frame, TRUE, TRUE, 0);
    gtk_container_add(GTK_CONTAINER(frame), tree);
    gtk_container_set_border_width(GTK_CONTAINER(frame), padding);

    gtk_widget_show_all(dialog);
    gtk_widget_grab_focus(tree);
}

/* GDestroyNotify for sdi. */
static void
sd_destroy_notify(SelectDialogInfo * sdi)
{
    if (sdi->idle_handler_id) {
        g_source_remove(sdi->idle_handler_id);
        sdi->idle_handler_id = 0;
    }
    g_free(sdi);
}

/* Callback for the dialog's "response" signal. */
static void
sd_response_cb(GtkWidget * dialog, gint response, SelectDialogInfo * sdi)
{
    if (response == GTK_RESPONSE_OK) {
        GtkTreeSelection *selection =
            gtk_tree_view_get_selection(GTK_TREE_VIEW(sdi->tree));
        GtkTreeModel *model;
        GtkTreeIter iter;

        if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
            LibBalsaIdentity *identity;

            gtk_tree_model_get(model, &iter, IDENT_COLUMN, &identity, -1);
            sdi->update(sdi->data, identity);
        }
    }

    /* Clear the data set on the parent window, so we know that the
     * dialog was destroyed. This will also trigger the GDestroyNotify
     * function, sd_destroy_notify.
     */
    g_object_set_data(G_OBJECT(sdi->parent),
                      LIBBALSA_IDENTITY_SELECT_DIALOG_KEY,
                      NULL);

    gtk_widget_destroy(dialog);
}

/* Helper for adding idles. */
static void
sd_idle_add_response_ok(SelectDialogInfo * sdi)
{
    if (!sdi->idle_handler_id)
        sdi->idle_handler_id =
            g_idle_add((GSourceFunc) sd_response_ok, sdi);
}

/* Idle handler for sending the OK response to the dialog. */
static gboolean
sd_response_ok(SelectDialogInfo * sdi)
{
    gdk_threads_enter();
    if (sdi->idle_handler_id) {
        sdi->idle_handler_id = 0;
        gtk_dialog_response(GTK_DIALOG(sdi->dialog), GTK_RESPONSE_OK);
    }
    gdk_threads_leave();
    return FALSE;
}

/*
 * The Manage Identities dialog; called from main window.
 */

#define ELEMENTS(x) (sizeof (x) / sizeof (x[0]))
typedef struct _IdentityDeleteInfo IdentityDeleteInfo;

/* button actions */
static gboolean close_cb(GtkWidget * dialog);
static void new_ident_cb(GtkTreeView * tree, GtkWidget * dialog);
static void delete_ident_cb(GtkTreeView * tree, GtkWidget * dialog);
static void delete_ident_response(GtkWidget * confirm, gint response,
                                  IdentityDeleteInfo * di);
static void help_ident_cb(void);

static void set_default_ident_cb(GtkTreeView * tree, GtkTreePath * path,
                                 GtkTreeViewColumn * column,
                                 gpointer data);
static void config_frame_button_select_cb(GtkTreeSelection * selection,
                                          GtkDialog * dialog);

static void ident_dialog_add_checkbutton(GtkWidget *, gint, GtkDialog *,
                                         const gchar *, const gchar *);
static void ident_dialog_add_entry(GtkWidget *, gint, GtkDialog *,
                                   const gchar *, const gchar *);
static gchar *ident_dialog_get_text(GtkDialog *, const gchar *);
static gboolean ident_dialog_get_bool(GtkDialog *, const gchar *);
static gboolean ident_dialog_update(GtkDialog *);
static void config_dialog_select(GtkTreeSelection * selection,
                                 GtkDialog * dialog);

static void display_frame_update(GtkDialog * dialog, LibBalsaIdentity* ident);
static void display_frame_set_field(GtkDialog * dialog, const gchar* key, 
                                    const gchar* value);
static void display_frame_set_boolean(GtkDialog * dialog, const gchar* key, 
                                      gboolean value);


static void identity_list_update(GtkTreeView * tree);
static gboolean select_identity(GtkTreeView * tree,
                                LibBalsaIdentity * identity);
static LibBalsaIdentity *get_selected_identity(GtkTreeView * tree);
static void set_identity_name_in_tree(GtkTreeView * tree,
                              LibBalsaIdentity * identity,
                              const gchar * name);
static void md_response_cb(GtkWidget * dialog, gint response,
                           GtkTreeView * tree);
static void md_name_changed(GtkEntry * name, GtkTreeView * tree);
static void md_sig_path_changed(GtkEntry * sig_path, GObject * dialog);

#ifdef HAVE_GPGME
static void add_show_menu(const char* label, gint value, GtkWidget* menu);
static void ident_dialog_add_option_menu(GtkWidget * table, gint row,
                                         GtkDialog * dialog,
                                         const gchar * label_name,
                                         const gchar * menu_key);
static gint ident_dialog_get_menu(GtkDialog * dialog, const gchar * key);
static void display_frame_set_menu(GtkDialog * dialog, const gchar* key,
                                   gint * value);
#endif /* HAVE_GPGME */


/* Callback for the "toggled" signal of the "Default" column. */
static void
toggle_cb(GtkWidget * dialog, gchar * path)
{
    GtkTreeView *tree = g_object_get_data(G_OBJECT(dialog), "tree");
    GtkTreeModel *model = gtk_tree_view_get_model(tree);
    GtkTreeIter iter;

    /* Save any changes to current identity; if it's not valid, just
     * return. */
    if (!ident_dialog_update(GTK_DIALOG(dialog)))
      return;

    if (gtk_tree_model_get_iter_from_string(model, &iter, path)) {
        LibBalsaIdentity *identity, **default_id;

        gtk_tree_model_get(model, &iter, IDENT_COLUMN, &identity, -1);
        default_id = g_object_get_data(G_OBJECT(tree), "default-id");
        *default_id = identity;
        identity_list_update(tree);
    }
}

/*
 * Common code for making a GtkTreeView list of identities:
 *
 * toggled_cb           callback for the "toggled" signal of the boolean
 *                      column;
 * toggled_data         user_data for the callback;
 * toggled_title        title for the boolean column.
 */
static GtkWidget *
libbalsa_identity_tree(GCallback toggled_cb, gpointer toggled_data,
                       gchar * toggled_title)
{
    GtkListStore *store;
    GtkWidget *tree;
    GtkCellRenderer *renderer;
    GtkTreeViewColumn *column;

    store = gtk_list_store_new(N_COLUMNS,
                               G_TYPE_BOOLEAN,
                               G_TYPE_STRING,
                               G_TYPE_POINTER);

    tree = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
    g_object_unref(store);

    renderer = gtk_cell_renderer_toggle_new();
    g_signal_connect_swapped(G_OBJECT(renderer), "toggled",
                             toggled_cb, toggled_data);
    column =
        gtk_tree_view_column_new_with_attributes(toggled_title, renderer,
                                                 "radio", DEFAULT_COLUMN,
                                                 NULL);
    gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column);

    renderer = gtk_cell_renderer_text_new();
    column = gtk_tree_view_column_new_with_attributes("Name", renderer,
                                                      "text", NAME_COLUMN,
                                                      NULL);
    gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column);

    return tree;
}

/*
 * Create and return a frame containing a list of the identities in
 * the application and a number of buttons to edit, create, and delete
 * identities.  Also provides a way to set the default identity.
 */
static GtkWidget* 
libbalsa_identity_config_frame(GList** identities,
                         LibBalsaIdentity** defid, GtkWidget * dialog,
                               void (*cb)(gpointer), gpointer data)
{
    GtkWidget* config_frame = gtk_frame_new(NULL);
    GtkWidget *tree;

    gtk_container_set_border_width(GTK_CONTAINER(config_frame), 0);
    
    tree = libbalsa_identity_tree(G_CALLBACK(toggle_cb), dialog,
                                  _("Default"));
    g_signal_connect(G_OBJECT(tree), "row-activated",
                     G_CALLBACK(set_default_ident_cb), NULL);
    g_object_set_data(G_OBJECT(tree), "identities", identities);
    g_object_set_data(G_OBJECT(tree), "default-id", defid);
    g_object_set_data(G_OBJECT(tree), "callback", cb);
    g_object_set_data(G_OBJECT(tree), "cb-data",  data);

    gtk_container_add(GTK_CONTAINER(config_frame), tree);

    identity_list_update(GTK_TREE_VIEW(tree));

    return config_frame;
}

static gint
compare_identities(LibBalsaIdentity *id1, LibBalsaIdentity *id2)
{
    return g_ascii_strcasecmp(id1->identity_name, id2->identity_name);
}

/* identity_list_update:
 * Update the list of identities in the config frame, displaying the
 * available identities in the application, and which is default.
 */
static void
identity_list_update(GtkTreeView * tree)
{
    GList **identities =
        g_object_get_data(G_OBJECT(tree), "identities");
    LibBalsaIdentity **default_id =
        g_object_get_data(G_OBJECT(tree), "default-id");

    identity_list_update_real(tree, *identities, *default_id);
}

static void
identity_list_update_real(GtkTreeView * tree,
                          GList * identities,
                          LibBalsaIdentity * default_id)
{
    GtkListStore *store = GTK_LIST_STORE(gtk_tree_view_get_model(tree));
    GList *sorted, *list;
    LibBalsaIdentity *current;
    GtkTreeIter iter;

    current = get_selected_identity(tree);

    gtk_list_store_clear(store);
    
    sorted = g_list_sort(g_list_copy(identities),
                         (GCompareFunc) compare_identities);
    for (list = sorted; list; list = g_list_next(list)) {
        LibBalsaIdentity* ident = LIBBALSA_IDENTITY(list->data);
        gtk_list_store_append(store, &iter);
        gtk_list_store_set(store, &iter,
                           DEFAULT_COLUMN, ident == default_id,
                           NAME_COLUMN, ident->identity_name,
                           IDENT_COLUMN, ident,
                           -1);
    }
    g_list_free(sorted);

    if (!select_identity(tree, current))
        select_identity(tree, default_id);
}

static gboolean
select_identity(GtkTreeView * tree, LibBalsaIdentity * identity)
{
    GtkTreeModel *model = gtk_tree_view_get_model(tree);
    GtkTreeIter iter;
    gboolean valid;
    
    for (valid = gtk_tree_model_get_iter_first(model, &iter);
         valid;
         valid = gtk_tree_model_iter_next(model, &iter)) {
        LibBalsaIdentity *tmp;
        
        gtk_tree_model_get(model, &iter, IDENT_COLUMN, &tmp, -1);
        if (identity == tmp) {
            GtkTreePath *path = gtk_tree_model_get_path(model, &iter);
            gtk_tree_view_set_cursor(tree, path, NULL, FALSE);
            gtk_tree_path_free(path);

            return TRUE;
        }
    }

    return FALSE;
}

static LibBalsaIdentity *
get_selected_identity(GtkTreeView * tree)
{
    GtkTreeSelection *select =
        gtk_tree_view_get_selection(GTK_TREE_VIEW(tree));
    GtkTreeModel *model = gtk_tree_view_get_model(tree);
    GtkTreeIter iter;
    LibBalsaIdentity *identity = NULL;

    if (gtk_tree_selection_get_selected(select, &model, &iter))
        gtk_tree_model_get(model, &iter, IDENT_COLUMN, &identity, -1);

    return identity;
}

enum {
    IDENTITY_RESPONSE_CLOSE,
    IDENTITY_RESPONSE_NEW,
    IDENTITY_RESPONSE_REMOVE,
    IDENTITY_RESPONSE_HELP
};
    
/* callback for the "changed" signal */
static void
config_frame_button_select_cb(GtkTreeSelection * selection,
                              GtkDialog * dialog)
{
    config_dialog_select(selection, dialog);
}

/*
 * Callback for the close button.
 * Call ident_dialog_update to save any changes, and close the dialog if
 * OK.
 */
static gboolean
close_cb(GtkWidget * dialog)
{
    return ident_dialog_update(GTK_DIALOG(dialog));
}

/*
 * Create a new identity
 */
static void
new_ident_cb(GtkTreeView * tree, GtkWidget * dialog)
{
    LibBalsaIdentity *ident;
    GList **identities;
    GtkWidget *name_entry;
    void (*cb)(gpointer) = g_object_get_data(G_OBJECT(tree), "callback");
    gpointer data        = g_object_get_data(G_OBJECT(tree), "cb-data");

    /* Save any changes to current identity; if it's not valid, just
     * return. */
    if (!ident_dialog_update(GTK_DIALOG(dialog)))
      return;

    ident = LIBBALSA_IDENTITY(libbalsa_identity_new());
    identities = g_object_get_data(G_OBJECT(tree), "identities");
    *identities = g_list_append(*identities, ident);
    identity_list_update(tree);
    /* select just added identity */
    select_identity(tree, ident);

    name_entry = g_object_get_data(G_OBJECT(dialog), "identity-name");
    gtk_widget_grab_focus(name_entry);
    cb(data);
}


/*
 * Put the required GtkEntries, Labels, and Checkbuttons in the dialog
 * for creating/editing identities.
 */
static GtkWidget*
setup_ident_frame(GtkDialog * dialog, gboolean createp, gpointer tree)
{
     
    GtkWidget* frame = gtk_frame_new(NULL);
#ifdef HAVE_GPGME
    GtkWidget *table = gtk_table_new(18, 2, FALSE);
#else
    GtkWidget *table = gtk_table_new(15, 2, FALSE);
#endif
    gint row = 0;
    GObject *name;
    GObject *sig_path;

    gtk_container_set_border_width(GTK_CONTAINER(frame), padding);
    gtk_container_set_border_width(GTK_CONTAINER(table), padding);

    gtk_container_add(GTK_CONTAINER(frame), table);
    gtk_table_set_row_spacings(GTK_TABLE(table), padding);
    gtk_table_set_col_spacings(GTK_TABLE(table), padding);

    ident_dialog_add_entry(table, row++, dialog, _("_Identity Name:"), 
                       "identity-name");
    ident_dialog_add_entry(table, row++, dialog, _("_Full Name:"), 
                           "identity-fullname");
    ident_dialog_add_entry(table, row++, dialog, _("_Mailing Address:"), 
                           "identity-address");
    ident_dialog_add_entry(table, row++, dialog, _("Reply _To:"), 
                           "identity-replyto");
    ident_dialog_add_entry(table, row++, dialog, _("_Domain:"), 
                           "identity-domain");
    ident_dialog_add_entry(table, row++, dialog, _("_Bcc:"), 
                           "identity-bcc");
    ident_dialog_add_entry(table, row++, dialog, _("Reply _String:"), 
                           "identity-replystring");
    ident_dialog_add_entry(table, row++, dialog, _("F_orward String:"), 
                           "identity-forwardstring");
    ident_dialog_add_entry(table, row++, dialog, _("Signature _Path:"), 
                           "identity-sigpath");
    
    ident_dialog_add_checkbutton(table, row++, dialog,
                                _("_Execute Signature"),
                        "identity-sigexecutable");
    ident_dialog_add_checkbutton(table, row++, dialog,
                                 _("Incl_ude Signature"), 
                                 "identity-sigappend");
    ident_dialog_add_checkbutton(table, row++, dialog, 
                                 _("Include Signature When For_warding"),
                                 "identity-whenforward");
    ident_dialog_add_checkbutton(table, row++, dialog,
                                 _("Include Signature When Rep_lying"),
                                 "identity-whenreply");
    ident_dialog_add_checkbutton(table, row++, dialog, 
                                 _("_Add Signature Separator"),
                                 "identity-sigseparator");
    ident_dialog_add_checkbutton(table, row++, dialog,
                                 _("Prepend Si_gnature"),
                                 "identity-sigprepend");

#ifdef HAVE_GPGME
    ident_dialog_add_checkbutton(table, row++, dialog, 
                                 _("sign messages by default"),
                                 "identity-gpgsign");
    gtk_widget_set_sensitive(GTK_WIDGET(g_object_get_data(G_OBJECT(dialog),
                                            "identity-gpgsign")),
                       TRUE);
    ident_dialog_add_checkbutton(table, row++, dialog,
                                 _("encrypt messages by default"),
                                 "identity-gpgencrypt");
    gtk_widget_set_sensitive(GTK_WIDGET(g_object_get_data(G_OBJECT(dialog),
                                            "identity-gpgencrypt")),
                       TRUE);
    ident_dialog_add_option_menu(table, row++, dialog,
                         _("default crypto protocol"),
                         "identity-crypt-protocol");
    gtk_widget_set_sensitive(GTK_WIDGET(g_object_get_data(G_OBJECT(dialog),
                                            "identity-crypt-protocol")),
                       TRUE);
#endif

    name = g_object_get_data(G_OBJECT(dialog), "identity-name");
    g_signal_connect(name, "changed",
                     G_CALLBACK(md_name_changed), tree);
    sig_path = g_object_get_data(G_OBJECT(dialog), "identity-sigpath");
    g_signal_connect(sig_path, "changed",
                     G_CALLBACK(md_sig_path_changed), dialog);

    return GTK_WIDGET(frame);
}

/* Callback for the "changed" signal of the name entry; updates the name
 * in the tree. */
static void
md_name_changed(GtkEntry * name, GtkTreeView * tree)
{
    set_identity_name_in_tree(tree, get_selected_identity(tree),
                        gtk_entry_get_text(name));
}

/* Callback for the "changed" signal of the signature path entry; sets
 * sensitivity of the signature-related buttons; checks only for a
 * non-empty string, not for a valid path. */
static void
md_sig_path_changed(GtkEntry * sig_path, GObject * dialog)
{
    guint i;
    static gchar *button_key[] = {
        "identity-sigexecutable",
        "identity-sigappend",
        "identity-whenforward",
        "identity-whenreply",
        "identity-sigseparator",
        "identity-sigprepend",
    };
    gboolean has_sig = *gtk_entry_get_text(sig_path);

    for (i = 0; i < ELEMENTS(button_key); i++) {
        GtkWidget *button = g_object_get_data(dialog, button_key[i]);
        gtk_widget_set_sensitive(button, has_sig);
    }
}

/*
 * Create and add a GtkCheckButton to the given dialog with caption
 * and add a pointer to it stored under the given key.  The check
 * button is initialized to the given value.
 */
static void
ident_dialog_add_checkbutton(GtkWidget * table, gint row,
                             GtkDialog * dialog, const gchar * check_label,
                             const gchar * check_key)
{
    GtkWidget *check;

    check = gtk_check_button_new_with_mnemonic(check_label);
    gtk_table_attach_defaults(GTK_TABLE(table), check, 0, 2, row, row + 1);
    g_object_set_data(G_OBJECT(dialog), check_key, check);
    gtk_widget_set_sensitive(check, FALSE);
}


/*
 * Add a GtkEntry to the given dialog with a label next to it
 * explaining the contents.  A reference to the entry is stored as
 * object data attached to the dialog with the given key.  The entry
 * is initialized to the init_value given.
 */
static void
ident_dialog_add_entry(GtkWidget * table, gint row, GtkDialog * dialog,
                       const gchar * label_name, const gchar * entry_key)
{
    GtkWidget *label;
    GtkWidget *entry;

    label = gtk_label_new_with_mnemonic(label_name);
    gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
    gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, row, row + 1);

    entry = gtk_entry_new();
    gtk_table_attach_defaults(GTK_TABLE(table), entry, 1, 2, row, row + 1);

    g_object_set_data(G_OBJECT(dialog), entry_key, entry);
    if (row == 0)
        gtk_widget_grab_focus(entry);
    gtk_label_set_mnemonic_widget(GTK_LABEL(label), entry);
}

/* set_identity_name_in_tree:
 * update the tree to reflect the (possibly) new name of the identity
 */
static void
set_identity_name_in_tree(GtkTreeView * tree, LibBalsaIdentity * identity,
                  const gchar * name)
{
    GtkTreeModel *model = gtk_tree_view_get_model(tree);
    GtkTreeIter iter;
    gboolean valid;

    for (valid =
         gtk_tree_model_get_iter_first(model, &iter);
         valid;
         valid = gtk_tree_model_iter_next(model, &iter)) {
        LibBalsaIdentity *tmp;

        gtk_tree_model_get(model, &iter, IDENT_COLUMN, &tmp, -1);
        if (identity == tmp) {
            gtk_list_store_set(GTK_LIST_STORE(model), &iter,
                               NAME_COLUMN, name, -1);
            break;
        }
    }
}

/* 
 * Update the identity object associated with the edit/new dialog,
 * validating along the way.  Correct validation results in a true
 * return value, otherwise it returns false.
 */

static gboolean
ident_dialog_update(GtkDialog* dlg)
{
    LibBalsaIdentity* id;
    LibBalsaIdentity* exist_ident;
    InternetAddress *ia;
    GtkWidget *tree;
    GList **identities, *list;
    gchar* text;
    
    id = g_object_get_data(G_OBJECT(dlg), "identity");
    if (!id)
        return TRUE;
    tree = g_object_get_data(G_OBJECT(dlg), "tree");
    identities = g_object_get_data(G_OBJECT(tree), "identities");

    text = ident_dialog_get_text(dlg, "identity-name");
    g_return_val_if_fail(text != NULL, FALSE);

    if (text[0] == '\0') {
        libbalsa_information(LIBBALSA_INFORMATION_ERROR,
                             _("Error: The identity does not have a name"));
        return FALSE;
    }

    for (list = *identities; list; list = g_list_next(list)) {
        exist_ident = LIBBALSA_IDENTITY(list->data);
        
        if (g_ascii_strcasecmp(exist_ident->identity_name, text) == 0
            && id != exist_ident) {
            libbalsa_information(LIBBALSA_INFORMATION_ERROR,
                                 _("Error: An identity with that"
                                   " name already exists"));
            return FALSE;
        }
    }

    g_free(id->identity_name); id->identity_name = text;
    set_identity_name_in_tree(GTK_TREE_VIEW(tree), id, text);

    text = ident_dialog_get_text(dlg, "identity-fullname");
    g_return_val_if_fail(text != NULL, FALSE);
    ia = internet_address_new();
    internet_address_set_name(ia, text);
    g_free(text);
    
    text = ident_dialog_get_text(dlg, "identity-address");
    internet_address_set_addr(ia, text);
    g_free(text);
    libbalsa_identity_set_address(id, ia);

    g_free(id->replyto);
    id->replyto         = ident_dialog_get_text(dlg, "identity-replyto");
    g_free(id->domain);
    id->domain          = ident_dialog_get_text(dlg, "identity-domain");    
    g_free(id->bcc);
    id->bcc             = ident_dialog_get_text(dlg, "identity-bcc");
    g_free(id->reply_string);
    id->reply_string    = ident_dialog_get_text(dlg, "identity-replystring");
    g_free(id->forward_string);
    id->forward_string  = ident_dialog_get_text(dlg, "identity-forwardstring");
    g_free(id->signature_path);
    id->signature_path  = ident_dialog_get_text(dlg, "identity-sigpath");
    
    id->sig_executable  = ident_dialog_get_bool(dlg, "identity-sigexecutable");
    id->sig_sending     = ident_dialog_get_bool(dlg, "identity-sigappend");
    id->sig_whenforward = ident_dialog_get_bool(dlg, "identity-whenforward");
    id->sig_whenreply   = ident_dialog_get_bool(dlg, "identity-whenreply");
    id->sig_separator   = ident_dialog_get_bool(dlg, "identity-sigseparator");
    id->sig_prepend     = ident_dialog_get_bool(dlg, "identity-sigprepend");
   
#ifdef HAVE_GPGME
    id->gpg_sign        = ident_dialog_get_bool(dlg, "identity-gpgsign");
    id->gpg_encrypt     = ident_dialog_get_bool(dlg, "identity-gpgencrypt");
    id->crypt_protocol  = ident_dialog_get_menu(dlg, "identity-crypt-protocol");
#endif
   
    return TRUE;
}


/* 
 * Get the text from an entry in the editing/creation dialog.  The
 * given key accesses the entry using object data.
 */
static gchar*
ident_dialog_get_text(GtkDialog* dialog, const gchar* key)
{
    GtkEntry* entry;
    gchar* text;
    
    entry = GTK_ENTRY(g_object_get_data(G_OBJECT(dialog), key));
    text = gtk_editable_get_chars(GTK_EDITABLE(entry), 0, -1);

    return text;
}


/*
 * Get the value of a check button from the editing dialog.  The key
 * is used to retreive the reference to the check button using object
 * data
 */
static gboolean
ident_dialog_get_bool(GtkDialog* dialog, const gchar* key)
{
    GtkCheckButton* button;
    gboolean value;
    
    button = GTK_CHECK_BUTTON(g_object_get_data(G_OBJECT(dialog), key));
    value = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button));
    
    return value;
}

/* 
 * Set the default identity to the currently selected.
 */
static void
set_default_ident_cb(GtkTreeView * tree, GtkTreePath * path,
                     GtkTreeViewColumn * column, gpointer data)
{
    LibBalsaIdentity *ident, **default_id;

    default_id = g_object_get_data(G_OBJECT(tree), "default-id");
    ident = get_selected_identity(tree);
    g_return_if_fail(ident != NULL);
    *default_id = ident;

    identity_list_update(tree);
}


/*
 * Confirm the deletion of an identity, do the actual deletion here,
 * and close the dialog.
 */
static void
identity_delete_selected(GtkTreeView * tree, GtkWidget * dialog)
{
    GtkTreeSelection *selection = gtk_tree_view_get_selection(tree);
    GtkTreeModel *model;
    GtkTreeIter iter;
    GtkTreePath *path;
    LibBalsaIdentity *ident;
    GList **identities;
    void (*cb)(gpointer) = g_object_get_data(G_OBJECT(tree), "callback");
    gpointer data        = g_object_get_data(G_OBJECT(tree), "cb-data");

    /* Save the path to the current row. */
    if (!gtk_tree_selection_get_selected(selection, &model, &iter))
        return;
    path = gtk_tree_model_get_path(model, &iter);

    ident = get_selected_identity(tree);
    identities = g_object_get_data(G_OBJECT(tree), "identities");
    *identities = g_list_remove(*identities, ident);
    g_object_set_data(G_OBJECT(dialog), "identity", NULL);
    identity_list_update(tree);
    g_object_unref(ident);

    /* Select the row at the saved path, or the previous one. */
    if (gtk_tree_model_get_iter(model, &iter, path)
        || gtk_tree_path_prev(path)) {
        gtk_tree_view_set_cursor(tree, path, NULL, FALSE);
        gtk_tree_view_scroll_to_cell(tree, path, NULL,
                                     FALSE, 0, 0);
    }
    gtk_tree_path_free(path);
    gtk_widget_grab_focus(GTK_WIDGET(tree));
    cb(data);
}

/* 
 * Delete the currently selected identity after confirming. 
 */
struct _IdentityDeleteInfo {
    GtkTreeView *tree;
    GtkWidget *dialog;
};
static void
delete_ident_cb(GtkTreeView * tree, GtkWidget * dialog)
{
    LibBalsaIdentity* ident, **default_id;
    GtkWidget* confirm;
    IdentityDeleteInfo *di;
    
    ident = get_selected_identity(tree);
    default_id = g_object_get_data(G_OBJECT(tree), "default-id");
    g_return_if_fail(ident != *default_id);
    confirm = gtk_message_dialog_new(GTK_WINDOW(dialog),
                                     GTK_DIALOG_DESTROY_WITH_PARENT,
                                     GTK_MESSAGE_QUESTION,
                                     GTK_BUTTONS_OK_CANCEL,
                                     _("Do you really want to delete"
                                       " the selected identity?"));
    di = g_new(IdentityDeleteInfo, 1);
    di->tree = tree;
    di->dialog = dialog;
    g_signal_connect(G_OBJECT(confirm), "response",
                     G_CALLBACK(delete_ident_response), di);
    g_object_weak_ref(G_OBJECT(confirm), (GWeakNotify) g_free, di);
    gtk_widget_set_sensitive(dialog, FALSE);
    gtk_widget_show_all(confirm);
}

static void 
delete_ident_response(GtkWidget * confirm, gint response,
                      IdentityDeleteInfo * di)
{
    if(response == GTK_RESPONSE_OK)
        identity_delete_selected(di->tree, di->dialog);
    gtk_widget_set_sensitive(di->dialog, TRUE);
    gtk_widget_destroy(confirm);
}

/*
 * Show the help file.
 */
static void
help_ident_cb(void)
{
    GError *err = NULL;

#ifdef HAVE_GNOME
    gnome_help_display("balsa", "identities", &err);
#endif

    if (err) {
        g_print(_("Error displaying help for identities: %s\n"),
                err->message);
        g_error_free(err);
    }
}

/* libbalsa_identity_config_dialog displays an identity management
   dialog. The dialog has a specified parent, existing list of
   identites, the default one. Additionally, a callback is passed that
   will be executed when the identity list is modified: new entries
   are added or other entries are removed. */
void
libbalsa_identity_config_dialog(GtkWindow *parent, GList **identities,
                        LibBalsaIdentity **default_id,
                                void (*changed_cb)(gpointer))
{
    static GtkWidget *dialog = NULL;
    GtkWidget* frame;
    GtkWidget* display_frame;
    GtkWidget* hbox;
    GtkTreeView* tree;
    GtkTreeSelection *select;

    /* Show only one dialog at a time. */
    if (dialog) {
        gdk_window_raise(dialog->window);
        return;
    }

    dialog =
        gtk_dialog_new_with_buttons(_("Manage Identities"),
                                    parent, /* must NOT be modal */
                                    GTK_DIALOG_DESTROY_WITH_PARENT,
                                    GTK_STOCK_HELP, IDENTITY_RESPONSE_HELP,
                                    GTK_STOCK_NEW, IDENTITY_RESPONSE_NEW,
                                    GTK_STOCK_REMOVE, IDENTITY_RESPONSE_REMOVE,
                                    GTK_STOCK_CLOSE, IDENTITY_RESPONSE_CLOSE,
                                    NULL);

    frame = libbalsa_identity_config_frame(identities, default_id, dialog,
                                           changed_cb, parent);
    tree = GTK_TREE_VIEW(gtk_bin_get_child(GTK_BIN(frame)));

    g_signal_connect(G_OBJECT(dialog), "response",
                     G_CALLBACK(md_response_cb), tree);
    g_object_set_data(G_OBJECT(dialog), "tree", tree);
    g_object_add_weak_pointer(G_OBJECT(dialog), (gpointer) & dialog);
    gtk_dialog_set_default_response(GTK_DIALOG(dialog),
                                    IDENTITY_RESPONSE_CLOSE);

    hbox = gtk_hbox_new(FALSE, padding);
    gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), 
                       hbox, TRUE, TRUE, 0);

    gtk_box_pack_start(GTK_BOX(hbox), frame, FALSE, FALSE, 0);

    display_frame = setup_ident_frame(GTK_DIALOG(dialog),
                                      FALSE, tree);
    gtk_box_pack_start(GTK_BOX(hbox), display_frame, TRUE, TRUE, 0);

    select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree));
    g_signal_connect(G_OBJECT(select), "changed",
                     G_CALLBACK(config_frame_button_select_cb), dialog);
    config_dialog_select(select, GTK_DIALOG(dialog));

    gtk_widget_show_all(dialog);
    gtk_widget_grab_focus(GTK_WIDGET(tree));
}

/* Callback for the "response" signal of the dialog. */
static void
md_response_cb(GtkWidget * dialog, gint response, GtkTreeView * tree)
{
    switch (response) {
    case IDENTITY_RESPONSE_CLOSE:
        if (close_cb(dialog))
            break;
        return;
    case IDENTITY_RESPONSE_NEW:
        new_ident_cb(tree, dialog);
        return;
    case IDENTITY_RESPONSE_REMOVE:
        delete_ident_cb(tree, dialog);
        return;
    case IDENTITY_RESPONSE_HELP:
        help_ident_cb();
        return;
    default:
        break;
    }

    gtk_widget_destroy(dialog);
}

/* config_dialog_select
 *
 * called when the tree's selection changes
 * manage the button sensitivity, and update the display frame
 */
static void
config_dialog_select(GtkTreeSelection * selection, GtkDialog * dialog)
{
    LibBalsaIdentity *ident, **default_id;
    GtkTreeView *tree = gtk_tree_selection_get_tree_view(selection);

    ident = get_selected_identity(tree);
    default_id = g_object_get_data(G_OBJECT(tree), "default-id");
    gtk_dialog_set_response_sensitive(dialog, IDENTITY_RESPONSE_REMOVE,
                                      ident && ident != *default_id);
    display_frame_update(dialog, ident);
    g_object_set_data(G_OBJECT(dialog), "identity", ident);
}

static void 
display_frame_update(GtkDialog * dialog, LibBalsaIdentity* ident)
{
    if (!ident)
        return;

    ident_dialog_update(dialog);
    display_frame_set_field(dialog, "identity-name", ident->identity_name);
    display_frame_set_field(dialog, "identity-fullname", ident->ia->name);
    if (ident->ia->type == INTERNET_ADDRESS_NAME)
        display_frame_set_field(dialog, "identity-address", 
                                ident->ia->value.addr);
    else
        display_frame_set_field(dialog, "identity-address", NULL);
    
    display_frame_set_field(dialog, "identity-replyto", ident->replyto);
    display_frame_set_field(dialog, "identity-domain", ident->domain);
    display_frame_set_field(dialog, "identity-bcc", ident->bcc);
    display_frame_set_field(dialog, "identity-replystring", 
                            ident->reply_string);
    display_frame_set_field(dialog, "identity-forwardstring", 
                            ident->forward_string);
    display_frame_set_field(dialog, "identity-sigpath", ident->signature_path);

    display_frame_set_boolean(dialog, "identity-sigexecutable", ident->sig_executable);

    display_frame_set_boolean(dialog, "identity-sigappend", ident->sig_sending);
    display_frame_set_boolean(dialog, "identity-whenforward", 
                              ident->sig_whenforward);
    display_frame_set_boolean(dialog, "identity-whenreply", 
                              ident->sig_whenreply);
    display_frame_set_boolean(dialog, "identity-sigseparator", 
                              ident->sig_separator);    
    display_frame_set_boolean(dialog, "identity-sigprepend", 
                              ident->sig_prepend);    

#ifdef HAVE_GPGME
    display_frame_set_boolean(dialog, "identity-gpgsign", 
                              ident->gpg_sign);    
    display_frame_set_boolean(dialog, "identity-gpgencrypt", 
                              ident->gpg_encrypt);    
    display_frame_set_menu(dialog, "identity-crypt-protocol",
                     &ident->crypt_protocol);
#endif
}


static void
display_frame_set_field(GtkDialog * dialog,
                        const gchar* key,
                        const gchar* value)
{
    GtkEntry *entry = GTK_ENTRY(g_object_get_data(G_OBJECT(dialog), key));
    
    gtk_entry_set_text(entry, value ? value : "");
}

static void
display_frame_set_boolean(GtkDialog * dialog,
                          const gchar* key,
                          gboolean value)
{
    GtkCheckButton *check =
        GTK_CHECK_BUTTON(g_object_get_data(G_OBJECT(dialog), key));
    
    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), value);
}


/* libbalsa_identity_new_config:
   factory-type method creating new Identity object from given
   configuration data.
*/
LibBalsaIdentity*
libbalsa_identity_new_config(const gchar* prefix, const gchar* name)
{
    LibBalsaIdentity* ident;
    gchar* tmpstr;
    
    g_return_val_if_fail(prefix != NULL, NULL);

    libbalsa_conf_push_prefix(prefix);

    ident = LIBBALSA_IDENTITY(libbalsa_identity_new_with_name(name));

    tmpstr = libbalsa_conf_get_string("FullName");
    internet_address_set_name(ident->ia, tmpstr);
    g_free(tmpstr);

    tmpstr = libbalsa_conf_get_string("Address");
    internet_address_set_addr(ident->ia, tmpstr);
    g_free(tmpstr);

    ident->replyto = libbalsa_conf_get_string("ReplyTo");
    ident->domain = libbalsa_conf_get_string("Domain");
    ident->bcc = libbalsa_conf_get_string("Bcc");

    /* 
     * these two have defaults, so we need to use the appropriate
     * functions to manage the memory. 
     */
    if ((tmpstr = libbalsa_conf_get_string("ReplyString"))) {
        g_free(ident->reply_string);
        ident->reply_string = tmpstr;
    }
    
    if ((tmpstr = libbalsa_conf_get_string("ForwardString"))) {
        g_free(ident->forward_string);
        ident->forward_string = tmpstr;
    }
    
    ident->signature_path = libbalsa_conf_get_string("SignaturePath");
    ident->sig_executable = libbalsa_conf_get_bool("SigExecutable");
    ident->sig_sending = libbalsa_conf_get_bool("SigSending");
    ident->sig_whenforward = libbalsa_conf_get_bool("SigForward");
    ident->sig_whenreply = libbalsa_conf_get_bool("SigReply");
    ident->sig_separator = libbalsa_conf_get_bool("SigSeparator");
    ident->sig_prepend = libbalsa_conf_get_bool("SigPrepend");

#ifdef HAVE_GPGME
    ident->gpg_sign = libbalsa_conf_get_bool("GpgSign");
    ident->gpg_encrypt = libbalsa_conf_get_bool("GpgEncrypt");
    ident->crypt_protocol = libbalsa_conf_get_int("CryptProtocol=16");
#endif

    libbalsa_conf_pop_prefix();

    return ident;
}

void 
libbalsa_identity_save(LibBalsaIdentity* ident, const gchar* prefix)
{
    g_return_if_fail(ident);

    libbalsa_conf_push_prefix(prefix);
    libbalsa_conf_set_string("FullName", ident->ia->name);
    
    if (ident->ia->type == INTERNET_ADDRESS_NAME)
        libbalsa_conf_set_string("Address", ident->ia->value.addr);

    libbalsa_conf_set_string("ReplyTo", ident->replyto);
    libbalsa_conf_set_string("Domain", ident->domain);
    libbalsa_conf_set_string("Bcc", ident->bcc);
    libbalsa_conf_set_string("ReplyString", ident->reply_string);
    libbalsa_conf_set_string("ForwardString", ident->forward_string);
    libbalsa_conf_set_string("SignaturePath", ident->signature_path);

    libbalsa_conf_set_bool("SigExecutable", ident->sig_executable);
    libbalsa_conf_set_bool("SigSending", ident->sig_sending);
    libbalsa_conf_set_bool("SigForward", ident->sig_whenforward);
    libbalsa_conf_set_bool("SigReply", ident->sig_whenreply);
    libbalsa_conf_set_bool("SigSeparator", ident->sig_separator);
    libbalsa_conf_set_bool("SigPrepend", ident->sig_prepend);

#ifdef HAVE_GPGME
    libbalsa_conf_set_bool("GpgSign", ident->gpg_sign);
    libbalsa_conf_set_bool("GpgEncrypt", ident->gpg_encrypt);
    libbalsa_conf_set_int("CryptProtocol", ident->crypt_protocol);
#endif

    libbalsa_conf_pop_prefix();
}


#ifdef HAVE_GPGME
/* collected helper stuff for GPGME support */

void
libbalsa_identity_set_gpg_sign(LibBalsaIdentity* ident, gboolean sign)
{
    g_return_if_fail(ident != NULL);
    ident->gpg_sign = sign;
}


void
libbalsa_identity_set_gpg_encrypt(LibBalsaIdentity* ident, gboolean encrypt)
{
    g_return_if_fail(ident != NULL);
    ident->gpg_encrypt = encrypt;
}


void
libbalsa_identity_set_crypt_protocol(LibBalsaIdentity* ident, gint protocol)
{
    g_return_if_fail(ident != NULL);
    ident->crypt_protocol = protocol;
}


static void
add_show_menu(const char* label, gint value, GtkWidget* menu)
{
    GArray *values = g_object_get_data(G_OBJECT(menu), "identity-value");
    gtk_combo_box_append_text(GTK_COMBO_BOX(menu), label);
    g_array_append_val(values, value);
}


/*
 * Add an option menu to the given dialog with a label next to it
 * explaining the contents.  A reference to the entry is stored as
 * object data attached to the dialog with the given key.
 */
static void
ident_dialog_free_values(GArray * values)
{
    g_array_free(values, TRUE);
}

static void
ident_dialog_add_option_menu(GtkWidget * table, gint row, GtkDialog * dialog,
                             const gchar * label_name, const gchar * menu_key)
{
    GtkWidget *label;
    GtkWidget *opt_menu;
    GArray *values;

    label = gtk_label_new_with_mnemonic(label_name);
    gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
    gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, row, row + 1);

    opt_menu = gtk_combo_box_new_text();
    values = g_array_new(FALSE, FALSE, sizeof(gint));
    g_object_set_data_full(G_OBJECT(opt_menu), "identity-value", values,
                           (GDestroyNotify) ident_dialog_free_values);
    gtk_table_attach_defaults(GTK_TABLE(table), opt_menu, 1, 2, row, row + 1);
    g_object_set_data(G_OBJECT(dialog), menu_key, opt_menu);

    add_show_menu(_("GnuPG using MIME mode"), LIBBALSA_PROTECT_RFC3156,
                  opt_menu);
    add_show_menu(_("GnuPG using OpenPGP mode"), LIBBALSA_PROTECT_OPENPGP,
                  opt_menu);
#ifdef HAVE_SMIME
    add_show_menu(_("S/MIME mode"), LIBBALSA_PROTECT_SMIMEV3, opt_menu);
#endif
}


/*
 * Get the value of the active option menu item
 */
static gint
ident_dialog_get_menu(GtkDialog * dialog, const gchar * key)
{
    GtkWidget * menu;
    gint value;
    GArray *values;

    menu = g_object_get_data(G_OBJECT(dialog), key);
    value = gtk_combo_box_get_active(GTK_COMBO_BOX(menu));
    values = g_object_get_data(G_OBJECT(menu), "identity-value");
    
    return g_array_index(values, gint, value);
}


static void
display_frame_set_menu(GtkDialog * dialog, const gchar* key, gint * value)
{
    GtkComboBox *opt_menu = g_object_get_data(G_OBJECT(dialog), key);
 
    switch (*value)
        {
        case LIBBALSA_PROTECT_OPENPGP:
          gtk_combo_box_set_active(opt_menu, 1);
            break;
#ifdef HAVE_SMIME
        case LIBBALSA_PROTECT_SMIMEV3:
          gtk_combo_box_set_active(opt_menu, 2);
            break;
#endif
        case LIBBALSA_PROTECT_RFC3156:
        default:
          gtk_combo_box_set_active(opt_menu, 0);
            *value = LIBBALSA_PROTECT_RFC3156;
        }
}

#endif  /* HAVE_GPGME */

Generated by  Doxygen 1.6.0   Back to index