#include "ClientSocket.h" // Windows.h, WinSock2.h ¼ø¼­¸¦ À¯ÁöÇϱâ À§ÇØ ¸ÕÀú includeÇÑ´Ù. #include "SmtpClient.h" #include "Base64.h" #include "Mime.h" #include #define DEF_CLIENTSOCKET( name ) ClientSocket* name = ( ClientSocket* )m_instanceSocket #define DEF_MIME( name ) Mime* name = ( Mime* )m_mime; #define CHECK_CONNECTION 0 #define CHECK_HELLO 1 #define CHECK_LOGIN 2 #define CHECK_USERNAME 3 #define CHECK_PASSWORD 4 #define CHECK_MAIL 5 #define CHECK_RCPT 6 #define CHECK_DATA_START 7 #define CHECK_DATA_END 8 #define CHECK_QUIT 9 #define CHECK_DATA 10 SMTPClient::SMTPClient() { // ¹èÆ÷½Ã ClientSocket.h¸¦ ¿­¿Ü½Ã۱â À§Çؼ­´Â cpp¿¡¼­ ClientSocketÀ» // »ç¿ëÇØ¾ß ÇÑ´Ù. ¶§¹®¿¡ member·Î´Â LPVOID·Î ¼±¾ðÇϰí ClientSocketÀÇ // °³Ã¼¸¦ »ý¼ºÇÑ ÈÄ Æ÷ÀÎÅ͸¦ °¡¸®Å°°Ô ÇÏ´Â °ÍÀÌ´Ù. m_instanceSocket = ( LPVOID )new ClientSocket(); m_mime = ( LPVOID )new Mime(); } SMTPClient::~SMTPClient() { DEF_CLIENTSOCKET( clientSocket ); clientSocket->Close(); delete m_instanceSocket; delete m_mime; } BOOL SMTPClient::CheckResponse( BYTE type ) { DEF_CLIENTSOCKET( clientSocket ); char buffer[512], temp[3]; int typeNo; int codeList[11] = { 220, 250, 334, 334, 235, 250, 250, 354, 250, 221, 354 }; ZeroMemory( buffer, 512 ); clientSocket->Recv( buffer, sizeof( buffer ) ); ::strncpy( temp, buffer, 3 ); typeNo = atoi( temp ); if( typeNo != codeList[type] ) return FALSE; return TRUE; } //================================================================================================= /** @remarks ¸ÞÀϼ­¹ö¿¡ ¿¬°áÀ» ½ÃµµÇÑ´Ù. @param ipAddress Á¢¼ÓÇÒ ¸ÞÀÏ ¼­¹öÀÇ ÁÖ¼Ò¸¦ ÀÔ·ÂÇÑ´Ù. ÁÖ¼ÒÀÇ Çü½ÄÀº ¼ýÀÚ·Î ±¸¼ºµÈ IP ÁÖ¼Ò¿Í ¹®ÀÚ·Î ±¸¼ºµÈ dns ÁÖ¼Ò µÎ °¡Áö ¸ðµÎ Çã¿ëµÈ´Ù. ( "10.0.0.1" or "mail.webzen.co.kr" ) @param userName ¸ÞÀÏ ¼­¹ö¿¡ µû¶ó ÀÎÁõÀ» ÇÊ¿ä·Î ÇÏ´Â °æ¿ì°¡ ÀÖ´Ù. ÀÌ ¶§´Â userName°ú password µÎ ÆÄ¶ó¹ÌÅ͸¦ ¸ðµÎ ä¿öÁÖ¾î¾ß ÇÑ´Ù. ±âº»°ªÀ¸·Î NULLÀÌ ÀԷµȴÙ. ÀÌ °ªÀº ¸ÞÀÏ ¼­¹ö·ÎºÎÅÍ ¹ß±Þ¹ÞÀº °èÁ¤ÀÌ´Ù. @param password ±âº»°ªÀ¸·Î NULLÀÌ ÀԷµȴÙ. °èÁ¤¿¡ ÇÒ´çµÈ ÆÐ½º¿öµå¸¦ ÀÔ·ÂÇÑ´Ù. @param portNo Á¢¼ÓÇÒ ¸ÞÀÏ ¼­¹öÀÇ Æ÷Æ® ¹øÈ£. ´ëºÎºÐÀÇ °æ¿ì 23¹ø Æ÷Æ®¸¦ »ç¿ëÇϸç ÀÌ °ªÀÌ ±âº»°ªÀ¸·Î ÀԷµȴÙ. @ret ¿¬°á¿¡ ¼º°øÇϸé TRUE¸¦ ¹ÝȯÇÑ´Ù. */ //================================================================================================= BOOL SMTPClient::Connect( LPCTSTR ipAddress, LPCTSTR userName, LPCTSTR password, u_short portNo ) { DEF_CLIENTSOCKET( clientSocket ); TCHAR hostName[127]; TCHAR buffer[512]; ::gethostname( hostName, 127 ); if( clientSocket->Connect( ipAddress, portNo ) == false ) return FALSE; if( CheckResponse( CHECK_CONNECTION ) == FALSE ) return FALSE; m_receiverCount = 0; if( userName != 0 && password != 0 ) { ::sprintf( buffer, "EHLO %s\r\n", hostName ); clientSocket->Send( buffer, ( int )::strlen( buffer ) ); if( CheckResponse( CHECK_HELLO ) == FALSE ) return FALSE; if( MailLogin( userName, password ) == FALSE ) return FALSE; } else { ::sprintf( buffer, "HELO %s\r\n", hostName ); clientSocket->Send( buffer, ( int )::strlen( buffer ) ); if( CheckResponse( CHECK_HELLO ) == FALSE ) return FALSE; } return TRUE; } //================================================================================================= /** @remarks ¼­¹ö¿ÍÀÇ ¿¬°áÀ» Á¾·áÇÑ´Ù. @ret ¿¬°áÀÌ Á¤»óÀûÀ¸·Î Á¾·áµÇ¸é TRUE¸¦ ¹ÝȯÇÑ´Ù. */ //================================================================================================= BOOL SMTPClient::Disconnect() { DEF_CLIENTSOCKET( clientSocket ); TCHAR buffer[127]; ::sprintf( buffer, "QUIT\r\n" ); clientSocket->Send( buffer, ( int )::strlen( buffer ) ); return ( CheckResponse( CHECK_QUIT ) == TRUE ); } BOOL SMTPClient::MailLogin( LPCTSTR userName, LPCTSTR password ) { DEF_CLIENTSOCKET( clientSocket ); TCHAR encodeUserName[256]; TCHAR encodePassword[256]; TCHAR buffer[127]; Base64Encode( userName, ( int )::strlen( userName ), encodeUserName, 256 ); Base64Encode( password, ( int )::strlen( password ), encodePassword, 256 ); ::sprintf( buffer, "AUTH LOGIN\r\n" ); clientSocket->Send( buffer, ( int )::strlen( buffer ) ); if( CheckResponse( CHECK_LOGIN ) == FALSE ) return FALSE; ::sprintf( buffer, "%s\r\n", encodeUserName ); clientSocket->Send( buffer, ( int )::strlen( buffer ) ); if( CheckResponse( CHECK_USERNAME ) == FALSE ) return FALSE; ::sprintf( buffer, "%s\r\n", encodePassword ); clientSocket->Send( buffer, ( int )::strlen( buffer ) ); if( CheckResponse( CHECK_PASSWORD ) == FALSE ) return FALSE; return TRUE; } //================================================================================================= /** @remarks ¸ÞÀÏ ¼­¹ö·Î ¹ß½ÅÀÚÀÇ Á¤º¸¸¦ º¸³½´Ù. @param fromNick ¹ß½ÅÀÚÀÇ E-Mail ÁÖ¼Ò¿¡ ´ëÇÑ À̸§ ȤÀº º°ÄªÀ» ÀԷ¹޴´Ù. ÃÖ´ë ±æÀÌ´Â 63 BytesÀÌ´Ù. @param fromEMail ¹ß½ÅÀÚÀÇ E-Mail ÁÖ¼Ò¸¦ ÀԷ¹޴´Ù. ÃÖ´ë ±æÀÌ´Â 63 BytesÀÌ´Ù. @ret ÀÛ¾÷ÀÌ Á¤»óÀûÀ¸·Î ÀÌ·ç¾îÁö¸é TRUE¸¦ ¹ÝȯÇÑ´Ù. */ //================================================================================================= BOOL SMTPClient::MailFrom( LPCTSTR fromNick, LPCTSTR fromEMail ) { DEF_CLIENTSOCKET( clientSocket ); TCHAR buffer[127]; ::strcpy( m_fromNick, fromNick ); ::strcpy( m_fromEMail, fromEMail ); ::sprintf( buffer, "MAIL FROM:%s\r\n", m_fromEMail ); clientSocket->Send( buffer, ( int )::strlen( buffer ) ); return ( CheckResponse( CHECK_MAIL ) == TRUE ); } //================================================================================================= /** @remarks ¸ÞÀÏ ¼­¹ö·Î ¼ö½ÅÀÚÀÇ Á¤º¸( email °èÁ¤ )À» º¸³½´Ù. @param to ¼ö½ÅÀÚÀÇ E-Mail ÁÖ¼Ò¸¦ ÀԷ¹޴´Ù. ¼ö½ÅÀÚ¸¦ ¿©·¯¸í ÁöÁ¤ÇϰíÀÚ ÇÒ ¶§¿¡´Â, ¼ö½ÅÀÚ E-Mail ÁÖ¼Ò¸¦ ¹Ù²Ù¸é¼­ ÀÌ ÇÔ¼ö¸¦ °è¼Ó È£ÃâÇØÁÖ¸é µÈ´Ù. @ret ÀÛ¾÷ÀÌ Á¤»óÀûÀ¸·Î ÀÌ·ç¾îÁö¸é TRUE¸¦ ¹ÝȯÇÑ´Ù. */ //================================================================================================= BOOL SMTPClient::MailTo( LPCTSTR to ) { DEF_CLIENTSOCKET( clientSocket ); TCHAR buffer[127]; ::sprintf( buffer, "RCPT TO:<%s>\r\n", to ); clientSocket->Send( buffer, ( int )::strlen( buffer ) ); if( CheckResponse( CHECK_RCPT ) == FALSE ) return FALSE; ::strcpy( m_listReceiver[m_receiverCount], to ); m_receiverCount++; return TRUE; } //================================================================================================= /** @remarks ¸ÞÀÏÀÇ ³»¿ëÀ» ¼­¹ö·Î º¸³½´Ù. @param subject ¸ÞÀÏÀÇ Á¦¸ñÀ» ÀԷ¹޴´Ù. @param body text·Î ±¸¼ºµÈ ¸ÞÀÏÀÇ º»¹®À» ÀԷ¹޴´Ù. bodyÀÇ Å©±â´Â Á¦ÇÑÀÌ ¾øÁö¸¸, °¡´ÉÇϸé ÀÛ¾÷ÀÇ È¿À²¼ºÀ» °í·ÁÇÏ¿© unsigned short±îÁö·Î Á¦ÇÑÇÒ °ÍÀ» ±ÇÀ¯ÇÑ´Ù. @ret ÀÛ¾÷ÀÌ Á¤»óÀûÀ¸·Î ÀÌ·ç¾îÁö¸é TRUE¸¦ ¹ÝȯÇÑ´Ù. */ //================================================================================================= BOOL SMTPClient::MailContents( LPCTSTR subject, LPCTSTR body ) { DEF_CLIENTSOCKET( clientSocket ); DEF_MIME( mime ); TCHAR buffer[127]; ::sprintf( buffer, "DATA\r\n" ); clientSocket->Send( buffer, ( int )::strlen( buffer ) ); if( CheckResponse( CHECK_DATA ) == FALSE ) return FALSE; // ¹ß½ÅÀÚ Á¤º¸ { ::sprintf( buffer, "From: %s<%s>\r\n", m_fromNick, m_fromEMail ); clientSocket->Send( buffer, ( int )::strlen( buffer ) ); ::sprintf( buffer, "X-Mailer:SSUL SendMail v1.0 [Korea]\r\n" ); clientSocket->Send( buffer, ( int )::strlen( buffer ) ); } // ¼ö½ÅÀÚ Á¤º¸ { int i; ::sprintf( buffer, "To: <" ); for( i = 0 ; i < m_receiverCount ; i++ ) { if( i > 0 ) ::strcat( buffer, ";" ); ::strcat( buffer, m_listReceiver[i] ); } ::strcat( buffer, ">\r\n" ); clientSocket->Send( buffer, ( int )::strlen( buffer ) ); } // ¸ÞÀÏ Á¦¸ñ Àü¼Û { ::sprintf( buffer, "Subject: %s\r\n", subject ); clientSocket->Send( buffer, ( int )::strlen( buffer ) ); } ::sprintf( buffer, "Mime-Version: 1.0\r\n" ); clientSocket->Send( buffer, ( int )::strlen( buffer ) ); ::sprintf( buffer, "Content-Type: multipart/mixed; boundary=\"%s\"\r\n\r\n", mime->GetDefaultBoundary() ); clientSocket->Send( buffer, ( int )::strlen( buffer ) ); ::sprintf( buffer, "--%s\r\n", mime->GetDefaultBoundary() ); clientSocket->Send( buffer, ( int )::strlen( buffer ) ); // ¸ÞÀÏ º»¹® Àü¼Û { LPTSTR bodyText; int bodySize, encodeSize; bodySize = ( int )::strlen( body ); encodeSize = ( int )( ( float )bodySize * 1.5f ); bodyText = new TCHAR [ encodeSize ]; ::sprintf( buffer, "Content-Type: text/plain; charset=euc_kr\r\n" ); clientSocket->Send( buffer, ( int )::strlen( buffer ) ); ::sprintf( buffer, "Content-Transfer-Encoding: Base64\r\n\r\n" ); clientSocket->Send( buffer, ( int )::strlen( buffer ) ); Base64Encode( body, bodySize, bodyText, encodeSize ); encodeSize = ( int )::strlen( bodyText ); clientSocket->Send( bodyText, encodeSize ); delete bodyText; } return TRUE; } //================================================================================================= /** @remarks ¸ÞÀÏ¿¡ ÷ºÎÆÄÀÏÀ» »ðÀÔÇÑ´Ù. ¿©·¯°³ÀÇ ÆÄÀÏÀ» ÷ºÎÇϱâ À§Çؼ­´Â ÀÌ ÇÔ¼ö¸¦ ¿øÇÏ´Â ¸¸Å­ È£ÃâÇØÁÙ ¼ö ÀÖ´Ù. @param fileName ÷ºÎÇÒ ÆÄÀϸíÀ» ÀÔ·ÂÇÑ´Ù. ÆÄÀϸíÀº Àý´ë°æ·Î ȤÀº »ó´ë°æ·Î ¸ðµÎ¸¦ Çã¿ëÇϸç, °æ·Î°¡ ¾ø´Â ÆÄÀÏ¸í¸¸ ÀÔ·ÂÇÒ ¼ö ÀÖ´Ù. @ret ÀÛ¾÷ÀÌ Á¤»óÀûÀ¸·Î ÀÌ·ç¾îÁö¸é TRUE¸¦ ¹ÝȯÇÑ´Ù. @note ÆÄÀÏ Ã·ºÎ¸¦ ¿äûÇϱâ À§Çؼ­´Â ¾Õ¼­ ¸ÞÀÏÀÇ º»¹® ÀÛ¼ºÀÌ ³¡³ª¾ß ÇÑ´Ù. ÀÌ ÇÔ¼öº¸´Ù ¾Õ¼­ MailContentsÇÔ¼ö°¡ Á¤»óÀûÀ¸·Î ¿Ï·áµÇ¾ú´ÂÁö¸¦ È®ÀÎÇÒ ¼ö ÀÖµµ·Ï ÇÑ´Ù. */ //================================================================================================= BOOL SMTPClient::MailAttachFile( LPTSTR fileName ) { DEF_CLIENTSOCKET( clientSocket ); DEF_MIME( mime ); TCHAR buffer[127], filePath[2048]; LPTSTR contentType; // Split File extend { TCHAR drive[127], dir[127]; TCHAR name[127], ext[24]; int i; ::_splitpath( fileName, drive, dir, name, ext ); // È®ÀåÀÚ¿¡¼­ dotÀ» Á¦°ÅÇÑ´Ù. for( i = 1 ; ext[i] != 0 ; i++ ) { ext[i - 1] = ext[i]; ext[i] = 0; } contentType = mime->GetContentType( ext ); // ÆÄÀÏÀÇ °æ·Î¿Í ÆÄÀϸíÀ» ºÐ¸®ÇÏ¿© ÀúÀåÇÑ´Ù. if( drive[0] == 0 && dir[0] == 0 ) ::sprintf( filePath, "." ); if( drive[0] == 0 && dir[0] != 0 ) ::sprintf( filePath, ".\\%s", dir ); if( drive[0] != 0 && dir[0] != 0 ) ::sprintf( filePath, "%s\\%s", drive, dir ); ::sprintf( fileName, "%s.%s", name, ext ); } // Start boundary ::sprintf( buffer, "\r\n--%s\r\n", mime->GetDefaultBoundary() ); clientSocket->Send( buffer, ( int )::strlen( buffer ) ); ::sprintf( buffer, "Content-Type: %s; file=\"%s\"\r\n", contentType, fileName ); clientSocket->Send( buffer, ( int )::strlen( buffer ) ); ::sprintf( buffer, "Content-Transfer-Encoding: Base64\r\n" ); clientSocket->Send( buffer, ( int )::strlen( buffer ) ); ::sprintf( buffer, "Content-Disposition: attachment; filename=\"%s\"\r\n", fileName ); clientSocket->Send( buffer, ( int )::strlen( buffer ) ); ::sprintf( buffer, "Content-Description: Created from SSUL mail engine\r\n\r\n" ); clientSocket->Send( buffer, ( int )::strlen( buffer ) ); // Encoding File to Base64 { HANDLE handleFile; TCHAR readBuffer[8192], encodeBuffer[8192]; TCHAR fileFullName[2048]; DWORD readBytes; int size; ::sprintf( fileFullName, "%s\\%s", filePath, fileName ); handleFile = CreateFile( fileFullName, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0 ); if( handleFile == INVALID_HANDLE_VALUE ) return FALSE; do { if( ReadFile( handleFile, readBuffer, 3072, &readBytes, 0 ) == FALSE ) break; Base64Encode( readBuffer, readBytes, encodeBuffer, 8192 ); size = ( int )::strlen( encodeBuffer ); if( readBytes > 0 ) clientSocket->Send( encodeBuffer, size ); } while( readBytes > 0 ); CloseHandle( handleFile ); } return TRUE; } //================================================================================================= /** @remarks ¸ÞÀÏ ÀÛ¼ºÀ» ³¡³»°í ¹ß½ÅÇ϶ó´Â ¸í·ÉÀ» ¸ÞÀϼ­¹ö·Î ¿äûÇÑ´Ù. ¹ß½ÅÀÌ Á¤»óÀûÀ¸·Î ÀÌ·ç¾îÁö´õ¶óµµ ¸ÞÀÏ ¼­¹ö¿ÍÀÇ ¿¬°áÀº ²÷Áö ¾Ê´Â´Ù. ¿¬°á Á¾·á¸¦ ¿øÇÑ´Ù¸é Disconnect ÇÔ¼ö¸¦ Á÷Á¢ È£ÃâÇØ¾ß ÇÑ´Ù. @ret ÀÛ¾÷ÀÌ Á¤»óÀûÀ¸·Î ÀÌ·ç¾îÁö¸é TRUE¸¦ ¹ÝȯÇÑ´Ù. */ //================================================================================================= BOOL SMTPClient::MailSubmit() { DEF_CLIENTSOCKET( clientSocket ); DEF_MIME( mime ); TCHAR buffer[127]; ::sprintf( buffer, "\r\n--%s--\r\n", mime->GetDefaultBoundary() ); clientSocket->Send( buffer, ( int )::strlen( buffer ) ); ::sprintf( buffer, "\r\n.\r\n" ); clientSocket->Send( buffer, ( int )::strlen( buffer ) ); if( CheckResponse( CHECK_DATA_END ) == FALSE ) return FALSE; ::sprintf( buffer, "QUIT\r\n" ); clientSocket->Send( buffer, ( int )::strlen( buffer ) ); if( CheckResponse( CHECK_QUIT ) == FALSE ) return FALSE; return TRUE; }