Desktop
/* $Id: mailer.c,v 1.89 2011/06/27 01:03:29 khorben Exp $ */
/* Copyright (c) 2011 Pierre Pronchery <khorben@defora.org> */
/* This file is part of DeforaOS Desktop Mailer */
/* 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, version 3 of the License.
*
* 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, see <http://www.gnu.org/licenses/>. */
#include <dirent.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <libintl.h>
#include <gdk/gdkkeysyms.h>
#include <Desktop.h>
#include "folder.h"
#include "message.h"
#include "compose.h"
#include "callbacks.h"
#include "mailer.h"
#include "../config.h"
#include "common.c"
#define _(string) gettext(string)
#define N_(string) (string)
/* constants */
#ifndef PREFIX
# define PREFIX "/usr/local"
#endif
#ifndef LIBDIR
# define LIBDIR PREFIX "/lib"
#endif
#ifndef PLUGINDIR
# define PLUGINDIR LIBDIR "/Mailer"
#endif
/* Mailer */
/* private */
/* types */
struct _Mailer
{
Account ** available; /* XXX consider using another data type */
unsigned int available_cnt;
Account ** account;
unsigned int account_cnt;
Account * account_cur;
Folder * folder_cur;
guint source;
/* configuration */
Config * config;
/* widgets */
/* folders */
GtkWidget * fo_window;
GtkTreeStore * fo_store;
GtkWidget * fo_view;
/* headers */
GtkWidget * he_window;
GtkWidget * he_view;
GtkTreeViewColumn * he_view_from;
GtkTreeViewColumn * he_view_to;
/* body */
GtkWidget * bo_window;
GtkWidget * hdr_vbox;
GtkWidget * hdr_subject;
GtkWidget * hdr_from;
GtkWidget * hdr_to;
GtkWidget * hdr_date;
GtkTextBuffer * bo_buffer;
GtkWidget * bo_view;
GtkWidget * statusbar;
gint statusbar_id;
/* about */
GtkWidget * ab_window;
/* preferences */
GtkWidget * pr_window;
GtkWidget * pr_accounts;
GtkWidget * pr_messages_font;
};
/* FIXME use a more elegant model with an AccountMessage directly */
typedef void (*MailerForeachMessageCallback)(Mailer * mailer,
GtkTreeModel * model, GtkTreeIter * iter);
/* constants */
static const char * _title[3] =
{
N_("New account"), N_("Account settings"), N_("Account confirmation")
};
/* variables */
#ifdef EMBEDDED
static DesktopAccel _mailer_accel[] =
{
{ G_CALLBACK(on_quit), GDK_CONTROL_MASK, GDK_KEY_Q },
{ G_CALLBACK(on_view_source), GDK_CONTROL_MASK, GDK_KEY_U },
{ NULL, 0, 0 }
};
#endif
#ifndef EMBEDDED
static DesktopMenu _menu_file[] =
{
{ N_("_New mail"), G_CALLBACK(on_file_new_mail), "stock_mail-compose",
GDK_CONTROL_MASK, GDK_KEY_N },
{ "", NULL, NULL, 0, 0 },
{ N_("Send / Receive"), NULL, "stock_mail-send-receive",
GDK_CONTROL_MASK, GDK_KEY_R },
{ "", NULL, NULL, 0, 0 },
{ N_("_Print"), NULL, GTK_STOCK_PRINT, GDK_CONTROL_MASK, GDK_KEY_P },
{ N_("Print pre_view"), NULL, GTK_STOCK_PRINT_PREVIEW, GDK_CONTROL_MASK,
0 },
{ "", NULL, NULL, 0, 0 },
{ N_("_Quit"), G_CALLBACK(on_file_quit), GTK_STOCK_QUIT,
GDK_CONTROL_MASK, GDK_KEY_Q },
{ NULL, NULL, NULL, 0, 0 }
};
static DesktopMenu _menu_edit[] =
{
{ N_("_Cut"), G_CALLBACK(on_edit_cut), GTK_STOCK_CUT, GDK_CONTROL_MASK,
GDK_KEY_X },
{ N_("Cop_y"), G_CALLBACK(on_edit_copy), GTK_STOCK_COPY,
GDK_CONTROL_MASK, GDK_KEY_C },
{ N_("_Paste"), G_CALLBACK(on_edit_paste), GTK_STOCK_PASTE,
GDK_CONTROL_MASK, GDK_KEY_V },
{ "", NULL, NULL, 0, 0 },
{ N_("Select _all"), G_CALLBACK(on_edit_select_all),
#if GTK_CHECK_VERSION(2, 10, 0)
GTK_STOCK_SELECT_ALL,
#else
"edit-select-all",
#endif
GDK_CONTROL_MASK, GDK_KEY_A },
{ N_("_Unselect all"), G_CALLBACK(on_edit_unselect_all), NULL, 0, 0 },
{ "", NULL, NULL, 0, 0 },
{ N_("_Preferences"), G_CALLBACK(on_edit_preferences),
GTK_STOCK_PREFERENCES, 0, 0 },
{ NULL, NULL, NULL, 0, 0 }
};
static DesktopMenu _menu_message[] =
{
{ N_("_Reply"), G_CALLBACK(on_message_reply), "stock_mail-reply", 0,
0 },
{ N_("Reply to _all"), G_CALLBACK(on_message_reply_to_all),
"stock_mail-reply-to-all", 0, 0 },
{ N_("_Forward"), G_CALLBACK(on_message_forward), "stock_mail-forward",
0, 0 },
{ "", NULL, NULL, 0, 0 },
{ N_("_Delete"), G_CALLBACK(on_message_delete), GTK_STOCK_DELETE, 0,
GDK_KEY_Delete },
{ "", NULL, NULL, 0, 0 },
{ N_("_View source"), G_CALLBACK(on_message_view_source), NULL,
GDK_CONTROL_MASK, GDK_KEY_U },
{ NULL, NULL, NULL, 0, 0 }
};
static DesktopMenu _menu_help[] =
{
#if GTK_CHECK_VERSION(2, 6, 0)
{ N_("_About"), G_CALLBACK(on_help_about), GTK_STOCK_ABOUT, 0, 0 },
#else
{ N_("_About"), G_CALLBACK(on_help_about), NULL, 0, 0 },
#endif
{ NULL, NULL, NULL, 0, 0 }
};
static DesktopMenubar _mailer_menubar[] =
{
{ N_("_File"), _menu_file },
{ N_("_Edit"), _menu_edit },
{ N_("_Message"), _menu_message },
{ N_("_Help"), _menu_help },
{ NULL, NULL }
};
#endif
static DesktopToolbar _mailer_fo_toolbar[] =
{
{ N_("New mail"), G_CALLBACK(on_file_new_mail), "stock_mail-compose", 0,
0, NULL },
{ "", NULL, NULL, 0, 0, NULL },
{ N_("Send / Receive"), NULL, "stock_mail-send-receive", 0, 0, NULL },
{ N_("Stop"), NULL, GTK_STOCK_STOP, 0, GDK_KEY_Escape, NULL },
{ "", NULL, NULL, 0, 0, NULL },
#ifndef EMBEDDED
{ N_("Reply"), G_CALLBACK(on_reply), "stock_mail-reply", 0, 0, NULL },
{ N_("Reply to all"), G_CALLBACK(on_reply_to_all),
"stock_mail-reply-to-all", 0, 0, NULL },
{ N_("Forward"), G_CALLBACK(on_forward), "stock_mail-forward", 0, 0,
NULL},
#endif
{ N_("Delete"), G_CALLBACK(on_delete), GTK_STOCK_DELETE, 0, 0, NULL },
{ N_("Print"), NULL, GTK_STOCK_PRINT, 0, 0, NULL },
#ifdef EMBEDDED
{ "", NULL, NULL, 0, 0, NULL },
{ N_("Preferences"), G_CALLBACK(on_preferences), GTK_STOCK_PREFERENCES,
0, 0, NULL },
#endif
{ NULL, NULL, NULL, 0, 0, NULL }
};
#ifdef EMBEDDED
static DesktopToolbar _mailer_he_toolbar[] =
{
{ N_("New mail"), G_CALLBACK(on_file_new_mail), "stock_mail-compose", 0,
0, NULL },
{ "", NULL, NULL, 0, 0, NULL },
{ N_("Reply"), G_CALLBACK(on_reply), "stock_mail-reply", 0, 0, NULL },
{ N_("Reply to all"), G_CALLBACK(on_reply_to_all),
"stock_mail-reply-to-all", 0, 0, NULL },
{ N_("Forward"), G_CALLBACK(on_forward), "stock_mail-forward", 0, 0,
NULL},
{ N_("Delete"), G_CALLBACK(on_delete), GTK_STOCK_DELETE, 0, 0, NULL },
{ NULL, NULL, NULL, 0, 0, NULL }
};
static DesktopToolbar _mailer_bo_toolbar[] =
{
{ N_("New mail"), G_CALLBACK(on_file_new_mail), "stock_mail-compose", 0,
0, NULL },
{ "", NULL, NULL, 0, 0, NULL },
{ N_("Reply"), G_CALLBACK(on_reply), "stock_mail-reply", 0, 0, NULL },
{ N_("Reply to all"), G_CALLBACK(on_reply_to_all),
"stock_mail-reply-to-all", 0, 0, NULL },
{ N_("Forward"), G_CALLBACK(on_forward), "stock_mail-forward", 0, 0,
NULL},
{ N_("Delete"), G_CALLBACK(on_delete), GTK_STOCK_DELETE, 0, 0, NULL },
{ N_("Print"), NULL, GTK_STOCK_PRINT, 0, 0, NULL },
{ NULL, NULL, NULL, 0, 0, NULL }
};
#endif
/* prototypes */
static int _mailer_config_load_account(Mailer * mailer, char const * name);
static gboolean _mailer_confirm(Mailer * mailer, char const * message);
static void _mailer_foreach_message_selected(Mailer * mailer,
MailerForeachMessageCallback callback);
static char * _mailer_get_config_filename(void);
static void _mailer_update_status(Mailer * mailer);
/* functions */
static int _mailer_config_load_account(Mailer * mailer, char const * name)
{
Account * account;
char const * type;
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s(\"%s\")\n", __func__, name);
#endif
if((type = config_get(mailer->config, name, "type")) == NULL)
return -1;
if((account = account_new(mailer, type, name, mailer->fo_store))
== NULL)
return -mailer_error(mailer, error_get(), 1);
account_config_load(account, mailer->config);
mailer_account_add(mailer, account);
return 0;
}
/* public */
/* functions */
/* mailer_new */
static int _new_plugins(Mailer * mailer);
static GtkWidget * _new_folders_view(Mailer * mailer);
static void _on_folders_changed(GtkTreeSelection * selection, gpointer data);
static GtkWidget * _new_headers_view(Mailer * mailer);
static GtkWidget * _new_headers(Mailer * mailer);
static GtkTreeViewColumn * _headers_view_column_pixbuf(GtkTreeView * view,
char const * title, int id, int sortid);
static GtkTreeViewColumn * _headers_view_column_text(GtkTreeView * view,
char const * title, int id, int sortid, int boldid);
static void _on_headers_changed(GtkTreeSelection * selection, gpointer data);
static gboolean _new_config_load(gpointer data);
Mailer * mailer_new(void)
{
Mailer * mailer;
GtkAccelGroup * group;
GtkWidget * vbox;
GtkWidget * vbox2;
#ifndef EMBEDDED
GtkWidget * hpaned;
GtkWidget * vpaned;
#endif
GtkWidget * widget;
if((mailer = object_new(sizeof(*mailer))) == NULL)
{
error_print("mailer");
return NULL;
}
_new_plugins(mailer);
mailer->account = NULL;
mailer->account_cnt = 0;
mailer->account_cur = NULL;
mailer->folder_cur = NULL;
/* widgets */
group = gtk_accel_group_new();
mailer->fo_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_add_accel_group(GTK_WINDOW(mailer->fo_window), group);
#ifndef EMBEDDED
gtk_window_set_default_size(GTK_WINDOW(mailer->fo_window), 800, 600);
gtk_window_set_title(GTK_WINDOW(mailer->fo_window), _("Mailer"));
#else
gtk_window_set_default_size(GTK_WINDOW(mailer->fo_window), 200, 300);
gtk_window_set_title(GTK_WINDOW(mailer->fo_window), _("Folders"));
#endif
#if GTK_CHECK_VERSION(2, 6, 0)
gtk_window_set_icon_name(GTK_WINDOW(mailer->fo_window), "mailer");
#endif
g_signal_connect_swapped(G_OBJECT(mailer->fo_window), "delete-event",
G_CALLBACK(on_closex), mailer);
vbox = gtk_vbox_new(FALSE, 0);
/* menubar */
#ifndef EMBEDDED
widget = desktop_menubar_create(_mailer_menubar, mailer, group);
gtk_box_pack_start(GTK_BOX(vbox), widget, FALSE, FALSE, 0);
#else
desktop_accel_create(_mailer_accel, mailer, group);
#endif
/* toolbar */
widget = desktop_toolbar_create(_mailer_fo_toolbar, mailer, group);
gtk_box_pack_start(GTK_BOX(vbox), widget, FALSE, TRUE, 0);
/* folders */
widget = gtk_scrolled_window_new(NULL, NULL);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(widget),
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
mailer->fo_view = _new_folders_view(mailer);
gtk_container_add(GTK_CONTAINER(widget), mailer->fo_view);
#ifndef EMBEDDED
hpaned = gtk_hpaned_new();
gtk_paned_set_position(GTK_PANED(hpaned), 160);
gtk_paned_add1(GTK_PANED(hpaned), widget);
vpaned = gtk_vpaned_new();
gtk_paned_set_position(GTK_PANED(vpaned), 160);
gtk_box_pack_start(GTK_BOX(vbox), hpaned, TRUE, TRUE, 0);
#else
gtk_box_pack_start(GTK_BOX(vbox), widget, TRUE, TRUE, 0);
#endif
/* statusbar */
mailer->statusbar = gtk_statusbar_new();
mailer->statusbar_id = 0;
gtk_box_pack_start(GTK_BOX(vbox), mailer->statusbar, FALSE, TRUE, 0);
gtk_container_add(GTK_CONTAINER(mailer->fo_window), vbox);
gtk_widget_show_all(vbox);
/* messages list */
#ifndef EMBEDDED
mailer->he_window = mailer->fo_window;
#else
group = gtk_accel_group_new();
mailer->he_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_add_accel_group(GTK_WINDOW(mailer->he_window), group);
gtk_window_set_default_size(GTK_WINDOW(mailer->he_window), 200, 300);
# if GTK_CHECK_VERSION(2, 6, 0)
gtk_window_set_icon_name(GTK_WINDOW(mailer->he_window), "mailer");
# endif
gtk_window_set_title(GTK_WINDOW(mailer->he_window), _("Message list"));
g_signal_connect_swapped(G_OBJECT(mailer->he_window), "delete-event",
G_CALLBACK(on_headers_closex), mailer);
vbox = gtk_vbox_new(FALSE, 0);
gtk_container_add(GTK_CONTAINER(mailer->he_window), vbox);
widget = desktop_toolbar_create(_mailer_he_toolbar, mailer, group);
gtk_box_pack_start(GTK_BOX(vbox), widget, FALSE, TRUE, 0);
#endif
widget = gtk_scrolled_window_new(NULL, NULL);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(widget),
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
mailer->he_view = _new_headers_view(mailer);
gtk_container_add(GTK_CONTAINER(widget), mailer->he_view);
#ifndef EMBEDDED
gtk_paned_add1(GTK_PANED(vpaned), widget);
#else
gtk_box_pack_start(GTK_BOX(vbox), widget, TRUE, TRUE, 0);
#endif
gtk_widget_show_all(vbox);
/* messages body */
#ifndef EMBEDDED
mailer->bo_window = mailer->fo_window;
#else
group = gtk_accel_group_new();
mailer->bo_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_add_accel_group(GTK_WINDOW(mailer->bo_window), group);
gtk_window_set_default_size(GTK_WINDOW(mailer->bo_window), 200, 300);
#if GTK_CHECK_VERSION(2, 6, 0)
gtk_window_set_icon_name(GTK_WINDOW(mailer->bo_window), "mailer");
#endif
gtk_window_set_title(GTK_WINDOW(mailer->bo_window), _("Message"));
g_signal_connect_swapped(G_OBJECT(mailer->bo_window), "delete-event",
G_CALLBACK(on_body_closex), mailer);
vbox = gtk_vbox_new(FALSE, 0);
gtk_container_add(GTK_CONTAINER(mailer->bo_window), vbox);
widget = desktop_toolbar_create(_mailer_bo_toolbar, mailer, group);
gtk_box_pack_start(GTK_BOX(vbox), widget, FALSE, TRUE, 0);
#endif
vbox2 = _new_headers(mailer);
mailer->bo_buffer = gtk_text_buffer_new(NULL);
mailer->bo_view = gtk_text_view_new_with_buffer(mailer->bo_buffer);
gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(mailer->bo_view), FALSE);
gtk_text_view_set_editable(GTK_TEXT_VIEW(mailer->bo_view), FALSE);
gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(mailer->bo_view),
GTK_WRAP_WORD_CHAR);
widget = gtk_scrolled_window_new(NULL, NULL);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(widget),
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
gtk_container_add(GTK_CONTAINER(widget), mailer->bo_view);
gtk_box_pack_start(GTK_BOX(vbox2), widget, TRUE, TRUE, 0);
#ifndef EMBEDDED
gtk_paned_add2(GTK_PANED(vpaned), vbox2);
gtk_paned_add2(GTK_PANED(hpaned), vpaned);
#else
gtk_box_pack_start(GTK_BOX(vbox), vbox2, TRUE, TRUE, 0);
#endif
gtk_widget_show_all(vbox);
/* widgets */
mailer->ab_window = NULL;
mailer->pr_window = NULL;
/* show window */
gtk_widget_hide(mailer->hdr_vbox);
_mailer_update_status(mailer);
gtk_widget_show(mailer->fo_window);
/* load configuration */
mailer->source = g_idle_add(_new_config_load, mailer);
return mailer;
}
static int _new_plugins(Mailer * mailer)
{
int ret = 0;
char * dirname;
DIR * dir;
struct dirent * de;
size_t len;
Account ** p;
mailer->available = NULL;
mailer->available_cnt = 0;
if((dirname = string_new_append(PLUGINDIR, "/account", NULL)) == NULL)
return -1;
if((dir = opendir(dirname)) == NULL)
{
error_set_code(1, "%s: %s", dirname, strerror(errno));
string_delete(dirname);
return error_print("mailer");
}
for(de = readdir(dir); de != NULL; de = readdir(dir))
{
if((len = strlen(de->d_name)) < 4
|| strcmp(".so", &de->d_name[len - 3]) != 0)
continue;
de->d_name[len - 3] = '\0';
if((p = realloc(mailer->available, sizeof(*p)
* (mailer->available_cnt + 1)))
== NULL)
{
error_set_print("mailer", 1, "%s", strerror(errno));
continue;
}
mailer->available = p;
if((p[mailer->available_cnt] = account_new(mailer, de->d_name,
NULL, NULL)) == NULL)
{
error_print("mailer");
continue;
}
mailer->available_cnt++;
}
if(closedir(dir) != 0)
ret = error_set_print("mailer", 1, "%s: %s", dirname, strerror(
errno));
string_delete(dirname);
return ret;
}
static GtkWidget * _new_folders_view(Mailer * mailer)
{
GtkWidget * widget;
GtkCellRenderer * renderer;
GtkTreeSelection * treesel;
mailer->fo_store = gtk_tree_store_new(MFC_COUNT, G_TYPE_POINTER,
G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_POINTER,
GDK_TYPE_PIXBUF, G_TYPE_STRING);
widget = gtk_tree_view_new_with_model(GTK_TREE_MODEL(mailer->fo_store));
renderer = gtk_cell_renderer_pixbuf_new();
gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(widget), -1,
NULL, renderer, "pixbuf", MFC_ICON, NULL);
renderer = gtk_cell_renderer_text_new();
gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(widget), -1,
_("Folders"), renderer, "text", MFC_NAME, NULL);
treesel = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
g_signal_connect(G_OBJECT(treesel), "changed", G_CALLBACK(
_on_folders_changed), mailer);
return widget;
}
static void _on_folders_changed(GtkTreeSelection * selection, gpointer data)
{
Mailer * mailer = data;
GtkTreeModel * model;
GtkTreeIter iter;
GtkTreePath * path;
gboolean sent;
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s()\n", __func__);
#endif
if(gtk_tree_selection_get_selected(selection, &model, &iter) == FALSE)
{
mailer->account_cur = NULL;
mailer->folder_cur = NULL;
gtk_tree_view_set_model(GTK_TREE_VIEW(mailer->he_view), NULL);
_mailer_update_status(mailer);
return;
}
/* get current folder */
gtk_tree_model_get(model, &iter, MFC_FOLDER, &mailer->folder_cur, -1);
/* get current account */
path = gtk_tree_model_get_path(model, &iter);
while(gtk_tree_path_get_depth(path) > 1 && gtk_tree_path_up(path));
gtk_tree_model_get_iter(model, &iter, path);
gtk_tree_model_get(model, &iter, MFC_ACCOUNT, &mailer->account_cur, -1);
gtk_tree_path_free(path);
/* display relevant columns */
sent = (mailer->folder_cur != NULL && folder_get_type(
mailer->folder_cur) == FT_SENT) ? TRUE : FALSE;
gtk_tree_view_column_set_visible(mailer->he_view_from, !sent);
gtk_tree_view_column_set_visible(mailer->he_view_to, sent);
/* display headers */
if(mailer->folder_cur != NULL)
{
model = GTK_TREE_MODEL(folder_get_messages(mailer->folder_cur));
account_select(mailer->account_cur, mailer->folder_cur, NULL);
}
else
model = NULL;
gtk_tree_view_set_model(GTK_TREE_VIEW(mailer->he_view), model);
_mailer_update_status(mailer);
#ifdef EMBEDDED
if(model != NULL)
gtk_window_present(GTK_WINDOW(mailer->he_window));
#endif
}
static GtkWidget * _new_headers_view(Mailer * mailer)
{
GtkWidget * widget;
GtkTreeView * treeview;
GtkTreeSelection * treesel;
widget = gtk_tree_view_new();
treeview = GTK_TREE_VIEW(widget);
gtk_tree_view_set_rules_hint(treeview, TRUE);
_headers_view_column_pixbuf(treeview, "", MHC_ICON, MHC_READ);
_headers_view_column_text(treeview, _("Subject"), MHC_SUBJECT,
MHC_SUBJECT, MHC_WEIGHT);
mailer->he_view_from = _headers_view_column_text(treeview, _("From"),
MHC_FROM, MHC_FROM, MHC_WEIGHT);
mailer->he_view_to = _headers_view_column_text(treeview, _("To"),
MHC_TO, MHC_TO, MHC_WEIGHT);
_headers_view_column_text(treeview, _("Date"), MHC_DATE_DISPLAY,
MHC_DATE, MHC_WEIGHT);
treesel = gtk_tree_view_get_selection(treeview);
gtk_tree_selection_set_mode(treesel, GTK_SELECTION_MULTIPLE);
g_signal_connect(G_OBJECT(treesel), "changed", G_CALLBACK(
_on_headers_changed), mailer);
return widget;
}
static void _on_headers_changed(GtkTreeSelection * selection, gpointer data)
{
Mailer * mailer = data;
GtkTreeModel * model;
GList * sel;
GtkTreeIter iter;
gchar * p;
gchar * q;
gchar * r;
Message * message;
GtkTextBuffer * tbuf;
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s()\n", __func__);
#endif
sel = gtk_tree_selection_get_selected_rows(selection, &model);
if(sel == NULL || sel->next != NULL) /* empty or multiple */
{
gtk_widget_hide(mailer->hdr_vbox);
gtk_text_view_set_buffer(GTK_TEXT_VIEW(mailer->bo_view),
mailer->bo_buffer);
g_list_foreach(sel, (GFunc)gtk_tree_path_free, NULL);
g_list_free(sel);
return;
}
gtk_tree_model_get_iter(model, &iter, sel->data);
gtk_tree_model_get(model, &iter, MHC_MESSAGE, &message, -1);
gtk_tree_model_get(model, &iter, MHC_SUBJECT, &p, -1);
gtk_label_set_text(GTK_LABEL(mailer->hdr_subject), p);
g_free(p);
gtk_tree_model_get(model, &iter, MHC_FROM, &p, MHC_FROM_EMAIL, &q, -1);
if(q == NULL || strlen(q) == 0 || strcmp(p, q) == 0)
r = g_strdup(p);
else
r = g_strdup_printf("%s <%s>", p, q);
gtk_label_set_text(GTK_LABEL(mailer->hdr_from), r);
g_free(p);
g_free(q);
g_free(r);
gtk_tree_model_get(model, &iter, MHC_TO, &p, MHC_TO_EMAIL, &q, -1);
if(q == NULL || strlen(q) == 0 || strcmp(p, q) == 0)
r = g_strdup(p);
else
r = g_strdup_printf("%s <%s>", p, q);
gtk_label_set_text(GTK_LABEL(mailer->hdr_to), r);
g_free(p);
g_free(q);
g_free(r);
gtk_tree_model_get(model, &iter, MHC_DATE_DISPLAY, &p, -1);
gtk_label_set_text(GTK_LABEL(mailer->hdr_date), p);
g_free(p);
message_set_read(message, TRUE);
gtk_widget_show(mailer->hdr_vbox);
if((tbuf = account_select(mailer->account_cur, mailer->folder_cur,
message)) != NULL)
gtk_text_view_set_buffer(GTK_TEXT_VIEW(mailer->bo_view), tbuf);
g_list_foreach(sel, (GFunc)gtk_tree_path_free, NULL);
g_list_free(sel);
#ifdef EMBEDDED
gtk_window_present(GTK_WINDOW(mailer->bo_window));
#endif
}
static GtkTreeViewColumn * _headers_view_column_pixbuf(GtkTreeView * view,
char const * title, int id, int sortid)
{
GtkCellRenderer * renderer;
GtkTreeViewColumn * column;
renderer = gtk_cell_renderer_pixbuf_new();
column = gtk_tree_view_column_new_with_attributes(title, renderer,
"pixbuf", id, NULL);
gtk_tree_view_column_set_sort_column_id(column, sortid);
gtk_tree_view_append_column(view, column);
return column;
}
static GtkTreeViewColumn * _headers_view_column_text(GtkTreeView * view,
char const * title, int id, int sortid, int weightid)
{
GtkCellRenderer * renderer;
GtkTreeViewColumn * column;
renderer = gtk_cell_renderer_text_new();
g_object_set(G_OBJECT(renderer), "ellipsize", PANGO_ELLIPSIZE_END,
NULL);
column = gtk_tree_view_column_new_with_attributes(title, renderer,
"text", id, (weightid >= 0) ? "weight" : NULL, weightid,
NULL);
#if GTK_CHECK_VERSION(2, 4, 0)
gtk_tree_view_column_set_expand(column, TRUE);
#endif
gtk_tree_view_column_set_resizable(column, TRUE);
gtk_tree_view_column_set_sort_column_id(column, sortid);
gtk_tree_view_append_column(view, column);
return column;
}
static GtkWidget * _new_headers(Mailer * mailer)
{
struct
{
char * hdr;
GtkWidget ** widget;
} widgets[] =
{
{ N_(" Subject: "), NULL },
{ N_(" From: "), NULL },
{ N_(" To: "), NULL },
{ N_(" Date: "), NULL },
{ NULL, NULL }
};
int i;
GtkWidget * vbox;
GtkWidget * hbox;
GtkWidget * widget;
GtkSizeGroup * group;
PangoFontDescription * bold;
widgets[0].widget = &mailer->hdr_subject;
widgets[1].widget = &mailer->hdr_from;
widgets[2].widget = &mailer->hdr_to;
widgets[3].widget = &mailer->hdr_date;
vbox = gtk_vbox_new(FALSE, 0);
mailer->hdr_vbox = gtk_vbox_new(FALSE, 0);
group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
bold = pango_font_description_new();
pango_font_description_set_weight(bold, PANGO_WEIGHT_BOLD);
for(i = 0; widgets[i].hdr != NULL; i++)
{
hbox = gtk_hbox_new(FALSE, 0);
widget = gtk_label_new(_(widgets[i].hdr));
gtk_widget_modify_font(widget, bold);
gtk_misc_set_alignment(GTK_MISC(widget), 1.0, 0.0);
gtk_size_group_add_widget(GTK_SIZE_GROUP(group), widget);
gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, TRUE, 0);
widget = gtk_label_new("");
*(widgets[i].widget) = widget;
gtk_label_set_ellipsize(GTK_LABEL(widget),
PANGO_ELLIPSIZE_MIDDLE);
gtk_misc_set_alignment(GTK_MISC(widget), 0.0, 0.0);
gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0);
gtk_box_pack_start(GTK_BOX(mailer->hdr_vbox), hbox, FALSE,
FALSE, 0);
}
gtk_box_pack_start(GTK_BOX(vbox), mailer->hdr_vbox, FALSE, FALSE, 0);
pango_font_description_free(bold);
return vbox;
}
static gboolean _new_config_load(gpointer data)
{
Mailer * mailer = data;
char * filename;
char const * value;
PangoFontDescription * font;
char * p;
char * q;
mailer->source = 0;
if((mailer->config = config_new()) == NULL)
return FALSE;
if((filename = _mailer_get_config_filename()) == NULL)
return FALSE;
config_load(mailer->config, filename);
free(filename);
if((value = config_get(mailer->config, NULL, "messages_font")) != NULL)
{
font = pango_font_description_from_string(value);
gtk_widget_modify_font(mailer->bo_view, font);
pango_font_description_free(font);
}
if((value = config_get(mailer->config, NULL, "accounts")) == NULL
|| value[0] == '\0')
return FALSE;
if((p = strdup(value)) == NULL)
return FALSE;
value = p;
for(q = p; *q != '\0'; q++)
{
if(*q != ',')
continue;
*q = '\0';
_mailer_config_load_account(mailer, value);
value = q + 1;
}
if(value[0] != '\0')
_mailer_config_load_account(mailer, value);
free(p);
return FALSE;
}
/* mailer_delete */
void mailer_delete(Mailer * mailer)
{
unsigned int i;
if(mailer->source != 0)
g_source_remove(mailer->source);
for(i = 0; i < mailer->available_cnt; i++)
account_delete(mailer->available[i]);
free(mailer->available);
for(i = 0; i < mailer->account_cnt; i++)
account_delete(mailer->account[i]);
free(mailer->account);
object_delete(mailer);
}
/* accessors */
/* mailer_get_config */
char const * mailer_get_config(Mailer * mailer, char const * variable)
{
return config_get(mailer->config, NULL, variable);
}
/* mailer_set_status */
void mailer_set_status(Mailer * mailer, char const * status)
{
GtkStatusbar * sb;
sb = GTK_STATUSBAR(mailer->statusbar);
if(mailer->statusbar_id != 0)
gtk_statusbar_remove(sb, gtk_statusbar_get_context_id(sb, ""),
mailer->statusbar_id);
mailer->statusbar_id = gtk_statusbar_push(sb,
gtk_statusbar_get_context_id(sb, ""), status);
}
/* useful */
/* mailer_error */
int mailer_error(Mailer * mailer, char const * message, int ret)
{
GtkWidget * dialog;
if(mailer == NULL)
return error_set_print("mailer", ret, "%s", message);
dialog = gtk_message_dialog_new(GTK_WINDOW(mailer->fo_window),
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
#if GTK_CHECK_VERSION(2, 6, 0)
"%s", _("Error"));
gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
#endif
"%s", message);
gtk_window_set_title(GTK_WINDOW(dialog), _("Error"));
gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(
mailer->fo_window));
g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(
gtk_widget_destroy), NULL);
gtk_widget_show(dialog);
return ret;
}
/* mailer_account_add */
int mailer_account_add(Mailer * mailer, Account * account)
{
Account ** p;
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s(%p)\n", __func__, (void*)account);
#endif
if((p = realloc(mailer->account, sizeof(*p) * (mailer->account_cnt
+ 1))) == NULL)
return -mailer_error(mailer, "realloc", 1);
mailer->account = p;
mailer->account[mailer->account_cnt] = account;
if(account_init(account) != 0)
return -mailer_error(mailer, account_get_title(account), 1);
mailer->account_cnt++;
return 0;
}
#if 0 /* FIXME deprecate? */
/* mailer_account_disable */
int mailer_account_disable(Mailer * mailer, Account * account)
{
unsigned int i;
for(i = 0; i < mailer->account_cnt; i++)
if(mailer->account[i] == account)
break;
if(i == mailer->account_cnt)
return 1;
account_set_enabled(account, 0);
return 0;
}
/* mailer_account_enable */
int mailer_account_enable(Mailer * mailer, Account * account)
{
unsigned int i;
for(i = 0; i < mailer->account_cnt; i++)
if(mailer->account[i] == account)
break;
if(i == mailer->account_cnt)
return 1;
account_set_enabled(account, 1);
return 0;
}
#endif
/* mailer_compose */
void mailer_compose(Mailer * mailer)
{
compose_new(mailer->config);
}
/* mailer_delete_selected */
static void _mailer_delete_selected_foreach(GtkTreeRowReference * reference,
Mailer * mailer);
void mailer_delete_selected(Mailer * mailer)
{
/* FIXME figure which area is focused first (deleting folders) */
GtkTreeModel * model;
GtkTreeSelection * treesel;
GList * selected;
GList * s;
GtkTreePath * path;
GtkTreeRowReference * reference;
if((model = gtk_tree_view_get_model(GTK_TREE_VIEW(mailer->he_view)))
== NULL)
return;
if((treesel = gtk_tree_view_get_selection(GTK_TREE_VIEW(
mailer->he_view))) == NULL)
return;
if((selected = gtk_tree_selection_get_selected_rows(treesel, NULL))
== NULL)
return;
/* FIXME move messages to trash first */
if(_mailer_confirm(mailer, _("The messages selected will be deleted.\n"
"Continue?")) != TRUE)
{
g_list_free(selected);
return;
}
for(s = g_list_first(selected); s != NULL; s = g_list_next(s))
{
if((path = s->data) == NULL)
continue;
reference = gtk_tree_row_reference_new(model, path);
s->data = reference;
gtk_tree_path_free(path);
}
g_list_foreach(selected, (GFunc)_mailer_delete_selected_foreach,
mailer);
g_list_free(selected);
}
static void _mailer_delete_selected_foreach(GtkTreeRowReference * reference,
Mailer * mailer)
{
GtkTreeModel * model;
GtkTreePath * path;
GtkTreeIter iter;
Message * message;
if((model = gtk_tree_view_get_model(GTK_TREE_VIEW(mailer->he_view)))
== NULL)
return;
if(reference == NULL)
return;
if((path = gtk_tree_row_reference_get_path(reference)) == NULL)
return;
if(gtk_tree_model_get_iter(model, &iter, path) == TRUE)
gtk_tree_model_get(model, &iter, MHC_MESSAGE, &message, -1);
gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
gtk_tree_path_free(path);
}
/* mailer_copy */
void mailer_copy(Mailer * mailer)
{
GtkTextBuffer * buffer;
GtkClipboard * clipboard;
if(gtk_window_get_focus(GTK_WINDOW(mailer->fo_window))
== mailer->bo_view)
{
buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(
mailer->bo_view));
clipboard = gtk_widget_get_clipboard(mailer->bo_view,
GDK_SELECTION_CLIPBOARD);
gtk_text_buffer_copy_clipboard(buffer, clipboard);
}
/* FIXME implement the other widgets */
}
/* mailer_cut */
void mailer_cut(Mailer * mailer)
{
GtkTextBuffer * buffer;
GtkClipboard * clipboard;
if(gtk_window_get_focus(GTK_WINDOW(mailer->fo_window))
== mailer->bo_view) /* XXX copies, really */
{
buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(
mailer->bo_view));
clipboard = gtk_widget_get_clipboard(mailer->bo_view,
GDK_SELECTION_CLIPBOARD);
gtk_text_buffer_cut_clipboard(buffer, clipboard, FALSE);
}
/* FIXME implement the other widgets */
}
/* mailer_open_selected_source */
static void _open_selected_source(Mailer * mailer, GtkTreeModel * model,
GtkTreeIter * iter);
void mailer_open_selected_source(Mailer * mailer)
{
_mailer_foreach_message_selected(mailer, _open_selected_source);
}
static void _open_selected_source(Mailer * mailer, GtkTreeModel * model,
GtkTreeIter * iter)
{
Message * message;
GtkWidget * window;
GtkWidget * scrolled;
PangoFontDescription * font;
char const * p;
GtkWidget * widget;
GtkTextBuffer * tbuf;
gtk_tree_model_get(model, iter, MHC_MESSAGE, &message, -1);
if(message == NULL)
return;
if((tbuf = account_select_source(mailer->account_cur,
mailer->folder_cur, message)) == NULL)
return;
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size(GTK_WINDOW(window), 640, 480);
/* XXX choose a better title */
gtk_window_set_title(GTK_WINDOW(window), _("Mailer - View source"));
scrolled = gtk_scrolled_window_new(NULL, NULL);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
widget = gtk_text_view_new_with_buffer(tbuf);
if((p = config_get(mailer->config, NULL, "messages_font")) != NULL)
{
font = pango_font_description_from_string(p);
gtk_widget_modify_font(widget, font);
pango_font_description_free(font);
}
gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(widget), FALSE);
gtk_text_view_set_editable(GTK_TEXT_VIEW(widget), FALSE);
gtk_container_add(GTK_CONTAINER(scrolled), widget);
gtk_container_add(GTK_CONTAINER(window), scrolled);
gtk_widget_show_all(window);
/* FIXME count the window */
}
/* mailer_paste */
void mailer_paste(Mailer * mailer)
{
GtkTextBuffer * buffer;
GtkClipboard * clipboard;
if(gtk_window_get_focus(GTK_WINDOW(mailer->fo_window))
== mailer->bo_view) /* XXX does nothing, really */
{
buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(
mailer->bo_view));
clipboard = gtk_widget_get_clipboard(mailer->bo_view,
GDK_SELECTION_CLIPBOARD);
gtk_text_buffer_paste_clipboard(buffer, clipboard, NULL, FALSE);
}
/* FIXME implement the other widgets */
}
/* mailer_reply_selected */
static void _reply_selected(Mailer * mailer, GtkTreeModel * model,
GtkTreeIter * iter);
void mailer_reply_selected(Mailer * mailer)
{
_mailer_foreach_message_selected(mailer, _reply_selected);
}
static void _reply_selected(Mailer * mailer, GtkTreeModel * model,
GtkTreeIter * iter)
{
Compose * compose;
char * from;
char * subject;
char * p;
char const * q;
if((compose = compose_new(mailer->config)) == NULL)
return; /* XXX error message? */
gtk_tree_model_get(model, iter, MHC_FROM, &from, MHC_SUBJECT,
&subject, -1);
#if 0 /* FIXME adapt */
if(from != NULL)
compose_set_to(compose, from);
#endif
q = N_("Re: ");
if(subject != NULL && strncasecmp(subject, q, strlen(q)) != 0
&& strncasecmp(subject, _(q), strlen(_(q))) != 0
&& (p = malloc(strlen(q) + strlen(subject) + 1))
!= NULL)
{
sprintf(p, "%s%s", q, subject);
free(subject);
subject = p;
}
compose_set_subject(compose, subject);
free(subject);
free(from);
}
/* mailer_reply_selected_to_all */
static void _reply_selected_to_all(Mailer * mailer, GtkTreeModel * model,
GtkTreeIter * iter);
void mailer_reply_selected_to_all(Mailer * mailer)
{
_mailer_foreach_message_selected(mailer, _reply_selected_to_all);
}
static void _reply_selected_to_all(Mailer * mailer, GtkTreeModel * model,
GtkTreeIter * iter)
{
/* FIXME really implement */
_reply_selected(mailer, model, iter);
}
/* mailer_select_all */
void mailer_select_all(Mailer * mailer)
{
GtkTreeSelection * treesel;
#if GTK_CHECK_VERSION(2, 4, 0)
GtkTextBuffer * tbuf;
GtkTextIter start;
GtkTextIter end;
#endif
#if GTK_CHECK_VERSION(2, 4, 0)
if(gtk_window_get_focus(GTK_WINDOW(mailer->fo_window))
== mailer->bo_view)
{
tbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(mailer->bo_view));
gtk_text_buffer_get_start_iter(tbuf, &start);
gtk_text_buffer_get_end_iter(tbuf, &end);
gtk_text_buffer_select_range(tbuf, &start, &end);
return;
}
#endif
treesel = gtk_tree_view_get_selection(GTK_TREE_VIEW(mailer->he_view));
gtk_tree_selection_select_all(treesel);
}
/* mailer_show_about */
static gboolean _about_on_closex(gpointer data);
void mailer_show_about(Mailer * mailer, gboolean show)
{
GtkWidget * dialog;
if(mailer->ab_window != NULL)
{
if(show)
gtk_widget_show(mailer->ab_window);
else
gtk_widget_hide(mailer->ab_window);
return;
}
dialog = desktop_about_dialog_new();
mailer->ab_window = dialog;
g_signal_connect_swapped(G_OBJECT(dialog), "delete-event", G_CALLBACK(
_about_on_closex), mailer);
gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(
mailer->fo_window));
desktop_about_dialog_set_name(dialog, PACKAGE);
desktop_about_dialog_set_version(dialog, VERSION);
desktop_about_dialog_set_authors(dialog, _authors);
desktop_about_dialog_set_copyright(dialog, _copyright);
desktop_about_dialog_set_logo_icon_name(dialog, "mailer");
desktop_about_dialog_set_license(dialog, _license);
gtk_widget_show(dialog);
}
static gboolean _about_on_closex(gpointer data)
{
Mailer * mailer = data;
gtk_widget_hide(mailer->ab_window);
return TRUE;
}
/* mailer_show_body */
void mailer_show_body(Mailer * mailer, gboolean show)
{
if(show == TRUE)
gtk_window_present(GTK_WINDOW(mailer->bo_window));
else
gtk_widget_hide(mailer->bo_window);
}
/* mailer_show_headers */
void mailer_show_headers(Mailer * mailer, gboolean show)
{
if(show == TRUE)
gtk_window_present(GTK_WINDOW(mailer->he_window));
else
gtk_widget_hide(mailer->he_window);
}
/* mailer_show_preferences */
typedef enum _AccountColumn
{
AC_DATA = 0,
AC_ACTIVE,
AC_ENABLED,
AC_TITLE,
AC_TYPE
} AccountColumn;
#define AC_LAST AC_TYPE
#define AC_COUNT (AC_LAST + 1)
static void _preferences_set(Mailer * mailer);
/* callbacks */
static gboolean _on_preferences_closex(gpointer data);
static void _on_preferences_response(GtkWidget * widget, gint response,
gpointer data);
static void _on_preferences_account_delete(gpointer data);
static void _on_preferences_account_edit(gpointer data);
static void _on_preferences_account_new(gpointer data);
static void _on_preferences_account_toggle(GtkCellRendererToggle * renderer,
char * path, gpointer data);
static void _on_preferences_cancel(gpointer data);
static void _on_preferences_ok(gpointer data);
static int _preferences_ok_accounts(Mailer * mailer);
static int _preferences_ok_display(Mailer * mailer);
static int _preferences_ok_save(Mailer * mailer);
void mailer_show_preferences(Mailer * mailer, gboolean show)
{
GtkWidget * notebook;
GtkWidget * vbox;
GtkWidget * hbox;
GtkWidget * vbox2;
GtkWidget * vbox3;
GtkWidget * widget;
GtkSizeGroup * group;
GtkListStore * store;
size_t i;
Account * ac;
GtkTreeIter iter;
GtkCellRenderer * renderer;
if(mailer->pr_window != NULL)
{
if(show)
gtk_window_present(GTK_WINDOW(mailer->pr_window));
else
gtk_widget_hide(mailer->pr_window);
return;
}
mailer->pr_window = gtk_dialog_new_with_buttons(
_("Mailer preferences"), GTK_WINDOW(mailer->fo_window),
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
g_signal_connect_swapped(G_OBJECT(mailer->pr_window), "delete-event",
G_CALLBACK(_on_preferences_closex), mailer);
g_signal_connect(G_OBJECT(mailer->pr_window), "response",
G_CALLBACK(_on_preferences_response), mailer);
#if GTK_CHECK_VERSION(2, 14, 0)
vbox = gtk_dialog_get_content_area(GTK_DIALOG(mailer->pr_window));
#else
vbox = GTK_DIALOG(mailer->pr_window)->vbox;
#endif
notebook = gtk_notebook_new();
/* accounts */
vbox2 = gtk_vbox_new(FALSE, 4);
gtk_container_set_border_width(GTK_CONTAINER(vbox2), 4);
hbox = gtk_hbox_new(FALSE, 4);
widget = gtk_scrolled_window_new(NULL, NULL);
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(widget),
GTK_SHADOW_IN);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(widget),
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
store = gtk_list_store_new(AC_COUNT, G_TYPE_POINTER, G_TYPE_BOOLEAN,
G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_STRING);
for(i = 0; i < mailer->account_cnt; i++)
{
ac = mailer->account[i];
gtk_list_store_insert_with_values(store, &iter, -1,
AC_DATA, ac, AC_ACTIVE, TRUE,
AC_ENABLED, account_get_enabled(ac),
AC_TITLE, account_get_title(ac),
AC_TYPE, account_get_type(ac), -1);
}
mailer->pr_accounts = gtk_tree_view_new_with_model(GTK_TREE_MODEL(
store));
gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(mailer->pr_accounts),
TRUE);
gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(mailer->pr_accounts), TRUE);
renderer = gtk_cell_renderer_toggle_new();
g_signal_connect(G_OBJECT(renderer), "toggled", G_CALLBACK(
_on_preferences_account_toggle), store);
gtk_tree_view_append_column(GTK_TREE_VIEW(mailer->pr_accounts),
gtk_tree_view_column_new_with_attributes(_("Enabled"),
renderer, "active", AC_ENABLED, NULL));
renderer = gtk_cell_renderer_text_new();
gtk_tree_view_append_column(GTK_TREE_VIEW(mailer->pr_accounts),
gtk_tree_view_column_new_with_attributes(_("Name"),
renderer, "text", AC_TITLE, NULL));
renderer = gtk_cell_renderer_text_new();
gtk_tree_view_append_column(GTK_TREE_VIEW(mailer->pr_accounts),
gtk_tree_view_column_new_with_attributes(_("Type"),
renderer, "text", AC_TYPE, NULL));
gtk_container_add(GTK_CONTAINER(widget), mailer->pr_accounts);
gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0);
vbox3 = gtk_vbox_new(FALSE, 4);
widget = gtk_button_new_from_stock(GTK_STOCK_NEW);
g_signal_connect_swapped(G_OBJECT(widget), "clicked", G_CALLBACK(
_on_preferences_account_new), mailer);
gtk_box_pack_start(GTK_BOX(vbox3), widget, FALSE, TRUE, 0);
#if GTK_CHECK_VERSION(2, 6, 0)
widget = gtk_button_new_from_stock(GTK_STOCK_EDIT);
#else
widget = gtk_button_new_with_mnemonic("_Edit");
#endif
g_signal_connect_swapped(G_OBJECT(widget), "clicked", G_CALLBACK(
_on_preferences_account_edit), mailer);
gtk_box_pack_start(GTK_BOX(vbox3), widget, FALSE, TRUE, 0);
widget = gtk_button_new_from_stock(GTK_STOCK_DELETE);
g_signal_connect_swapped(G_OBJECT(widget), "clicked", G_CALLBACK(
_on_preferences_account_delete), mailer);
gtk_box_pack_start(GTK_BOX(vbox3), widget, FALSE, TRUE, 0);
gtk_box_pack_start(GTK_BOX(hbox), vbox3, FALSE, TRUE, 0);
gtk_box_pack_start(GTK_BOX(vbox2), hbox, TRUE, TRUE, 0);
gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox2, gtk_label_new(
_("Accounts")));
/* display */
vbox2 = gtk_vbox_new(FALSE, 4);
gtk_container_set_border_width(GTK_CONTAINER(vbox2), 4);
group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
/* default font */
hbox = gtk_hbox_new(FALSE, 4);
widget = gtk_label_new(_("Messages font:"));
gtk_misc_set_alignment(GTK_MISC(widget), 0.0, 0.5);
gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, TRUE, 0);
mailer->pr_messages_font = gtk_font_button_new();
widget = mailer->pr_messages_font;
gtk_size_group_add_widget(group, widget);
gtk_font_button_set_use_font(GTK_FONT_BUTTON(widget), TRUE);
gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0);
gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, FALSE, 0);
gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox2, gtk_label_new(
_("Display")));
gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0);
_preferences_set(mailer);
gtk_widget_show_all(vbox);
if(show)
gtk_widget_show(mailer->pr_window);
else
gtk_widget_hide(mailer->pr_window);
}
static void _preferences_set(Mailer * mailer)
{
char const * p;
if((p = mailer_get_config(mailer, "messages_font")) == NULL)
p = MAILER_MESSAGES_FONT;
gtk_font_button_set_font_name(GTK_FONT_BUTTON(mailer->pr_messages_font),
p);
}
static gboolean _on_preferences_closex(gpointer data)
{
Mailer * mailer = data;
gtk_widget_hide(mailer->pr_window);
return TRUE;
}
static void _on_preferences_response(GtkWidget * widget, gint response,
gpointer data)
{
Mailer * mailer = data;
gtk_widget_hide(widget);
if(response == GTK_RESPONSE_OK)
_on_preferences_ok(mailer);
else if(response == GTK_RESPONSE_CANCEL)
_on_preferences_cancel(mailer);
}
/* _on_preferences_account_new */
/* types */
typedef struct _AccountData
{
Mailer * mailer;
char * type;
AccountIdentity identity;
unsigned int available;
Account * account;
GtkWidget * assistant;
GtkWidget * settings;
GtkWidget * confirm;
} AccountData;
/* functions */
static GtkWidget * _assistant_account_select(AccountData * ad);
static GtkWidget * _assistant_account_config(AccountConfig * config);
#if !GTK_CHECK_VERSION(2, 10, 0)
# include "gtkassistant.c"
#endif
static void _on_assistant_cancel(GtkWidget * widget, gpointer data);
static void _on_assistant_close(GtkWidget * widget, gpointer data);
static void _on_assistant_apply(gpointer data);
static void _on_assistant_prepare(GtkWidget * widget, GtkWidget * page,
gpointer data);
static void _on_entry_changed(GtkWidget * widget, gpointer data);
static void _on_account_type_changed(GtkWidget * widget, gpointer data);
static void _on_preferences_account_new(gpointer data)
{
Mailer * mailer = data;
AccountData * ad;
GtkAssistant * assistant;
GtkWidget * page;
if(mailer->available_cnt == 0)
{
mailer_error(mailer, _("No account plug-in available"), 0);
return;
}
if((ad = malloc(sizeof(*ad))) == NULL)
{
mailer_error(mailer, strerror(errno), 0);
return;
}
ad->mailer = mailer;
ad->type = strdup("");
memset(&(ad->identity), 0, sizeof(ad->identity));
ad->available = 0;
ad->account = NULL;
ad->assistant = gtk_assistant_new();
assistant = GTK_ASSISTANT(ad->assistant);
g_signal_connect(G_OBJECT(ad->assistant), "cancel", G_CALLBACK(
_on_assistant_cancel), ad);
g_signal_connect(G_OBJECT(ad->assistant), "close", G_CALLBACK(
_on_assistant_close), ad);
g_signal_connect_swapped(G_OBJECT(ad->assistant), "apply", G_CALLBACK(
_on_assistant_apply), ad);
g_signal_connect(G_OBJECT(ad->assistant), "prepare", G_CALLBACK(
_on_assistant_prepare), ad);
/* plug-in selection */
page = _assistant_account_select(ad);
gtk_assistant_append_page(assistant, page);
gtk_assistant_set_page_title(assistant, page, _(_title[0]));
gtk_assistant_set_page_type(assistant, page, GTK_ASSISTANT_PAGE_INTRO);
gtk_assistant_set_page_complete(assistant, page, FALSE);
/* plug-in preferences */
page = gtk_vbox_new(FALSE, 0);
ad->settings = page;
gtk_widget_show(page);
gtk_assistant_append_page(assistant, page);
gtk_assistant_set_page_title(assistant, page, _(_title[1]));
gtk_assistant_set_page_type(assistant, page,
GTK_ASSISTANT_PAGE_CONTENT);
gtk_assistant_set_page_complete(assistant, page, TRUE);
/* confirmation page */
page = gtk_vbox_new(FALSE, 0);
ad->confirm = page;
gtk_widget_show(page);
gtk_assistant_append_page(assistant, page);
gtk_assistant_set_page_title(assistant, page, _(_title[2]));
gtk_assistant_set_page_type(assistant, page,
GTK_ASSISTANT_PAGE_CONFIRM);
gtk_assistant_set_page_complete(assistant, page, TRUE);
gtk_widget_show(ad->assistant);
}
static void _on_assistant_cancel(GtkWidget * widget, gpointer data)
{
_on_assistant_close(widget, data);
}
static void _on_assistant_close(GtkWidget * widget, gpointer data)
{
AccountData * ad = data;
if(ad->account != NULL)
account_delete(ad->account);
free(ad);
gtk_widget_destroy(widget);
}
static void _on_assistant_apply(gpointer data)
{
AccountData * ad = data;
GtkTreeModel * model;
GtkTreeIter iter;
model = gtk_tree_view_get_model(GTK_TREE_VIEW(ad->mailer->pr_accounts));
gtk_list_store_append(GTK_LIST_STORE(model), &iter);
#ifdef DEBUG
fprintf(stderr, "%s%p%s%s%s%s\n", "AC_DATA ", (void*)ad->account,
", AC_ACTIVE FALSE, AC_ENABLED TRUE, AC_TITLE ",
account_get_title(ad->account), ", AC_TYPE ",
account_get_type(ad->account));
#endif
gtk_list_store_set(GTK_LIST_STORE(model), &iter,
AC_DATA, ad->account, AC_ACTIVE, FALSE,
AC_ENABLED, TRUE,
AC_TITLE, account_get_title(ad->account),
AC_TYPE, account_get_type(ad->account), -1);
ad->account = NULL;
/* _on_assistant_close is then automatically called */
}
/* on_assistant_prepare */
static GtkWidget * _account_display(Account * account);
static void _on_assistant_prepare(GtkWidget * widget, GtkWidget * page,
gpointer data)
{
static int old = 0;
AccountData * ad = data;
unsigned int i;
Account * ac;
i = gtk_assistant_get_current_page(GTK_ASSISTANT(widget));
gtk_window_set_title(GTK_WINDOW(widget), _(_title[i]));
if(i == 1)
{
/* XXX something is wrong with gtk_container_remove */
gtk_container_remove(GTK_CONTAINER(page), ad->settings);
if(old == 0)
{
if(ad->account != NULL)
account_delete(ad->account);
ac = ad->mailer->available[ad->available];
ad->account = account_new(ad->mailer,
account_get_type(ac), ad->type, NULL);
}
if(ad->account == NULL)
{
mailer_error(ad->mailer, error_get(), 0);
gtk_assistant_set_current_page(GTK_ASSISTANT(widget),
0);
ad->settings = _assistant_account_select(ad);
}
else
ad->settings = _assistant_account_config(
account_get_config(ad->account));
gtk_container_add(GTK_CONTAINER(page), ad->settings);
gtk_widget_show_all(ad->settings);
}
else if(i == 2)
{
gtk_container_remove(GTK_CONTAINER(page), ad->confirm);
ad->confirm = _account_display(ad->account);
gtk_container_add(GTK_CONTAINER(page), ad->confirm);
}
old = i;
}
/* _assistant_account_select */
static void _on_account_name_changed(GtkWidget * widget, gpointer data);
static void _account_add_label(GtkWidget * box, PangoFontDescription * desc,
GtkSizeGroup * group, char const * text);
static GtkWidget * _assistant_account_select(AccountData * ad)
{
GtkWidget * vbox;
GtkWidget * hbox;
GtkSizeGroup * group;
PangoFontDescription * desc;
GtkWidget * widget;
unsigned int i;
vbox = gtk_vbox_new(FALSE, 4);
gtk_container_set_border_width(GTK_CONTAINER(vbox), 4);
group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
hbox = gtk_hbox_new(FALSE, 4);
desc = pango_font_description_new();
pango_font_description_set_weight(desc, PANGO_WEIGHT_BOLD);
_account_add_label(hbox, desc, group, _("Account name"));
widget = gtk_entry_new();
g_signal_connect(G_OBJECT(widget), "changed", G_CALLBACK(
_on_account_name_changed), ad);
gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0);
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
hbox = gtk_hbox_new(FALSE, 4);
_account_add_label(hbox, NULL, group, _("Your name"));
widget = gtk_entry_new();
g_signal_connect(G_OBJECT(widget), "changed", G_CALLBACK(
_on_entry_changed), &(ad->identity.from));
gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0);
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
hbox = gtk_hbox_new(FALSE, 4);
_account_add_label(hbox, NULL, group, _("e-mail address"));
widget = gtk_entry_new();
g_signal_connect(G_OBJECT(widget), "changed", G_CALLBACK(
_on_entry_changed), &(ad->identity.email));
gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0);
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
hbox = gtk_hbox_new(FALSE, 4);
_account_add_label(hbox, NULL, group, _("Type of account"));
#if GTK_CHECK_VERSION(3, 0, 0)
widget = gtk_combo_box_text_new();
#else
widget = gtk_combo_box_new_text();
#endif
/* XXX this works because there is no plug-in list reload
* would it be implemented this will need validation later */
for(i = 0; i < ad->mailer->available_cnt; i++)
#if GTK_CHECK_VERSION(3, 0, 0)
gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(widget), NULL,
account_get_name(ad->mailer->available[i]));
#else
gtk_combo_box_append_text(GTK_COMBO_BOX(widget),
account_get_name(ad->mailer->available[i]));
#endif
gtk_combo_box_set_active(GTK_COMBO_BOX(widget), 0);
g_signal_connect(G_OBJECT(widget), "changed", G_CALLBACK(
_on_account_type_changed), ad);
gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0);
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
pango_font_description_free(desc);
gtk_widget_show_all(vbox);
return vbox;
}
static void _on_account_name_changed(GtkWidget * widget, gpointer data)
{
AccountData * ad = data;
int current;
GtkWidget * page;
_on_entry_changed(widget, &ad->type);
current = gtk_assistant_get_current_page(GTK_ASSISTANT(ad->assistant));
page = gtk_assistant_get_nth_page(GTK_ASSISTANT(ad->assistant),
current);
gtk_assistant_set_page_complete(GTK_ASSISTANT(ad->assistant), page,
strlen(ad->type) ? TRUE : FALSE);
}
static void _account_add_label(GtkWidget * box, PangoFontDescription * desc,
GtkSizeGroup * group, char const * text)
{
static char buf[80]; /* XXX hard-coded size */
GtkWidget * label;
snprintf(buf, sizeof(buf), "%s:", text);
label = gtk_label_new(buf);
if(desc != NULL)
gtk_widget_modify_font(label, desc);
if(group != NULL)
gtk_size_group_add_widget(group, label);
gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
gtk_box_pack_start(GTK_BOX(box), label, FALSE, TRUE, 0);
}
/* _assistant_account_config */
static GtkWidget * _update_string(AccountConfig * config,
PangoFontDescription * desc, GtkSizeGroup * group);
static GtkWidget * _update_password(AccountConfig * config,
PangoFontDescription * desc, GtkSizeGroup * group);
static GtkWidget * _update_file(AccountConfig * config,
PangoFontDescription * desc, GtkSizeGroup * group);
static GtkWidget * _update_uint16(AccountConfig * config,
PangoFontDescription * desc, GtkSizeGroup * group);
static GtkWidget * _update_boolean(AccountConfig * config);
static GtkWidget * _assistant_account_config(AccountConfig * config)
{
GtkWidget * vbox;
GtkSizeGroup * group;
GtkWidget * widget;
size_t i;
vbox = gtk_vbox_new(FALSE, 4);
gtk_container_set_border_width(GTK_CONTAINER(vbox), 4);
group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
for(i = 0; config != NULL && config[i].type != ACT_NONE; i++)
{
switch(config[i].type)
{
case ACT_STRING:
widget = _update_string(&config[i], NULL,
group);
break;
case ACT_PASSWORD:
widget = _update_password(&config[i], NULL,
group);
break;
case ACT_FILE:
widget = _update_file(&config[i], NULL, group);
break;
case ACT_UINT16:
widget = _update_uint16(&config[i], NULL,
group);
break;
case ACT_BOOLEAN:
widget = _update_boolean(&config[i]);
break;
case ACT_SEPARATOR:
widget = gtk_hseparator_new();
break;
default: /* should not happen */
assert(0);
continue;
}
gtk_box_pack_start(GTK_BOX(vbox), widget, FALSE, TRUE, 0);
}
return vbox;
}
static GtkWidget * _update_string(AccountConfig * config,
PangoFontDescription * desc, GtkSizeGroup * group)
{
GtkWidget * hbox;
GtkWidget * widget;
hbox = gtk_hbox_new(FALSE, 0);
_account_add_label(hbox, desc, group, config->title);
widget = gtk_entry_new();
if(config->value != NULL)
gtk_entry_set_text(GTK_ENTRY(widget), config->value);
g_signal_connect(G_OBJECT(widget), "changed", G_CALLBACK(
_on_entry_changed), &config->value);
gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0);
return hbox;
}
static GtkWidget * _update_password(AccountConfig * config,
PangoFontDescription * desc, GtkSizeGroup * group)
{
GtkWidget * hbox;
GtkWidget * widget;
hbox = gtk_hbox_new(FALSE, 0);
_account_add_label(hbox, desc, group, config->title);
widget = gtk_entry_new();
gtk_entry_set_visibility(GTK_ENTRY(widget), FALSE);
if(config->value != NULL)
gtk_entry_set_text(GTK_ENTRY(widget), config->value);
g_signal_connect(G_OBJECT(widget), "changed", G_CALLBACK(
_on_entry_changed), &config->value);
gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0);
return hbox;
}
static void _on_file_activated(GtkWidget * widget, gpointer data);
static GtkWidget * _update_file(AccountConfig * config,
PangoFontDescription * desc, GtkSizeGroup * group)
{
GtkWidget * hbox;
GtkWidget * widget;
hbox = gtk_hbox_new(FALSE, 0);
_account_add_label(hbox, desc, group, config->title);
widget = gtk_file_chooser_button_new(_("Choose file"),
GTK_FILE_CHOOSER_ACTION_OPEN);
if(config->value != NULL)
gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(widget),
config->value);
gtk_file_chooser_button_set_title(GTK_FILE_CHOOSER_BUTTON(widget),
config->title);
g_signal_connect(G_OBJECT(widget), "file-set", G_CALLBACK(
_on_file_activated), &config->value);
gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0);
return hbox;
}
static void _on_file_activated(GtkWidget * widget, gpointer data)
{
char * filename;
char ** value = data;
char * p = NULL;
filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(widget));
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s(%s)\n", __func__, filename);
#endif
if(filename == NULL)
free(*value);
else if((p = realloc(*value, strlen(filename) + 1)) == NULL)
{
mailer_error(NULL, strerror(errno), 0);
return;
}
*value = p;
if(filename != NULL)
strcpy(p, filename);
}
static void _on_uint16_changed(GtkWidget * widget, gpointer data);
static GtkWidget * _update_uint16(AccountConfig * config,
PangoFontDescription * desc, GtkSizeGroup * group)
{
GtkWidget * hbox;
GtkWidget * widget;
uint16_t u16 = (intptr_t)(config->value);
gdouble value = u16;
hbox = gtk_hbox_new(FALSE, 0);
_account_add_label(hbox, desc, group, config->title);
widget = gtk_spin_button_new_with_range(0, 65535, 1);
gtk_spin_button_set_digits(GTK_SPIN_BUTTON(widget), 0);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(widget), value);
g_signal_connect(G_OBJECT(widget), "value-changed", G_CALLBACK(
_on_uint16_changed), &config->value);
gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0);
return hbox;
}
static void _on_uint16_changed(GtkWidget * widget, gpointer data)
{
int * value = data;
*value = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget));
#ifdef DEBUG
fprintf(stderr, "DEBUG: new value is %d\n", *value);
#endif
}
static void _on_boolean_toggled(GtkWidget * widget, gpointer data);
static GtkWidget * _update_boolean(AccountConfig * config)
{
GtkWidget * widget;
widget = gtk_check_button_new_with_label(config->title);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget),
config->value != NULL);
g_signal_connect(G_OBJECT(widget), "toggled", G_CALLBACK(
_on_boolean_toggled), &config->value);
return widget;
}
static void _on_boolean_toggled(GtkWidget * widget, gpointer data)
{
int * value = data;
*value = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
}
static GtkWidget * _display_string(AccountConfig * config,
PangoFontDescription * desc, GtkSizeGroup * group);
static GtkWidget * _display_password(AccountConfig * config,
PangoFontDescription * desc, GtkSizeGroup * group);
static GtkWidget * _display_file(AccountConfig * config,
PangoFontDescription * desc, GtkSizeGroup * group);
static GtkWidget * _display_uint16(AccountConfig * config,
PangoFontDescription * desc, GtkSizeGroup * group);
static GtkWidget * _display_boolean(AccountConfig * config,
PangoFontDescription * desc, GtkSizeGroup * group);
static GtkWidget * _account_display(Account * account)
{
AccountConfig * config;
AccountConfig p;
GtkWidget * vbox;
GtkSizeGroup * group;
PangoFontDescription * desc;
GtkWidget * widget;
unsigned int i;
config = account_get_config(account);
vbox = gtk_vbox_new(FALSE, 4);
gtk_container_set_border_width(GTK_CONTAINER(vbox), 4);
group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
p.name = NULL;
p.title = _("Account name");
p.value = (void *)account_get_title(account);
desc = pango_font_description_new();
pango_font_description_set_weight(desc, PANGO_WEIGHT_BOLD);
widget = _display_string(&p, desc, group);
gtk_box_pack_start(GTK_BOX(vbox), widget, FALSE, TRUE, 0);
for(i = 0; config[i].type != ACT_NONE; i++)
{
switch(config[i].type)
{
case ACT_STRING:
widget = _display_string(&config[i], desc,
group);
break;
case ACT_PASSWORD:
widget = _display_password(&config[i], desc,
group);
break;
case ACT_FILE:
widget = _display_file(&config[i], desc, group);
break;
case ACT_UINT16:
widget = _display_uint16(&config[i], desc,
group);
break;
case ACT_BOOLEAN:
widget = _display_boolean(&config[i], desc,
group);
break;
case ACT_SEPARATOR:
widget = gtk_hseparator_new();
break;
default: /* should not happen */
assert(0);
continue;
}
gtk_box_pack_start(GTK_BOX(vbox), widget, FALSE, TRUE, 0);
}
pango_font_description_free(desc);
gtk_widget_show_all(vbox);
return vbox;
}
static GtkWidget * _display_string(AccountConfig * config,
PangoFontDescription * desc, GtkSizeGroup * group)
{
GtkWidget * hbox;
GtkWidget * widget;
hbox = gtk_hbox_new(FALSE, 0);
_account_add_label(hbox, desc, group, config->title);
widget = gtk_label_new(config->value);
gtk_misc_set_alignment(GTK_MISC(widget), 0.0, 0.5);
gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0);
return hbox;
}
static GtkWidget * _display_file(AccountConfig * config,
PangoFontDescription * desc, GtkSizeGroup * group)
{
return _display_string(config, desc, group);
}
static GtkWidget * _display_password(AccountConfig * config,
PangoFontDescription * desc, GtkSizeGroup * group)
{
GtkWidget * hbox;
GtkWidget * widget;
hbox = gtk_hbox_new(FALSE, 0);
_account_add_label(hbox, desc, group, config->title);
widget = gtk_label_new(_("hidden"));
desc = pango_font_description_new();
pango_font_description_set_style(desc, PANGO_STYLE_ITALIC);
gtk_widget_modify_font(widget, desc);
gtk_misc_set_alignment(GTK_MISC(widget), 0.0, 0.5);
gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0);
return hbox;
}
static GtkWidget * _display_uint16(AccountConfig * config,
PangoFontDescription * desc, GtkSizeGroup * group)
{
GtkWidget * hbox;
GtkWidget * widget;
char buf[6];
uint16_t u16 = (intptr_t)config->value;
hbox = gtk_hbox_new(FALSE, 0);
_account_add_label(hbox, desc, group, config->title);
snprintf(buf, sizeof(buf), "%hu", u16);
widget = gtk_label_new(buf);
gtk_misc_set_alignment(GTK_MISC(widget), 0.0, 0.5);
gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0);
return hbox;
}
static GtkWidget * _display_boolean(AccountConfig * config,
PangoFontDescription * desc, GtkSizeGroup * group)
{
GtkWidget * hbox;
GtkWidget * widget;
hbox = gtk_hbox_new(FALSE, 0);
_account_add_label(hbox, desc, group, config->title);
widget = gtk_label_new(config->value != 0 ? _("Yes") : _("No"));
gtk_misc_set_alignment(GTK_MISC(widget), 0.0, 0.5);
gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0);
return hbox;
}
static void _on_entry_changed(GtkWidget * widget, gpointer data)
{
const char * text;
char ** value = data;
char * p;
text = gtk_entry_get_text(GTK_ENTRY(widget));
if((p = realloc(*value, strlen(text) + 1)) == NULL)
{
mailer_error(NULL, strerror(errno), 0);
return;
}
*value = p;
strcpy(p, text);
}
static void _on_account_type_changed(GtkWidget * widget, gpointer data)
{
AccountData * ad = data;
ad->available = gtk_combo_box_get_active(GTK_COMBO_BOX(widget));
#ifdef DEBUG
fprintf(stderr, "%s%u%s", _("Account type "), ad->available,
_(" active\n"));
#endif
}
static void _on_preferences_account_toggle(GtkCellRendererToggle * renderer,
char * path, gpointer data)
{
GtkListStore * store = data;
GtkTreeIter iter;
gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(store), &iter, path);
gtk_list_store_set(store, &iter, AC_ENABLED,
!gtk_cell_renderer_toggle_get_active(renderer), -1);
}
/* _on_preferences_account_edit */
static void _account_edit(Mailer * mailer, Account * account);
static void _on_preferences_account_edit(gpointer data)
{
Mailer * mailer = data;
GtkTreeSelection * selection;
GtkTreeModel * model;
GtkTreeIter iter;
Account * account;
selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(
mailer->pr_accounts));
if(gtk_tree_selection_get_selected(selection, &model, &iter) != TRUE)
return;
gtk_tree_model_get(model, &iter, AC_DATA, &account, -1);
_account_edit(mailer, account);
}
static void _account_edit(Mailer * mailer, Account * account)
{
GtkWidget * window;
char buf[80];
GtkWidget * vbox;
GtkWidget * widget;
GtkWidget * hbox;
GtkSizeGroup * group;
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
snprintf(buf, sizeof(buf), "%s%s", _("Edit account: "),
account_get_title(account));
gtk_window_set_title(GTK_WINDOW(window), buf);
gtk_window_set_transient_for(GTK_WINDOW(window), GTK_WINDOW(
mailer->fo_window));
gtk_window_set_modal(GTK_WINDOW(window), TRUE);
vbox = gtk_vbox_new(FALSE, 4);
/* FIXME also allow to modify the identity, plug-in values... */
/* FIXME this affects the account directly (eg cancel does not) */
widget = _assistant_account_config(account_get_config(account));
gtk_box_pack_start(GTK_BOX(vbox), widget, TRUE, TRUE, 0);
hbox = gtk_hbox_new(FALSE, 0);
group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
widget = gtk_button_new_from_stock(GTK_STOCK_OK);
gtk_size_group_add_widget(group, widget);
/* FIXME implement properly */
g_signal_connect_swapped(G_OBJECT(widget), "clicked", G_CALLBACK(
gtk_widget_destroy), window);
gtk_box_pack_end(GTK_BOX(hbox), widget, FALSE, TRUE, 4);
widget = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
gtk_size_group_add_widget(group, widget);
g_signal_connect_swapped(G_OBJECT(widget), "clicked", G_CALLBACK(
gtk_widget_destroy), window);
gtk_box_pack_end(GTK_BOX(hbox), widget, FALSE, TRUE, 0);
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 4);
gtk_container_add(GTK_CONTAINER(window), vbox);
gtk_widget_show_all(window);
}
static void _on_preferences_account_delete(gpointer data)
{
Mailer * mailer = data;
GtkTreePath * path;
GtkTreeModel * model;
GtkTreeIter iter;
gtk_tree_view_get_cursor(GTK_TREE_VIEW(mailer->pr_accounts), &path,
NULL);
if(path == NULL)
return;
model = gtk_tree_view_get_model(GTK_TREE_VIEW(mailer->pr_accounts));
gtk_tree_model_get_iter(model, &iter, path);
gtk_tree_path_free(path);
gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
/* FIXME non-interface code (flag account as deleted and on ok apply) */
}
static void _on_preferences_cancel(gpointer data)
{
Mailer * mailer = data;
gtk_widget_hide(mailer->pr_window);
_preferences_set(mailer);
}
static void _on_preferences_ok(gpointer data)
{
Mailer * mailer = data;
mailer_show_preferences(mailer, FALSE);
if(_preferences_ok_accounts(mailer) != 0
|| _preferences_ok_display(mailer) != 0
|| _preferences_ok_save(mailer) != 0)
mailer_error(mailer, _("An error occured while saving"
" preferences"), 0);
}
static int _preferences_ok_accounts(Mailer * mailer)
{
GtkTreeModel * model;
GtkTreeIter iter;
GtkTreeModel * view_model;
gboolean loop;
Account * account;
gboolean active;
gboolean enabled;
char * title;
size_t title_len;
char * accounts = NULL;
size_t accounts_len = 0;
char * p;
model = gtk_tree_view_get_model(GTK_TREE_VIEW(mailer->pr_accounts));
view_model = gtk_tree_view_get_model(GTK_TREE_VIEW(
mailer->fo_view));
for(loop = gtk_tree_model_get_iter_first(model, &iter); loop == TRUE;
loop = gtk_tree_model_iter_next(model, &iter))
{
gtk_tree_model_get(model, &iter, AC_DATA, &account,
AC_ACTIVE, &active, AC_ENABLED, &enabled,
AC_TITLE, &title, -1);
title_len = strlen(title);
if(account_config_save(account, mailer->config) != 0)
return 1;
if((p = realloc(accounts, accounts_len + title_len + 2))
== NULL)
{
free(accounts);
return 1;
}
accounts = p;
sprintf(&accounts[accounts_len], "%s%s", accounts_len ? ","
: "", title);
accounts_len += title_len + (accounts_len ? 1 : 0);
if(active)
{
if(enabled)
continue;
#if 0 /* FIXME API+behaviour change here */
if(mailer_account_disable(mailer, account) == 0)
gtk_list_store_set(GTK_LIST_STORE(model), &iter,
AC_ACTIVE, FALSE, -1);
#endif
}
else if(enabled && mailer_account_add(mailer, account) == 0)
gtk_list_store_set(GTK_LIST_STORE(model), &iter,
AC_ACTIVE, TRUE, -1);
}
/* FIXME delete accounts that need to be */
/* FIXME force a refresh of the ones remaining and not just added */
#ifdef DEBUG
fprintf(stderr, "DEBUG: saved accounts \"%s\"\n", accounts);
#endif
config_set(mailer->config, "", "accounts", accounts);
free(accounts);
return 0;
}
static int _preferences_ok_display(Mailer * mailer)
{
PangoFontDescription * font = NULL;
char const * p;
p = gtk_font_button_get_font_name(GTK_FONT_BUTTON(
mailer->pr_messages_font));
config_set(mailer->config, "", "messages_font", p);
if(p != NULL)
font = pango_font_description_from_string(p);
gtk_widget_modify_font(mailer->bo_view, font);
if(font != NULL)
pango_font_description_free(font);
return 0;
}
static int _preferences_ok_save(Mailer * mailer)
{
int ret;
char * p;
if((p = _mailer_get_config_filename()) == NULL)
return 1;
ret = config_save(mailer->config, p);
free(p);
return ret;
}
/* mailer_unselect_all */
void mailer_unselect_all(Mailer * mailer)
{
GtkTreeSelection * treesel;
#if GTK_CHECK_VERSION(2, 4, 0)
GtkTextBuffer * tbuf;
GtkTextMark * mark;
GtkTextIter iter;
#endif
if(gtk_window_get_focus(GTK_WINDOW(mailer->fo_window))
== mailer->bo_view)
{
#if GTK_CHECK_VERSION(2, 4, 0)
tbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(mailer->bo_view));
mark = gtk_text_buffer_get_mark(tbuf, "insert");
gtk_text_buffer_get_iter_at_mark(tbuf, &iter, mark);
gtk_text_buffer_select_range(tbuf, &iter, &iter);
#endif
return;
}
treesel = gtk_tree_view_get_selection(GTK_TREE_VIEW(mailer->he_view));
gtk_tree_selection_unselect_all(treesel);
}
/* private */
/* functions */
/* mailer_confirm */
static gboolean _mailer_confirm(Mailer * mailer, char const * message)
{
GtkWidget * dialog;
int res;
dialog = gtk_message_dialog_new(GTK_WINDOW(mailer->fo_window),
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO, "%s",
#if GTK_CHECK_VERSION(2, 8, 0)
_("Question"));
gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
"%s",
#endif
message);
gtk_window_set_title(GTK_WINDOW(dialog), _("Question"));
res = gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
if(res == GTK_RESPONSE_YES)
return TRUE;
return FALSE;
}
/* mailer_foreach_message_selected */
static void _mailer_foreach_message_selected(Mailer * mailer,
MailerForeachMessageCallback callback)
{
GtkTreeModel * model;
GtkTreeSelection * treesel;
GList * selected;
GList * s;
GtkTreePath * path;
GtkTreeIter iter;
if((model = gtk_tree_view_get_model(GTK_TREE_VIEW(mailer->he_view)))
== NULL)
return;
if((treesel = gtk_tree_view_get_selection(GTK_TREE_VIEW(
mailer->he_view))) == NULL)
return;
if((selected = gtk_tree_selection_get_selected_rows(treesel, NULL))
== NULL)
return;
for(s = g_list_first(selected); s != NULL; s = g_list_next(s))
{
if((path = s->data) == NULL)
continue;
gtk_tree_model_get_iter(model, &iter, path);
callback(mailer, model, &iter);
}
g_list_free(selected);
}
/* mailer_get_config_filename */
static char * _mailer_get_config_filename(void)
/* FIXME consider replacing with mailer_save_config() */
{
char const * homedir;
char * filename;
if((homedir = getenv("HOME")) == NULL)
homedir = g_get_home_dir();
if((filename = malloc(strlen(homedir) + sizeof(MAILER_CONFIG_FILE) + 1))
== NULL)
return NULL;
sprintf(filename, "%s/%s", homedir, MAILER_CONFIG_FILE);
return filename;
}
/* mailer_update_status */
static void _mailer_update_status(Mailer * mailer)
{
GtkTreeModel * store;
int cnt;
char buf[256];
if((store = gtk_tree_view_get_model(GTK_TREE_VIEW(mailer->he_view)))
!= NULL)
{
cnt = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(store),
NULL);
snprintf(buf, sizeof(buf), _("%s/%s: %d %s"),
account_get_name(mailer->account_cur),
folder_get_name(mailer->folder_cur), cnt,
(cnt > 1) ? _("messages") : _("message"));
}
else
snprintf(buf, sizeof(buf), "%s", _("Ready"));
mailer_set_status(mailer, buf);
}