"Fossies" - the Fresh Open Source Software Archive 
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "sendmail.cc" see the
Fossies "Dox" file reference documentation.
1 /*
2 * xstress - xk0derz SMTP Stress Tester
3 *
4 * (c) Amit Singh amit@xkoder.com
5 * http://xkoder.com
6 *
7 * This software and related files are licensed under GNU GPL version 2
8 * Please visit the following webpage for more details
9 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
10 */
11 #include "common.h"
12 #include "logger.h"
13 #include "sendmail.h"
14 #include <fstream>
15 #include <cstdlib>
16 #include <cstring>
17
18 using namespace std;
19
20 const char *MIMETypeStr[]=
21 {
22 " ",
23 "plain",
24 "html"
25 "bin",
26 "image",
27 " "
28 };
29
30 /*SendMail Methods*/
31 SendMail::SendMail()
32 {
33 uiLastState = IDLE;
34 uiStateCounter = 0;
35 iState = IDLE;
36 iAuthState = 0;
37 bAuthDone = false;
38 iSock = -1;
39 sFrom = sTo = "";
40 sSubject = "Test Mail!";
41 sAttachment = "";
42 iConnected = false;
43 sPassword = "";
44 sUsername = "";
45 bAuthenticated = false;
46 }
47
48 SendMail::SendMail
49 (string _sTo, string _sFrom, string _sSubject, string _sBody, string _sAttachment)
50 {
51 uiLastState = IDLE;
52 uiStateCounter = 0;
53 iConnected = false;
54 iState = IDLE;
55 iAuthState = 0;
56 bAuthDone = false;
57 iSock = -1;
58 setTo(_sTo);
59 setFrom(_sFrom);
60 setSubject(_sSubject);
61 setBody(_sBody);
62 setAttachment(_sAttachment);
63 }
64
65 void SendMail::reset()
66 {
67 string sBuf = "\r\n.";
68 sBuf.append("\r\n");
69 char cBuf[4092];
70 cBuf[0]=0x00;
71
72 if(iConnected && iState == MAIL)
73 {
74 send(iSock, sBuf.c_str(), sBuf.length(), 0);
75 }
76
77 uiLastState = IDLE;
78 uiStateCounter = 0;
79 iState = IDLE;
80 }
81
82 void SendMail::disconnect()
83 {
84 iConnected = false;
85 }
86
87 void SendMail::setMailInfo
88 (string _sTo, string _sFrom, string _sSubject, string _sBody, string _sAttachment)
89 {
90 setTo(_sTo);
91 setFrom(_sFrom);
92 setSubject(_sSubject);
93 setBody(_sBody);
94 setAttachment(_sAttachment);
95 }
96
97 int SendMail::changeState(int sockState)
98 {
99 int rv = NO_ERR;
100 if(iState == FINISHED) return 0;
101
102 //cout << "last State = " << uiLastState << " Curr State " << iState << endl;
103
104 if(sockState==READ_READY)
105 {
106 //cout << "READ_READY" << endl;
107 char cBuf[4092];
108 cBuf[0]=0x00;
109 rv = recv(iSock, cBuf, 4000, 0);
110 cBuf[rv] = 0x00;
111 sRecvBuf = "";
112 sRecvBuf = cBuf;
113 if(sRecvBuf[0] == '4' || sRecvBuf[0] == '5' )
114 {
115 logger.log(sRecvBuf);
116 return ERR_IO;
117 }
118 //cout << "RECEIVED:" << sRecvBuf << endl;
119 debug("S: " + sRecvBuf);
120 }
121 else if(sockState==WRITE_READY)
122 {
123 //cout << "WRITE_READY" << endl;
124 uiLastState = iState;
125 switch(iState)
126 {
127 case IDLE:
128 iState = CONNECT;
129 //cout << "IDLE-->CONNECT" << endl;
130 break;
131 case CONNECT:
132 //cout << "CONNECT-->EHLO" << endl;
133 iState = EHLO;
134 break;
135 case EHLO:
136 //cout << "EHLO->MAILFROM" << endl;
137 //cout << "sAuthType = " << sAuthType << endl;
138 if(sAuthType == "NONE")
139 {
140 bAuthenticated = true;
141 //cout << "seeting bAuthenticated to true" << endl;
142 }
143
144 if(bAuthenticated)
145 {
146 iState = MAILFROM;
147 }
148 else
149 {
150 iState = AUTH;
151 iAuthState = 0;
152 }
153 break;
154 case AUTH:
155 if(bAuthDone)
156 {
157 bAuthenticated = true;
158 iState = MAILFROM;
159 }
160 else
161 {
162 iAuthState++;
163 }
164 break;
165 case MAILFROM:
166 //cout << "MAILFROM-->RCPTTO" << endl;
167 iState = RCPTTO;
168 break;
169 case RCPTTO:
170 //cout << "RCPTTO-->DATA" << endl;
171 iState = DATA;
172 break;
173 case DATA:
174 //cout << "DATA-->MAIL" << endl;
175 iState = MAIL;
176 break;
177 case MAIL:
178 //cout << "MAIL:" << sSendBuf << endl;
179 if(sSendBuf.empty())
180 {
181 iSentBytes = 0;
182 iState = FINISHED;
183 }
184 else if(iSentBytes>=sSendBuf.length())
185 {
186 //cout << "MAIL-->FINISHED" << endl;
187 iState = FINISHED;
188 }
189 else if(iSentBytes<sSendBuf.length())
190 {
191 //cout << "MAIL-->MAIL" << endl;
192 string sBuf;
193 sBuf = sSendBuf.substr(iSentBytes, sSendBuf.length());
194 sSendBuf = sBuf;
195 iSentBytes = 0;
196 }
197 else
198 {
199 sSendBuf = "";
200 }
201 break;
202 }
203 /*
204 if(iState==uiLastState) uiStateCounter++;
205 if(uiStateCounter>10) return ERR_IO;
206 */
207 }
208 return NO_ERR;
209 }
210
211 int SendMail::run(int sockState)
212 {
213 if(iSock==-1) return ERR_INVALID_SOCKET;
214
215 //cout << "[run(" << iState << ")]" << endl;
216
217 switch(iState)
218 {
219 case CONNECT:
220 {
221 if(iConnected)
222 {
223 //string sBuf = "NOOP";
224 //sBuf.append("\r\n");
225 //send(iSock, sBuf.c_str(), sBuf.length(), 0);
226 break;
227 }
228 sockaddr_in addr;
229 addr.sin_family = AF_INET;
230 addr.sin_port = htons(uiServerPort);
231 inet_aton(sServerIP.c_str(), &addr.sin_addr);
232 debug("Trying to connect to " + sServerIP);
233 //cout << "Server : " << sServerIP << ":" << uiServerPort << endl;
234 if(iSock!=-1)
235 {
236
237 if(connect(iSock, (const sockaddr*) &addr, sizeof(sockaddr))==-1 &&
238 ( (errno == EINPROGRESS)|| (errno == EALREADY)))
239 {
240 iConnected = true;
241 debug("Connected to the server!");
242 }
243 else
244 {
245 return ERR_CONNECT;
246 //cout << "ERR" << endl;
247 debug("Error connecting!");
248 }
249 /*
250 if (connect(iSock, (const sockaddr*) &addr, sizeof(sockaddr)) == -1)
251 return ERR_CONNECT;
252 */
253
254 iConnected = true;
255
256 }
257 }
258 break;
259 case EHLO:
260 {
261 string sBuf = "EHLO localhost";
262 sBuf.append("\r\n");
263 debug("C: EHLO localhost");
264 send(iSock, sBuf.c_str(), sBuf.length(), 0);
265 }
266 break;
267 case AUTH:
268 {
269 if(sAuthType != "NONE")
270 {
271 bAuthDone = false;
272 if(sAuthType == "PLAIN")
273 {
274 string sAuth64;
275 char cBuf[255];
276 string sBuf = "AUTH";
277 //switch(uiAuthType)
278 sBuf.append(" PLAIN ");
279
280 string sFilenameTMP;
281 string sFilename;
282 sprintf(cBuf, ".auth.b64.%i.tmp", logger.getThreadId());
283 sFilenameTMP = cBuf;
284 sprintf(cBuf, ".auth.b64.%i", logger.getThreadId());
285 sFilename = cBuf;
286
287 cBuf[0] = 0x00;
288 ofstream ofilp;
289 ofilp.open(sFilenameTMP.c_str(), ofstream::out | ofstream::binary);
290 if(!ofilp.fail())
291 {
292 ofilp.write(sUsername.c_str(), sUsername.length());
293 ofilp.write(cBuf, 1);
294 ofilp.write(sUsername.c_str(), sUsername.length());
295 ofilp.write(cBuf, 1);
296 ofilp.write(sPassword.c_str(), sPassword.length());
297 ofilp.close();
298 }
299
300 sprintf(cBuf, "./base64 -e %s > %s", sFilenameTMP.c_str(), sFilename.c_str());
301 system(cBuf);
302
303 ifstream filp;
304 filp.open(sFilename.c_str(), ifstream::in);
305
306 char cBuffer[1024];
307 if(!filp.fail())
308 {
309 if(!filp.eof())
310 {
311 filp.getline(cBuffer, 1000);
312 cBuffer[1023]=0x00;
313 sAuth64 = cBuffer;
314 }
315
316 sBuf.append(sAuth64);
317 sBuf.append("\r\n");
318
319 debug("C: " + sBuf);
320
321 send(iSock, sBuf.c_str(), sBuf.length(), 0);
322
323 }
324
325 system("rm -f .auth.*");
326 bAuthDone = true;
327 }
328 else if(sAuthType == "LOGIN")
329 {
330 string sBuf;
331 char cBuf[1024];
332 string sFilename;
333 string sFilenameTMP;
334
335 sprintf(cBuf, ".auth.b64.%i", logger.getThreadId());
336 sFilename = cBuf;
337
338 sprintf(cBuf, ".auth.b64.%i.tmp", logger.getThreadId());
339 sFilenameTMP = cBuf;
340
341 ifstream filp;
342 ofstream ofilp;
343
344 switch(iAuthState)
345 {
346 case 0: // AUTH LOGIN
347 sBuf = "AUTH LOGIN\r\n";
348 break;
349 case 1: // Username
350 ofilp.open(sFilenameTMP.c_str(), ofstream::out | ofstream::binary);
351
352 if(!ofilp.fail())
353 {
354 ofilp.write(sUsername.c_str(), sUsername.length());
355 }
356 ofilp.close();
357
358 sprintf(cBuf,"./base64 -e %s > %s", sFilenameTMP.c_str(), sFilename.c_str());
359 system(cBuf);
360
361 filp.open(sFilename.c_str(), ifstream::in);
362 if(!filp.fail())
363 {
364 filp.getline(cBuf, 1000);
365 cBuf[1023] = 0x00;
366 sBuf = cBuf;
367 sBuf.append("\r\n");
368 }
369 filp.close();
370
371 //system("rm -f .auth.*");
372 break;
373 case 2: // Password
374 ofilp.open(sFilenameTMP.c_str(), ofstream::out | ofstream::binary);
375
376 if(!ofilp.fail())
377 {
378 ofilp.write(sPassword.c_str(), sPassword.length());
379 }
380 ofilp.close();
381
382 sprintf(cBuf,"./base64 -e %s > %s", sFilenameTMP.c_str(), sFilename.c_str());
383 system(cBuf);
384
385 filp.open(sFilename.c_str(), ifstream::in);
386 if(!filp.fail())
387 {
388 filp.getline(cBuf, 1000);
389 cBuf[1023] = 0x00;
390 sBuf = cBuf;
391 sBuf.append("\r\n");
392 }
393 filp.close();
394 //system("rm -f .auth.*");
395 bAuthDone = true;
396 break;
397 }
398 debug("C: " + sBuf);
399 send(iSock, sBuf.c_str(), sBuf.length(), 0);
400 }
401 }
402 else
403 {
404 bAuthDone = true;
405 }
406 }
407 break;
408 case MAILFROM:
409 {
410 string sBuf = "MAIL FROM:";
411 sBuf.append(sFrom);
412 debug("C: " + sBuf);
413 sBuf.append("\r\n");
414 send(iSock, sBuf.c_str(), sBuf.length(), 0);
415 }
416 break;
417 case RCPTTO:
418 {
419 string sBuf = "RCPT TO:";
420 sBuf.append(sTo);
421 debug("C: " + sBuf);
422 sBuf.append("\r\n");
423 send(iSock,sBuf.c_str(), sBuf.length(), 0);
424 }
425 break;
426 case DATA:
427 {
428 debug("C: DATA");
429 string sBuf = "DATA";
430 string sLine;
431 char cBuffer[1024];
432 sBuf.append("\r\n");
433 send(iSock,sBuf.c_str(), sBuf.length(), 0);
434 ifstream filp;
435 int iMType = MT_BIN, ii;
436
437 sSendBuf = "MIME-Version: 1.0\r\n";
438 {
439 /*Create Send Buffer*/
440 char cBuffer[255];
441 struct tm *currTime;
442 time_t currTS;
443 unsigned int tzHr, tzMin;
444 char tzSign;
445 const char *pcWDay[] = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
446 const char *pcMonth[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
447 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
448
449 time(&currTS);
450 currTime = localtime(&currTS);
451
452 tzHr = (((currTime->tm_gmtoff)/60)/60);
453 tzMin = ((currTime->tm_gmtoff)/60)-(tzHr*60);
454
455 tzSign = '+';
456 if(tzHr>12)
457 {
458 tzHr = 12-tzHr;
459 tzSign = '-';
460 }
461
462
463 sprintf(cBuffer, "%s, %i %s %i %02i:%02i:%02i %c%02i%02i",
464 pcWDay[currTime->tm_wday],
465 currTime->tm_mday,
466 pcMonth[currTime->tm_mon],
467 1900+currTime->tm_year,
468 currTime->tm_hour, currTime->tm_min, currTime->tm_sec,
469 tzSign, tzHr, tzMin);
470
471 sSendBuf.append("Date: ");
472 sSendBuf.append(cBuffer);
473 sSendBuf.append("\r\n");
474 }
475
476 sSendBuf.append("To:");
477 sSendBuf.append(sTo);
478 sSendBuf.append("\r\n");
479
480 sSendBuf.append("From:");
481 sSendBuf.append(sFrom);
482 sSendBuf.append("\r\n");
483
484 sSendBuf.append("Subject:");
485 sSendBuf.append(sSubject);
486 sSendBuf.append("\r\n");
487
488 sSendBuf.append("Content-Type: multipart/mixed;");
489 sSendBuf.append(" boundary=");
490 sSendBuf.append(BOUNDARY);
491 sSendBuf.append("\r\n\r\n");
492
493 sSendBuf.append("This is a multi-part message in MIME format.\r\n");
494 sSendBuf.append("\r\n--");
495 sSendBuf.append(BOUNDARY);
496 sSendBuf.append("\r\n");
497
498
499 sSendBuf.append("Content-Type: text/plain; charset=ISO-8859-1; format=flowed\r\n");
500 sSendBuf.append("Content-Transfer-Encoding: 7bit\r\n");
501
502 sSendBuf.append("\r\n");
503
504 filp.clear();
505 /*Fetch Body here*/
506 filp.open(sBody.c_str(), ifstream::in);
507 if(!filp.fail())
508 {
509 while(!filp.eof())
510 {
511 filp.getline(cBuffer, 1000);
512 cBuffer[1023]=0x00;
513 sLine = cBuffer;
514 sLine.append("\r\n");
515
516 sSendBuf.append(sLine);
517 }
518 filp.close();
519 }
520 else
521 {
522 sSendBuf.append("\r\nUnable to open body file'");
523 sSendBuf.append(sBody);
524 sSendBuf.append("'\r\n");
525 }
526 sSendBuf.append("\r\n");
527
528
529
530 if(!sAttachment.empty()) // If we have an attachment
531 {
532 // Attachment goes here!!
533 for(ii=1;ii<MT_MAX;ii++)
534 {
535 if(sAttachType==MIMETypeStr[ii])
536 {
537 iMType = ii;
538 break;
539 }
540 }
541
542 if(sAttachment.find("/")!=string::npos)
543 {
544 sLine = sAttachment.substr(sAttachment.rfind("/"),sAttachment.length());
545 }
546 else
547 {
548 sLine = sAttachment;
549 }
550
551 sSendBuf.append("\r\n--");
552 sSendBuf.append(BOUNDARY);
553 sSendBuf.append("\r\n");
554
555 switch(iMType)
556 {
557 case MT_BIN:
558 sSendBuf.append("Content-Type: application/octet-stream; name=");
559 sSendBuf.append("\"");
560 sSendBuf.append(sLine);
561 sSendBuf.append("\"\r\n");
562
563 sSendBuf.append("Content-Transfer-Encoding: base64\r\n");
564 sSendBuf.append("Content-Disposition: attachment; filename=\"");
565 sSendBuf.append(sLine);
566 sSendBuf.append("\"\r\n\r\n");
567
568 {
569 char cBuf[255];
570 sprintf(cBuf,"./base64 -e %s > .xstress.b64.%i.tmp",sAttachment.c_str(),
571 logger.getThreadId());
572 system(cBuf);
573
574 sprintf(cBuf,".xstress.b64.%i.tmp", logger.getThreadId());
575 sAttachment = cBuf;
576 }
577
578 break;
579 case MT_PLAIN:
580 sSendBuf.append("Content-Type: text/plain; charset=UTF-8; name=");
581 sSendBuf.append("\"");
582 sSendBuf.append(sLine);
583 sSendBuf.append("\"\r\n");
584 sSendBuf.append("Content-Transfer-Encoding: 7bit\r\n");
585 sSendBuf.append("Content-Disposition: attachment; filename=\"");
586 sSendBuf.append(sLine);
587 sSendBuf.append("\"\r\n\r\n");
588 break;
589 case MT_HTML:
590 sSendBuf.append("Content-Type: text/html; charset=UTF-8; name=");
591 sSendBuf.append("\"");
592 sSendBuf.append(sLine);
593 sSendBuf.append("\"\r\n");
594 sSendBuf.append("Content-Transfer-Encoding: 7bit\r\n");
595 sSendBuf.append("Content-Disposition: attachment; filename=\"");
596 sSendBuf.append(sLine);
597 sSendBuf.append("\"\r\n\r\n");
598 break;
599 case MT_IMAGE:
600 sSendBuf.append("Content-Type: application/octet-stream; name=");
601 sSendBuf.append("\"");
602 sSendBuf.append(sLine);
603 sSendBuf.append("\"\r\n");
604 sSendBuf.append("Content-Transfer-Encoding: base64\r\n");
605 sSendBuf.append("Content-Disposition: inline; filename=\"");
606 sSendBuf.append(sLine);
607 sSendBuf.append("\"\r\n\r\n");
608 {
609 char cBuf[255];
610 sprintf(cBuf,"./base64 -e %s > .xstress.b64.%i.tmp",sAttachment.c_str(),
611 logger.getThreadId());
612 system(cBuf);
613
614 sprintf(cBuf,".xstress.b64.%i.tmp", logger.getThreadId());
615 sAttachment = cBuf;
616 }
617 break;
618 }
619
620 filp.clear();
621 if(filp.is_open()) filp.close();
622 filp.open(sAttachment.c_str(), ios::in | ios::binary);
623 if(!filp.fail())
624 {
625 unsigned long int ulTS = time(NULL);
626 while(!filp.eof())
627 {
628 memset(cBuffer,0,80);
629 filp.read(cBuffer, 77);
630
631 cBuffer[77]=0x00;
632 sSendBuf.append(cBuffer);
633
634 if(time(NULL)-ulTS>10)
635 {
636 logger.log("Timeout while reading attachment file!");
637 sSendBuf.append("Timeout while reading attachment file"); break; }
638 }
639
640 filp.close();
641 }
642 else
643 {
644 sSendBuf.append("\r\nUnable to open attachment file '");
645 sSendBuf.append(sAttachment);
646 sSendBuf.append("'\r\n");
647 }
648 sSendBuf.append("\r\n");
649
650 {
651 char cBuf[255];
652 sprintf(cBuf,"rm -f .xstress.b64.%i.tmp",logger.getThreadId());
653 system(cBuf);
654 }
655
656
657 }
658
659 sSendBuf.append("\r\n--");
660 sSendBuf.append(BOUNDARY);
661 sSendBuf.append("--\r\n");
662 sSendBuf.append(".\r\n");
663 iSentBytes = 0;
664 }
665 break;
666 case MAIL:
667 debug("Data sending in progress...");
668 if(sSendBuf.length()>0)
669 {
670 iSentBytes = send(iSock, sSendBuf.c_str(), sSendBuf.length(), 0);
671 debug("C: " + sSendBuf.substr(0, iSentBytes));
672 }
673 else iSentBytes = 1;
674 break;
675 case FINISHED:
676 //cout << "This session has exhausted!" << endl;
677 break;
678 }
679
680 return NO_ERR;
681 }
682
683 void SendMail::setTo(string _sTo)
684 {
685 sTo = _sTo;
686 }
687
688 void SendMail::setFrom(string _sFrom)
689 {
690 sFrom = _sFrom;
691 }
692
693 void SendMail::setSubject(string _sSubject)
694 {
695 sSubject = _sSubject;
696 }
697
698 void SendMail::setBody(string _sBody)
699 {
700 sBody = _sBody;
701 }
702
703 void SendMail::setAttachment(string _sAttachment)
704 {
705 if(_sAttachment.find("!")!=string::npos)
706 {
707 sAttachment = _sAttachment.substr(0,_sAttachment.find("!"));
708 sAttachType = _sAttachment.substr(_sAttachment.find("!")+1,_sAttachment.length());
709 }
710 else
711 {
712 sAttachment = _sAttachment;
713 sAttachType = "bin";
714 }
715 }
716
717 int SendMail::state(void)
718 {
719 return iState;
720 }
721
722 int SendMail::setServer(string _ip, unsigned int _port)
723 {
724 sServerIP = _ip;
725 uiServerPort = _port;
726 return NO_ERR;
727 }
728
729 void SendMail::setAuthInfo(string _username, string _password, string _authType)
730 {
731 sUsername = _username;
732 sPassword = _password;
733 sAuthType = _authType;
734
735 //cout << "setAuthInfo : Username '" << sUsername << "'" << endl;
736 //cout << "setAuthInfo : Password '" << sPassword << "'" << endl;
737 //cout << "setAuthInfo : AuthType '" << sAuthType << "'" << endl;
738
739 if(sUsername.empty() || sPassword.empty())
740 {
741 sAuthType = "NONE";
742 bAuthenticated = true;
743 }
744 else if(!sUsername.empty() && !sPassword.empty())
745 {
746 // We defaul to AUTH PLAIN if none is provided.
747 if(sAuthType.empty())
748 {
749 sAuthType = "PLAIN";
750 }
751 }
752 }
753
754 void SendMail::resetAuth()
755 {
756 bAuthenticated = false;
757 }