OSDN Git Service

Success Send patch body but attachment have been problem
[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 BOOL CHwSMTP::SendBuffer(char *buff,int size)\r
217 {\r
218         if(size<0)\r
219                 size=strlen(buff);\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         if ( m_SendSock.Send ( buff, size ) != size )\r
227         {\r
228                 m_csLastError.Format ( _T("Socket send data failed") );\r
229                 return FALSE;\r
230         }\r
231         \r
232         return TRUE;\r
233 }\r
234 // ÀûÓÃsocket·¢ËÍÊý¾Ý£¬Êý¾Ý³¤¶È²»Äܳ¬¹ý10M\r
235 BOOL CHwSMTP::Send(LPCTSTR lpszData, ... )\r
236 {\r
237         if ( !m_bConnected )\r
238         {\r
239                 m_csLastError.Format ( _T("Didn't connect") );\r
240                 return FALSE;\r
241         }\r
242 \r
243         TCHAR *buf = NULL;\r
244         // Ñ­»·¸ñʽ»¯×Ö·û´®£¬Èç¹û»º³å²»¹»Ôò½«»º³å¼Ó´óÈ»ºóÖØÊÔÒÔ±£Ö¤»º³å¹»ÓÃͬʱÓÖ²»ÀË·Ñ\r
245         for ( int nBufCount = 1024; nBufCount<10*1024*1024; nBufCount += 1024 )\r
246         {\r
247                 buf = new TCHAR[nBufCount];\r
248                 if ( !buf )\r
249                 {\r
250                         ::AfxThrowMemoryException ();\r
251                         return FALSE;\r
252                 }\r
253                 memset ( buf, 0, nBufCount*sizeof(TCHAR) );\r
254 \r
255                 va_list  va;\r
256                 va_start (va, lpszData);\r
257                 int nLen = _vsnprintf_hw ((TCHAR*)buf, nBufCount-sizeof(TCHAR), lpszData, va);\r
258                 va_end(va);\r
259                 if ( nLen <= (int)(nBufCount-sizeof(TCHAR)) )\r
260                         break;\r
261                 delete[] buf; buf = NULL;\r
262         }\r
263         if ( !buf )\r
264         {\r
265                 m_csLastError.Format ( _T("Memory too small or data too big.") );\r
266                 return FALSE;\r
267         }\r
268 \r
269         CMultiByteString cbsData ( buf );\r
270         delete[] buf; buf = NULL;\r
271         TRACE ( _T("Send : %s\r\n"), cbsData.GetBuffer() );\r
272         if ( m_SendSock.Send ( cbsData.GetBuffer(), cbsData.GetLength() ) != cbsData.GetLength() )\r
273         {\r
274                 m_csLastError.Format ( _T("Socket send data failed") );\r
275                 return FALSE;\r
276         }\r
277         \r
278         return TRUE;\r
279 }\r
280 \r
281 BOOL CHwSMTP::SendEmail()\r
282 {\r
283         BOOL bRet = TRUE;\r
284         char szLocalHostName[64] = {0};\r
285         gethostname ( (char*)szLocalHostName, sizeof(szLocalHostName) );\r
286 \r
287         // hello£¬ÎÕÊÖ\r
288         if ( !Send ( _T("HELO %s\r\n"), GetCompatibleString(szLocalHostName,FALSE) ) )\r
289         {\r
290                 return FALSE;\r
291         }\r
292         if ( !GetResponse ( _T("250") ) )\r
293         {\r
294                 return FALSE;\r
295         }\r
296         // Éí·ÝÑéÖ¤\r
297         if ( m_bMustAuth && !auth() )\r
298         {\r
299                 return FALSE;\r
300         }\r
301         // ·¢ËÍÓʼþÍ·\r
302         if ( !SendHead() )\r
303         {\r
304                 return FALSE;\r
305         }\r
306         // ·¢ËÍÓʼþÖ÷Ìâ\r
307         if ( !SendSubject() )\r
308         {\r
309                 return FALSE;\r
310         }\r
311         // ·¢ËÍÓʼþÕýÎÄ\r
312         if ( !SendBody() )\r
313         {\r
314                 return FALSE;\r
315         }\r
316         // ·¢Ë͸½¼þ\r
317         if ( !SendAttach() )\r
318         {\r
319                 return FALSE;\r
320         }\r
321         // ½áÊøÓʼþÕýÎÄ\r
322         if ( !Send ( _T(".\r\n") ) ) return FALSE;\r
323         if ( !GetResponse ( _T("250") ) )\r
324                 return FALSE;\r
325 \r
326         // Í˳ö·¢ËÍ\r
327         if ( HANDLE_IS_VALID(m_SendSock.m_hSocket) )\r
328                 Send ( _T("QUIT\r\n") );\r
329         m_bConnected = FALSE;\r
330 \r
331         return bRet;\r
332 }\r
333 \r
334 BOOL CHwSMTP::auth()\r
335 {\r
336         int nResponseCode = 0;\r
337         if ( !Send ( _T("auth login\r\n") ) ) return FALSE;\r
338         if ( !GetResponse ( _T("334"), &nResponseCode ) ) return FALSE;\r
339         if ( nResponseCode != 334 )     // ²»ÐèÒªÑéÖ¤Óû§ÃûºÍÃÜÂë\r
340                 return TRUE;\r
341         \r
342         CBase64 Base64Encode;\r
343         CMultiByteString cbsUserName ( m_csUserName ), cbsPasswd ( m_csPasswd );\r
344         CString csBase64_UserName = GetCompatibleString ( Base64Encode.Encode ( cbsUserName.GetBuffer(), cbsUserName.GetLength() ).GetBuffer(0), FALSE );\r
345         CString csBase64_Passwd = GetCompatibleString ( Base64Encode.Encode ( cbsPasswd.GetBuffer(), cbsPasswd.GetLength() ).GetBuffer(0), FALSE );\r
346 \r
347         if ( !Send ( _T("%s\r\n"), csBase64_UserName ) ) return FALSE;\r
348         if ( !GetResponse ( _T("334") ) )\r
349         {\r
350                 m_csLastError.Format ( _T("Authentication UserName failed") );\r
351                 return FALSE;\r
352         }\r
353 \r
354         if ( !Send ( _T("%s\r\n"), csBase64_Passwd ) ) return FALSE;\r
355         if ( !GetResponse ( _T("235") ) )\r
356         {\r
357                 m_csLastError.Format ( _T("Authentication Password failed") );\r
358                 return FALSE;\r
359         }\r
360 \r
361         return TRUE;\r
362 }\r
363 \r
364 BOOL CHwSMTP::SendHead()\r
365 {\r
366         if ( !Send ( _T("MAIL From: <%s>\r\n"), m_csAddrFrom ) ) return FALSE;\r
367         if ( !GetResponse ( _T("250") ) ) return FALSE;\r
368         if ( !Send ( _T("RCPT TO: <%s>\r\n"), m_csAddrTo ) ) return FALSE;\r
369         if ( !GetResponse ( _T("250") ) ) return FALSE;\r
370 \r
371         for ( int i=0; i<m_StrAryCC.GetSize(); i++ )\r
372         {\r
373                 if ( !Send ( _T("RCPT TO: <%s>\r\n"), m_StrAryCC.GetAt(i) ) ) return FALSE;\r
374                 if ( !GetResponse ( _T("250") ) ) return FALSE;\r
375         }\r
376         if ( !Send ( _T("DATA\r\n") ) ) return FALSE;\r
377         if ( !GetResponse ( _T("354") ) ) return FALSE; \r
378 \r
379         return TRUE;\r
380 }\r
381 \r
382 BOOL CHwSMTP::SendSubject()\r
383 {\r
384         CString csSubject;\r
385         csSubject += _T("Date: ");\r
386         COleDateTime tNow = COleDateTime::GetCurrentTime();\r
387         if ( tNow > 1 )\r
388         {\r
389                 csSubject += GetCompatibleString(FormatDateTime (tNow, _T("%a, %d %b %y %H:%M:%S %Z")).GetBuffer(0),FALSE);\r
390         }\r
391         csSubject += _T("\r\n");\r
392         csSubject += FormatString ( _T("From: %s\r\nTo: %s\r\n"), m_csSenderName, m_csReceiverName );\r
393         csSubject += FormatString ( _T("Subject: %s\r\n"), m_csSubject );\r
394         csSubject += FormatString ( _T("X-Mailer: chrys\r\nMIME-Version: 1.0\r\nContent-Type: %s; %s boundary=%s\r\n\r\n") , \r
395                 m_csMIMEContentType, m_csCharSet, m_csPartBoundary );\r
396 \r
397         return Send ( csSubject );\r
398 }\r
399 \r
400 BOOL CHwSMTP::SendBody()\r
401 {\r
402         CString csBody, csTemp;\r
403 \r
404         if ( m_StrAryAttach.GetSize() > 0 )\r
405         {\r
406                 csTemp.Format ( _T("%s\r\n\r\n"), m_csNoMIMEText );\r
407                 csBody += csTemp;\r
408                 \r
409                 csTemp.Format ( _T("--%s\r\n"), m_csPartBoundary );\r
410                 csBody += csTemp;\r
411                 \r
412                 csTemp.Format ( _T("Content-Type: text/plain\r\n%sContent-Transfer-Encoding: 7Bit\r\n\r\n"),\r
413                         m_csCharSet );\r
414                 csBody += csTemp;\r
415         }\r
416 \r
417         csTemp.Format ( _T("%s\r\n"), m_csBody );\r
418         csBody += csTemp;\r
419 \r
420         if ( m_StrAryAttach.GetSize() > 0 )\r
421         {\r
422                 csTemp.Format ( _T("--%s\r\n"), m_csPartBoundary );\r
423                 csBody += csTemp;\r
424         }\r
425 \r
426         return Send ( csBody );\r
427 }\r
428 \r
429 BOOL CHwSMTP::SendAttach()\r
430 {\r
431         int nCountAttach = (int)m_StrAryAttach.GetSize();\r
432         if ( nCountAttach < 1 ) return TRUE;\r
433 \r
434         for ( int i=0; i<nCountAttach; i++ )\r
435         {\r
436                 if ( !SendOnAttach ( m_StrAryAttach.GetAt(i) ) )\r
437                         return FALSE;\r
438         }\r
439 \r
440         return TRUE;\r
441 }\r
442 \r
443 BOOL CHwSMTP::SendOnAttach(LPCTSTR lpszFileName)\r
444 {\r
445         ASSERT ( lpszFileName );\r
446         CString csAttach, csTemp;\r
447 \r
448         csTemp = lpszFileName;\r
449         CString csShortFileName = csTemp.GetBuffer(0) + csTemp.ReverseFind ( '\\' );\r
450         csShortFileName.TrimLeft ( _T("\\") );\r
451 \r
452         csTemp.Format ( _T("Content-Type: application/octet-stream; file=%s\r\n"), csShortFileName );\r
453         csAttach += csTemp;\r
454 \r
455         csTemp.Format ( _T("Content-Transfer-Encoding: base64\r\n") );\r
456         csAttach += csTemp;\r
457 \r
458         csTemp.Format ( _T("Content-Disposition: attachment; filename=%s\r\n\r\n"), csShortFileName );\r
459         csAttach += csTemp;\r
460 \r
461         DWORD dwFileSize =  hwGetFileAttr(lpszFileName);\r
462         if ( dwFileSize > 5*1024*1024 )\r
463         {\r
464                 m_csLastError.Format ( _T("File [%s] too big. File size is : %s"), lpszFileName, FormatBytes(dwFileSize) );\r
465                 return FALSE;\r
466         }\r
467         char *pBuf = new char[dwFileSize+1];\r
468         if ( !pBuf ) \r
469         {\r
470                 ::AfxThrowMemoryException ();\r
471                 return FALSE;\r
472         }\r
473 \r
474         if(!Send ( csAttach ))\r
475                 return FALSE;\r
476 \r
477         CFile file;\r
478         CStringA filedata;\r
479         try\r
480         {\r
481                 if ( !file.Open ( lpszFileName, CFile::modeRead ) )\r
482                 {\r
483                         m_csLastError.Format ( _T("Open file [%s] failed"), lpszFileName );\r
484                         return FALSE;\r
485                 }\r
486                 UINT nFileLen = file.Read ( pBuf, dwFileSize );\r
487                 CBase64 Base64Encode;\r
488                 filedata = Base64Encode.Encode ( pBuf, nFileLen );\r
489                 filedata += _T("\r\n\r\n");\r
490         }\r
491         catch ( CFileException e )\r
492         {\r
493                 e.Delete();\r
494                 m_csLastError.Format ( _T("Read file [%s] failed"), lpszFileName );\r
495                 delete[] pBuf;\r
496                 return FALSE;\r
497         }\r
498 \r
499         if(!SendBuffer( filedata.GetBuffer() ))\r
500                 return FALSE;\r
501 \r
502         csAttach.Empty();\r
503         csTemp.Format ( _T("--%s\r\n"), m_csPartBoundary );\r
504         csAttach += csTemp;\r
505 \r
506         delete[] pBuf;\r
507         \r
508         return Send ( csAttach );\r
509 }\r
510 \r
511 CString CHwSMTP::GetLastErrorText()\r
512 {\r
513         return m_csLastError;\r
514 }\r
515 \r
516 \r
517 DWORD WINAPI ThreadProc_SendEmail( LPVOID lpParameter )\r
518 {\r
519         CEMailObject *pEMailObject = (CEMailObject*)lpParameter;\r
520         ASSERT ( pEMailObject );\r
521 \r
522         CHwSMTP HwSMTP;\r
523         BOOL bRet = HwSMTP.SendEmail (\r
524                 pEMailObject->m_csSmtpSrvHost,\r
525                 pEMailObject->m_csUserName,\r
526                 pEMailObject->m_csPasswd,\r
527                 pEMailObject->m_bMustAuth,\r
528                 pEMailObject->m_csAddrFrom,\r
529                 pEMailObject->m_csAddrTo,\r
530                 pEMailObject->m_csSenderName,\r
531                 pEMailObject->m_csReceiverName,\r
532                 pEMailObject->m_csSubject,\r
533                 pEMailObject->m_csBody,\r
534                 pEMailObject->m_csCharSet,\r
535                 &pEMailObject->m_StrAryAttach,\r
536                 &pEMailObject->m_StrAryCC,\r
537                 pEMailObject->m_nSmtpSrvPort\r
538                 );\r
539         if ( !bRet)\r
540         {\r
541 #ifdef _DEBUG\r
542                 CString csError = HwSMTP.GetLastErrorText ();\r
543                 csError = FormatString ( _T("Send a email to [%s] failed."), pEMailObject->m_csSmtpSrvHost );\r
544                 AfxMessageBox ( csError );\r
545 #endif\r
546         }\r
547 \r
548         m_CSFor__g_PtrAry_Threads.Lock ();\r
549         int nFindPos = FindFromArray ( g_PtrAry_Threads, pEMailObject->m_hThread );\r
550         if ( nFindPos >= 0 )\r
551                 g_PtrAry_Threads.RemoveAt ( nFindPos );\r
552         m_CSFor__g_PtrAry_Threads.Unlock ();\r
553 \r
554         delete pEMailObject;\r
555         return bRet;\r
556 }\r
557 \r
558 //\r
559 // ÓàSMTP ·þÎñ·¢Ë͵ç×ÓÓʼþ£¬Èç¹ûÉèÖòÎÊý bViaThreadSend=TRUE£¬ÄÇÔÚ³ÌÐò½áÊøʱӦ¸ÃÔÚ ExitInstance() Öе÷ÓàEndOfSMTP() º¯Êý\r
560 //\r
561 BOOL SendEmail (\r
562                                 BOOL bViaThreadSend,\r
563                                 LPCTSTR lpszSmtpSrvHost,\r
564                                 LPCTSTR lpszUserName,\r
565                                 LPCTSTR lpszPasswd,\r
566                                 BOOL bMustAuth,\r
567                                 LPCTSTR lpszAddrFrom,\r
568                                 LPCTSTR lpszAddrTo,\r
569                                 LPCTSTR lpszSenderName,\r
570                                 LPCTSTR lpszReceiverName,\r
571                                 LPCTSTR lpszSubject,\r
572                                 LPCTSTR lpszBody,\r
573                                 LPCTSTR lpszCharSet/*=NULL*/,\r
574                                 CStringArray *pStrAryAttach/*=NULL*/,\r
575                                 CStringArray *pStrAryCC/*=NULL*/,\r
576                                 UINT nSmtpSrvPort/*=25*/\r
577                                 )\r
578 {\r
579         if ( !lpszSmtpSrvHost || lstrlen(lpszSmtpSrvHost) < 1 ||\r
580                 !lpszSubject || lstrlen(lpszSubject) < 1 ||\r
581                 !lpszBody || lstrlen(lpszBody) < 1 )\r
582         {\r
583                 AfxMessageBox ( _T("Parameter error !") );\r
584                 return FALSE;\r
585         }\r
586 \r
587         CEMailObject *pEMailObject = new CEMailObject (\r
588                 lpszSmtpSrvHost,\r
589                 lpszUserName,\r
590                 lpszPasswd,\r
591                 bMustAuth,\r
592                 lpszAddrFrom,\r
593                 lpszAddrTo,\r
594                 lpszSenderName,\r
595                 lpszReceiverName,\r
596                 lpszSubject,\r
597                 lpszBody,\r
598                 lpszCharSet,\r
599                 pStrAryAttach,\r
600                 pStrAryCC,\r
601                 nSmtpSrvPort\r
602                 );\r
603         if ( !pEMailObject ) return FALSE;\r
604 \r
605         BOOL bRet = FALSE;\r
606         if ( bViaThreadSend )\r
607         {\r
608                 DWORD dwThreadId = 0;\r
609                 pEMailObject->m_hThread = ::CreateThread ( NULL, 0, ::ThreadProc_SendEmail, pEMailObject, CREATE_SUSPENDED, &dwThreadId );\r
610                 bRet = HANDLE_IS_VALID(pEMailObject->m_hThread);\r
611                 m_CSFor__g_PtrAry_Threads.Lock();\r
612                 g_PtrAry_Threads.Add ( pEMailObject->m_hThread );\r
613                 m_CSFor__g_PtrAry_Threads.Unlock();\r
614                 ResumeThread ( pEMailObject->m_hThread );\r
615         }\r
616         else\r
617         {\r
618                 bRet = (BOOL)ThreadProc_SendEmail ( pEMailObject );\r
619         }\r
620 \r
621         return bRet;\r
622 }\r
623 \r
624 void EndOfSMTP ()\r
625 {\r
626         // µÈ´ýËùÓÐÏß³ÌÖ´ÐÐÍê±Ï\r
627         for ( int i=0; i<g_PtrAry_Threads.GetSize(); i++ )\r
628         {\r
629                 HANDLE hThread = (HANDLE)g_PtrAry_Threads.GetAt(i);\r
630                 if ( HANDLE_IS_VALID(hThread) )\r
631                 {\r
632                         WaitForThreadEnd ( &hThread, 30*1000 );\r
633                 }\r
634         }\r
635         g_PtrAry_Threads.RemoveAll ();\r
636 }\r
637 \r
638 \r
639 //\r
640 // ½«×Ö·û´® lpszOrg ×ª»»Îª¶à×Ö½ÚµÄ×Ö·û´®£¬Èç¹û»¹ÒªÊ¹Óöà×Ö·û´®µÄ³¤¶È£¬¿ÉÒÔÓÃÒÔÏ·½Ê½À´Ê¹ÓÃÕâ¸öÀࣺ\r
641 // CMultiByteString MultiByteString(_T("UNICODE×Ö·û´®"));\r
642 // printf ( "ANSI ×Ö·û´®Îª£º %s£¬ ×Ö·û¸öÊýΪ£º %d £¬ ³¤¶ÈΪ£º %d×Ö½Ú\n", MultiByteString.GetBuffer(), MultiByteString.GetLength(), MultiByteString.GetSize() );\r
643 //\r
644 CMultiByteString::CMultiByteString( LPCTSTR lpszOrg, int nOrgStringEncodeType/*=STRING_IS_SOFTCODE*/, OUT char *pOutBuf/*=NULL*/, int nOutBufSize/*=0*/ )\r
645 {\r
646         m_bNewBuffer = FALSE;\r
647         m_pszData = NULL;\r
648         m_nDataSize = 0;\r
649         m_nCharactersNumber = 0;\r
650         if ( !lpszOrg ) return;\r
651         \r
652         // ÅжÏԭʼ×Ö·û´®µÄ±àÂ뷽ʽ\r
653         BOOL bOrgIsUnicode = FALSE;\r
654         if ( nOrgStringEncodeType == STRING_IS_MULTICHARS ) bOrgIsUnicode = FALSE;\r
655         else if ( nOrgStringEncodeType == STRING_IS_UNICODE ) bOrgIsUnicode = TRUE;\r
656         else\r
657         {\r
658 #ifdef UNICODE\r
659                 bOrgIsUnicode = TRUE;\r
660 #else\r
661                 bOrgIsUnicode = FALSE;\r
662 #endif\r
663         }\r
664         \r
665         // ¼ÆËã×Ö·û´®¸öÊýºÍÐèÒªµÄÄ¿±ê»º³å´óС\r
666         if ( bOrgIsUnicode )\r
667         {\r
668                 m_nCharactersNumber = (int)wcslen((WCHAR*)lpszOrg);\r
669                 m_nDataSize = (m_nCharactersNumber + 1) * sizeof(WCHAR);\r
670         }\r
671         else\r
672         {\r
673                 m_nCharactersNumber = (int)strlen((char*)lpszOrg);\r
674                 m_nDataSize = (m_nCharactersNumber + 1) * sizeof(char);\r
675         }\r
676         \r
677         // Ê¹Óõ÷ÓÃÕß´«ÈëµÄ»º³å\r
678         if ( pOutBuf && nOutBufSize > 0 )\r
679         {\r
680                 m_pszData = pOutBuf;\r
681                 m_nDataSize = nOutBufSize;\r
682         }\r
683         // ×Ô¼ºÉêÇëÄڴ滺³å\r
684         else\r
685         {\r
686                 m_pszData = (char*)new BYTE[m_nDataSize];\r
687                 if ( !m_pszData )\r
688                 {\r
689                         ::AfxThrowMemoryException ();\r
690                         return;\r
691                 }\r
692                 m_bNewBuffer = TRUE;\r
693         }\r
694         memset ( m_pszData, 0, m_nDataSize );\r
695         \r
696         if ( bOrgIsUnicode )\r
697         {\r
698                 m_nCharactersNumber = WideCharToMultiByte ( CP_ACP, 0, (LPCWSTR)lpszOrg, m_nCharactersNumber, (LPSTR)m_pszData, m_nDataSize/sizeof(char)-1, NULL, NULL );\r
699                 if ( m_nCharactersNumber < 1 ) m_nCharactersNumber = (int)strlen ( m_pszData );\r
700         }\r
701         else\r
702         {\r
703                 m_nCharactersNumber = __min ( m_nCharactersNumber, (int)(m_nDataSize/sizeof(char)-1) );\r
704                 strncpy ( m_pszData, (const char*)lpszOrg, m_nCharactersNumber );\r
705                 m_nCharactersNumber = (int)strlen ( m_pszData );\r
706         }\r
707         m_nDataSize = ( m_nCharactersNumber + 1 ) * sizeof(char);\r
708 }\r
709 \r
710 CMultiByteString::~CMultiByteString ()\r
711 {\r
712         if ( m_bNewBuffer && m_pszData )\r
713         {\r
714                 delete[] m_pszData;\r
715         }\r
716 }\r
717 \r
718 //\r
719 // ½« lpszOrg ×ª»»Îª¸Ã³ÌÐòʹÓõıàÂë×Ö·û´®£¬Èç¹û¸Ã³ÌÐòÊÇ UNICODE ¾ÍתΪ UNICODE£¬Èç¹ûÊÇ ANSI ¾ÍתΪ ANSI µÄ\r
720 //\r
721 CString GetCompatibleString ( LPVOID lpszOrg, BOOL bOrgIsUnicode, int nOrgLength/*=-1*/ )\r
722 {\r
723         if ( !lpszOrg ) return _T("");\r
724         \r
725         TRY\r
726         {\r
727 #ifdef UNICODE\r
728                 if ( bOrgIsUnicode )\r
729                 {\r
730                         if ( nOrgLength > 0 )\r
731                         {\r
732                                 WCHAR *szRet = new WCHAR[nOrgLength+1];\r
733                                 if ( !szRet ) return _T("");\r
734                                 memset ( szRet, 0, (nOrgLength+1)*sizeof(WCHAR) );\r
735                                 memcpy ( szRet, lpszOrg, nOrgLength*sizeof(WCHAR) );\r
736                                 CString csRet = szRet;\r
737                                 delete[] szRet;\r
738                                 return csRet;\r
739                         }\r
740                         else if ( nOrgLength == 0 )\r
741                                 return _T("");\r
742                         else\r
743                                 return (LPCTSTR)lpszOrg;\r
744                 }\r
745                 \r
746                 if ( nOrgLength < 0 )\r
747                         nOrgLength = (int)strlen((const char*)lpszOrg);\r
748                 int nWideCount = nOrgLength + 1;\r
749                 WCHAR *wchar = new WCHAR[nWideCount];\r
750                 if ( !wchar ) return _T("");\r
751                 memset ( wchar, 0, nWideCount*sizeof(WCHAR) );\r
752                 ::MultiByteToWideChar(CP_ACP, 0, (LPCSTR)lpszOrg, nOrgLength, wchar, nWideCount);\r
753                 CString csRet = wchar;\r
754                 delete[] wchar;\r
755                 return csRet;\r
756 #else\r
757                 if ( !bOrgIsUnicode )\r
758                 {\r
759                         if ( nOrgLength > 0 )\r
760                         {\r
761                                 char *szRet = new char[nOrgLength+1];\r
762                                 if ( !szRet ) return _T("");\r
763                                 memset ( szRet, 0, (nOrgLength+1)*sizeof(char) );\r
764                                 memcpy ( szRet, lpszOrg, nOrgLength*sizeof(char) );\r
765                                 CString csRet = szRet;\r
766                                 delete[] szRet;\r
767                                 return csRet;\r
768                         }\r
769                         else if ( nOrgLength == 0 )\r
770                                 return _T("");\r
771                         else\r
772                                 return (LPCTSTR)lpszOrg;\r
773                 }\r
774                 \r
775                 if ( nOrgLength < 0 )\r
776                         nOrgLength = (int)wcslen((WCHAR*)lpszOrg);\r
777                 int nMultiByteCount = nOrgLength + 1;\r
778                 char *szMultiByte = new char[nMultiByteCount];\r
779                 if ( !szMultiByte ) return _T("");\r
780                 memset ( szMultiByte, 0, nMultiByteCount*sizeof(char) );\r
781                 ::WideCharToMultiByte ( CP_ACP, 0, (LPCWSTR)lpszOrg, nOrgLength, (LPSTR)szMultiByte, nMultiByteCount, NULL, NULL );\r
782                 CString csRet = szMultiByte;\r
783                 delete[] szMultiByte;\r
784                 return csRet;\r
785 #endif\r
786         }\r
787         CATCH_ALL(e)\r
788         {\r
789                 THROW_LAST ();\r
790         }\r
791         END_CATCH_ALL\r
792                 \r
793                 return _T("");\r
794 }\r
795 \r
796 CString FormatDateTime ( COleDateTime &DateTime, LPCTSTR pFormat )\r
797 {       \r
798         // If null, return empty string\r
799         if ( DateTime.GetStatus() == COleDateTime::null || DateTime.GetStatus() == COleDateTime::invalid )\r
800                 return _T("");\r
801         \r
802         UDATE ud;\r
803         if (S_OK != VarUdateFromDate(DateTime.m_dt, 0, &ud))\r
804         {\r
805                 return _T("");\r
806         }\r
807         \r
808         struct tm tmTemp;\r
809         tmTemp.tm_sec   = ud.st.wSecond;\r
810         tmTemp.tm_min   = ud.st.wMinute;\r
811         tmTemp.tm_hour  = ud.st.wHour;\r
812         tmTemp.tm_mday  = ud.st.wDay;\r
813         tmTemp.tm_mon   = ud.st.wMonth - 1;\r
814         tmTemp.tm_year  = ud.st.wYear - 1900;\r
815         tmTemp.tm_wday  = ud.st.wDayOfWeek;\r
816         tmTemp.tm_yday  = ud.wDayOfYear - 1;\r
817         tmTemp.tm_isdst = 0;\r
818         \r
819         CString strDate;\r
820         LPTSTR lpszTemp = strDate.GetBufferSetLength(256);\r
821         _tcsftime(lpszTemp, strDate.GetLength(), pFormat, &tmTemp);\r
822         strDate.ReleaseBuffer();\r
823         \r
824         return strDate;\r
825 }\r
826 \r
827 CString FormatString ( LPCTSTR lpszStr, ... )\r
828 {\r
829         TCHAR *buf = NULL;\r
830         // Ñ­»·¸ñʽ»¯×Ö·û´®£¬Èç¹û»º³å²»¹»Ôò½«»º³å¼Ó´óÈ»ºóÖØÊÔÒÔ±£Ö¤»º³å¹»ÓÃͬʱÓÖ²»ÀË·Ñ\r
831         for ( int nBufCount = 1024; nBufCount<5*1024*1024; nBufCount += 1024 )\r
832         {\r
833                 buf = new TCHAR[nBufCount];\r
834                 if ( !buf )\r
835                 {\r
836                         ::AfxThrowMemoryException ();\r
837                         return _T("");\r
838                 }\r
839                 memset ( buf, 0, nBufCount*sizeof(TCHAR) );\r
840                 \r
841                 va_list  va;\r
842                 va_start (va, lpszStr);\r
843                 int nLen = _vsnprintf_hw ((TCHAR*)buf, nBufCount-sizeof(TCHAR), lpszStr, va);\r
844                 va_end(va);\r
845                 if ( nLen <= (int)(nBufCount-sizeof(TCHAR)) )\r
846                         break;\r
847                 delete[] buf; buf = NULL;\r
848         }\r
849         if ( !buf )\r
850         {\r
851                 return _T("");\r
852         }\r
853         \r
854         CString csMsg = buf;\r
855         delete[] buf; buf = NULL;\r
856         return csMsg;\r
857 }\r
858 \r
859 /********************************************************************************\r
860 * Function Type :       Global\r
861 * Parameter             :       lpFileName      -       Îļþ·¾¶\r
862 * Return Value  :       -1                      -       Ê§°Ü\r
863 *                                       >=0                     -       Îļþ´óС\r
864 * Description   :       »ñÈ¡ÎļþÊôÐÔ ( Îļþ´óС¡¢´´½¨Ê±¼ä )\r
865 *********************************************************************************/\r
866 int hwGetFileAttr ( LPCTSTR lpFileName, OUT CFileStatus *pFileStatus/*=NULL*/ )\r
867 {\r
868         if ( !lpFileName || lstrlen(lpFileName) < 1 ) return -1;\r
869         \r
870         CFileStatus fileStatus;\r
871         fileStatus.m_attribute = 0;\r
872         fileStatus.m_size = 0;\r
873         memset ( fileStatus.m_szFullName, 0, sizeof(fileStatus.m_szFullName) );\r
874         BOOL bRet = FALSE;\r
875         TRY\r
876         {\r
877                 if ( CFile::GetStatus(lpFileName,fileStatus) )\r
878                 {\r
879                         bRet = TRUE;\r
880                 }\r
881         }\r
882         CATCH (CFileException, e)\r
883         {\r
884                 ASSERT ( FALSE );\r
885                 bRet = FALSE;\r
886         }\r
887         CATCH_ALL(e)\r
888         {\r
889                 ASSERT ( FALSE );\r
890                 bRet = FALSE;\r
891         }\r
892         END_CATCH_ALL;\r
893         \r
894         if ( pFileStatus )\r
895         {\r
896                 pFileStatus->m_ctime = fileStatus.m_ctime;\r
897                 pFileStatus->m_mtime = fileStatus.m_mtime;\r
898                 pFileStatus->m_atime = fileStatus.m_atime;\r
899                 pFileStatus->m_size = fileStatus.m_size;\r
900                 pFileStatus->m_attribute = fileStatus.m_attribute;\r
901                 pFileStatus->_m_padding = fileStatus._m_padding;\r
902                 lstrcpy ( pFileStatus->m_szFullName, fileStatus.m_szFullName );\r
903                 \r
904         }\r
905         \r
906         return (int)fileStatus.m_size;\r
907 }\r
908 \r
909 //\r
910 // ½«Ò»¸ö±íʾ×Ö½ÚµÄÊýÓÿɶÁÐԺõÄ×Ö·û´®À´±íʾ£¬ÀýÈ罫 12345678 ×Ö½Úת»»Îª£º\r
911 // 11.77M\r
912 // nFlag        -       0 : ×Ô¶¯Æ¥Å䵥λ\r
913 //                              1 : ÒÔ Kb Îªµ¥Î»\r
914 //                              2 : ÒÔ Mb Îªµ¥Î»\r
915 //                              3 : ÒÔ Gb Îªµ¥Î»\r
916 // \r
917 CString FormatBytes ( double fBytesNum, BOOL bShowUnit/*=TRUE*/, int nFlag/*=0*/ )\r
918 {\r
919         CString csRes;\r
920         if ( nFlag == 0 )\r
921         {\r
922                 if ( fBytesNum >= 1024.0 && fBytesNum < 1024.0*1024.0 )\r
923                         csRes.Format ( _T("%.2f%s"), fBytesNum / 1024.0, bShowUnit?_T(" K"):_T("") );\r
924                 else if ( fBytesNum >= 1024.0*1024.0 && fBytesNum < 1024.0*1024.0*1024.0 )\r
925                         csRes.Format ( _T("%.2f%s"), fBytesNum / (1024.0*1024.0), bShowUnit?_T(" M"):_T("") );\r
926                 else if ( fBytesNum >= 1024.0*1024.0*1024.0 )\r
927                         csRes.Format ( _T("%.2f%s"), fBytesNum / (1024.0*1024.0*1024.0), bShowUnit?_T(" G"):_T("") );\r
928                 else\r
929                         csRes.Format ( _T("%.2f%s"), fBytesNum, bShowUnit?_T(" B"):_T("") );\r
930         }\r
931         else if ( nFlag == 1 )\r
932         {\r
933                 csRes.Format ( _T("%.2f%s"), fBytesNum / 1024.0, bShowUnit?_T(" K"):_T("") );\r
934         }\r
935         else if ( nFlag == 2 )\r
936         {\r
937                 csRes.Format ( _T("%.2f%s"), fBytesNum / (1024.0*1024.0), bShowUnit?_T(" M"):_T("") );\r
938         }\r
939         else if ( nFlag == 3 )\r
940         {\r
941                 csRes.Format ( _T("%.2f%s"), fBytesNum / (1024.0*1024.0*1024.0), bShowUnit?_T(" G"):_T("") );\r
942         }\r
943         \r
944         return csRes;\r
945 }\r
946 \r
947 //\r
948 // µÈ´ýÏß³ÌÍ˳ö\r
949 //\r
950 BOOL WaitForThreadEnd ( HANDLE *phThread, DWORD dwWaitTime /*=10*1000*/ )\r
951 {\r
952         BOOL bRet = TRUE;\r
953         ASSERT ( phThread );\r
954         if ( !(*phThread) ) return TRUE;\r
955         if ( ::WaitForSingleObject ( *phThread, dwWaitTime ) == WAIT_TIMEOUT )\r
956         {\r
957                 bRet = FALSE;\r
958                 ::TerminateThread ( *phThread, 0 );\r
959         }\r
960         ::CloseHandle ( *phThread );\r
961         (*phThread) = NULL;\r
962         return bRet;\r
963 }\r