SMailer.cpp
上传用户:zhanglf88
上传日期:2013-11-19
资源大小:6036k
文件大小:16k
源码类别:

金融证券系统

开发平台:

Visual C++

  1. ////////////////////////////////////////////////////////////////////////////////
  2. // Simple Mail Sender (Implementation)
  3. // Version 0.0
  4. //
  5. // Copyright (c) 2003 by Morning
  6. // http://morningspace.51.net
  7. // mailto:moyingzz@etang.com
  8. //
  9. // Permission to use, copy, modify, distribute and sell this program for any 
  10. // purpose is hereby granted without fee, provided that the above copyright 
  11. // notice appear in all copies and that both that copyright notice and this 
  12. // permission notice appear in supporting documentation.
  13. //
  14. // It is provided "as is" without express or implied warranty.
  15. ////////////////////////////////////////////////////////////////////////////////
  16. #include "StdAfx.h"
  17. #include "SMailer.h"
  18. #include <iostream>
  19. #include <time.h>
  20. #include <stdlib.h>
  21. #include "../MUtils/Base64Helper.h"
  22. #include "../MUtils/FileHelper.h"
  23. //
  24. namespace SMailer {
  25. // constants defination
  26. /////////////////////////////////////
  27. enum {MAX_BUFFER_SIZE = 255};
  28. const std::string Priority::important = "1";
  29. const std::string Priority::normal    = "3";
  30. const std::string Priority::trivial   = "5";
  31. const std::string MailWrapper::_mailer_name = "SMailer";
  32. const std::string MailWrapper::_boundary    = "#BOUNDARY#";
  33. // Member functions of class MimeContent
  34. /////////////////////////////////////
  35. MimeContent::MimeContent(const std::string content) : _content(content)
  36. {
  37. }
  38. std::string MimeContent::getDisposition() const
  39. {
  40.     return "";
  41. }
  42. // Member functions of class PlainTextContent
  43. /////////////////////////////////////
  44. TextPlainContent::TextPlainContent(const std::string content, 
  45.                                    const std::string charset)
  46.     : MimeContent(content), _charset(charset)
  47. {
  48. }
  49. std::string TextPlainContent::getType() const
  50. {
  51.     return "text/plain; charset=" + _charset;
  52. }
  53. std::string TextPlainContent::getTransEncoding() const
  54. {
  55.     return "8bit";
  56. }
  57. std::string& TextPlainContent::getContent()
  58. {
  59.     // you can add more codes here, such as wrapping lines 
  60.     // or replacing 'n' with 'rn', etc.
  61.     return _content;
  62. }
  63. // Member functions of class TextHtmlContent
  64. /////////////////////////////////////
  65. TextHtmlContent::TextHtmlContent(const std::string content, 
  66.                                  const std::string charset)
  67.     : MimeContent(content), _charset(charset)
  68. {
  69. }
  70. std::string TextHtmlContent::getType() const
  71. {
  72.     return "text/html; charset=" + _charset;
  73. }
  74. std::string TextHtmlContent::getTransEncoding() const
  75. {
  76.     return "8bit";
  77. }
  78. std::string& TextHtmlContent::getContent()
  79. {
  80.     // you can add more codes here, such as wrapping lines 
  81.     // or replacing 'n' with 'rn', etc.
  82.     return _content;
  83. }
  84. // Member functions of class AppOctStrmContent
  85. /////////////////////////////////////
  86. AppOctStrmContent::AppOctStrmContent(const std::string file_name)
  87.     : _file_name(file_name)
  88. {
  89.     char drive[_MAX_DRIVE];
  90.     char direc[_MAX_DIR];
  91.     char fname[_MAX_FNAME];
  92.     char ext[_MAX_EXT];
  93.     _splitpath(file_name.c_str(), drive, direc, fname, ext);
  94.     _name  = fname;
  95.     _name += ext;
  96. }
  97. std::string AppOctStrmContent::getType() const
  98. {
  99.     return "application/octet-stream; name=" + _name;
  100. }
  101. std::string AppOctStrmContent::getDisposition() const
  102. {
  103.     return "attachment; filename=" + _name;
  104. }
  105. std::string AppOctStrmContent::getTransEncoding() const
  106. {
  107.     return "base64";
  108. }
  109. std::string& AppOctStrmContent::getContent()
  110. {
  111.     // you can add more codes here, such as wrapping lines 
  112.     // or replacing 'n' with 'rn', etc.
  113.     MUtils::FileHelper::open(_file_name, _content);
  114.     _content = MUtils::Base64Helper::encode(_content);
  115.     return _content;
  116. }
  117. // Member functions of class MailInfo
  118. /////////////////////////////////////
  119. MailInfo::MailInfo() : _priority(Priority::normal)
  120. {
  121. }
  122. void MailInfo::setSenderName(const std::string name)
  123. {
  124.     _sender_name = name;
  125. }
  126. void MailInfo::setSenderAddress(const std::string address)
  127. {
  128.     _sender_address = address;
  129. }
  130. std::string MailInfo::getSenderName() const
  131. {
  132.     return _sender_name;
  133. }
  134. std::string MailInfo::getSenderAddress() const
  135. {
  136.     return _sender_address;
  137. }
  138. void MailInfo::addReceiver(const std::string name, const std::string address)
  139. {
  140.     _receivers.insert(Receivers::value_type(name, address));
  141. }
  142. void MailInfo::setReceiver(const std::string name, const std::string address)
  143. {
  144.     _receivers.clear();
  145.     _receivers.insert(Receivers::value_type(name, address));
  146. }
  147. const Receivers& MailInfo::getReceivers() const
  148. {
  149.     return _receivers;
  150. }
  151. void MailInfo::setPriority(std::string priority)
  152. {
  153.     _priority = priority;
  154. }
  155. std::string MailInfo::getPriority() const
  156. {
  157.     return _priority;
  158. }
  159. void MailInfo::setSubject(const std::string subject)
  160. {
  161.     _subject = subject;
  162. }
  163. std::string MailInfo::getSubject() const
  164. {
  165.     return _subject;
  166. }
  167. void MailInfo::addMimeContent(MimeContent* content)
  168. {
  169.     _contents.push_back(content);
  170. }
  171. void MailInfo::clearMimeContents()
  172. {
  173.     _contents.clear();
  174. }
  175. const MimeContents& MailInfo::getMimeContents() const
  176. {
  177.     return _contents;
  178. }
  179. // Member functions of class MailWrapper
  180. /////////////////////////////////////
  181. MailWrapper::MailWrapper(MailInfo* mail_info) : _mail_info(mail_info)
  182. {
  183. }
  184. std::string MailWrapper::getSenderAddress()
  185. {
  186.     std::string address;
  187.     address  = "<";
  188.     address += _mail_info->getSenderAddress();
  189.     address += ">";
  190.     return address;
  191. }
  192. std::string MailWrapper::getHeader()
  193. {
  194.     std::string header;
  195.     header  = "From: ";
  196.     header += prepareFrom() + "rn";
  197.     header += "Reply-To: ";
  198.     header += _mail_info->getSenderAddress() + "rn";
  199.     header += "To: ";
  200.     header += prepareTo() + "rn";
  201.     header += "Date: ";
  202.     header += prepareDate() + "rn";
  203.     header += "Subject: ";
  204.     header += _mail_info->getSubject() + "rn";
  205.     header += "X-Mailer: ";
  206.     header += _mailer_name + "rn";
  207.     header += "X-Priority: ";
  208.     header += _mail_info->getPriority() + "rn";
  209.     header += "MIME-Version: 1.0rn";
  210.     header += "Content-type: multipart/mixed; boundary="";
  211.     header += _boundary + ""rn";
  212.     header += "rn";
  213.     return header;
  214. }
  215. void MailWrapper::traverseReceiver()
  216. {
  217.     _rcv_itr = _mail_info->getReceivers().begin();
  218. }
  219. bool MailWrapper::hasMoreReceiver()
  220. {
  221.     return ( _rcv_itr != _mail_info->getReceivers().end() );
  222. }
  223. std::string MailWrapper::nextReceiverAddress()
  224. {
  225.     std::string address;
  226.     address  = "<";
  227.     address += (_rcv_itr++)->second;
  228.     address += ">";
  229.     return address;
  230. }
  231. void MailWrapper::traverseContent()
  232. {
  233.     _con_itr = _mail_info->getMimeContents().begin();
  234. }
  235. bool MailWrapper::hasMoreContent()
  236. {
  237.     return ( _con_itr != _mail_info->getMimeContents().end() );
  238. }
  239. std::string& MailWrapper::nextContent()
  240. {
  241.     _content  = "--" + _boundary + "rn";
  242.     _content += "Content-Type: ";
  243.     _content += (*_con_itr)->getType() + "rn";
  244.     std::string disposition = (*_con_itr)->getDisposition();
  245.     if ( !disposition.empty() )
  246.     {
  247.         _content += "Content-Disposition: ";;
  248.         _content += disposition + "rn";
  249.     }
  250.     _content += "Content-Transfer-Encoding: ";
  251.     _content += (*_con_itr)->getTransEncoding() + "rnrn";
  252.     _content += (*_con_itr)->getContent() + "rnrn";
  253.     _con_itr++;
  254.     return _content;
  255. }
  256. std::string MailWrapper::getEnd()
  257. {
  258.     std::string end;
  259.     end += "rn--" + _boundary + "--rn";
  260.     end += ".rn";
  261.     return end;
  262. }
  263. std::string MailWrapper::prepareFrom()
  264. {
  265.     std::string from_string;
  266.     from_string = prepareName(_mail_info->getSenderName());
  267.     from_string += getSenderAddress();
  268.     return from_string;
  269. }
  270. std::string MailWrapper::prepareTo()
  271. {
  272.     std::string to_string;
  273.     traverseReceiver();
  274.     while ( hasMoreReceiver() )
  275.     {
  276.         to_string += prepareName(_rcv_itr->first);
  277.         to_string += nextReceiverAddress() + ", ";
  278.     }
  279.     return to_string.substr(0, to_string.length()-2);
  280. }
  281. std::string MailWrapper::prepareDate()
  282. {
  283.     char date_string[MAX_BUFFER_SIZE];
  284.     time_t seconds;
  285.     time(&seconds);
  286.     strftime(date_string, MAX_BUFFER_SIZE, 
  287.              "%a, %d %b %y %H:%M:%S +0800", 
  288.              localtime(&seconds));          // +0800 maybe hard code
  289.     return date_string;
  290. }
  291. std::string MailWrapper::prepareName(const std::string raw_name)
  292. {
  293.     std::string decorated_name;
  294.     if (!raw_name.empty())
  295.     {
  296.         decorated_name  = """;
  297.         decorated_name += raw_name;
  298.         decorated_name += "" ";
  299.     }
  300.     return decorated_name;
  301. }
  302. // Member functions of class MailSender
  303. /////////////////////////////////////
  304. MailSender::MailSender(const std::string server_name, 
  305.                        const std::string user_name, 
  306.                        const std::string user_pwd)
  307.     : _server_name(server_name), _user_name(user_name), 
  308.       _user_pwd(user_pwd), _mail(0)
  309. {
  310.     conn();
  311.     hello();
  312.     if ( !user_name.empty() )
  313.         login();
  314. }
  315. MailSender::~MailSender()
  316. {
  317.     quit();
  318. }
  319. void MailSender::setMail(MailWrapper* mail)
  320. {
  321.     _mail = mail;
  322. }
  323. bool MailSender::sendMail()
  324. {
  325.     if (!_mail)
  326.         return false;
  327.     if (!sendHeader())
  328.      return false;
  329.     if (!sendContent())
  330.      return false;
  331.     if (!sendEnd())
  332.      return false;
  333.     return true;
  334. }
  335. std::string MailSender::getSenderAddress() const
  336. {
  337.     std::string sender = _user_name;
  338. size_t index = sender.find('@');
  339. if( index >= 0 && index < sender.length() )
  340. {
  341. sender = "<" + sender + ">";
  342. }
  343. else
  344. {
  345. std::string server = _server_name;
  346. size_t h = server.find("mail.");
  347. if( h >= 0 && h < server.length() )
  348. server = server.substr(5,server.length()-5);
  349. h = server.find("smtp.");
  350. if( h >= 0 && h < server.length() )
  351. server = server.substr(5,server.length()-5);
  352. sender = sender + "." + server;
  353. sender = "<" + sender + ">";
  354. }
  355.     return sender;
  356. }
  357. bool MailSender::conn()
  358. {
  359.     struct hostent* host = gethostbyname(_server_name.c_str());
  360.     if (host == 0)
  361.     {
  362.      // throw new MailException("Get server infomation error");
  363.      _err_message = "Get server infomation error";
  364.      return false;
  365.     }
  366.     _socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  367.     struct sockaddr_in server_addr;
  368.     server_addr.sin_family = AF_INET;
  369.     server_addr.sin_addr.s_addr = *(ULONG *)host->h_addr_list[0];
  370.     server_addr.sin_port = htons(SERVICE_PORT);
  371.     connect(_socket, (struct sockaddr *)&server_addr, sizeof(server_addr));
  372.     return rcvResponse("220");
  373. }
  374. bool MailSender::hello()
  375. {
  376.     char local_host[MAX_BUFFER_SIZE];
  377.     if ( gethostname(local_host, MAX_BUFFER_SIZE) != 0 )
  378.     {
  379.         // throw new MailException("Get local host name error");
  380.         _err_message = "Get local host name error";
  381.         return false;
  382.     }
  383.     std::string msg;
  384.     msg  = "HELO ";
  385.     msg += std::string(local_host) + "rn";
  386.     if(!sendRequest(send_helo_cmd, msg))
  387.      return false;
  388.     return rcvResponse("250");
  389. }
  390. bool MailSender::login()
  391. {
  392.     std::string msg;
  393.     msg = "AUTH LOGINrn";
  394.     if(!sendRequest(send_auth_cmd, msg))
  395.      return false;
  396.     if(!rcvResponse("334"))
  397.      return false;
  398.     msg = MUtils::Base64Helper::encode(_user_name) + "rn";
  399.     if(!sendRequest(send_username, msg))
  400.      return false;
  401.     if(!rcvResponse("334"))
  402.      return false;
  403.     msg = MUtils::Base64Helper::encode(_user_pwd) + "rn";
  404.     if(!sendRequest(send_password, msg))
  405.      return false;
  406.     return rcvResponse("235");
  407. }
  408. bool MailSender::sendHeader()
  409. {
  410.     std::string msg;
  411.     msg  = "MAIL FROM: ";
  412.     msg += getSenderAddress() + "rn";
  413.     if(!sendRequest(send_mail_cmd, msg))
  414.      return false;
  415.     if(!rcvResponse("250"))
  416.      return false;
  417.     _mail->traverseReceiver();
  418.     while ( _mail->hasMoreReceiver() )
  419.     {
  420.         msg  = "RCPT TO: ";
  421.         msg += _mail->nextReceiverAddress() + "rn";
  422.         if(!sendRequest(send_rcpt_cmd, msg))
  423.          return false;
  424.         if(!rcvResponse("250"))
  425.          return false;
  426.     }
  427.     msg  = "DATArn";
  428.     if(!sendRequest(send_data_cmd, msg))
  429.      return false;
  430.     if(!rcvResponse("354"))
  431.      return false;
  432.     return sendRequest(send_header, _mail->getHeader());
  433. }
  434. bool MailSender::sendContent()
  435. {
  436.     _mail->traverseContent();
  437.     while ( _mail->hasMoreContent() )
  438.     {
  439.         if(!sendRequest(send_content, _mail->nextContent()))
  440.          return false;
  441.     }
  442.     return true;
  443. }
  444. bool MailSender::sendEnd()
  445. {
  446.     if(!sendRequest(send_end, _mail->getEnd()))
  447.      return false;
  448.     return rcvResponse("250");
  449. }
  450. bool MailSender::quit()
  451. {
  452.     if(!sendRequest(send_quit_cmd, "QUITrn"))
  453.      return false;
  454.     if(!rcvResponse("221"))
  455.      return false;
  456.     closesocket(_socket);
  457.     return true;
  458. }
  459. bool MailSender::rcvResponse(const std::string expected_response)
  460. {
  461.     int recv_bytes = 0;
  462.     char response_buffer[MAX_BUFFER_SIZE];
  463.     if ( (recv_bytes = recv(_socket, response_buffer, MAX_BUFFER_SIZE, 0)) < 0 )
  464.     {
  465.      _err_message = ErrorMessage::getInstance().response(expected_response);
  466.      return false;
  467.         //throw new MailException( 
  468.         //    ErrorMessage::getInstance().response(expected_response)
  469.         //);
  470.     }
  471.     std::string response(response_buffer, recv_bytes);
  472.     std::cout << "[INFO]RECV(" << expected_response << "):" 
  473.               << response << std::endl;
  474.     if ( response.substr(0, 3) != expected_response )
  475.     {
  476.      _err_message = ErrorMessage::getInstance().response(expected_response);
  477.      return false;
  478.         //throw new MailException( 
  479.         //    ErrorMessage::getInstance().response(expected_response)
  480.         //);
  481.     }
  482.     return true;
  483. }
  484. bool MailSender::sendRequest(Operaion operation, 
  485.                              const std::string content)
  486. {
  487.     std::cout << "[INFO]SEND:" << content << std::endl;
  488.     if ( send(_socket, content.c_str(), content.length(), 0) < 0 )
  489.     {
  490.      _err_message = ErrorMessage::getInstance().request(operation);
  491.      return false;
  492.         //throw new MailException(
  493.         //    ErrorMessage::getInstance().request(operation)
  494.         //);
  495.     }
  496.     return true;
  497. }
  498. // Member functions of class ErrorMessage
  499. /////////////////////////////////////
  500. ErrorMessage& ErrorMessage::getInstance()
  501. {
  502.     static ErrorMessage _instance;
  503.     return _instance;
  504. }
  505. ErrorMessage::ErrorMessage()
  506. {
  507.     _request_errmsg_map[MailSender::send_helo_cmd] = "Send HELO cmd error";
  508.     _request_errmsg_map[MailSender::send_auth_cmd] = "Send AUTH cmd error";
  509.     _request_errmsg_map[MailSender::send_username] = "Send user name error";
  510.     _request_errmsg_map[MailSender::send_password] = "Send user password error";
  511.     _request_errmsg_map[MailSender::send_mail_cmd] = "Send MAIL FROM cmd error";
  512.     _request_errmsg_map[MailSender::send_rcpt_cmd] = "Send RCPT TO cmd error";
  513.     _request_errmsg_map[MailSender::send_data_cmd] = "Send DATA cmd error";
  514.     _request_errmsg_map[MailSender::send_header  ] = "Send mail header error";
  515.     _request_errmsg_map[MailSender::send_content ] = "Send mail content error";
  516.     _request_errmsg_map[MailSender::send_end     ] = "Send mail end error";
  517.     _request_errmsg_map[MailSender::send_quit_cmd] = "Send QUIT cmd error";
  518.     _respons_errmsg_map["220"] = "Server connect error";
  519.     _respons_errmsg_map["250"] = "General server error";
  520.     _respons_errmsg_map["334"] = "Server authentication error";
  521.     _respons_errmsg_map["235"] = "Password error";
  522.     _respons_errmsg_map["354"] = "Server not ready for data";
  523.     _respons_errmsg_map["221"] = "Server didn't terminate session";
  524. }
  525. std::string ErrorMessage::request(MailSender::Operaion request_operation)
  526. {
  527.     return _request_errmsg_map[request_operation];
  528. }
  529. std::string ErrorMessage::response(const std::string expected_response)
  530. {
  531.     return _respons_errmsg_map[expected_response];
  532. }
  533. } // namespace SMailer