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;
};


Reply via email to