From 5819f0ed092e3d8c46406250919f038791d5fab7 Mon Sep 17 00:00:00 2001 From: Sebastian Dransfeld Date: Thu, 21 Jun 2007 05:46:45 +0000 Subject: [PATCH] Working on a more compliant imap checker using IDLE. See: http://www.washington.edu/imap/documentation/commndmt.txt.html Code isn't done yet, only here for those who want to play with it. Must be enabled manually. SVN revision: 30415 --- Makefile.am | 6 +- configure.in | 3 + e_mod_main.c | 4 + imap2.c | 519 +++++++++++++++++++++++++++++++++++++++++++++++++++ imap2.h | 48 +++++ 5 files changed, 579 insertions(+), 1 deletion(-) create mode 100644 imap2.c create mode 100644 imap2.h diff --git a/Makefile.am b/Makefile.am index e16cbf5..d12cd66 100644 --- a/Makefile.am +++ b/Makefile.am @@ -34,10 +34,14 @@ module_la_SOURCES = e_mod_main.c \ e_mod_config.c \ e_mod_config_box.h \ e_mod_config_box.c \ - imap.h imap.c \ pop.h pop.c \ mdir.h mdir.c \ mbox.h mbox.c +if IMAP2 +module_la_SOURCES += imap2.h imap2.c +else +module_la_SOURCES += imap.h imap.c +endif module_la_LIBADD = @e_libs@ module_la_LDFLAGS = -module -avoid-version diff --git a/configure.in b/configure.in index f86b8ca..d3bfc8b 100644 --- a/configure.in +++ b/configure.in @@ -131,6 +131,9 @@ AC_SUBST(e_cflags) AC_SUBST(e_libs) AC_SUBST(e_modules) +# uncomment this for new imap code +#AM_CONDITIONAL(IMAP2, true) + AC_OUTPUT([ Makefile po/Makefile diff --git a/e_mod_main.c b/e_mod_main.c index 093ce1b..65cfe7e 100644 --- a/e_mod_main.c +++ b/e_mod_main.c @@ -22,7 +22,11 @@ #include #include "e_mod_main.h" +#ifdef IMAP2 +#include "imap2.h" +#else #include "imap.h" +#endif #include "pop.h" #include "mdir.h" #include "mbox.h" diff --git a/imap2.c b/imap2.c new file mode 100644 index 0000000..b0afc56 --- /dev/null +++ b/imap2.c @@ -0,0 +1,519 @@ +/* + * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 + */ +#include +#include "e_mod_main.h" +#include "imap2.h" + +static ImapClient *_mail_imap_client_find (Ecore_Con_Server *server); +static ImapClient *_mail_imap_client_get (Config_Box *cb); +static int _mail_imap_server_add (void *data, int type, void *event); +static int _mail_imap_server_del (void *data, int type, void *event); +static int _mail_imap_server_data (void *data, int type, void *event); +static int _mail_imap_server_data_parse (ImapClient *ic, char *line, int length); +static void _mail_imap_client_logout (ImapClient *ic); +static int _mail_imap_server_idle (void *data); +static int _mail_imap_server_noop (void *data); + +static Evas_List *iclients = NULL; + +void +_mail_imap_check_mail (void *data) +{ + Ecore_Con_Type type; + Evas_List *l; + + for (l = iclients; l; l = l->next) + { + ImapClient *ic; + + ic = l->data; + ic->data = data; + if (!ic->server) + { + if (!ic->add_handler) + ic->add_handler = + ecore_event_handler_add (ECORE_CON_EVENT_SERVER_ADD, + _mail_imap_server_add, NULL); + if (!ic->del_handler) + ic->del_handler = + ecore_event_handler_add (ECORE_CON_EVENT_SERVER_DEL, + _mail_imap_server_del, NULL); + if (!ic->data_handler) + ic->data_handler = + ecore_event_handler_add (ECORE_CON_EVENT_SERVER_DATA, + _mail_imap_server_data, NULL); + + if (ic->config->local) + type = ECORE_CON_LOCAL_SYSTEM; + else + type = ECORE_CON_REMOTE_SYSTEM; + + if (ecore_con_ssl_available_get () && (ic->config->ssl)) + type |= ECORE_CON_USE_SSL; + ic->state = IMAP_STATE_DISCONNECTED; + printf ("Connect: %s %d %d\n", ic->config->host, ic->config->port, ic->config->ssl); + ic->server = + ecore_con_server_connect (type, ic->config->host, + ic->config->port, NULL); + ic->cmd = 1; + ic->idle = -1; + } + } +} + +void +_mail_imap_add_mailbox (void *data) +{ + Config_Box *cb; + + cb = data; + if (!cb) + return; + /* Client get will create the client if it does not exist */ + _mail_imap_client_get (cb); +} + +void +_mail_imap_del_mailbox (void *data) +{ + ImapClient *ic; + Config_Box *cb; + + cb = data; + if (!cb) + return; + ic = _mail_imap_client_get (cb); + if (!ic) + return; + if (ic->add_handler) + ecore_event_handler_del (ic->add_handler); + if (ic->del_handler) + ecore_event_handler_del (ic->del_handler); + if (ic->data_handler) + ecore_event_handler_del (ic->data_handler); + iclients = evas_list_remove (iclients, ic); + _mail_imap_client_logout (ic); + E_FREE (ic); + +} + +void +_mail_imap_shutdown () +{ + while (iclients) + { + ImapClient *ic; + + ic = iclients->data; + if (ic->add_handler) + ecore_event_handler_del (ic->add_handler); + if (ic->del_handler) + ecore_event_handler_del (ic->del_handler); + if (ic->data_handler) + ecore_event_handler_del (ic->data_handler); + iclients = evas_list_remove_list (iclients, iclients); + _mail_imap_client_logout (ic); + E_FREE (ic); + } +} + +/* PRIVATES */ +static ImapClient * +_mail_imap_client_find (Ecore_Con_Server *server) +{ + Evas_List *l; + + for (l = iclients; l; l = l->next) + { + ImapClient *ic; + + ic = l->data; + if (ic->server == server) + return ic; + } + return NULL; +} + +static ImapClient * +_mail_imap_client_get (Config_Box *cb) +{ + ImapClient *ic; + Evas_List *l; + + if (!cb) + return NULL; + + for (l = iclients; l; l = l->next) + { + ic = l->data; + if (ic->config == cb) return ic; + } + + ic = E_NEW (ImapClient, 1); + ic->config = cb; + + ic->cmd = 1; + ic->state = IMAP_STATE_DISCONNECTED; + + ic->config->num_new = 0; + ic->config->num_total = 0; + + iclients = evas_list_append (iclients, ic); + return ic; +} + +static int +_mail_imap_server_add (void *data, int type, void *event) +{ + Ecore_Con_Event_Server_Add *ev = event; + ImapClient *ic; + + ic = _mail_imap_client_find (ev->server); + if (!ic) + return 1; + + ic->state = IMAP_STATE_CONNECTED; + ic->cmd = 1; + return 0; +} + +static int +_mail_imap_server_del (void *data, int type, void *event) +{ + Ecore_Con_Event_Server_Del *ev = event; + ImapClient *ic; + + ic = _mail_imap_client_find (ev->server); + if (!ic) + return 1; + + if (ic->state == IMAP_STATE_DISCONNECTED) + printf ("Imap Server Disconnected\n"); + else + ic->state = IMAP_STATE_DISCONNECTED; + + ecore_con_server_del (ic->server); + ic->server = NULL; + + _mail_set_text (ic->data); + return 0; +} + +static int +_mail_imap_server_data (void *data, int type, void *event) +{ + Ecore_Con_Event_Server_Data *ev = event; + ImapClient *ic; + char *reply, *p, *pp; + char out[1024]; + int len; + + ic = _mail_imap_client_find (ev->server); + if (!ic) + return 1; + if (ic->state == IMAP_STATE_DISCONNECTED) + return 1; + + reply = ev->data; + /* Check for correct EOD */ + if ((*(reply + ev->size - 2) != '\r') && (*(reply + ev->size - 1) != '\n')) + { + printf ("Imap Failure: Data from imap server has wrong eol termination 0x%x0x%x!\n", + *(reply + ev->size - 2), *(reply + ev->size - 2)); + _mail_imap_client_logout (ic); + return 0; + } + + p = reply; + while ((p) && ((p - reply) < ev->size)) + { + /* find eol */ + pp = strstr (p, "\r\n"); + if (pp) *pp = '\0'; + else + { + printf ("Imap Failure: Couldn't find eol\n"); + return 0; + } + printf ("Server data |%s|\n", p); + /* parse data */ + if (!_mail_imap_server_data_parse (ic, p, pp - p)) + { + _mail_imap_client_logout (ic); + return 0; + } + /* cleanup */ + p = pp + 2; + } + + switch (ic->state) + { + case IMAP_STATE_DISCONNECTED: + /* ignore */ + break; + case IMAP_STATE_CONNECTED: + if (ic->idle == -1) + { + /* Check whether this server supports idle */ + len = snprintf (out, sizeof (out), "A%04i CAPABILITY\r\n", ic->cmd++); + ecore_con_server_send (ic->server, out, len); + } + else + { + /* Log in */ + len = snprintf (out, sizeof (out), "A%04i LOGIN %s %s\r\n", ic->cmd++, + ic->config->user, ic->config->pass); + ecore_con_server_send (ic->server, out, len); + ic->state++; + } + break; + case IMAP_STATE_AUTHENTICATED: + len = snprintf (out, sizeof (out), "A%04i SELECT %s\r\n", ic->cmd++, + ic->config->new_path); + ecore_con_server_send (ic->server, out, len); + ic->state++; + break; + case IMAP_STATE_SELECTED: + if (ic->idle == 1) + { + if (!ic->timer) + { + len = snprintf (out, sizeof (out), "A%04i IDLE\r\n", ic->cmd++); + ecore_con_server_send (ic->server, out, len); + ic->timer = ecore_timer_add (29 * 60.0, _mail_imap_server_idle, ic); + } + } + else if (ic->idle == 0) + { + if (!ic->timer) ic->timer = ecore_timer_add (5 * 60.0, _mail_imap_server_noop, ic); + } + break; + } + if (ic->cmd > 9999) + ic->cmd = 1; + return 0; +} + +static int +_mail_imap_server_data_parse (ImapClient *ic, char *line, int length) +{ + if (line[0] == 'A') + { + char *result, *value; + + result = strchr (line, ' '); + if (!result) + { + printf ("Imap Failure: Missing result for tagged reply\n"); + return 0; + } + result++; + value = strchr (result, ' '); + if (value) + { + *value = '\0'; + value++; + } + else + value = ""; + /* This is a reply to one of our commands */ + if (!strcmp (result, "NO")) + { + printf ("Imap Failure: %s\n", value); + return 0; + } + else if (!strcmp (result, "BAD")) + { + printf ("Imap Bad Command: %s\n", value); + return 0; + } + else if (!strcmp (result, "OK")) + { + printf ("Reply ok: %s\n", value); + } + else + { + printf ("Unknown tagged reply: %s %s\n", line, value); + } + } + else if (line[0] == '*') + { + char *result, *value; + + result = strchr (line, ' '); + if (!result) + { + printf ("Imap Failure: Missing result for tagged reply\n"); + return 0; + } + result++; + value = strchr (result, ' '); + if (value) + { + *value = '\0'; + value++; + } + else + value = ""; + + if (!strcmp (result, "CAPABILITY")) + { + char *p, *pp; + + p = value; + while (p) + { + pp = strchr (p, ' '); + if (pp) *pp = '\0'; + if (!strcmp (p, "IDLE")) + { + printf ("Server supports idle\n"); + ic->idle = 1; + } + if (pp) + { + *pp = ' '; + p = pp + 1; + } + else + p = NULL; + } + if (ic->idle == -1) ic->idle = 0; + } + else if (!strcmp (result, "OK")) + { + printf ("Result OK: %s\n", value); + } + else + { + char *p; + + /* The result can be */ + p = strchr (value, ' '); + if (p) *p = '\0'; + if (!strcmp (value, "RECENT")) + { + printf ("Recent mails: %d\n", atoi (result)); + ic->config->num_new = atoi (result); + _mail_set_text (ic->data); + } + else if (!strcmp (value, "EXISTS")) + { + printf ("Existing mails: %d\n", atoi (result)); + ic->config->num_total = atoi (result); + _mail_set_text (ic->data); + } + else + { + printf ("Unknown untagged reply: %s %s\n", line, value); + } + } + } + else if (line[0] == '+') + { + /* Continuation mode */ + } + else + { + printf ("Unknown reply: %s\n", line); + } +#if 0 + + if (!is->current) return 0; + ic = is->current->data; + is->state++; + + printf ("IMAP data: |%s|\n", in); + printf ("|%s|\n", strstr (in, "\r\n")); + switch (is->state) + { + case IMAP_STATE_SERVER_READY: + len = + snprintf (out, sizeof (out), "A%04i LOGIN %s %s\r\n", ++is->cmd, + is->user, is->pass); + ecore_con_server_send (ev->server, out, len); + break; + case IMAP_STATE_STATUS_OK: + if (sscanf (in, "* STATUS %*s (MESSAGES %i UNSEEN %i)", &total, &num) == 2) + { + ic->config->num_new = num; + ic->config->num_total = total; + _mail_set_text (is->data); + + if ((num > 0) && (ic->config->use_exec) && (ic->config->exec)) + _mail_start_exe (ic->config); + } + + ic = NULL; + is->current = is->current->next; + if (is->current) + { + is->state = IMAP_STATE_LOGGED_IN; + ic = is->current->data; + } + else + _mail_imap_server_logout (is); + /* Fall through if we have another mailbox to check */ + if (!ic) + break; + case IMAP_STATE_LOGGED_IN: + len = + snprintf (out, sizeof (out), "A%04i STATUS %s (MESSAGES UNSEEN)\r\n", + ++is->cmd, ic->config->new_path); + ecore_con_server_send (ev->server, out, len); + break; + default: + break; + } +#endif + return 1; +} + +static void +_mail_imap_client_logout (ImapClient *ic) +{ + if (!ic) + return; + + if (ic->server) + { + int len; + char out[1024]; + + len = snprintf (out, sizeof (out), "A%04i LOGOUT", ic->cmd++); + ecore_con_server_send (ic->server, out, len); + ecore_con_server_del (ic->server); + } + ic->server = NULL; + if (ic->timer) ecore_timer_del(ic->timer); + ic->timer = NULL; + ic->state = IMAP_STATE_DISCONNECTED; +} + +static int +_mail_imap_server_idle (void *data) +{ + ImapClient *ic; + char out[1024]; + int len; + + ic = data; + len = snprintf (out, sizeof (out), "DONE\r\n"); + ecore_con_server_send (ic->server, out, len); + ic->timer = NULL; + return 0; +} + +static int +_mail_imap_server_noop (void *data) +{ + ImapClient *ic; + char out[1024]; + int len; + + ic = data; + len = snprintf (out, sizeof (out), "A%04i NOOP\r\n", ic->cmd++); + ecore_con_server_send (ic->server, out, len); + return 1; +} diff --git a/imap2.h b/imap2.h new file mode 100644 index 0000000..4462a3f --- /dev/null +++ b/imap2.h @@ -0,0 +1,48 @@ +/* + * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 + */ +#ifndef IMAP_H +#define IMAP_H + +#include +#include "e_mod_main.h" + +typedef struct _ImapServer ImapServer; +typedef struct _ImapClient ImapClient; + +typedef enum +{ + IMAP_STATE_DISCONNECTED, + IMAP_STATE_CONNECTED, + IMAP_STATE_AUTHENTICATED, + IMAP_STATE_SELECTED +} ImapState; + +struct _ImapClient +{ + Config_Box *config; + + Ecore_Con_Server *server; + int cmd; + ImapState state; + int idle; + + Ecore_Event_Handler *add_handler; + Ecore_Event_Handler *del_handler; + Ecore_Event_Handler *data_handler; + Ecore_Timer *timer; + + void *data; +}; + +void _mail_imap_check_mail(void *data); +void _mail_imap_add_mailbox(void *data); +void _mail_imap_del_mailbox(void *data); +void _mail_imap_shutdown(); + +#endif + +//imap.1and1.com +//m39988144-2/3 +////testing/2 +//