OSDN Git Service

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