SMTP.cpp
上传用户:xmpantheon
上传日期:2016-10-20
资源大小:7502k
文件大小:7k
源码类别:

Email服务器

开发平台:

Visual C++

  1. // SMTP.cpp: implementation of the CSMTP class.
  2. // Copyright (c) 1998, Wes Clyburn
  3. //////////////////////////////////////////////////////////////////////
  4. #include "stdafx.h"
  5. #include "SMTP.h"
  6. #ifdef _DEBUG
  7. #undef THIS_FILE
  8. static char THIS_FILE[]=__FILE__;
  9. #define new DEBUG_NEW
  10. #endif
  11. // Static member initializers
  12. //
  13. // Note: the order of the entries is important.
  14. //       They must be synchronized with eResponse entries. 
  15. CSMTP::response_code CSMTP::response_table[] =
  16. {
  17. // GENERIC_SUCCESS
  18. { 250, _T( "SMTP server error" ) },
  19. // CONNECT_SUCCESS
  20. { 220, _T( "SMTP server not available" ) },
  21. // DATA_SUCCESS
  22. { 354, _T( "SMTP server not ready for data" ) },
  23. // QUIT_SUCCESS
  24. { 221, _T( "SMTP server didn't terminate session" ) }
  25. };
  26. //////////////////////////////////////////////////////////////////////
  27. // Construction/Destruction
  28. //////////////////////////////////////////////////////////////////////
  29. CSMTP::CSMTP( LPCTSTR szSMTPServerName, UINT nPort )
  30. {
  31. ASSERT( szSMTPServerName != NULL );
  32. AfxSocketInit();
  33. m_sSMTPServerHostName = szSMTPServerName;
  34. m_nPort = nPort;
  35. m_bConnected = FALSE;
  36. m_sError = _T( "OK" );
  37. response_buf = NULL;
  38. }
  39. CSMTP::~CSMTP()
  40. {
  41. Disconnect();
  42. }
  43. CString CSMTP::GetServerHostName()
  44. {
  45. return m_sSMTPServerHostName;
  46. }
  47. BOOL CSMTP::Connect()
  48. {
  49. CString sHello;
  50. TCHAR local_host[ 80 ]; // Warning: arbitrary size
  51. if( m_bConnected )
  52. return TRUE;
  53. try
  54. {
  55. // This will be deleted in Disconnect();
  56. response_buf = new TCHAR[ RESPONSE_BUFFER_SIZE ];
  57. // I can't count on all class users' applications
  58. // to have exception-throwing operator-new implementations,
  59. // so I'll soul-kiss the ones that don't.
  60. if( response_buf == NULL )
  61. {
  62. m_sError = _T( "Not enough memory" );
  63. return FALSE;
  64. }
  65. }
  66. catch( CException *e )
  67. {
  68. response_buf = NULL;
  69. m_sError = _T( "Not enough memory" );
  70. delete e;
  71. return FALSE;
  72. }
  73. if( !m_wsSMTPServer.Create() )
  74. {
  75. m_sError = _T( "Unable to create the socket." );
  76. delete response_buf;
  77. response_buf = NULL;
  78. return FALSE;
  79. }
  80. if( !m_wsSMTPServer.Connect( GetServerHostName(), GetPort() ) )
  81. {
  82. m_sError = _T( "Unable to connect to server" );
  83. m_wsSMTPServer.Close();
  84. delete response_buf;
  85. response_buf = NULL;
  86. return FALSE;
  87. }
  88. if( !get_response( CONNECT_SUCCESS ) )
  89. {
  90. m_sError = _T( "Server didn't respond." );
  91. m_wsSMTPServer.Close();
  92. delete response_buf;
  93. response_buf = NULL;
  94. return FALSE;
  95. }
  96. gethostname( local_host, 80 );
  97. sHello.Format( _T( "HELO %srn" ), local_host );
  98. m_wsSMTPServer.Send( (LPCTSTR)sHello, sHello.GetLength() );
  99. if( !get_response( GENERIC_SUCCESS ) )
  100. {
  101. m_wsSMTPServer.Close();
  102. delete response_buf;
  103. response_buf = NULL;
  104. return FALSE;
  105. }
  106. m_bConnected = TRUE;
  107. return TRUE;
  108. }
  109. BOOL CSMTP::Disconnect()
  110. {
  111. BOOL ret;
  112. if( !m_bConnected )
  113. return TRUE;
  114. // Disconnect gracefully from the server and close the socket
  115. CString sQuit = _T( "QUITrn" );
  116. m_wsSMTPServer.Send( (LPCTSTR)sQuit, sQuit.GetLength() );
  117. // No need to check return value here.
  118. // If it fails, the message is available with GetLastError
  119. ret = get_response( QUIT_SUCCESS );
  120. m_wsSMTPServer.Close();
  121. if( response_buf != NULL )
  122. {
  123. delete[] response_buf;
  124. response_buf = NULL;
  125. }
  126. m_bConnected = FALSE;
  127. return ret;
  128. }
  129. UINT CSMTP::GetPort()
  130. {
  131. return m_nPort;
  132. }
  133. CString CSMTP::GetLastError()
  134. {
  135. return m_sError;
  136. }
  137. BOOL CSMTP::SendMessage(CMailMessage * msg)
  138. {
  139. ASSERT( msg != NULL );
  140. if( !m_bConnected )
  141. {
  142. m_sError = _T( "Must be connected" );
  143. return FALSE;
  144. }
  145. if( FormatMailMessage( msg ) == FALSE )
  146. {
  147. return FALSE;
  148. }
  149. if( transmit_message( msg ) == FALSE )
  150. {
  151. return FALSE;
  152. }
  153. return TRUE;
  154. }
  155. BOOL CSMTP::FormatMailMessage( CMailMessage* msg )
  156. {
  157. ASSERT( msg != NULL );
  158. if( msg->GetNumRecipients() == 0 )
  159. {
  160. m_sError = _T( "No Recipients" );
  161. return FALSE;
  162. }
  163. msg->FormatMessage();
  164. return TRUE;
  165. }
  166. void CSMTP::SetServerProperties( LPCTSTR szSMTPServerName, UINT nPort)
  167. {
  168. ASSERT( szSMTPServerName != NULL );
  169. // Needs to be safe in non-debug too
  170. if( szSMTPServerName == NULL )
  171. return;
  172. m_sSMTPServerHostName = szSMTPServerName;
  173. m_nPort = nPort;
  174. }
  175. CString CSMTP::cook_body(CMailMessage * msg)
  176. {
  177. ASSERT( msg != NULL );
  178. CString sTemp;
  179. CString sCooked = _T( "" );
  180. LPTSTR szBad = _T( "rn.rn" );
  181. LPTSTR szGood = _T( "rn..rn" );
  182. int nPos;
  183. int nStart = 0;
  184. int nBadLength = strlen( szBad );
  185. sTemp = msg->m_sBody;
  186. if( sTemp.Left( 3 ) == _T( ".rn" ) )
  187. sTemp = _T( "." ) + sTemp;
  188. //
  189. // This is a little inefficient because it beings a search
  190. // at the beginning of the string each time. This was
  191. // the only thing I could think of that handled ALL variations.
  192. // In particular, the sequence "rn.rn.rn" is troublesome. 
  193. // (Even CStringEx's FindReplace wouldn't handle that situation
  194. // with the global flag set.)
  195. //
  196. while( (nPos = sTemp.Find( szBad )) > -1 )
  197. {
  198. sCooked = sTemp.Mid( nStart, nPos );
  199. sCooked += szGood;
  200. sTemp = sCooked + sTemp.Right( sTemp.GetLength() - (nPos + nBadLength) );
  201. }
  202. return sTemp;
  203. }
  204. BOOL CSMTP::transmit_message(CMailMessage * msg)
  205. {
  206. CString sFrom;
  207. CString sTo;
  208. CString sTemp;
  209. CString sEmail;
  210. ASSERT( msg != NULL );
  211. if( !m_bConnected )
  212. {
  213. m_sError = _T( "Must be connected" );
  214. return FALSE;
  215. }
  216. // Send the MAIL command
  217. //
  218. sFrom.Format( _T( "MAIL From: <%s>rn" ), (LPCTSTR)msg->m_sFrom );
  219. m_wsSMTPServer.Send( (LPCTSTR)sFrom, sFrom.GetLength() );
  220. if( !get_response( GENERIC_SUCCESS ) )
  221. return FALSE;
  222. // Send RCPT commands (one for each recipient)
  223. //
  224. for( int i = 0; i < msg->GetNumRecipients(); i++ )
  225. {
  226. msg->GetRecipient( sEmail, sTemp, i );
  227. sTo.Format( _T( "RCPT TO: <%s>rn" ), (LPCTSTR)sEmail );
  228. m_wsSMTPServer.Send( (LPCTSTR)sTo, sTo.GetLength() );
  229. get_response( GENERIC_SUCCESS );
  230. }
  231. // Send the DATA command
  232. sTemp = _T( "DATArn" );
  233. m_wsSMTPServer.Send( (LPCTSTR)sTemp, sTemp.GetLength() );
  234. if( !get_response( DATA_SUCCESS ) )
  235. {
  236. return FALSE;
  237. }
  238. // Send the header
  239. //
  240. m_wsSMTPServer.Send( (LPCTSTR)msg->m_sHeader, msg->m_sHeader.GetLength() );
  241. // Send the body
  242. //
  243. sTemp = cook_body( msg );
  244. m_wsSMTPServer.Send( (LPCTSTR)sTemp, sTemp.GetLength() );
  245. // Signal end of data
  246. //
  247. sTemp = _T( "rn.rn" );
  248. m_wsSMTPServer.Send( (LPCTSTR)sTemp, sTemp.GetLength() );
  249. if( !get_response( GENERIC_SUCCESS ) )
  250. {
  251. return FALSE;
  252. }
  253. return TRUE;
  254. }
  255. BOOL CSMTP::get_response( UINT response_expected )
  256. {
  257. ASSERT( response_expected >= GENERIC_SUCCESS );
  258. ASSERT( response_expected < LAST_RESPONSE );
  259. CString sResponse;
  260. UINT response;
  261. response_code* pResp; // Shorthand
  262. if( m_wsSMTPServer.Receive( response_buf, RESPONSE_BUFFER_SIZE ) == SOCKET_ERROR )
  263. {
  264. m_sError = _T( "Socket Error" );
  265. return FALSE;
  266. }
  267. sResponse = response_buf;
  268. sscanf( (LPCTSTR)sResponse.Left( 3 ), _T( "%d" ), &response );
  269. pResp = &response_table[ response_expected ];
  270. if( response != pResp->nResponse )
  271. {
  272. m_sError.Format( _T( "%d:%s" ), response, (LPCTSTR)pResp->sMessage );
  273. return FALSE;
  274. }
  275. return TRUE;
  276. }