With the recent checkin of the gadget stuff in CVS, I suddenly got this
idea to implement a gadget that tells you of new mail in a more clean
way than the current alternative does..
so, to get started, I just wrote the code that talks to IMAP (over SSL)
it works well enough, but I'd like to get some input on the code early
on, so I don't code myself into a corner later on..
now, keep in mind, this is extremely basic code..
one of the very next things I'll be implementing is using ecore_config
rather than #define :)
to compile, gcc -lecore -lecore_con -lpcre email.c -o email
Cheers,
--
Morten
// Enlightened mail checker by Morten Nilsen
#include "email.h"
int imap_seq, recent;
struct imap_res *imap_queue;
Ecore_Con_Server *srv;
pcre *imapre;
pcre *listre;
pcre *rcntre;
int main (int argc, char **argv)
{
const char *error;
int erroffset;
imapre = pcre_compile("^A(\\d\\d\\d) (OK|NO) ([\\[\\]A-Z-]*) (.*?)", 0,
&error, &erroffset, NULL);
listre = pcre_compile("^\\* LIST \\(.*\\\\Marked .*\\) \"\\.\" \"(.*)\"", 0,
&error, &erroffset, NULL);
rcntre = pcre_compile("^\\* (\\d+) RECENT", 0, &error, &erroffset, NULL);
Ecore_Event_Handler *data = NULL;
struct Data *imap;
ecore_init();
ecore_con_init();
imap = calloc(1, sizeof(struct Data));
imap_queue = calloc(1, sizeof(struct imap_res));
data =
ecore_event_handler_add(ECORE_CON_EVENT_SERVER_DATA, server_data_cb, NULL);
ecore_event_handler_add(ECORE_CON_EVENT_SERVER_ADD, server_add_cb, NULL);
ecore_event_handler_add(ECORE_CON_EVENT_SERVER_DEL, server_del_cb, NULL);
ecore_event_handler_add(ECORE_EVENT_SIGNAL_EXIT, imap_logout, NULL);
srv = ecore_con_server_connect(ECORE_CON_REMOTE_SYSTEM | ECORE_CON_USE_SSL,
"ryo-ohki.4th-age.com", 993, imap);
ecore_main_loop_begin();
ecore_event_handler_del(data);
ecore_con_shutdown();
return 0;
}
void imap_command(char *cmd)
{
char buf[1024];
snprintf(buf, 1024, "A%03d %s\n", imap_seq++, cmd);
ecore_con_server_send(srv, buf, strlen(buf));
}
void imap_login(char *username, char *password)
{
char buf[200];
snprintf(buf, 200, "LOGIN %s %s", username, password);
imap_command(buf);
}
static int imap_logout(void *data, int type, void *ev)
{
imap_command("LOGOUT");
return 0;
}
static int imap_list(void *data)
{
printf("---\n");
struct imap_res *queue;
while((queue = imap_queue->next))
{
free(imap_queue);
imap_queue = queue;
}
imap_queue->seq = 0;
imap_command("LIST \"\" *");
return 1;
}
void imap_cap()
{
ecore_con_server_send(srv, "CAPABILITY\n", 11);
}
void imap_examine(const char *mbox)
{
char buf[1024];
snprintf(buf, 1024, "EXAMINE %s", mbox);
imap_command(buf);
}
void imap_parse(char *line)
{
int rc, seq;
int ovector[30];
const char *r;
struct imap_res *queue;
if(line[0] == '*')
{
rc = pcre_exec(rcntre, NULL, line, strlen(line), 0, 0, ovector, 30);
if(rc >= 0)
{
pcre_get_substring(line, ovector, rc, 1, &r);
recent = atoi(r);
return;
}
rc = pcre_exec(listre, NULL, line, strlen(line), 0, 0, ovector, 30);
if(rc < 0)
{
if(imap_seq == 0)
{
printf("Logging in...\n");
imap_login(USERNAME, PASSWORD);
}
return;
}
pcre_get_substring(line, ovector, rc, 1, &r);
queue = imap_queue;
while(queue->seq > 0 && queue->next != NULL)
queue = queue->next;
if(queue == NULL)
{
queue = calloc(1, sizeof(struct imap_res));
} else if(queue->next == NULL) {
queue->next = calloc(1, sizeof(struct imap_res));
queue = queue->next;
}
queue->seq = imap_seq;
queue->mbox = strdup(r);
imap_examine(queue->mbox);
return;
} else {
if(line[5] == 'N')
{
printf("Error: %s\n", line);
return;
}
rc = pcre_exec(imapre, NULL, line, strlen(line), 0, 0, ovector, 30);
pcre_get_substring(line, ovector, rc, 1, &r);
seq = atoi(r);
pcre_get_substring(line, ovector, rc, 3, &r);
if(!strcmp("LOGIN", r))
{
imap_list(NULL);
ecore_timer_add(CHECK_DELAY, imap_list, NULL);
} else
if(!strcmp("[READ-ONLY]", r))
{
queue = imap_queue;
while(queue->seq != seq && queue->next != NULL)
queue = queue->next;
if(queue == NULL || queue->seq != seq)
{
printf("!!! no match found for seq %d\n", seq);
return;
}
if(recent == 0)
{
printf("%s has unread messages.\n", queue->mbox);
} else {
printf("%s has %d new messages.\n", queue->mbox, recent);
}
recent = 0;
free(queue->mbox);
}
}
}
int imap_process(char *buf)
{
char *l;
int i, j, done;
l = malloc(strlen(buf));
i = 0;
j = 0;
done = 0;
while(buf[j]) {
switch(buf[j]) {
case 0:
break;
case '\r':
j++;
break;
case '\n':
l[i] = 0;
j++;
done = j;
i = 0;
imap_parse(l);
break;
default:
l[i++] = buf[j++];
break;
}
}
return done;
}
static int server_add_cb(void *data, int type, void *ev)
{
Ecore_Con_Event_Server_Add *e;
e = ev;
printf("Connected..\n");
imap_seq = 0;
return 0;
}
static int server_del_cb(void *data, int type, void *ev)
{
Ecore_Con_Event_Server_Del *e;
e = ev;
ecore_con_server_del(e->server);
ecore_main_loop_quit();
return 0;
}
static int server_data_cb(void *data, int type, void *ev)
{
Ecore_Con_Event_Server_Data *e;
struct Data *imap;
int done;
e = ev;
imap = ecore_con_server_data_get(e->server);
imap->buf = realloc(imap->buf, imap->size + e->size + 1);
memcpy(imap->buf + imap->size, e->data, e->size);
imap->size += e->size;
imap->buf[imap->size] = 0;
done = imap_process(imap->buf);
if(imap->buf[imap->size - 1] == '\n')
{
imap->size = 0;
imap->buf[0] = 0;
return 1;
}
memmove(imap->buf, imap->buf + done, imap->size - done);
imap->size -= done;
imap->buf = realloc(imap->buf, imap->size);
return 1;
}
#include <Ecore.h>
#include <Ecore_Con.h>
#include <pcre/pcre.h>
#include <stdio.h>
#include <string.h>
#define CHECK_DELAY 120
#define USERNAME "user"
#define PASSWORD "secret"
static int server_add_cb(void *data, int type, void *ev);
static int server_del_cb(void *data, int type, void *ev);
static int server_data_cb(void *data, int type, void *ev);
static int imap_logout(void *data, int type, void *ev);
static int imap_list(void *data);
int imap_process(char *buf);
void imap_command(char *cmd);
void imap_login(char *username, char *password);
void imap_examine(const char *mbox);
void imap_parse(char *line);
void imap_cap();
struct imap_res {
char *mbox;
int seq;
struct imap_res *next;
};
struct Data {
char *buf;
int size;
};