Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members

EDClient.cpp

Go to the documentation of this file.
00001 //
00002 // EDClient.cpp
00003 //
00004 // Copyright (c) Shareaza Development Team, 2002-2005.
00005 // This file is part of SHAREAZA (www.shareaza.com)
00006 //
00007 // Shareaza is free software; you can redistribute it
00008 // and/or modify it under the terms of the GNU General Public License
00009 // as published by the Free Software Foundation; either version 2 of
00010 // the License, or (at your option) any later version.
00011 //
00012 // Shareaza is distributed in the hope that it will be useful,
00013 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 // GNU General Public License for more details.
00016 //
00017 // You should have received a copy of the GNU General Public License
00018 // along with Shareaza; if not, write to the Free Software
00019 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00020 //
00021 
00022 #include "StdAfx.h"
00023 #include "Shareaza.h"
00024 #include "Settings.h"
00025 #include "Network.h"
00026 #include "Neighbours.h"
00027 #include "EDNeighbour.h"
00028 #include "EDClient.h"
00029 #include "EDClients.h"
00030 #include "EDPacket.h"
00031 #include "GProfile.h"
00032 #include "HostCache.h"
00033 #include "ED2K.h"
00034 
00035 #include "Library.h"
00036 #include "SharedFile.h"
00037 #include "Download.h"
00038 #include "Downloads.h"
00039 #include "DownloadSource.h"
00040 #include "DownloadTransferED2K.h"
00041 #include "UploadTransferED2K.h"
00042 #include "SourceURL.h"
00043 
00044 #include "ChatCore.h"
00045 #include "Security.h"
00046 #include "UploadQueues.h"
00047 
00048 #ifdef _DEBUG
00049 #undef THIS_FILE
00050 static char THIS_FILE[]=__FILE__;
00051 #define new DEBUG_NEW
00052 #endif
00053 
00054 
00056 // CEDClient construction
00057 
00058 CEDClient::CEDClient()
00059 {
00060         m_pEdPrev               = NULL;
00061         m_pEdNext               = NULL;
00062         
00063         m_bGUID                 = FALSE;
00064         m_pGUID                 = (GGUID&)GUID_NULL;
00065         m_nClientID             = 0;
00066         m_nUDP                  = 0;
00067         
00068         // Client ID and version
00069         m_bEmule                = FALSE;
00070         m_nEmVersion    = 0;
00071         m_nEmCompatible = 0;
00072         m_nSoftwareVersion=0;
00073 
00074         // Client capabilities
00075         m_bEmAICH               = FALSE;                // Not supported
00076         m_bEmUnicode    = FALSE;
00077         m_bEmUDPVersion = FALSE;
00078         m_bEmDeflate    = FALSE;
00079         m_bEmSecureID   = FALSE;                // Not supported
00080         m_bEmSources    = FALSE;
00081         m_bEmRequest    = FALSE;
00082         m_bEmComments   = FALSE;
00083         m_bEmPeerCache  = FALSE;                // Not supported
00084         m_bEmBrowse             = FALSE;                // Not over ed2k
00085         m_bEmMultiPacket= FALSE;                // Not supported
00086         m_bEmPreview    = FALSE;                // Not over ed2k
00087         
00088         // Misc stuff
00089         m_bLogin                = FALSE;
00090         m_bUpMD4                = FALSE;
00091         
00092         m_pDownload             = NULL;
00093         m_pUpload               = NULL;
00094         m_bSeeking              = FALSE;
00095         m_nRunExCookie  = 0;
00096 
00097         m_bOpenChat             = FALSE;
00098         m_bCommentSent  = FALSE;
00099         
00100         m_mInput.pLimit         = &Settings.Bandwidth.Request;
00101         m_mOutput.pLimit        = &Settings.Bandwidth.Request;
00102         
00103         EDClients.Add( this );
00104 }
00105 
00106 CEDClient::~CEDClient()
00107 {
00108         ASSERT( m_hSocket == INVALID_SOCKET );
00109         ASSERT( m_pUpload == NULL );
00110         ASSERT( m_pDownload == NULL );
00111         
00112         EDClients.Remove( this );
00113 }
00114 
00116 // CEDClient outbound connection
00117 
00118 BOOL CEDClient::ConnectTo(DWORD nClientID, WORD nClientPort, IN_ADDR* pServerAddress, WORD nServerPort, GGUID* pGUID)
00119 {
00120         ASSERT( m_nClientID == 0 );
00121         
00122         m_nClientID = nClientID;
00123         if ( m_bGUID = ( pGUID != NULL ) ) m_pGUID = *pGUID;
00124         
00125         m_pHost.sin_family              = AF_INET;
00126         m_pHost.sin_addr                = (IN_ADDR&)nClientID;
00127         m_pHost.sin_port                = htons( nClientPort );
00128         
00129         if ( pServerAddress != NULL && nServerPort != 0 )
00130         {
00131                 m_pServer.sin_family    = AF_INET;
00132                 m_pServer.sin_addr              = *pServerAddress;
00133                 m_pServer.sin_port              = htons( nServerPort );
00134         }
00135         else
00136         {
00137                 ZeroMemory( &m_pServer, sizeof(m_pServer) );
00138         }
00139         
00140         return TRUE;
00141 }
00142 
00144 // CEDClient equality
00145 
00146 BOOL CEDClient::Equals(CEDClient* pClient)
00147 {
00148         ASSERT( this != NULL );
00149         ASSERT( pClient != NULL );
00150 
00151         if ( m_bGUID && pClient->m_bGUID ) return m_pGUID == pClient->m_pGUID;
00152         
00153         if ( CEDPacket::IsLowID( m_nClientID ) &&
00154                  CEDPacket::IsLowID( pClient->m_nClientID ) )
00155         {
00156                 return  ( m_pServer.sin_addr.S_un.S_addr == pClient->m_pServer.sin_addr.S_un.S_addr ) &&
00157                                 ( m_nClientID == pClient->m_nClientID );
00158         }
00159         
00160         return m_pHost.sin_addr.S_un.S_addr == pClient->m_pHost.sin_addr.S_un.S_addr;
00161 }
00162 
00164 // CEDClient connect
00165 
00166 BOOL CEDClient::Connect()
00167 {
00168         if ( m_hSocket != INVALID_SOCKET ) return FALSE;
00169         if ( EDClients.IsFull( this ) ) 
00170         {
00171                 // If this download isn't queued, don't try to start it.
00172                 if ( ! m_pDownload || m_pDownload->m_nState != dtsQueued ) return FALSE;        
00173 
00174                 // If we're really overloaded, we may have to drop some queued downloads
00175                 if ( EDClients.IsOverloaded() ) 
00176                 {
00177                         theApp.Message( MSG_ERROR, _T("ED2K Queued download was dropped due to connection overloading") );
00178                         return FALSE;
00179                 }
00180         }
00181         
00182         if ( CEDPacket::IsLowID( m_nClientID ) )
00183         {
00184                 if ( ! Neighbours.PushDonkey( m_nClientID, &m_pServer.sin_addr, htons( m_pServer.sin_port ) ) ) return FALSE;
00185                 m_tConnected = GetTickCount();
00186         }
00187         else
00188         {
00189                 if ( ! CConnection::ConnectTo( &m_pHost ) ) return FALSE;
00190                 theApp.Message( MSG_DEFAULT, IDS_ED2K_CLIENT_CONNECTING, (LPCTSTR)m_sAddress );
00191         }
00192         
00193         return TRUE;
00194 }
00195 
00197 // CEDClient remove
00198 
00199 void CEDClient::Remove()
00200 {
00201         ASSERT( this != NULL );
00202         
00203         m_bGUID = TRUE;
00204         Close();
00205         
00206         DetachUpload();
00207         DetachDownload();
00208         
00209         Close();
00210         
00211         if ( Settings.General.Debug && Settings.General.DebugLog ) theApp.Message( MSG_DEBUG, _T("CEDClient::Remove(): %x"), this );
00212         
00213         delete this;
00214 }
00215 
00217 // CEDClient merge
00218 
00219 void CEDClient::Merge(CEDClient* pClient)
00220 {
00221         ASSERT( pClient != NULL );
00222         
00223         if ( pClient->m_pDownload != NULL )
00224         {
00225                 DetachDownload();
00226                 m_pDownload = pClient->m_pDownload;
00227                 m_pDownload->m_pClient = this;
00228                 pClient->m_pDownload = NULL;
00229         }
00230         
00231         if ( pClient->m_pUpload != NULL )
00232         {
00233                 DetachUpload();
00234                 m_pUpload = pClient->m_pUpload;
00235                 m_pUpload->m_pClient = this;
00236                 pClient->m_pUpload = NULL;
00237         }
00238 
00239         // Make sure connection stuff is copied over
00240         if ( ( pClient->m_mInput.pLimit = &Downloads.m_nLimitDonkey ) ||
00241                  ( m_mInput.pLimit = &Downloads.m_nLimitDonkey ) )
00242         {
00243                 m_mInput.pLimit = &Downloads.m_nLimitDonkey;
00244         }
00245         else
00246         {
00247                 m_mInput.pLimit = &Settings.Bandwidth.Request;
00248         }
00249 
00250         if ( ( pClient->m_mOutput.pLimit != &Settings.Bandwidth.Request ) &&
00251                  ( pClient->m_mOutput.pLimit != NULL ) )
00252         {
00253                 m_mOutput.pLimit = pClient->m_mOutput.pLimit;
00254         }
00255         else if ( m_mOutput.pLimit == NULL )
00256         {
00257                 m_mOutput.pLimit = &Settings.Bandwidth.Request;
00258         }
00259 
00260         // Make sure chat/comments values are carried over
00261         if ( ! m_bOpenChat )            m_bOpenChat = pClient->m_bOpenChat;
00262         if ( ! m_bCommentSent )         m_bCommentSent = pClient->m_bCommentSent;
00263 
00264         // Copy client capabilities. (This should not be necessary)
00265         if ( ! m_nEmVersion )           m_nEmVersion = pClient->m_nEmVersion;
00266         if ( ! m_nEmCompatible )        m_nEmCompatible = pClient->m_nEmCompatible;
00267         if ( ! m_nSoftwareVersion )     m_nSoftwareVersion = pClient->m_nSoftwareVersion;
00268         if ( ! m_bEmAICH )                      m_bEmAICH = pClient->m_bEmAICH;
00269         if ( ! m_bEmUnicode )           m_bEmUnicode = pClient->m_bEmUnicode;
00270         if ( ! m_bEmUDPVersion )        m_bEmUDPVersion = pClient->m_bEmUDPVersion;
00271         if ( ! m_bEmDeflate )           m_bEmDeflate = pClient->m_bEmDeflate;
00272         if ( ! m_bEmSecureID )          m_bEmSecureID = pClient->m_bEmSecureID; 
00273         if ( ! m_bEmSources )           m_bEmSources = pClient->m_bEmSources;
00274         if ( ! m_bEmRequest )           m_bEmRequest = pClient->m_bEmRequest;   
00275         if ( ! m_bEmComments )          m_bEmComments = pClient->m_bEmComments;
00276         if ( ! m_bEmPeerCache )         m_bEmPeerCache = pClient->m_bEmPeerCache;
00277         if ( ! m_bEmBrowse )            m_bEmBrowse = pClient->m_bEmBrowse;
00278         if ( ! m_bEmMultiPacket )       m_bEmMultiPacket = pClient->m_bEmMultiPacket;   
00279         if ( ! m_bEmPreview )           m_bEmPreview = pClient->m_bEmPreview;
00280 }
00281 
00283 // CEDClient send a packet
00284 
00285 void CEDClient::Send(CEDPacket* pPacket, BOOL bRelease)
00286 {
00287         if ( pPacket != NULL )
00288         {
00289                 ASSERT( pPacket->m_nProtocol == PROTOCOL_ED2K );
00290                 ASSERT( pPacket->m_nEdProtocol == ED2K_PROTOCOL_EDONKEY || m_bEmule || pPacket->m_nType == ED2K_C2C_EMULEINFO );
00291                 
00292                 if ( m_hSocket != INVALID_SOCKET )
00293                 {
00294                         // pPacket->Debug( _T("CEDClient::Send") );
00295                         pPacket->ToBuffer( m_pOutput );
00296                         OnWrite();
00297                 }
00298                 
00299                 if ( bRelease ) pPacket->Release();
00300         }
00301         else if ( m_hSocket != INVALID_SOCKET )
00302         {
00303                 OnWrite();
00304         }
00305 }
00306 
00308 // CEDClient attach to existing connection
00309 
00310 void CEDClient::AttachTo(CConnection* pConnection)
00311 {
00312         ASSERT( m_hSocket == INVALID_SOCKET );
00313         CTransfer::AttachTo( pConnection );
00314         theApp.Message( MSG_DEFAULT, IDS_ED2K_CLIENT_ACCEPTED, (LPCTSTR)m_sAddress );
00315 }
00316 
00318 // CEDClient close
00319 
00320 void CEDClient::Close()
00321 {
00322         ASSERT( this != NULL );
00323         CTransfer::Close();
00324         m_bConnected = m_bLogin = FALSE;
00325 
00326         if ( ( m_pDownload ) && ( m_pDownload->m_nState == dtsDownloading ) )
00327         {
00328                 theApp.Message( MSG_ERROR, _T("Warning: CEDClient::Close() called for downloading client %s"), m_sAddress );
00329                 m_pDownload->SetState( dtsNull );
00330         }
00331         // if ( ! m_bGUID ) Remove();
00332 }
00333 
00335 // CEDClient transfer coupling
00336 
00337 BOOL CEDClient::AttachDownload(CDownloadTransferED2K* pDownload)
00338 {
00339         if ( m_pDownload != NULL ) return FALSE;
00340         m_pDownload = pDownload;
00341         
00342         if ( m_bLogin )
00343                 return m_pDownload->OnConnected();
00344         else if ( m_hSocket == INVALID_SOCKET )
00345                 Connect();
00346         
00347         return TRUE;
00348 }
00349 
00350 void CEDClient::OnDownloadClose()
00351 {
00352         CDownloadSource* pExcept = m_pDownload ? m_pDownload->m_pSource : NULL;
00353         m_pDownload = NULL;
00354         m_mInput.pLimit = &Settings.Bandwidth.Request;
00355         SeekNewDownload( pExcept );
00356 }
00357 
00358 BOOL CEDClient::SeekNewDownload(CDownloadSource* pExcept)
00359 {
00360         // Removed for a while
00361         return FALSE;
00362         
00363         if ( m_pDownload != NULL ) return FALSE;
00364         if ( m_bSeeking ) return FALSE;
00365         m_bSeeking = TRUE;
00366         BOOL bSeek = Downloads.OnDonkeyCallback( this, pExcept );
00367         m_bSeeking = FALSE;
00368         return bSeek;
00369 }
00370 
00371 void CEDClient::DetachDownload()
00372 {
00373         m_bSeeking = TRUE;
00374         if ( m_pDownload != NULL ) m_pDownload->Close( TS_UNKNOWN );
00375         ASSERT( m_pDownload == NULL );
00376         m_bSeeking = FALSE;
00377 }
00378 
00379 void CEDClient::OnUploadClose()
00380 {
00381         m_pUpload = NULL;
00382         m_mOutput.pLimit = &Settings.Bandwidth.Request;
00383 }
00384 
00385 void CEDClient::DetachUpload()
00386 {
00387         if ( m_pUpload != NULL ) m_pUpload->Close();
00388         ASSERT( m_pUpload == NULL );
00389 }
00390 
00392 // CEDClient run event
00393 
00394 BOOL CEDClient::OnRun()
00395 {
00396         // CTransfer::OnRun();
00397 
00398         DWORD tNow = GetTickCount();
00399         
00400         if ( ! m_bConnected )
00401         {
00402                 if ( tNow - m_tConnected > Settings.Connection.TimeoutConnect )
00403                 {
00404                         theApp.Message( MSG_ERROR, IDS_ED2K_CLIENT_CONNECT_TIMEOUT, (LPCTSTR)m_sAddress );
00405                         NotifyDropped();
00406                         Close();
00407                         return FALSE;
00408                 }
00409         }
00410         else if ( ! m_bLogin )
00411         {
00412                 if ( tNow - m_tConnected > Settings.Connection.TimeoutHandshake )
00413                 {
00414                         // Handshake timeout
00415                         theApp.Message( MSG_ERROR, IDS_ED2K_CLIENT_HANDSHAKE_TIMEOUT, (LPCTSTR)m_sAddress );
00416                         NotifyDropped();
00417                         Close();
00418                         return FALSE;
00419                 }
00420         }
00421         else
00422         {
00423                 if ( m_bOpenChat )
00424                 {
00425                         // Open a chat window.
00426                         if ( Settings.Community.ChatEnable ) ChatCore.OnED2KMessage( this, NULL );
00427                         m_bOpenChat = FALSE;
00428                 }
00429                 else if ( tNow - m_mInput.tLast > Settings.Connection.TimeoutTraffic &&
00430                          tNow - m_mOutput.tLast > Settings.Connection.TimeoutTraffic )
00431                 {
00432                         // Don't time out downloading clients.
00433                         if ( ( m_pDownload ) && ( m_pDownload->m_nState == dtsDownloading ) )
00434                                 return TRUE;
00435                         // Connection closed (Inactive)
00436                         theApp.Message( MSG_DEFAULT, IDS_ED2K_CLIENT_CLOSED, (LPCTSTR)m_sAddress );
00437                         Close();
00438                         return FALSE;
00439                 }
00440         }
00441         
00442         return TRUE;
00443 }
00444 
00445 void CEDClient::OnRunEx(DWORD tNow)
00446 {
00447         if ( m_pDownload != NULL )
00448         {
00449                 m_pDownload->OnRunEx( tNow );
00450                 if ( m_pUpload != NULL ) m_pUpload->OnRunEx( tNow );
00451         }
00452         else if ( m_pUpload != NULL )
00453         {
00454                 m_pUpload->OnRunEx( tNow );
00455         }
00456         else if ( m_hSocket == INVALID_SOCKET )
00457         {
00458                 // This client has no valid connections and should probably be removed. 
00459 
00460                 if ( m_bOpenChat )
00461                 {
00462                         // We might be waiting for a push reply- give it a little time
00463                         DWORD tNow = GetTickCount();
00464                         if ( tNow - m_tConnected < Settings.Connection.TimeoutHandshake  ) return;
00465                 }
00466 
00467                 Remove();
00468         }
00469 }
00470 
00472 // CEDClient connection event
00473 
00474 BOOL CEDClient::OnConnected()
00475 {
00476         SendHello( ED2K_C2C_HELLO );
00477         return TRUE;
00478 }
00479 
00481 // CEDClient connection loss event
00482 
00483 void CEDClient::OnDropped(BOOL bError)
00484 {
00485         theApp.Message( MSG_ERROR, IDS_ED2K_CLIENT_DROPPED, (LPCTSTR)m_sAddress );
00486         NotifyDropped( bError );
00487         Close();
00488 }
00489 
00490 void CEDClient::NotifyDropped(BOOL bError)
00491 {
00492         m_bSeeking = TRUE;
00493         if ( m_pDownload != NULL ) m_pDownload->OnDropped( bError );
00494         if ( m_pUpload != NULL ) m_pUpload->OnDropped( bError );
00495         m_bSeeking = FALSE;
00496 }
00497 
00499 // CEDClient write event
00500 
00501 BOOL CEDClient::OnWrite()
00502 {
00503         CTransfer::OnWrite();
00504         return TRUE;
00505 }
00506 
00508 // CEDClient read event
00509 
00510 BOOL CEDClient::OnRead()
00511 {
00512         BOOL bSuccess = TRUE;
00513         CEDPacket* pPacket;
00514         
00515         CTransfer::OnRead();
00516         
00517         while ( pPacket = CEDPacket::ReadBuffer( m_pInput, ED2K_PROTOCOL_EMULE ) )
00518         {
00519                 try
00520                 {
00521                         bSuccess = OnPacket( pPacket );
00522                 }
00523                 catch ( CException* pException )
00524                 {
00525                         pException->Delete();
00526                         if ( ! m_bGUID ) bSuccess = FALSE;
00527                 }
00528                 
00529                 pPacket->Release();
00530                 if ( ! bSuccess ) break;
00531         }
00532         
00533         return bSuccess;
00534 }
00535 
00537 // CEDClient logged in event
00538 
00539 BOOL CEDClient::OnLoggedIn()
00540 {
00541         m_bLogin = TRUE;
00542 
00543         EDClients.Merge( this );
00544 
00545         if ( m_pDownload != NULL )
00546         {
00547                 m_pDownload->OnConnected();
00548         }
00549         else
00550         {
00551                 SeekNewDownload();
00552         }
00553         
00554         if ( m_pUpload != NULL ) m_pUpload->OnConnected();
00555         
00556         return TRUE;
00557 }
00558 
00560 // CEDClient packet switch
00561 
00562 BOOL CEDClient::OnPacket(CEDPacket* pPacket)
00563 {
00564         // pPacket->Debug( _T("CEDClient::OnPacket") );
00565         
00566         if ( pPacket->m_nEdProtocol == ED2K_PROTOCOL_EDONKEY )
00567         {
00568                 switch ( pPacket->m_nType )
00569                 {
00570                 // Handshake
00571 
00572                 case ED2K_C2C_HELLO:
00573                         if ( pPacket->GetRemaining() ) pPacket->ReadByte();
00574                         return OnHello( pPacket );
00575                 case ED2K_C2C_HELLOANSWER:
00576                         return OnHello( pPacket );
00577                 
00578                 // Upload
00579 
00580                 case ED2K_C2C_FILEREQUEST:
00581                         return OnFileRequest( pPacket );
00582                 case ED2K_C2C_FILESTATUSREQUEST:
00583                         return OnFileStatusRequest( pPacket );
00584                 case ED2K_C2C_HASHSETREQUEST:
00585                         return OnHashsetRequest( pPacket );
00586                 case ED2K_C2C_QUEUEREQUEST:
00587                         return OnQueueRequest( pPacket );
00588                 case ED2K_C2C_QUEUERELEASE:
00589                         if ( m_pUpload != NULL ) m_pUpload->OnQueueRelease( pPacket );
00590                         return TRUE;
00591                 case ED2K_C2C_REQUESTPARTS:
00592                         if ( m_pUpload != NULL ) m_pUpload->OnRequestParts( pPacket );
00593                         return TRUE;
00594                 
00595                 // Download
00596                 
00597                 case ED2K_C2C_FILEREQANSWER:
00598                         if ( m_pDownload != NULL ) m_pDownload->OnFileReqAnswer( pPacket );
00599                         return TRUE;
00600                 case ED2K_C2C_FILENOTFOUND:
00601                         if ( m_pDownload != NULL ) m_pDownload->OnFileNotFound( pPacket );
00602                         return TRUE;
00603                 case ED2K_C2C_FILESTATUS:
00604                         if ( m_pDownload != NULL ) m_pDownload->OnFileStatus( pPacket );
00605                         return TRUE;
00606                 case ED2K_C2C_HASHSETANSWER:
00607                         if ( m_pDownload != NULL ) m_pDownload->OnHashsetAnswer( pPacket );
00608                         return TRUE;
00609                 case ED2K_C2C_QUEUERANK:
00610                         if ( m_pDownload != NULL ) m_pDownload->OnQueueRank( pPacket );
00611                         return TRUE;
00612                 case ED2K_C2C_STARTUPLOAD:
00613                         if ( m_pDownload != NULL ) m_pDownload->OnStartUpload( pPacket );
00614                         return TRUE;
00615                 case ED2K_C2C_FINISHUPLOAD:
00616                         if ( m_pDownload != NULL ) m_pDownload->OnFinishUpload( pPacket );
00617                         return TRUE;
00618                 case ED2K_C2C_SENDINGPART:
00619                         if ( m_pDownload != NULL ) m_pDownload->OnSendingPart( pPacket );
00620                         return TRUE;
00621 
00622                 // Misc
00623                 case ED2K_C2C_MESSAGE:
00624                         return OnMessage( pPacket );
00625 
00626                 default:
00627                         CString str;
00628                         str.Format( _T("Unrecognised packet - IP: %s - edonkey - type: 0x%x - in CEDClient::OnPacket"),
00629                                 LPCTSTR( m_sAddress ), int( pPacket->m_nType ) );
00630                         theApp.Message( MSG_DEBUG, LPCTSTR( str ) );
00631                 }
00632         }
00633         else if ( pPacket->m_nEdProtocol == ED2K_PROTOCOL_EMULE )
00634         {
00635                 switch ( pPacket->m_nType )
00636                 {
00637                 case ED2K_C2C_EMULEINFO:
00638                         return OnEmuleInfo( pPacket );
00639                 case ED2K_C2C_EMULEINFOANSWER:
00640                         return OnEmuleInfo( pPacket );  
00641 
00642                 case ED2K_C2C_COMPRESSEDPART:
00643                         if ( m_pDownload != NULL ) m_pDownload->OnCompressedPart( pPacket );
00644                         return TRUE;
00645                 case ED2K_C2C_QUEUERANKING:
00646                         if ( m_pDownload != NULL ) m_pDownload->OnRankingInfo( pPacket );
00647                         return TRUE;
00648                 case ED2K_C2C_FILEDESC:
00649                         if ( m_pDownload != NULL ) m_pDownload->OnFileComment( pPacket );
00650                         return TRUE;
00651 
00652                 case ED2K_C2C_REQUESTSOURCES:
00653                         return OnSourceRequest( pPacket );
00654                 case ED2K_C2C_ANSWERSOURCES:
00655                         return OnSourceAnswer( pPacket );
00656         
00657                 default:
00658                         CString str;
00659                         str.Format( _T("Unrecognised packet - IP: %s - emule - type: 0x%x - in CEDClient::OnPacket"),
00660                                 LPCTSTR( m_sAddress ), int( pPacket->m_nType ) );
00661                         theApp.Message( MSG_DEBUG, LPCTSTR( str ) );
00662                 }
00663         }
00664         
00665         return TRUE;
00666 }
00667 
00669 // CEDClient get comments
00670 
00671 BOOL CEDClient::SendCommentsPacket(int nRating, LPCTSTR pszComments)
00672 {
00673         // If we have not sent comments yet, and this client supports comments
00674         if ( ( ! m_bCommentSent ) && ( m_bEmComments > 0 ) && ( m_bEmule ) )
00675         { 
00676                 // Remove new lines and excess whitespace
00677                 CString strComments = pszComments;
00678                 strComments.Replace( '\n', ' ' );
00679                 strComments.Replace( '\r', ' ' );
00680                 strComments.Trim();
00681 
00682                 // If there's comments in the library
00683                 if ( ( nRating > 0 ) || ( strComments.GetLength() ) )
00684                 {
00685                         // Create the comments packet
00686                         CEDPacket* pComment = CEDPacket::New( ED2K_C2C_FILEDESC, ED2K_PROTOCOL_EMULE  );
00687                         pComment->WriteByte( (BYTE)min( nRating, 5 ) );
00688                         pComment->WriteLongEDString( strComments.Left(ED2K_COMMENT_MAX), m_bEmUnicode );
00689 
00690                         // Send comments / rating
00691                         theApp.Message( MSG_DEBUG, _T("Sending file comments to %s"), m_sAddress );
00692                         m_bCommentSent = TRUE;
00693                         Send( pComment );
00694                         
00695                         return TRUE;
00696                 }
00697         }
00698         return FALSE;
00699 }
00700 
00702 // CEDClient HELLO packet exchange
00703 
00704 void CEDClient::SendHello(BYTE nType)
00705 {
00706         CEDPacket* pPacket = CEDPacket::New( nType );
00707         
00708         if ( nType == ED2K_C2C_HELLO ) pPacket->WriteByte( 0x10 );
00709         
00710         CEDNeighbour* pServer = Neighbours.GetDonkeyServer();
00711         
00712         GGUID pGUID     = MyProfile.GUID;
00713         pGUID.n[5]      = 14;
00714         pGUID.n[14]     = 111;
00715         pPacket->Write( &pGUID, 16 );
00716         
00717         pPacket->WriteLongLE( pServer ? pServer->m_nClientID : Network.m_pHost.sin_addr.S_un.S_addr );
00718         pPacket->WriteShortLE( htons( Network.m_pHost.sin_port ) );
00719         
00720         pPacket->WriteLongLE( 5 );      // Number of Tags
00721         
00722         // 1 - Nickname
00723         CString strNick = MyProfile.GetNick();
00724         
00725         if ( Settings.eDonkey.TagNames )
00726         {
00727                 if ( strNick.GetLength() )
00728                         strNick += _T(" (shareaza.com)");
00729                 else
00730                         strNick = _T("www.shareaza.com");
00731         }
00732         strNick.Left( 255 );
00733         
00734         CEDTag( ED2K_CT_NAME, strNick ).Write( pPacket, ED2K_SERVER_TCP_UNICODE );
00735 
00736         // 2 - ED2K version
00737         CEDTag( ED2K_CT_VERSION, ED2K_VERSION ).Write( pPacket );
00738 
00739         // 3 - Software Version. 
00740         //              Note we're likely to corrupt the beta number, since there's only 3 bits available, 
00741         //              but it's the least important anyway.
00742         //              Note: Including this stops the remote client sending the eMuleInfo packet.
00743         DWORD nVersion =  ( ( ( ED2K_COMPATIBLECLIENT_ID & 0xFF ) << 24 ) | 
00744                                                         ( ( theApp.m_nVersion[0] & 0x7F ) << 17 ) | 
00745                                                         ( ( theApp.m_nVersion[1] & 0x7F ) << 10 ) |
00746                                                         ( ( theApp.m_nVersion[2] & 0x07 ) << 7  ) |
00747                                                         ( ( theApp.m_nVersion[3] & 0x7F )       ) );
00748 
00749         CEDTag( ED2K_CT_SOFTWAREVERSION, nVersion ).Write( pPacket );
00750 
00751         // 4 - Feature Versions. 
00752         BYTE nExtendedRequests = ( Settings.eDonkey.ExtendedRequest ) ? ED2K_VERSION_EXTENDEDREQUEST : 0 ;
00753         nVersion = ( ( ED2K_VERSION_AICH << 29) |                       // AICH
00754                                  ( TRUE << 28) |                                                // Unicode
00755                                  ( ED2K_VERSION_UDP << 24) |                    // UDP version
00756                                  ( ED2K_VERSION_COMPRESSION << 20) |    // Compression
00757                              ( ED2K_VERSION_SECUREID << 16) |           // Secure ID
00758                                  ( ED2K_VERSION_SOURCEEXCHANGE << 12) | // Source exchange
00759                                  ( nExtendedRequests << 8) |                    // Extended requests
00760                                  ( ED2K_VERSION_COMMENTS << 4) |                // Comments
00761                                  ( FALSE << 3) |                                                // Peer Cache
00762                                  ( TRUE << 2) |                                                 // No browse
00763                                  ( FALSE << 1) |                                                // Multipacket
00764                                  ( FALSE ) );                                                   // Preview
00765 
00766         CEDTag( ED2K_CT_FEATUREVERSIONS, nVersion ).Write( pPacket );
00767 
00768         // 5 - UDP Port
00769         CEDTag( ED2K_CT_UDPPORTS, htons( Network.m_pHost.sin_port ) ).Write( pPacket );
00770 
00771 
00772 //Note: This isn't needed
00773 /*
00774         // 6 - Port
00775         CEDTag( ED2K_CT_PORT, htons( Network.m_pHost.sin_port )  ).Write( pPacket );
00776 */      
00777         if ( pServer != NULL )
00778         {
00779                 pPacket->WriteLongLE( pServer->m_pHost.sin_addr.S_un.S_addr );
00780                 pPacket->WriteShortLE( htons( pServer->m_pHost.sin_port ) );
00781         }
00782         else
00783         {
00784                 pPacket->WriteLongLE( 0 );
00785                 pPacket->WriteShortLE( 0 );
00786         }
00787         
00788         Send( pPacket );
00789 }
00790 
00791 BOOL CEDClient::OnHello(CEDPacket* pPacket)
00792 {
00793         if ( m_bLogin ) return TRUE;
00794         
00795         if ( pPacket->GetRemaining() < sizeof(GUID) + 6 + 4 + 6 )
00796         {
00797                 theApp.Message( MSG_ERROR, IDS_ED2K_CLIENT_HANDSHAKE_FAIL, (LPCTSTR)m_sAddress );
00798                 Close();
00799                 return FALSE;
00800         }
00801         
00802         GGUID pGUID;
00803         pPacket->Read( &pGUID, sizeof(GUID) );
00804         
00805         /*
00806         if ( m_bGUID )
00807         {
00808                 if ( pGUID != m_pGUID )
00809                 {
00810                         theApp.Message( MSG_ERROR, IDS_ED2K_CLIENT_WRONG_GUID, (LPCTSTR)m_sAddress );
00811                         Close();
00812                         return FALSE;
00813                 }
00814         }
00815         */
00816         
00817         m_bGUID                         = TRUE;
00818         m_pGUID                         = pGUID;
00819         m_nClientID                     = pPacket->ReadLongLE();
00820         m_pHost.sin_port        = htons( pPacket->ReadShortLE() );
00821         
00822         DWORD nCount = pPacket->ReadLongLE();
00823         
00824         while ( nCount-- > 0 && pPacket->GetRemaining() > 0 )
00825         {
00826                 CEDTag pTag;
00827                 if ( ! pTag.Read( pPacket, ED2K_SERVER_TCP_UNICODE ) )
00828                 {
00829                         theApp.Message( MSG_ERROR, IDS_ED2K_CLIENT_HANDSHAKE_FAIL, (LPCTSTR)m_sAddress );
00830                         Close();
00831                         return FALSE;
00832                 }
00833                 switch ( pTag.m_nKey )
00834                 {
00835                 case ED2K_CT_NAME:
00836                         if ( pTag.m_nType == ED2K_TAG_STRING ) m_sNick = pTag.m_sValue;
00837                         break;
00838                 case ED2K_CT_PORT:
00839                         if ( pTag.m_nType == ED2K_TAG_INT ) m_pHost.sin_port = htons( (WORD)pTag.m_nValue );
00840                         break;
00841                 case ED2K_CT_VERSION:
00842                         if ( pTag.m_nType == ED2K_TAG_INT ) m_nVersion = pTag.m_nValue;
00843                         break;
00844                 case ED2K_CT_MODVERSION:
00845                         break;
00846                 case ED2K_CT_UDPPORTS:
00847                         if ( pTag.m_nType == ED2K_TAG_INT )     m_nUDP = (WORD)(pTag.m_nValue & 0x0000FFFF);
00848                         break;
00849                 case ED2K_CT_FEATUREVERSIONS:
00850                         if ( pTag.m_nType == ED2K_TAG_INT ) 
00851                         {
00852                                 m_bEmule = TRUE;
00853                                 m_bEmAICH               = (pTag.m_nValue >> 29) & 0x07;
00854                                 m_bEmUnicode    = (pTag.m_nValue >> 28) & 0x01;
00855                                 m_bEmUDPVersion = (pTag.m_nValue >> 24) & 0x0F;
00856                                 m_bEmDeflate    = (pTag.m_nValue >> 20) & 0x0F;
00857                                 m_bEmSecureID   = (pTag.m_nValue >> 16) & 0x0F;
00858                                 m_bEmSources    = (pTag.m_nValue >> 12) & 0x0F;
00859                                 m_bEmRequest    = (pTag.m_nValue >> 8 ) & 0x0F;
00860                                 m_bEmComments   = (pTag.m_nValue >> 4 ) & 0x0F;
00861                                 m_bEmPeerCache  = (pTag.m_nValue >> 3 ) & 0x01;
00862                                 m_bEmBrowse             =!(pTag.m_nValue >> 2 ) & 0x01;
00863                                 m_bEmMultiPacket= (pTag.m_nValue >> 1 ) & 0x01;
00864                                 m_bEmPreview    = (pTag.m_nValue) & 0x01;
00865                         }
00866                         break;
00867                 case ED2K_CT_SOFTWAREVERSION:
00868                         if ( pTag.m_nType == ED2K_TAG_INT ) 
00869                         {
00870                                 m_bEmule = TRUE;
00871                                 m_nSoftwareVersion = pTag.m_nValue & 0x00FFFFFF;
00872                                 m_nEmCompatible = pTag.m_nValue >> 24;
00873                         }
00874                         break;
00875                 case ED2K_CT_UNKNOWN1:
00876                         break;
00877                 case ED2K_CT_UNKNOWN2:
00878                         break;
00879                 case ED2K_CT_MOREFEATUREVERSIONS:
00880                         // This currently only holds the KAD version- We aren't interested in that.
00881                         break;
00882                 case ED2K_CT_UNKNOWN3:
00883                         break;
00884                 default:
00885                         if ( _tcsicmp( pTag.m_sKey, _T("pr") ) == 0 )
00886                         {
00887                                 // No idea what this means. Probably from the eDonkey client.
00888                         }
00889                         else
00890                         {
00891                                 CString str;
00892                                 str.Format( _T("Unrecognised packet - IP: %s - opcode: 0x%x - in CEDClient::OnHello"),
00893                                         LPCTSTR( m_sAddress ), int( pTag.m_nKey ) );
00894                                 theApp.Message( MSG_DEBUG, LPCTSTR( str ) );
00895                         }
00896                 }
00897         }
00898         
00899         if ( pPacket->GetRemaining() < 6 )
00900         {
00901                 theApp.Message( MSG_ERROR, IDS_ED2K_CLIENT_HANDSHAKE_FAIL, (LPCTSTR)m_sAddress );
00902                 Close();
00903                 return FALSE;
00904         }
00905         
00906         // Read their server IP / port
00907         m_pServer.sin_addr.S_un.S_addr = pPacket->ReadLongLE();
00908         m_pServer.sin_port = htons( pPacket->ReadShortLE() );
00909 
00910         // If we are learning new servers from clients
00911         if ( Settings.eDonkey.LearnNewServersClient && ! Network.IsFirewalledAddress( &m_pServer.sin_addr ) )
00912         {       // Add their server
00913                 HostCache.eDonkey.Add( &m_pServer.sin_addr, htons( m_pServer.sin_port ) );
00914         }
00915 
00916         // Some clients append additional "stuff" at the end.
00917         if ( pPacket->GetRemaining() >= 4 )
00918         {
00919                 // We can use it to ID clients
00920                 DWORD nValue = pPacket->ReadLongLE();
00921                 
00922                 // MLDonkey
00923                 if ( nValue == 0x4B444C4D ) m_nEmCompatible = 10;
00924         }
00925         
00926 
00927         // Get client name/version
00928         DeriveSoftwareVersion();
00929         
00930         // If this was a hello
00931         if ( pPacket->m_nType == ED2K_C2C_HELLO )
00932         {
00933                 // If it's an eMule compatible client that has not already sent us extended details
00934                 if ( ( m_bEmule ) && ( ! m_nSoftwareVersion ) ) 
00935                         SendEmuleInfo( ED2K_C2C_EMULEINFO );    // Send extended hello
00936 
00937                 // Send hello answer
00938                 SendHello( ED2K_C2C_HELLOANSWER );
00939         }
00940         
00941         if ( m_bLogin )
00942                 return TRUE;
00943         else
00944                 return OnLoggedIn();
00945 }
00946 
00948 // CEDClient EMULE INFO packet exchange
00949 
00950 void CEDClient::SendEmuleInfo(BYTE nType)
00951 {
00952         CEDPacket* pPacket = CEDPacket::New( nType, ED2K_PROTOCOL_EMULE );
00953         
00954         pPacket->WriteByte( 0x40 );             // eMule version
00955         pPacket->WriteByte( 0x01 );             // eMule protocol
00956         
00957         // Write number of tags
00958         pPacket->WriteLongLE( Settings.eDonkey.ExtendedRequest ? 7 : 6 );
00959 
00960         // Write tags
00961         CEDTag( ED2K_ET_COMPATIBLECLIENT, ED2K_COMPATIBLECLIENT_ID ).Write( pPacket );
00962         CEDTag( ED2K_ET_COMPRESSION, ED2K_VERSION_COMPRESSION ).Write( pPacket );
00963         CEDTag( ED2K_ET_SOURCEEXCHANGE, ED2K_VERSION_SOURCEEXCHANGE ).Write( pPacket );
00964         CEDTag( ED2K_ET_UDPVER, ED2K_VERSION_UDP ).Write( pPacket );
00965         CEDTag( ED2K_ET_UDPPORT, htons( Network.m_pHost.sin_port ) ).Write( pPacket );
00966         CEDTag( ED2K_ET_COMMENTS, ED2K_VERSION_COMMENTS ).Write( pPacket );     
00967         if ( Settings.eDonkey.ExtendedRequest ) CEDTag( ED2K_ET_EXTENDEDREQUEST, ED2K_VERSION_EXTENDEDREQUEST ).Write( pPacket );
00968         Send( pPacket );
00969 }
00970 
00971 BOOL CEDClient::OnEmuleInfo(CEDPacket* pPacket)
00972 {
00973         if ( pPacket->GetRemaining() < 5 )
00974         {
00975                 theApp.Message( MSG_ERROR, IDS_ED2K_CLIENT_HANDSHAKE_FAIL, (LPCTSTR)m_sAddress );
00976                 Close();
00977                 return FALSE;
00978         }
00979         
00980         m_nEmVersion    = pPacket->ReadByte();
00981         BYTE nProtocol  = pPacket->ReadByte();
00982         
00983         if ( nProtocol != 1 ) return TRUE;
00984         
00985         // Have to assume capabilities for these versions
00986         if ( m_nEmVersion > 0x22 && m_nEmVersion < 0x25 ) m_bEmSources = 1;
00987         if ( m_nEmVersion == 0x24 ) m_bEmComments = 1;
00988         // Set the client ID to unknown
00989         m_nEmCompatible = ED2K_CLIENT_UNKNOWN;
00990         
00991         // Read number of tags
00992         DWORD nCount = pPacket->ReadLongLE();
00993         
00994         while ( nCount-- > 0 && pPacket->GetRemaining() > 0 )
00995         {
00996                 CEDTag pTag;
00997                 
00998                 // Read tag
00999                 if ( ! pTag.Read( pPacket ) )
01000                 {
01001                         theApp.Message( MSG_ERROR, IDS_ED2K_CLIENT_HANDSHAKE_FAIL, (LPCTSTR)m_sAddress );
01002                         Close();
01003                         return FALSE;
01004                 }
01005                 
01006                 switch ( pTag.m_nKey )
01007                 {
01008                 case ED2K_ET_COMPRESSION:
01009                          if ( pTag.m_nType == ED2K_TAG_INT ) m_bEmDeflate = pTag.m_nValue;
01010                         break;
01011                 case ED2K_ET_UDPPORT:
01012                         if ( pTag.m_nType == ED2K_TAG_INT ) m_nUDP = (WORD)pTag.m_nValue;
01013                         break;
01014                 case ED2K_ET_UDPVER:
01015                         if ( pTag.m_nType == ED2K_TAG_INT ) m_bEmUDPVersion = (WORD)pTag.m_nValue;
01016                         break;
01017                 case ED2K_ET_SOURCEEXCHANGE:
01018                         if ( pTag.m_nType == ED2K_TAG_INT ) m_bEmSources = pTag.m_nValue;
01019                         break;
01020                 case ED2K_ET_COMMENTS:
01021                         if ( pTag.m_nType == ED2K_TAG_INT ) m_bEmComments = pTag.m_nValue;
01022                         break;
01023                 case ED2K_ET_EXTENDEDREQUEST:
01024                         if ( pTag.m_nType == ED2K_TAG_INT ) m_bEmRequest = pTag.m_nValue;
01025                         break;
01026                 case ED2K_ET_COMPATIBLECLIENT:
01027                         if ( pTag.m_nType == ED2K_TAG_INT ) m_nEmCompatible = pTag.m_nValue;
01028                         break;
01029                 case ED2K_ET_FEATURES:          // We don't use these
01030                         break;
01031                 case ED2K_CT_MODVERSION:        // Some clients send this here
01032                         if ( m_nEmCompatible == ED2K_CLIENT_UNKNOWN )
01033                                 m_nEmCompatible = ED2K_CLIENT_MOD;
01034                         break;
01035                 default:
01036                         CString str;
01037                         str.Format( _T("Unrecognised packet - IP: %s - opcode: 0x%x - in CEDClient::OnEmuleInfo"),
01038                                 LPCTSTR( m_sAddress ), int( pTag.m_nKey ) );
01039                         theApp.Message( MSG_DEBUG, LPCTSTR( str ) );
01040                 }
01041         }
01042         
01043         m_bEmule = TRUE;
01044 
01045         // Send answer if required
01046         if ( pPacket->m_nType == ED2K_C2C_EMULEINFO ) SendEmuleInfo( ED2K_C2C_EMULEINFOANSWER );
01047 
01048         // Get client name/version
01049         DeriveVersion();
01050         
01051         return TRUE;
01052 }
01053 
01055 // CEDClient client version
01056 
01057 //Newer clients send the 24 bit "software version" + client ID
01058 void CEDClient::DeriveSoftwareVersion()
01059 {
01060         //Newer clients send the 24 bit software version + client ID
01061         if ( m_nSoftwareVersion )
01062         {
01063                 // It's eMule compatible
01064                 m_bEmule = TRUE;
01065 
01066                 // Determine client from the compatible client byte
01067                 switch ( m_nEmCompatible )
01068                 {
01069                 case 0:
01070                         m_sUserAgent.Format( _T("eMule %i.%i%c"), 
01071                                 ( ( m_nSoftwareVersion >> 17 ) & 0x7F ), ( ( m_nSoftwareVersion >> 10 ) & 0x7F ), 
01072                                 ( ( m_nSoftwareVersion >>  7 ) & 0x07 ) + 'a' );
01073 /*
01074                         //This code displays the eMule build number- not currently used
01075                         m_sUserAgent.Format( _T("eMule %i.%i%c (%i)"), 
01076                                 ( ( m_nSoftwareVersion >> 17 ) & 0x7F ), ( ( m_nSoftwareVersion >> 10 ) & 0x7F ), 
01077                                 ( ( m_nSoftwareVersion >>  7 ) & 0x07 ) + 'a', ( ( m_nSoftwareVersion ) & 0x7F ) );
01078 */
01079                         break;
01080                 case 1:
01081                         m_sUserAgent.Format( _T("cDonkey %i.%i%c"), 
01082                                 ( ( m_nSoftwareVersion >> 17 ) & 0x7F ), ( ( m_nSoftwareVersion >> 10 ) & 0x7F ), 
01083                                 ( ( m_nSoftwareVersion >>  7 ) & 0x07 ) + 'a' );
01084                         break;
01085                 case 2:
01086                         m_sUserAgent.Format( _T("xMule %i.%i%c"), 
01087                                 ( ( m_nSoftwareVersion >> 17 ) & 0x7F ), ( ( m_nSoftwareVersion >> 10 ) & 0x7F ), 
01088                                 ( ( m_nSoftwareVersion >>  7 ) & 0x07 ) + 'a' );
01089                         break;
01090                 case 3:
01091                         m_sUserAgent.Format( _T("aMule %i.%i%c"), 
01092                                 ( ( m_nSoftwareVersion >> 17 ) & 0x7F ), ( ( m_nSoftwareVersion >> 10 ) & 0x7F ), 
01093                                 ( ( m_nSoftwareVersion >>  7 ) & 0x07 ) + 'a' );
01094                         break;
01095                 case 4:
01096                         //Note- 2nd last number (Beta build #) may be truncated, since it's only 3 bits.
01097                         m_sUserAgent.Format( _T("Shareaza %i.%i.%i.%i"), 
01098                                 ( ( m_nSoftwareVersion >> 17 ) &0x7F ), ( ( m_nSoftwareVersion >> 10 ) &0x7F ), 
01099                                 ( ( m_nSoftwareVersion >>  7 ) &0x07 ), ( ( m_nSoftwareVersion ) &0x7F ) );
01100                         
01101                         //Client allows G2 browse, etc
01102                         if ( m_pUpload ) m_pUpload->m_bClientExtended = TRUE;
01103                         if ( m_pDownload && m_pDownload->m_pSource ) m_pDownload->m_pSource->m_bClientExtended = TRUE;
01104                         break;
01105                 case 5:
01106                         m_sUserAgent.Format( _T("ePlus %i.%i%c"), 
01107                                 ( ( m_nSoftwareVersion >> 17 ) & 0x7F ), ( ( m_nSoftwareVersion >> 10 ) & 0x7F ), 
01108                                 ( ( m_nSoftwareVersion >>  7 ) & 0x07 ) + 'a' );
01109                         break;
01110                 case 10:
01111                         m_sUserAgent.Format( _T("MlDonkey") );
01112                         break;
01113                 case 20:
01114                         m_sUserAgent.Format( _T("Lphant %i.%i%c"), 
01115                                 ( ( m_nSoftwareVersion >> 17 ) & 0x7F ), ( ( m_nSoftwareVersion >> 10 ) & 0x7F ), 
01116                                 ( ( m_nSoftwareVersion >>  7 ) & 0x07 ) + 'a' );
01117                         break;
01118                 case 40:
01119                         //Note- 2nd last number (Beta build #) may be truncated, since it's only 3 bits.
01120                         m_sUserAgent.Format( _T("Shareaza %i.%i.%i.%i"), 
01121                                 ( ( m_nSoftwareVersion >> 17 ) &0x7F ), ( ( m_nSoftwareVersion >> 10 ) &0x7F ), 
01122                                 ( ( m_nSoftwareVersion >>  7 ) &0x07 ), ( ( m_nSoftwareVersion ) &0x7F ) );
01123                         
01124                         //Client allows G2 browse, etc
01125                         if ( m_pUpload ) m_pUpload->m_bClientExtended = TRUE;
01126                         if ( m_pDownload && m_pDownload->m_pSource ) m_pDownload->m_pSource->m_bClientExtended = TRUE;
01127                         break;
01128                 default:
01129                         m_sUserAgent.Format( _T("eMule/c(%i) %i.%i%c"), m_nEmCompatible,
01130                                 ( ( m_nSoftwareVersion >> 17 ) & 0x7F ), ( ( m_nSoftwareVersion >> 10 ) & 0x7F ), 
01131                                 ( ( m_nSoftwareVersion >>  7 ) & 0x07 ) + 'a' );
01132                         break;
01133                 }
01134         }
01135         else
01136         {
01137                 DeriveVersion();
01138         }
01139 }
01140 
01141 //This is the older style of IDing a client
01142 void CEDClient::DeriveVersion()
01143 {
01144         if ( m_nSoftwareVersion ) return;
01145 
01146         if ( m_pGUID.n[5] == 13 && m_pGUID.n[14] == 110 )
01147         {
01148                 m_bEmule = TRUE;
01149                 m_sUserAgent.Format( _T("eMule v%i"), m_nVersion );
01150         }
01151         else if ( m_pGUID.n[5] == 14 && m_pGUID.n[14] == 111 )
01152         {
01153                 m_bEmule = TRUE;
01154                 m_sUserAgent.Format( _T("eMule v%i"), m_nVersion );
01155         }
01156         else if ( m_pGUID.n[5] == 'M' && m_pGUID.n[14] == 'L' )
01157         {
01158                 m_sUserAgent.Format( _T("mlDonkey v%i"), m_nVersion );
01159         }
01160         else
01161         {
01162                 if ( m_nVersion >= 1000 )
01163                         m_sUserAgent.Format( _T("eDonkey v1.%i"), m_nVersion - 1000 );
01164                 else
01165                         m_sUserAgent.Format( _T("eDonkey v1.%i"), m_nVersion);
01166         }
01167 
01168         
01169         if ( m_bEmule && m_nEmVersion > 0 )
01170         {
01171                 switch ( m_nEmCompatible )
01172                 {
01173                 case 0:
01174                         m_sUserAgent.Format( _T("eMule v0.%i%i"), m_nEmVersion >> 4, m_nEmVersion & 15 );
01175                         break;
01176                 case 1:
01177                         m_sUserAgent.Format( _T("cDonkey v%i.%i"), m_nEmVersion >> 4, m_nEmVersion & 15 );
01178                         break;
01179                 case 2:
01180                         m_sUserAgent.Format( _T("xMule v0.%i%i"), m_nEmVersion >> 4, m_nEmVersion & 15 );
01181                         break;
01182                 case 3:
01183                         m_sUserAgent.Format( _T("aMule v0.%i%i"), m_nEmVersion >> 4, m_nEmVersion & 15 );
01184                         break;
01185                 case 4:
01186                         m_sUserAgent.Format( _T("Shareaza") );
01187                         if ( m_pUpload ) m_pUpload->m_bClientExtended = TRUE;
01188                         if ( m_pDownload && m_pDownload->m_pSource ) m_pDownload->m_pSource->m_bClientExtended = TRUE;
01189                         break;
01190                 case 10:
01191                         m_sUserAgent.Format( _T("MlDonkey v0.%i%i"), m_nEmVersion >> 4, m_nEmVersion & 15 );
01192                         break;
01193                 case 20:
01194                         m_sUserAgent.Format( _T("Lphant v0.%i%i"), m_nEmVersion >> 4, m_nEmVersion & 15 );
01195                         break;
01196                 case 40:
01197                         m_sUserAgent.Format( _T("Shareaza") );
01198                         if ( m_pUpload ) m_pUpload->m_bClientExtended = TRUE;
01199                         if ( m_pDownload && m_pDownload->m_pSource ) m_pDownload->m_pSource->m_bClientExtended = TRUE;
01200                         break;
01201                 case ED2K_CLIENT_MOD:   // (Did not send a compatible client ID, but did send a MOD tag)
01202                         m_sUserAgent.Format( _T("eMule mod %i"), m_nEmVersion );
01203                         break;
01204                 case ED2K_CLIENT_UNKNOWN:       // (Did not send a compatible client ID)
01205                         if ( _tcsistr( m_sNick, _T("www.pruna.com") ) )
01206                                 m_sUserAgent.Format( _T("Pruna %i"), m_nEmVersion );
01207                         else
01208                                 m_sUserAgent.Format( _T("Unidentified %i"), m_nEmVersion );
01209                         break;
01210                 default:        // (Sent a compatible client ID, but we don't recognise it)
01211                         m_sUserAgent.Format( _T("eMule/c (%i) v0.%i%i"), m_nEmCompatible, m_nEmVersion >> 4, m_nEmVersion & 15 );
01212                         break;
01213                 }
01214         }
01215 }
01216 
01218 // CEDClient FILE REQUEST handler
01219 
01220 BOOL CEDClient::OnFileRequest(CEDPacket* pPacket)
01221 {
01222         int nRating;
01223         CString strComments;
01224 
01225         if ( pPacket->GetRemaining() < sizeof(MD4) )
01226         {
01227                 theApp.Message( MSG_ERROR, IDS_ED2K_CLIENT_BAD_PACKET, (LPCTSTR)m_sAddress, pPacket->m_nType );
01228                 return TRUE;
01229         }
01230         
01231         CEDPacket* pReply = CEDPacket::New( ED2K_C2C_FILEREQANSWER );
01232         
01233         pPacket->Read( &m_pUpMD4, sizeof(MD4) );
01234         pReply->Write( &m_pUpMD4, sizeof(MD4) );
01235 
01236 
01237         // Extra security check (Shouldn't be needed, but there have been reports of glitches)
01238         if ( Security.IsDenied( &m_pHost.sin_addr ) )
01239         {
01240                 pReply->m_nType = ED2K_C2C_FILENOTFOUND;
01241                 Send( pReply );
01242                 theApp.Message( MSG_ERROR, _T("ED2K upload to %s blocked by security rules."), m_sAddress);
01243                 return TRUE;
01244         }
01245 
01246         m_bUpMD4 = TRUE;
01247         
01248         CSingleLock oLock( &Library.m_pSection,TRUE );
01249         CLibraryFile* pFile = LibraryMaps.LookupFileByED2K( &m_pUpMD4, TRUE, TRUE );
01250         if ( ( pFile ) && ( UploadQueues.CanUpload( PROTOCOL_ED2K, pFile, TRUE ) ) )
01251         {
01252                 // Create the reply packet
01253                 pReply->WriteEDString( pFile->m_sName, m_bEmUnicode );
01254                 // Get the comments/rating data
01255                 nRating = pFile->m_nRating;
01256                 strComments = pFile->m_sComments;
01257                 oLock.Unlock();
01258 
01259                 // Send reply
01260                 Send( pReply );
01261                 // Send comments / rating (if required)
01262                 SendCommentsPacket( nRating, strComments );
01263 
01264 
01265                 return TRUE;
01266         }
01267         oLock.Unlock();
01268 
01269         if ( CDownload* pDownload = Downloads.FindByED2K( &m_pUpMD4, TRUE ) )
01270         {
01271                 pReply->WriteEDString( pDownload->m_sRemoteName, m_bEmUnicode );
01272                 Send( pReply );
01273                 return TRUE;
01274         }
01275         
01276         pReply->m_nType = ED2K_C2C_FILENOTFOUND;
01277         Send( pReply );
01278         
01279         theApp.Message( MSG_ERROR, IDS_UPLOAD_FILENOTFOUND, (LPCTSTR)m_sAddress,
01280                 (LPCTSTR)CED2K::HashToString( &m_pUpMD4, TRUE ) );
01281         
01282         return TRUE;
01283 }
01284 
01286 // CEDClient file status request
01287 
01288 BOOL CEDClient::OnFileStatusRequest(CEDPacket* pPacket)
01289 {
01290         if ( pPacket->GetRemaining() < sizeof(MD4) )
01291         {
01292                 theApp.Message( MSG_ERROR, IDS_ED2K_CLIENT_BAD_PACKET, (LPCTSTR)m_sAddress, pPacket->m_nType );
01293                 return TRUE;
01294         }
01295         
01296         CEDPacket* pReply = CEDPacket::New( ED2K_C2C_FILESTATUS );
01297         
01298         pPacket->Read( &m_pUpMD4, sizeof(MD4) );
01299         pReply->Write( &m_pUpMD4, sizeof(MD4) );
01300         m_bUpMD4 = TRUE;
01301         
01302         CSingleLock oLock( &Library.m_pSection, TRUE );
01303         if ( CLibraryFile* pFile = LibraryMaps.LookupFileByED2K( &m_pUpMD4, TRUE, TRUE ) )
01304         {
01305                 pReply->WriteShortLE( 0 );
01306                 pReply->WriteByte( 0 );
01307                 
01308                 m_nUpSize = pFile->GetSize();
01309                 if ( ! CEDPacket::IsLowID( m_nClientID ) )
01310                         pFile->AddAlternateSource( GetSourceURL() );
01311                 
01312                 oLock.Unlock();
01313                 Send( pReply );
01314                 return TRUE;
01315         }
01316         oLock.Unlock();
01317         if ( CDownload* pDownload = Downloads.FindByED2K( &m_pUpMD4, TRUE ) )
01318         {
01319                 WritePartStatus( pReply, pDownload );
01320                 m_nUpSize = pDownload->m_nSize;
01321                 
01322                 if ( ! pDownload->IsMoving() )
01323                         pDownload->AddSourceED2K( m_nClientID, htons( m_pHost.sin_port ), 
01324                         m_pServer.sin_addr.S_un.S_addr, htons( m_pServer.sin_port ), &m_pGUID );
01325                 
01326                 Send( pReply );
01327                 return TRUE;
01328         }
01329         
01330         m_bUpMD4 = FALSE;
01331         
01332         pReply->m_nType = ED2K_C2C_FILENOTFOUND;
01333         Send( pReply );
01334         
01335         theApp.Message( MSG_ERROR, IDS_UPLOAD_FILENOTFOUND, (LPCTSTR)m_sAddress,
01336                 (LPCTSTR)CED2K::HashToString( &m_pUpMD4, TRUE ) );      
01337         
01338         return TRUE;
01339 }
01340 
01342 // CEDClient hash set request
01343 
01344 BOOL CEDClient::OnHashsetRequest(CEDPacket* pPacket)
01345 {
01346         if ( pPacket->GetRemaining() < sizeof(MD4) )
01347         {
01348                 theApp.Message( MSG_ERROR, IDS_ED2K_CLIENT_BAD_PACKET, (LPCTSTR)m_sAddress, pPacket->m_nType );
01349                 return TRUE;
01350         }
01351         
01352         MD4 pHash;
01353         pPacket->Read( &pHash, sizeof(MD4) );
01354         
01355         CED2K* pHashset = NULL;
01356         BOOL bDelete = FALSE;
01357         CString strName;
01358 
01359         CSingleLock oLock( &Library.m_pSection, TRUE );
01360         if ( CLibraryFile* pFile = LibraryMaps.LookupFileByED2K( &pHash, TRUE, TRUE ) )
01361         {
01362                 strName         = pFile->m_sName;
01363                 pHashset        = pFile->GetED2K();
01364                 bDelete         = TRUE;
01365                 oLock.Unlock();
01366         }
01367         else
01368         {
01369                 oLock.Unlock();
01370                 if ( CDownload* pDownload = Downloads.FindByED2K( &pHash, TRUE ) )
01371                 {
01372                         if ( pHashset = pDownload->GetHashset() )
01373                         {
01374                                 strName         = pDownload->m_sRemoteName;
01375                                 bDelete         = FALSE;
01376                         }
01377                 }
01378         }
01379 
01380         if ( pHashset != NULL )
01381         {
01382                 CEDPacket* pReply = CEDPacket::New( ED2K_C2C_HASHSETANSWER );
01383                 pReply->Write( &pHash, sizeof(MD4) );
01384                 int nBlocks = pHashset->GetBlockCount();
01385                 if ( nBlocks <= 1 ) nBlocks = 0;
01386                 pReply->WriteShortLE( (WORD)nBlocks );
01387                 pReply->Write( pHashset->GetRawPtr(), sizeof(MD4) * nBlocks );
01388                 if ( bDelete ) delete pHashset;
01389                 Send( pReply );
01390                 
01391                 theApp.Message( MSG_DEFAULT, IDS_ED2K_CLIENT_SENT_HASHSET,
01392                         (LPCTSTR)strName, (LPCTSTR)m_sAddress );        
01393         }
01394         else
01395         {
01396                 CEDPacket* pReply = CEDPacket::New( ED2K_C2C_FILENOTFOUND );
01397                 pReply->Write( &pHash, sizeof(MD4) );
01398                 Send( pReply );
01399                 
01400                 theApp.Message( MSG_ERROR, IDS_UPLOAD_FILENOTFOUND, (LPCTSTR)m_sAddress,
01401                         (LPCTSTR)CED2K::HashToString( &pHash, TRUE ) ); 
01402         }
01403         
01404         return TRUE;
01405 }
01406 
01408 // CEDClient queue request
01409 
01410 BOOL CEDClient::OnQueueRequest(CEDPacket* pPacket)
01411 {
01412         if ( m_bUpMD4 == FALSE )
01413         {
01414                 // MESSAGE: File not requested yet
01415                 return TRUE;
01416         }
01417         
01418         if ( m_pUpload != NULL && m_pUpload->m_pED2K != m_pUpMD4 )
01419                 DetachUpload();
01420         
01421         if ( m_pUpload == NULL )
01422                 m_pUpload = new CUploadTransferED2K( this );
01423         
01424         m_pUpload->Request( &m_pUpMD4 );
01425         
01426         return TRUE;
01427 }
01428 
01430 // CEDClient Message handler
01431 
01432 BOOL CEDClient::OnMessage(CEDPacket* pPacket)
01433 {
01434         DWORD nMessageLength;
01435         CString sMessage;
01436 
01437         // Check packet has message length
01438         if ( pPacket->GetRemaining() < 3 )
01439         {
01440                 theApp.Message( MSG_ERROR, _T("Empty message packet received from %s"), (LPCTSTR)m_sAddress );
01441                 return TRUE;
01442         }
01443 
01444         // Read message length
01445         nMessageLength = pPacket->ReadShortLE();
01446 
01447         // Validate message length
01448         if ( ( nMessageLength < 1 ) || ( nMessageLength > ED2K_MESSAGE_MAX ) || ( nMessageLength != pPacket->GetRemaining() ) )
01449         {
01450                 theApp.Message( MSG_ERROR, _T("Invalid message packet received from %s"), (LPCTSTR)m_sAddress );
01451                 return TRUE;
01452         }
01453 
01454         // Read in message
01455         if ( m_bEmUnicode )
01456                 sMessage = pPacket->ReadStringUTF8( nMessageLength );
01457         else
01458                 sMessage = pPacket->ReadString( nMessageLength );
01459 
01460 
01461         // Check the message is not spam
01462         if ( MessageFilter.IsED2KSpam( sMessage ) )     
01463         {
01464                 // Block L33cher mods
01465                 if ( m_pDownload == NULL ) Security.Ban( &m_pHost.sin_addr, banSession, FALSE );
01466                 // Don't display message
01467                 return TRUE;
01468         }
01469         if ( MessageFilter.IsFiltered( sMessage ) ) return TRUE;        // General spam filter (if enabled)
01470 
01471         // Check chat settings.
01472         if ( Settings.Community.ChatEnable && Settings.Community.ChatAllNetworks )      
01473         {       
01474                 // Chat is enabled, open/update a chat window
01475                 ChatCore.OnED2KMessage( this, pPacket );
01476         }
01477         else
01478         {       
01479                 // Chat is disabled- don't open a chat window. Display in system window instead.
01480                 theApp.Message( MSG_DEFAULT, _T("Message from %s: %s"), (LPCTSTR)m_sAddress, sMessage );
01481         }
01482         return TRUE;
01483 }
01484 
01486 // CEDClient source request
01487 
01488 BOOL CEDClient::OnSourceRequest(CEDPacket* pPacket)
01489 {
01490         if ( pPacket->GetRemaining() < sizeof(MD4) )
01491         {
01492                 theApp.Message( MSG_ERROR, IDS_ED2K_CLIENT_BAD_PACKET, (LPCTSTR)m_sAddress, pPacket->m_nType );
01493                 return TRUE;
01494         }
01495         
01496         MD4 pHash;
01497         pPacket->Read( &pHash, sizeof(MD4) );
01498         
01499         CEDPacket* pReply = CEDPacket::New( ED2K_C2C_ANSWERSOURCES, ED2K_PROTOCOL_EMULE );
01500         int nCount = 0;
01501         
01502         if ( CDownload* pDownload = Downloads.FindByED2K( &pHash, TRUE ))
01503         {
01504                 for ( CDownloadSource* pSource = pDownload->GetFirstSource() ; pSource ; pSource = pSource->m_pNext )
01505                 {
01506                         if ( pSource->m_nProtocol == PROTOCOL_ED2K && pSource->m_bReadContent )
01507                         {
01508                                 pReply->WriteLongLE( pSource->m_pAddress.S_un.S_addr );
01509                                 pReply->WriteShortLE( pSource->m_nPort );
01510                                 pReply->WriteLongLE( pSource->m_pServerAddress.S_un.S_addr );
01511                                 pReply->WriteShortLE( (WORD)pSource->m_nServerPort );
01512                                 if ( m_bEmSources >= 2 ) pReply->Write( &pSource->m_pGUID, sizeof(GGUID) );
01513                                 nCount++;
01514                         }
01515                 }
01516         }
01517         
01518         if ( pReply->m_nLength > 0 )
01519         {
01520                 BYTE* pStart = pReply->WriteGetPointer( sizeof(MD4) + 2, 0 );
01521                 CopyMemory( pStart, &pHash, sizeof(MD4) );
01522                 pStart += sizeof(MD4);
01523                 *(WORD*)pStart = nCount;
01524                 Send( pReply, FALSE );
01525         }
01526         
01527         pReply->Release();
01528         
01529         return TRUE;
01530 }
01531 
01533 // CEDClient source answer
01534 
01535 BOOL CEDClient::OnSourceAnswer(CEDPacket* pPacket)
01536 {
01537         if ( Settings.Library.SourceMesh == FALSE ) return TRUE;
01538         
01539         if ( pPacket->GetRemaining() < sizeof(MD4) + 2 )
01540         {
01541                 theApp.Message( MSG_ERROR, IDS_ED2K_CLIENT_BAD_PACKET, (LPCTSTR)m_sAddress, pPacket->m_nType );
01542                 return TRUE;
01543         }
01544         
01545         MD4 pHash;
01546         pPacket->Read( &pHash, sizeof(MD4) );
01547         int nCount = pPacket->ReadShortLE();
01548         
01549         if ( pPacket->GetRemaining() < nCount * ( m_bEmSources >= 2 ? 12+16 : 12 ) )
01550         {
01551                 theApp.Message( MSG_ERROR, IDS_ED2K_CLIENT_BAD_PACKET, (LPCTSTR)m_sAddress, pPacket->m_nType );
01552                 return TRUE;
01553         }
01554         
01555         if ( CDownload* pDownload = Downloads.FindByED2K( &pHash ))
01556         {
01557                 // Don't bother adding sources if this download has finished
01558                 if ( pDownload->IsMoving() ) return TRUE;
01559 
01560                 while ( nCount-- > 0 )
01561                 {
01562                         GGUID pGUID;
01563                         
01564                         DWORD nClientID         = pPacket->ReadLongLE();
01565                         WORD nClientPort        = pPacket->ReadShortLE();
01566                         DWORD nServerIP         = pPacket->ReadLongLE();
01567                         WORD nServerPort        = pPacket->ReadShortLE();
01568                         
01569                         if ( m_bEmSources >= 2 )
01570                         {
01571                                 pPacket->Read( &pGUID, sizeof(GGUID) );
01572                                 pDownload->AddSourceED2K( nClientID, nClientPort, nServerIP, nServerPort, &pGUID );
01573                         }
01574                         else
01575                         {
01576                                 pDownload->AddSourceED2K( nClientID, nClientPort, nServerIP, nServerPort );
01577                         }
01578                 }
01579         }       
01580         
01581         return TRUE;
01582 }
01583 
01585 // CEDClient source URL utility
01586 
01587 CString CEDClient::GetSourceURL()
01588 {
01589         ASSERT( m_bGUID );
01590         ASSERT( m_bUpMD4 );
01591         
01592         CString str;
01593 
01594         if ( CEDPacket::IsLowID( m_nClientID ) )
01595         {
01596                 str.Format( _T("ed2kftp://%lu@%s:%i/%s/%I64i/"),
01597                         m_nClientID,
01598                         (LPCTSTR)CString( inet_ntoa( m_pHost.sin_addr ) ),
01599                         htons( m_pHost.sin_port ),
01600                         (LPCTSTR)CED2K::HashToString( &m_pUpMD4 ), m_nUpSize );
01601         }
01602         else
01603         {
01604                 str.Format( _T("ed2kftp://%s:%lu/%s/%I64i/"),
01605                         (LPCTSTR)CString( inet_ntoa( m_pHost.sin_addr ) ),
01606                         htons( m_pHost.sin_port ),
01607                         (LPCTSTR)CED2K::HashToString( &m_pUpMD4 ), m_nUpSize );
01608         }
01609         
01610         return str;
01611 }
01612 
01614 // CEDClient part status utility
01615 
01616 void CEDClient::WritePartStatus(CEDPacket* pPacket, CDownload* pDownload)
01617 {
01618         QWORD nParts = ( pDownload->m_nSize + ED2K_PART_SIZE - 1 ) / ED2K_PART_SIZE;
01619         pPacket->WriteShortLE( (WORD)nParts );
01620         
01621         if ( pDownload->m_pHashsetBlock != NULL && pDownload->m_nHashsetBlock == nParts )
01622         {
01623                 for ( QWORD nPart = 0 ; nPart < nParts ; )
01624                 {
01625                         BYTE nByte = 0;
01626                         
01627                         for ( DWORD nBit = 0 ; nBit < 8 && nPart < nParts ; nBit++, nPart++ )
01628                         {
01629                                 if ( pDownload->m_pHashsetBlock[ nPart ] == TS_TRUE )
01630                                 {
01631                                         nByte |= ( 1 << nBit );
01632                                 }
01633                         }
01634                         
01635                         pPacket->WriteByte( nByte );
01636                 }
01637         }
01638         else
01639         {
01640                 for ( QWORD nPart = 0 ; nPart < nParts ; )
01641                 {
01642                         BYTE nByte = 0;
01643                         
01644                         for ( DWORD nBit = 0 ; nBit < 8 && nPart < nParts ; nBit++, nPart++ )
01645                         {
01646                                 QWORD nOffset = nPart * ED2K_PART_SIZE;
01647                                 QWORD nLength = min( QWORD(ED2K_PART_SIZE), pDownload->m_nSize - nOffset );
01648                                 
01649                                 if ( pDownload->IsRangeUseful( nOffset, nLength ) == FALSE )
01650                                 {
01651                                         nByte |= ( 1 << nBit );
01652                                 }
01653                         }
01654                         
01655                         pPacket->WriteByte( nByte );
01656                 }
01657         }
01658 }
01659 
01661 // CEDClient UDP packet handlers
01662 
01663 BOOL CEDClient::OnUdpReask(CEDPacket* pPacket)
01664 {
01665         if ( pPacket->GetRemaining() < sizeof(MD4) ) return FALSE;
01666         if ( m_bUpMD4 == FALSE || m_pUpload == NULL ) return FALSE;
01667         
01668         MD4 pMD4;
01669         pPacket->Read( &pMD4, sizeof(MD4) );
01670         if ( pMD4 != m_pUpMD4 ) return FALSE;
01671         
01672         return m_pUpload->OnReask();
01673 }
01674 
01675 BOOL CEDClient::OnUdpReaskAck(CEDPacket* pPacket)
01676 {
01677         if ( pPacket->GetRemaining() < 2 ) return FALSE;
01678         if ( m_pDownload == NULL ) return FALSE;
01679         
01680         int nRank = pPacket->ReadShortLE();
01681         m_pDownload->SetQueueRank( nRank );
01682         
01683         return TRUE;
01684 }
01685 
01686 BOOL CEDClient::OnUdpQueueFull(CEDPacket* pPacket)
01687 {
01688         if ( m_pDownload != NULL )
01689         {
01690                 m_pDownload->m_pSource->m_tAttempt = GetTickCount() + Settings.eDonkey.ReAskTime * 1000;
01691                 m_pDownload->Close( TS_UNKNOWN );
01692         }
01693         
01694         return TRUE;
01695 }
01696 
01697 BOOL CEDClient::OnUdpFileNotFound(CEDPacket* pPacket)
01698 {
01699         if ( m_pDownload != NULL ) m_pDownload->Close( TS_FALSE );
01700         return TRUE;
01701 }

Generated on Thu Dec 15 10:39:41 2005 for Shareaza 2.2.1.0 by  doxygen 1.4.2