00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "StdAfx.h"
00027 #include "Shareaza.h"
00028 #include "Settings.h"
00029 #include "Download.h"
00030 #include "Downloads.h"
00031 #include "DownloadSource.h"
00032 #include "DownloadTransfer.h"
00033 #include "DownloadTransferFTP.h"
00034 #include "FragmentedFile.h"
00035 #include "Network.h"
00036 #include "SourceURL.h"
00037 #include "GProfile.h"
00038
00039 #ifdef _DEBUG
00040 #undef THIS_FILE
00041 static char THIS_FILE[]=__FILE__;
00042 #define new DEBUG_NEW
00043 #endif
00044
00046
00047
00048 inline void MakePORTArgs (const SOCKADDR_IN& host, CString& strValue)
00049 {
00050 strValue.Format( _T("%u,%u,%u,%u,%hu,%hu"),
00051 unsigned( host.sin_addr.S_un.S_un_b.s_b1 ),
00052 unsigned( host.sin_addr.S_un.S_un_b.s_b2 ),
00053 unsigned( host.sin_addr.S_un.S_un_b.s_b3 ),
00054 unsigned( host.sin_addr.S_un.S_un_b.s_b4 ),
00055 host.sin_port & 0xff,
00056 (host.sin_port >> 8) & 0xff );
00057 }
00058
00059 inline bool ParsePASVArgs (const CString& args, SOCKADDR_IN& host)
00060 {
00061 CString strValue (args);
00062 int begin = strValue.Find (_T('('));
00063 int end = strValue.Find (_T(')'));
00064 if (begin == -1 || end == -1 || end - begin < 12)
00065 return false;
00066 strValue = strValue.Mid (begin + 1, end - begin - 1);
00067 ZeroMemory (&host, sizeof (host));
00068 host.sin_family = AF_INET;
00069 int d;
00070
00071 d = strValue.Find (_T(','));
00072 if (d == -1)
00073 return false;
00074 host.sin_addr.S_un.S_un_b.s_b1 = (unsigned char) (_tstoi (strValue.Mid (0, d)) & 0xff);
00075 strValue = strValue.Mid (d + 1);
00076
00077 d = strValue.Find (_T(','));
00078 if (d == -1)
00079 return false;
00080 host.sin_addr.S_un.S_un_b.s_b2 = (unsigned char) (_tstoi (strValue.Mid (0, d)) & 0xff);
00081 strValue = strValue.Mid (d + 1);
00082
00083 d = strValue.Find (_T(','));
00084 if (d == -1)
00085 return false;
00086 host.sin_addr.S_un.S_un_b.s_b3 = (unsigned char) (_tstoi (strValue.Mid (0, d)) & 0xff);
00087 strValue = strValue.Mid (d + 1);
00088
00089 d = strValue.Find (_T(','));
00090 if (d == -1)
00091 return false;
00092 host.sin_addr.S_un.S_un_b.s_b4 = (unsigned char) (_tstoi (strValue.Mid (0, d)) & 0xff);
00093 strValue = strValue.Mid (d + 1);
00094
00095 d = strValue.Find (_T(','));
00096 if (d == -1)
00097 return false;
00098 host.sin_port = (unsigned char) (_tstoi (strValue.Mid (0, d)) & 0xff);
00099 strValue = strValue.Mid (d + 1);
00100
00101 host.sin_port += (unsigned char) (_tstoi (strValue) & 0xff) * 256;
00102 return true;
00103 }
00104
00105 inline bool FTPisOK( const CString& str )
00106 {
00107 return ( str.GetLength () == 3 && str [0] == _T('2') );
00108 }
00109
00111
00112
00113 CDownloadTransferFTP::CDownloadTransferFTP (CDownloadSource* pSource) :
00114 CDownloadTransfer ( pSource, PROTOCOL_FTP ),
00115 m_FtpState (ftpConnecting),
00116 m_tRequest (0),
00117 m_bPassive (TRUE ),
00118 m_bSizeChecked (FALSE)
00119 {
00120 m_RETR.SetOwner (this);
00121 }
00122
00124
00125
00126 BOOL CDownloadTransferFTP::Initiate()
00127 {
00128 theApp.Message( MSG_DEFAULT, IDS_DOWNLOAD_CONNECTING,
00129 (LPCTSTR)CString( inet_ntoa( m_pSource->m_pAddress ) ), m_pSource->m_nPort,
00130 (LPCTSTR)m_pDownload->GetDisplayName() );
00131
00132 m_tConnected = GetTickCount();
00133 m_FtpState = ftpConnecting;
00134
00135 if ( ConnectTo( &m_pSource->m_pAddress, m_pSource->m_nPort ) )
00136 {
00137 SetState( dtsConnecting );
00138
00139 if ( !m_pDownload->IsBoosted() )
00140 m_mInput.pLimit = m_mOutput.pLimit = &Downloads.m_nLimitGeneric;
00141
00142 return TRUE;
00143 }
00144 else
00145 {
00146 theApp.Message( MSG_ERROR, IDS_DOWNLOAD_CONNECT_ERROR, (LPCTSTR)m_sAddress );
00147 Close( TS_UNKNOWN );
00148 return FALSE;
00149 }
00150 }
00151
00153
00154
00155 void CDownloadTransferFTP::Close (TRISTATE bKeepSource)
00156 {
00157 m_LIST.Close ();
00158 m_RETR.Close ();
00159
00160 if ( m_pSource != NULL && m_nState == dtsDownloading && m_FtpState == ftpRETR)
00161 m_pSource->AddFragment( m_nOffset, m_nPosition );
00162
00163 m_FtpState = ftpConnecting;
00164 m_bSizeChecked = FALSE;
00165
00166 CDownloadTransfer::Close( bKeepSource );
00167 }
00168
00170
00171
00172 void CDownloadTransferFTP::Boost()
00173 {
00174 m_mInput.pLimit = m_mOutput.pLimit =
00175 m_LIST.m_mInput.pLimit = m_LIST.m_mOutput.pLimit =
00176 m_RETR.m_mInput.pLimit = m_RETR.m_mOutput.pLimit = NULL;
00177 }
00178
00179 DWORD CDownloadTransferFTP::GetAverageSpeed()
00180 {
00181 return m_pSource->m_nSpeed = GetMeasuredSpeed();
00182 }
00183
00184 DWORD CDownloadTransferFTP::GetMeasuredSpeed()
00185 {
00186 Measure();
00187 m_LIST.Measure();
00188 m_RETR.Measure();
00189 return m_mInput.nMeasure + m_LIST.m_mInput.nMeasure + m_RETR.m_mInput.nMeasure;
00190 }
00191
00193
00194
00195 BOOL CDownloadTransferFTP::OnConnected()
00196 {
00197 theApp.Message( MSG_DEFAULT, IDS_DOWNLOAD_CONNECTED, (LPCTSTR)m_sAddress );
00198
00199 m_tConnected = GetTickCount();
00200 SetState( dtsRequesting );
00201
00202 return StartNextFragment();
00203 }
00204
00206
00207
00208 BOOL CDownloadTransferFTP::StartNextFragment()
00209 {
00210 ASSERT( this != NULL );
00211 if ( this == NULL ) return FALSE;
00212
00213 m_nOffset = SIZE_UNKNOWN;
00214 m_nPosition = 0;
00215 m_bWantBackwards = FALSE;
00216 m_bRecvBackwards = FALSE;
00217
00218 if ( m_pInput == NULL || m_pOutput == NULL )
00219 {
00220 theApp.Message( MSG_DEFAULT, IDS_DOWNLOAD_CLOSING_EXTRA, (LPCTSTR)m_sAddress );
00221 Close( TS_TRUE );
00222 return FALSE;
00223 } else if ( m_FtpState == ftpConnecting )
00224 {
00225
00226 m_tRequest = GetTickCount();
00227 return TRUE;
00228 }
00229 else if ( m_pDownload->m_nSize == SIZE_UNKNOWN || !m_bSizeChecked )
00230 {
00231
00232 m_FtpState = ftpSIZE_TYPE;
00233 SetState( dtsRequesting );
00234 return SendCommand ();
00235 }
00236 else if ( m_pDownload->GetFragment( this ) )
00237 {
00238
00239
00240 theApp.Message( MSG_DEFAULT, IDS_DOWNLOAD_FRAGMENT_REQUEST,
00241 m_nOffset, m_nOffset + m_nLength - 1,
00242 (LPCTSTR)m_pDownload->GetDisplayName(), (LPCTSTR)m_sAddress );
00243
00244 m_FtpState = ftpRETR_TYPE;
00245 SetState( dtsDownloading );
00246 return SendCommand ();
00247 }
00248 else
00249 {
00250 if ( m_pSource != NULL ) m_pSource->SetAvailableRanges( NULL );
00251 theApp.Message( MSG_DEFAULT, IDS_DOWNLOAD_FRAGMENT_END, (LPCTSTR)m_sAddress );
00252 Close( TS_TRUE );
00253 return FALSE;
00254 }
00255 }
00256
00258
00259
00260 BOOL CDownloadTransferFTP::SubtractRequested(FF::SimpleFragmentList& ppFragments)
00261 {
00262 if ( m_nOffset < SIZE_UNKNOWN && m_nLength < SIZE_UNKNOWN )
00263 {
00264 if ( m_nState == dtsRequesting || m_nState == dtsDownloading )
00265 {
00266 ppFragments.erase( FF::SimpleFragment( m_nOffset, m_nOffset + m_nLength ) );
00267 return TRUE;
00268 }
00269 }
00270
00271 return FALSE;
00272 }
00273
00275
00276
00277 BOOL CDownloadTransferFTP::OnRun()
00278 {
00279 CDownloadTransfer::OnRun();
00280
00281 DWORD tNow = GetTickCount();
00282
00283 switch ( m_nState )
00284 {
00285 case dtsConnecting:
00286 if ( tNow - m_tConnected > Settings.Connection.TimeoutConnect )
00287 {
00288 theApp.Message( MSG_ERROR, IDS_CONNECTION_TIMEOUT_CONNECT, (LPCTSTR)m_sAddress );
00289 if ( m_pSource != NULL ) m_pSource->PushRequest();
00290 Close( TS_UNKNOWN );
00291 return FALSE;
00292 }
00293 break;
00294
00295 case dtsRequesting:
00296 case dtsHeaders:
00297 if ( tNow - m_tRequest > Settings.Connection.TimeoutHandshake )
00298 {
00299 theApp.Message( MSG_ERROR, IDS_DOWNLOAD_REQUEST_TIMEOUT, (LPCTSTR)m_sAddress );
00300 Close( TS_UNKNOWN );
00301 return FALSE;
00302 }
00303 break;
00304
00305 case dtsDownloading:
00306 case dtsFlushing:
00307 case dtsTiger:
00308 case dtsMetadata:
00309 if ( tNow - m_mInput.tLast > Settings.Connection.TimeoutTraffic * 2 )
00310 {
00311 theApp.Message( MSG_ERROR, IDS_DOWNLOAD_TRAFFIC_TIMEOUT, (LPCTSTR)m_sAddress );
00312 Close( TS_TRUE );
00313 return FALSE;
00314 }
00315 break;
00316
00317 case dtsBusy:
00318 if ( tNow - m_tRequest > 1000 )
00319 {
00320 theApp.Message( MSG_ERROR, IDS_DOWNLOAD_BUSY, (LPCTSTR)m_sAddress, Settings.Downloads.RetryDelay / 1000 );
00321 Close( TS_TRUE );
00322 return FALSE;
00323 }
00324 break;
00325
00326 case dtsQueued:
00327 if ( tNow >= m_tRequest )
00328 {
00329 return StartNextFragment();
00330 }
00331 break;
00332 }
00333
00334 return TRUE;
00335 }
00336
00338
00339
00340 BOOL CDownloadTransferFTP::OnRead()
00341 {
00342 CDownloadTransfer::OnRead();
00343
00344 CString strLine;
00345 while( m_pInput->ReadLine( strLine ) )
00346 {
00347 strLine.Trim( _T(" \t\r\n") );
00348 if ( strLine.GetLength() > 256 )
00349 strLine = _T("#LINE_TOO_LONG#");
00350 if ( strLine.GetLength() > 3 )
00351 {
00352 m_sLastHeader = strLine.Left( 3 ).TrimRight( _T(" \t\r\n") );
00353 if ( !OnHeaderLine( m_sLastHeader,
00354 strLine.Mid( 4 ).TrimLeft( _T(" \t\r\n") ) ) )
00355 return FALSE;
00356 }
00357 }
00358 return TRUE;
00359 }
00360
00362
00363
00364 BOOL CDownloadTransferFTP::OnHeaderLine( CString& strHeader, CString& strValue )
00365 {
00366 theApp.Message( MSG_DEBUG, _T("%s >> %s: %s"),
00367 (LPCTSTR) m_sAddress, (LPCTSTR) strHeader, (LPCTSTR) strValue );
00368 TRACE( _T("%s >> %s: %s\n"),
00369 (LPCTSTR) m_sAddress, (LPCTSTR) strHeader, (LPCTSTR) strValue );
00370
00371 m_pSource->SetLastSeen();
00372
00373 switch( m_FtpState )
00374 {
00375 case ftpConnecting:
00376 if ( strHeader == _T("220") )
00377 {
00378 m_LIST.m_sUserAgent = m_RETR.m_sUserAgent = m_sUserAgent = strValue;
00379 if ( IsAgentBlocked() )
00380 {
00381 Close( TS_FALSE );
00382 return FALSE;
00383 }
00384
00385 m_FtpState = ftpUSER;
00386 SetState( dtsRequesting );
00387 return SendCommand();
00388 }
00389 break;
00390
00391 case ftpUSER:
00392 if ( strHeader == _T("331") )
00393 {
00394
00395 m_FtpState = ftpPASS;
00396 SetState( dtsRequesting );
00397 return SendCommand ();
00398 } else
00399 if ( FTPisOK( strHeader ) )
00400
00401 return TRUE;
00402
00403
00404 break;
00405
00406 case ftpPASS:
00407 if ( strHeader == _T("230") )
00408 {
00409
00410 m_FtpState = ftpDownloading;
00411 SetState( dtsRequesting );
00412 return StartNextFragment();
00413 } else
00414 if ( FTPisOK( strHeader ) )
00415
00416 return TRUE;
00417
00418
00419 break;
00420
00421 case ftpSIZE_TYPE:
00422 if ( strHeader == _T("200") )
00423 {
00424
00425 m_FtpState = ftpSIZE;
00426 SetState( dtsRequesting );
00427 return SendCommand ();
00428 } else
00429 if ( FTPisOK( strHeader ) )
00430
00431 return TRUE;
00432 break;
00433
00434 case ftpSIZE:
00435 if ( strHeader == _T("213") )
00436 {
00437 QWORD size = _tstoi64( strValue );
00438 if ( size <= 0 )
00439 {
00440
00441 ASSERT( FALSE );
00442 Close( TS_TRUE );
00443 return FALSE;
00444 }
00445 if ( m_pDownload->m_nSize == SIZE_UNKNOWN )
00446 m_pDownload->m_nSize = size;
00447 else
00448 {
00449 if ( m_pDownload->m_nSize != size )
00450 {
00451
00452 theApp.Message( MSG_ERROR, IDS_DOWNLOAD_WRONG_SIZE,
00453 (LPCTSTR)m_sAddress, (LPCTSTR)m_pDownload->GetDisplayName() );
00454 Close( TS_FALSE );
00455 return FALSE;
00456 }
00457 }
00458 m_bSizeChecked = TRUE;
00459
00460 m_FtpState = ftpDownloading;
00461 SetState( dtsRequesting );
00462 return StartNextFragment();
00463 } else
00464 if ( FTPisOK( strHeader ) )
00465
00466 return TRUE;
00467 else
00468 if ( strHeader == _T("550") )
00469 {
00470 theApp.Message( MSG_ERROR, IDS_DOWNLOAD_FILENOTFOUND,
00471 (LPCTSTR)m_sAddress, (LPCTSTR)m_pDownload->GetDisplayName() );
00472 Close( TS_FALSE );
00473 return FALSE;
00474 }
00475 break;
00476
00477 case ftpLIST_TYPE:
00478 if ( strHeader == _T("200") )
00479 {
00480
00481 m_FtpState = ftpLIST_PASVPORT;
00482 SetState( dtsRequesting );
00483 return SendCommand ();
00484 } else
00485 if ( FTPisOK( strHeader ) )
00486
00487 return TRUE;
00488 break;
00489
00490 case ftpLIST_PASVPORT:
00491 if ( strHeader == _T("227") ||
00492 strHeader == _T("200") )
00493 {
00494
00495 if ( m_bPassive )
00496 {
00497
00498 SOCKADDR_IN host;
00499 if ( !ParsePASVArgs( strValue, host ) )
00500 {
00501
00502 ASSERT( FALSE );
00503 Close( TS_TRUE );
00504 return FALSE;
00505 }
00506 if ( !m_LIST.ConnectTo( &host ) )
00507 {
00508
00509 theApp.Message( MSG_ERROR, IDS_DOWNLOAD_CONNECT_ERROR,
00510 (LPCTSTR)m_sAddress );
00511 Close( TS_TRUE );
00512 return FALSE;
00513 }
00514 }
00515 m_FtpState = ftpLIST;
00516 SetState( dtsRequesting );
00517 return SendCommand ();
00518 } else
00519 if ( FTPisOK( strHeader ) )
00520
00521 return TRUE;
00522 break;
00523
00524 case ftpLIST:
00525 if ( strHeader == _T("125") ||
00526 strHeader == _T("150") )
00527 {
00528
00529 return TRUE;
00530 } else
00531 if ( strHeader == _T("226") )
00532 {
00533
00534 QWORD size = m_LIST.ExtractFileSize();
00535 if ( size == SIZE_UNKNOWN )
00536 {
00537
00538 Close( TS_TRUE );
00539 return FALSE;
00540 }
00541 if ( m_pDownload->m_nSize == SIZE_UNKNOWN )
00542 m_pDownload->m_nSize = size;
00543 else
00544 {
00545 if ( m_pDownload->m_nSize != size )
00546 {
00547
00548 theApp.Message( MSG_ERROR, IDS_DOWNLOAD_WRONG_SIZE,
00549 (LPCTSTR)m_sAddress, (LPCTSTR)m_pDownload->GetDisplayName() );
00550 Close( TS_FALSE );
00551 return FALSE;
00552 }
00553 }
00554 m_bSizeChecked = TRUE;
00555
00556 m_LIST.Close();
00557 m_FtpState = ftpABOR;
00558 SetState( dtsRequesting );
00559 return SendCommand();
00560 } else
00561 if ( strHeader == _T("550") )
00562 {
00563 theApp.Message( MSG_ERROR, IDS_DOWNLOAD_FILENOTFOUND,
00564 (LPCTSTR)m_sAddress, (LPCTSTR)m_pDownload->GetDisplayName() );
00565 Close( TS_FALSE );
00566 return FALSE;
00567 }
00568 break;
00569
00570 case ftpRETR_TYPE:
00571 if ( strHeader == _T("200") )
00572 {
00573
00574 m_FtpState = ftpRETR_PASVPORT;
00575 SetState( dtsDownloading );
00576 return SendCommand();
00577 } else
00578 if ( FTPisOK( strHeader ) )
00579
00580 return TRUE;
00581 break;
00582
00583 case ftpRETR_PASVPORT:
00584 if ( strHeader == _T("227") ||
00585 strHeader == _T("200") )
00586 {
00587
00588 if ( m_bPassive )
00589 {
00590 SOCKADDR_IN host;
00591 if ( !ParsePASVArgs( strValue, host ) )
00592 {
00593
00594 ASSERT( FALSE );
00595 Close( TS_TRUE );
00596 return FALSE;
00597 }
00598 if ( !m_RETR.ConnectTo( &host ) )
00599 {
00600
00601 theApp.Message( MSG_ERROR, IDS_DOWNLOAD_CONNECT_ERROR,
00602 (LPCTSTR)m_sAddress );
00603 Close( TS_TRUE );
00604 return FALSE;
00605 }
00606 }
00607 m_FtpState = ftpRETR_REST;
00608 SetState (dtsDownloading);
00609 return SendCommand ();
00610 } else
00611 if ( FTPisOK( strHeader ) )
00612
00613 return TRUE;
00614 break;
00615
00616 case ftpRETR_REST:
00617 if ( strHeader == _T("350") )
00618 {
00619
00620 m_FtpState = ftpRETR;
00621 SetState( dtsDownloading );
00622 return SendCommand ();
00623 }
00624 break;
00625
00626 case ftpRETR:
00627 if ( strHeader == _T("125") ||
00628 strHeader == _T("150") )
00629 {
00630
00631 return TRUE;
00632 } else
00633 if ( strHeader == _T("226") ||
00634 strHeader == _T("426") )
00635 {
00636
00637 m_RETR.Close();
00638 m_FtpState = ftpABOR;
00639 SetState( dtsDownloading );
00640 return SendCommand ();
00641 } else
00642 if ( strHeader == _T("550") )
00643 {
00644 theApp.Message( MSG_ERROR, IDS_DOWNLOAD_FILENOTFOUND,
00645 (LPCTSTR)m_sAddress, (LPCTSTR)m_pDownload->GetDisplayName() );
00646 Close( TS_FALSE );
00647 return FALSE;
00648 }
00649 break;
00650
00651 case ftpABOR:
00652
00653 m_FtpState = ftpDownloading;
00654 SetState( dtsDownloading );
00655 return StartNextFragment();
00656
00657 default:
00658
00659 ASSERT( FALSE );
00660 }
00661
00662 theApp.Message( MSG_ERROR, IDS_DOWNLOAD_HTTPCODE,
00663 (LPCTSTR)m_sAddress, (LPCTSTR)strHeader, (LPCTSTR)strValue);
00664 Close( TS_TRUE );
00665 return FALSE;
00666 }
00667
00668 BOOL CDownloadTransferFTP::SendCommand (LPCTSTR args)
00669 {
00670 CSourceURL pURL;
00671 if ( !pURL.ParseFTP( m_pSource->m_sURL, TRUE ) )
00672 return FALSE;
00673
00674 CString strLine;
00675 switch( m_FtpState )
00676 {
00677 case ftpUSER:
00678
00679 strLine = _T("USER ");
00680 strLine += pURL.m_sLogin;
00681 break;
00682
00683 case ftpPASS:
00684
00685 strLine = _T("PASS ");
00686 strLine += pURL.m_sPassword;
00687 break;
00688
00689 case ftpLIST_PASVPORT:
00690
00691 if ( m_bPassive )
00692 strLine = _T("PASV");
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707 break;
00708
00709 case ftpSIZE:
00710
00711 strLine = _T("SIZE ");
00712 strLine += pURL.m_sPath;
00713 break;
00714
00715 case ftpLIST_TYPE:
00716
00717 strLine = _T("TYPE A");
00718 break;
00719
00720 case ftpLIST:
00721
00722 strLine = _T("LIST ");
00723 strLine += pURL.m_sPath;
00724 break;
00725
00726 case ftpSIZE_TYPE:
00727 case ftpRETR_TYPE:
00728
00729 strLine = _T("TYPE I");
00730 break;
00731
00732 case ftpRETR_PASVPORT:
00733
00734 if ( m_bPassive )
00735 strLine = _T("PASV");
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750 break;
00751
00752 case ftpRETR_REST:
00753
00754 strLine.Format( _T("REST %d"), m_nOffset );
00755 break;
00756
00757 case ftpRETR:
00758
00759 strLine = _T("RETR ");
00760 strLine += pURL.m_sPath;
00761 break;
00762
00763 case ftpABOR:
00764
00765 strLine = _T("ABOR");
00766 break;
00767
00768 default:
00769 return TRUE;
00770 }
00771
00772 theApp.Message( MSG_DEBUG, _T("%s << %s"), (LPCTSTR) m_sAddress, (LPCTSTR) strLine );
00773 TRACE( _T("%s << %s\n"), (LPCTSTR) m_sAddress, (LPCTSTR) strLine );
00774
00775 m_tRequest = GetTickCount();
00776 m_pOutput->Clear ();
00777 m_pOutput->Print( strLine + _T("\r\n") );
00778
00779 return TRUE;
00780 }
00781
00783
00784
00785 void CDownloadTransferFTP::OnDropped(BOOL bError)
00786 {
00787 if ( m_nState == dtsConnecting )
00788 {
00789 theApp.Message( MSG_ERROR, IDS_DOWNLOAD_CONNECT_ERROR, (LPCTSTR)m_sAddress );
00790 if ( m_pSource != NULL ) m_pSource->PushRequest();
00791 Close( TS_UNKNOWN );
00792 } else
00793 {
00794 theApp.Message( MSG_ERROR, IDS_DOWNLOAD_DROPPED, (LPCTSTR)m_sAddress );
00795 Close( m_nState >= dtsDownloading ? TS_TRUE : TS_UNKNOWN );
00796 }
00797 }