Reviewing Mailer's API

This commit is contained in:
Pierre Pronchery 2012-07-19 19:53:48 +00:00
parent 2c93657cc6
commit 3ea562e600
6 changed files with 139 additions and 38 deletions

View File

@ -59,6 +59,45 @@ typedef struct _AccountConfig
} AccountConfig;
/* AccountStatus */
typedef enum _AccountStatus
{
AS_CONNECTING = 0,
AS_CONNECTED,
AS_DISCONNECTED,
AS_AUTHENTICATED,
AS_READY
} AccountStatus;
/* AccountEvent */
typedef enum _AccountEventType
{
AET_ERROR = 0,
AET_STATUS
} AccountEventType;
typedef union _AccountEvent
{
AccountEventType type;
/* AET_ERROR */
struct
{
AccountEventType type;
char const * message;
} error;
/* AET_STATUS */
struct
{
AccountEventType type;
AccountStatus status;
char const * message;
} status;
} AccountEvent;
/* AccountPlugin */
typedef struct _AccountPluginHelper
{
@ -67,7 +106,7 @@ typedef struct _AccountPluginHelper
SSL_CTX * (*get_ssl_context)(Account * account);
/* useful */
int (*error)(Account * account, char const * message, int ret);
void (*status)(Account * account, char const * format, ...);
void (*event)(Account * account, AccountEvent * event);
/* authentication */
char * (*authenticate)(Account * account, char const * message);
int (*confirm)(Account * account, char const * message);

View File

@ -69,7 +69,7 @@ static SSL_CTX * _account_helper_get_ssl_context(Account * account);
/* useful */
static int _account_helper_error(Account * account, char const * message,
int ret);
static void _account_helper_status(Account * account, char const * format, ...);
static void _account_helper_event(Account * account, AccountEvent * event);
static char * _account_helper_authenticate(Account * account,
char const * message);
static int _account_helper_confirm(Account * account, char const * message);
@ -90,7 +90,7 @@ static const AccountPluginHelper _account_plugin_helper =
NULL,
_account_helper_get_ssl_context,
_account_helper_error,
_account_helper_status,
_account_helper_event,
_account_helper_authenticate,
_account_helper_confirm,
_account_helper_folder_new,
@ -187,7 +187,7 @@ void account_delete(Account * account)
/* accessors */
/* account_get_config */
AccountConfig * account_get_config(Account * account)
AccountConfig const * account_get_config(Account * account)
{
if(account->account == NULL)
return account->definition->config;
@ -436,28 +436,20 @@ static int _account_helper_error(Account * account, char const * message,
}
/* account_helper_status */
static void _account_helper_status(Account * account, char const * format, ...)
/* account_helper_event */
static void _account_helper_event(Account * account, AccountEvent * event)
{
va_list ap;
int res;
size_t size;
char * p = NULL;
Mailer * mailer = account->mailer;
va_start(ap, format);
res = vsprintf(NULL, format, ap);
va_end(ap);
if(res >= 0)
switch(event->type)
{
va_start(ap, format);
size = res;
if((p = malloc(++size)) != NULL)
vsnprintf(p, size, format, ap);
va_end(ap);
case AET_ERROR:
mailer_error(mailer, event->error.message, 1);
break;
case AET_STATUS:
mailer_set_status(mailer, event->status.message);
break;
}
if(p != NULL)
mailer_set_status(account->mailer, p);
free(p);
}

View File

@ -35,7 +35,7 @@ void account_delete(Account * account);
int account_get_enabled(Account * account);
void account_set_enabled(Account * account, int enabled);
AccountConfig * account_get_config(Account * account);
AccountConfig const * account_get_config(Account * account);
char const * account_get_name(Account * account);
char const * account_get_title(Account * account);
char const * account_get_type(Account * account);

View File

@ -943,11 +943,13 @@ static gboolean _on_connect(gpointer data)
{
IMAP4 * imap4 = data;
AccountPluginHelper * helper = imap4->helper;
AccountEvent event;
char const * hostname;
char const * p;
uint16_t port;
struct sockaddr_in sa;
int res;
char buf[128];
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s()\n", __func__);
@ -956,7 +958,7 @@ static gboolean _on_connect(gpointer data)
/* get the hostname and port */
if((hostname = imap4->config[I4CV_HOSTNAME].value) == NULL)
{
helper->error(NULL, "No hostname set", 1);
helper->error(helper->account, "No hostname set", 1);
return FALSE;
}
if((p = imap4->config[I4CV_PORT].value) == NULL)
@ -978,9 +980,15 @@ static gboolean _on_connect(gpointer data)
&& fcntl(imap4->fd, F_SETFL, res | O_NONBLOCK) == -1)
/* ignore this error */
helper->error(NULL, strerror(errno), 1);
/* connect to the remote host */
helper->status(helper->account, "Connecting to %s (%s:%u)", hostname,
/* report the current status */
memset(&event, 0, sizeof(event));
event.status.type = AET_STATUS;
event.status.status = AS_CONNECTING;
snprintf(buf, sizeof(buf), "Connecting to %s (%s:%u)", hostname,
inet_ntoa(sa.sin_addr), port);
event.status.message = buf;
helper->event(helper->account, &event);
/* connect to the remote host */
if((connect(imap4->fd, (struct sockaddr *)&sa, sizeof(sa)) != 0
&& errno != EINPROGRESS)
|| _connect_channel(imap4) != 0)
@ -1050,6 +1058,7 @@ static gboolean _on_watch_can_connect(GIOChannel * source,
{
IMAP4 * imap4 = data;
AccountPluginHelper * helper = imap4->helper;
AccountEvent event;
char const * hostname = imap4->config[I4CV_HOSTNAME].value;
uint16_t port = (unsigned long)imap4->config[I4CV_PORT].value;
struct sockaddr_in sa;
@ -1063,8 +1072,16 @@ static gboolean _on_watch_can_connect(GIOChannel * source,
#endif
/* XXX remember the address instead */
if(_imap4_lookup(imap4, hostname, port, &sa) == 0)
helper->status(helper->account, "Connected to %s (%s:%u)",
{
/* report the current status */
memset(&event, 0, sizeof(event));
event.status.type = AET_STATUS;
event.status.status = AS_CONNECTED;
snprintf(buf, sizeof(buf), "Connected to %s (%s:%u)",
hostname, inet_ntoa(sa.sin_addr), port);
event.status.message = buf;
helper->event(helper->account, &event);
}
imap4->wr_source = 0;
/* setup SSL */
if(imap4->config[I4CV_SSL].value != NULL)

View File

@ -21,6 +21,7 @@
#include <sys/socket.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
@ -155,7 +156,7 @@ static int _pop3_refresh(POP3 * pop3, AccountFolder * folder,
/* useful */
static POP3Command * _pop3_command(POP3 * pop3, POP3Context context,
char const * command);
static int _pop3_lookup(POP3 * pop3, char const * hostname, unsigned short port,
static int _pop3_lookup(POP3 * pop3, char const * hostname, uint16_t port,
struct sockaddr_in * sa);
static int _pop3_parse(POP3 * pop3);
static void _pop3_reset(POP3 * pop3);
@ -316,7 +317,7 @@ static POP3Command * _pop3_command(POP3 * pop3, POP3Context context,
/* pop3_lookup */
static int _pop3_lookup(POP3 * pop3, char const * hostname, unsigned short port,
static int _pop3_lookup(POP3 * pop3, char const * hostname, uint16_t port,
struct sockaddr_in * sa)
{
struct hostent * he;
@ -587,11 +588,13 @@ static gboolean _on_connect(gpointer data)
{
POP3 * pop3 = data;
AccountPluginHelper * helper = pop3->helper;
AccountEvent event;
char const * hostname;
char const * p;
unsigned short port;
uint16_t port;
struct sockaddr_in sa;
int res;
char buf[128];
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s()\n", __func__);
@ -612,6 +615,7 @@ static gboolean _on_connect(gpointer data)
helper->error(NULL, error_get(), 1);
return FALSE;
}
/* create the socket */
if((pop3->fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
helper->error(NULL, strerror(errno), 1);
@ -621,9 +625,15 @@ static gboolean _on_connect(gpointer data)
&& fcntl(pop3->fd, F_SETFL, res | O_NONBLOCK) == -1)
/* ignore this error */
helper->error(NULL, strerror(errno), 1);
/* connect to the remote host */
helper->status(helper->account, "Connecting to %s (%s:%u)", hostname,
/* report the current status */
memset(&event, 0, sizeof(event));
event.status.type = AET_STATUS;
event.status.status = AS_CONNECTING;
snprintf(buf, sizeof(buf), "Connecting to %s (%s:%u)", hostname,
inet_ntoa(sa.sin_addr), port);
event.status.message = buf;
helper->event(helper->account, &event);
/* connect to the remote host */
if((connect(pop3->fd, (struct sockaddr *)&sa, sizeof(sa)) != 0
&& errno != EINPROGRESS)
|| _connect_channel(pop3) != 0)
@ -691,8 +701,9 @@ static gboolean _on_watch_can_connect(GIOChannel * source,
{
POP3 * pop3 = data;
AccountPluginHelper * helper = pop3->helper;
AccountEvent event;
char const * hostname = pop3->config[P3CV_HOSTNAME].value;
unsigned short port = (unsigned long)pop3->config[P3CV_PORT].value;
uint16_t port = (unsigned long)pop3->config[P3CV_PORT].value;
struct sockaddr_in sa;
SSL_CTX * ssl_ctx;
char buf[128];
@ -704,8 +715,16 @@ static gboolean _on_watch_can_connect(GIOChannel * source,
#endif
/* XXX remember the address instead */
if(_pop3_lookup(pop3, hostname, port, &sa) == 0)
helper->status(helper->account, "Connected to %s (%s:%u)",
{
/* report the current status */
memset(&event, 0, sizeof(event));
event.status.type = AET_STATUS;
event.status.status = AS_CONNECTED;
snprintf(buf, sizeof(buf), "Connected to %s (%s:%u)",
hostname, inet_ntoa(sa.sin_addr), port);
event.status.message = buf;
helper->event(helper->account, &event);
}
pop3->wr_source = 0;
/* setup SSL */
if(pop3->config[P3CV_SSL].value != NULL)

View File

@ -92,6 +92,10 @@ struct _Mailer
/* widgets */
/* folders */
GtkWidget * fo_window;
#if GTK_CHECK_VERSION(2, 18, 0)
GtkWidget * fo_infobar;
GtkWidget * fo_infobar_label;
#endif
GtkTreeStore * fo_store;
GtkWidget * fo_view;
/* headers */
@ -397,6 +401,25 @@ Mailer * mailer_new(void)
/* toolbar */
widget = desktop_toolbar_create(_mailer_fo_toolbar, mailer, group);
gtk_box_pack_start(GTK_BOX(vbox), widget, FALSE, TRUE, 0);
#if GTK_CHECK_VERSION(2, 18, 0)
/* infobar */
mailer->fo_infobar = gtk_info_bar_new_with_buttons(GTK_STOCK_CLOSE,
GTK_RESPONSE_CLOSE, NULL);
gtk_info_bar_set_message_type(GTK_INFO_BAR(mailer->fo_infobar),
GTK_MESSAGE_ERROR);
g_signal_connect(mailer->fo_infobar, "close", G_CALLBACK(
gtk_widget_hide), NULL);
g_signal_connect(mailer->fo_infobar, "response", G_CALLBACK(
gtk_widget_hide), NULL);
widget = gtk_info_bar_get_content_area(GTK_INFO_BAR(
mailer->fo_infobar));
mailer->fo_infobar_label = gtk_label_new(NULL);
gtk_widget_show(mailer->fo_infobar_label);
gtk_box_pack_start(GTK_BOX(widget), mailer->fo_infobar_label, TRUE,
TRUE, 0);
gtk_widget_set_no_show_all(mailer->fo_infobar, TRUE);
gtk_box_pack_start(GTK_BOX(vbox), mailer->fo_infobar, FALSE, TRUE, 0);
#endif
/* folders */
widget = gtk_scrolled_window_new(NULL, NULL);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(widget),
@ -457,9 +480,9 @@ Mailer * mailer_new(void)
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)
# if GTK_CHECK_VERSION(2, 6, 0)
gtk_window_set_icon_name(GTK_WINDOW(mailer->bo_window), "mailer");
#endif
# 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);
@ -992,17 +1015,25 @@ void mailer_set_status(Mailer * mailer, char const * status)
/* mailer_error */
int mailer_error(Mailer * mailer, char const * message, int ret)
{
#if !GTK_CHECK_VERSION(2, 18, 0)
GtkWidget * dialog;
#endif
if(mailer == NULL)
return error_set_print("mailer", ret, "%s", message);
#if GTK_CHECK_VERSION(2, 18, 0)
/* info bar */
gtk_label_set_text(GTK_LABEL(mailer->fo_infobar_label), message);
gtk_widget_show(mailer->fo_infobar);
#else
/* dialog window */
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)
# if GTK_CHECK_VERSION(2, 6, 0)
"%s", _("Error"));
gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
#endif
# endif
"%s", message);
gtk_window_set_title(GTK_WINDOW(dialog), _("Error"));
gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(
@ -1010,6 +1041,7 @@ int mailer_error(Mailer * mailer, char const * message, int ret)
g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(
gtk_widget_destroy), NULL);
gtk_widget_show(dialog);
#endif
return ret;
}
@ -2058,6 +2090,8 @@ static GtkWidget * _assistant_account_select(AccountData * ad)
_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);
/* default identity */
/* FIXME seems to not be remembered */
hbox = gtk_hbox_new(FALSE, 4);
_account_add_label(hbox, NULL, group, _("Your name"));
widget = gtk_entry_new();