- 论坛徽章:
- 1
|
- #include "SendMail.h"
- CSendMail::CSendMail ()
- :m_bConnected (false),
- m_socket (-1),
- m_nPort (25)
- {
- m_sendTimeout.tv_sec = 3;
- m_sendTimeout.tv_usec = 0;
- }
- CSendMail::~CSendMail ()
- {
- m_bConnected = false;
- close (m_socket);
- }
- //-------------------------------------member function--------------------------------------
- //return -1: get host by name error
- //return -2: open socket error
- //return -3: connect error
- int CSendMail::ConnectTo (const char *sHost)
- {
- if (sHost == NULL || m_nPort < 0)
- return -1;
- struct sockaddr_in client;
- struct hostent *hp;
- bzero ((char*)&client, sizeof (client));
- if (isdigit (sHost[0]) && isdigit (sHost[1])) //192.169.5.132
- {
- client.sin_family = AF_INET;
- client.sin_addr.s_addr = inet_addr (sHost);
- client.sin_port = htons (m_nPort);
- }else //www.google.com
- {
- if ((hp = gethostbyname (sHost)) == NULL)
- {
- #ifdef IP_DEBUG
- print_bug (gethostbyname failed!);
- perror("gethostbyname");
- #endif
- m_socket = INVALID_SOCKET;
- return -1; //
- }
- bcopy (hp->h_addr, (char *)&client.sin_addr, hp->h_length);
- client.sin_family = hp->h_addrtype;
- client.sin_port = htons (m_nPort);
- }
- m_socket = socket (AF_INET, SOCK_STREAM, 0);
- if (m_socket <= 0)
- {
- #ifdef IP_DEBUG
- perror("socket");
- #endif
- return -2;
- }
- const int on = 1;
- setsockopt (m_socket, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on));
- if (connect (m_socket, (struct sockaddr *)&client, sizeof (client)) < 0)
- {
- #ifdef IP_DEBUG
- perror ("connect");
- #endif
- close (m_socket);
- return -3;
- }
- if (CheckResponseCode (CONNECTION_CHECK) != 0)
- {
- DisConnect ();
- return -1;
- }
- m_bConnected = true;
- return 0;
- }
- //send RCPT TO
- void CSendMail::SetFromAndTo (const std::string &sFrom, const std::string &sTo)
- {
- std::string tmp;
- m_sFrom = sFrom;
- //
- char *buff = new char[sTo.length () + 1];
- strcpy (buff, sTo.c_str ());
- buff[sTo.length ()] = '\0';
- char *pTok = strtok (buff, ", ");
- m_vTo.push_back (std::string (pTok));
- while ((pTok = strtok (NULL, ", ")))
- {
- m_vTo.push_back (std::string (pTok));
- }
- delete []buff;
- }
- //
- void CSendMail::SetUsernameAndPasswd (const std::string &username, const std::string &passwd)
- {
- m_userName = username;
- m_passwd = passwd;
- char buff[64] = {0};
- int ret = EncodingBase64 (m_userName.c_str(), buff, m_userName.length ());
- m_encodeName.assign (buff, ret);
- memset (buff, 0, 64);
- ret = EncodingBase64 (m_passwd.c_str (), buff, m_passwd.length ());
- m_encodePasswd.assign (buff, ret);
- }
- //send DATA
- void CSendMail::SetSubject (const std::string &subject)
- {
- m_sSubject = subject;
- }
- void CSendMail::SetSenderName (const std::string &senderName)
- {
- m_senderName = senderName;
- }
- void CSendMail::SetCC (const std::string &cc)
- {
- char *buff = new char[cc.length () + 1];
- strcpy (buff, cc.c_str ());
- buff[cc.length ()] = '\0';
- char *pTok = strtok (buff, ", ");
- m_vCC.push_back (std::string (pTok));
- while ((pTok = strtok (NULL, ", ")))
- {
- m_vCC.push_back (std::string (pTok));
- }
- delete []buff;
- }
- void CSendMail::SetBCC (const std::string &bcc)
- {
- char *buff = new char[bcc.length () + 1];
- strcpy (buff, bcc.c_str ());
- buff[bcc.length ()] = '\0';
- char *pTok = strtok (buff, ", ");
- m_vBCC.push_back (std::string (pTok));
- while ((pTok = strtok (NULL, ", ")))
- {
- m_vBCC.push_back (std::string (pTok));
- }
- delete []buff;
- }
- std::string CSendMail::GetAttachType (std::string &filename)
- {
- return std::string ("application/octet-stream");
- }
- //
- int CSendMail::SendAuth ()
- {
- char buff[128] = {0};
- snprintf (buff, 127, "AUTH LOGIN\r\n");
- if (SendCtrlMsg (buff) != 0)
- return -1;
- if (CheckResponseCode (AUTH_START_CHECK) != 0) // 334
- return -1;
- std::string tmp (m_encodeName);
- tmp.append ("\r\n");
- if (SendCtrlMsg (tmp) != 0)
- return -1;
- if (CheckResponseCode (AUTH_START_CHECK) != 0) //334
- return -1;
- tmp.assign (m_encodePasswd);
- tmp.append ("\r\n");
- if (SendCtrlMsg (tmp) != 0)
- return -1;
- if (CheckResponseCode (AUTH_CHECK) != 0) //235 succ
- return -1;
- return 0;
- }
- //send header
- int CSendMail::SendHead ()
- {
- std::string head;
- char stime[128] = {0};
- time_t tt = time (NULL);
- struct tm *ttm = localtime (&tt);
- strftime (stime, 127, "%a, %d %b %Y %H:%M:%S %z\r\n", ttm);
- //add Date
- head.append ("Date: ");
- head.append (stime);
- //add From
- if (m_senderName.empty ())
- m_senderName = m_sFrom.substr (0, m_sFrom.find ('@'));
- head += std::string ("From: \"") + m_senderName + "\"" + "<" + m_sFrom + ">" + "\r\n";
- //add To
- std::vector<std::string>::iterator pos;
- head += "To:";
- for (pos = m_vTo.begin (); pos != m_vTo.end (); ++pos)
- {
- std::string to = pos->substr (0, pos->find ('@'));
- head += std::string (" \"") + to + "\"" + "<" + *pos + ">" + "\r\n";
- }
- //add CC
- if (!m_vCC.empty ())
- {
- head += "Cc:";
- for (pos = m_vCC.begin (); pos != m_vCC.end (); ++pos)
- {
- std::string to = pos->substr (0, pos->find ('@'));
- head += std::string (" \"") + to + "\"" + "<" + *pos + ">" + "\r\n";
- }
- }
- //add BCC
- if (!m_vBCC.empty ())
- {
- head += "Bcc:";
- for (pos = m_vBCC.begin (); pos != m_vBCC.end (); ++pos)
- {
- std::string to = pos->substr (0, pos->find ('@'));
- head += std::string (" \"") + to + "\"" + "<" + *pos + ">" + "\r\n";
- }
- }
- //add subject
- head += std::string ("Subject: ") + m_sSubject + "\r\n";
- //add MessageID
- memset (stime, 0, 128);
- long lTime = (long)(time (NULL));
- std::string prefix = m_sFrom.substr (m_sFrom.find ('@'));
- snprintf (stime, 128, "Message-ID: <%ld%s>\r\n", lTime, prefix.c_str ());
- head += stime;
- //add X-mailer
- head += "X-mailer: HXHT-cuishaowei (mail:shaovie@gmail.com)\r\n";
- //add mime version
- head += "Mime-version: 1.0\r\n";
- m_majorSplitTag = "====MajorSplitTag====";
- if (!m_vAttachment.empty ()) //having attachment
- {
- m_nMailType = MAIL_TEXT_ATTACHMENT;
- head += std::string ("Content-Type: multipart/mixed;\r\n\tboundary=\"") + m_majorSplitTag + "\"\r\n";;
- }else //pure text mail, no attachment
- {
- m_nMailType = MAIL_PURE_TEXT;
- head += "Content-Type: text/plain;\r\n\tcharset=\"gb2312\"\r\n";
- head += "Content-Transfer-Encoding: base64\r\n";
- //head += "Content-Transfer-Encoding: 7bit\r\n";
- }
- m_majorSplitTag = std::string ("--") + m_majorSplitTag + "\r\n";
- head += "\r\n"; //mustn't lost
- int ret = SendCtrlMsg (head);
- return ret;
- }
- //
- int CSendMail::SendBodyPureText (const std::string &encodeText)
- {
- std::string text;
- text.assign (encodeText);
- text.append ("\r\n");
- text.append ("\r\n.\r\n");
- SendCtrlMsg (text);
- return CheckResponseCode (DATA_END_CHECK);
- }
- int CSendMail::SendBodyHtmlOnly (const std::string &encodeText, const std::string &encodeHtml,
- const std::string &splitTag)
- {
- std::string data;
- data.append ("This is a multi-part message in MIME format.\r\n");
- data.append ("\r\n");
- data.append (splitTag);
- data.append ("Content-Type: text/plain;\r\n\tcharset=\"gb2312\"\r\n");
- data.append ("Content-Transfer-Encoding: 7bit\r\n");
- data.append ("\r\n");
- data.append (encodeText);
- data.append ("\r\n");
- data.append (splitTag);
- data.append ("Content-Type: text/html;\r\n\tcharset=\"gb2312\"\r\n");
- data.append ("Content-Transfer-Encoding: 7bit\r\n");
- data.append ("\r\n");
- data.append (encodeHtml);
- data.append ("\r\n");
- data.append (splitTag);
- data.append ("\r\n.\r\n");
- SendCtrlMsg (data);
- return CheckResponseCode (DATA_END_CHECK);
- }
- int CSendMail::SendBodyTextAndAttachMent (const std::string &encodeText,
- const std::string &majorSplitTag)
- {
- std::string data;
- data.append ("This is a multi-part message in MIME format.\r\n");
- data.append ("\r\n");
- data.append (majorSplitTag);
- data.append ("Content-Type: text/plain;\r\n\tcharset=\"gb2312\"\r\n");
- data.append ("Content-Transfer-Encoding: base64\r\n");
- data.append ("\r\n");
- data.append (encodeText);
- data.append ("\r\n");
- SendCtrlMsg (data);
- SendAttachment (majorSplitTag);
- return CheckResponseCode (DATA_END_CHECK);;
- }
- int CSendMail::SendBodyTextAndHtmlAndAttachMent (const std::string &encodeText,
- const std::string &encodeHtml,
- const std::string &majorSplitTag,
- const std::string &subSplitTag)
- {
- std::string data;
- data.append ("This is a multi-part message in MIME format.\r\n");
- data.append ("\r\n");
- data.append (majorSplitTag);
- data.append ("Content-Type: multipart/alternative;\r\n\tboundary=\"");
- data.append (subSplitTag);
- data.append ("\"\r\n");
- data.append ("\r\n");
- std::string sub = "--" + subSplitTag + "\r\n";
- data.append (sub);
- data.append ("Content-Type: text/plain;\r\n\tcharset=\"gb2312\"\r\n");
- data.append ("Content-Transfer-Encoding: base64\r\n");
- data.append ("\r\n");
- data.append (encodeText);
- data.append ("\r\n");
- SendCtrlMsg (data);
- SendAttachment (sub);
- return CheckResponseCode (DATA_END_CHECK);
- }
- //只是发送附近数据段部分,包括最后的分隔符
- int CSendMail::SendAttachment (const std::string &splitTag)
- {
- std::vector<std::string>::iterator pos;
- std::string data;
- std::string name;
- data.reserve (256);
- for (pos = m_vAttachment.begin (); pos != m_vAttachment.end (); ++pos)
- {
- data.assign (splitTag);
- data.append ("Content-Type: ");
- data.append (GetAttachType (*pos));
- data.append (";\r\n\tname=\"=?gb2312?B?");
- int nP = pos->find ('/');
- if ( nP != std::string::npos)
- nP += 1;
- else
- nP = 0;
- name = pos->substr (nP);
- char *buff = new char[name.length () * 2];
- int ret = EncodingBase64 (name.c_str (), buff, name.length ());
- data.append (buff, ret);
- data.append ("?=\"\r\n");
- data.append ("Content-Transfer-Encoding: base64\r\n");
- data.append ("Content-Disposition: attachment;\r\n\t");
- data.append ("filename=\"=?gb2312?B?");
- data.append (buff, ret);
- delete []buff;
- buff = NULL;
- data.append ("?=\"\r\n");
- data.append ("\r\n");
- SendCtrlMsg (data);
- //start read attachment
- int fd = open (pos->c_str (), O_RDONLY);
- if (fd < 0)
- {
- #ifdef IP_DEBUG
- print_info_n (attachment file can not open);
- #endif
- SendCtrlMsg (std::string ("\r\n"));
- continue;
- }
- char fileBuff[76];
- char base64buff[150] = {0}; // 4096 > 2048 : base64Buff'len must longer 1/3times than buff
- std::string streamBuff;
- streamBuff.reserve (4096 + 76);
- while ((ret = read (fd, fileBuff, 76)) > 0)
- {
- int n = EncodingBase64 (fileBuff, base64buff, ret);
- streamBuff.append (base64buff, n);
- streamBuff.append ("\r\n");
- if (streamBuff.length () < 4096 && ret >= 76)
- continue;
- SendCtrlMsg (streamBuff);
- streamBuff.assign ("");
- }
- close (fd);
- SendCtrlMsg (std::string ("\r\n"));
- }
- data.assign (m_majorSplitTag);
- data.append ("\r\n.\r\n");
- return SendCtrlMsg (data);
- }
- //
- int CSendMail::SendMail (const std::string &msg, std::string attachment, std::string html)
- {
- if (!attachment.empty ())
- {
- char buf[512] = {0};
- strncpy (buf, attachment.c_str (), 511);
- char *pTok = strtok (buf, ", ");
- m_vAttachment.push_back (std::string (pTok));
- while ((pTok = strtok (NULL, ", ")))
- m_vAttachment.push_back (std::string (pTok));
- }
- char buff[128] = {0};
- int ret;
- char *pText = NULL;
- std::string encodeText;
- std::string encodeHtml;
- std::vector<std::string>::iterator pos;
- // 1. send ehlo
- snprintf (buff, 128, "EHLO %s\r\n", m_sFrom.substr (m_sFrom.find ('@') + 1).c_str ());
- if (SendCtrlMsg (buff) != 0)
- return -1;
- if (CheckResponseCode (HELLO_CHECK) != 0)
- goto END;
- // 2. auth
- if (SendAuth () != 0)
- goto END;
- // 3. send Mail
- memset (buff, 0, 128);
- snprintf (buff, 127, "MAIL From:<%s>\r\n", m_sFrom.c_str ());
- if (SendCtrlMsg (buff) != 0)
- return -1;
- if (CheckResponseCode (MAIL_CHECK) != 0)
- goto END;
- //4. send to
- for (pos = m_vTo.begin (); pos != m_vTo.end (); ++pos)
- {
- memset (buff, 0, 128);
- snprintf (buff, 127, "RCPT TO:<%s>\r\n", pos->c_str ());
- if (SendCtrlMsg (buff) != 0)
- goto END;
- if (CheckResponseCode (RCPT_CHECK) != 0)
- goto END;
- }
- //5. send Data
- memset (buff, 0, 128);
- snprintf (buff, 127, "DATA\r\n");
- if (SendCtrlMsg (buff) != 0)
- goto END;
- if (CheckResponseCode (DATA_START_CHECK) != 0)
- goto END;
- //6. send head info
- if (SendHead () != 0)
- goto END;
- //7. send body
- pText = new char[msg.length () * 2];
- ret = EncodingBase64 (msg.c_str (), pText, msg.length ());
- encodeText.assign (pText, ret);
- delete []pText;
- if (!html.empty ())
- {
- pText = new char[html.length () * 2];
- ret = EncodingBase64 (html.c_str (), pText, html.length ());
- encodeHtml.assign (pText, ret);
- delete []pText;
- }
- switch (m_nMailType)
- {
- case MAIL_PURE_TEXT:
- SendBodyPureText (encodeText);
- break;
- case MAIL_TEXT_ATTACHMENT:
- SendBodyTextAndAttachMent (encodeText, m_majorSplitTag);
- break;
- case MAIL_TEXT_HTML_ATTACH:
- SendBodyTextAndHtmlAndAttachMent (encodeText, encodeHtml, m_majorSplitTag, m_subSplitTag);
- break;
- default:
- break;
- }
- memset (buff, 0, 128);
- strncpy (buff, "QUIT\r\n", 127);
- if (SendCtrlMsg (buff) != 0)
- goto END;
- if (CheckResponseCode (QUIT_CHECK) != 0)
- goto END;
- return 0;
- END:
- DisConnect ();
- return -1;
- }
- int CSendMail::SendCtrlMsg (const std::string &msg)
- {
-
- fd_set writeFds;
- FD_ZERO (&writeFds);
- FD_SET (m_socket, &writeFds);
-
- if (m_bConnected && (m_socket > 0))
- {
- while (true)
- {
- if (select (m_socket + 1, NULL, &writeFds, NULL, &m_sendTimeout) > 0)
- {
- //if (FD_ISSET (m_socket, &writeFds))
- if (send (m_socket, msg.c_str (), msg.length (), 0) > 0)
- break;
- else return -1;
- }else
- {
- #ifdef IP_DEBUG
- print_info_n ([Mail] send msg timeout or error);
- #endif
- }
- }
- }else
- return -1;
- return 0;
- }
- //
- int CSendMail::CheckResponseCode (int type)
- {
- char buff[1024] = {0};
- if (recv (m_socket, buff, 1023, 0) <= 0)
- return -1;
- char temp[3] = {0};
-
- strncpy (temp, buff, 3);
- int nRetCode = atoi (temp);
- switch (type)
- {
- case CONNECTION_CHECK:
- if (nRetCode != 220) // 220 服务就绪
- goto END;
- break;
-
- case HELLO_CHECK:
- if (nRetCode != 250) // 请求邮件动作正确,完成(EHLO,MAIL FROM,RCPT TO,QUIT指令执行成功会返回此信息)
- goto END;
- break;
- case MAIL_CHECK:
- if (nRetCode != 250)
- goto END;
- break;
- case RCPT_CHECK:
- if (nRetCode != 250)
- goto END;
- break;
- case AUTH_CHECK:
- if (nRetCode != 235)
- goto END;
- break;
- case AUTH_START_CHECK:
- if (nRetCode != 334)
- goto END;
- break;
- case DATA_START_CHECK:
- if (nRetCode != 354) // 354 开始发送数据,结束以 .(DATA指令执行成功会返回此信息,客户端应发送信息)
- goto END;
- break;
- case DATA_END_CHECK:
- if (nRetCode != 250)
- goto END;
- break;
- case QUIT_CHECK:
- if (nRetCode != 221) // 221 正在处理 250 queued
- goto END;
- break;
- case DATA_CHECK:
- if (nRetCode != 354)
- goto END;
- break;
- default:
- return -1;
- break;
- }
- return 0;
- END:
- #ifdef IP_DEBUG
- print_info ();
- printf ("%s\n", buff);
- #endif
- return nRetCode;
- }
- //
- int CSendMail::DisConnect ()
- {
- m_bConnected = false;
- return close (m_socket);
- }
- int CSendMail::EncodingBase64 (const char* src, char* des, int srcLen)
- {
- assert (src && des);
- char *pdes = des;
- const char *psrc = src;
- int len = 0;
- int i = 0;
- char sixbit_encoding[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
- while ((src - psrc) < srcLen)//(*src != NULL)
- {
- *des++ = sixbit_encoding[(unsigned char)*src++ >> 2]; //6
- if ((src - psrc) == srcLen) //(*src == NULL)
- {
- *des++ = sixbit_encoding[(*(src - 1) & 0x3) << 4];//2+4
- *des++ = '=';
- *des++ = '=';
- break;
- }
- else
- {
- *des++ = sixbit_encoding[(*(src - 1) & 0x3) << 4 | (unsigned char)(*src) >> 4];//2+4
- src++;
- }
- if ((src - psrc) == srcLen) //(*src == NULL)
- {
- *des++ = sixbit_encoding[(*(src - 1) & 0xF) << 2];//4+2
- *des++ = '=';
- }
- else
- {
- *des++ = sixbit_encoding[(*(src - 1) & 0xF) << 2 | (unsigned char)(*src) >> 6];//4+2
- *des++ = sixbit_encoding[*src & 0x3F];//6
- src++;
- }
- }
- //*des = '\0';
- len = des - pdes;
- return len;
- }
- int main ()
- {
- CSendMail cui;
- cui.ConnectTo ("mail.megaeyes.com");
- cui.SetFromAndTo ("xxxxx@megaeyes.com", "xxxxx@sina.com.cn");
- cui.SetSubject ("test");
- cui.SetUsernameAndPasswd ("xxxx@megaeyes.com", "xxxx");
- cui.SetSenderName ("hello");
- cui.SendMail ("hello world!", "error.JPG");
- }
复制代码
这里我只给出了.cpp的东西..
我抓到的Foxmail包就没有RST.不过间倒有FIN位的包,
首先Foxmail会发送Helo通知服务器建立链接,但现在一般的服务器都有验证的过程..但这种链接方式没有验证过程,所以服务器拒绝..然后客户端重新用EHLO 建立链接, 然后发送验证信息,
你看你抓的包.RST之前肯定有一个FIN的包..然后你再发送数据,服务器端的TCP会返回一个RST位..
肯定有些地方数据格式不对.
这也仅是我的个人见解,,如有哪位高手熟悉SMTP 可以指点一下.. |
|