Implement SEARCH and take care when the data does not end with \r\n.

SVN revision: 30973
This commit is contained in:
Sebastian Dransfeld 2007-07-25 18:27:21 +00:00
parent 6421d38bcf
commit 70373ad673
2 changed files with 162 additions and 41 deletions

186
imap2.c
View File

@ -7,11 +7,8 @@
/*
* TODO:
* * Make it possible to get Unseen mail
* * Let the user select between Unseen and Recent mail
* * When a client reads the mailbox we don't always get <n> EXISTS
* and <n> RECENT updates. Need to parse f.eks.
* '* 71 FETCH (FLAGS (\Seen \Deleted \Recent NonJunk))'
* * Let the user select between Unseen, Recent and New mail
* * Don't fail on incomplete data from the server
*/
static ImapClient *_mail_imap_client_find (Ecore_Con_Server *server);
@ -24,6 +21,9 @@ static void _mail_imap_client_logout (ImapClient *ic);
static void _mail_imap_server_idle (ImapClient *ic);
static void _mail_imap_server_noop (ImapClient *ic);
static int elements (char *p);
static char *find_rn (char *data, unsigned int size);
static Evas_List *iclients = NULL;
void
@ -70,7 +70,7 @@ _mail_imap_check_mail (void *data)
}
else
{
if (ic->idle == 1) _mail_imap_server_idle (ic);
if (ic->idling) _mail_imap_server_idle (ic);
else _mail_imap_server_noop (ic);
/* Need to set this to revert the state of the icon */
_mail_set_text (ic->data);
@ -111,7 +111,6 @@ _mail_imap_del_mailbox (void *data)
iclients = evas_list_remove (iclients, ic);
_mail_imap_client_logout (ic);
E_FREE (ic);
}
void
@ -130,6 +129,7 @@ _mail_imap_shutdown ()
ecore_event_handler_del (ic->data_handler);
iclients = evas_list_remove_list (iclients, iclients);
_mail_imap_client_logout (ic);
E_FREE (ic->old.data);
E_FREE (ic);
}
}
@ -210,6 +210,7 @@ _mail_imap_server_del (void *data, int type, void *event)
ic->state = IMAP_STATE_DISCONNECTED;
}
E_FREE (ic->old.data);
ecore_con_server_del (ic->server);
ic->server = NULL;
@ -224,7 +225,7 @@ _mail_imap_server_data (void *data, int type, void *event)
ImapClient *ic;
char *reply, *p, *pp;
char out[1024];
int len;
unsigned int len, size;
ic = _mail_imap_client_find (ev->server);
if (!ic)
@ -232,36 +233,83 @@ _mail_imap_server_data (void *data, int type, void *event)
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'))
/* Hijack server data.
* We require minimum 2 characters, as the minimum server data is '\r\n' */
if ((ic->old.data) || (ev->size < 2))
{
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;
}
/* TODO: Check that we don't grow to big! */
ic->old.data = realloc (ic->old.data, ic->old.size + ev->size);
memcpy (ic->old.data + ic->old.size, ev->data, ev->size);
ic->old.size += ev->size;
E_FREE (ev->data);
if (ic->old.size < 2) return 0;
p = reply;
while ((p) && ((p - reply) < ev->size))
reply = ic->old.data;
size = ic->old.size;
ic->old.data = NULL;
ic->old.size = 0;
}
else
{
/* find eol */
pp = strstr (p, "\r\n");
if (pp) *pp = '\0';
reply = ev->data;
size = ev->size;
}
ev->data = NULL;
/* Check for correct EOD */
if ((*(reply + size - 2) != '\r') && (*(reply + size - 1) != '\n'))
{
/* We got incomplete data, search for last EOD */
unsigned int pos = 0;
char *data;
data = reply;
while (pos < (size - 1))
{
if ((*(reply + pos) == '\r') && (*(reply + pos + 1) == '\n'))
data = reply + pos + 2;
pos++;
}
ic->old.size = size - (data - reply);
ic->old.data = malloc (ic->old.size);
memcpy (ic->old.data, data, ic->old.size);
/* Remove captured data from reply */
if (data == reply)
E_FREE (reply);
else
{
printf ("Imap Failure: Couldn't find eol\n");
_mail_imap_client_logout (ic);
return 0;
data -= 2;
data = NULL;
data += 2;
size -= ic->old.size;
}
/* parse data */
if (!_mail_imap_server_data_parse (ic, p))
}
if (reply)
{
p = reply;
pp = p;
while ((p) && ((p - reply) < size))
{
_mail_imap_client_logout (ic);
return 0;
/* find EOL */
pp = find_rn (p, size - (pp - p));
if (!pp)
{
printf ("Imap Failure: Couldn't find EOL\n");
_mail_imap_client_logout (ic);
return 0;
}
*pp = '\0';
/* parse data */
if (!_mail_imap_server_data_parse (ic, p))
{
_mail_imap_client_logout (ic);
return 0;
}
/* next */
p = pp + 2;
}
/* next */
p = pp + 2;
free (reply);
}
switch (ic->state)
@ -282,23 +330,42 @@ _mail_imap_server_data (void *data, int type, void *event)
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++;
ic->state = IMAP_STATE_AUTHENTICATED;
}
break;
case IMAP_STATE_AUTHENTICATED:
len = snprintf (out, sizeof (out), "A%04i EXAMINE %s\r\n", ic->cmd++,
ic->config->new_path);
ecore_con_server_send (ic->server, out, len);
ic->state++;
ic->state = IMAP_STATE_SEARCH_UNSEEN;
break;
case IMAP_STATE_SELECTED:
case IMAP_STATE_IDLING:
if ((ic->idle == 1) && (!ic->idling))
{
printf ("Begin idle\n");
len = snprintf (out, sizeof (out), "A%04i IDLE\r\n", ic->cmd++);
ecore_con_server_send (ic->server, out, len);
ic->idling = 1;
}
break;
case IMAP_STATE_SEARCH_UNSEEN:
_mail_imap_server_idle (ic);
len = snprintf (out, sizeof (out), "A%04i SEARCH UNSEEN UNDELETED\r\n", ic->cmd++);
ecore_con_server_send (ic->server, out, len);
ic->state = IMAP_STATE_IDLING;
break;
case IMAP_STATE_SEARCH_RECENT:
_mail_imap_server_idle (ic);
len = snprintf (out, sizeof (out), "A%04i SEARCH RECENT UNDELETED\r\n", ic->cmd++);
ecore_con_server_send (ic->server, out, len);
ic->state = IMAP_STATE_IDLING;
break;
case IMAP_STATE_SEARCH_NEW:
_mail_imap_server_idle (ic);
len = snprintf (out, sizeof (out), "A%04i SEARCH NEW UNDELETED\r\n", ic->cmd++);
ecore_con_server_send (ic->server, out, len);
ic->state = IMAP_STATE_IDLING;
break;
}
if (ic->cmd > 9999)
ic->cmd = 1;
@ -400,6 +467,11 @@ _mail_imap_server_data_parse (ImapClient *ic, char *line)
{
printf ("Flags: %s\n", value);
}
else if (!strcmp (result, "SEARCH"))
{
ic->config->num_new = elements (value);
printf ("New mail: %d\n", ic->config->num_new);
}
else
{
char *p;
@ -410,16 +482,35 @@ _mail_imap_server_data_parse (ImapClient *ic, char *line)
if (!strcmp (value, "RECENT"))
{
printf ("Recent mails: %d\n", atoi (result));
ic->config->num_new = atoi (result);
//ic->state = IMAP_STATE_SEARCH_UNSEEN;
//ic->state = IMAP_STATE_SEARCH_RECENT;
ic->state = IMAP_STATE_SEARCH_NEW;
}
else if (!strcmp (value, "EXISTS"))
{
printf ("Existing mails: %d\n", atoi (result));
ic->config->num_total = atoi (result);
}
else if (!strcmp (value, "FETCH"))
{
printf ("Reading mail: %d\n", atoi (result));
//ic->state = IMAP_STATE_SEARCH_UNSEEN;
//ic->state = IMAP_STATE_SEARCH_RECENT;
ic->state = IMAP_STATE_SEARCH_NEW;
}
else if (!strcmp (value, "EXPUNGE"))
{
printf ("Deleting mail: %d\n", atoi (result));
//ic->state = IMAP_STATE_SEARCH_UNSEEN;
//ic->state = IMAP_STATE_SEARCH_RECENT;
ic->state = IMAP_STATE_SEARCH_NEW;
}
else
{
printf ("Unknown untagged reply: %s %s\n", line, value);
//ic->state = IMAP_STATE_SEARCH_UNSEEN;
//ic->state = IMAP_STATE_SEARCH_RECENT;
//ic->state = IMAP_STATE_SEARCH_NEW;
}
}
}
@ -440,6 +531,7 @@ _mail_imap_client_logout (ImapClient *ic)
if (!ic)
return;
E_FREE (ic->old.data);
if (ic->server)
{
int len;
@ -474,3 +566,29 @@ _mail_imap_server_noop (ImapClient *ic)
len = snprintf (out, sizeof (out), "A%04i NOOP\r\n", ic->cmd++);
ecore_con_server_send (ic->server, out, len);
}
static int
elements (char *p)
{
int count = 0;
if (!p) return 0;
do {
if (*p) count++;
p = strchr (p, ' ');
if (p) p++;
} while (p);
return count;
}
static char *
find_rn (char *data, unsigned int size)
{
while (size >= 2)
{
if ((*data == '\r') && (*(data + 1) == '\n')) return data;
data++;
size--;
}
return NULL;
}

17
imap2.h
View File

@ -15,7 +15,10 @@ typedef enum
IMAP_STATE_DISCONNECTED,
IMAP_STATE_CONNECTED,
IMAP_STATE_AUTHENTICATED,
IMAP_STATE_SELECTED
IMAP_STATE_IDLING,
IMAP_STATE_SEARCH_UNSEEN,
IMAP_STATE_SEARCH_RECENT,
IMAP_STATE_SEARCH_NEW
} ImapState;
struct _ImapClient
@ -23,7 +26,7 @@ struct _ImapClient
Config_Box *config;
Ecore_Con_Server *server;
int cmd;
unsigned int cmd;
ImapState state;
int idle;
unsigned char idling : 1;
@ -33,6 +36,11 @@ struct _ImapClient
Ecore_Event_Handler *data_handler;
void *data;
struct {
char *data;
unsigned int size;
} old;
};
void _mail_imap_check_mail(void *data);
@ -41,8 +49,3 @@ void _mail_imap_del_mailbox(void *data);
void _mail_imap_shutdown();
#endif
//imap.1and1.com
//m39988144-2/3
////testing/2
//