Fixed issue #124: Incorrect Date header in patch e-mail
[TortoiseGit.git] / src / Utils / HwSMTP.cpp
blob406f4b64dece25e969d5188b370bc334d54d86ad
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, // ×Ö·û¼¯ÀàÐÍ£¬ÀýÈ磺·±ÌåÖÐÎÄÕâÀïÓ¦ÊäÈë"big5"£¬¼òÌåÖÐÎÄʱÊäÈë"gb2312"
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;
181 Address[addr].push_back(one);
185 std::map<CString,std::vector<CString>>::iterator itr1 = Address.begin();
186 for( ; itr1 != Address.end(); ++itr1 )
188 PDNS_RECORD pDnsRecord;
189 PDNS_RECORD pNext;
191 DnsQuery(itr1->first ,
192 DNS_TYPE_MX,DNS_QUERY_STANDARD,
193 NULL, //Contains DNS server IP address.
194 &pDnsRecord, //Resource record that contains the response.
195 NULL
198 CString to;
199 to.Empty();
200 for(int i=0;i<itr1->second.size();i++)
202 to+=itr1->second[i];
203 to+=_T(";");
205 if(to.IsEmpty())
206 continue;
208 pNext=pDnsRecord;
209 while(pNext)
211 if(pNext->wType == DNS_TYPE_MX)
212 if(SendEmail(pNext->Data.MX.pNameExchange,NULL,NULL,false,
213 lpszAddrFrom,to,lpszSubject,lpszBody,lpszCharSet,pStrAryAttach,pStrAryCC,
214 25,pSend,lpszAddrTo))
215 break;
216 pNext=pNext->pNext;
218 if(pNext == NULL)
219 ret = false;
221 //SendEmail(itr1.first,NULL,NULL,false,lpszAddrFrom,,lpszFromname);
222 DnsRecordListFree(pDnsRecord,DnsFreeRecordList);
225 return ret;
227 BOOL CHwSMTP::SendEmail (
228 LPCTSTR lpszSmtpSrvHost,
229 LPCTSTR lpszUserName,
230 LPCTSTR lpszPasswd,
231 BOOL bMustAuth,
232 LPCTSTR lpszAddrFrom,
233 LPCTSTR lpszAddrTo,
234 LPCTSTR lpszSubject,
235 LPCTSTR lpszBody,
236 LPCTSTR lpszCharSet, // ×Ö·û¼¯ÀàÐÍ£¬ÀýÈ磺·±ÌåÖÐÎÄÕâÀïÓ¦ÊäÈë"big5"£¬¼òÌåÖÐÎÄʱÊäÈë"gb2312"
237 CStringArray *pStrAryAttach/*=NULL*/,
238 LPCTSTR pStrAryCC/*=NULL*/,
239 UINT nSmtpSrvPort,/*=25*/
240 LPCTSTR pSender,
241 LPCTSTR pToList
244 TRACE ( _T("·¢ËÍÓʼþ£º%s, %s\n"), lpszAddrTo, lpszBody );
245 m_StrAryAttach.RemoveAll();
247 m_StrCC += GET_SAFE_STRING(pStrAryCC);
249 m_csSmtpSrvHost = GET_SAFE_STRING ( lpszSmtpSrvHost );
250 if ( m_csSmtpSrvHost.GetLength() <= 0 )
252 m_csLastError.Format ( _T("Parameter Error!") );
253 return FALSE;
255 m_csUserName = GET_SAFE_STRING ( lpszUserName );
256 m_csPasswd = GET_SAFE_STRING ( lpszPasswd );
257 m_bMustAuth = bMustAuth;
258 if ( m_bMustAuth && m_csUserName.GetLength() <= 0 )
260 m_csLastError.Format ( _T("Parameter Error!") );
261 return FALSE;
264 m_csAddrFrom = GET_SAFE_STRING ( lpszAddrFrom );
265 m_csAddrTo = GET_SAFE_STRING ( lpszAddrTo );
266 // m_csFromName = GET_SAFE_STRING ( lpszFromName );
267 // m_csReceiverName = GET_SAFE_STRING ( lpszReceiverName );
268 m_csSubject = GET_SAFE_STRING ( lpszSubject );
269 m_csBody = GET_SAFE_STRING ( lpszBody );
271 this->m_csSender = GET_SAFE_STRING(pSender);
272 this->m_csToList = GET_SAFE_STRING(pToList);
274 m_nSmtpSrvPort = nSmtpSrvPort;
276 if ( lpszCharSet && lstrlen(lpszCharSet) > 0 )
277 m_csCharSet.Format ( _T("\r\n\tcharset=\"%s\"\r\n"), lpszCharSet );
279 if (
280 m_csAddrFrom.GetLength() <= 0 || m_csAddrTo.GetLength() <= 0
283 m_csLastError.Format ( _T("Parameter Error!") );
284 return FALSE;
287 if ( pStrAryAttach )
289 m_StrAryAttach.Append ( *pStrAryAttach );
291 if ( m_StrAryAttach.GetSize() < 1 )
292 m_csMIMEContentType = FormatString ( _T( "text/plain; %s" ), m_csCharSet);
294 // ´´½¨Socket
295 m_SendSock.Close();
296 if ( !m_SendSock.Create () )
298 int nResult = GetLastError();
299 m_csLastError.Format ( _T("Create socket failed!") );
300 return FALSE;
303 // Á¬½Óµ½·þÎñÆ÷
304 if ( !m_SendSock.Connect ( m_csSmtpSrvHost, m_nSmtpSrvPort ) )
306 m_csLastError.Format ( _T("Connect to [ %s ] failed"), m_csSmtpSrvHost );
307 TRACE ( _T("%d\n"), GetLastError() );
308 return FALSE;
310 if ( !GetResponse( _T("220") ) ) return FALSE;
312 m_bConnected = TRUE;
313 BOOL ret= SendEmail();
315 m_SendSock.Close();
317 return ret;
321 BOOL CHwSMTP::GetResponse ( LPCTSTR lpszVerifyCode, int *pnCode/*=NULL*/)
323 if ( !lpszVerifyCode || lstrlen(lpszVerifyCode) < 1 )
324 return FALSE;
326 char szRecvBuf[1024] = {0};
327 int nRet = 0;
328 char szStatusCode[4] = {0};
329 nRet = m_SendSock.Receive ( szRecvBuf, sizeof(szRecvBuf) );
330 TRACE ( _T("Received : %s\r\n"), szRecvBuf );
331 if ( nRet <= 0 )
333 m_csLastError.Format ( _T("Receive TCP data failed") );
334 return FALSE;
336 // TRACE ( _T("ÊÕµ½·þÎñÆ÷»ØÓ¦£º%s\n"), szRecvBuf );
338 memcpy ( szStatusCode, szRecvBuf, 3 );
339 if ( pnCode ) (*pnCode) = atoi ( szStatusCode );
341 if ( strcmp ( szStatusCode, CMultiByteString(lpszVerifyCode).GetBuffer() ) != 0 )
343 m_csLastError.Format ( _T("Received invalid response : %s"), GetCompatibleString(szRecvBuf,FALSE) );
344 return FALSE;
347 return TRUE;
349 BOOL CHwSMTP::SendBuffer(char *buff,int size)
351 if(size<0)
352 size=strlen(buff);
353 if ( !m_bConnected )
355 m_csLastError.Format ( _T("Didn't connect") );
356 return FALSE;
359 if ( m_SendSock.Send ( buff, size ) != size )
361 m_csLastError.Format ( _T("Socket send data failed") );
362 return FALSE;
365 return TRUE;
367 // ÀûÓÃsocket·¢ËÍÊý¾Ý£¬Êý¾Ý³¤¶È²»Äܳ¬¹ý10M
368 BOOL CHwSMTP::Send(CString &str )
370 if ( !m_bConnected )
372 m_csLastError.Format ( _T("Didn't connect") );
373 return FALSE;
376 CMultiByteString cbsData ( str );
378 TRACE ( _T("Send : %s\r\n"), cbsData.GetBuffer() );
379 if ( m_SendSock.Send ( cbsData.GetBuffer(), cbsData.GetLength() ) != cbsData.GetLength() )
381 m_csLastError.Format ( _T("Socket send data failed") );
382 return FALSE;
385 return TRUE;
388 BOOL CHwSMTP::SendEmail()
390 BOOL bRet = TRUE;
391 char szLocalHostName[64] = {0};
392 gethostname ( (char*)szLocalHostName, sizeof(szLocalHostName) );
394 // hello£¬ÎÕÊÖ
395 CString str;
396 str.Format(_T("HELO %s\r\n"), GetCompatibleString(szLocalHostName,FALSE));
397 if ( !Send ( str ))
399 return FALSE;
401 if ( !GetResponse ( _T("250") ) )
403 return FALSE;
405 // Éí·ÝÑéÖ¤
406 if ( m_bMustAuth && !auth() )
408 return FALSE;
410 // ·¢ËÍÓʼþÍ·
411 if ( !SendHead() )
413 return FALSE;
415 // ·¢ËÍÓʼþÖ÷Ìâ
416 if ( !SendSubject() )
418 return FALSE;
420 // ·¢ËÍÓʼþÕýÎÄ
421 if ( !SendBody() )
423 return FALSE;
425 // ·¢Ë͸½¼þ
426 if ( !SendAttach() )
428 return FALSE;
430 // ½áÊøÓʼþÕýÎÄ
431 if ( !Send ( CString(_T(".\r\n") ) ) ) return FALSE;
432 if ( !GetResponse ( _T("250") ) )
433 return FALSE;
435 // Í˳ö·¢ËÍ
436 if ( HANDLE_IS_VALID(m_SendSock.m_hSocket) )
437 Send ( CString(_T("QUIT\r\n")) );
438 m_bConnected = FALSE;
440 return bRet;
443 BOOL CHwSMTP::auth()
445 int nResponseCode = 0;
446 if ( !Send ( CString(_T("auth login\r\n")) ) ) return FALSE;
447 if ( !GetResponse ( _T("334"), &nResponseCode ) ) return FALSE;
448 if ( nResponseCode != 334 ) // ²»ÐèÒªÑéÖ¤Óû§ÃûºÍÃÜÂë
449 return TRUE;
451 CBase64 Base64Encode;
452 CMultiByteString cbsUserName ( m_csUserName ), cbsPasswd ( m_csPasswd );
453 CString csBase64_UserName = GetCompatibleString ( Base64Encode.Encode ( cbsUserName.GetBuffer(), cbsUserName.GetLength() ).GetBuffer(0), FALSE );
454 CString csBase64_Passwd = GetCompatibleString ( Base64Encode.Encode ( cbsPasswd.GetBuffer(), cbsPasswd.GetLength() ).GetBuffer(0), FALSE );
456 CString str;
457 str.Format( _T("%s\r\n"), csBase64_UserName );
458 if ( !Send ( str ) )
459 return FALSE;
461 if ( !GetResponse ( _T("334") ) )
463 m_csLastError.Format ( _T("Authentication UserName failed") );
464 return FALSE;
467 str.Format(_T("%s\r\n"), csBase64_Passwd );
468 if ( !Send ( str ) )
469 return FALSE;
471 if ( !GetResponse ( _T("235") ) )
473 m_csLastError.Format ( _T("Authentication Password failed") );
474 return FALSE;
477 return TRUE;
480 BOOL CHwSMTP::SendHead()
482 CString str;
483 CString name,addr;
484 GetNameAddress(m_csAddrFrom,name,addr);
486 str.Format( _T("MAIL From: <%s>\r\n"), addr );
487 if ( !Send ( str ) ) return FALSE;
489 if ( !GetResponse ( _T("250") ) ) return FALSE;
491 int start=0;
492 while(start>=0)
494 CString one=m_csAddrTo.Tokenize(_T(";"),start);
495 one=one.Trim();
496 if(one.IsEmpty())
497 continue;
500 GetNameAddress(one,name,addr);
502 str.Format(_T("RCPT TO: <%s>\r\n"), addr );
503 if ( !Send ( str ) ) return FALSE;
504 if ( !GetResponse ( _T("250") ) ) return FALSE;
507 #if 0
508 for ( int i=0; i<m_StrAryCC.GetSize(); i++ )
510 str.Format(_T("RCPT TO: <%s>\r\n"), m_StrAryCC.GetAt(i) );
511 if ( !Send ( str ) ) return FALSE;
512 if ( !GetResponse ( _T("250") ) ) return FALSE;
514 #endif
516 if ( !Send ( CString(_T("DATA\r\n") ) ) ) return FALSE;
517 if ( !GetResponse ( CString(_T("354") )) ) return FALSE;
519 return TRUE;
522 BOOL CHwSMTP::SendSubject()
524 CString csSubject;
525 csSubject += _T("Date: ");
526 COleDateTime tNow = COleDateTime::GetCurrentTime();
527 if ( tNow > 1 )
529 csSubject += FormatDateTime (tNow, _T("%a, %d %b %y %H:%M:%S %Z"));
531 csSubject += _T("\r\n");
532 csSubject += FormatString ( _T("From: %s\r\n"), this->m_csAddrFrom);
534 csSubject += FormatString ( _T("CC: %s\r\n"), this->m_StrCC);
536 if(m_csSender.IsEmpty())
537 m_csSender = this->m_csAddrFrom;
539 csSubject += FormatString ( _T("Sender: %s\r\n"), this->m_csSender);
541 if(this->m_csToList.IsEmpty())
542 m_csToList = m_csReceiverName;
544 csSubject += FormatString ( _T("To: %s\r\n"), this->m_csToList);
546 CString m_csToList;
548 csSubject += FormatString ( _T("Subject: %s\r\n"), m_csSubject );
551 csSubject += FormatString ( _T("X-Mailer: TortoiseGit\r\nMIME-Version: 1.0\r\nContent-Type: %s\r\n\r\n"),
552 m_csMIMEContentType );
554 return Send ( csSubject );
557 BOOL CHwSMTP::SendBody()
559 CString csBody, csTemp;
561 if ( m_StrAryAttach.GetSize() > 0 )
563 csTemp.Format ( _T("%s\r\n\r\n"), m_csNoMIMEText );
564 csBody += csTemp;
566 csTemp.Format ( _T("--%s\r\n"), m_csPartBoundary );
567 csBody += csTemp;
569 csTemp.Format ( _T("Content-Type: text/plain\r\n%sContent-Transfer-Encoding: 7Bit\r\n\r\n"),
570 m_csCharSet );
571 csBody += csTemp;
574 //csTemp.Format ( _T("%s\r\n"), m_csBody );
575 csBody += m_csBody;
576 csBody += _T("\r\n");
578 return Send ( csBody );
581 BOOL CHwSMTP::SendAttach()
583 int nCountAttach = (int)m_StrAryAttach.GetSize();
584 if ( nCountAttach < 1 ) return TRUE;
586 for ( int i=0; i<nCountAttach; i++ )
588 if ( !SendOnAttach ( m_StrAryAttach.GetAt(i) ) )
589 return FALSE;
592 return TRUE;
595 BOOL CHwSMTP::SendOnAttach(LPCTSTR lpszFileName)
597 ASSERT ( lpszFileName );
598 CString csAttach, csTemp;
600 csTemp = lpszFileName;
601 CString csShortFileName = csTemp.GetBuffer(0) + csTemp.ReverseFind ( '\\' );
602 csShortFileName.TrimLeft ( _T("\\") );
604 csTemp.Format ( _T("--%s\r\n"), m_csPartBoundary );
605 csAttach += csTemp;
607 csTemp.Format ( _T("Content-Type: application/octet-stream; file=%s\r\n"), csShortFileName );
608 csAttach += csTemp;
610 csTemp.Format ( _T("Content-Transfer-Encoding: base64\r\n") );
611 csAttach += csTemp;
613 csTemp.Format ( _T("Content-Disposition: attachment; filename=%s\r\n\r\n"), csShortFileName );
614 csAttach += csTemp;
616 DWORD dwFileSize = hwGetFileAttr(lpszFileName);
617 if ( dwFileSize > 5*1024*1024 )
619 m_csLastError.Format ( _T("File [%s] too big. File size is : %s"), lpszFileName, FormatBytes(dwFileSize) );
620 return FALSE;
622 char *pBuf = new char[dwFileSize+1];
623 if ( !pBuf )
625 ::AfxThrowMemoryException ();
626 return FALSE;
629 if(!Send ( csAttach ))
630 return FALSE;
632 CFile file;
633 CStringA filedata;
636 if ( !file.Open ( lpszFileName, CFile::modeRead ) )
638 m_csLastError.Format ( _T("Open file [%s] failed"), lpszFileName );
639 return FALSE;
641 UINT nFileLen = file.Read ( pBuf, dwFileSize );
642 CBase64 Base64Encode;
643 filedata = Base64Encode.Encode ( pBuf, nFileLen );
644 filedata += _T("\r\n\r\n");
646 catch ( CFileException e )
648 e.Delete();
649 m_csLastError.Format ( _T("Read file [%s] failed"), lpszFileName );
650 delete[] pBuf;
651 return FALSE;
654 if(!SendBuffer( filedata.GetBuffer() ))
655 return FALSE;
658 delete[] pBuf;
660 return TRUE;
661 //return Send ( csAttach );
664 CString CHwSMTP::GetLastErrorText()
666 return m_csLastError;
670 DWORD WINAPI ThreadProc_SendEmail( LPVOID lpParameter )
672 CEMailObject *pEMailObject = (CEMailObject*)lpParameter;
673 ASSERT ( pEMailObject );
675 CHwSMTP HwSMTP;
676 BOOL bRet = HwSMTP.SendEmail (
677 pEMailObject->m_csSmtpSrvHost,
678 pEMailObject->m_csUserName,
679 pEMailObject->m_csPasswd,
680 pEMailObject->m_bMustAuth,
681 pEMailObject->m_csAddrFrom,
682 pEMailObject->m_csAddrTo,
683 pEMailObject->m_csSubject,
684 pEMailObject->m_csBody,
685 pEMailObject->m_csCharSet,
686 &pEMailObject->m_StrAryAttach,
687 pEMailObject->m_StrCC,
688 pEMailObject->m_nSmtpSrvPort,
689 pEMailObject->m_csSender
691 if ( !bRet)
693 #ifdef _DEBUG
694 CString csError = HwSMTP.GetLastErrorText ();
695 csError = FormatString ( _T("Send a email to [%s] failed."), pEMailObject->m_csSmtpSrvHost );
696 AfxMessageBox ( csError );
697 #endif
700 m_CSFor__g_PtrAry_Threads.Lock ();
701 int nFindPos = FindFromArray ( g_PtrAry_Threads, pEMailObject->m_hThread );
702 if ( nFindPos >= 0 )
703 g_PtrAry_Threads.RemoveAt ( nFindPos );
704 m_CSFor__g_PtrAry_Threads.Unlock ();
706 delete pEMailObject;
707 return bRet;
711 // Óà SMTP ·þÎñ·¢Ë͵ç×ÓÓʼþ£¬Èç¹ûÉèÖòÎÊý bViaThreadSend=TRUE£¬ÄÇÔÚ³ÌÐò½áÊøʱӦ¸ÃÔÚ ExitInstance() Öе÷Óà EndOfSMTP() º¯Êý
713 BOOL SendEmail (
714 BOOL bViaThreadSend,
715 LPCTSTR lpszSmtpSrvHost,
716 LPCTSTR lpszUserName,
717 LPCTSTR lpszPasswd,
718 BOOL bMustAuth,
719 LPCTSTR lpszAddrFrom,
720 LPCTSTR lpszAddrTo,
721 LPCTSTR lpszFromName,
722 LPCTSTR lpszReceiverName,
723 LPCTSTR lpszSubject,
724 LPCTSTR lpszBody,
725 LPCTSTR lpszCharSet/*=NULL*/,
726 CStringArray *pStrAryAttach/*=NULL*/,
727 LPCTSTR pStrAryCC/*=NULL*/,
728 UINT nSmtpSrvPort/*=25*/,
729 LPCTSTR lpszSender,
730 LPCTSTR lpszToList
733 if ( !lpszSmtpSrvHost || lstrlen(lpszSmtpSrvHost) < 1 ||
734 !lpszSubject || lstrlen(lpszSubject) < 1 ||
735 !lpszBody || lstrlen(lpszBody) < 1 )
737 AfxMessageBox ( _T("Parameter error !") );
738 return FALSE;
741 CEMailObject *pEMailObject = new CEMailObject (
742 lpszSmtpSrvHost,
743 lpszUserName,
744 lpszPasswd,
745 bMustAuth,
746 lpszAddrFrom,
747 lpszAddrTo,
748 lpszFromName,
749 lpszReceiverName,
750 lpszSubject,
751 lpszBody,
752 lpszCharSet,
753 pStrAryAttach,
754 pStrAryCC,
755 nSmtpSrvPort,
756 lpszSender,
757 lpszToList
759 if ( !pEMailObject ) return FALSE;
761 BOOL bRet = FALSE;
762 if ( bViaThreadSend )
764 DWORD dwThreadId = 0;
765 pEMailObject->m_hThread = ::CreateThread ( NULL, 0, ::ThreadProc_SendEmail, pEMailObject, CREATE_SUSPENDED, &dwThreadId );
766 bRet = HANDLE_IS_VALID(pEMailObject->m_hThread);
767 m_CSFor__g_PtrAry_Threads.Lock();
768 g_PtrAry_Threads.Add ( pEMailObject->m_hThread );
769 m_CSFor__g_PtrAry_Threads.Unlock();
770 ResumeThread ( pEMailObject->m_hThread );
772 else
774 bRet = (BOOL)ThreadProc_SendEmail ( pEMailObject );
777 return bRet;
780 void EndOfSMTP ()
782 // µÈ´ýËùÓÐÏß³ÌÖ´ÐÐÍê±Ï
783 for ( int i=0; i<g_PtrAry_Threads.GetSize(); i++ )
785 HANDLE hThread = (HANDLE)g_PtrAry_Threads.GetAt(i);
786 if ( HANDLE_IS_VALID(hThread) )
788 WaitForThreadEnd ( &hThread, 30*1000 );
791 g_PtrAry_Threads.RemoveAll ();
796 // ½«×Ö·û´® lpszOrg ת»»Îª¶à×Ö½ÚµÄ×Ö·û´®£¬Èç¹û»¹ÒªÊ¹Óöà×Ö·û´®µÄ³¤¶È£¬¿ÉÒÔÓÃÒÔÏ·½Ê½À´Ê¹ÓÃÕâ¸öÀࣺ
797 // CMultiByteString MultiByteString(_T("UNICODE×Ö·û´®"));
798 // printf ( "ANSI ×Ö·û´®Îª£º %s£¬ ×Ö·û¸öÊýΪ£º %d £¬ ³¤¶ÈΪ£º %d×Ö½Ú\n", MultiByteString.GetBuffer(), MultiByteString.GetLength(), MultiByteString.GetSize() );
800 CMultiByteString::CMultiByteString( LPCTSTR lpszOrg, int nOrgStringEncodeType/*=STRING_IS_SOFTCODE*/, OUT char *pOutBuf/*=NULL*/, int nOutBufSize/*=0*/ )
802 m_bNewBuffer = FALSE;
803 m_pszData = NULL;
804 m_nDataSize = 0;
805 m_nCharactersNumber = 0;
806 if ( !lpszOrg ) return;
808 // ÅжÏԭʼ×Ö·û´®µÄ±àÂ뷽ʽ
809 BOOL bOrgIsUnicode = FALSE;
810 if ( nOrgStringEncodeType == STRING_IS_MULTICHARS ) bOrgIsUnicode = FALSE;
811 else if ( nOrgStringEncodeType == STRING_IS_UNICODE ) bOrgIsUnicode = TRUE;
812 else
814 #ifdef UNICODE
815 bOrgIsUnicode = TRUE;
816 #else
817 bOrgIsUnicode = FALSE;
818 #endif
821 // ¼ÆËã×Ö·û´®¸öÊýºÍÐèÒªµÄÄ¿±ê»º³å´óС
822 if ( bOrgIsUnicode )
824 m_nCharactersNumber = (int)wcslen((WCHAR*)lpszOrg);
825 m_nDataSize = (m_nCharactersNumber + 1) * sizeof(WCHAR);
827 else
829 m_nCharactersNumber = (int)strlen((char*)lpszOrg);
830 m_nDataSize = (m_nCharactersNumber + 1) * sizeof(char);
833 // ʹÓõ÷ÓÃÕß´«ÈëµÄ»º³å
834 if ( pOutBuf && nOutBufSize > 0 )
836 m_pszData = pOutBuf;
837 m_nDataSize = nOutBufSize;
839 // ×Ô¼ºÉêÇëÄڴ滺³å
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_ACP, 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;
875 // ½« lpszOrg ת»»Îª¸Ã³ÌÐòʹÓõıàÂë×Ö·û´®£¬Èç¹û¸Ã³ÌÐòÊÇ UNICODE ¾ÍתΪ UNICODE£¬Èç¹ûÊÇ ANSI ¾ÍתΪ ANSI µÄ
877 CString GetCompatibleString ( LPVOID lpszOrg, BOOL bOrgIsUnicode, int nOrgLength/*=-1*/ )
879 if ( !lpszOrg ) return _T("");
883 #ifdef UNICODE
884 if ( bOrgIsUnicode )
886 if ( nOrgLength > 0 )
888 WCHAR *szRet = new WCHAR[nOrgLength+1];
889 if ( !szRet ) return _T("");
890 memset ( szRet, 0, (nOrgLength+1)*sizeof(WCHAR) );
891 memcpy ( szRet, lpszOrg, nOrgLength*sizeof(WCHAR) );
892 CString csRet = szRet;
893 delete[] szRet;
894 return csRet;
896 else if ( nOrgLength == 0 )
897 return _T("");
898 else
899 return (LPCTSTR)lpszOrg;
902 if ( nOrgLength < 0 )
903 nOrgLength = (int)strlen((const char*)lpszOrg);
904 int nWideCount = nOrgLength + 1;
905 WCHAR *wchar = new WCHAR[nWideCount];
906 if ( !wchar ) return _T("");
907 memset ( wchar, 0, nWideCount*sizeof(WCHAR) );
908 ::MultiByteToWideChar(CP_ACP, 0, (LPCSTR)lpszOrg, nOrgLength, wchar, nWideCount);
909 CString csRet = wchar;
910 delete[] wchar;
911 return csRet;
912 #else
913 if ( !bOrgIsUnicode )
915 if ( nOrgLength > 0 )
917 char *szRet = new char[nOrgLength+1];
918 if ( !szRet ) return _T("");
919 memset ( szRet, 0, (nOrgLength+1)*sizeof(char) );
920 memcpy ( szRet, lpszOrg, nOrgLength*sizeof(char) );
921 CString csRet = szRet;
922 delete[] szRet;
923 return csRet;
925 else if ( nOrgLength == 0 )
926 return _T("");
927 else
928 return (LPCTSTR)lpszOrg;
931 if ( nOrgLength < 0 )
932 nOrgLength = (int)wcslen((WCHAR*)lpszOrg);
933 int nMultiByteCount = nOrgLength + 1;
934 char *szMultiByte = new char[nMultiByteCount];
935 if ( !szMultiByte ) return _T("");
936 memset ( szMultiByte, 0, nMultiByteCount*sizeof(char) );
937 ::WideCharToMultiByte ( CP_ACP, 0, (LPCWSTR)lpszOrg, nOrgLength, (LPSTR)szMultiByte, nMultiByteCount, NULL, NULL );
938 CString csRet = szMultiByte;
939 delete[] szMultiByte;
940 return csRet;
941 #endif
943 CATCH_ALL(e)
945 THROW_LAST ();
947 END_CATCH_ALL
949 return _T("");
952 CString FormatDateTime ( COleDateTime &DateTime, LPCTSTR pFormat )
954 // If null, return empty string
955 if ( DateTime.GetStatus() == COleDateTime::null || DateTime.GetStatus() == COleDateTime::invalid )
956 return _T("");
958 UDATE ud;
959 if (S_OK != VarUdateFromDate(DateTime.m_dt, 0, &ud))
961 return _T("");
964 TCHAR *weeks[]={_T("Sun"),_T("Mon"),_T("Tue"),_T("Wen"),_T("Thu"),_T("Fri"),_T("Sat")};
965 TCHAR *month[]={_T("JAN"),_T("FEB"),_T("MAR"),_T("APR"),
966 _T("MAY"),_T("JUN"),_T("JUL"),_T("AUG"),
967 _T("SEP"),_T("OCT"),_T("NOV"),_T("DEC")};
969 TIME_ZONE_INFORMATION stTimeZone;
970 GetTimeZoneInformation(&stTimeZone);
972 CString strDate;
973 strDate.Format(_T("%s, %d %s %02d %d:%d:%d %c%04d")
974 ,weeks[ud.st.wDayOfWeek],
975 ud.st.wDay,month[ud.st.wMonth-1],ud.st.wYear%100,ud.st.wHour,
976 ud.st.wMinute,ud.st.wSecond,
977 stTimeZone.Bias>0?_T('-'):_T('+'),
978 abs(stTimeZone.Bias*10/6)
980 return strDate;
983 CString FormatString ( LPCTSTR lpszStr, ... )
985 TCHAR *buf = NULL;
986 // Ñ­»·¸ñʽ»¯×Ö·û´®£¬Èç¹û»º³å²»¹»Ôò½«»º³å¼Ó´óÈ»ºóÖØÊÔÒÔ±£Ö¤»º³å¹»ÓÃͬʱÓÖ²»ÀË·Ñ
987 for ( int nBufCount = 1024; nBufCount<5*1024*1024; nBufCount += 1024 )
989 buf = new TCHAR[nBufCount];
990 if ( !buf )
992 ::AfxThrowMemoryException ();
993 return _T("");
995 memset ( buf, 0, nBufCount*sizeof(TCHAR) );
997 va_list va;
998 va_start (va, lpszStr);
999 int nLen = _vsnprintf_hw ((TCHAR*)buf, nBufCount-sizeof(TCHAR), lpszStr, va);
1000 va_end(va);
1001 if ( nLen <= (int)(nBufCount-sizeof(TCHAR)) )
1002 break;
1003 delete[] buf; buf = NULL;
1005 if ( !buf )
1007 return _T("");
1010 CString csMsg = buf;
1011 delete[] buf; buf = NULL;
1012 return csMsg;
1015 /********************************************************************************
1016 * Function Type : Global
1017 * Parameter : lpFileName - Îļþ·¾¶
1018 * Return Value : -1 - ʧ°Ü
1019 * >=0 - Îļþ´óС
1020 * Description : »ñÈ¡ÎļþÊôÐÔ ( Îļþ´óС¡¢´´½¨Ê±¼ä )
1021 *********************************************************************************/
1022 int hwGetFileAttr ( LPCTSTR lpFileName, OUT CFileStatus *pFileStatus/*=NULL*/ )
1024 if ( !lpFileName || lstrlen(lpFileName) < 1 ) return -1;
1026 CFileStatus fileStatus;
1027 fileStatus.m_attribute = 0;
1028 fileStatus.m_size = 0;
1029 memset ( fileStatus.m_szFullName, 0, sizeof(fileStatus.m_szFullName) );
1030 BOOL bRet = FALSE;
1033 if ( CFile::GetStatus(lpFileName,fileStatus) )
1035 bRet = TRUE;
1038 CATCH (CFileException, e)
1040 ASSERT ( FALSE );
1041 bRet = FALSE;
1043 CATCH_ALL(e)
1045 ASSERT ( FALSE );
1046 bRet = FALSE;
1048 END_CATCH_ALL;
1050 if ( pFileStatus )
1052 pFileStatus->m_ctime = fileStatus.m_ctime;
1053 pFileStatus->m_mtime = fileStatus.m_mtime;
1054 pFileStatus->m_atime = fileStatus.m_atime;
1055 pFileStatus->m_size = fileStatus.m_size;
1056 pFileStatus->m_attribute = fileStatus.m_attribute;
1057 pFileStatus->_m_padding = fileStatus._m_padding;
1058 lstrcpy ( pFileStatus->m_szFullName, fileStatus.m_szFullName );
1062 return (int)fileStatus.m_size;
1066 // ½«Ò»¸ö±íʾ×Ö½ÚµÄÊýÓÿɶÁÐԺõÄ×Ö·û´®À´±íʾ£¬ÀýÈ罫 12345678 ×Ö½Úת»»Îª£º
1067 // 11.77M
1068 // nFlag - 0 : ×Ô¶¯Æ¥Å䵥λ
1069 // 1 : ÒÔ Kb Ϊµ¥Î»
1070 // 2 : ÒÔ Mb Ϊµ¥Î»
1071 // 3 : ÒÔ Gb Ϊµ¥Î»
1073 CString FormatBytes ( double fBytesNum, BOOL bShowUnit/*=TRUE*/, int nFlag/*=0*/ )
1075 CString csRes;
1076 if ( nFlag == 0 )
1078 if ( fBytesNum >= 1024.0 && fBytesNum < 1024.0*1024.0 )
1079 csRes.Format ( _T("%.2f%s"), fBytesNum / 1024.0, bShowUnit?_T(" K"):_T("") );
1080 else if ( fBytesNum >= 1024.0*1024.0 && fBytesNum < 1024.0*1024.0*1024.0 )
1081 csRes.Format ( _T("%.2f%s"), fBytesNum / (1024.0*1024.0), bShowUnit?_T(" M"):_T("") );
1082 else if ( fBytesNum >= 1024.0*1024.0*1024.0 )
1083 csRes.Format ( _T("%.2f%s"), fBytesNum / (1024.0*1024.0*1024.0), bShowUnit?_T(" G"):_T("") );
1084 else
1085 csRes.Format ( _T("%.2f%s"), fBytesNum, bShowUnit?_T(" B"):_T("") );
1087 else if ( nFlag == 1 )
1089 csRes.Format ( _T("%.2f%s"), fBytesNum / 1024.0, bShowUnit?_T(" K"):_T("") );
1091 else if ( nFlag == 2 )
1093 csRes.Format ( _T("%.2f%s"), fBytesNum / (1024.0*1024.0), bShowUnit?_T(" M"):_T("") );
1095 else if ( nFlag == 3 )
1097 csRes.Format ( _T("%.2f%s"), fBytesNum / (1024.0*1024.0*1024.0), bShowUnit?_T(" G"):_T("") );
1100 return csRes;
1104 // µÈ´ýÏß³ÌÍ˳ö
1106 BOOL WaitForThreadEnd ( HANDLE *phThread, DWORD dwWaitTime /*=10*1000*/ )
1108 BOOL bRet = TRUE;
1109 ASSERT ( phThread );
1110 if ( !(*phThread) ) return TRUE;
1111 if ( ::WaitForSingleObject ( *phThread, dwWaitTime ) == WAIT_TIMEOUT )
1113 bRet = FALSE;
1114 ::TerminateThread ( *phThread, 0 );
1116 ::CloseHandle ( *phThread );
1117 (*phThread) = NULL;
1118 return bRet;