免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12
最近访问板块 发新帖
楼主: zjzfb
打印 上一主题 下一主题

请教SMTP发邮件时未发DATA而发RSET的问题 [复制链接]

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
11 [报告]
发表于 2007-01-18 09:16 |只看该作者

  1. #include "SendMail.h"

  2. CSendMail::CSendMail ()
  3. :m_bConnected (false),
  4. m_socket (-1),
  5. m_nPort (25)
  6. {
  7.         m_sendTimeout.tv_sec   = 3;
  8.         m_sendTimeout.tv_usec  = 0;
  9. }
  10. CSendMail::~CSendMail ()
  11. {
  12.         m_bConnected = false;
  13.         close (m_socket);
  14. }
  15. //-------------------------------------member function--------------------------------------
  16. //return -1: get host by name error
  17. //return -2: open socket error
  18. //return -3: connect error
  19. int CSendMail::ConnectTo (const char *sHost)
  20. {
  21.         if (sHost == NULL || m_nPort < 0)
  22.                 return -1;
  23.         struct sockaddr_in client;
  24.         struct hostent *hp;
  25.         bzero ((char*)&client, sizeof (client));
  26.         if (isdigit (sHost[0]) && isdigit (sHost[1]))  //192.169.5.132
  27.         {
  28.                 client.sin_family       = AF_INET;
  29.                 client.sin_addr.s_addr  = inet_addr (sHost);
  30.                 client.sin_port         = htons (m_nPort);
  31.         }else          //www.google.com
  32.         {
  33.                 if ((hp = gethostbyname (sHost)) == NULL)
  34.                 {
  35. #ifdef IP_DEBUG
  36.                         print_bug (gethostbyname failed!);
  37.                         perror("gethostbyname");
  38. #endif
  39.                         m_socket = INVALID_SOCKET;
  40.                         return -1; //
  41.                 }
  42.                 bcopy (hp->h_addr, (char *)&client.sin_addr, hp->h_length);
  43.             client.sin_family = hp->h_addrtype;
  44.               client.sin_port   = htons (m_nPort);
  45.         }
  46.         m_socket = socket (AF_INET, SOCK_STREAM, 0);
  47.         if (m_socket <= 0)
  48.         {
  49. #ifdef IP_DEBUG
  50.               perror("socket");
  51. #endif
  52.               return -2;
  53.     }
  54.         const int on = 1;
  55.         setsockopt (m_socket, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on));
  56.         if (connect (m_socket, (struct sockaddr *)&client, sizeof (client)) < 0)
  57.         {
  58. #ifdef IP_DEBUG
  59.                 perror ("connect");
  60. #endif
  61.                 close (m_socket);
  62.                 return -3;
  63.         }
  64.         if (CheckResponseCode (CONNECTION_CHECK) != 0)
  65.         {
  66.                 DisConnect ();
  67.                 return -1;
  68.         }
  69.         m_bConnected = true;
  70.         return 0;
  71. }
  72. //send RCPT TO
  73. void CSendMail::SetFromAndTo (const std::string &sFrom, const std::string &sTo)
  74. {
  75.         std::string tmp;
  76.         m_sFrom = sFrom;
  77.         //
  78.         char *buff = new char[sTo.length () + 1];
  79.         strcpy (buff, sTo.c_str ());
  80.         buff[sTo.length ()] = '\0';
  81.         char *pTok = strtok (buff, ", ");
  82.         m_vTo.push_back (std::string (pTok));
  83.         while ((pTok = strtok (NULL, ", ")))
  84.         {
  85.                 m_vTo.push_back (std::string (pTok));
  86.         }
  87.         delete []buff;
  88. }
  89. //
  90. void CSendMail::SetUsernameAndPasswd (const std::string &username, const std::string &passwd)
  91. {
  92.         m_userName = username;
  93.         m_passwd   = passwd;
  94.         char buff[64] = {0};
  95.         int ret = EncodingBase64 (m_userName.c_str(), buff, m_userName.length ());
  96.         m_encodeName.assign (buff, ret);
  97.         memset (buff, 0, 64);
  98.         ret = EncodingBase64 (m_passwd.c_str (), buff, m_passwd.length ());
  99.         m_encodePasswd.assign (buff, ret);
  100. }
  101. //send DATA
  102. void CSendMail::SetSubject (const std::string &subject)
  103. {
  104.         m_sSubject = subject;
  105. }
  106. void CSendMail::SetSenderName (const std::string &senderName)
  107. {
  108.         m_senderName = senderName;
  109. }
  110. void CSendMail::SetCC (const std::string &cc)
  111. {
  112.         char *buff = new char[cc.length () + 1];
  113.         strcpy (buff, cc.c_str ());
  114.         buff[cc.length ()] = '\0';
  115.         char *pTok = strtok (buff, ", ");
  116.         m_vCC.push_back (std::string (pTok));
  117.         while ((pTok = strtok (NULL, ", ")))
  118.         {
  119.                 m_vCC.push_back (std::string (pTok));
  120.         }
  121.         delete []buff;
  122. }
  123. void CSendMail::SetBCC (const std::string &bcc)
  124. {
  125.         char *buff = new char[bcc.length () + 1];
  126.         strcpy (buff, bcc.c_str ());
  127.         buff[bcc.length ()] = '\0';
  128.         char *pTok = strtok (buff, ", ");
  129.         m_vBCC.push_back (std::string (pTok));
  130.         while ((pTok = strtok (NULL, ", ")))
  131.         {
  132.                 m_vBCC.push_back (std::string (pTok));
  133.         }
  134.         delete []buff;
  135. }
  136. std::string CSendMail::GetAttachType (std::string &filename)
  137. {
  138.         return std::string ("application/octet-stream");
  139. }
  140. //
  141. int CSendMail::SendAuth ()
  142. {
  143.         char buff[128] = {0};
  144.         snprintf (buff, 127, "AUTH LOGIN\r\n");
  145.         if (SendCtrlMsg (buff) != 0)
  146.                 return -1;
  147.         if (CheckResponseCode (AUTH_START_CHECK) != 0)  // 334
  148.                 return -1;
  149.         std::string tmp (m_encodeName);
  150.         tmp.append ("\r\n");
  151.         if (SendCtrlMsg (tmp) != 0)
  152.                 return -1;
  153.         if (CheckResponseCode (AUTH_START_CHECK) != 0) //334
  154.                 return -1;
  155.         tmp.assign (m_encodePasswd);
  156.         tmp.append ("\r\n");
  157.         if (SendCtrlMsg (tmp) != 0)
  158.                 return -1;
  159.         if (CheckResponseCode (AUTH_CHECK) != 0) //235 succ
  160.                 return -1;
  161.         return 0;
  162. }
  163. //send header
  164. int CSendMail::SendHead ()
  165. {
  166.         std::string head;
  167.         char stime[128] = {0};
  168.         time_t tt = time (NULL);
  169.         struct tm *ttm = localtime (&tt);
  170.         strftime (stime, 127, "%a, %d %b %Y %H:%M:%S %z\r\n", ttm);
  171.         //add Date
  172.         head.append ("Date: ");
  173.         head.append (stime);
  174.         //add From
  175.         if (m_senderName.empty ())
  176.                 m_senderName = m_sFrom.substr (0, m_sFrom.find ('@'));
  177.         head += std::string ("From: \"") + m_senderName + "\"" + "<" + m_sFrom + ">" + "\r\n";
  178.         //add To
  179.         std::vector<std::string>::iterator pos;
  180.         head += "To:";
  181.         for (pos = m_vTo.begin (); pos != m_vTo.end (); ++pos)
  182.         {
  183.                 std::string to = pos->substr (0, pos->find ('@'));
  184.                 head += std::string (" \"") + to + "\"" + "<" + *pos + ">" + "\r\n";
  185.         }
  186.         //add CC
  187.         if (!m_vCC.empty ())
  188.         {
  189.                 head += "Cc:";
  190.                 for (pos = m_vCC.begin (); pos != m_vCC.end (); ++pos)
  191.                 {
  192.                         std::string to = pos->substr (0, pos->find ('@'));
  193.                         head += std::string (" \"") + to + "\"" + "<" + *pos + ">" + "\r\n";
  194.                 }
  195.         }
  196.         //add BCC
  197.         if (!m_vBCC.empty ())
  198.         {
  199.                 head += "Bcc:";
  200.                 for (pos = m_vBCC.begin (); pos != m_vBCC.end (); ++pos)
  201.                 {
  202.                         std::string to = pos->substr (0, pos->find ('@'));
  203.                         head += std::string (" \"") + to + "\"" + "<" + *pos + ">" + "\r\n";
  204.                 }
  205.         }
  206.         //add subject
  207.         head += std::string ("Subject: ") + m_sSubject + "\r\n";
  208.         //add MessageID
  209.         memset (stime, 0, 128);
  210.         long lTime = (long)(time (NULL));
  211.         std::string prefix = m_sFrom.substr (m_sFrom.find ('@'));
  212.         snprintf (stime, 128, "Message-ID: <%ld%s>\r\n", lTime, prefix.c_str ());
  213.         head += stime;
  214.         //add X-mailer
  215.         head += "X-mailer: HXHT-cuishaowei (mail:shaovie@gmail.com)\r\n";
  216.         //add mime version
  217.         head += "Mime-version: 1.0\r\n";
  218.         m_majorSplitTag = "====MajorSplitTag====";
  219.         if (!m_vAttachment.empty ()) //having attachment
  220.         {
  221.                 m_nMailType = MAIL_TEXT_ATTACHMENT;
  222.                 head += std::string ("Content-Type: multipart/mixed;\r\n\tboundary=\"") + m_majorSplitTag + "\"\r\n";;
  223.         }else  //pure text mail, no attachment
  224.         {
  225.                 m_nMailType = MAIL_PURE_TEXT;
  226.                 head += "Content-Type: text/plain;\r\n\tcharset=\"gb2312\"\r\n";
  227.                 head += "Content-Transfer-Encoding: base64\r\n";
  228.                 //head += "Content-Transfer-Encoding: 7bit\r\n";
  229.         }
  230.         m_majorSplitTag = std::string ("--") + m_majorSplitTag + "\r\n";
  231.         head += "\r\n"; //mustn't lost
  232.         int ret = SendCtrlMsg (head);       
  233.         return ret;
  234. }
  235. //
  236. int CSendMail::SendBodyPureText (const std::string &encodeText)
  237. {
  238.         std::string text;
  239.         text.assign (encodeText);
  240.         text.append ("\r\n");
  241.         text.append ("\r\n.\r\n");
  242.         SendCtrlMsg (text);
  243.         return CheckResponseCode (DATA_END_CHECK);
  244. }
  245. int CSendMail::SendBodyHtmlOnly (const std::string &encodeText, const std::string &encodeHtml,
  246.                                                                  const std::string &splitTag)
  247. {
  248.         std::string data;
  249.         data.append ("This is a multi-part message in MIME format.\r\n");
  250.         data.append ("\r\n");
  251.         data.append (splitTag);
  252.         data.append ("Content-Type: text/plain;\r\n\tcharset=\"gb2312\"\r\n");
  253.         data.append ("Content-Transfer-Encoding: 7bit\r\n");
  254.         data.append ("\r\n");
  255.         data.append (encodeText);
  256.         data.append ("\r\n");
  257.         data.append (splitTag);
  258.         data.append ("Content-Type: text/html;\r\n\tcharset=\"gb2312\"\r\n");
  259.         data.append ("Content-Transfer-Encoding: 7bit\r\n");
  260.         data.append ("\r\n");
  261.         data.append (encodeHtml);
  262.         data.append ("\r\n");
  263.         data.append (splitTag);
  264.         data.append ("\r\n.\r\n");
  265.         SendCtrlMsg (data);
  266.         return CheckResponseCode (DATA_END_CHECK);       
  267. }
  268. int CSendMail::SendBodyTextAndAttachMent (const std::string &encodeText,
  269.                                                                                   const std::string &majorSplitTag)
  270. {
  271.         std::string data;
  272.         data.append ("This is a multi-part message in MIME format.\r\n");
  273.         data.append ("\r\n");
  274.         data.append (majorSplitTag);
  275.         data.append ("Content-Type: text/plain;\r\n\tcharset=\"gb2312\"\r\n");
  276.         data.append ("Content-Transfer-Encoding: base64\r\n");
  277.         data.append ("\r\n");
  278.         data.append (encodeText);
  279.         data.append ("\r\n");
  280.         SendCtrlMsg (data);
  281.         SendAttachment (majorSplitTag);
  282.         return CheckResponseCode (DATA_END_CHECK);;
  283. }
  284. int CSendMail::SendBodyTextAndHtmlAndAttachMent (const std::string &encodeText,
  285.                                                                                   const std::string &encodeHtml,
  286.                                                                                   const std::string &majorSplitTag,
  287.                                                                                   const std::string &subSplitTag)
  288. {
  289.         std::string data;
  290.         data.append ("This is a multi-part message in MIME format.\r\n");
  291.         data.append ("\r\n");
  292.         data.append (majorSplitTag);
  293.         data.append ("Content-Type: multipart/alternative;\r\n\tboundary=\"");
  294.         data.append (subSplitTag);
  295.         data.append ("\"\r\n");
  296.         data.append ("\r\n");
  297.         std::string sub = "--" + subSplitTag + "\r\n";
  298.         data.append (sub);
  299.         data.append ("Content-Type: text/plain;\r\n\tcharset=\"gb2312\"\r\n");
  300.         data.append ("Content-Transfer-Encoding: base64\r\n");
  301.         data.append ("\r\n");
  302.         data.append (encodeText);
  303.         data.append ("\r\n");
  304.         SendCtrlMsg (data);
  305.         SendAttachment (sub);
  306.         return CheckResponseCode (DATA_END_CHECK);
  307. }
  308. //只是发送附近数据段部分,包括最后的分隔符
  309. int CSendMail::SendAttachment (const std::string &splitTag)
  310. {
  311.         std::vector<std::string>::iterator pos;
  312.         std::string data;
  313.         std::string name;
  314.         data.reserve (256);
  315.         for (pos = m_vAttachment.begin (); pos != m_vAttachment.end (); ++pos)
  316.         {
  317.                 data.assign (splitTag);
  318.                 data.append ("Content-Type: ");
  319.                 data.append (GetAttachType (*pos));
  320.                 data.append (";\r\n\tname=\"=?gb2312?B?");
  321.                 int nP = pos->find ('/');
  322.                 if ( nP != std::string::npos)
  323.                         nP += 1;
  324.                 else
  325.                         nP = 0;
  326.                 name = pos->substr (nP);
  327.                 char *buff = new char[name.length () * 2];
  328.                 int ret = EncodingBase64 (name.c_str (), buff, name.length ());
  329.                 data.append (buff, ret);

  330.                 data.append ("?=\"\r\n");
  331.                 data.append ("Content-Transfer-Encoding: base64\r\n");
  332.                 data.append ("Content-Disposition: attachment;\r\n\t");
  333.                 data.append ("filename=\"=?gb2312?B?");
  334.                 data.append (buff, ret);
  335.                 delete []buff;
  336.                 buff = NULL;
  337.                 data.append ("?=\"\r\n");
  338.                 data.append ("\r\n");
  339.                 SendCtrlMsg (data);
  340.                 //start read attachment
  341.                 int fd = open (pos->c_str (), O_RDONLY);
  342.                 if (fd < 0)
  343.                 {
  344. #ifdef IP_DEBUG
  345.                         print_info_n (attachment file can not open);
  346. #endif
  347.                         SendCtrlMsg (std::string ("\r\n"));
  348.                         continue;
  349.                 }
  350.                 char fileBuff[76];
  351.                 char base64buff[150] = {0};  // 4096 > 2048 : base64Buff'len must longer 1/3times than buff
  352.                 std::string streamBuff;
  353.                 streamBuff.reserve (4096 + 76);
  354.                 while ((ret = read (fd, fileBuff, 76)) > 0)
  355.                 {
  356.                         int n = EncodingBase64 (fileBuff, base64buff, ret);
  357.                         streamBuff.append (base64buff, n);
  358.                         streamBuff.append ("\r\n");
  359.                         if (streamBuff.length () < 4096 &&  ret >= 76)
  360.                                 continue;
  361.                         SendCtrlMsg (streamBuff);
  362.                         streamBuff.assign ("");
  363.                 }
  364.                 close (fd);
  365.                 SendCtrlMsg (std::string ("\r\n"));
  366.         }
  367.         data.assign (m_majorSplitTag);
  368.         data.append ("\r\n.\r\n");
  369.         return SendCtrlMsg (data);
  370. }
  371. //
  372. int CSendMail::SendMail (const std::string &msg, std::string attachment, std::string html)
  373. {
  374.         if (!attachment.empty ())
  375.         {
  376.                 char buf[512] = {0};
  377.                 strncpy (buf, attachment.c_str (), 511);
  378.                 char *pTok = strtok (buf, ", ");
  379.                 m_vAttachment.push_back (std::string (pTok));
  380.                 while ((pTok = strtok (NULL, ", ")))
  381.                         m_vAttachment.push_back (std::string (pTok));
  382.         }
  383.         char buff[128] = {0};
  384.         int ret;
  385.         char *pText = NULL;
  386.         std::string encodeText;
  387.         std::string encodeHtml;
  388.         std::vector<std::string>::iterator pos;
  389.         // 1. send ehlo
  390.         snprintf (buff, 128, "EHLO %s\r\n", m_sFrom.substr (m_sFrom.find ('@') + 1).c_str ());
  391.         if (SendCtrlMsg (buff) != 0)
  392.                 return -1;
  393.         if (CheckResponseCode (HELLO_CHECK) != 0)
  394.                 goto END;
  395.         // 2. auth
  396.         if (SendAuth () != 0)
  397.                 goto END;
  398.         // 3. send Mail
  399.         memset (buff, 0, 128);
  400.         snprintf (buff, 127, "MAIL From:<%s>\r\n", m_sFrom.c_str ());
  401.         if (SendCtrlMsg (buff) != 0)
  402.                 return -1;
  403.         if (CheckResponseCode (MAIL_CHECK) != 0)
  404.                 goto END;
  405.         //4. send to
  406.         for (pos = m_vTo.begin (); pos != m_vTo.end (); ++pos)
  407.         {
  408.                 memset (buff, 0, 128);
  409.                 snprintf (buff, 127, "RCPT TO:<%s>\r\n", pos->c_str ());
  410.                 if (SendCtrlMsg (buff) != 0)
  411.                         goto END;
  412.                 if (CheckResponseCode (RCPT_CHECK) != 0)
  413.                         goto END;
  414.         }
  415.         //5. send Data
  416.         memset (buff, 0, 128);
  417.         snprintf (buff, 127, "DATA\r\n");
  418.         if (SendCtrlMsg (buff) != 0)
  419.                 goto END;
  420.         if (CheckResponseCode (DATA_START_CHECK) != 0)
  421.                 goto END;
  422.         //6. send head info
  423.         if (SendHead () != 0)
  424.                 goto END;
  425.         //7. send body
  426.         pText = new char[msg.length () * 2];
  427.         ret = EncodingBase64 (msg.c_str (), pText, msg.length ());
  428.         encodeText.assign (pText, ret);
  429.         delete []pText;
  430.         if (!html.empty ())
  431.         {
  432.                 pText = new char[html.length () * 2];
  433.                 ret = EncodingBase64 (html.c_str (), pText, html.length ());
  434.                 encodeHtml.assign (pText, ret);
  435.                 delete []pText;
  436.         }
  437.         switch (m_nMailType)
  438.         {
  439.         case MAIL_PURE_TEXT:
  440.                 SendBodyPureText (encodeText);
  441.                 break;
  442.         case MAIL_TEXT_ATTACHMENT:
  443.                 SendBodyTextAndAttachMent (encodeText, m_majorSplitTag);
  444.                 break;
  445.         case MAIL_TEXT_HTML_ATTACH:
  446.                 SendBodyTextAndHtmlAndAttachMent (encodeText, encodeHtml, m_majorSplitTag, m_subSplitTag);
  447.                 break;
  448.         default:
  449.                 break;
  450.         }
  451.         memset (buff, 0, 128);
  452.         strncpy (buff, "QUIT\r\n", 127);
  453.         if (SendCtrlMsg (buff) != 0)
  454.                 goto END;
  455.         if (CheckResponseCode (QUIT_CHECK) != 0)
  456.                 goto END;
  457.         return 0;
  458. END:
  459.         DisConnect ();
  460.         return -1;
  461. }

  462. int CSendMail::SendCtrlMsg (const std::string &msg)
  463. {
  464.        
  465.         fd_set writeFds;
  466.         FD_ZERO (&writeFds);
  467.         FD_SET (m_socket, &writeFds);
  468.        
  469.         if (m_bConnected && (m_socket > 0))
  470.         {
  471.                 while (true)
  472.                 {
  473.                         if (select (m_socket + 1, NULL, &writeFds, NULL, &m_sendTimeout) > 0)
  474.                         {
  475.                                 //if (FD_ISSET (m_socket, &writeFds))
  476.                                 if (send (m_socket, msg.c_str (), msg.length (), 0) > 0)
  477.                                         break;
  478.                                 else return -1;
  479.                         }else
  480.                         {
  481. #ifdef IP_DEBUG
  482.                                 print_info_n ([Mail] send msg timeout or error);
  483. #endif
  484.                         }
  485.                 }
  486.         }else
  487.                 return -1;
  488.         return 0;
  489. }
  490. //
  491. int CSendMail::CheckResponseCode (int type)
  492. {
  493.         char buff[1024] = {0};
  494.         if (recv (m_socket, buff, 1023, 0) <= 0)
  495.                 return -1;
  496.         char temp[3] = {0};
  497.        
  498.         strncpy (temp, buff, 3);
  499.         int nRetCode = atoi (temp);
  500.         switch (type)
  501.         {
  502.         case CONNECTION_CHECK:
  503.                 if (nRetCode != 220)   // 220 服务就绪
  504.                         goto END;
  505.                 break;
  506.                
  507.         case HELLO_CHECK:
  508.                 if (nRetCode != 250)   // 请求邮件动作正确,完成(EHLO,MAIL FROM,RCPT TO,QUIT指令执行成功会返回此信息)
  509.                         goto END;
  510.                 break;
  511.         case MAIL_CHECK:
  512.                 if (nRetCode != 250)
  513.                         goto END;
  514.                 break;
  515.         case RCPT_CHECK:
  516.                 if (nRetCode != 250)
  517.                         goto END;
  518.                 break;
  519.         case AUTH_CHECK:
  520.                 if (nRetCode != 235)
  521.                         goto END;
  522.                 break;
  523.         case AUTH_START_CHECK:
  524.                 if (nRetCode != 334)
  525.                         goto END;
  526.                 break;
  527.         case DATA_START_CHECK:
  528.                 if (nRetCode != 354) //   354 开始发送数据,结束以 .(DATA指令执行成功会返回此信息,客户端应发送信息)
  529.                         goto END;
  530.                 break;
  531.         case DATA_END_CHECK:
  532.                 if (nRetCode != 250)
  533.                         goto END;
  534.                 break;
  535.         case QUIT_CHECK:
  536.                 if (nRetCode != 221) //  221 正在处理 250 queued
  537.                         goto END;
  538.                 break;
  539.         case DATA_CHECK:
  540.                 if (nRetCode != 354)
  541.                         goto END;
  542.                 break;
  543.         default:
  544.                 return -1;
  545.                 break;       
  546.         }
  547.         return 0;
  548. END:
  549. #ifdef IP_DEBUG
  550.         print_info ();
  551.         printf ("%s\n", buff);
  552. #endif
  553.         return nRetCode;
  554. }
  555. //
  556. int CSendMail::DisConnect ()
  557. {
  558.         m_bConnected = false;
  559.         return close (m_socket);
  560. }
  561. int CSendMail::EncodingBase64 (const char* src, char* des, int srcLen)
  562. {
  563.         assert (src && des);
  564.         char *pdes = des;
  565.         const char *psrc = src;
  566.         int len = 0;
  567.         int i = 0;
  568.         char sixbit_encoding[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  569.         while ((src - psrc) < srcLen)//(*src != NULL)
  570.         {
  571.                 *des++ = sixbit_encoding[(unsigned char)*src++ >> 2]; //6
  572.                 if ((src - psrc) == srcLen) //(*src == NULL)
  573.                 {
  574.                         *des++ = sixbit_encoding[(*(src - 1) & 0x3) << 4];//2+4
  575.                         *des++ = '=';
  576.                         *des++ = '=';
  577.                         break;
  578.                 }
  579.                 else
  580.                 {
  581.                         *des++ = sixbit_encoding[(*(src - 1) & 0x3) << 4 | (unsigned char)(*src) >> 4];//2+4
  582.                         src++;
  583.                 }
  584.                 if ((src - psrc) == srcLen) //(*src == NULL)
  585.                 {
  586.                         *des++ = sixbit_encoding[(*(src - 1) & 0xF) << 2];//4+2
  587.                         *des++ = '=';
  588.                 }
  589.                 else
  590.                 {
  591.                         *des++ = sixbit_encoding[(*(src - 1) & 0xF) << 2 | (unsigned char)(*src) >> 6];//4+2
  592.                         *des++ = sixbit_encoding[*src & 0x3F];//6
  593.                         src++;
  594.                 }
  595.         }
  596.         //*des = '\0';
  597.         len = des - pdes;
  598.         return len;
  599. }
  600. int main ()
  601. {
  602.          CSendMail cui;
  603.          cui.ConnectTo ("mail.megaeyes.com");
  604.          cui.SetFromAndTo ("xxxxx@megaeyes.com", "xxxxx@sina.com.cn");
  605.          cui.SetSubject ("test");
  606.          cui.SetUsernameAndPasswd ("xxxx@megaeyes.com", "xxxx");
  607.          cui.SetSenderName ("hello");
  608.          cui.SendMail ("hello world!", "error.JPG");
  609. }
复制代码



这里我只给出了.cpp的东西..
我抓到的Foxmail包就没有RST.不过间倒有FIN位的包,
首先Foxmail会发送Helo通知服务器建立链接,但现在一般的服务器都有验证的过程..但这种链接方式没有验证过程,所以服务器拒绝..然后客户端重新用EHLO 建立链接, 然后发送验证信息,
你看你抓的包.RST之前肯定有一个FIN的包..然后你再发送数据,服务器端的TCP会返回一个RST位..
肯定有些地方数据格式不对.

这也仅是我的个人见解,,如有哪位高手熟悉SMTP 可以指点一下..

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
12 [报告]
发表于 2007-01-18 09:18 |只看该作者
另外,,代码不是很高效..请高手们指点一二

论坛徽章:
0
13 [报告]
发表于 2007-01-18 16:52 |只看该作者
也贴一下我自己的

  1. VSmtpServer::VSmtpServer()
  2. {
  3. }

  4. VSmtpServer::~VSmtpServer()
  5. {
  6.     this->DisconnectFromServer();
  7. }

  8. mInt32 VSmtpServer::ConnectToServer( const char* pServerAddr, mUInt16 nServerPort )
  9. {
  10.     mInt32  retVal      =   E_SUCCESS;
  11.     mInt32  bytesRecv   =   0;

  12.     size_t  lenCmd      =   0;

  13.     // connect to SMTP server
  14.     retVal  =   this->m_connector.Open( pServerAddr, nServerPort );
  15.     if ( retVal != E_SUCCESS )
  16.     {
  17.         goto EXIT_FUNCTION;
  18.     }

  19.     // query status of SMTP server
  20.     bytesRecv   =   this->RecvResp();
  21.     if ( bytesRecv < 0 )
  22.     {
  23.         retVal  =   bytesRecv;
  24.         goto EXIT_FUNCTION;
  25.     }
  26.     else if ( bytesRecv == 0 )
  27.     {
  28.         retVal  =   E_SOCKET_PEER_CLOSED;
  29.         goto EXIT_FUNCTION;
  30.     }
  31.     if ( ::atoi(this->m_bufRecv) != 220 )
  32.     {
  33.         retVal  =   E_SOCKET_PEER_INVALID;
  34.         goto EXIT_FUNCTION;
  35.     }

  36.     // identify self to SMTP
  37.     lenCmd  =   ::strlen( "EHLO " );
  38.     ::memset( this->m_bufSend, 0, MMAIL_MAX_CMD_DATA_LEN );
  39.     ::memcpy( this->m_bufSend, "EHLO ", lenCmd );
  40.     MSocketBase::GetHostName( this->m_bufSend + lenCmd, MMAIL_MAX_CMD_DATA_LEN - lenCmd );
  41.     lenCmd  =   ::strlen( this->m_bufSend );
  42.     this->m_bufSend[lenCmd]     =   0xD;
  43.     this->m_bufSend[lenCmd+1]   =   0xA;
  44.     retVal  =   this->m_connector.Send( this->m_bufSend, lenCmd + 2 );
  45.     if ( retVal != E_SUCCESS )
  46.     {
  47.         goto EXIT_FUNCTION;
  48.     }

  49.     // check identify result
  50.     bytesRecv   =   this->RecvResp();
  51.     if ( bytesRecv < 0 )
  52.     {
  53.         retVal  =   bytesRecv;
  54.         goto EXIT_FUNCTION;
  55.     }
  56.     else if ( bytesRecv == 0 )
  57.     {
  58.         retVal  =   E_SOCKET_PEER_CLOSED;
  59.         goto EXIT_FUNCTION;
  60.     }
  61.     if ( ::atoi(this->m_bufRecv) != 250 )
  62.     {
  63.         retVal  =   E_SOCKET_PEER_INVALID;
  64.         goto EXIT_FUNCTION;
  65.     }

  66.     // set send/recv timeout - 10s
  67.     this->m_connector.SetTimeoutSend( 10000 );
  68.     this->m_connector.SetTimeoutRecv( 10000 );

  69. EXIT_FUNCTION:
  70.     if ( retVal != E_SUCCESS )
  71.     {
  72.         this->m_connector.Close();
  73.         return retVal;
  74.     }

  75.     return retVal;
  76. }

  77. mInt32 VSmtpServer::DisconnectFromServer()
  78. {
  79.     if ( this->m_connector.IsValidSocket() )
  80.     {
  81.         this->SendReq( "QUIT", ::strlen("QUIT") );
  82.         this->RecvResp();

  83.         this->m_connector.Close();
  84.     }

  85.     return E_SUCCESS;
  86. }

  87. mInt32 VSmtpServer::Authenticate( const char* pUserName, const char* pPassword )
  88. {
  89.     mInt32  retVal      =   E_SUCCESS;
  90.     mInt32  bytesRecv   =   0;

  91.     mInt32  lenSrc      =   0;

  92.     // send AUTH LOGIN
  93.     retVal  =   this->SendReq( "AUTH LOGIN", ::strlen("AUTH LOGIN") );
  94.     if ( retVal != E_SUCCESS )
  95.     {
  96.         goto EXIT_FUNCTION;
  97.     }
  98.     // get reponse
  99.     bytesRecv   =   this->RecvResp();
  100.     if ( bytesRecv < 0 )
  101.     {
  102.         retVal  =   bytesRecv;
  103.         goto EXIT_FUNCTION;
  104.     }
  105.     else if ( bytesRecv == 0 )
  106.     {
  107.         retVal  =   E_SOCKET_PEER_CLOSED;
  108.         goto EXIT_FUNCTION;
  109.     }
  110.     // check reponse
  111.     if ( ::atoi(this->m_bufRecv) != 334 )
  112.     {
  113.         retVal  =   E_SOCKET_SERVER_HANDLE;
  114.         goto EXIT_FUNCTION;
  115.     }

  116.     // send username encoded by base64
  117.     lenSrc  =   (mInt32)( ::strlen(pUserName) );
  118.     EncodeBase64( this->m_bufRecv, pUserName, lenSrc );
  119.     retVal  =   this->SendReq( this->m_bufRecv, CalLenBase64(lenSrc) );
  120.     if ( retVal != E_SUCCESS )
  121.     {
  122.         goto EXIT_FUNCTION;
  123.     }
  124.     // get reponse
  125.     bytesRecv   =   this->RecvResp();
  126.     if ( bytesRecv < 0 )
  127.     {
  128.         retVal  =   bytesRecv;
  129.         goto EXIT_FUNCTION;
  130.     }
  131.     else if ( bytesRecv == 0 )
  132.     {
  133.         retVal  =   E_SOCKET_PEER_CLOSED;
  134.         goto EXIT_FUNCTION;
  135.     }
  136.     // check reponse
  137.     if ( ::atoi(this->m_bufRecv) != 334 )
  138.     {
  139.         retVal  =   E_SOCKET_SERVER_HANDLE;
  140.         goto EXIT_FUNCTION;
  141.     }

  142.     // send password encoded by base64
  143.     lenSrc  =   (mInt32)( ::strlen(pPassword) );
  144.     EncodeBase64( this->m_bufRecv, pPassword, lenSrc );
  145.     retVal  =   this->SendReq( this->m_bufRecv, CalLenBase64(lenSrc) );
  146.     if ( retVal != E_SUCCESS )
  147.     {
  148.         goto EXIT_FUNCTION;
  149.     }
  150.     // get reponse
  151.     bytesRecv   =   this->RecvResp();
  152.     if ( bytesRecv < 0 )
  153.     {
  154.         retVal  =   bytesRecv;
  155.         goto EXIT_FUNCTION;
  156.     }
  157.     else if ( bytesRecv == 0 )
  158.     {
  159.         retVal  =   E_SOCKET_PEER_CLOSED;
  160.         goto EXIT_FUNCTION;
  161.     }
  162.     // check reponse
  163.     if ( ::atoi(this->m_bufRecv) != 235 )
  164.     {
  165.         retVal  =   E_SOCKET_SERVER_HANDLE;
  166.         goto EXIT_FUNCTION;
  167.     }

  168. EXIT_FUNCTION:
  169.     return E_SUCCESS;
  170. }

  171. mInt32 VSmtpServer::SendMailBegin( const char* pSender, const char* pRecivers )
  172. {
  173.     mInt32  retVal      =   E_SUCCESS;
  174.     mInt32  bytesRecv   =   0;

  175.     std::string strSender;
  176.     std::string strReceiver;

  177.     // send sender info
  178.     strSender.assign( "MAIL FROM: <" );
  179.     strSender.append( pSender );
  180.     strSender.append( ">" );
  181.     retVal  =   this->SendReq( strSender.c_str(), strSender.length() );
  182.     if ( retVal != E_SUCCESS )
  183.     {
  184.         goto EXIT_FUNCTION;
  185.     }
  186.     // get reponse
  187.     bytesRecv   =   this->RecvResp();
  188.     if ( bytesRecv < 0 )
  189.     {
  190.         retVal  =   bytesRecv;
  191.         goto EXIT_FUNCTION;
  192.     }
  193.     else if ( bytesRecv == 0 )
  194.     {
  195.         retVal  =   E_SOCKET_PEER_CLOSED;
  196.         goto EXIT_FUNCTION;
  197.     }
  198.     // check reponse
  199.     if ( ::atoi(this->m_bufRecv) != 250 )
  200.     {
  201.         retVal  =   E_SOCKET_SERVER_HANDLE;
  202.         goto EXIT_FUNCTION;
  203.     }

  204.     // send receivers info - TODO, list
  205.     strReceiver.assign( "RCPT TO: <" );
  206.     strReceiver.append( pRecivers );
  207.     strReceiver.append( ">" );
  208.     retVal  =   this->SendReq( strReceiver.c_str(), strReceiver.length() );
  209.     if ( retVal != E_SUCCESS )
  210.     {
  211.         goto EXIT_FUNCTION;
  212.     }
  213.     // get reponse
  214.     bytesRecv   =   this->RecvResp();
  215.     if ( bytesRecv < 0 )
  216.     {
  217.         retVal  =   bytesRecv;
  218.         goto EXIT_FUNCTION;
  219.     }
  220.     else if ( bytesRecv == 0 )
  221.     {
  222.         retVal  =   E_SOCKET_PEER_CLOSED;
  223.         goto EXIT_FUNCTION;
  224.     }
  225.     // check reponse
  226.     if ( ::atoi(this->m_bufRecv) != 250 )
  227.     {
  228.         retVal  =   E_SOCKET_SERVER_HANDLE;
  229.         goto EXIT_FUNCTION;
  230.     }

  231.     // send DATA command
  232.     retVal  =   this->SendReq( "DATA", ::strlen("DATA") );
  233.     if ( retVal != E_SUCCESS )
  234.     {
  235.         goto EXIT_FUNCTION;
  236.     }
  237.     // get reponse
  238.     bytesRecv   =   this->RecvResp();
  239.     if ( bytesRecv < 0 )
  240.     {
  241.         retVal  =   bytesRecv;
  242.         goto EXIT_FUNCTION;
  243.     }
  244.     else if ( bytesRecv == 0 )
  245.     {
  246.         retVal  =   E_SOCKET_PEER_CLOSED;
  247.         goto EXIT_FUNCTION;
  248.     }
  249.     // check reponse
  250.     if ( ::atoi(this->m_bufRecv) != 354 )
  251.     {
  252.         retVal  =   E_SOCKET_SERVER_HANDLE;
  253.         goto EXIT_FUNCTION;
  254.     }

  255. EXIT_FUNCTION:
  256.     return E_SUCCESS;
  257. }

  258. mInt32 VSmtpServer::SendMailData( const char* pData, mInt32 lenData )
  259. {
  260.     //TODO
  261.     mInt32  retVal  =   E_SUCCESS;

  262.     retVal  =   this->m_connector.Send( pData, lenData );
  263.     if ( retVal == E_SUCCESS )
  264.     {
  265.         std::string strData( pData, lenData );
  266.         std::cout << strData << std::endl;
  267.     }

  268.     return retVal;
  269. }

  270. mInt32 VSmtpServer::SendMailEnd()
  271. {
  272.     mInt32  retVal      =   E_SUCCESS;
  273.     mInt32  bytesRecv   =   0;

  274.     // send <CRLF>.<CRLF> - end of mail
  275.     this->m_bufRecv[0]  =   0xD;
  276.     this->m_bufRecv[1]  =   0xA;
  277.     this->m_bufRecv[2]  =   '.';
  278.     this->m_bufRecv[3]  =   0xD;
  279.     this->m_bufRecv[4]  =   0xA;
  280.     retVal  =   this->SendReq( this->m_bufRecv, 5 );
  281.     if ( retVal != E_SUCCESS )
  282.     {
  283.         goto EXIT_FUNCTION;
  284.     }

  285.     // get response
  286.     bytesRecv   =   this->RecvResp();
  287.     if ( bytesRecv < 0 )
  288.     {
  289.         retVal  =   bytesRecv;
  290.         goto EXIT_FUNCTION;
  291.     }
  292.     else if ( bytesRecv == 0 )
  293.     {
  294.         retVal  =   E_SOCKET_PEER_CLOSED;
  295.         goto EXIT_FUNCTION;
  296.     }

  297.     // check reponse
  298.     if ( ::atoi(this->m_bufRecv) != 250 )
  299.     {
  300.         retVal  =   E_SOCKET_SERVER_HANDLE;
  301.         goto EXIT_FUNCTION;
  302.     }

  303. EXIT_FUNCTION:
  304.     return retVal;
  305. }

  306. mInt32 VSmtpServer::Reset()
  307. {
  308.     mInt32  retVal      =   E_SUCCESS;
  309.     mInt32  bytesRecv   =   0;

  310.     // send RSET command
  311.     retVal  =   this->SendReq( "RSET", ::strlen("RSET") );
  312.     if ( retVal != E_SUCCESS )
  313.     {
  314.         goto EXIT_FUNCTION;
  315.     }
  316.     // get reponse
  317.     bytesRecv   =   this->RecvResp();
  318.     if ( bytesRecv < 0 )
  319.     {
  320.         retVal  =   bytesRecv;
  321.         goto EXIT_FUNCTION;
  322.     }
  323.     else if ( bytesRecv == 0 )
  324.     {
  325.         retVal  =   E_SOCKET_PEER_CLOSED;
  326.         goto EXIT_FUNCTION;
  327.     }
  328.     // check reponse
  329.     if ( ::atoi(this->m_bufRecv) != 250 )
  330.     {
  331.         retVal  =   E_SOCKET_SERVER_HANDLE;
  332.         goto EXIT_FUNCTION;
  333.     }

  334. EXIT_FUNCTION:
  335.     return retVal;
  336. }

  337. mInt32 VSmtpServer::SendReq( const char* pReq, mInt32 lenData )
  338. {
  339.     mInt32  retVal  =   E_SUCCESS;

  340.     ::memcpy( this->m_bufSend, pReq, lenData );
  341.     this->m_bufSend[lenData]    =   0xD;
  342.     this->m_bufSend[lenData+1]  =   0xA;
  343.     this->m_bufSend[lenData+2]  =   '\0';

  344.     retVal  =   this->m_connector.Send( this->m_bufSend, lenData + 2 );
  345.     if ( retVal != E_SUCCESS )
  346.     {
  347.         return retVal;
  348.     }

  349.     //TODO
  350.     std::cout << "C: " << this->m_bufSend << std::endl;

  351.     return  this->m_connector.Send( strCRLF, 2 );
  352. }

  353. mInt32 VSmtpServer::RecvResp()
  354. {
  355.     mInt32  retVal      =   0;
  356.     mInt32  bytesUnit   =   0;
  357.     mInt32  bytesRecv   =   0;

  358.     //TODO
  359.     std::string strRecv;

  360.     ::memset( this->m_bufRecv, 0, MMAIL_MAX_CMD_DATA_LEN );

  361.     // get response data
  362.     bytesUnit   =   this->m_connector.Recv( this->m_bufRecv, MMAIL_MAX_CMD_DATA_LEN );
  363.     if ( bytesUnit < 0 )
  364.     {
  365.         retVal  =   bytesUnit;
  366.         goto EXIT_FUNCTION;
  367.     }
  368.     else if ( bytesUnit == 0 )
  369.     {
  370.         retVal  =   E_SOCKET_PEER_CLOSED;
  371.         goto EXIT_FUNCTION;
  372.     }
  373.     bytesRecv   +=  bytesUnit;
  374.     while( bytesRecv < MMAIL_MAX_CMD_DATA_LEN )
  375.     {
  376.         if ( (bytesRecv > 2) && (this->m_bufRecv[bytesRecv - 2] == 0xD) && (this->m_bufRecv[bytesRecv - 1] == 0xA) )
  377.         {
  378.             break;
  379.         }

  380.         bytesUnit   =   this->m_connector.Recv( this->m_bufRecv + bytesRecv, MMAIL_MAX_CMD_DATA_LEN - bytesRecv );
  381.         if ( bytesUnit < 0 )
  382.         {
  383.             retVal  =   bytesUnit;
  384.             goto EXIT_FUNCTION;
  385.         }
  386.         else if ( bytesUnit == 0 )
  387.         {
  388.             retVal  =   E_SOCKET_PEER_CLOSED;
  389.             goto EXIT_FUNCTION;
  390.         }

  391.         bytesRecv   +=  bytesUnit;
  392.     }

  393.     //TODO
  394.     strRecv.assign( this->m_bufRecv, bytesRecv );
  395.     std::cout << "S: " << strRecv << std::endl;

  396.     retVal  =   bytesRecv;

  397. EXIT_FUNCTION:
  398.     return retVal;
  399. }
复制代码

调用代码,试着发RSET命令,没有成功

  1.         VSmtpServer serverSmtp;
  2.         retVal  =   serverSmtp.ConnectToServer( "smtp.163.com", 25 );
  3.         retVal  =   serverSmtp.Authenticate( pUserName, pPassword );

  4.         if ( retVal == E_SUCCESS )
  5.         {
  6.             retVal  |=  serverSmtp.Reset();
  7.             retVal  |=  serverSmtp.SendMailBegin( strSender.c_str(), strReceiver.c_str() );
  8.             //retVal  |=  serverSmtp.Reset();
  9.             //retVal  |=  serverSmtp.SendMailBegin( strSender.c_str(), strReceiver.c_str() );
  10.             retVal  |=  serverSmtp.SendReq( strMsgID.c_str(), strMsgID.length() );
  11.             retVal  |=  serverSmtp.SendReq( strMailer.c_str(), strMailer.length() );
  12.             retVal  |=  serverSmtp.SendReq( strMIME.c_str(), strMIME.length() );
  13.             retVal  |=  serverSmtp.SendReq( strMIMEType.c_str(), strMIMEType.length() );
  14.             retVal  |=  serverSmtp.SendReq( strDate.c_str(), strDate.length() );
  15.             retVal  |=  serverSmtp.SendReq( strSenderI.c_str(), strSenderI.length() );
  16.             retVal  |=  serverSmtp.SendReq( strReceiverI.c_str(), strReceiverI.length() );
  17.             retVal  |=  serverSmtp.SendReq( strSubject.c_str(), strSubject.length() );
  18.             retVal  |=  serverSmtp.SendMailData( strData.c_str(), strData.length() );
  19.             retVal  |=  serverSmtp.SendMailEnd();
  20.         }

  21.         retVal  =   serverSmtp.DisconnectFromServer();
  22.     }
复制代码

FIN包倒是没看到

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
14 [报告]
发表于 2007-01-18 17:10 |只看该作者
SMTP 指令里边有 RSET 这个指令吗.

论坛徽章:
0
15 [报告]
发表于 2007-01-19 12:35 |只看该作者
原帖由 cookis 于 2007-1-18 17:10 发表
SMTP 指令里边有 RSET 这个指令吗.

LS的去看看RFC2821吧
RSET是有的
如果是RFC821,那我就不知道了

论坛徽章:
0
16 [报告]
发表于 2007-01-21 22:59 |只看该作者
原帖由 星尘细雨 于 2007-1-17 14:11 发表
很可能是机器上装有有诺顿搞的。
诺顿有个anti_spam的东西。。

这几天一直在测试,都没通过
今天把诺顿的邮件监控关闭了,发送成功了
不过弱弱地问一下
大部分人的邮件监控都开着的,该如何解决?

[ 本帖最后由 zjzfb 于 2007-1-21 23:06 编辑 ]

论坛徽章:
0
17 [报告]
发表于 2007-01-21 23:15 |只看该作者
google搜索到RFC2505: Anti-Spam Recommendations for SMTP MTAs
以前还没注意过
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP