发信人: wenbobo(灌了拂衣去) 
整理人: wenbobo(2002-06-06 11:12:21), 站内信件
 | 
 
 
【 在 headspring 的大作中提到:】
 :像outlook和foxmail等等,都带有身份验证支持,我想实现它,请问它遵循什么标准呢?
 :......
 
 除了RFC,就是STD,平时多看看。这个是同事的日常练习程序,也不知道对不对,参考一下吧
 
 // atmosmail.cpp : Defines the entry point for the console application.
 //
 #pragma comment (lib,"wsock32.lib")
 
 #ifndef  CMD_RESPONSE_SIZE
 #define  CMD_RESPONSE_SIZE 1024
 #endif
 
 #ifndef  CMD_BLOCK_SIZE
 #define  CMD_BLOCK_SIZE 1024
 #endif
 
 #ifndef  m_dwCmdTimeout
 #define  m_dwCmdTimeout 60
 #endif 
 
 #ifndef  MAXPATH
 #define  MAXPATH 100
 #endif
 
 #include "stdafx.h"
 #include <winsock2.h>
 #include <stdio.h>
 #include <TCHAR.h>
 #include <String>
 
 SOCKET m_hSocket; 
 LPTSTR m_strResult;
 
 bool m_bExtensions=true;  // 默认情况下使用ESMTP协议
 
 unsigned int  m_LineWidth = 76;
 
 //Base64解码表
 const char BASE64_ENCODE_TABLE[64] = {
 	 65,  66,  67,  68,  69,  70,  71,  72,  // 00 - 07
 	 73,  74,  75,  76,  77,  78,  79,  80,  // 08 - 15
 	 81,  82,  83,  84,  85,  86,  87,  88,  // 16 - 23
 	 89,  90,  97,  98,  99, 100, 101, 102,  // 24 - 31
 	103, 104, 105, 106, 107, 108, 109, 110,  // 32 - 39
 	111, 112, 113, 114, 115, 116, 117, 118,  // 40 - 47
 	119, 120, 121, 122,  48,  49,  50,  51,  // 48 - 55
 	 52,  53,  54,  55,  56,  57,  43,  47 };// 56 - 63
 	
 	 ///////////////////////base64
 //获取Base64编码长度
 int Base64EncodeSize(int iSize)
 {
 	int nSize, nCR;
 	nSize = (iSize + 2) / 3 * 4 ;
 	nCR = nSize / m_LineWidth; //计算回车数量
 	nSize+= nCR * 2;
 	return nSize;
 }
 //////////////////////////////////////////////////////////
 int base64_encode(char *pSrc, unsigned int nSize, char *pDest)
 {
    /*
 
 	*  对一段Buffer进行Base64编码
 	*
 	*	 	pSrc	输入Buffer
 	*		nSize	Buffer长度
 	*		pDest	输出缓冲
 	*
 	*	 注: 输出Buffer的长度可以使用 Base64EncodeSize(int) 方法取得
     *
     *  return: base64编码后的字符串的长度
 
 	*/
 
 	if ((pSrc == NULL) || (nSize <= 0)) return 0;
 		
 	unsigned int iB, iInMax3, Len;
 	char *pInPtr, *pInLimitPtr;
 	char *OutPtr ;
 			
 	pInPtr = pSrc;
 	iInMax3 = (nSize / 3) * 3;
 	OutPtr = pDest;
 	pInLimitPtr = pInPtr + iInMax3;
 				
 	while (pInPtr != pInLimitPtr)
 	{
 		Len = 0;
 		while ((Len < m_LineWidth) && (pInPtr != pInLimitPtr))
 		{
 			iB = (unsigned char) *pInPtr++;
 			iB = iB << 8;
 				
 			iB = iB | (unsigned char) *pInPtr++;
 			iB = iB << 8;
 						
 			iB = iB | (unsigned char) *pInPtr++;
 						
 			//以4 byte倒序写入输出缓冲
 			OutPtr[3] = BASE64_ENCODE_TABLE[iB & 0x3F];
 			iB = iB >> 6;
 			OutPtr[2] = BASE64_ENCODE_TABLE[iB & 0x3F];
 			iB = iB >> 6;
 			OutPtr[1] = BASE64_ENCODE_TABLE[iB & 0x3F];
 			iB = iB >> 6;
 			OutPtr[0] = BASE64_ENCODE_TABLE[iB];
 			OutPtr+=4;
 			Len+=4;
 		}
 		if (Len >= m_LineWidth)
 		{
 			*OutPtr++ = '\r'; //加上回车换行符
 			*OutPtr++ = '\n';
 		}
 	}
 	//设置尾部
 	switch (nSize - iInMax3)
 	{
 		case 1:
 			iB = (unsigned char) *pInPtr;
 			iB = iB << 4;
 			OutPtr[1] = BASE64_ENCODE_TABLE[iB & 0x3F];
 			iB = iB >> 6;
 			OutPtr[0] = BASE64_ENCODE_TABLE[iB];
 			OutPtr[2] = '='; //用'='也就是64码填充剩余部分
 			OutPtr[3] = '=';
 			OutPtr+=4;
 			break;
 		case 2:
 			iB = (unsigned char) *pInPtr++;
 			iB = iB << 8;
 			iB = iB | (unsigned char) *pInPtr;
 			iB = iB << 2;
 			OutPtr[2] = BASE64_ENCODE_TABLE[iB & 0x3F];
 			iB = iB >> 6;
 			OutPtr[1] = BASE64_ENCODE_TABLE[iB & 0x3F];
 			iB = iB >> 6;
 			OutPtr[0] = BASE64_ENCODE_TABLE[iB];
 			OutPtr[3] = '='; // Fill remaining byte.
 			OutPtr+=4;
 			break;
 	}
 	return (unsigned int) (OutPtr - pDest);
 }
 /////////////////////////////////////////////////////////////
 // Send a command to the SMTP server and wait for a response
 //if success return the integer message of the smtp server
 //or failed return -1 
 int SendCmd(LPTSTR pszCmd)
 {
   FD_SET set;
   TIMEVAL tv;
   int nRet = 0;
   DWORD dwTick;
   CHAR szResult[CMD_RESPONSE_SIZE];
   LPSTR pszPos;
   LPSTR pszTok;
   DWORD dwPosition;
   DWORD dwLen;
   DWORD dwMax;
   BOOL bReportProgress = FALSE;
   LPSTR pszBuff;
   
   ZeroMemory(szResult,CMD_RESPONSE_SIZE);
   FD_ZERO(&set);
 
   // If we have a command to send, then send it.
   if (pszCmd)
   {  
      pszBuff = (LPSTR) malloc(lstrlen(pszCmd)+1);
 	 lstrcpyA(pszBuff,pszCmd);
 
     // Make sure the input buffer is clear before sending
     nRet = 1;
     while (nRet > 0)
     {
       FD_SET(m_hSocket,&set);
       tv.tv_sec = 0;
       tv.tv_usec = 0;
       nRet = select(1,&set,NULL,NULL,&tv);
       if (nRet == 1) nRet = recv(m_hSocket,szResult,CMD_RESPONSE_SIZE,0);
     }
 
     dwPosition = 0;
     dwLen = lstrlen(pszCmd);
 
     if (dwLen > CMD_BLOCK_SIZE) bReportProgress = TRUE;
 
     while (dwLen != dwPosition)
     {
       dwMax = min(CMD_BLOCK_SIZE,dwLen - dwPosition);
 	  printf("send char is %s\n",&pszBuff[dwPosition]);
       nRet = send(m_hSocket,&pszBuff[dwPosition],dwMax,0);
       if (nRet == SOCKET_ERROR)
       {
         free(pszBuff);
         return nRet;
       }
       dwPosition += dwMax;
       if (bReportProgress)
       {
        //
       }
     }
     // Wait for the CMD to finish being sent
     FD_ZERO(&set);
     FD_SET(m_hSocket,&set);
     nRet = select(1,NULL,&set,NULL,NULL);
     free(pszBuff);
   }
 
   // Prepare to receive a response
   ZeroMemory(szResult,CMD_RESPONSE_SIZE);
   pszPos = szResult;
   nRet=1;
   // Wait for the specified timeout for a full response string
   dwTick = GetTickCount();
   while ((GetTickCount() - dwTick) < (m_dwCmdTimeout * 1000))
   {
     FD_SET(m_hSocket,&set);
     
     tv.tv_sec = m_dwCmdTimeout - ((GetTickCount() - dwTick) / 1000);
     tv.tv_usec = 0;
 
     // Check the socket for readability
     nRet = select(1,&set,NULL,NULL,&tv);
     if (nRet == SOCKET_ERROR)
 	{  
 	   printf("error:read message from smtp server\n");
 	   break;
 	}
 
     // If the socket has data, read it.
     if (nRet == 1)
     {
       nRet = recv(m_hSocket,pszPos,CMD_RESPONSE_SIZE - (pszPos - szResult),0);
 	  printf("Message from smtp server:%s\n",pszPos);
       // Treats a graceful shutdown as an error
       if (nRet == 0) nRet = SOCKET_ERROR;
       if (nRet == SOCKET_ERROR) 
 	  {   
 		  printf("error:read Null message from smtp server\n");
 		  break;
 	  }
       
       // Add the data to the total response string & check for a LF
       pszPos += nRet;
       pszTok = strrchr(szResult,'\n');
       if (pszTok)
       {
         // Truncate CRLF combination and exit our wait loop
         pszTok --;
         pszTok[0] = 0;
         break;
       }
     }
   }
 
    // Assign the response string
      m_strResult = szResult;
 
   // Evaluate the numeric response code
   if (nRet && (nRet != SOCKET_ERROR))
   {
     szResult[3] = 0;
     nRet = atoi(szResult);
   }
   else nRet = -1;
 
   return nRet;
 }
 
 int	 SendAuthentication(LPSTR Auth,LPSTR PassWord)
 {   
     int length;
 	int nRet;
 	LPSTR pszBuff;
 	TCHAR szName[128];
     TCHAR szPassWord[128];
    
 	nRet=SendCmd("Auth Login\r\n");
 	if (nRet != 334)
 	{  
        printf("Auth Login failed\r\n");
        return nRet;
 	 }
 
 	length=lstrlen(Auth);
 	pszBuff = (LPSTR) malloc(Base64EncodeSize(length)+1);
 	pszBuff[Base64EncodeSize(length)]=0;
 	base64_encode(Auth, length, pszBuff);
 	printf("Auth=%s\r\n",Auth);
 	printf("Auth=%s\r\n",pszBuff);
 
     wsprintf(szName,(_T("%s\r\n")),pszBuff);
 
 	printf("%s\n",szName);
 	nRet=SendCmd(szName);
    //if (nRet != 235)
 	
     length=lstrlen(PassWord);
 	pszBuff = (LPSTR) malloc(Base64EncodeSize(length));
 	pszBuff[Base64EncodeSize(length)]=0;
 	base64_encode(PassWord, length, pszBuff);
 	printf("PassWrod=%s\r\n",PassWord);
 	printf("PassWrod=%s\r\n",pszBuff);
 	wsprintf(szPassWord,(_T("%s\r\n")),pszBuff);
 	printf("%s\n",szPassWord);
 	nRet=SendCmd(szPassWord);
 	
 
 	return 1;
 }
 
 // Initiate a conversation with the SMTP server
 // Returns 0 if successful, or a positive
 // error values if the SMTP server gave an error or failure response.
 int SendHelo()
 {
   int nRet = 0;
   TCHAR szName[32];
   TCHAR szMsg[39];
   DWORD dwSize = 32;
 	GetComputerName(szName,&dwSize);
 	printf("%s\n",szName);
     wsprintf(szMsg,(_T("EHLO %s\r\n")),szName);
 	printf("%s\n",szMsg);
 	if (m_bExtensions)
 	
 		nRet = SendCmd(szMsg);
 
 	if (nRet != 250)
 	{
 		szMsg[0] = 'H';
 		szMsg[1] = 'E';
 		nRet = SendCmd(szMsg);
 	}
      
 	if (nRet != 250)
 			return nRet;
 
 
 	
 	return 0;
 }
 
 // Send a MAIL FROM command to the server
 // Returns 0 if successful, or a positive
 // error value if the SMTP server gave an error or failure response.
 int SendFrom(LPTSTR pszFrom)
 {
   int nRet = 0;
   TCHAR szMsg[MAX_PATH];
 
   wsprintf(szMsg,_T("MAIL FROM:%s\r\n"),pszFrom);
   
   while (1)
   {
     nRet = SendCmd(szMsg);
 
     // Send authentication if required, and retry the command
     if (nRet == 530) nRet = SendAuthentication("xxxx\r\n","*******\r\n");
 
     else break;
   }
   // Raise an error if we failed
   if (nRet != 250) return nRet;
   return (nRet == 250) ? 0:nRet;
 }
 
 // Send a RCPT TO command to the server
 // Returns 0 if successful, or a positive
 // error value if the SMTP server gave an error or failure response.
 int SendTo(LPTSTR pszTo)
 {
   int nRet;
   TCHAR szMsg[MAX_PATH];
 
   wsprintf(szMsg,_T("RCPT TO:%s\r\n"),pszTo);
   
   nRet = SendCmd(szMsg);
   if (nRet != 250 && nRet != 251) return (nRet);
   return (nRet == 250 || nRet == 251) ? 0:nRet;
 }
 
 // Send the body of an e-mail message to the server
 // Returns 0 if successful, or a positive
 // error value if the SMTP server gave an error or failure response.
 int SendData(LPSTR Message)
 {
   int nRet;
 
   // Send the DATA command.  We need a 354 to proceed
   nRet = SendCmd(_T("DATA\r\n"));
   if (nRet != 354)
   {
     return nRet;
   }
   // Parse the body of the email message
   // Send the body and expect a 250 OK reply.
   nRet = SendCmd(Message);
   if (nRet != 250)  return(nRet);
   
   return (nRet == 250) ? 0:nRet;
 }
 
 // Tell the SMTP server we're quitting
 // Returns 0 if successful, or a positive
 // error value if the SMTP server gave an error or failure response.
 int SendQuitCmd()
 {
 
   int nRet;
 
  // if (!m_bConnected) return 0;
 
   nRet = SendCmd(_T("QUIT\r\n"));
 
   if (nRet != 221) return (nRet);
 
   return (nRet == 221) ? 0:nRet;
 }
 
 
 
 
 ////////////////////////////////////////////////////////////////////////////
 ///////////////////////////////MAIN( )//////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////////
 
 void main(int argc,char *argv[])
 {
 	struct sockaddr_in server_addr; 
 	struct hostent *hp; 
     int nRet;
 	WORD wVersionRequested;
 	WSADATA wsaData;
 
 	int err;
    	if (argc < 2)
 	{
 		printf("Usage is error!\n");
 		printf("Right usage:\n");
 		printf("Exmaple:  client 10.38.0.119  25\n");
 		printf("OR: client smtp-ent.21cn.com  25\n");
 		return;
 	}
 
 	wVersionRequested=MAKEWORD(1,1);
 
 	err=WSAStartup(wVersionRequested, &wsaData);
 	if (err!=0)
 	{
 		perror("there is no DLL to use");
 		return;
 	}
 
 
 	if ( (LOBYTE(wsaData.wVersion)!=1) || (HIBYTE(wsaData.wVersion)!=1) )
 	{
 		perror("there is not right DLL");
 		WSACleanup();
 		return;
 	}
 
 	m_hSocket=socket(AF_INET,SOCK_STREAM,0);
     if (m_hSocket<0)
 	{
 		perror("there is error in opening stream socket!");
 	    return;
 	}
    	
 
 	server_addr.sin_family=AF_INET;
     hp=gethostbyname(argv[1]);
 	if(hp==0)
 	{   
 	perror("cannot find hostname\n"); 
        return;
 	}
 
 	memcpy((char *)&server_addr.sin_addr,(char *)hp->h_addr,hp->h_length);
 	server_addr.sin_port=htons((unsigned short)atoi(argv[2]));
 	
 	//Before send data,listenning
      
 	//进行连接
 	if(connect(m_hSocket,(struct sockaddr*)&server_addr,sizeof(server_addr))<0)
 	{
 		perror("there is error in connecting stream socket");
 		return;
 	}
   
 	nRet  = SendCmd(NULL);
 	if (nRet != 220)
 	{
 	//关闭socket
 	closesocket(m_hSocket);
 	WSACleanup();
     return;
 	}
 	printf("220\n");
 
 	if (SendHelo())
 	{ 
 	//关闭socket
 	closesocket(m_hSocket);
 	WSACleanup();
     return;
 	}
 
     getchar();
 	SendAuthentication("[email protected]","*****");
     getchar();
 
 	if (SendFrom("[email protected]"))
 	{ 
 	//关闭socket
 	closesocket(m_hSocket);
 	WSACleanup();
     return;
 	}
 
 	getchar();
 	if (SendTo("[email protected]"))
 	{ 
 	//关闭socket
 	closesocket(m_hSocket);
 	WSACleanup();
     return;
 	}
 
 	getchar();
 	if (SendData("Subject: test \r\n\r\nthis is a test\r\nhyx\r\n.\r\n"))
 	{ 
 	//关闭socket
 	closesocket(m_hSocket);
 	WSACleanup();
     return;
 	}
 
 	getchar();
 	if (SendQuitCmd())
 	{ 
 	//关闭socket
 	closesocket(m_hSocket);
 	WSACleanup();
     return;
 	}
 
 	printf("send is ok\n");
 	//关闭socket
 	closesocket(m_hSocket);
 	WSACleanup();
     return;
 }
 
 
  ---- ◢█◣◢█◣
 ◤◥◢█◤◥
 ◣◢█◤◣◢
 ◥█◤◥█◤   | 
 
 
 |