OSDN Git Service

84d0b20d77745d37e573e257d0b180f49aab65b4
[tortoisegit/TortoiseGitJp.git] / src / Utils / HwSMTP.cpp
1 // HwSMTP.cpp: implementation of the CHwSMTP class.\r
2 //\r
3 //////////////////////////////////////////////////////////////////////\r
4 \r
5 #include "stdafx.h"\r
6 #include "afxstr.h"\r
7 #include "HwSMTP.h"\r
8 #include "CBase64.h"\r
9 #include "SpeedPostEmail.h"\r
10 \r
11 #include <Afxmt.h>\r
12 \r
13 #ifdef _DEBUG\r
14 #undef THIS_FILE\r
15 static char THIS_FILE[]=__FILE__;\r
16 #define new DEBUG_NEW\r
17 #endif\r
18 \r
19 CPtrArray g_PtrAry_Threads;\r
20 ::CCriticalSection m_CSFor__g_PtrAry_Threads;\r
21 \r
22 class CEMailObject\r
23 {\r
24 public:\r
25         CEMailObject (\r
26                 LPCTSTR lpszSmtpSrvHost,\r
27                 LPCTSTR lpszUserName,\r
28                 LPCTSTR lpszPasswd,\r
29                 BOOL bMustAuth,\r
30                 LPCTSTR lpszAddrFrom,\r
31                 LPCTSTR lpszAddrTo,\r
32                 LPCTSTR lpszSenderName,\r
33                 LPCTSTR lpszReceiverName,\r
34                 LPCTSTR lpszSubject,\r
35                 LPCTSTR lpszBody,\r
36                 LPCTSTR lpszCharSet,\r
37                 CStringArray *pStrAryAttach,\r
38                 CStringArray *pStrAryCC,\r
39                 UINT nSmtpSrvPort\r
40                 )\r
41         {\r
42                 m_csSmtpSrvHost = GET_SAFE_STRING(lpszSmtpSrvHost);\r
43                 m_csUserName = GET_SAFE_STRING(lpszUserName);\r
44                 m_csPasswd = GET_SAFE_STRING(lpszPasswd);\r
45                 m_bMustAuth = bMustAuth;\r
46                 m_csAddrFrom = GET_SAFE_STRING(lpszAddrFrom);\r
47                 m_csAddrTo = GET_SAFE_STRING(lpszAddrTo);\r
48                 m_csSenderName = GET_SAFE_STRING(lpszSenderName);\r
49                 m_csReceiverName = GET_SAFE_STRING(lpszReceiverName);\r
50                 m_csSubject = GET_SAFE_STRING(lpszSubject);\r
51                 m_csBody = GET_SAFE_STRING(lpszBody);\r
52                 m_csCharSet = GET_SAFE_STRING(lpszCharSet);\r
53                 if ( pStrAryAttach )\r
54                         m_StrAryAttach.Append ( *pStrAryAttach );\r
55                 if ( pStrAryCC )\r
56                         m_StrAryCC.Append ( *pStrAryCC );\r
57                 m_nSmtpSrvPort = nSmtpSrvPort;\r
58                 m_hThread = NULL;\r
59         }\r
60 \r
61 public:\r
62         CString m_csSmtpSrvHost;\r
63         CString m_csUserName;\r
64         CString m_csPasswd;\r
65         BOOL m_bMustAuth;\r
66         CString m_csAddrFrom;\r
67         CString m_csAddrTo;\r
68         CString m_csSenderName;\r
69         CString m_csReceiverName;\r
70         CString m_csSubject;\r
71         CString m_csBody;\r
72         CString m_csCharSet;\r
73         CStringArray m_StrAryAttach;\r
74         CStringArray m_StrAryCC;\r
75         UINT m_nSmtpSrvPort;\r
76 \r
77         HANDLE m_hThread;\r
78 };\r
79 \r
80 //////////////////////////////////////////////////////////////////////\r
81 // Construction/Destruction\r
82 //////////////////////////////////////////////////////////////////////\r
83 \r
84 CHwSMTP::CHwSMTP () :\r
85         m_bConnected ( FALSE ),\r
86         m_nSmtpSrvPort ( 25 ),\r
87         m_bMustAuth ( TRUE )\r
88 {\r
89         m_csMIMEContentType = _T( "multipart/mixed");\r
90         m_csPartBoundary = _T( "WC_MAIL_PaRt_BoUnDaRy_05151998" );\r
91         m_csNoMIMEText = _T( "This is a multi-part message in MIME format." );\r
92 //      m_csCharSet = _T("\r\n\tcharset=\"iso-8859-1\"\r\n");\r
93 }\r
94 \r
95 CHwSMTP::~CHwSMTP()\r
96 {\r
97 }\r
98 \r
99 BOOL CHwSMTP::SendEmail (\r
100                 LPCTSTR lpszSmtpSrvHost,\r
101                 LPCTSTR lpszUserName,\r
102                 LPCTSTR lpszPasswd,\r
103                 BOOL bMustAuth,\r
104                 LPCTSTR lpszAddrFrom,\r
105                 LPCTSTR lpszAddrTo,\r
106                 LPCTSTR lpszSenderName,\r
107                 LPCTSTR lpszReceiverName,\r
108                 LPCTSTR lpszSubject,\r
109                 LPCTSTR lpszBody,\r
110                 LPCTSTR lpszCharSet,                                            // ×Ö·û¼¯ÀàÐÍ£¬ÀýÈ磺·±ÌåÖÐÎÄÕâÀïÓ¦ÊäÈë"big5"£¬¼òÌåÖÐÎÄʱÊäÈë"gb2312"\r
111                 CStringArray *pStrAryAttach/*=NULL*/,\r
112                 CStringArray *pStrAryCC/*=NULL*/,\r
113                 UINT nSmtpSrvPort/*=25*/\r
114                 )\r
115 {\r
116         TRACE ( _T("·¢ËÍÓʼþ£º%s, %s, %s\n"), lpszAddrTo, lpszReceiverName, lpszBody );\r
117         m_StrAryAttach.RemoveAll();\r
118         m_StrAryCC.RemoveAll();\r
119         m_csSmtpSrvHost = GET_SAFE_STRING ( lpszSmtpSrvHost );\r
120         if ( m_csSmtpSrvHost.GetLength() <= 0 )\r
121         {\r
122                 m_csLastError.Format ( _T("Parameter Error!") );\r
123                 return FALSE;\r
124         }\r
125         m_csUserName = GET_SAFE_STRING ( lpszUserName );\r
126         m_csPasswd = GET_SAFE_STRING ( lpszPasswd );\r
127         m_bMustAuth = bMustAuth;\r
128         if ( m_bMustAuth && m_csUserName.GetLength() <= 0 )\r
129         {\r
130                 m_csLastError.Format ( _T("Parameter Error!") );\r
131                 return FALSE;\r
132         }\r
133 \r
134         m_csAddrFrom = GET_SAFE_STRING ( lpszAddrFrom );\r
135         m_csAddrTo = GET_SAFE_STRING ( lpszAddrTo );\r
136         m_csSenderName = GET_SAFE_STRING ( lpszSenderName );\r
137         m_csReceiverName = GET_SAFE_STRING ( lpszReceiverName );\r
138         m_csSubject = GET_SAFE_STRING ( lpszSubject );\r
139         m_csBody = GET_SAFE_STRING ( lpszBody );\r
140         m_nSmtpSrvPort = nSmtpSrvPort;\r
141         if ( lpszCharSet && lstrlen(lpszCharSet) > 0 )\r
142                 m_csCharSet.Format ( _T("\r\n\tcharset=\"%s\"\r\n"), lpszCharSet );\r
143 \r
144         if      (\r
145                         m_csAddrFrom.GetLength() <= 0 || m_csAddrTo.GetLength() <= 0 ||\r
146                         m_csSenderName.GetLength() <= 0 || m_csReceiverName.GetLength() <= 0 ||\r
147                         m_csSubject.GetLength() <= 0 || m_csBody.GetLength() <= 0\r
148                 )\r
149         {\r
150                 m_csLastError.Format ( _T("Parameter Error!") );\r
151                 return FALSE;\r
152         }\r
153 \r
154         if ( pStrAryAttach )\r
155         {\r
156                 m_StrAryAttach.Append ( *pStrAryAttach );\r
157         }\r
158         if ( m_StrAryAttach.GetSize() < 1 )\r
159                 m_csMIMEContentType = _T( "text/plain");\r
160 \r
161         if ( pStrAryCC )\r
162         {\r
163                 m_StrAryCC.Append ( *pStrAryCC );\r
164         }       \r
165 \r
166         // ´´½¨Socket\r
167         if ( !m_SendSock.Create () )\r
168         {\r
169                 m_csLastError.Format ( _T("Create socket failed!") );\r
170                 return FALSE;\r
171         }\r
172 \r
173         // Á¬½Óµ½·þÎñÆ÷\r
174         if ( !m_SendSock.Connect ( m_csSmtpSrvHost, m_nSmtpSrvPort ) )\r
175         {\r
176                 m_csLastError.Format ( _T("Connect to [ %s ] failed"), m_csSmtpSrvHost );\r
177                 TRACE ( _T("%d\n"), GetLastError() );\r
178                 return FALSE;\r
179         }\r
180         if ( !GetResponse( _T("220") ) ) return FALSE;\r
181 \r
182         m_bConnected = TRUE;\r
183         return SendEmail();\r
184 \r
185 }\r
186 \r
187 \r
188 BOOL CHwSMTP::GetResponse ( LPCTSTR lpszVerifyCode, int *pnCode/*=NULL*/)\r
189 {\r
190         if ( !lpszVerifyCode || lstrlen(lpszVerifyCode) < 1 )\r
191                 return FALSE;\r
192 \r
193         char szRecvBuf[1024] = {0};\r
194         int nRet = 0;\r
195         char szStatusCode[4] = {0};\r
196         nRet = m_SendSock.Receive ( szRecvBuf, sizeof(szRecvBuf) );\r
197         TRACE ( _T("Received : %s\r\n"), szRecvBuf );\r
198         if ( nRet <= 0 )\r
199         {\r
200                 m_csLastError.Format ( _T("Receive TCP data failed") );\r
201                 return FALSE;\r
202         }\r
203 //      TRACE ( _T("ÊÕµ½·þÎñÆ÷»ØÓ¦£º%s\n"), szRecvBuf );\r
204 \r
205         memcpy ( szStatusCode, szRecvBuf, 3 );\r
206         if ( pnCode ) (*pnCode) = atoi ( szStatusCode );\r
207 \r
208         if ( strcmp ( szStatusCode, CMultiByteString(lpszVerifyCode).GetBuffer() ) != 0 )\r
209         {\r
210                 m_csLastError.Format ( _T("Received invalid response  : %s"), GetCompatibleString(szRecvBuf,FALSE) );\r
211                 return FALSE;\r
212         }\r
213 \r
214         return TRUE;\r
215 }\r
216 \r
217 // ÀûÓÃsocket·¢ËÍÊý¾Ý£¬Êý¾Ý³¤¶È²»Äܳ¬¹ý10M\r
218 BOOL CHwSMTP::Send(LPCTSTR lpszData, ... )\r
219 {\r
220         if ( !m_bConnected )\r
221         {\r
222                 m_csLastError.Format ( _T("Didn't connect") );\r
223                 return FALSE;\r
224         }\r
225 \r
226         TCHAR *buf = NULL;\r
227         // Ñ­»·¸ñʽ»¯×Ö·û´®£¬Èç¹û»º³å²»¹»Ôò½«»º³å¼Ó´óÈ»ºóÖØÊÔÒÔ±£Ö¤»º³å¹»ÓÃͬʱÓÖ²»ÀË·Ñ\r
228         for ( int nBufCount = 1024; nBufCount<10*1024*1024; nBufCount += 1024 )\r
229         {\r
230                 buf = new TCHAR[nBufCount];\r
231                 if ( !buf )\r
232                 {\r
233                         ::AfxThrowMemoryException ();\r
234                         return FALSE;\r
235                 }\r
236                 memset ( buf, 0, nBufCount*sizeof(TCHAR) );\r
237 \r
238                 va_list  va;\r
239                 va_start (va, lpszData);\r
240                 int nLen = _vsnprintf_hw ((TCHAR*)buf, nBufCount-sizeof(TCHAR), lpszData, va);\r
241                 va_end(va);\r
242                 if ( nLen <= (int)(nBufCount-sizeof(TCHAR)) )\r
243                         break;\r
244                 delete[] buf; buf = NULL;\r
245         }\r
246         if ( !buf )\r
247         {\r
248                 m_csLastError.Format ( _T("Memory too small or data too big.") );\r
249                 return FALSE;\r
250         }\r
251 \r
252         CMultiByteString cbsData ( buf );\r
253         delete[] buf; buf = NULL;\r
254         TRACE ( _T("Send : %s\r\n"), cbsData.GetBuffer() );\r
255         if ( m_SendSock.Send ( cbsData.GetBuffer(), cbsData.GetLength() ) != cbsData.GetLength() )\r
256         {\r
257                 m_csLastError.Format ( _T("Socket send data failed") );\r
258                 return FALSE;\r
259         }\r
260         \r
261         return TRUE;\r
262 }\r
263 \r
264 BOOL CHwSMTP::SendEmail()\r
265 {\r
266         BOOL bRet = TRUE;\r
267         char szLocalHostName[64] = {0};\r
268         gethostname ( (char*)szLocalHostName, sizeof(szLocalHostName) );\r
269 \r
270         // hello£¬ÎÕÊÖ\r
271         if ( !Send ( _T("HELO %s\r\n"), GetCompatibleString(szLocalHostName,FALSE) ) )\r
272         {\r
273                 return FALSE;\r
274         }\r
275         if ( !GetResponse ( _T("250") ) )\r
276         {\r
277                 return FALSE;\r
278         }\r
279         // Éí·ÝÑéÖ¤\r
280         if ( m_bMustAuth && !auth() )\r
281         {\r
282                 return FALSE;\r
283         }\r
284         // ·¢ËÍÓʼþÍ·\r
285         if ( !SendHead() )\r
286         {\r
287                 return FALSE;\r
288         }\r
289         // ·¢ËÍÓʼþÖ÷Ìâ\r
290         if ( !SendSubject() )\r
291         {\r
292                 return FALSE;\r
293         }\r
294         // ·¢ËÍÓʼþÕýÎÄ\r
295         if ( !SendBody() )\r
296         {\r
297                 return FALSE;\r
298         }\r
299         // ·¢Ë͸½¼þ\r
300         if ( !SendAttach() )\r
301         {\r
302                 return FALSE;\r
303         }\r
304         // ½áÊøÓʼþÕýÎÄ\r
305         if ( !Send ( _T(".\r\n") ) ) return FALSE;\r
306         if ( !GetResponse ( _T("250") ) )\r
307                 return FALSE;\r
308 \r
309         // Í˳ö·¢ËÍ\r
310         if ( HANDLE_IS_VALID(m_SendSock.m_hSocket) )\r
311                 Send ( _T("QUIT\r\n") );\r
312         m_bConnected = FALSE;\r
313 \r
314         return bRet;\r
315 }\r
316 \r
317 BOOL CHwSMTP::auth()\r
318 {\r
319         int nResponseCode = 0;\r
320         if ( !Send ( _T("auth login\r\n") ) ) return FALSE;\r
321         if ( !GetResponse ( _T("334"), &nResponseCode ) ) return FALSE;\r
322         if ( nResponseCode != 334 )     // ²»ÐèÒªÑéÖ¤Óû§ÃûºÍÃÜÂë\r
323                 return TRUE;\r
324         \r
325         CBase64 Base64Encode;\r
326         CMultiByteString cbsUserName ( m_csUserName ), cbsPasswd ( m_csPasswd );\r
327         CString csBase64_UserName = GetCompatibleString ( Base64Encode.Encode ( cbsUserName.GetBuffer(), cbsUserName.GetLength() ).GetBuffer(0), FALSE );\r
328         CString csBase64_Passwd = GetCompatibleString ( Base64Encode.Encode ( cbsPasswd.GetBuffer(), cbsPasswd.GetLength() ).GetBuffer(0), FALSE );\r
329 \r
330         if ( !Send ( _T("%s\r\n"), csBase64_UserName ) ) return FALSE;\r
331         if ( !GetResponse ( _T("334") ) )\r
332         {\r
333                 m_csLastError.Format ( _T("Authentication UserName failed") );\r
334                 return FALSE;\r
335         }\r
336 \r
337         if ( !Send ( _T("%s\r\n"), csBase64_Passwd ) ) return FALSE;\r
338         if ( !GetResponse ( _T("235") ) )\r
339         {\r
340                 m_csLastError.Format ( _T("Authentication Password failed") );\r
341                 return FALSE;\r
342         }\r
343 \r
344         return TRUE;\r
345 }\r
346 \r
347 BOOL CHwSMTP::SendHead()\r
348 {\r
349         if ( !Send ( _T("MAIL From: <%s>\r\n"), m_csAddrFrom ) ) return FALSE;\r
350         if ( !GetResponse ( _T("250") ) ) return FALSE;\r
351         if ( !Send ( _T("RCPT TO: <%s>\r\n"), m_csAddrTo ) ) return FALSE;\r
352         if ( !GetResponse ( _T("250") ) ) return FALSE;\r
353 \r
354         for ( int i=0; i<m_StrAryCC.GetSize(); i++ )\r
355         {\r
356                 if ( !Send ( _T("RCPT TO: <%s>\r\n"), m_StrAryCC.GetAt(i) ) ) return FALSE;\r
357                 if ( !GetResponse ( _T("250") ) ) return FALSE;\r
358         }\r
359         if ( !Send ( _T("DATA\r\n") ) ) return FALSE;\r
360         if ( !GetResponse ( _T("354") ) ) return FALSE; \r
361 \r
362         return TRUE;\r
363 }\r
364 \r
365 BOOL CHwSMTP::SendSubject()\r
366 {\r
367         CString csSubject;\r
368         csSubject += _T("Date: ");\r
369         COleDateTime tNow = COleDateTime::GetCurrentTime();\r
370         if ( tNow > 1 )\r
371         {\r
372                 csSubject += GetCompatibleString(FormatDateTime (tNow, _T("%a, %d %b %y %H:%M:%S %Z")).GetBuffer(0),FALSE);\r
373         }\r
374         csSubject += _T("\r\n");\r
375         csSubject += FormatString ( _T("From: %s\r\nTo: %s\r\n"), m_csSenderName, m_csReceiverName );\r
376         csSubject += FormatString ( _T("Subject: %s\r\n"), m_csSubject );\r
377         csSubject += FormatString ( _T("X-Mailer: chrys\r\nMIME-Version: 1.0\r\nContent-Type: %s; %s boundary=%s\r\n\r\n") , \r
378                 m_csMIMEContentType, m_csCharSet, m_csPartBoundary );\r
379 \r
380         return Send ( csSubject );\r
381 }\r
382 \r
383 BOOL CHwSMTP::SendBody()\r
384 {\r
385         CString csBody, csTemp;\r
386 \r
387         if ( m_StrAryAttach.GetSize() > 0 )\r
388         {\r
389                 csTemp.Format ( _T("%s\r\n\r\n"), m_csNoMIMEText );\r
390                 csBody += csTemp;\r
391                 \r
392                 csTemp.Format ( _T("--%s\r\n"), m_csPartBoundary );\r
393                 csBody += csTemp;\r
394                 \r
395                 csTemp.Format ( _T("Content-Type: text/plain\r\n%sContent-Transfer-Encoding: 7Bit\r\n\r\n"),\r
396                         m_csCharSet );\r
397                 csBody += csTemp;\r
398         }\r
399 \r
400         csTemp.Format ( _T("%s\r\n"), m_csBody );\r
401         csBody += csTemp;\r
402 \r
403         if ( m_StrAryAttach.GetSize() > 0 )\r
404         {\r
405                 csTemp.Format ( _T("--%s\r\n"), m_csPartBoundary );\r
406                 csBody += csTemp;\r
407         }\r
408 \r
409         return Send ( csBody );\r
410 }\r
411 \r
412 BOOL CHwSMTP::SendAttach()\r
413 {\r
414         int nCountAttach = (int)m_StrAryAttach.GetSize();\r
415         if ( nCountAttach < 1 ) return TRUE;\r
416 \r
417         for ( int i=0; i<nCountAttach; i++ )\r
418         {\r
419                 if ( !SendOnAttach ( m_StrAryAttach.GetAt(i) ) )\r
420                         return FALSE;\r
421         }\r
422 \r
423         return TRUE;\r
424 }\r
425 \r
426 BOOL CHwSMTP::SendOnAttach(LPCTSTR lpszFileName)\r
427 {\r
428         ASSERT ( lpszFileName );\r
429         CString csAttach, csTemp;\r
430 \r
431         csTemp = lpszFileName;\r
432         CString csShortFileName = csTemp.GetBuffer(0) + csTemp.ReverseFind ( '\\' );\r
433         csShortFileName.TrimLeft ( _T("\\") );\r
434 \r
435         csTemp.Format ( _T("Content-Type: application/octet-stream; file=%s\r\n"), csShortFileName );\r
436         csAttach += csTemp;\r
437 \r
438         csTemp.Format ( _T("Content-Transfer-Encoding: base64\r\n") );\r
439         csAttach += csTemp;\r
440 \r
441         csTemp.Format ( _T("Content-Disposition: attachment; filename=%s\r\n\r\n"), csShortFileName );\r
442         csAttach += csTemp;\r
443 \r
444         DWORD dwFileSize =  hwGetFileAttr(lpszFileName);\r
445         if ( dwFileSize > 5*1024*1024 )\r
446         {\r
447                 m_csLastError.Format ( _T("File [%s] too big. File size is : %s"), lpszFileName, FormatBytes(dwFileSize) );\r
448                 return FALSE;\r
449         }\r
450         char *pBuf = new char[dwFileSize+1];\r
451         if ( !pBuf ) \r
452         {\r
453                 ::AfxThrowMemoryException ();\r
454                 return FALSE;\r
455         }\r
456 \r
457         CFile file;\r
458         try\r
459         {\r
460                 if ( !file.Open ( lpszFileName, CFile::modeRead ) )\r
461                 {\r
462                         m_csLastError.Format ( _T("Open file [%s] failed"), lpszFileName );\r
463                         return FALSE;\r
464                 }\r
465                 UINT nFileLen = file.Read ( pBuf, dwFileSize );\r
466                 CBase64 Base64Encode;\r
467                 csTemp = Base64Encode.Encode ( pBuf, nFileLen );\r
468                 csAttach += csTemp;\r
469                 csAttach += _T("\r\n\r\n");\r
470         }\r
471         catch ( CFileException e )\r
472         {\r
473                 e.Delete();\r
474                 m_csLastError.Format ( _T("Read file [%s] failed"), lpszFileName );\r
475                 delete[] pBuf;\r
476                 return FALSE;\r
477         }\r
478 \r
479         csTemp.Format ( _T("--%s\r\n"), m_csPartBoundary );\r
480         csAttach += csTemp;\r
481 \r
482         delete[] pBuf;\r
483         \r
484         return Send ( csAttach );\r
485 }\r
486 \r
487 CString CHwSMTP::GetLastErrorText()\r
488 {\r
489         return m_csLastError;\r
490 }\r
491 \r
492 \r
493 DWORD WINAPI ThreadProc_SendEmail( LPVOID lpParameter )\r
494 {\r
495         CEMailObject *pEMailObject = (CEMailObject*)lpParameter;\r
496         ASSERT ( pEMailObject );\r
497 \r
498         CHwSMTP HwSMTP;\r
499         BOOL bRet = HwSMTP.SendEmail (\r
500                 pEMailObject->m_csSmtpSrvHost,\r
501                 pEMailObject->m_csUserName,\r
502                 pEMailObject->m_csPasswd,\r
503                 pEMailObject->m_bMustAuth,\r
504                 pEMailObject->m_csAddrFrom,\r
505                 pEMailObject->m_csAddrTo,\r
506                 pEMailObject->m_csSenderName,\r
507                 pEMailObject->m_csReceiverName,\r
508                 pEMailObject->m_csSubject,\r
509                 pEMailObject->m_csBody,\r
510                 pEMailObject->m_csCharSet,\r
511                 &pEMailObject->m_StrAryAttach,\r
512                 &pEMailObject->m_StrAryCC,\r
513                 pEMailObject->m_nSmtpSrvPort\r
514                 );\r
515         if ( !bRet)\r
516         {\r
517 #ifdef _DEBUG\r
518                 CString csError = HwSMTP.GetLastErrorText ();\r
519                 csError = FormatString ( _T("Send a email to [%s] failed."), pEMailObject->m_csSmtpSrvHost );\r
520                 AfxMessageBox ( csError );\r
521 #endif\r
522         }\r
523 \r
524         m_CSFor__g_PtrAry_Threads.Lock ();\r
525         int nFindPos = FindFromArray ( g_PtrAry_Threads, pEMailObject->m_hThread );\r
526         if ( nFindPos >= 0 )\r
527                 g_PtrAry_Threads.RemoveAt ( nFindPos );\r
528         m_CSFor__g_PtrAry_Threads.Unlock ();\r
529 \r
530         delete pEMailObject;\r
531         return bRet;\r
532 }\r
533 \r
534 //\r
535 // ÓàSMTP ·þÎñ·¢Ë͵ç×ÓÓʼþ£¬Èç¹ûÉèÖòÎÊý bViaThreadSend=TRUE£¬ÄÇÔÚ³ÌÐò½áÊøʱӦ¸ÃÔÚ ExitInstance() Öе÷ÓàEndOfSMTP() º¯Êý\r
536 //\r
537 BOOL SendEmail (\r
538                                 BOOL bViaThreadSend,\r
539                                 LPCTSTR lpszSmtpSrvHost,\r
540                                 LPCTSTR lpszUserName,\r
541                                 LPCTSTR lpszPasswd,\r
542                                 BOOL bMustAuth,\r
543                                 LPCTSTR lpszAddrFrom,\r
544                                 LPCTSTR lpszAddrTo,\r
545                                 LPCTSTR lpszSenderName,\r
546                                 LPCTSTR lpszReceiverName,\r
547                                 LPCTSTR lpszSubject,\r
548                                 LPCTSTR lpszBody,\r
549                                 LPCTSTR lpszCharSet/*=NULL*/,\r
550                                 CStringArray *pStrAryAttach/*=NULL*/,\r
551                                 CStringArray *pStrAryCC/*=NULL*/,\r
552                                 UINT nSmtpSrvPort/*=25*/\r
553                                 )\r
554 {\r
555         if ( !lpszSmtpSrvHost || lstrlen(lpszSmtpSrvHost) < 1 ||\r
556                 !lpszSubject || lstrlen(lpszSubject) < 1 ||\r
557                 !lpszBody || lstrlen(lpszBody) < 1 )\r
558         {\r
559                 AfxMessageBox ( _T("Parameter error !") );\r
560                 return FALSE;\r
561         }\r
562 \r
563         CEMailObject *pEMailObject = new CEMailObject (\r
564                 lpszSmtpSrvHost,\r
565                 lpszUserName,\r
566                 lpszPasswd,\r
567                 bMustAuth,\r
568                 lpszAddrFrom,\r
569                 lpszAddrTo,\r
570                 lpszSenderName,\r
571                 lpszReceiverName,\r
572                 lpszSubject,\r
573                 lpszBody,\r
574                 lpszCharSet,\r
575                 pStrAryAttach,\r
576                 pStrAryCC,\r
577                 nSmtpSrvPort\r
578                 );\r
579         if ( !pEMailObject ) return FALSE;\r
580 \r
581         BOOL bRet = FALSE;\r
582         if ( bViaThreadSend )\r
583         {\r
584                 DWORD dwThreadId = 0;\r
585                 pEMailObject->m_hThread = ::CreateThread ( NULL, 0, ::ThreadProc_SendEmail, pEMailObject, CREATE_SUSPENDED, &dwThreadId );\r
586                 bRet = HANDLE_IS_VALID(pEMailObject->m_hThread);\r
587                 m_CSFor__g_PtrAry_Threads.Lock();\r
588                 g_PtrAry_Threads.Add ( pEMailObject->m_hThread );\r
589                 m_CSFor__g_PtrAry_Threads.Unlock();\r
590                 ResumeThread ( pEMailObject->m_hThread );\r
591         }\r
592         else\r
593         {\r
594                 bRet = (BOOL)ThreadProc_SendEmail ( pEMailObject );\r
595         }\r
596 \r
597         return bRet;\r
598 }\r
599 \r
600 void EndOfSMTP ()\r
601 {\r
602         // µÈ´ýËùÓÐÏß³ÌÖ´ÐÐÍê±Ï\r
603         for ( int i=0; i<g_PtrAry_Threads.GetSize(); i++ )\r
604         {\r
605                 HANDLE hThread = (HANDLE)g_PtrAry_Threads.GetAt(i);\r
606                 if ( HANDLE_IS_VALID(hThread) )\r
607                 {\r
608                         WaitForThreadEnd ( &hThread, 30*1000 );\r
609                 }\r
610         }\r
611         g_PtrAry_Threads.RemoveAll ();\r
612 }\r
613 \r
614 \r
615 //\r
616 // ½«×Ö·û´® lpszOrg ×ª»»Îª¶à×Ö½ÚµÄ×Ö·û´®£¬Èç¹û»¹ÒªÊ¹Óöà×Ö·û´®µÄ³¤¶È£¬¿ÉÒÔÓÃÒÔÏ·½Ê½À´Ê¹ÓÃÕâ¸öÀࣺ\r
617 // CMultiByteString MultiByteString(_T("UNICODE×Ö·û´®"));\r
618 // printf ( "ANSI ×Ö·û´®Îª£º %s£¬ ×Ö·û¸öÊýΪ£º %d £¬ ³¤¶ÈΪ£º %d×Ö½Ú\n", MultiByteString.GetBuffer(), MultiByteString.GetLength(), MultiByteString.GetSize() );\r
619 //\r
620 CMultiByteString::CMultiByteString( LPCTSTR lpszOrg, int nOrgStringEncodeType/*=STRING_IS_SOFTCODE*/, OUT char *pOutBuf/*=NULL*/, int nOutBufSize/*=0*/ )\r
621 {\r
622         m_bNewBuffer = FALSE;\r
623         m_pszData = NULL;\r
624         m_nDataSize = 0;\r
625         m_nCharactersNumber = 0;\r
626         if ( !lpszOrg ) return;\r
627         \r
628         // ÅжÏԭʼ×Ö·û´®µÄ±àÂ뷽ʽ\r
629         BOOL bOrgIsUnicode = FALSE;\r
630         if ( nOrgStringEncodeType == STRING_IS_MULTICHARS ) bOrgIsUnicode = FALSE;\r
631         else if ( nOrgStringEncodeType == STRING_IS_UNICODE ) bOrgIsUnicode = TRUE;\r
632         else\r
633         {\r
634 #ifdef UNICODE\r
635                 bOrgIsUnicode = TRUE;\r
636 #else\r
637                 bOrgIsUnicode = FALSE;\r
638 #endif\r
639         }\r
640         \r
641         // ¼ÆËã×Ö·û´®¸öÊýºÍÐèÒªµÄÄ¿±ê»º³å´óС\r
642         if ( bOrgIsUnicode )\r
643         {\r
644                 m_nCharactersNumber = (int)wcslen((WCHAR*)lpszOrg);\r
645                 m_nDataSize = (m_nCharactersNumber + 1) * sizeof(WCHAR);\r
646         }\r
647         else\r
648         {\r
649                 m_nCharactersNumber = (int)strlen((char*)lpszOrg);\r
650                 m_nDataSize = (m_nCharactersNumber + 1) * sizeof(char);\r
651         }\r
652         \r
653         // Ê¹Óõ÷ÓÃÕß´«ÈëµÄ»º³å\r
654         if ( pOutBuf && nOutBufSize > 0 )\r
655         {\r
656                 m_pszData = pOutBuf;\r
657                 m_nDataSize = nOutBufSize;\r
658         }\r
659         // ×Ô¼ºÉêÇëÄڴ滺³å\r
660         else\r
661         {\r
662                 m_pszData = (char*)new BYTE[m_nDataSize];\r
663                 if ( !m_pszData )\r
664                 {\r
665                         ::AfxThrowMemoryException ();\r
666                         return;\r
667                 }\r
668                 m_bNewBuffer = TRUE;\r
669         }\r
670         memset ( m_pszData, 0, m_nDataSize );\r
671         \r
672         if ( bOrgIsUnicode )\r
673         {\r
674                 m_nCharactersNumber = WideCharToMultiByte ( CP_ACP, 0, (LPCWSTR)lpszOrg, m_nCharactersNumber, (LPSTR)m_pszData, m_nDataSize/sizeof(char)-1, NULL, NULL );\r
675                 if ( m_nCharactersNumber < 1 ) m_nCharactersNumber = (int)strlen ( m_pszData );\r
676         }\r
677         else\r
678         {\r
679                 m_nCharactersNumber = __min ( m_nCharactersNumber, (int)(m_nDataSize/sizeof(char)-1) );\r
680                 strncpy ( m_pszData, (const char*)lpszOrg, m_nCharactersNumber );\r
681                 m_nCharactersNumber = (int)strlen ( m_pszData );\r
682         }\r
683         m_nDataSize = ( m_nCharactersNumber + 1 ) * sizeof(char);\r
684 }\r
685 \r
686 CMultiByteString::~CMultiByteString ()\r
687 {\r
688         if ( m_bNewBuffer && m_pszData )\r
689         {\r
690                 delete[] m_pszData;\r
691         }\r
692 }\r
693 \r
694 //\r
695 // ½« lpszOrg ×ª»»Îª¸Ã³ÌÐòʹÓõıàÂë×Ö·û´®£¬Èç¹û¸Ã³ÌÐòÊÇ UNICODE ¾ÍתΪ UNICODE£¬Èç¹ûÊÇ ANSI ¾ÍתΪ ANSI µÄ\r
696 //\r
697 CString GetCompatibleString ( LPVOID lpszOrg, BOOL bOrgIsUnicode, int nOrgLength/*=-1*/ )\r
698 {\r
699         if ( !lpszOrg ) return _T("");\r
700         \r
701         TRY\r
702         {\r
703 #ifdef UNICODE\r
704                 if ( bOrgIsUnicode )\r
705                 {\r
706                         if ( nOrgLength > 0 )\r
707                         {\r
708                                 WCHAR *szRet = new WCHAR[nOrgLength+1];\r
709                                 if ( !szRet ) return _T("");\r
710                                 memset ( szRet, 0, (nOrgLength+1)*sizeof(WCHAR) );\r
711                                 memcpy ( szRet, lpszOrg, nOrgLength*sizeof(WCHAR) );\r
712                                 CString csRet = szRet;\r
713                                 delete[] szRet;\r
714                                 return csRet;\r
715                         }\r
716                         else if ( nOrgLength == 0 )\r
717                                 return _T("");\r
718                         else\r
719                                 return (LPCTSTR)lpszOrg;\r
720                 }\r
721                 \r
722                 if ( nOrgLength < 0 )\r
723                         nOrgLength = (int)strlen((const char*)lpszOrg);\r
724                 int nWideCount = nOrgLength + 1;\r
725                 WCHAR *wchar = new WCHAR[nWideCount];\r
726                 if ( !wchar ) return _T("");\r
727                 memset ( wchar, 0, nWideCount*sizeof(WCHAR) );\r
728                 ::MultiByteToWideChar(CP_ACP, 0, (LPCSTR)lpszOrg, nOrgLength, wchar, nWideCount);\r
729                 CString csRet = wchar;\r
730                 delete[] wchar;\r
731                 return csRet;\r
732 #else\r
733                 if ( !bOrgIsUnicode )\r
734                 {\r
735                         if ( nOrgLength > 0 )\r
736                         {\r
737                                 char *szRet = new char[nOrgLength+1];\r
738                                 if ( !szRet ) return _T("");\r
739                                 memset ( szRet, 0, (nOrgLength+1)*sizeof(char) );\r
740                                 memcpy ( szRet, lpszOrg, nOrgLength*sizeof(char) );\r
741                                 CString csRet = szRet;\r
742                                 delete[] szRet;\r
743                                 return csRet;\r
744                         }\r
745                         else if ( nOrgLength == 0 )\r
746                                 return _T("");\r
747                         else\r
748                                 return (LPCTSTR)lpszOrg;\r
749                 }\r
750                 \r
751                 if ( nOrgLength < 0 )\r
752                         nOrgLength = (int)wcslen((WCHAR*)lpszOrg);\r
753                 int nMultiByteCount = nOrgLength + 1;\r
754                 char *szMultiByte = new char[nMultiByteCount];\r
755                 if ( !szMultiByte ) return _T("");\r
756                 memset ( szMultiByte, 0, nMultiByteCount*sizeof(char) );\r
757                 ::WideCharToMultiByte ( CP_ACP, 0, (LPCWSTR)lpszOrg, nOrgLength, (LPSTR)szMultiByte, nMultiByteCount, NULL, NULL );\r
758                 CString csRet = szMultiByte;\r
759                 delete[] szMultiByte;\r
760                 return csRet;\r
761 #endif\r
762         }\r
763         CATCH_ALL(e)\r
764         {\r
765                 THROW_LAST ();\r
766         }\r
767         END_CATCH_ALL\r
768                 \r
769                 return _T("");\r
770 }\r
771 \r
772 CString FormatDateTime ( COleDateTime &DateTime, LPCTSTR pFormat )\r
773 {       \r
774         // If null, return empty string\r
775         if ( DateTime.GetStatus() == COleDateTime::null || DateTime.GetStatus() == COleDateTime::invalid )\r
776                 return _T("");\r
777         \r
778         UDATE ud;\r
779         if (S_OK != VarUdateFromDate(DateTime.m_dt, 0, &ud))\r
780         {\r
781                 return _T("");\r
782         }\r
783         \r
784         struct tm tmTemp;\r
785         tmTemp.tm_sec   = ud.st.wSecond;\r
786         tmTemp.tm_min   = ud.st.wMinute;\r
787         tmTemp.tm_hour  = ud.st.wHour;\r
788         tmTemp.tm_mday  = ud.st.wDay;\r
789         tmTemp.tm_mon   = ud.st.wMonth - 1;\r
790         tmTemp.tm_year  = ud.st.wYear - 1900;\r
791         tmTemp.tm_wday  = ud.st.wDayOfWeek;\r
792         tmTemp.tm_yday  = ud.wDayOfYear - 1;\r
793         tmTemp.tm_isdst = 0;\r
794         \r
795         CString strDate;\r
796         LPTSTR lpszTemp = strDate.GetBufferSetLength(256);\r
797         _tcsftime(lpszTemp, strDate.GetLength(), pFormat, &tmTemp);\r
798         strDate.ReleaseBuffer();\r
799         \r
800         return strDate;\r
801 }\r
802 \r
803 CString FormatString ( LPCTSTR lpszStr, ... )\r
804 {\r
805         TCHAR *buf = NULL;\r
806         // Ñ­»·¸ñʽ»¯×Ö·û´®£¬Èç¹û»º³å²»¹»Ôò½«»º³å¼Ó´óÈ»ºóÖØÊÔÒÔ±£Ö¤»º³å¹»ÓÃͬʱÓÖ²»ÀË·Ñ\r
807         for ( int nBufCount = 1024; nBufCount<5*1024*1024; nBufCount += 1024 )\r
808         {\r
809                 buf = new TCHAR[nBufCount];\r
810                 if ( !buf )\r
811                 {\r
812                         ::AfxThrowMemoryException ();\r
813                         return _T("");\r
814                 }\r
815                 memset ( buf, 0, nBufCount*sizeof(TCHAR) );\r
816                 \r
817                 va_list  va;\r
818                 va_start (va, lpszStr);\r
819                 int nLen = _vsnprintf_hw ((TCHAR*)buf, nBufCount-sizeof(TCHAR), lpszStr, va);\r
820                 va_end(va);\r
821                 if ( nLen <= (int)(nBufCount-sizeof(TCHAR)) )\r
822                         break;\r
823                 delete[] buf; buf = NULL;\r
824         }\r
825         if ( !buf )\r
826         {\r
827                 return _T("");\r
828         }\r
829         \r
830         CString csMsg = buf;\r
831         delete[] buf; buf = NULL;\r
832         return csMsg;\r
833 }\r
834 \r
835 /********************************************************************************\r
836 * Function Type :       Global\r
837 * Parameter             :       lpFileName      -       Îļþ·¾¶\r
838 * Return Value  :       -1                      -       Ê§°Ü\r
839 *                                       >=0                     -       Îļþ´óС\r
840 * Description   :       »ñÈ¡ÎļþÊôÐÔ ( Îļþ´óС¡¢´´½¨Ê±¼ä )\r
841 *********************************************************************************/\r
842 int hwGetFileAttr ( LPCTSTR lpFileName, OUT CFileStatus *pFileStatus/*=NULL*/ )\r
843 {\r
844         if ( !lpFileName || lstrlen(lpFileName) < 1 ) return -1;\r
845         \r
846         CFileStatus fileStatus;\r
847         fileStatus.m_attribute = 0;\r
848         fileStatus.m_size = 0;\r
849         memset ( fileStatus.m_szFullName, 0, sizeof(fileStatus.m_szFullName) );\r
850         BOOL bRet = FALSE;\r
851         TRY\r
852         {\r
853                 if ( CFile::GetStatus(lpFileName,fileStatus) )\r
854                 {\r
855                         bRet = TRUE;\r
856                 }\r
857         }\r
858         CATCH (CFileException, e)\r
859         {\r
860                 ASSERT ( FALSE );\r
861                 bRet = FALSE;\r
862         }\r
863         CATCH_ALL(e)\r
864         {\r
865                 ASSERT ( FALSE );\r
866                 bRet = FALSE;\r
867         }\r
868         END_CATCH_ALL;\r
869         \r
870         if ( pFileStatus )\r
871         {\r
872                 pFileStatus->m_ctime = fileStatus.m_ctime;\r
873                 pFileStatus->m_mtime = fileStatus.m_mtime;\r
874                 pFileStatus->m_atime = fileStatus.m_atime;\r
875                 pFileStatus->m_size = fileStatus.m_size;\r
876                 pFileStatus->m_attribute = fileStatus.m_attribute;\r
877                 pFileStatus->_m_padding = fileStatus._m_padding;\r
878                 lstrcpy ( pFileStatus->m_szFullName, fileStatus.m_szFullName );\r
879                 \r
880         }\r
881         \r
882         return (int)fileStatus.m_size;\r
883 }\r
884 \r
885 //\r
886 // ½«Ò»¸ö±íʾ×Ö½ÚµÄÊýÓÿɶÁÐԺõÄ×Ö·û´®À´±íʾ£¬ÀýÈ罫 12345678 ×Ö½Úת»»Îª£º\r
887 // 11.77M\r
888 // nFlag        -       0 : ×Ô¶¯Æ¥Å䵥λ\r
889 //                              1 : ÒÔ Kb Îªµ¥Î»\r
890 //                              2 : ÒÔ Mb Îªµ¥Î»\r
891 //                              3 : ÒÔ Gb Îªµ¥Î»\r
892 // \r
893 CString FormatBytes ( double fBytesNum, BOOL bShowUnit/*=TRUE*/, int nFlag/*=0*/ )\r
894 {\r
895         CString csRes;\r
896         if ( nFlag == 0 )\r
897         {\r
898                 if ( fBytesNum >= 1024.0 && fBytesNum < 1024.0*1024.0 )\r
899                         csRes.Format ( _T("%.2f%s"), fBytesNum / 1024.0, bShowUnit?_T(" K"):_T("") );\r
900                 else if ( fBytesNum >= 1024.0*1024.0 && fBytesNum < 1024.0*1024.0*1024.0 )\r
901                         csRes.Format ( _T("%.2f%s"), fBytesNum / (1024.0*1024.0), bShowUnit?_T(" M"):_T("") );\r
902                 else if ( fBytesNum >= 1024.0*1024.0*1024.0 )\r
903                         csRes.Format ( _T("%.2f%s"), fBytesNum / (1024.0*1024.0*1024.0), bShowUnit?_T(" G"):_T("") );\r
904                 else\r
905                         csRes.Format ( _T("%.2f%s"), fBytesNum, bShowUnit?_T(" B"):_T("") );\r
906         }\r
907         else if ( nFlag == 1 )\r
908         {\r
909                 csRes.Format ( _T("%.2f%s"), fBytesNum / 1024.0, bShowUnit?_T(" K"):_T("") );\r
910         }\r
911         else if ( nFlag == 2 )\r
912         {\r
913                 csRes.Format ( _T("%.2f%s"), fBytesNum / (1024.0*1024.0), bShowUnit?_T(" M"):_T("") );\r
914         }\r
915         else if ( nFlag == 3 )\r
916         {\r
917                 csRes.Format ( _T("%.2f%s"), fBytesNum / (1024.0*1024.0*1024.0), bShowUnit?_T(" G"):_T("") );\r
918         }\r
919         \r
920         return csRes;\r
921 }\r
922 \r
923 //\r
924 // µÈ´ýÏß³ÌÍ˳ö\r
925 //\r
926 BOOL WaitForThreadEnd ( HANDLE *phThread, DWORD dwWaitTime /*=10*1000*/ )\r
927 {\r
928         BOOL bRet = TRUE;\r
929         ASSERT ( phThread );\r
930         if ( !(*phThread) ) return TRUE;\r
931         if ( ::WaitForSingleObject ( *phThread, dwWaitTime ) == WAIT_TIMEOUT )\r
932         {\r
933                 bRet = FALSE;\r
934                 ::TerminateThread ( *phThread, 0 );\r
935         }\r
936         ::CloseHandle ( *phThread );\r
937         (*phThread) = NULL;\r
938         return bRet;\r
939 }\r