/*
** Copyright (C) 2006 Thadeu Lima de Souza Cascardo <cascardo@minaslivre.org>
-** Copyright (C) 2009 Thadeu Lima de Souza Cascardo <cascardo@holoscopio.com>
+** Copyright (C) 2009 Thadeu Lima de Souza Cascardo <cascardo@minaslivre.org>
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
**
*/
-#include <gnet.h>
#include <glib.h>
-#include "nethook.h"
+#include <string.h>
+#include "hcconn_internal.h"
#include "pop.h"
+#include "usermap.h"
typedef struct
{
- net_read orig_read;
- gpointer orig_data;
+ GString *buffer;
+ GString *line;
+ GString *push;
+ gchar *user;
+ HCConn *lowconn;
} pop_t;
+void
+pop_destroy (pop_t *pop)
+{
+ g_string_free (pop->buffer, TRUE);
+ g_string_free (pop->line, TRUE);
+ g_string_free (pop->push, TRUE);
+ if (pop->user)
+ g_free (pop->user);
+ g_slice_free (pop_t, (gpointer) pop);
+}
+
+static int
+pop_check_user (pop_t *pop)
+{
+ gchar *end;
+ gchar *s;
+ end = pop->line->str + pop->line->len;
+ s = pop->line->str;
+ while (s < end && *s == ' ') s++;
+ if (end - s < 5)
+ return -1;
+ if (g_ascii_strncasecmp (s, "USER ", 5) != 0)
+ return -1;
+ s += 5;
+ while (s < end && *s == ' ') s++;
+ if (s == end)
+ return -1;
+ end--;
+ while (end >= s && (*end == '\n' || *end == '\r')) end--;
+ if (end < s)
+ return -1;
+ if (pop->user)
+ g_free (pop->user);
+ pop->user = g_strndup (s, end - s + 2);
+ pop->user[end - s + 1] = 0;
+ return 0;
+}
+
+static int
+pop_getline (pop_t *pop)
+{
+ char * end;
+ size_t len;
+ if (pop->buffer->len == 0)
+ return -1;
+ end = memchr (pop->buffer->str, '\n', pop->buffer->len);
+ if (end == NULL)
+ return -1;
+ len = end - pop->buffer->str + 1;
+ g_string_truncate (pop->line, 0);
+ g_string_append_len (pop->line, pop->buffer->str, len);
+ g_string_erase (pop->buffer, 0, len);
+ return 0;
+}
+
static void
-pop_read (net_hook_t *hook, gchar *buffer, size_t len)
+pop_watch (HCConn *conn, HCEvent event, gpointer data)
{
- pop_t *pop = hook->data;
- hook->data = pop->orig_data;
- pop->orig_read (hook, buffer, len);
- hook->data = pop;
+ char buffer[4096];
+ int r;
+ HCConn *pop_conn = data;
+ pop_t *pop = pop_conn->layer;
+ switch (event)
+ {
+ case HC_EVENT_READ:
+ while ((r = hc_conn_read (conn, buffer, sizeof (buffer))) > 0)
+ {
+ g_string_append_len (pop->buffer, buffer, r);
+ while (pop_getline (pop) == 0)
+ {
+ if (pop_check_user (pop) == 0)
+ {
+ g_message ("User is trying to authenticate as %s.",
+ pop->user);
+ if (usermap_perm (pop->user) == ACCESS_DENY)
+ {
+ g_message ("Denying access to user %s.", pop->user);
+ if (pop_conn->func)
+ pop_conn->func (pop_conn, HC_EVENT_CLOSE,
+ pop_conn->data);
+ return;
+ }
+ }
+ g_string_append_len (pop->push, pop->line->str, pop->line->len);
+ if (pop_conn->func)
+ pop_conn->func (pop_conn, HC_EVENT_READ, pop_conn->data);
+ }
+ }
+ break;
+ default:
+ if (pop_conn->func)
+ pop_conn->func (pop_conn, event, pop_conn->data);
+ break;
+ }
}
-net_hook_t *
-pop_hook_new (net_hook_t *layer)
+static ssize_t
+pop_read (gpointer data, gchar *buffer, size_t len)
{
- pop_t *pop;
- pop = g_slice_new (pop_t);
- pop->orig_read = layer->read;
- pop->orig_data = layer->data;
- layer->read = pop_read;
- layer->data = pop;
- return layer;
+ pop_t *pop = data;
+ int r;
+ if (len > pop->push->len)
+ {
+ r = pop->push->len;
+ memcpy (buffer, pop->push->str, r);
+ g_string_truncate (pop->push, 0);
+ }
+ else
+ {
+ r = len;
+ memcpy (buffer, pop->push->str, r);
+ g_string_erase (pop->push, 0, r);
+ }
+ return r;
}
-void
-pop_destroy (net_hook_t *hook)
+static ssize_t
+pop_write (gpointer data, gchar *buffer, size_t len)
+{
+ pop_t *pop = data;
+ hc_conn_write (pop->lowconn, buffer, len);
+ return len;
+}
+
+static void
+pop_close (gpointer data)
{
- g_slice_free (net_hook_t, hook->data);
+ pop_t *pop = data;
+ hc_conn_close (pop->lowconn);
+ pop_destroy (pop);
+}
+
+int
+hc_conn_set_driver_pop (HCConn *conn, HCConn *lowconn)
+{
+ pop_t *pop;
+ pop = g_slice_new (pop_t);
+ pop->buffer = g_string_sized_new (4096);
+ pop->line = g_string_sized_new (4096);
+ pop->push = g_string_sized_new (4096);
+ pop->user = NULL;
+ pop->lowconn = lowconn;
+ conn->read = pop_read;
+ conn->write = pop_write;
+ conn->close = pop_close;
+ conn->layer = pop;
+ hc_conn_set_callback (lowconn, pop_watch, conn);
+ return 0;
}