4 Copyright (C) 2007 Carlos Daniel Ruvalcaba Valenzuela <clsdaniel@gmail.com>
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License along
17 with this program; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 const char * demomsg
= "From: Test John <testjohn@localhost>\n"
25 "To: test@localhost\n"
26 "Content-Type: text/plain\n"
27 "Date: Wed, 06 Jun 2007 15:21:21 -0700\n"
28 "Message-Id: <1181168481.15047.2.camel@localhost>\n"
30 "X-Mailer: Evolution 2.10.1 \n"
31 "Content-Transfer-Encoding: 7bit\n"
35 const int POP3_PORT
= 12001; //25;
36 const char CRLF
[2] = {0x0D, 0x0A};
37 const char *welcome
= "+OK FancyMail v0.1";
40 const int CMD_USER
= 1;
41 const int CMD_PASS
= 2;
42 const int CMD_STAT
= 3;
43 const int CMD_LIST
= 4;
44 const int CMD_RETR
= 5;
45 const int CMD_DELE
= 6;
46 const int CMD_NOOP
= 7;
47 const int CMD_QUIT
= 8;
48 const int CMD_RSET
= 9;
49 const int CMD_TOP
= 10;
50 const int CMD_CAPA
= 10;
52 const char KEY_END_DATA
[6] = {0x0D, 0x0A, '.', 0x0D, 0x0A, 0x00};
55 enum {STATE_AUTH
= 1, STATE_AUTH2
= 2, STATE_TRANSACTION
= 3,
59 if ((v
>= 'A') && (v
<= 'Z'))
65 if ((v
>= 'a') && (v
<= 'z'))
77 class POP3Handler
: public Job
{
78 SearchTree
<int, 27, &knhash
> cmdtree
;
81 POP3Handler(Socket
*sock
) : Job() {
82 /* Insert POP3 commands to search tree, 4 letters only for optimization */
83 cmdtree
.Insert("USER", 1);
84 cmdtree
.Insert("PASS", 2);
85 cmdtree
.Insert("STAT", 3);
86 cmdtree
.Insert("LIST", 4);
87 cmdtree
.Insert("RETR", 5);
88 cmdtree
.Insert("DELE", 6);
89 cmdtree
.Insert("NOOP", 7);
90 cmdtree
.Insert("QUIT", 8);
91 cmdtree
.Insert("RSET", 9);
92 cmdtree
.Insert("TOP", 10);
93 cmdtree
.Insert("CAPA", 11);
94 printf("SearchTree Memory Usage: %i bytes\n", cmdtree
.getTreeSize());
102 //char userbuff[255];
105 int onrun
, cmd
, state
;
106 //IPC * ipc, * ipcmb;
109 pcrecpp::RE
reg("[\\w\\a]*\\s([\\w\\a]*)");
111 //ipc = IPC::CreateIPC("socket://127.0.0.1:14000");
112 //ipcmb = IPC::CreateIPC("socket://127.0.0.1:14001");
114 /* Send greeting to client */
115 s
->Write(welcome
, strlen(welcome
));
123 /* Wait for client input */
124 memset(buffer
, 0, 255);
125 r
= s
->Read(buffer
, 255);
127 /* Lookup the command in out command search tree */
129 cmd
= cmdtree
.Lookup(buffer
);
130 } catch (SearchNotFound
){
134 if (cmd
== CMD_QUIT
){
135 printf("Got QUIT\n");
140 /* Change state to UPDATE, will quit after that */
141 state
= STATE_UPDATE
;
146 if (cmd
== CMD_USER
){
147 /* Parse username from command */
148 reg
.PartialMatch(buffer
, &user
);
149 printf("Got USERNAME: %s\n", user
.c_str());
154 /* Change our state to expect password */
157 printf("INVALID [AUTH]: %s\n", buffer
);
158 s
->Write( "-ERR", 4);
163 if (cmd
== CMD_PASS
){
164 /* Extract password from command */
165 reg
.PartialMatch(buffer
, &pass
);
167 printf("Got Password: %s\n", pass
.c_str());
173 /* If we got a positive response move to next state */
174 state
= STATE_TRANSACTION
;
176 s
->Write( "-ERR", 4);
179 /* Authentication failed, change to initial state */
184 printf("INVALID [AUTH2]: %s\n", buffer
);
185 s
->Write( "-ERR", 4);
190 case STATE_TRANSACTION
:
193 /* Return server status (OK) */
194 printf("Got STAT Command\n");
195 s
->Write( "+OK 3 400", 9);
199 /* TODO: Consult the mailbox server and send the real list */
200 printf("Got LIST Command: %s\n", buffer
);
204 s
->Write( "1 150", 5);
207 s
->Write( "2 150", 5);
210 s
->Write( "3 100", 5);
216 /* TODO: Retrieve the real message from mailbox */
217 printf("Got RETR Command: %s\n", buffer
);
218 s
->Write( "+OK 150 octets", 14);
221 s
->Write( demomsg
, strlen(demomsg
));
228 /* TODO: Delete the real message from mailbox */
229 printf("Got DELE Command: %s\n", buffer
);
234 printf("Got NOOP Command\n");
239 printf("Got RSET Command\n");
243 /* TODO: Return the real top messages from mailbox */
244 printf("Got TOP Command: %s\n", buffer
);
245 for (i
= strlen(buffer
); i
> 0; i
--){
246 if (buffer
[i
] == ' ')
250 i
= atoi((char *)(buffer
+ i
));
258 for (r
= 0; r
< i
; r
++){
259 sscanf((char *)(demomsg
+j
), "%s", buffer
);
260 j
= j
+ strlen(buffer
);
261 s
->Write( buffer
, strlen(buffer
));
268 printf("INVALID [TRANS]: %s\n", buffer
);
269 s
->Write( "-ERR", 4);
284 class SimpleLoad
: public LoadHandler
{
286 int Dispatch(Socket
* sock
, ProtocolHandler
* ph
){
288 return ph
->Handle(sock
);
294 Socket
* s
, * client
;
298 /* Create our POP3 Handler and Threaded Load Handler */
299 //pop3 = new POP3Handler();
300 //tlh = new ThreadLoad(pop3);
303 /* Create and bind our socket to POP3 port */
304 s
= Socket::CreateSocket(SOCKET_INET
, 0);
305 s
->setPort(POP3_PORT
);
306 s
->setAddress("127.0.0.1");
311 /* Poll for incoming connections */
312 ret
= s
->Poll(1000000, SOCKET_POLL_READ
| SOCKET_POLL_ERROR
);
314 if (ret
& SOCKET_POLL_READ
){
315 /* Accept client and dispatch */
316 client
= s
->Accept();
317 boss
->Dispatch(new POP3Handler(client
));
318 } else if(ret
& SOCKET_POLL_ERROR
){ //error