Correctly deallocate buffer
[TortoiseGit.git] / src / Utils / HwSMTP.cpp
blobae5456b715ff448ffe4b7e1fa2edb8e4c997b3f0
1 // HwSMTP.cpp: implementation of the CHwSMTP class.
2 //
3 //////////////////////////////////////////////////////////////////////
5 #include "stdafx.h"
6 #include "afxstr.h"
7 #include "HwSMTP.h"
8 #include "CBase64.h"
9 #include "SpeedPostEmail.h"
10 #include "Windns.h"
11 #include <Afxmt.h>
13 #ifdef _DEBUG
14 #undef THIS_FILE
15 static char THIS_FILE[]=__FILE__;
16 #define new DEBUG_NEW
17 #endif
19 CPtrArray g_PtrAry_Threads;
20 ::CCriticalSection m_CSFor__g_PtrAry_Threads;
22 class CEMailObject
24 public:
25 CEMailObject (
26 LPCTSTR lpszSmtpSrvHost,
27 LPCTSTR lpszUserName,
28 LPCTSTR lpszPasswd,
29 BOOL bMustAuth,
30 LPCTSTR lpszAddrFrom,
31 LPCTSTR lpszAddrTo,
32 LPCTSTR lpszFromName,
33 LPCTSTR lpszReceiverName,
34 LPCTSTR lpszSubject,
35 LPCTSTR lpszBody,
36 LPCTSTR lpszCharSet,
37 CStringArray *pStrAryAttach,
38 LPCTSTR pStrAryCC,
39 UINT nSmtpSrvPort,
40 LPCTSTR pSender,
41 LPCTSTR pToList
44 m_csSmtpSrvHost = GET_SAFE_STRING(lpszSmtpSrvHost);
45 m_csUserName = GET_SAFE_STRING(lpszUserName);
46 m_csPasswd = GET_SAFE_STRING(lpszPasswd);
47 m_bMustAuth = bMustAuth;
48 m_csAddrFrom = GET_SAFE_STRING(lpszAddrFrom);
49 m_csAddrTo = GET_SAFE_STRING(lpszAddrTo);
50 m_csFromName = GET_SAFE_STRING(lpszFromName);
51 m_csReceiverName = GET_SAFE_STRING(lpszReceiverName);
52 m_csSubject = GET_SAFE_STRING(lpszSubject);
53 m_csBody = GET_SAFE_STRING(lpszBody);
54 m_csCharSet = GET_SAFE_STRING(lpszCharSet);
55 m_StrCC = GET_SAFE_STRING(pStrAryCC);
56 m_csSender = GET_SAFE_STRING(pSender);
57 m_csToList = GET_SAFE_STRING(pToList);
59 if ( pStrAryAttach )
60 m_StrAryAttach.Append ( *pStrAryAttach );
62 m_nSmtpSrvPort = nSmtpSrvPort;
63 m_hThread = NULL;
66 public:
67 CString m_csSmtpSrvHost;
68 CString m_csUserName;
69 CString m_csPasswd;
70 BOOL m_bMustAuth;
71 CString m_csAddrFrom;
72 CString m_csAddrTo;
73 CString m_csFromName;
74 CString m_csReceiverName;
75 CString m_csSubject;
76 CString m_csBody;
77 CString m_csCharSet;
78 CStringArray m_StrAryAttach;
79 CString m_StrCC;
80 UINT m_nSmtpSrvPort;
81 CString m_csSender;
82 CString m_csToList;
84 HANDLE m_hThread;
87 //////////////////////////////////////////////////////////////////////
88 // Construction/Destruction
89 //////////////////////////////////////////////////////////////////////
91 CHwSMTP::CHwSMTP () :
92 m_bConnected ( FALSE ),
93 m_nSmtpSrvPort ( 25 ),
94 m_bMustAuth ( TRUE )
96 m_csPartBoundary = _T( "WC_MAIL_PaRt_BoUnDaRy_05151998" );
97 m_csMIMEContentType = FormatString ( _T( "multipart/mixed; boundary=%s" ), m_csPartBoundary);
98 m_csNoMIMEText = _T( "This is a multi-part message in MIME format." );
99 //m_csCharSet = _T("\r\n\tcharset=\"iso-8859-1\"\r\n");
101 AfxSocketInit();
104 CHwSMTP::~CHwSMTP()
108 void CHwSMTP::GetNameAddress(CString &in, CString &name,CString &address)
110 int start,end;
111 start=in.Find(_T('<'));
112 end=in.Find(_T('>'));
114 if(start >=0 && end >=0)
116 name=in.Left(start);
117 address=in.Mid(start+1,end-start-1);
119 else
120 address=in;
123 CString CHwSMTP::GetServerAddress(CString &email)
125 CString str;
126 int start,end;
128 start = email.Find(_T("<"));
129 end = email.Find(_T(">"));
131 if(start>=0 && end >=0)
133 str=email.Mid(start+1,end-start-1);
135 else
137 str=email;
140 start = str.Find(_T('@'));
141 return str.Mid(start+1);
145 BOOL CHwSMTP::SendSpeedEmail
147 LPCTSTR lpszAddrFrom,
148 LPCTSTR lpszAddrTo,
149 LPCTSTR lpszSubject,
150 LPCTSTR lpszBody,
151 LPCTSTR lpszCharSet,
152 CStringArray *pStrAryAttach,
153 LPCTSTR pStrAryCC,
154 UINT nSmtpSrvPort,
155 LPCTSTR pSend
159 BOOL ret=true;
160 CString To;
161 To += GET_SAFE_STRING(lpszAddrTo);
162 To += _T(";");
163 To += GET_SAFE_STRING(pStrAryCC);
165 std::map<CString,std::vector<CString>> Address;
167 int start = 0;
168 while( start >= 0 )
170 CString one= To.Tokenize(_T(";"),start);
171 one=one.Trim();
172 if(one.IsEmpty())
173 continue;
175 CString addr;
176 addr = GetServerAddress(one);
177 if(addr.IsEmpty())
178 continue;
180 Address[addr].push_back(one);
184 std::map<CString,std::vector<CString>>::iterator itr1 = Address.begin();
185 for( ; itr1 != Address.end(); ++itr1 )
187 PDNS_RECORD pDnsRecord;
188 PDNS_RECORD pNext;
190 DnsQuery(itr1->first ,
191 DNS_TYPE_MX,DNS_QUERY_STANDARD,
192 NULL, //Contains DNS server IP address.
193 &pDnsRecord, //Resource record that contains the response.
194 NULL
197 CString to;
198 to.Empty();
199 for(int i=0;i<itr1->second.size();i++)
201 to+=itr1->second[i];
202 to+=_T(";");
204 if(to.IsEmpty())
205 continue;
207 pNext=pDnsRecord;
208 while(pNext)
210 if(pNext->wType == DNS_TYPE_MX)
211 if(SendEmail(pNext->Data.MX.pNameExchange,NULL,NULL,false,
212 lpszAddrFrom,to,lpszSubject,lpszBody,lpszCharSet,pStrAryAttach,pStrAryCC,
213 25,pSend,lpszAddrTo))
214 break;
215 pNext=pNext->pNext;
217 if(pNext == NULL)
218 ret = false;
220 //SendEmail(itr1.first,NULL,NULL,false,lpszAddrFrom,,lpszFromname);
221 DnsRecordListFree(pDnsRecord,DnsFreeRecordList);
224 return ret;
226 BOOL CHwSMTP::SendEmail (
227 LPCTSTR lpszSmtpSrvHost,
228 LPCTSTR lpszUserName,
229 LPCTSTR lpszPasswd,
230 BOOL bMustAuth,
231 LPCTSTR lpszAddrFrom,
232 LPCTSTR lpszAddrTo,
233 LPCTSTR lpszSubject,
234 LPCTSTR lpszBody,
235 LPCTSTR lpszCharSet, // ×Ö·û¼¯ÀàÐÍ£¬ÀýÈ磺·±ÌåÖÐÎÄÕâÀïÓ¦ÊäÈë"big5"£¬¼òÌåÖÐÎÄʱÊäÈë"gb2312"
236 CStringArray *pStrAryAttach/*=NULL*/,
237 LPCTSTR pStrAryCC/*=NULL*/,
238 UINT nSmtpSrvPort,/*=25*/
239 LPCTSTR pSender,
240 LPCTSTR pToList
243 TRACE ( _T("·¢ËÍÓʼþ£º%s, %s\n"), lpszAddrTo, lpszBody );
244 m_StrAryAttach.RemoveAll();
246 m_StrCC += GET_SAFE_STRING(pStrAryCC);
248 m_csSmtpSrvHost = GET_SAFE_STRING ( lpszSmtpSrvHost );
249 if ( m_csSmtpSrvHost.GetLength() <= 0 )
251 m_csLastError.Format ( _T("Parameter Error!") );
252 return FALSE;
254 m_csUserName = GET_SAFE_STRING ( lpszUserName );
255 m_csPasswd = GET_SAFE_STRING ( lpszPasswd );
256 m_bMustAuth = bMustAuth;
257 if ( m_bMustAuth && m_csUserName.GetLength() <= 0 )
259 m_csLastError.Format ( _T("Parameter Error!") );
260 return FALSE;
263 m_csAddrFrom = GET_SAFE_STRING ( lpszAddrFrom );
264 m_csAddrTo = GET_SAFE_STRING ( lpszAddrTo );
265 // m_csFromName = GET_SAFE_STRING ( lpszFromName );
266 // m_csReceiverName = GET_SAFE_STRING ( lpszReceiverName );
267 m_csSubject = GET_SAFE_STRING ( lpszSubject );
268 m_csBody = GET_SAFE_STRING ( lpszBody );
270 this->m_csSender = GET_SAFE_STRING(pSender);
271 this->m_csToList = GET_SAFE_STRING(pToList);
273 m_nSmtpSrvPort = nSmtpSrvPort;
275 if ( lpszCharSet && lstrlen(lpszCharSet) > 0 )
276 m_csCharSet.Format ( _T("\r\n\tcharset=\"%s\"\r\n"), lpszCharSet );
278 if (
279 m_csAddrFrom.GetLength() <= 0 || m_csAddrTo.GetLength() <= 0
282 m_csLastError.Format ( _T("Parameter Error!") );
283 return FALSE;
286 if ( pStrAryAttach )
288 m_StrAryAttach.Append ( *pStrAryAttach );
290 if ( m_StrAryAttach.GetSize() < 1 )
291 m_csMIMEContentType = FormatString ( _T( "text/plain; %s" ), m_csCharSet);
293 // ´´½¨Socket
294 m_SendSock.Close();
295 if ( !m_SendSock.Create () )
297 int nResult = GetLastError();
298 m_csLastError.Format ( _T("Create socket failed!") );
299 return FALSE;
302 // Á¬½Óµ½·þÎñÆ÷
303 if ( !m_SendSock.Connect ( m_csSmtpSrvHost, m_nSmtpSrvPort ) )
305 m_csLastError.Format ( _T("Connect to [ %s ] failed"), m_csSmtpSrvHost );
306 TRACE ( _T("%d\n"), GetLastError() );
307 return FALSE;
309 if ( !GetResponse( _T("220") ) ) return FALSE;
311 m_bConnected = TRUE;
312 BOOL ret= SendEmail();
314 m_SendSock.Close();
316 return ret;
320 BOOL CHwSMTP::GetResponse ( LPCTSTR lpszVerifyCode, int *pnCode/*=NULL*/)
322 if ( !lpszVerifyCode || lstrlen(lpszVerifyCode) < 1 )
323 return FALSE;
325 char szRecvBuf[1024] = {0};
326 int nRet = 0;
327 char szStatusCode[4] = {0};
328 nRet = m_SendSock.Receive ( szRecvBuf, sizeof(szRecvBuf) );
329 TRACE ( _T("Received : %s\r\n"), szRecvBuf );
330 if ( nRet <= 0 )
332 m_csLastError.Format ( _T("Receive TCP data failed") );
333 return FALSE;
335 // TRACE ( _T("ÊÕµ½·þÎñÆ÷»ØÓ¦£º%s\n"), szRecvBuf );
337 memcpy ( szStatusCode, szRecvBuf, 3 );
338 if ( pnCode ) (*pnCode) = atoi ( szStatusCode );
340 if ( strcmp ( szStatusCode, CMultiByteString(lpszVerifyCode).GetBuffer() ) != 0 )
342 m_csLastError.Format ( _T("Received invalid response : %s"), GetCompatibleString(szRecvBuf,FALSE) );
343 return FALSE;
346 return TRUE;
348 BOOL CHwSMTP::SendBuffer(char *buff,int size)
350 if(size<0)
351 size=(int)strlen(buff);
352 if ( !m_bConnected )
354 m_csLastError.Format ( _T("Didn't connect") );
355 return FALSE;
358 if ( m_SendSock.Send ( buff, size ) != size )
360 m_csLastError.Format ( _T("Socket send data failed") );
361 return FALSE;
364 return TRUE;
366 // ÀûÓÃsocket·¢ËÍÊý¾Ý£¬Êý¾Ý³¤¶È²»Äܳ¬¹ý10M
367 BOOL CHwSMTP::Send(CString &str )
369 if ( !m_bConnected )
371 m_csLastError.Format ( _T("Didn't connect") );
372 return FALSE;
375 CMultiByteString cbsData ( str );
377 TRACE ( _T("Send : %s\r\n"), cbsData.GetBuffer() );
378 if ( m_SendSock.Send ( cbsData.GetBuffer(), cbsData.GetLength() ) != cbsData.GetLength() )
380 m_csLastError.Format ( _T("Socket send data failed") );
381 return FALSE;
384 return TRUE;
387 BOOL CHwSMTP::SendEmail()
389 BOOL bRet = TRUE;
390 char szLocalHostName[64] = {0};
391 gethostname ( (char*)szLocalHostName, sizeof(szLocalHostName) );
393 // hello£¬ÎÕÊÖ
394 CString str;
395 str.Format(_T("HELO %s\r\n"), GetCompatibleString(szLocalHostName,FALSE));
396 if ( !Send ( str ))
398 return FALSE;
400 if ( !GetResponse ( _T("250") ) )
402 return FALSE;
404 // Éí·ÝÑéÖ¤
405 if ( m_bMustAuth && !auth() )
407 return FALSE;
409 // ·¢ËÍÓʼþÍ·
410 if ( !SendHead() )
412 return FALSE;
414 // ·¢ËÍÓʼþÖ÷Ìâ
415 if ( !SendSubject() )
417 return FALSE;
419 // ·¢ËÍÓʼþÕýÎÄ
420 if ( !SendBody() )
422 return FALSE;
424 // ·¢Ë͸½¼þ
425 if ( !SendAttach() )
427 return FALSE;
429 // ½áÊøÓʼþÕýÎÄ
430 if ( !Send ( CString(_T(".\r\n") ) ) ) return FALSE;
431 if ( !GetResponse ( _T("250") ) )
432 return FALSE;
434 // Í˳ö·¢ËÍ
435 if ( HANDLE_IS_VALID(m_SendSock.m_hSocket) )
436 Send ( CString(_T("QUIT\r\n")) );
437 m_bConnected = FALSE;
439 return bRet;
442 BOOL CHwSMTP::auth()
444 int nResponseCode = 0;
445 if ( !Send ( CString(_T("auth login\r\n")) ) ) return FALSE;
446 if ( !GetResponse ( _T("334"), &nResponseCode ) ) return FALSE;
447 if ( nResponseCode != 334 ) // ²»ÐèÒªÑéÖ¤Óû§ÃûºÍÃÜÂë
448 return TRUE;
450 CBase64 Base64Encode;
451 CMultiByteString cbsUserName ( m_csUserName ), cbsPasswd ( m_csPasswd );
452 CString csBase64_UserName = GetCompatibleString ( Base64Encode.Encode ( cbsUserName.GetBuffer(), cbsUserName.GetLength() ).GetBuffer(0), FALSE );
453 CString csBase64_Passwd = GetCompatibleString ( Base64Encode.Encode ( cbsPasswd.GetBuffer(), cbsPasswd.GetLength() ).GetBuffer(0), FALSE );
455 CString str;
456 str.Format( _T("%s\r\n"), csBase64_UserName );
457 if ( !Send ( str ) )
458 return FALSE;
460 if ( !GetResponse ( _T("334") ) )
462 m_csLastError.Format ( _T("Authentication UserName failed") );
463 return FALSE;
466 str.Format(_T("%s\r\n"), csBase64_Passwd );
467 if ( !Send ( str ) )
468 return FALSE;
470 if ( !GetResponse ( _T("235") ) )
472 m_csLastError.Format ( _T("Authentication Password failed") );
473 return FALSE;
476 return TRUE;
479 BOOL CHwSMTP::SendHead()
481 CString str;
482 CString name,addr;
483 GetNameAddress(m_csAddrFrom,name,addr);
485 str.Format( _T("MAIL From: <%s>\r\n"), addr );
486 if ( !Send ( str ) ) return FALSE;
488 if ( !GetResponse ( _T("250") ) ) return FALSE;
490 int start=0;
491 while(start>=0)
493 CString one=m_csAddrTo.Tokenize(_T(";"),start);
494 one=one.Trim();
495 if(one.IsEmpty())
496 continue;
499 GetNameAddress(one,name,addr);
501 str.Format(_T("RCPT TO: <%s>\r\n"), addr );
502 if ( !Send ( str ) ) return FALSE;
503 if ( !GetResponse ( _T("250") ) ) return FALSE;
506 #if 0
507 for ( int i=0; i<m_StrAryCC.GetSize(); i++ )
509 str.Format(_T("RCPT TO: <%s>\r\n"), m_StrAryCC.GetAt(i) );
510 if ( !Send ( str ) ) return FALSE;
511 if ( !GetResponse ( _T("250") ) ) return FALSE;
513 #endif
515 if ( !Send ( CString(_T("DATA\r\n") ) ) ) return FALSE;
516 if ( !GetResponse ( CString(_T("354") )) ) return FALSE;
518 return TRUE;
521 BOOL CHwSMTP::SendSubject()
523 CString csSubject;
524 csSubject += _T("Date: ");
525 COleDateTime tNow = COleDateTime::GetCurrentTime();
526 if ( tNow > 1 )
528 csSubject += FormatDateTime (tNow, _T("%a, %d %b %y %H:%M:%S %Z"));
530 csSubject += _T("\r\n");
531 csSubject += FormatString ( _T("From: %s\r\n"), this->m_csAddrFrom);
533 csSubject += FormatString ( _T("CC: %s\r\n"), this->m_StrCC);
535 if(m_csSender.IsEmpty())
536 m_csSender = this->m_csAddrFrom;
538 csSubject += FormatString ( _T("Sender: %s\r\n"), this->m_csSender);
540 if(this->m_csToList.IsEmpty())
541 m_csToList = m_csReceiverName;
543 csSubject += FormatString ( _T("To: %s\r\n"), this->m_csToList);
545 CString m_csToList;
547 csSubject += FormatString ( _T("Subject: %s\r\n"), m_csSubject );
549 csSubject += FormatString ( _T("X-Mailer: TortoiseGit\r\nMIME-Version: 1.0\r\nContent-Type: %s\r\n\r\n"),
550 m_csMIMEContentType );
552 return Send ( csSubject );
555 BOOL CHwSMTP::SendBody()
557 CString csBody, csTemp;
559 if ( m_StrAryAttach.GetSize() > 0 )
561 csTemp.Format ( _T("%s\r\n\r\n"), m_csNoMIMEText );
562 csBody += csTemp;
564 csTemp.Format ( _T("--%s\r\n"), m_csPartBoundary );
565 csBody += csTemp;
567 csTemp.Format ( _T("Content-Type: text/plain\r\n%sContent-Transfer-Encoding: UTF-8\r\n\r\n"),
568 m_csCharSet );
569 csBody += csTemp;
572 //csTemp.Format ( _T("%s\r\n"), m_csBody );
573 csBody += m_csBody;
574 csBody += _T("\r\n");
576 return Send ( csBody );
579 BOOL CHwSMTP::SendAttach()
581 int nCountAttach = (int)m_StrAryAttach.GetSize();
582 if ( nCountAttach < 1 ) return TRUE;
584 for ( int i=0; i<nCountAttach; i++ )
586 if ( !SendOnAttach ( m_StrAryAttach.GetAt(i) ) )
587 return FALSE;
590 return TRUE;
593 BOOL CHwSMTP::SendOnAttach(LPCTSTR lpszFileName)
595 ASSERT ( lpszFileName );
596 CString csAttach, csTemp;
598 csTemp = lpszFileName;
599 CString csShortFileName = csTemp.GetBuffer(0) + csTemp.ReverseFind ( '\\' );
600 csShortFileName.TrimLeft ( _T("\\") );
602 csTemp.Format ( _T("--%s\r\n"), m_csPartBoundary );
603 csAttach += csTemp;
605 csTemp.Format ( _T("Content-Type: application/octet-stream; file=%s\r\n"), csShortFileName );
606 csAttach += csTemp;
608 csTemp.Format ( _T("Content-Transfer-Encoding: base64\r\n") );
609 csAttach += csTemp;
611 csTemp.Format ( _T("Content-Disposition: attachment; filename=%s\r\n\r\n"), csShortFileName );
612 csAttach += csTemp;
614 DWORD dwFileSize = hwGetFileAttr(lpszFileName);
615 if ( dwFileSize > 5*1024*1024 )
617 m_csLastError.Format ( _T("File [%s] too big. File size is : %s"), lpszFileName, FormatBytes(dwFileSize) );
618 return FALSE;
620 char *pBuf = new char[dwFileSize+1];
621 if ( !pBuf )
623 ::AfxThrowMemoryException ();
624 return FALSE;
627 if(!Send ( csAttach ))
629 delete[] pBuf;
630 return FALSE;
633 CFile file;
634 CStringA filedata;
637 if ( !file.Open ( lpszFileName, CFile::modeRead ) )
639 m_csLastError.Format ( _T("Open file [%s] failed"), lpszFileName );
640 delete[] pBuf;
641 return FALSE;
643 UINT nFileLen = file.Read ( pBuf, dwFileSize );
644 CBase64 Base64Encode;
645 filedata = Base64Encode.Encode ( pBuf, nFileLen );
646 filedata += _T("\r\n\r\n");
648 catch (CFileException *e)
650 e->Delete();
651 m_csLastError.Format ( _T("Read file [%s] failed"), lpszFileName );
652 delete[] pBuf;
653 return FALSE;
656 if(!SendBuffer( filedata.GetBuffer() ))
658 delete[] pBuf;
659 return FALSE;
662 delete[] pBuf;
664 return TRUE;
665 //return Send ( csAttach );
668 CString CHwSMTP::GetLastErrorText()
670 return m_csLastError;
674 DWORD WINAPI ThreadProc_SendEmail( LPVOID lpParameter )
676 CEMailObject *pEMailObject = (CEMailObject*)lpParameter;
677 ASSERT ( pEMailObject );
679 CHwSMTP HwSMTP;
680 BOOL bRet = HwSMTP.SendEmail (
681 pEMailObject->m_csSmtpSrvHost,
682 pEMailObject->m_csUserName,
683 pEMailObject->m_csPasswd,
684 pEMailObject->m_bMustAuth,
685 pEMailObject->m_csAddrFrom,
686 pEMailObject->m_csAddrTo,
687 pEMailObject->m_csSubject,
688 pEMailObject->m_csBody,
689 pEMailObject->m_csCharSet,
690 &pEMailObject->m_StrAryAttach,
691 pEMailObject->m_StrCC,
692 pEMailObject->m_nSmtpSrvPort,
693 pEMailObject->m_csSender
695 if ( !bRet)
697 #ifdef _DEBUG
698 CString csError = HwSMTP.GetLastErrorText ();
699 csError = FormatString ( _T("Send a email to [%s] failed."), pEMailObject->m_csSmtpSrvHost );
700 AfxMessageBox ( csError );
701 #endif
704 m_CSFor__g_PtrAry_Threads.Lock ();
705 int nFindPos = FindFromArray ( g_PtrAry_Threads, pEMailObject->m_hThread );
706 if ( nFindPos >= 0 )
707 g_PtrAry_Threads.RemoveAt ( nFindPos );
708 m_CSFor__g_PtrAry_Threads.Unlock ();
710 delete pEMailObject;
711 return bRet;
715 // Óà SMTP ·þÎñ·¢Ë͵ç×ÓÓʼþ£¬Èç¹ûÉèÖòÎÊý bViaThreadSend=TRUE£¬ÄÇÔÚ³ÌÐò½áÊøʱӦ¸ÃÔÚ ExitInstance() Öе÷Óà EndOfSMTP() º¯Êý
717 BOOL SendEmail (
718 BOOL bViaThreadSend,
719 LPCTSTR lpszSmtpSrvHost,
720 LPCTSTR lpszUserName,
721 LPCTSTR lpszPasswd,
722 BOOL bMustAuth,
723 LPCTSTR lpszAddrFrom,
724 LPCTSTR lpszAddrTo,
725 LPCTSTR lpszFromName,
726 LPCTSTR lpszReceiverName,
727 LPCTSTR lpszSubject,
728 LPCTSTR lpszBody,
729 LPCTSTR lpszCharSet/*=NULL*/,
730 CStringArray *pStrAryAttach/*=NULL*/,
731 LPCTSTR pStrAryCC/*=NULL*/,
732 UINT nSmtpSrvPort/*=25*/,
733 LPCTSTR lpszSender,
734 LPCTSTR lpszToList
737 if ( !lpszSmtpSrvHost || lstrlen(lpszSmtpSrvHost) < 1 ||
738 !lpszSubject || lstrlen(lpszSubject) < 1 ||
739 !lpszBody || lstrlen(lpszBody) < 1 )
741 AfxMessageBox ( _T("Parameter error !") );
742 return FALSE;
745 CEMailObject *pEMailObject = new CEMailObject (
746 lpszSmtpSrvHost,
747 lpszUserName,
748 lpszPasswd,
749 bMustAuth,
750 lpszAddrFrom,
751 lpszAddrTo,
752 lpszFromName,
753 lpszReceiverName,
754 lpszSubject,
755 lpszBody,
756 lpszCharSet,
757 pStrAryAttach,
758 pStrAryCC,
759 nSmtpSrvPort,
760 lpszSender,
761 lpszToList
763 if ( !pEMailObject ) return FALSE;
765 BOOL bRet = FALSE;
766 if ( bViaThreadSend )
768 DWORD dwThreadId = 0;
769 pEMailObject->m_hThread = ::CreateThread ( NULL, 0, ::ThreadProc_SendEmail, pEMailObject, CREATE_SUSPENDED, &dwThreadId );
770 bRet = HANDLE_IS_VALID(pEMailObject->m_hThread);
771 m_CSFor__g_PtrAry_Threads.Lock();
772 g_PtrAry_Threads.Add ( pEMailObject->m_hThread );
773 m_CSFor__g_PtrAry_Threads.Unlock();
774 ResumeThread ( pEMailObject->m_hThread );
776 else
778 bRet = (BOOL)ThreadProc_SendEmail ( pEMailObject );
781 return bRet;
784 void EndOfSMTP ()
786 // µÈ´ýËùÓÐÏß³ÌÖ´ÐÐÍê±Ï
787 for ( int i=0; i<g_PtrAry_Threads.GetSize(); i++ )
789 HANDLE hThread = (HANDLE)g_PtrAry_Threads.GetAt(i);
790 if ( HANDLE_IS_VALID(hThread) )
792 WaitForThreadEnd ( &hThread, 30*1000 );
795 g_PtrAry_Threads.RemoveAll ();
800 // ½«×Ö·û´® lpszOrg ת»»Îª¶à×Ö½ÚµÄ×Ö·û´®£¬Èç¹û»¹ÒªÊ¹Óöà×Ö·û´®µÄ³¤¶È£¬¿ÉÒÔÓÃÒÔÏ·½Ê½À´Ê¹ÓÃÕâ¸öÀࣺ
801 // CMultiByteString MultiByteString(_T("UNICODE×Ö·û´®"));
802 // printf ( "ANSI ×Ö·û´®Îª£º %s£¬ ×Ö·û¸öÊýΪ£º %d £¬ ³¤¶ÈΪ£º %d×Ö½Ú\n", MultiByteString.GetBuffer(), MultiByteString.GetLength(), MultiByteString.GetSize() );
804 CMultiByteString::CMultiByteString( LPCTSTR lpszOrg, int nOrgStringEncodeType/*=STRING_IS_SOFTCODE*/, OUT char *pOutBuf/*=NULL*/, int nOutBufSize/*=0*/ )
806 m_bNewBuffer = FALSE;
807 m_pszData = NULL;
808 m_nDataSize = 0;
809 m_nCharactersNumber = 0;
810 if ( !lpszOrg ) return;
812 BOOL bOrgIsUnicode = FALSE;
813 if ( nOrgStringEncodeType == STRING_IS_MULTICHARS ) bOrgIsUnicode = FALSE;
814 else if ( nOrgStringEncodeType == STRING_IS_UNICODE ) bOrgIsUnicode = TRUE;
815 else
817 #ifdef UNICODE
818 bOrgIsUnicode = TRUE;
819 #else
820 bOrgIsUnicode = FALSE;
821 #endif
824 if ( bOrgIsUnicode )
826 m_nCharactersNumber = (int)wcslen((WCHAR*)lpszOrg);
827 m_nDataSize = (m_nCharactersNumber + 1) * sizeof(WCHAR);
829 else
831 m_nCharactersNumber = (int)strlen((char*)lpszOrg);
832 m_nDataSize = (m_nCharactersNumber + 1) * sizeof(char);
835 if ( pOutBuf && nOutBufSize > 0 )
837 m_pszData = pOutBuf;
838 m_nDataSize = nOutBufSize;
840 else
842 m_pszData = (char*)new BYTE[m_nDataSize];
843 if ( !m_pszData )
845 ::AfxThrowMemoryException ();
846 return;
848 m_bNewBuffer = TRUE;
850 memset ( m_pszData, 0, m_nDataSize );
852 if ( bOrgIsUnicode )
854 m_nCharactersNumber = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR)lpszOrg, m_nCharactersNumber, (LPSTR)m_pszData, m_nDataSize / sizeof(char) - 1, NULL, NULL);
855 if ( m_nCharactersNumber < 1 ) m_nCharactersNumber = (int)strlen ( m_pszData );
857 else
859 m_nCharactersNumber = __min ( m_nCharactersNumber, (int)(m_nDataSize/sizeof(char)-1) );
860 strncpy ( m_pszData, (const char*)lpszOrg, m_nCharactersNumber );
861 m_nCharactersNumber = (int)strlen ( m_pszData );
863 m_nDataSize = ( m_nCharactersNumber + 1 ) * sizeof(char);
866 CMultiByteString::~CMultiByteString ()
868 if ( m_bNewBuffer && m_pszData )
870 delete[] m_pszData;
874 CString GetCompatibleString ( LPVOID lpszOrg, BOOL bOrgIsUnicode, int nOrgLength/*=-1*/ )
876 if ( !lpszOrg ) return _T("");
880 #ifdef UNICODE
881 if ( bOrgIsUnicode )
883 if ( nOrgLength > 0 )
885 WCHAR *szRet = new WCHAR[nOrgLength+1];
886 if ( !szRet ) return _T("");
887 memset ( szRet, 0, (nOrgLength+1)*sizeof(WCHAR) );
888 memcpy ( szRet, lpszOrg, nOrgLength*sizeof(WCHAR) );
889 CString csRet = szRet;
890 delete[] szRet;
891 return csRet;
893 else if ( nOrgLength == 0 )
894 return _T("");
895 else
896 return (LPCTSTR)lpszOrg;
899 if ( nOrgLength < 0 )
900 nOrgLength = (int)strlen((const char*)lpszOrg);
901 int nWideCount = nOrgLength + 1;
902 WCHAR *wchar = new WCHAR[nWideCount];
903 if ( !wchar ) return _T("");
904 memset ( wchar, 0, nWideCount*sizeof(WCHAR) );
905 ::MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)lpszOrg, nOrgLength, wchar, nWideCount);
906 CString csRet = wchar;
907 delete[] wchar;
908 return csRet;
909 #else
910 if ( !bOrgIsUnicode )
912 if ( nOrgLength > 0 )
914 char *szRet = new char[nOrgLength+1];
915 if ( !szRet ) return _T("");
916 memset ( szRet, 0, (nOrgLength+1)*sizeof(char) );
917 memcpy ( szRet, lpszOrg, nOrgLength*sizeof(char) );
918 CString csRet = szRet;
919 delete[] szRet;
920 return csRet;
922 else if ( nOrgLength == 0 )
923 return _T("");
924 else
925 return (LPCTSTR)lpszOrg;
928 if ( nOrgLength < 0 )
929 nOrgLength = (int)wcslen((WCHAR*)lpszOrg);
930 int nMultiByteCount = nOrgLength + 1;
931 char *szMultiByte = new char[nMultiByteCount];
932 if ( !szMultiByte ) return _T("");
933 memset ( szMultiByte, 0, nMultiByteCount*sizeof(char) );
934 ::WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR)lpszOrg, nOrgLength, (LPSTR)szMultiByte, nMultiByteCount, NULL, NULL);
935 CString csRet = szMultiByte;
936 delete[] szMultiByte;
937 return csRet;
938 #endif
940 CATCH_ALL(e)
942 THROW_LAST ();
944 END_CATCH_ALL
946 return _T("");
949 CString FormatDateTime ( COleDateTime &DateTime, LPCTSTR pFormat )
951 // If null, return empty string
952 if ( DateTime.GetStatus() == COleDateTime::null || DateTime.GetStatus() == COleDateTime::invalid )
953 return _T("");
955 UDATE ud;
956 if (S_OK != VarUdateFromDate(DateTime.m_dt, 0, &ud))
958 return _T("");
961 TCHAR *weeks[]={_T("Sun"),_T("Mon"),_T("Tue"),_T("Wen"),_T("Thu"),_T("Fri"),_T("Sat")};
962 TCHAR *month[]={_T("JAN"),_T("FEB"),_T("MAR"),_T("APR"),
963 _T("MAY"),_T("JUN"),_T("JUL"),_T("AUG"),
964 _T("SEP"),_T("OCT"),_T("NOV"),_T("DEC")};
966 TIME_ZONE_INFORMATION stTimeZone;
967 GetTimeZoneInformation(&stTimeZone);
969 CString strDate;
970 strDate.Format(_T("%s, %d %s %02d %d:%d:%d %c%04d")
971 ,weeks[ud.st.wDayOfWeek],
972 ud.st.wDay,month[ud.st.wMonth-1],ud.st.wYear%100,ud.st.wHour,
973 ud.st.wMinute,ud.st.wSecond,
974 stTimeZone.Bias>0?_T('-'):_T('+'),
975 abs(stTimeZone.Bias*10/6)
977 return strDate;
980 CString FormatString ( LPCTSTR lpszStr, ... )
982 TCHAR *buf = NULL;
983 for ( int nBufCount = 1024; nBufCount<5*1024*1024; nBufCount += 1024 )
985 buf = new TCHAR[nBufCount];
986 if ( !buf )
988 ::AfxThrowMemoryException ();
989 return _T("");
991 memset ( buf, 0, nBufCount*sizeof(TCHAR) );
993 va_list va;
994 va_start (va, lpszStr);
995 int nLen = _vsnprintf_hw ((TCHAR*)buf, nBufCount-sizeof(TCHAR), lpszStr, va);
996 va_end(va);
997 if ( nLen <= (int)(nBufCount-sizeof(TCHAR)) )
998 break;
999 delete[] buf; buf = NULL;
1001 if ( !buf )
1003 return _T("");
1006 CString csMsg = buf;
1007 delete[] buf; buf = NULL;
1008 return csMsg;
1011 int hwGetFileAttr ( LPCTSTR lpFileName, OUT CFileStatus *pFileStatus/*=NULL*/ )
1013 if ( !lpFileName || lstrlen(lpFileName) < 1 ) return -1;
1015 CFileStatus fileStatus;
1016 fileStatus.m_attribute = 0;
1017 fileStatus.m_size = 0;
1018 memset ( fileStatus.m_szFullName, 0, sizeof(fileStatus.m_szFullName) );
1019 BOOL bRet = FALSE;
1022 if ( CFile::GetStatus(lpFileName,fileStatus) )
1024 bRet = TRUE;
1027 CATCH (CFileException, e)
1029 ASSERT ( FALSE );
1030 bRet = FALSE;
1032 CATCH_ALL(e)
1034 ASSERT ( FALSE );
1035 bRet = FALSE;
1037 END_CATCH_ALL;
1039 if ( pFileStatus )
1041 pFileStatus->m_ctime = fileStatus.m_ctime;
1042 pFileStatus->m_mtime = fileStatus.m_mtime;
1043 pFileStatus->m_atime = fileStatus.m_atime;
1044 pFileStatus->m_size = fileStatus.m_size;
1045 pFileStatus->m_attribute = fileStatus.m_attribute;
1046 lstrcpy ( pFileStatus->m_szFullName, fileStatus.m_szFullName );
1050 return (int)fileStatus.m_size;
1053 CString FormatBytes ( double fBytesNum, BOOL bShowUnit/*=TRUE*/, int nFlag/*=0*/ )
1055 CString csRes;
1056 if ( nFlag == 0 )
1058 if ( fBytesNum >= 1024.0 && fBytesNum < 1024.0*1024.0 )
1059 csRes.Format ( _T("%.2f%s"), fBytesNum / 1024.0, bShowUnit?_T(" K"):_T("") );
1060 else if ( fBytesNum >= 1024.0*1024.0 && fBytesNum < 1024.0*1024.0*1024.0 )
1061 csRes.Format ( _T("%.2f%s"), fBytesNum / (1024.0*1024.0), bShowUnit?_T(" M"):_T("") );
1062 else if ( fBytesNum >= 1024.0*1024.0*1024.0 )
1063 csRes.Format ( _T("%.2f%s"), fBytesNum / (1024.0*1024.0*1024.0), bShowUnit?_T(" G"):_T("") );
1064 else
1065 csRes.Format ( _T("%.2f%s"), fBytesNum, bShowUnit?_T(" B"):_T("") );
1067 else if ( nFlag == 1 )
1069 csRes.Format ( _T("%.2f%s"), fBytesNum / 1024.0, bShowUnit?_T(" K"):_T("") );
1071 else if ( nFlag == 2 )
1073 csRes.Format ( _T("%.2f%s"), fBytesNum / (1024.0*1024.0), bShowUnit?_T(" M"):_T("") );
1075 else if ( nFlag == 3 )
1077 csRes.Format ( _T("%.2f%s"), fBytesNum / (1024.0*1024.0*1024.0), bShowUnit?_T(" G"):_T("") );
1080 return csRes;
1084 // µÈ´ýÏß³ÌÍ˳ö
1086 BOOL WaitForThreadEnd ( HANDLE *phThread, DWORD dwWaitTime /*=10*1000*/ )
1088 BOOL bRet = TRUE;
1089 ASSERT ( phThread );
1090 if ( !(*phThread) ) return TRUE;
1091 if ( ::WaitForSingleObject ( *phThread, dwWaitTime ) == WAIT_TIMEOUT )
1093 bRet = FALSE;
1094 ::TerminateThread ( *phThread, 0 );
1096 ::CloseHandle ( *phThread );
1097 (*phThread) = NULL;
1098 return bRet;