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 int SMTP_PORT
= 12000; //25;
25 const char CRLF
[2] = {0x0D, 0x0A};
27 const int CMD_EHLO
= 1;
28 const int CMD_HELO
= 2;
29 const int CMD_MAIL
= 3;
30 const int CMD_RCPT
= 4;
31 const int CMD_DATA
= 5;
32 const int CMD_QUIT
= 6;
33 const int CMD_RSET
= 7;
34 const char KEY_END_DATA
[6] = {0x0D, 0x0A, '.', 0x0D, 0x0A, 0x00};
37 if ((v
>= 65) && (v
<= 90))
43 if ((v
>= 97) && (v
<= 122))
55 class SMTPHandler
: public ProtocolHandler
{
56 SearchTree
<int, 27, &knhash
> cmdtree
;
59 cmdtree
.Insert("EHLO", 1);
60 cmdtree
.Insert("HELO", 2);
61 cmdtree
.Insert("MAIL", 3);
62 cmdtree
.Insert("RCPT", 4);
63 cmdtree
.Insert("DATA", 5);
64 cmdtree
.Insert("QUIT", 6);
65 cmdtree
.Insert("RSET", 7);
67 int Handle(Socket
*s
){
68 char buffer
[255], *slotname
;
70 int onrun
, cmd
, state
;
72 pcrecpp::RE
reCmd("\\w*:<(.*)>");
76 string mailfrom
, rcpt
;
81 /* Write out the SMTP server Greeting */
82 s
->Write("220 FancyMail v0.1", 18);
86 /* Wait for client input */
87 memset(buffer
, 0, 255);
88 r
= s
->Read(buffer
, 255);
90 /* Find the given command on our search tree */
92 cmd
= cmdtree
.Lookup(buffer
);
93 }catch (SearchNotFound
){
99 /* We got normal SMTP HELO, write response */
100 s
->Write("250 ok localhost", 16);
103 /* Client presented itself, we can accept other
104 * commands, we pass to state 1 */
108 /* We still not support ESMTP, write not implemented */
109 s
->Write( "502 Not implemented", 19);
113 /* Check if we had the proper greeting */
115 s
->Write( "502 Not implemented", 19);
120 /* Extract the command mail from data */
121 ret
= reCmd
.PartialMatch(buffer
, &mailfrom
);
122 printf("[Debug] Sending Mail From: %s\n", mailfrom
.c_str());
125 s
->Write( "250 OK", 6);
128 /* We pass to next state */
132 /* Check that we have recieved the MAIL command first */
134 s
->Write( "502 Not implemented", 19);
139 /* Extract the recipent */
140 reCmd
.PartialMatch(buffer
, &rcpt
);
141 printf("[Debug] Recipent: %s\n", rcpt
.c_str());
143 s
->Write( "250 OK", 6);
149 /* Check that we have recived the RCPT command first */
151 s
->Write( "502 Not implemented", 19);
156 /* Give the client green light to send its data */
157 printf("Reciving Data!\n");
158 s
->Write( "354 OK", 6);
161 /* Connect to the Queue server */
162 ipc
= IPC::CreateIPC("socket://127.0.0.1:14002");
166 msg
= new IPCMessage("slot");
167 msg
->PushParam("incoming");
168 ipc
->PushMessage(msg
);
170 /* Retrieve Response */
171 msg
= ipc
->PopMessage();
172 if (!strcmp(msg
->GetMessageName(), "ok"){
173 slotname
= msg
->PopParam();
178 /* Open Queue Slot File */
179 fd
= fopen(slotname
, "w");
181 /* Write our headers */
182 fprintf(fd
, "MAIL FROM: %s\n", mailfrom
.c_str());
183 fprintf(fd
, "RCPT: %s\n", rcp
.c_str());
188 /* Read incoming client data */
189 memset(buffer
, 0, 255);
190 l
= s
->Read( buffer
, 255);
192 /* Write to slot file */
193 fwrite(buffer
, 1, l
, fd
);
196 if (strstr(buffer
, KEY_END_DATA
)){
198 printf("\nEnd of Data\n");
200 printf("Buffer[%i]: %s\n", l
, buffer
);
204 /* Close our slot file */
207 /* Push the message to the Queue */
208 msg
= new IPCMessage("push");
209 msg
->PushParam("incoming");
210 msg
->PushParam(slotname
);
211 ipc
->PushMessage(msg
);
216 s
->Write( "250 OK", 6);
219 /* Go back to initial state */
223 s
->Write( "250 OK", 6);
230 printf("Got Quit, Exiting\n");
231 s
->Write( "221 Exiting", 11);
238 printf("Not implemented [State: %i]: %s\n", state
, buffer
);
239 s
->Write( "502 Not implemented", 19);
244 printf("[COMMAND]: %s\n", buffer
);
247 /* Close Connection */
248 printf("Closing Connection\n");
253 class SimpleLoad
: public LoadHandler
{
255 int Dispatch(Socket
*sock
, ProtocolHandler
*ph
){
257 return ph
->Handle(sock
);
262 int main(int argc
, char **argv
){
264 SMTPHandler
*handler
;
268 /* Create a Socket and bind it to SMTP port */
269 s
= Socket::CreateSocket(SOCKET_INET
, 0);
270 s
->setAddress("localhost");
271 s
->setPort(SMTP_PORT
);
275 /* Create a handler object */
276 handler
= new SMTPHandler();
278 /* Create a LoadHandler Object*/
279 tlh
= new ThreadLoad(handler
);
282 /* Poll for incoming connections */
283 ret
= s
->Poll(1000000, SOCKET_POLL_READ
);
284 if (ret
== SOCKET_POLL_READ
){
285 /* Accept client and dispatch */
287 tlh
->Dispatch(cl
, handler
);