Fixed issue #1351: Add Hotkey to deselect all files on commit
[TortoiseGit.git] / src / Utils / HwSMTP.cpp
blobefbcebdf19c6fcd9a94c8e2b22cecc1005b1c21f
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 ))
628 return FALSE;
630 CFile file;
631 CStringA filedata;
634 if ( !file.Open ( lpszFileName, CFile::modeRead ) )
636 m_csLastError.Format ( _T("Open file [%s] failed"), lpszFileName );
637 return FALSE;
639 UINT nFileLen = file.Read ( pBuf, dwFileSize );
640 CBase64 Base64Encode;
641 filedata = Base64Encode.Encode ( pBuf, nFileLen );
642 filedata += _T("\r\n\r\n");
644 catch ( CFileException e )
646 e.Delete();
647 m_csLastError.Format ( _T("Read file [%s] failed"), lpszFileName );
648 delete[] pBuf;
649 return FALSE;
652 if(!SendBuffer( filedata.GetBuffer() ))
653 return FALSE;
656 delete[] pBuf;
658 return TRUE;
659 //return Send ( csAttach );
662 CString CHwSMTP::GetLastErrorText()
664 return m_csLastError;
668 DWORD WINAPI ThreadProc_SendEmail( LPVOID lpParameter )
670 CEMailObject *pEMailObject = (CEMailObject*)lpParameter;
671 ASSERT ( pEMailObject );
673 CHwSMTP HwSMTP;
674 BOOL bRet = HwSMTP.SendEmail (
675 pEMailObject->m_csSmtpSrvHost,
676 pEMailObject->m_csUserName,
677 pEMailObject->m_csPasswd,
678 pEMailObject->m_bMustAuth,
679 pEMailObject->m_csAddrFrom,
680 pEMailObject->m_csAddrTo,
681 pEMailObject->m_csSubject,
682 pEMailObject->m_csBody,
683 pEMailObject->m_csCharSet,
684 &pEMailObject->m_StrAryAttach,
685 pEMailObject->m_StrCC,
686 pEMailObject->m_nSmtpSrvPort,
687 pEMailObject->m_csSender
689 if ( !bRet)
691 #ifdef _DEBUG
692 CString csError = HwSMTP.GetLastErrorText ();
693 csError = FormatString ( _T("Send a email to [%s] failed."), pEMailObject->m_csSmtpSrvHost );
694 AfxMessageBox ( csError );
695 #endif
698 m_CSFor__g_PtrAry_Threads.Lock ();
699 int nFindPos = FindFromArray ( g_PtrAry_Threads, pEMailObject->m_hThread );
700 if ( nFindPos >= 0 )
701 g_PtrAry_Threads.RemoveAt ( nFindPos );
702 m_CSFor__g_PtrAry_Threads.Unlock ();
704 delete pEMailObject;
705 return bRet;
709 // Óà SMTP ·þÎñ·¢Ë͵ç×ÓÓʼþ£¬Èç¹ûÉèÖòÎÊý bViaThreadSend=TRUE£¬ÄÇÔÚ³ÌÐò½áÊøʱӦ¸ÃÔÚ ExitInstance() Öе÷Óà EndOfSMTP() º¯Êý
711 BOOL SendEmail (
712 BOOL bViaThreadSend,
713 LPCTSTR lpszSmtpSrvHost,
714 LPCTSTR lpszUserName,
715 LPCTSTR lpszPasswd,
716 BOOL bMustAuth,
717 LPCTSTR lpszAddrFrom,
718 LPCTSTR lpszAddrTo,
719 LPCTSTR lpszFromName,
720 LPCTSTR lpszReceiverName,
721 LPCTSTR lpszSubject,
722 LPCTSTR lpszBody,
723 LPCTSTR lpszCharSet/*=NULL*/,
724 CStringArray *pStrAryAttach/*=NULL*/,
725 LPCTSTR pStrAryCC/*=NULL*/,
726 UINT nSmtpSrvPort/*=25*/,
727 LPCTSTR lpszSender,
728 LPCTSTR lpszToList
731 if ( !lpszSmtpSrvHost || lstrlen(lpszSmtpSrvHost) < 1 ||
732 !lpszSubject || lstrlen(lpszSubject) < 1 ||
733 !lpszBody || lstrlen(lpszBody) < 1 )
735 AfxMessageBox ( _T("Parameter error !") );
736 return FALSE;
739 CEMailObject *pEMailObject = new CEMailObject (
740 lpszSmtpSrvHost,
741 lpszUserName,
742 lpszPasswd,
743 bMustAuth,
744 lpszAddrFrom,
745 lpszAddrTo,
746 lpszFromName,
747 lpszReceiverName,
748 lpszSubject,
749 lpszBody,
750 lpszCharSet,
751 pStrAryAttach,
752 pStrAryCC,
753 nSmtpSrvPort,
754 lpszSender,
755 lpszToList
757 if ( !pEMailObject ) return FALSE;
759 BOOL bRet = FALSE;
760 if ( bViaThreadSend )
762 DWORD dwThreadId = 0;
763 pEMailObject->m_hThread = ::CreateThread ( NULL, 0, ::ThreadProc_SendEmail, pEMailObject, CREATE_SUSPENDED, &dwThreadId );
764 bRet = HANDLE_IS_VALID(pEMailObject->m_hThread);
765 m_CSFor__g_PtrAry_Threads.Lock();
766 g_PtrAry_Threads.Add ( pEMailObject->m_hThread );
767 m_CSFor__g_PtrAry_Threads.Unlock();
768 ResumeThread ( pEMailObject->m_hThread );
770 else
772 bRet = (BOOL)ThreadProc_SendEmail ( pEMailObject );
775 return bRet;
778 void EndOfSMTP ()
780 // µÈ´ýËùÓÐÏß³ÌÖ´ÐÐÍê±Ï
781 for ( int i=0; i<g_PtrAry_Threads.GetSize(); i++ )
783 HANDLE hThread = (HANDLE)g_PtrAry_Threads.GetAt(i);
784 if ( HANDLE_IS_VALID(hThread) )
786 WaitForThreadEnd ( &hThread, 30*1000 );
789 g_PtrAry_Threads.RemoveAll ();
794 // ½«×Ö·û´® lpszOrg ת»»Îª¶à×Ö½ÚµÄ×Ö·û´®£¬Èç¹û»¹ÒªÊ¹Óöà×Ö·û´®µÄ³¤¶È£¬¿ÉÒÔÓÃÒÔÏ·½Ê½À´Ê¹ÓÃÕâ¸öÀࣺ
795 // CMultiByteString MultiByteString(_T("UNICODE×Ö·û´®"));
796 // printf ( "ANSI ×Ö·û´®Îª£º %s£¬ ×Ö·û¸öÊýΪ£º %d £¬ ³¤¶ÈΪ£º %d×Ö½Ú\n", MultiByteString.GetBuffer(), MultiByteString.GetLength(), MultiByteString.GetSize() );
798 CMultiByteString::CMultiByteString( LPCTSTR lpszOrg, int nOrgStringEncodeType/*=STRING_IS_SOFTCODE*/, OUT char *pOutBuf/*=NULL*/, int nOutBufSize/*=0*/ )
800 m_bNewBuffer = FALSE;
801 m_pszData = NULL;
802 m_nDataSize = 0;
803 m_nCharactersNumber = 0;
804 if ( !lpszOrg ) return;
806 BOOL bOrgIsUnicode = FALSE;
807 if ( nOrgStringEncodeType == STRING_IS_MULTICHARS ) bOrgIsUnicode = FALSE;
808 else if ( nOrgStringEncodeType == STRING_IS_UNICODE ) bOrgIsUnicode = TRUE;
809 else
811 #ifdef UNICODE
812 bOrgIsUnicode = TRUE;
813 #else
814 bOrgIsUnicode = FALSE;
815 #endif
818 if ( bOrgIsUnicode )
820 m_nCharactersNumber = (int)wcslen((WCHAR*)lpszOrg);
821 m_nDataSize = (m_nCharactersNumber + 1) * sizeof(WCHAR);
823 else
825 m_nCharactersNumber = (int)strlen((char*)lpszOrg);
826 m_nDataSize = (m_nCharactersNumber + 1) * sizeof(char);
829 if ( pOutBuf && nOutBufSize > 0 )
831 m_pszData = pOutBuf;
832 m_nDataSize = nOutBufSize;
834 else
836 m_pszData = (char*)new BYTE[m_nDataSize];
837 if ( !m_pszData )
839 ::AfxThrowMemoryException ();
840 return;
842 m_bNewBuffer = TRUE;
844 memset ( m_pszData, 0, m_nDataSize );
846 if ( bOrgIsUnicode )
848 m_nCharactersNumber = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR)lpszOrg, m_nCharactersNumber, (LPSTR)m_pszData, m_nDataSize / sizeof(char) - 1, NULL, NULL);
849 if ( m_nCharactersNumber < 1 ) m_nCharactersNumber = (int)strlen ( m_pszData );
851 else
853 m_nCharactersNumber = __min ( m_nCharactersNumber, (int)(m_nDataSize/sizeof(char)-1) );
854 strncpy ( m_pszData, (const char*)lpszOrg, m_nCharactersNumber );
855 m_nCharactersNumber = (int)strlen ( m_pszData );
857 m_nDataSize = ( m_nCharactersNumber + 1 ) * sizeof(char);
860 CMultiByteString::~CMultiByteString ()
862 if ( m_bNewBuffer && m_pszData )
864 delete[] m_pszData;
868 CString GetCompatibleString ( LPVOID lpszOrg, BOOL bOrgIsUnicode, int nOrgLength/*=-1*/ )
870 if ( !lpszOrg ) return _T("");
874 #ifdef UNICODE
875 if ( bOrgIsUnicode )
877 if ( nOrgLength > 0 )
879 WCHAR *szRet = new WCHAR[nOrgLength+1];
880 if ( !szRet ) return _T("");
881 memset ( szRet, 0, (nOrgLength+1)*sizeof(WCHAR) );
882 memcpy ( szRet, lpszOrg, nOrgLength*sizeof(WCHAR) );
883 CString csRet = szRet;
884 delete[] szRet;
885 return csRet;
887 else if ( nOrgLength == 0 )
888 return _T("");
889 else
890 return (LPCTSTR)lpszOrg;
893 if ( nOrgLength < 0 )
894 nOrgLength = (int)strlen((const char*)lpszOrg);
895 int nWideCount = nOrgLength + 1;
896 WCHAR *wchar = new WCHAR[nWideCount];
897 if ( !wchar ) return _T("");
898 memset ( wchar, 0, nWideCount*sizeof(WCHAR) );
899 ::MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)lpszOrg, nOrgLength, wchar, nWideCount);
900 CString csRet = wchar;
901 delete[] wchar;
902 return csRet;
903 #else
904 if ( !bOrgIsUnicode )
906 if ( nOrgLength > 0 )
908 char *szRet = new char[nOrgLength+1];
909 if ( !szRet ) return _T("");
910 memset ( szRet, 0, (nOrgLength+1)*sizeof(char) );
911 memcpy ( szRet, lpszOrg, nOrgLength*sizeof(char) );
912 CString csRet = szRet;
913 delete[] szRet;
914 return csRet;
916 else if ( nOrgLength == 0 )
917 return _T("");
918 else
919 return (LPCTSTR)lpszOrg;
922 if ( nOrgLength < 0 )
923 nOrgLength = (int)wcslen((WCHAR*)lpszOrg);
924 int nMultiByteCount = nOrgLength + 1;
925 char *szMultiByte = new char[nMultiByteCount];
926 if ( !szMultiByte ) return _T("");
927 memset ( szMultiByte, 0, nMultiByteCount*sizeof(char) );
928 ::WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR)lpszOrg, nOrgLength, (LPSTR)szMultiByte, nMultiByteCount, NULL, NULL);
929 CString csRet = szMultiByte;
930 delete[] szMultiByte;
931 return csRet;
932 #endif
934 CATCH_ALL(e)
936 THROW_LAST ();
938 END_CATCH_ALL
940 return _T("");
943 CString FormatDateTime ( COleDateTime &DateTime, LPCTSTR pFormat )
945 // If null, return empty string
946 if ( DateTime.GetStatus() == COleDateTime::null || DateTime.GetStatus() == COleDateTime::invalid )
947 return _T("");
949 UDATE ud;
950 if (S_OK != VarUdateFromDate(DateTime.m_dt, 0, &ud))
952 return _T("");
955 TCHAR *weeks[]={_T("Sun"),_T("Mon"),_T("Tue"),_T("Wen"),_T("Thu"),_T("Fri"),_T("Sat")};
956 TCHAR *month[]={_T("JAN"),_T("FEB"),_T("MAR"),_T("APR"),
957 _T("MAY"),_T("JUN"),_T("JUL"),_T("AUG"),
958 _T("SEP"),_T("OCT"),_T("NOV"),_T("DEC")};
960 TIME_ZONE_INFORMATION stTimeZone;
961 GetTimeZoneInformation(&stTimeZone);
963 CString strDate;
964 strDate.Format(_T("%s, %d %s %02d %d:%d:%d %c%04d")
965 ,weeks[ud.st.wDayOfWeek],
966 ud.st.wDay,month[ud.st.wMonth-1],ud.st.wYear%100,ud.st.wHour,
967 ud.st.wMinute,ud.st.wSecond,
968 stTimeZone.Bias>0?_T('-'):_T('+'),
969 abs(stTimeZone.Bias*10/6)
971 return strDate;
974 CString FormatString ( LPCTSTR lpszStr, ... )
976 TCHAR *buf = NULL;
977 for ( int nBufCount = 1024; nBufCount<5*1024*1024; nBufCount += 1024 )
979 buf = new TCHAR[nBufCount];
980 if ( !buf )
982 ::AfxThrowMemoryException ();
983 return _T("");
985 memset ( buf, 0, nBufCount*sizeof(TCHAR) );
987 va_list va;
988 va_start (va, lpszStr);
989 int nLen = _vsnprintf_hw ((TCHAR*)buf, nBufCount-sizeof(TCHAR), lpszStr, va);
990 va_end(va);
991 if ( nLen <= (int)(nBufCount-sizeof(TCHAR)) )
992 break;
993 delete[] buf; buf = NULL;
995 if ( !buf )
997 return _T("");
1000 CString csMsg = buf;
1001 delete[] buf; buf = NULL;
1002 return csMsg;
1005 int hwGetFileAttr ( LPCTSTR lpFileName, OUT CFileStatus *pFileStatus/*=NULL*/ )
1007 if ( !lpFileName || lstrlen(lpFileName) < 1 ) return -1;
1009 CFileStatus fileStatus;
1010 fileStatus.m_attribute = 0;
1011 fileStatus.m_size = 0;
1012 memset ( fileStatus.m_szFullName, 0, sizeof(fileStatus.m_szFullName) );
1013 BOOL bRet = FALSE;
1016 if ( CFile::GetStatus(lpFileName,fileStatus) )
1018 bRet = TRUE;
1021 CATCH (CFileException, e)
1023 ASSERT ( FALSE );
1024 bRet = FALSE;
1026 CATCH_ALL(e)
1028 ASSERT ( FALSE );
1029 bRet = FALSE;
1031 END_CATCH_ALL;
1033 if ( pFileStatus )
1035 pFileStatus->m_ctime = fileStatus.m_ctime;
1036 pFileStatus->m_mtime = fileStatus.m_mtime;
1037 pFileStatus->m_atime = fileStatus.m_atime;
1038 pFileStatus->m_size = fileStatus.m_size;
1039 pFileStatus->m_attribute = fileStatus.m_attribute;
1040 pFileStatus->_m_padding = fileStatus._m_padding;
1041 lstrcpy ( pFileStatus->m_szFullName, fileStatus.m_szFullName );
1045 return (int)fileStatus.m_size;
1048 CString FormatBytes ( double fBytesNum, BOOL bShowUnit/*=TRUE*/, int nFlag/*=0*/ )
1050 CString csRes;
1051 if ( nFlag == 0 )
1053 if ( fBytesNum >= 1024.0 && fBytesNum < 1024.0*1024.0 )
1054 csRes.Format ( _T("%.2f%s"), fBytesNum / 1024.0, bShowUnit?_T(" K"):_T("") );
1055 else if ( fBytesNum >= 1024.0*1024.0 && fBytesNum < 1024.0*1024.0*1024.0 )
1056 csRes.Format ( _T("%.2f%s"), fBytesNum / (1024.0*1024.0), bShowUnit?_T(" M"):_T("") );
1057 else if ( fBytesNum >= 1024.0*1024.0*1024.0 )
1058 csRes.Format ( _T("%.2f%s"), fBytesNum / (1024.0*1024.0*1024.0), bShowUnit?_T(" G"):_T("") );
1059 else
1060 csRes.Format ( _T("%.2f%s"), fBytesNum, bShowUnit?_T(" B"):_T("") );
1062 else if ( nFlag == 1 )
1064 csRes.Format ( _T("%.2f%s"), fBytesNum / 1024.0, bShowUnit?_T(" K"):_T("") );
1066 else if ( nFlag == 2 )
1068 csRes.Format ( _T("%.2f%s"), fBytesNum / (1024.0*1024.0), bShowUnit?_T(" M"):_T("") );
1070 else if ( nFlag == 3 )
1072 csRes.Format ( _T("%.2f%s"), fBytesNum / (1024.0*1024.0*1024.0), bShowUnit?_T(" G"):_T("") );
1075 return csRes;
1079 // µÈ´ýÏß³ÌÍ˳ö
1081 BOOL WaitForThreadEnd ( HANDLE *phThread, DWORD dwWaitTime /*=10*1000*/ )
1083 BOOL bRet = TRUE;
1084 ASSERT ( phThread );
1085 if ( !(*phThread) ) return TRUE;
1086 if ( ::WaitForSingleObject ( *phThread, dwWaitTime ) == WAIT_TIMEOUT )
1088 bRet = FALSE;
1089 ::TerminateThread ( *phThread, 0 );
1091 ::CloseHandle ( *phThread );
1092 (*phThread) = NULL;
1093 return bRet;