Added library to do a TCP connection.
[cascardo/rnetproxy.git] / pop.c
1 /*
2 ** Copyright (C) 2006 Thadeu Lima de Souza Cascardo <cascardo@minaslivre.org>
3 ** Copyright (C) 2009 Thadeu Lima de Souza Cascardo <cascardo@holoscopio.com>
4 **  
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **  
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 ** GNU General Public License for more details.
14 **  
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 **  
19 */
20
21 #include <gnet.h>
22 #include <glib.h>
23 #include <string.h>
24 #include "nethook.h"
25 #include "pop.h"
26 #include "usermap.h"
27
28 typedef struct
29 {
30   net_read orig_read;
31   gpointer orig_data;
32   GString *buffer;
33   GString *line;
34   gchar *user;
35 } pop_t;
36
37 static int
38 pop_check_user (pop_t *pop)
39 {
40   gchar *end;
41   gchar *s;
42   end = pop->line->str + pop->line->len;
43   s = pop->line->str;
44   while (s < end && *s == ' ') s++;
45   if (end - s < 5)
46     return -1;
47   if (g_ascii_strncasecmp (s, "USER ", 5) != 0)
48     return -1;
49   s += 5;
50   while (s < end && *s == ' ') s++;
51   if (s == end)
52     return -1;
53   end--;
54   while (end >= s && (*end == '\n' || *end == '\r')) end--;
55   if (end < s)
56     return -1;
57   if (pop->user)
58     g_free (pop->user);
59   pop->user = g_strndup (s, end - s + 2);
60   pop->user[end - s + 1] = 0;
61   return 0;
62 }
63
64 static int
65 pop_getline (pop_t *pop)
66 {
67   char * end;
68   size_t len;
69   if (pop->buffer->len == 0)
70     return -1;
71   end = memchr (pop->buffer->str, '\n', pop->buffer->len);
72   if (end == NULL)
73     return -1;
74   len = end - pop->buffer->str + 1;
75   g_string_truncate (pop->line, 0);
76   g_string_append_len (pop->line, pop->buffer->str, len);
77   g_string_erase (pop->buffer, 0, len);
78   return 0;
79 }
80
81 static void
82 pop_read (net_hook_t *hook, gchar *buffer, size_t len)
83 {
84   pop_t *pop = hook->data;
85   g_string_append_len (pop->buffer, buffer, len);
86   while (pop_getline (pop) == 0)
87     {
88       if (pop_check_user (pop) == 0)
89         {
90           g_message ("User is trying to authenticate as %s.", pop->user);
91           if (usermap_perm (pop->user) == ACCESS_DENY)
92             {
93               g_message ("Denying access to user %s.", pop->user);
94               pop_destroy (hook);
95               gnet_conn_disconnect (hook->conn);
96               hook->close (hook);
97               return;
98             }
99         }
100       hook->data = pop->orig_data;
101       pop->orig_read (hook, pop->line->str, pop->line->len);
102       hook->data = pop;
103     }
104 }
105
106 net_hook_t *
107 pop_hook_new (net_hook_t *layer)
108 {
109   pop_t *pop;
110   pop = g_slice_new (pop_t);
111   pop->orig_read = layer->read;
112   pop->orig_data = layer->data;
113   pop->buffer = g_string_sized_new (4096);
114   pop->line = g_string_sized_new (4096);
115   pop->user = NULL;
116   layer->read = pop_read;
117   layer->data = pop;
118   return layer;
119 }
120
121 void
122 pop_destroy (net_hook_t *hook)
123 {
124   pop_t *pop = hook->data;
125   g_string_free (pop->buffer, TRUE);
126   g_string_free (pop->line, TRUE);
127   if (pop->user)
128     g_free (pop->user);
129   hook->read = pop->orig_read;
130   hook->data = pop->orig_data;
131   g_slice_free (net_hook_t, (gpointer) pop);
132 }