With transmission, verification, base64 encoding function, has modified debugging
If you want to specify, please send a letter aaachii@263.net
// csmtp.cpp: Implementation of the csmtp class.////
#include "stdafx.h" #include "csmtp.h"
#ifdef _debug # undef this_filestatic char this_file [] = __ file __; # Define new debug_new # Endif
//// cmailMessage // Formats a Message Compliant with RFC 822.
//// construction / destruction //
CmailMessage :: cmailmessage () {m_smailername = IDS_APPNAME; setcharsperline (76);
CmailMessage :: ~ cmailmessage () {}
BOOL CMailMessage :: AddRecipient (LPCTSTR szEmailAddress, LPCTSTR szFriendlyName) {ASSERT (szEmailAddress = NULL!); ASSERT (szFriendlyName = NULL!); CRecipient to; to.m_sEmailAddress = szEmailAddress; to.m_sFriendlyName = szFriendlyName; m_Recipients.Add (to) Return True;}
// sEmailAddress and sFriendlyName are OUTPUT parameters.// If the function fails, it will return FALSE, and the OUTPUT // parameters will not be touched.BOOL CMailMessage :: GetRecipient (CString & sEmailAddress, CString & sFriendlyName, int nIndex) { CRecipient to; if (nIndex <0 || nIndex> m_Recipients.GetUpperBound ()) return FALSE; to = m_Recipients [nIndex]; sEmailAddress = to.m_sEmailAddress; sFriendlyName = to.m_sFriendlyName; return TRUE;}
INT cmailMessage :: getnumrecipients () {return m_recipients.getsize ();
Bool CmailMessage :: AddmultiPleRecipients (LPCTSTR Szrecipients) {Tchar * BUF; Uint Pos; uint start; cstring step; cstring semail; cstring sfriendly; uint length; int nmark; int nmark2;
Assert (Szrecipients! = NULL);
// add recipients length = strlen (szrecipients); buf = new tchar [length 1]; // allocate a Work Area (BUF, Szrecipients); for (pOS = 0, start = 0; POS <= Length; POS ) {IF (BUF [POS] == ';' || BUF [POS] == 0) {//first, Pick Apart The Sub-strings (Separated By ';') / / Store = 0; // redundant when at the end of string, but who caves. Step = & buf [start]; // now Divide the substring into friendly names and e-mail addresses. Nmark = STEMP.FIND ('<'); if (nmark> = 0) {sfriendly = STEMP.LEFT (NMARK); nmark2 = stepp.find ('>'); if (nmark2
Void CmailMessage :: setcharsperline (uint ncharsperline) {m_ncharsperline = ncharsperline;}
Uint cmailmessage :: getcharsperline () {return m_ncharsperline;}
// Create Header AS Per RFC 822 // Void CmailMessage :: Prepare_Header () {cstring STEMP; STEMP = _T ("");
// from: STEMP = _T ("from:") m_sfrom; add_header_line ((lpctstr) STEMP;
// TO: STEMP = _T ("to:"); cstring semail = _t (""); cstring sfriendly = _t ("); for (int i = 0; i
// Format: MON, 01 JUN 98 01:10:30 gmt stemp = _t ("date:"); STEMP = m_tdatetime.format ("% a,% D% B% Y% H:% M:% s % Z "); add_header_line ((lpctstr) STEMP;
// Subject: STEMP = _T ("Subject:") m_ssubject; add_header_line ((lpctstr) STEMP);
// x-mailer stemp = _t ("x-mailer:") m_smailername; add_header_Line ((lpctstr) stemp);}
Void cmailmessage :: prepare_body () {// append a cr / lf to body if Necessary. if (m_sbody.right (2)! = _t ("/ r / n")) m_sbody = _t ("/ r / n ");
}
Void cmailmessage :: start_header () {m_sheader = _t (");
Void cmailmessage :: end_header () {m_sheader = _t ("/ r / n");}
Void cmailMessage :: add_header_line (lpctstr szheaderline) {cstring STEMP; STEMP.FORMAT (_t ("% s / r / n"), szheaderline); m_sheader = step;}
//// cmimecontentagent ////
CmimeContentagent :: cmimecontentagent (int nmimetype) {m_nmimetypeihandle = nmimetype;
CMIMECONTENTAGENT :: ~ cmimecontentagent () {}
Bool cmimecontentagent :: querytype (int nContentType) {return ncontenttype == m_nmimetypeihandle? True: false;}
//// cmimode ////
Cmimecode :: cmimecode () {}
Cmimecode :: ~ cmimode () {}
//// CBase64 //// Static Member Initializers //// The 7-bit alphabet used to encode binary informationCString CBase64 :: m_sBase64Alphabet = _T ( "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 /");
INT CBase64 :: m_nmask [] = {0, 1, 3, 7, 15, 31, 63, 127, 255};
CBASE64 :: CBase64 () {}
CBASE64 :: ~ CBase64 () {}
CString CBase64 :: Encode (lpctstr szencoding, int nsize) {cstring soutput = _t ("); int NNUMBITS = 6; uint ndigit; int lp = 0;
Assert (szencoding! = Null); if (szencoding == null) Return Soutput; m_szinput = szencoding; m_nInputsize = nsize;
m_nBitsRemaining = 0; nDigit = read_bits (nNumBits, & nNumBits, lp); while (nNumBits> 0) {sOutput = m_sBase64Alphabet [(int) nDigit]; nDigit = read_bits (nNumBits, & nNumBits, lp);} // Pad with ' = 'As Per Rfc 1521 While (Soutput.getLength ()% 4! = 0) {SOUTPUT =' = ';} Return Soutput;}
// The size of the output buffer must not be less than // 3/4 the size of the input buffer. For simplicity, // make them the same size.int CBase64 :: Decode (LPCTSTR szDecoding, LPTSTR szOutput) {CString SINPUT; INT C, LP = 0; int NDIGIT; INT NDECode [256];
Assert (szdecoding! = Null); assert (szoutput! = Null); if (szoutput == null) return 0; if (szdecoding == null) return 0; sinput = szdecoding; if (SINPUT.GETLENGTH () == 0 RETURN 0;
// build decode Table // FOR (INT i = 0; I <256; i ) NDECode [i] = -2; // illegal Digit for (i = 0; i <64; i ) {ndecode [m_sbase64alphabet [i ]]]] = i; ndecode [m_sbase64alphabet [i] | 0x80] = i; // ignore 8th bit ndecode [= '] = -1; nDecode [' = '| 0x80] = -1; // ignore mime padding char } // clear the output buffer memory (szoutput, 0, sinput.getLength () 1);
// decode the input // for (lp = 0, i = 0; lp
UINT CBase64 :: read_bits (int nNumBits, int * pBitsRead, int & lp) {ULONG lScratch; while ((m_nBitsRemaining
Void CBase64 :: Write_bits (uint nbits, int nnumbits, lptstr szoutput, int & i) {uint nscratch;
m_lBitStorage = (m_lBitStorage << nNumBits) | nBits; m_nBitsRemaining = nNumBits; while (m_nBitsRemaining> 7) {nScratch = m_lBitStorage >> (m_nBitsRemaining - 8); szOutput [i ] = nScratch & 0xFF; m_nBitsRemaining - = 8;}} //// CappoctetStream //
// Important: The number of bytes we read must be // a multiple of 3 becault cbase64's encode () // Method Will append padding characters ('=') // to make the output's size a multiple of 4.// Base64 Treats 3 8-bittes AS 4 6-bit 'Bytes') .// Mime Decoders Are Free to Treat '=' As a Signal // That There's No more Data, So We don't want to pad // unsteil We're supposed to.// at the end of the file, the # of bytes read // May Not Be a multiple of 3, but what's okay // because we do want the padding chars.
#define bytes_to_read 54 // This Number Guarantess Output Won't // Won't Exceed Line-length Limit
CAPPOCTETSTREAM :: CAPPOCTETSTREAM (int nContentType): cmimecontentagent (ncontenttype) {}
CAPPOCTSTREAM :: ~ CappocTStream () {}
Bool CappoctetStream :: appendpart (lpctstr szcontent, lpctstr szparameters, int neencoding, bool bpath, cstring & sdestination) {cstdiofile fattachment
Assert (szcontent! = Null); // this class handles Only File Attachments, SO // IT IGNORES The bpath parameter. If (szcontent == null) Return False; if (! Fattachment.Open (szcontent, (cfile :: moderead) | CFile :: shareDenyWrite | CFile :: typeBinary))) return FALSE; sDestination = build_sub_header (szContent, szParameters, nEncoding, TRUE); attach_file (& fAttachment, CMIMEMessage :: BASE64, sDestination); fAttachment.Close (); return TRUE ;} CString CAppOctetStream :: build_sub_header (LPCTSTR szContent, LPCTSTR szParameters, int nEncoding, BOOL bPath) {CString sSubHeader; CString sTemp; TCHAR szFName [_MAX_FNAME]; TCHAR szExt [_MAX_EXT];
_TSPLitPath (Szcontent, NULL, NULL, SZFNAME, SZEXT);
// this class ignores szparameters and nencoding. // IT Controls ITS OWN Parameters and only handles // base64 encoding. If (bpath) STEMP.FORMAT ("; File =% S% S", SZFNAME, SZEXT); Else Stemp = _T (""); ssubheader.format (_T ("Content-Type:% S% S / R / N"), (LPCTSTR) getContentTypeString (), (lpctstr) stemp); SSUBHEADER = _T ("Content-Transfer -ENCODING: BASE64 / R / N "); STEMP.FORMAT (_T (" Content-Disposition: attachment; filename =% s / r / n "), SSUBHEADER = STEMP; // Signal End of sub-header. SSUBHEADER = _T ("/ r / n"); // Warning: Numerous ConcateNations // is inefficient. Return SSUBHEADER;}
CSTRING CAPPOCTSTREAM :: getContentTypeString () {cstring s; s = _t ("Application / Oct-stream"); Return S;}
// Caller is responsible for opening and closing the filevoid CAppOctetStream :: attach_file (CStdioFile * pFileAtt, int nEncoding, CString & sDestination) {CMIMECode * pEncoder; int nBytesRead; TCHAR szBuffer [BYTES_TO_READ 1]; ASSERT (! PFileAtt = NULL) ; If (pfileatt == null) return; switch (neencoding) {// this class handles Only Base64 Encoding, But Others // May Be Added Here. Default: // Fall Through To ... Case CmimeMessage :: Base64: Try {Pencoder = new CBase64;} catch (cMemoryException * e) {delete e; return;}}}} (pencoder == null) // Old Habits Are Hard to Break Return; do {Try {nbytesread = pfileatt-> read (Szbuffer , BYTES_TO_READ);} catch (CFileException * e) {delete e; break;} szBuffer [nBytesRead] = 0; // Terminate the string sDestination = pEncoder-> Encode (szBuffer, nBytesRead); sDestination = _T ( "/ R / N ");} while (nbytesread == bytes_to_read); SDESTINATION = _t (" / r / n "); delete pencoder;}
//// ctextplain ////
CTextPlain :: CTextPlain (int nContentType, uint nwrapos): cmimecontent (ncontentType) {m_nwrapos = nwrapos;
CTextPlain :: ~ ctextplain () {
}
CString ctextPlain :: getContentTypeString () {cstring s; s = _t ("text / html"); return s;}
BOOL CTextPlain :: AppendPart (LPCTSTR szContent, LPCTSTR szParameters, int nEncoding, BOOL bPath, CString & sDestination) {CString sSubHeader; CString sWrapped; sSubHeader = build_sub_header (szContent, szParameters, nEncoding, bPath); sWrapped = wrap_text (szContent); sDestination = (sSubHeader sWrapped); return TRUE;} CString CTextPlain :: build_sub_header (LPCTSTR szContent, LPCTSTR szParameters, int nEncoding, BOOL bPath) {CString sSubHeader; sSubHeader.Format (_T ( "Content-Type:% s% s / R / N "), (lpctstr) getContentTypeString (), szparameters); SSUBHEADER = _T (" Content-Transfer-Encoding: "); Switch (Nencoding) {// this class handles Only 7bit Encoding, But Others // May Be added here. default: case cmimeMessage ::_7bit: ssubhead = _t ("7bit");} SSUBHEADER = _t ("/ r / n / r / n"); return ssubheader;}
CString ctextPlain :: wrap_text (lpctstr sztext) {cstring STEMP; CSTRING SLEFT; INT LP = 0; uint ncount = 0; int nspacepos = 0;
Assert (sztext! = Null); if (sztext == null) Return STEMP; STEMP = sztext; while (lp
// Static Member InitializerscmimeMessage :: cmimetypeManager cmimementage :: m_mimetypecess;
CMIMEMessage :: CMIMEMessage () {m_sMIMEContentType = _T ( "multipart / mixed"); m_sPartBoundary = _T ( "WC_MAIL_PaRt_BoUnDaRy_05151998"); m_sNoMIMEText = _T ( "This is a multipart message in MIME format.");
// Register the MIME types handled by this class // CMIMEContentAgent * pType; // These objects are deleted by CMIMTypeManager's destructor pType = new CTextPlain (TEXT_PLAIN, GetCharsPerLine ()); register_mime_type (pType); pType = new CAppOctetStream (APPLICATION_OCTETSTREAM); REGISTER_MIME_TYPE (PTYPE);
CmimeMessage :: ~ cmimeMessage () {}
// This implementation adds the part to the part-list used // to build the body.BOOL CMIMEMessage :: AddMIMEPart (LPCTSTR szContent, int nContentType, LPCTSTR szParameters, int nEncoding, BOOL bPath) {CMIMEPart part; part.m_nContentType = nContentType ; part.m_sParameters = szParameters; part.m_nEncoding = nEncoding; part.m_bPath = bPath; part.m_sContent = szContent; part.m_sContent.TrimLeft (); part.m_sContent.TrimRight (); if (nContentType == TEXT_PLAIN) m_MIMEPartList. Addhead (Part); else m_mimepartlist.addtail (part); return true;} void cmimeMessage :: prepare_header () {CString STEMP;
// let the base class add its headers cmailMessage :: prepare_header (); add_header_line (_t ("mime-version: 1.0")); STEMP.FORMAT (_T ("Content-Type:% s; boundary =% s") , (Lpctstr) m_smimecontenttype, (lpctstr) m_spartboundary; add_header_line ((lpctstr) stemp);}
void CMIMEMessage :: prepare_body () {// Class user may have assigned body text directly. // Convert it to just another MIME part to be processed. // If this default Content-Type is not good enough for the // class User, He or She Should Have Used AddmimePart () INSTEAD. IF (m_sbody! = _t (")) AddmimePart ((LPCTSTSTR) m_sbody, text_plain," ", _7bit, false);
// INITIALIZE THE BODY (Replace Current Contents). M_sbody = m_snomimetext; m_sbody = _t ("/ r / n / r / n"); append_mime_parts (); INSERT_MESSAGE_END (M_SBODY);
// let the base class take me to funky town cmailMessage :: preted_body ();
Void cmimeMessage :: INSERT_BOUNDARY (CSTRING & Stext) {CString STEMP; IF (Stext.right (2)! = _t ("/ r / n")) Stext = _t ("/ r / n"); STEMP.FORMAT _T ("-% S / R / N"), (LPCTSTSTR) m_spartBoundBoundary; Stext = STEMP;} void cmimeMessage :: INSERT_MESSAGE_END (CSTRING & Stext) {cstring STEMP; if (Stext.right (2)! = _T ("/ r / n")) Stext = _t ("/ r / n"); STEMP.FORMAT (_t ("-% s - / r / n"), (lpctstr) m_spartboundary; Stext = STEMP;
void CMIMEMessage :: register_mime_type (CMIMEContentAgent * pMIMEType) {ASSERT (pMIMEType = NULL!); if (pMIMEType == NULL) return; m_MIMETypeManager.RegisterMIMEType (pMIMEType);}
Void cmimeMessage :: append_mime_parts () {position part_position; cmimepart * pmimepart = null; cmimecontentagent * PMIMETYPE = NULL
part_position = m_MIMEPartList.GetHeadPosition (); // Get each part from the list, retrieve a handler for it, // and let the handler do its thing while (part_position = NULL!) {pMIMEPart = & m_MIMEPartList.GetNext (part_position). ; pMIMEType = m_MIMETypeManager.GetHandler (pMIMEPart-> m_nContentType); if (pMIMEType = NULL!) {insert_boundary (m_sBody); pMIMEType-> AppendPart (pMIMEPart-> m_sContent, pMIMEPart-> m_sParameters, pMIMEPart-> m_nEncoding, pMIMEPart-> m_bPath , M_sbody);}}
}
//// cmimetypeManager importation //
CmimeMessage :: cmimetypeManager :: cmimetypeManager () {}
CMIMEMessage :: CMIMETypeManager :: ~ CMIMETypeManager () {POSITION pos; CMIMEContentAgent * p; m_csAccess.Lock (); pos = m_MIMETypeList.GetHeadPosition (); while (pos = NULL!) {P = m_MIMETypeList.GetNext (pos); delete p;}} void CMIMEMessage :: CMIMETypeManager :: RegisterMIMEType (CMIMEContentAgent * pMIMEType) {ASSERT (! pMIMEType = NULL); if (pMIMEType == NULL) return; m_csAccess.Lock (); m_MIMETypeList.AddTail (pMIMEType);}
Cmimecontentagent * cmimeMeMessage :: cmimetypeManager :: getHandler (int nContentType) {position pos; cmimecontentagent * ptype = null;
M_csaccess.lock (); pOS = m_mimetypelist.getHeadPosition (); while (pos! = null) {ptype = m_mimetypelist.getnext (POS); if (ptype-> querytype (ncontenttype) == true) Break;} returnit; }
//// construction / destruction //
// static member initializers //
// Note: the order of the entries is important.// They must be synchronized with eResponse entries CSmtp :: response_code CSmtp :: response_table [] = {// GENERIC_SUCCESS {250, _T ( "SMTP server error")},. // Connect_suCcess {220, _T ("SMTP Server Not Available")}, // Authque_suCcess {334, _T ("SMTP Server Authentication Error")}, // auth_success {235, _T ("Error User OR Password")} , // Data_suCcess {354, _T ("SMTP Server Not Ready for Data")}, // qit_success {221, _T ("SMTP Server Didn't Terminate Session)}}
//// construction / destruction //
CSmtp :: CSmtp (LPCTSTR szSMTPServerName, UINT nPort) {ASSERT (szSMTPServerName = NULL!); AfxSocketInit (); m_sSMTPServerHostName = szSMTPServerName; m_nPort = nPort; m_bConnected = FALSE; m_sError = _T ( "OK"); response_buf = NULL;}
Csmtp :: ~ csmtp () {disconnect ();} cstring csmtp :: getserverhostname () {return m_ssmtpserwaystname;}
Bool csmtp :: connect () {cstring shello; tchar local_host [80]; // Warning: arbitrary size if (m_bconnected) return true;
try {// This will be deleted in Disconnect (); response_buf = new TCHAR [RESPONSE_BUFFER_SIZE]; // I can not count on all class users' applications // to have exception-throwing operator-new implementations, // so I 'll soul-kiss the ones this don't. if (response_buf == null) {m_serror = _t ("not enough memory); return false;}} catch (CEXCEPTION * E) {response_buf = null; m_Serror = _t ("Not Enough Memory"; delete E; RETURN FALSE;}
if (! m_wsSMTPServer.Create ()) {m_sError = _T ( "Unable to create the socket"); delete response_buf; response_buf = NULL; return FALSE;} if (m_wsSMTPServer.Connect (GetServerHostName (), GetPort ())!) {m_sError = _T ( "Unable to connect to server"); m_wsSMTPServer.Close (); delete response_buf; response_buf = NULL; return FALSE;} (! get_response (CONNECT_SUCCESS)) if {m_sError = _T ( "Server did not respond "); M_wssmtpserver.close (); delete response_buf; response_buf = null; returnaf} geleo.format (local_host, 80); shello.format (_T (" helo% s / r / n "), local_host); m_wssmtpserver.send ((LPCTSTR) sHello, sHello.GetLength ()); if {m_wsSMTPServer.Close (); delete response_buf; response_buf = NULL; return FALSE;} (get_response (GENERIC_SUCCESS)!) m_bConnected = TRUE; return TRUE;}
BOOL CSmtp :: Auth () {CString sAuth; if (m_bConnected!) Return FALSE; try {// This will be deleted in Disconnect (); response_buf = new TCHAR [RESPONSE_BUFFER_SIZE]; // I can not count on all class Users' Applications // TO Have Exception-throwing operator-new importations, // SO I'll Soul-kiss the ones That Don't. if (response_buf == null) {m_serror = _t ("Not Enough Memory); Return false;}} catch (CEXCEPTION * E) {response_buf = null; m_serror = _t ("not enough memory"; delete e; returnaf false;} sauth.format (_T ("auth login / r / n"))) ; file:; (! get_response (AUTHQUE_SUCCESS)) // construct auth quest m_wsSMTPServer.Send ((LPCTSTR) sAuth, sAuth.GetLength ()) if {m_sError = "SMTP server with no auth"; m_bAuthed = TRUE; return TRUE; }
SAUTH.EMPTY ();
Sauth.format (_T ("% s / r / n"), m_ssmtpuser; file: // m_ssmtpuser is an String Encode with cbase64 m_wssmtpserver.send ((lpctstr) sauth, sauth.getlength ()); if (! Get_Response (Authque_suCcess)) {m_Serror = "unknown error"; m_wssmtpserver.close (); delete response_buf; response_buf = null; return false;}
SAUTH.EMPTY ();
Sauth.format (_T ("% s / r / n"), m_ssmtppass); file: // m_ssmtppass is an String Encoded with cbase64 m_wssmtpserver.send ((lpctstr) sauth, sauth.getlength ()); if (! Get_Response (Auth_success)) {m_wssmtpserver.close (); delete response_buf; response_buf = null; returnaf = null; return false;
m_bauthed = true; return true;
}
BOOL CSmtp :: Disconnect () {BOOL ret; if (m_bConnected!) Return TRUE; // Disconnect gracefully from the server and close the socket CString sQuit = _T ( "QUIT / r / n"); m_wsSMTPServer.Send ((LPCTSTR ) Squit, Squit.getLength ());
// No need to check return value here // If it fails, the message is available with GetLastError ret = get_response (QUIT_SUCCESS);. M_wsSMTPServer.Close (); if (! Response_buf = NULL) {delete [] response_buf; response_buf = NULL;} m_bconnected = false; return ret;
Uint csmtp :: getport () {return m_nport;}
CString csmtp :: getLastError () {return m_Serror;}
Bool csmtp :: seundMTP :: SendMessage (cmailmessage * msg) {assert (msg! = Null); if (! M_bconnected) {m_serror = _t ("muct be connect"); return false;} if (! M_bauthed) {m_SERROR = _t "Must be authaned"; return false;} f (formatmailMessage (msg) == false) {return false;} if (transmit_message (msg) == false) {Return False;} return true;}
Bool CSMTP :: FormatMailMessage (cmailmessage * msg) {assert (msg! = Null); if (msg -> getnumRecipients () == 0) {m_Serror = _t ("no recipients"); return false;} msg -> formAssage (); Return True;
void CSmtp :: SetServerProperties (LPCTSTR szSMTPServerName, UINT nPort) {ASSERT (szSMTPServerName = NULL!); // Needs to be safe in non-debug too if (szSMTPServerName == NULL) return; m_sSMTPServerHostName = szSMTPServerName; m_nPort = nPort;}
CSTRING CSMTP :: COOK_BODY (CMailMessage * msg) {assert (msg! = Null); cstract STEMP; cstract scooked = _t ("); lptstr szbad = _t (" / r / n. / R / n "); lptstr SZGOOD = _T ("/ r / n ../ r / n"); int NPOS; int nStart = 0; int NBADLENGTH = Strlen (SZBAD); STEMP = MSG -> m_sbody; if (STEMP.LEFT (3) = = _T ("./ r / n")) STEMP = _t (".") STEMP; /// this is a little ineffectient because it beings a search // at the beginning of the String Each Time. This WAS ////n. That Situation // with the global flag set.) // while ((npos = step (szbad))> -1) {scooked = STEMP.MID (nStart, npos); scooked = szgood; STEMP = Scooked sTemp.Right (sTemp.GetLength () - (nPos nBadLength));} return sTemp;} BOOL CSmtp :: transmit_message (CMailMessage * msg) {CString sFrom; CString sTo; CString sTemp; CString sEmail;
Assert (msg! = Null); if (! M_bconnected) {m_serror = _t ("muct be connect"); Return False;}
IF (! m_bauthed) {m_serror = _t ("must be authaed"); returnaf
// sent the mail command sfrom.format ("Mail from: <% s> / r / n"), (lpctstr) msg-> m_sfrom); m_wssmtpserver.send ((lpctstr) sfrom, sfrom.getlength () ); If (! Get_response (generic_success)) Return False;
// send RCPT Commands (ONE for Each Recipient) for (int i = 0; i
// send the header m_wssmtpserver.send ((lpctstr) msg -> m_sheader, msg -> m_sheader.getLength ());
// send the body stemp = cook_body (msg); m_wssmtpserver.send ((lpctstr) stemp, stepp.getLength ());
// signal end of data stemp = _t ("/ r / n. / R / n"); m_wssmtpserver.send ((lpctstr) stemp, step (! Get_response (gener_success)) {Return FALSE Return True;}
Bool csmtp :: get_response (uint response_expected) {ask (response_expected> = generic_success); assert (response_expected CSTRING SRESPONSE; UINT RESPONSE; Response_code * PRESP; // Shorthand if (m_wsSMTPServer.Receive (response_buf, RESPONSE_BUFFER_SIZE) == SOCKET_ERROR) {m_sError = _T ( "Socket Error"); return FALSE;} sResponse = response_buf; sscanf ((LPCTSTR) sResponse.Left (3), _T ( "% d "), & response); pRESP = & response_table [response_expected]; if (response! = preSP -> nresponse) {m_Serror.Format (_T ("% d:% s "), response, (lpctstr) PRESP -> SMESSAGE); Return false;} Return True; // csmtp.h: interface for the csmtp class.//// #if! defined (AFX_CSMTP_H__A0D4A072_65DE_11D2_9816_9523BDBAF506__INCLUDED _) # define AFX_CSMTP_H__A0D4A072_65DE_11D2_9816_9523BDBAF506__INCLUDED_ #iF _MSC_VER> = 1000 # pragma overce # endif //_Msc_Ver> = 1000 //// cmailmessage // Formats a Message Compliant with RFC 822 # include Class CmailMessage {public: cmailMessage (); Virtual ~ cmailMessage (); void FormatMessage (); int GetNumRecipients (); BOOL GetRecipient (CString & sEmailAddress, CString & sFriendlyName, int nIndex = 0); BOOL AddRecipient (LPCTSTR szEmailAddress, LPCTSTR szFriendlyName = ""); BOOL AddMultipleRecipients (LPCTSTR szRecipients = NULL); UINT GetCharsPerLine ( ); Void setcharsperline (uint ncharsperline); CString m_sFrom; CString m_sSubject; CString m_sEnvelope; CString m_sMailerName; CString m_sHeader; CTime m_tDateTime; CString m_sBody; CString m_sUser; CString m_sPass; private: UINT m_nCharsPerLine; class CRecipient {public: CString m_sEmailAddress; CString m_sFriendlyName;}; CArray // this Rarely Needs Overwriting, But IS Virtual Just In Case. // DO NOT INCLUSTITER. Virtual Void Add_Header_Line (LPCTSTST Szheaderline); // CMIMEContentAgent // Abstract base class Content agents support MIME // content types on behalf of CMIMEMessage // class CMIMEContentAgent {public:. CMIMEContentAgent (int nMIMEType); virtual ~ CMIMEContentAgent (); BOOL QueryType (int nContentType); virtual BOOL AppendPart (LPCTSTR szContent, LPCTSTR szParameters, int nEncoding, BOOL bPath, CString & sDestination) = 0; virtual CString GetContentTypeString () = 0; protected: virtual CString build_sub_header (LPCTSTR szContent, LPCTSTR szParameters, int nEncoding, BOOL bPath) = 0; PRIVATE: INT M_NMIMETYPEIHANDLE; //// cmimecode Class cmimode {public: cmimecode (); virtual ~ cmimode (); Virtual int decode (lpctstr szdecoding, lptstr szoutput) = 0; Virtual CSTRING ENCODE (LPCTSTSTSZENCODING, INT NSIZE) = 0; //// CBase64 // An encoding agent this handles base64class cbase64: public cmimode {public: cbase64 (); virtual ~ cbase64 (); // Override The Base Class Mandatory Functions Virtual Int Decode (LPTSTSTSTSTSTPUT); Virtual Cstring Encode (LPCTSTSTSZENCODING, INT NSIZE); Protected: Void Write_bits (Uint Nbits, Int NNUMBTS, LPTSTSTSTSTSTSTSUTPUT, INT & LP); UINT READ_BITS (int NNUMBITS, INT * PBITSREAD, INT & LP); INT M_NINPUTSIZE; INT M_NBITSREMAINING; ULONG M_LBITSTORAGE; LPCTSTR M_SZINPUT; Static int m_nmask []; static cstring m_sbase64alphabet; //// CappoctetStream Class CappoctetStream: public cmimecontentagent {public: Virtual cstring getContentTypeString (); cappocTstream (int nContentType); virtual ~ cappoctetStream (); virtual BOOL AppendPart (LPCTSTR szContent, LPCTSTR szParameters, int nEncoding, BOOL bPath, CString & sDestination); protected: virtual void attach_file (CStdioFile * pFileAtt, int nEncoding, CString & sDestination); virtual CString build_sub_header (LPCTSTR szContent, LPCTSTR szParameters, int nEncoding, Bool bpath); // CTextPlain // A MIME content agent that handles the "text / plain" // content typeclass CTextPlain: public CMIMEContentAgent {public: CTextPlain (int nContentType, UINT nWrapPos = 72); virtual ~ CTextPlain (); virtual BOOL AppendPart (LPCTSTR Szcontent, LPCTSTR SZPARETERS, INT NENCODING, BOOL BPATH, CSTRING & SDESTINATION; Virtual CString getContentTypeString (); protected: UINT m_nWrapPos; CString wrap_text (LPCTSTR szText); virtual CString build_sub_header (LPCTSTR szContent, LPCTSTR szParameters, int nEncoding, BOOL bPath);}; #include // cmimeMessage // Formats a Message Using the Mime Specification. class CMIMEMessage: public CMailMessage {public: CMIMEMessage (); virtual ~ CMIMEMessage (); // MIME Type Codes enum eMIMETypeCode {TEXT_PLAIN = 0, APPLICATION_OCTETSTREAM, NEXT_FREE_MIME_CODE}; enum eMIMEEncodingCode {_7BIT = 0, _8BIT, BINARY, QUOTED_PRINTABLE, BASE64, NEXT_FREE_ENCODING_CODE}; BOOL AddMIMEPart (LPCTSTR szContent, int nContentType = APPLICATION_OCTETSTREAM, LPCTSTR szParameters = _T ( ""), int nEncoding = BASE64, BOOL bPath = TRUE); protected: void insert_message_end (CString & sText); void register_mime_type (CMIMEContentAgent * pMIMEType) ; Void insert_boundary (CSTRING & Stext); virtual void append_mime_parts (); virtual void prepare_header (); virtual void prepare_body (); CString m_sNoMIMEText; CString m_sPartBoundary; CString m_sMIMEContentType; private: class CMIMEPart {public: int m_nEncoding; int m_nContentType; CString m_sParameters; BOOL m_bPath; CString m_sContent;} ; Clist class CMIMETypeManager {public: CMIMEContentAgent * GetHandler (int nContentType); void RegisterMIMEType (CMIMEContentAgent * pMIMEType); virtual ~ CMIMETypeManager (); CMIMETypeManager (); private: CCriticalSection m_csAccess; CList Static cmimetypeManager m_mimetypemanager; //// csmtp // main class for SMTP #include #define smtp_port 25 // Standard Port for SMTP Servers # Define Response_buffer_size 1024 Class CSMTP {public: CSMTP (LPCTSTSTSMTPSERVERNAME, UINT NPORT = SMTP_PORT); Virtual ~ CSMTP (); void SetServerProperties (LPCTSTR szSMTPServerName, UINT nPort = SMTP_PORT); CString GetLastError (); UINT GetPort (); BOOL Disconnect (); BOOL Connect (); virtual BOOL FormatMailMessage (CMailMessage * msg); BOOL SendMessage (CMailMessage * msg); CString GetServerHostName (); Private: BOOL GET_RESPONSE (uint response_expected); cstring cook_body (cmailmessage * msg); CSTRING M_SERROR; BOOL M_BCONNECTED; BOOL M_BAUTHED; UINT M_NPORT; CSTRING M_SSMTPSERVERHOSTNAME; CSOCKET M_WSSMTPSERVER; Protected: Virtual Bool Transmit_Message (CmailMessage * MSG); //// helper code // struct response_code {uint nresponse; // Response we're looking for tchar * smessage; // error message if we don't get it}; enum eResponse {GENERIC_SUCCESS = 0, CONNECT_SUCCESS, DATA_SUCCESS, QUIT_SUCCESS, // Include any others here LAST_RESPONSE // Do not add entries past this one}; TCHAR * response_buf; static response_code response_table [];};! # endif // defined ( AFX_CSMTP_H__A0D4A072_65DE_11D2_9816_9523BDBAF506__INCLUDED_)