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 "GProfile.h"
00030 #include "G2Packet.h"
00031 #include "EDPacket.h"
00032 #include "EDClient.h"
00033 #include "EDClients.h"
00034 #include "Transfers.h"
00035 #include "Network.h"
00036 #include "Buffer.h"
00037 #include "XML.h"
00038
00039 #include "ChatCore.h"
00040 #include "ChatSession.h"
00041
00042 #include "ChatWindows.h"
00043 #include "CtrlChatFrame.h"
00044 #include "CtrlPrivateChatFrame.h"
00045
00046
00047 typedef unsigned int UINT_PTR;
00048 #include <mmsystem.h>
00049
00050 #ifdef _DEBUG
00051 #undef THIS_FILE
00052 static char THIS_FILE[]=__FILE__;
00053 #define new DEBUG_NEW
00054 #endif
00055
00056
00058
00059
00060 CChatSession::CChatSession(CChatFrame* pFrame)
00061 {
00062 m_bGUID = FALSE;
00063
00064 m_nState = cssNull;
00065 m_nProtocol = PROTOCOL_NULL;
00066 m_bOld = FALSE;
00067 m_bMustPush = FALSE;
00068 m_tPushed = 0;
00069 m_pProfile = NULL;
00070
00071 m_pWndPrivate = NULL;
00072 m_pWndPublic = NULL;
00073
00074 m_bUnicode = FALSE;
00075 m_nClientID = 0;
00076 m_pServer.sin_addr.S_un.S_addr = 0;
00077 m_pServer.sin_port = 0;
00078
00079 if ( pFrame != NULL )
00080 {
00081 m_pWndPrivate = ( pFrame->IsKindOf( RUNTIME_CLASS(CPrivateChatFrame) ) )
00082 ? reinterpret_cast<CPrivateChatFrame*>(pFrame) : NULL;
00083
00084
00085 }
00086
00087 ChatCore.Add( this );
00088 }
00089
00090 CChatSession::~CChatSession()
00091 {
00092 ASSERT( m_hSocket == INVALID_SOCKET );
00093
00094 if ( m_pProfile != NULL ) delete m_pProfile;
00095
00096 ChatCore.Remove( this );
00097 }
00098
00100
00101
00102 void CChatSession::Setup(GGUID* pGUID, SOCKADDR_IN* pHost, BOOL bMustPush)
00103 {
00104 CSingleLock pLock( &ChatCore.m_pSection, TRUE );
00105
00106 if ( pGUID != NULL )
00107 {
00108 m_bGUID = TRUE;
00109 m_pGUID = *pGUID;
00110 }
00111
00112 m_pHost = *pHost;
00113 m_bMustPush = bMustPush;
00114
00115 m_sUserNick = inet_ntoa( m_pHost.sin_addr );
00116 }
00117
00119
00120
00121 BOOL CChatSession::Connect()
00122 {
00123 CSingleLock pLock1( &ChatCore.m_pSection, TRUE );
00124
00125
00126 if ( m_nProtocol == PROTOCOL_ED2K )
00127 {
00128 return TRUE;
00129 }
00130
00131
00132
00133 if ( m_nState > cssNull ) return FALSE;
00134
00135 if ( m_bMustPush )
00136 {
00137 if ( ! SendPush( FALSE ) )
00138 {
00139 StatusMessage( 1, IDS_CHAT_CANT_PUSH, (LPCTSTR)CString( inet_ntoa( m_pHost.sin_addr ) ) );
00140 return FALSE;
00141 }
00142 }
00143 else
00144 {
00145 if ( CConnection::ConnectTo( &m_pHost ) )
00146 {
00147 ChatCore.Add( this );
00148 StatusMessage( 0, IDS_CHAT_CONNECTING_TO, (LPCTSTR)m_sAddress );
00149 }
00150 else
00151 {
00152 StatusMessage( 1, IDS_CHAT_CANT_CONNECT, (LPCTSTR)m_sAddress );
00153 return FALSE;
00154 }
00155 }
00156
00157 m_nState = cssConnecting;
00158
00159 return TRUE;
00160 }
00161
00162 TRISTATE CChatSession::GetConnectedState() const
00163 {
00164 if ( m_nState == cssNull ) return TS_FALSE;
00165 if ( m_nState == cssActive ) return TS_TRUE;
00166 return TS_UNKNOWN;
00167 }
00168
00170
00171
00172 void CChatSession::OnED2KMessage(CEDPacket* pPacket)
00173 {
00174 CSingleLock pLock( &ChatCore.m_pSection, TRUE );
00175
00176
00177 PostOpenWindow();
00178
00179
00180 if ( pPacket && m_pInput ) pPacket->ToBuffer( m_pInput );
00181
00182
00183 if ( m_nState != cssActive )
00184 {
00185 StatusMessage( 2, IDS_CHAT_PRIVATE_ONLINE, (LPCTSTR)m_sUserNick );
00186 m_nState = cssActive;
00187 m_tConnected = GetTickCount();
00188 }
00189 }
00190
00192
00193
00194 void CChatSession::AttachTo(CConnection* pConnection)
00195 {
00196 CConnection::AttachTo( pConnection );
00197
00198 m_nState = cssRequest1;
00199 ChatCore.Add( this );
00200 }
00201
00203
00204
00205 BOOL CChatSession::SendPush(BOOL bAutomatic)
00206 {
00207 if ( ! m_bGUID ) return FALSE;
00208
00209 if ( m_nProtocol == PROTOCOL_ED2K ) return FALSE;
00210
00211 if ( Network.SendPush( &m_pGUID, 0 ) )
00212 {
00213 m_nState = cssNull;
00214 CConnection::Close();
00215
00216 m_tConnected = m_tPushed = GetTickCount();
00217 StatusMessage( 0, IDS_CHAT_PUSH_SENT, (LPCTSTR)CString( inet_ntoa( m_pHost.sin_addr ) ) );
00218
00219 return TRUE;
00220 }
00221 else
00222 {
00223 return FALSE;
00224 }
00225 }
00226
00227 BOOL CChatSession::OnPush(GGUID* pGUID, CConnection* pConnection)
00228 {
00229 if ( m_tPushed == 0 ) return FALSE;
00230 if ( ! m_bGUID || m_pGUID != *pGUID ) return FALSE;
00231 if ( m_nState > cssConnecting ) return FALSE;
00232 if ( m_nProtocol == PROTOCOL_ED2K ) return FALSE;
00233
00234 if ( m_nState > cssNull ) Close();
00235
00236 CConnection::AttachTo( pConnection );
00237
00238 StatusMessage( 0, IDS_CHAT_PUSH_DONE, (LPCTSTR)m_sAddress );
00239 ChatCore.Add( this );
00240 OnConnected();
00241
00242 return TRUE;
00243 }
00244
00246
00247
00248 void CChatSession::Close()
00249 {
00250
00251 if ( m_nProtocol == PROTOCOL_ED2K ) return;
00252
00253 CSingleLock pLock( &ChatCore.m_pSection );
00254 pLock.Lock( 250 );
00255
00256 if ( m_nState != cssNull )
00257 {
00258 m_nState = cssNull;
00259 StatusMessage( 0, IDS_CHAT_CLOSED );
00260 StatusMessage( 0, 0 );
00261 }
00262
00263 CConnection::Close();
00264
00265 if ( m_pWndPrivate == NULL && m_pWndPublic == NULL ) delete this;
00266 }
00267
00269
00270
00271 BOOL CChatSession::OnConnected()
00272 {
00273 StatusMessage( 0, IDS_CHAT_CONNECTED );
00274
00275 if ( m_nProtocol == PROTOCOL_ED2K )
00276 {
00277
00278 }
00279 else
00280 {
00281 CConnection::OnConnected();
00282
00283 m_pOutput->Print( "CHAT CONNECT/0.2\r\n" );
00284 m_pOutput->Print( "Accept: text/plain,application/x-gnutella2\r\n" );
00285 m_pOutput->Print( "User-Agent: " );
00286 m_pOutput->Print( Settings.SmartAgent() );
00287 m_pOutput->Print( "\r\n" );
00288 if ( m_bInitiated ) SendMyAddress();
00289 m_pOutput->Print( "\r\n" );
00290
00291 m_nState = cssRequest2;
00292 m_tConnected = GetTickCount();
00293
00294 OnWrite();
00295 }
00296
00297 return TRUE;
00298 }
00299
00301
00302
00303 void CChatSession::OnDropped(BOOL bError)
00304 {
00305 if ( m_hSocket == INVALID_SOCKET ) return;
00306
00307 if ( m_nState == cssConnecting )
00308 {
00309 StatusMessage( 1, IDS_CHAT_CANT_CONNECT, (LPCTSTR)m_sAddress );
00310 if ( m_tPushed == 0 && SendPush( TRUE ) ) return;
00311 }
00312 else
00313 {
00314 StatusMessage( 1, IDS_CHAT_DROPPED, (LPCTSTR)m_sAddress );
00315 }
00316
00317 Close();
00318 }
00319
00321
00322
00323 BOOL CChatSession::OnRun()
00324 {
00325 if ( m_nProtocol == PROTOCOL_ED2K )
00326 {
00327
00328
00329 return ( ReadPacketsED2K() && SendPacketsED2K() );
00330 }
00331 else if ( m_nState > cssNull && m_nState < cssActive )
00332 {
00333 DWORD nDelay = GetTickCount() - m_tConnected;
00334
00335 if ( nDelay >= ( m_nState == cssConnecting ?
00336 Settings.Connection.TimeoutConnect : Settings.Connection.TimeoutHandshake ) )
00337 {
00338 theApp.Message( MSG_ERROR, IDS_HANDSHAKE_TIMEOUT, (LPCTSTR)m_sAddress );
00339 Close();
00340 return FALSE;
00341 }
00342 }
00343
00344 return TRUE;
00345 }
00346
00348
00349
00350 BOOL CChatSession::OnRead()
00351 {
00352
00353 if ( m_nProtocol == PROTOCOL_ED2K ) return TRUE;
00354
00355 CConnection::OnRead();
00356
00357 switch ( m_nState )
00358 {
00359 case cssRequest1:
00360 case cssRequest2:
00361 case cssRequest3:
00362 return ReadHandshake();
00363 case cssHeaders1:
00364 case cssHeaders2:
00365 case cssHeaders3:
00366 return ReadHeaders();
00367 case cssHandshake:
00368 case cssActive:
00369 if ( m_nProtocol == PROTOCOL_G2 )
00370 return ReadPackets();
00371 else
00372 return ReadText();
00373 }
00374
00375 return TRUE;
00376 }
00377
00379
00380
00381 BOOL CChatSession::ReadHandshake()
00382 {
00383 CString strLine;
00384
00385 if ( ! m_pInput->ReadLine( strLine ) ) return TRUE;
00386 if ( strLine.IsEmpty() ) return TRUE;
00387
00388 theApp.Message( MSG_DEBUG, _T("CHAT HANDSHAKE: %s: %s"),
00389 (LPCTSTR)m_sAddress, (LPCTSTR)strLine );
00390
00391 m_bOld = strLine.Find( _T("/0.1") ) > 0;
00392
00393 if ( StartsWith( strLine, _T("CHAT CONNECT/") ) && m_nState == cssRequest1 )
00394 {
00395 m_nState = cssHeaders1;
00396 return TRUE;
00397 }
00398 else if ( StartsWith( strLine, _T("CHAT/") ) )
00399 {
00400 if ( _tcsistr( strLine, _T("200 OK") ) )
00401 {
00402 if ( m_nState == cssRequest2 )
00403 {
00404 m_nState = cssHeaders2;
00405 return TRUE;
00406 }
00407 else if ( m_nState == cssRequest3 )
00408 {
00409 m_nState = cssHeaders3;
00410 return TRUE;
00411 }
00412 }
00413 else
00414 {
00415
00416 }
00417 }
00418
00419 StatusMessage( 1, IDS_CHAT_PRIVATE_REFUSED, (LPCTSTR)m_sAddress );
00420 Close();
00421
00422 return FALSE;
00423 }
00424
00426
00427
00428 BOOL CChatSession::OnHeaderLine(CString& strHeader, CString& strValue)
00429 {
00430 ASSERT ( m_nProtocol != PROTOCOL_ED2K );
00431
00432 theApp.Message( MSG_DEBUG, _T("CHAT HEADER: %s: %s: %s"),
00433 (LPCTSTR)m_sAddress, (LPCTSTR)strHeader, (LPCTSTR)strValue );
00434
00435 if ( strHeader.CompareNoCase( _T("User-Agent") ) == 0 )
00436 {
00437 m_sUserAgent = strValue;
00438 }
00439 else if ( strHeader.CompareNoCase( _T("Accept") ) == 0 )
00440 {
00441 if ( strValue.Find( _T("application/x-gnutella2") ) >= 0 )
00442 m_nProtocol = PROTOCOL_G2;
00443 }
00444 else if ( strHeader.CompareNoCase( _T("X-Nickname") ) == 0 )
00445 {
00446 m_sUserNick = strValue;
00447 }
00448 else if ( strHeader.CompareNoCase( _T("X-My-Address") ) == 0 ||
00449 strHeader.CompareNoCase( _T("Listen-IP") ) == 0 ||
00450 strHeader.CompareNoCase( _T("X-Node") ) == 0 ||
00451 strHeader.CompareNoCase( _T("Node") ) == 0 )
00452 {
00453 int nColon = strValue.Find( ':' );
00454
00455 if ( ! m_bInitiated && nColon > 0 )
00456 {
00457 int nPort = GNUTELLA_DEFAULT_PORT;
00458
00459 if ( _stscanf( strValue.Mid( nColon + 1 ), _T("%i"), &nPort ) == 1 && nPort != 0 )
00460 {
00461 m_pHost.sin_port = htons( nPort );
00462 }
00463 }
00464 }
00465
00466 return TRUE;
00467 }
00468
00469 BOOL CChatSession::OnHeadersComplete()
00470 {
00471 if ( m_nState != cssHeaders3 )
00472 {
00473 m_pOutput->Print( "CHAT/0.2 200 OK\r\n" );
00474
00475 if ( m_nProtocol == PROTOCOL_G2 )
00476 {
00477 m_pOutput->Print( "Accept: application/x-gnutella2\r\n" );
00478 m_pOutput->Print( "Content-Type: application/x-gnutella2\r\n" );
00479 }
00480 else if ( MyProfile.IsValid() )
00481 {
00482 m_pOutput->Print( "X-Nickname: " );
00483 m_pOutput->Print( MyProfile.GetNick().Left( 255 ) );
00484 m_pOutput->Print( "\r\n" );
00485 }
00486
00487 m_pOutput->Print( "User-Agent: " );
00488 m_pOutput->Print( Settings.SmartAgent() );
00489 m_pOutput->Print( "\r\n" );
00490 m_pOutput->Print( "\r\n" );
00491
00492 OnWrite();
00493 }
00494
00495 if ( m_nState == cssHeaders1 )
00496 {
00497
00498 m_nState = cssRequest3;
00499 return TRUE;
00500 }
00501 else if ( m_nState == cssHeaders2 )
00502 {
00503
00504 m_nState = cssHandshake;
00505 return OnEstablished();
00506 }
00507 else if ( m_nState == cssHeaders3 )
00508 {
00509
00510 m_nState = cssHandshake;
00511 return OnEstablished();
00512 }
00513
00514 ASSERT( FALSE );
00515 return FALSE;
00516 }
00517
00519
00520
00521 BOOL CChatSession::OnEstablished()
00522 {
00523 ASSERT ( m_nProtocol != PROTOCOL_ED2K );
00524
00525 m_tConnected = GetTickCount();
00526
00527 if ( m_nProtocol == PROTOCOL_G2 )
00528 {
00529 StatusMessage( 0, IDS_CHAT_HANDSHAKE_G2 );
00530 Send( CG2Packet::New( G2_PACKET_PROFILE_CHALLENGE ) );
00531 }
00532 else
00533 {
00534 m_nState = cssActive;
00535 StatusMessage( 2, IDS_CHAT_HANDSHAKE_G1, m_bOld ? _T("0.1") : _T("0.2") );
00536 if ( m_pWndPrivate != NULL ) m_pWndPrivate->OnProfileReceived();
00537 StatusMessage( 0, 0 );
00538 PostOpenWindow();
00539 }
00540
00541 return TRUE;
00542 }
00543
00545
00546
00547
00548
00549
00550
00551 BOOL CChatSession::ReadPacketsED2K()
00552 {
00553 BOOL bSuccess = TRUE;
00554 CEDPacket* pPacket;
00555
00556 ASSERT( m_pInput != NULL );
00557
00558 while ( pPacket = CEDPacket::ReadBuffer( m_pInput, ED2K_PROTOCOL_EMULE ) )
00559 {
00560 try
00561 {
00562
00563
00564 if ( ( pPacket->m_nEdProtocol == ED2K_PROTOCOL_EDONKEY ) &&
00565 ( pPacket->m_nType == ED2K_C2C_MESSAGE ) )
00566 {
00567 bSuccess = OnChatMessage( pPacket );
00568 }
00569 else
00570 {
00571 CString str;
00572 str.Format( _T("Unrecognised packet - IP: %s - protocol: 0x%x - opcode: 0x%x - in CChatSession::ReadPacketsED2K"), int( pPacket->m_nEdProtocol ), int( pPacket->m_nType ) );
00573 LPCTSTR( m_sAddress ),
00574 theApp.Message( MSG_ERROR, LPCTSTR( str ) );
00575 }
00576 }
00577 catch ( CException* pException )
00578 {
00579 pException->Delete();
00580 if ( ! m_bGUID ) bSuccess = FALSE;
00581 }
00582
00583 pPacket->Release();
00584 if ( ! bSuccess ) break;
00585 }
00586
00587 return bSuccess;
00588 }
00589
00590 BOOL CChatSession::SendPacketsED2K()
00591 {
00592 CEDPacket* pPacket;
00593
00594 ASSERT( m_pOutput != NULL );
00595
00596 while ( pPacket = CEDPacket::ReadBuffer( m_pOutput, ED2K_PROTOCOL_EMULE ) )
00597 {
00598 ASSERT ( pPacket != NULL );
00599
00600
00601 if ( SendChatMessage ( pPacket ) )
00602 {
00603
00604
00605 pPacket->Release();
00606 }
00607 else
00608 {
00609
00610
00611
00612
00613 pPacket->ToBuffer( m_pOutput );
00614
00615 pPacket->Release();
00616
00617 return TRUE;
00618 }
00619 }
00620
00621 return TRUE;
00622 }
00623
00625
00626
00627 BOOL CChatSession::SendChatMessage(CEDPacket* pPacket)
00628 {
00629
00630 CSingleLock pLock( &Transfers.m_pSection );
00631 if ( ! pLock.Lock( 250 ) ) return FALSE;
00632
00633
00634 CEDClient* pClient = EDClients.GetByIP( &m_pHost.sin_addr );
00635
00636 if ( ( pClient ) && ( pClient->m_pGUID == m_pGUID ) )
00637 {
00638
00639 if ( pClient->IsOnline() )
00640 {
00641
00642
00643 if ( m_nState != cssActive )
00644 {
00645 StatusMessage( 2, IDS_CHAT_PRIVATE_ONLINE, (LPCTSTR)m_sUserNick );
00646 m_nState = cssActive;
00647 m_tConnected = GetTickCount();
00648 }
00649
00650
00651 pClient->Send ( pPacket, FALSE );
00652 return TRUE;
00653 }
00654 else if ( ( m_nState != cssConnecting ) && ( pClient->Connect() ) )
00655 {
00656
00657 m_nState = cssConnecting;
00658 m_tConnected = GetTickCount();
00659 StatusMessage( 0, IDS_CHAT_CONNECTING_TO, (LPCTSTR)pClient->m_sAddress );
00660
00661 return FALSE;
00662 }
00663 else
00664 {
00665
00666 if ( m_nState == cssConnecting )
00667 {
00668
00669 if ( ( GetTickCount() - m_tConnected ) >= Settings.Connection.TimeoutConnect )
00670 {
00671
00672 StatusMessage( 1, IDS_CHAT_CANT_CONNECT, (LPCTSTR)pClient->m_sAddress );
00673 m_nState = cssNull;
00674 return TRUE;
00675 }
00676 else
00677 {
00678
00679 return FALSE;
00680 }
00681 }
00682 else
00683 {
00684
00685 StatusMessage( 1, IDS_CHAT_CANT_CONNECT, (LPCTSTR)pClient->m_sAddress );
00686 m_nState = cssNull;
00687 return TRUE;
00688 }
00689 }
00690 }
00691 else
00692 {
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718
00719
00720
00721
00722
00723
00724 StatusMessage( 1, IDS_CHAT_DROPPED );
00725 m_nState = cssNull;
00726 return TRUE;
00727 }
00728 }
00729
00730 BOOL CChatSession::OnChatMessage(CEDPacket* pPacket)
00731 {
00732 DWORD nMessageLength;
00733 CString sMessage;
00734
00735
00736
00737
00738 nMessageLength = pPacket->ReadShortLE();
00739
00740
00741 if ( m_bUnicode )
00742 sMessage = pPacket->ReadStringUTF8( nMessageLength );
00743 else
00744 sMessage = pPacket->ReadString( nMessageLength );
00745
00746
00747 if ( m_pWndPrivate != NULL ) m_pWndPrivate->OnRemoteMessage( FALSE, sMessage.GetBuffer() );
00748 return TRUE;
00749 }
00750
00752
00753
00754 void CChatSession::Print(LPCTSTR pszString)
00755 {
00756 ASSERT( m_nProtocol != PROTOCOL_G2 );
00757 ASSERT( m_nState >= cssHandshake );
00758
00759 m_pOutput->Print( pszString );
00760 OnWrite();
00761 }
00762
00763 BOOL CChatSession::ReadText()
00764 {
00765 CString strLine;
00766
00767 while ( m_pInput->ReadLine( strLine ) )
00768 {
00769 if ( ! OnText( strLine ) )
00770 {
00771 Close();
00772 return FALSE;
00773 }
00774 }
00775
00776 return TRUE;
00777 }
00778
00779 BOOL CChatSession::OnText(const CString& str)
00780 {
00781 if ( m_pWndPrivate == NULL ) return TRUE;
00782
00783 if ( m_bOld )
00784 {
00785 if ( StartsWith( str, _T("\001ACTION ") ) )
00786 {
00787 m_pWndPrivate->OnRemoteMessage( TRUE, str.Mid( 8 ) );
00788 }
00789 else
00790 {
00791 m_pWndPrivate->OnRemoteMessage( FALSE, str );
00792 }
00793 }
00794 else if ( StartsWith( str, _T("MESSAGE ") ) )
00795 {
00796 if ( StartsWith( str, _T("MESSAGE \001ACTION ") ) )
00797 {
00798 m_pWndPrivate->OnRemoteMessage( TRUE, str.Mid( 16 ) );
00799 }
00800 else
00801 {
00802 m_pWndPrivate->OnRemoteMessage( FALSE, str.Mid( 8 ) );
00803 }
00804 }
00805 else if ( StartsWith( str, _T("NICK ") ) )
00806 {
00807
00808 }
00809
00810 return TRUE;
00811 }
00812
00814
00815
00816 void CChatSession::Send(CG2Packet* pPacket, BOOL bRelease)
00817 {
00818 ASSERT( m_nProtocol == PROTOCOL_G2 );
00819 ASSERT( pPacket != NULL );
00820 ASSERT( m_nState >= cssHandshake );
00821
00822 pPacket->ToBuffer( m_pOutput );
00823 if ( bRelease ) pPacket->Release();
00824
00825 OnWrite();
00826 }
00827
00828 BOOL CChatSession::ReadPackets()
00829 {
00830 BOOL bSuccess = TRUE;
00831 for ( ; bSuccess && m_pInput->m_nLength ; )
00832 {
00833 BYTE nInput = *( m_pInput->m_pBuffer );
00834
00835 if ( nInput == 0 )
00836 {
00837 m_pInput->Remove( 1 );
00838 continue;
00839 }
00840
00841 BYTE nLenLen = ( nInput & 0xC0 ) >> 6;
00842 BYTE nTypeLen = ( nInput & 0x38 ) >> 3;
00843 BYTE nFlags = ( nInput & 0x07 );
00844
00845 if ( nLenLen == 0 )
00846 {
00847 Close();
00848 return FALSE;
00849 }
00850
00851 if ( (DWORD)m_pInput->m_nLength < (DWORD)nLenLen + nTypeLen + 2 ) break;
00852
00853 DWORD nLength = 0;
00854
00855 if ( nFlags & G2_FLAG_BIG_ENDIAN )
00856 {
00857 BYTE* pLenIn = m_pInput->m_pBuffer + 1;
00858
00859 for ( BYTE nIt = nLenLen ; nIt ; nIt-- )
00860 {
00861 nLength <<= 8;
00862 nLength |= *pLenIn++;
00863 }
00864 }
00865 else
00866 {
00867 BYTE* pLenIn = m_pInput->m_pBuffer + 1;
00868 BYTE* pLenOut = (BYTE*)&nLength;
00869 for ( BYTE nLenCnt = nLenLen ; nLenCnt-- ; ) *pLenOut++ = *pLenIn++;
00870 }
00871
00872 if ( nLength >= Settings.Gnutella1.MaximumPacket )
00873 {
00874 Close();
00875 return FALSE;
00876 }
00877
00878 if ( (DWORD)m_pInput->m_nLength < (DWORD)nLength + nLenLen + nTypeLen + 2 ) break;
00879
00880 CG2Packet* pPacket = CG2Packet::New( m_pInput->m_pBuffer );
00881
00882 m_pInput->Remove( nLength + nLenLen + nTypeLen + 2 );
00883
00884 try
00885 {
00886 bSuccess = OnPacket( pPacket );
00887 }
00888 catch ( CException* pException )
00889 {
00890 pException->Delete();
00891 bSuccess = TRUE;
00892 }
00893
00894 pPacket->Release();
00895 }
00896
00897 if ( ! bSuccess ) Close();
00898
00899 return bSuccess;
00900 }
00901
00903
00904
00905 BOOL CChatSession::OnPacket(CG2Packet* pPacket)
00906 {
00907 if ( pPacket->IsType( "CMSG" ) )
00908 {
00909 return OnChatMessage( pPacket );
00910 }
00911 else if ( pPacket->IsType( G2_PACKET_PROFILE_CHALLENGE ) )
00912 {
00913 return OnProfileChallenge( pPacket );
00914 }
00915 else if ( pPacket->IsType( G2_PACKET_PROFILE_DELIVERY ) )
00916 {
00917 return OnProfileDelivery( pPacket );
00918 }
00919 else if ( pPacket->IsType( "CHATREQ" ) )
00920 {
00921 return OnChatRequest( pPacket );
00922 }
00923 else if ( pPacket->IsType( "CHATANS" ) )
00924 {
00925 return OnChatAnswer( pPacket );
00926 }
00927
00928 return TRUE;
00929 }
00930
00931 BOOL CChatSession::OnProfileChallenge(CG2Packet* pPacket)
00932 {
00933 if ( ! MyProfile.IsValid() ) return TRUE;
00934
00935 CG2Packet* pProfile = CG2Packet::New( G2_PACKET_PROFILE_DELIVERY, TRUE );
00936 CString strXML = MyProfile.GetXML( NULL, TRUE )->ToString( TRUE );
00937
00938 pProfile->WritePacket( "XML", pProfile->GetStringLen( strXML ) );
00939 pProfile->WriteString( strXML, FALSE );
00940
00941 Send( pProfile, TRUE );
00942
00943 return TRUE;
00944 }
00945
00946 BOOL CChatSession::OnProfileDelivery(CG2Packet* pPacket)
00947 {
00948 if ( ! pPacket->m_bCompound ) return TRUE;
00949
00950 if ( m_pProfile != NULL ) delete m_pProfile;
00951 m_pProfile = NULL;
00952
00953 CHAR szType[9];
00954 DWORD nLength;
00955
00956 while ( pPacket->ReadPacket( szType, nLength ) )
00957 {
00958 DWORD nOffset = pPacket->m_nPosition + nLength;
00959
00960 if ( strcmp( szType, "XML" ) == 0 )
00961 {
00962 CXMLElement* pXML = CXMLElement::FromString( pPacket->ReadString( nLength ), TRUE );
00963
00964 if ( pXML != NULL )
00965 {
00966 m_pProfile = new CGProfile();
00967
00968 if ( ! m_pProfile->FromXML( pXML ) || ! m_pProfile->IsValid() )
00969 {
00970 delete pXML;
00971 delete m_pProfile;
00972 m_pProfile = NULL;
00973 }
00974 }
00975 }
00976
00977 pPacket->m_nPosition = nOffset;
00978 }
00979
00980 if ( m_pProfile == NULL ) return TRUE;
00981
00982 m_sUserNick = m_pProfile->GetNick();
00983
00984 if ( m_bGUID )
00985 {
00986 if ( m_pGUID != m_pProfile->GUID )
00987 {
00988
00989 m_pGUID = m_pProfile->GUID;
00990 }
00991 }
00992 else
00993 {
00994 m_bGUID = TRUE;
00995 m_pGUID = m_pProfile->GUID;
00996 }
00997
00998 if ( m_pWndPrivate != NULL )
00999 {
01000 m_pWndPrivate->OnProfileReceived();
01001
01002 CG2Packet* pPacket = CG2Packet::New( "CHATREQ", TRUE );
01003 pPacket->WritePacket( "USERGUID", 16 );
01004 pPacket->Write( &m_pGUID, 16 );
01005
01006 Send( pPacket, TRUE );
01007 }
01008
01009 return TRUE;
01010 }
01011
01012 BOOL CChatSession::OnChatRequest(CG2Packet* pPacket)
01013 {
01014 if ( ! pPacket->m_bCompound ) return TRUE;
01015
01016 BOOL bGUID = FALSE;
01017 GGUID pGUID;
01018
01019 CHAR szType[9];
01020 DWORD nLength;
01021
01022 while ( pPacket->ReadPacket( szType, nLength ) )
01023 {
01024 DWORD nOffset = pPacket->m_nPosition + nLength;
01025
01026 if ( strcmp( szType, "USERGUID" ) == 0 && nLength >= 16 )
01027 {
01028 pPacket->Read( &pGUID, 16 );
01029 bGUID = TRUE;
01030 }
01031
01032 pPacket->m_nPosition = nOffset;
01033 }
01034
01035 pPacket = CG2Packet::New( "CHATANS", TRUE );
01036
01037 pPacket->WritePacket( "USERGUID", 16 );
01038 GGUID tmp( MyProfile.GUID );
01039 pPacket->Write( &tmp, 16 );
01040
01041 if ( bGUID && pGUID == MyProfile.GUID )
01042 {
01043 pPacket->WritePacket( "ACCEPT", 0 );
01044 PostOpenWindow();
01045 }
01046 else
01047 {
01048 pPacket->WritePacket( "DENY", 0 );
01049 }
01050
01051 Send( pPacket, TRUE );
01052
01053 return TRUE;
01054 }
01055
01056 BOOL CChatSession::OnChatAnswer(CG2Packet* pPacket)
01057 {
01058 if ( ! pPacket->m_bCompound ) return TRUE;
01059
01060 CHAR szType[9];
01061 DWORD nLength;
01062
01063 while ( pPacket->ReadPacket( szType, nLength ) )
01064 {
01065 DWORD nOffset = pPacket->m_nPosition + nLength;
01066
01067 if ( strcmp( szType, "ACCEPT" ) == 0 )
01068 {
01069 m_nState = cssActive;
01070 StatusMessage( 2, IDS_CHAT_PRIVATE_ONLINE, (LPCTSTR)m_sUserNick );
01071 StatusMessage( 0, 0 );
01072 return TRUE;
01073 }
01074 else if ( strcmp( szType, "DENY" ) == 0 )
01075 {
01076 StatusMessage( 1, IDS_CHAT_PRIVATE_REFUSED, (LPCTSTR)m_sUserNick );
01077 }
01078 else if ( strcmp( szType, "AWAY" ) == 0 )
01079 {
01080 CString strAway = pPacket->ReadString( nLength );
01081 StatusMessage( 1, IDS_CHAT_PRIVATE_AWAY, (LPCTSTR)m_sUserNick,
01082 (LPCTSTR)strAway );
01083 }
01084
01085 pPacket->m_nPosition = nOffset;
01086 }
01087
01088 Close();
01089
01090 return FALSE;
01091 }
01092
01093 BOOL CChatSession::OnChatMessage(CG2Packet* pPacket)
01094 {
01095 if ( ! pPacket->m_bCompound ) return TRUE;
01096
01097 BOOL bAction = FALSE;
01098 CString strBody;
01099 CHAR szType[9];
01100 DWORD nLength;
01101
01102 while ( pPacket->ReadPacket( szType, nLength ) )
01103 {
01104 DWORD nOffset = pPacket->m_nPosition + nLength;
01105
01106 if ( strcmp( szType, "BODY" ) == 0 )
01107 {
01108 strBody = pPacket->ReadString( nLength );
01109 }
01110 else if ( strcmp( szType, "ACT" ) == 0 )
01111 {
01112 bAction = TRUE;
01113 }
01114
01115 pPacket->m_nPosition = nOffset;
01116 }
01117
01118 if ( strBody.IsEmpty() ) return TRUE;
01119
01120 if ( m_pWndPrivate != NULL ) m_pWndPrivate->OnRemoteMessage( bAction, strBody );
01121
01122 return TRUE;
01123 }
01124
01126
01127
01128 BOOL CChatSession::SendPrivateMessage(BOOL bAction, LPCTSTR pszText)
01129 {
01130 CSingleLock pLock( &ChatCore.m_pSection, TRUE );
01131
01132 if ( m_nState != cssActive ) return FALSE;
01133
01134 if ( m_nProtocol == PROTOCOL_G2 )
01135 {
01136 CG2Packet* pPacket = CG2Packet::New( "CMSG", TRUE );
01137
01138 if ( bAction ) pPacket->WritePacket( "ACT", 0 );
01139
01140 pPacket->WritePacket( "BODY", pPacket->GetStringLen( pszText ) );
01141 pPacket->WriteString( pszText, FALSE );
01142
01143 Send( pPacket, TRUE );
01144 }
01145 else if ( m_nProtocol == PROTOCOL_ED2K )
01146 {
01147
01148 CString strMessage = pszText;
01149 strMessage = strMessage.Left( ED2K_MESSAGE_MAX - 50 );
01150
01151
01152 CEDPacket* pPacket = CEDPacket::New( ED2K_C2C_MESSAGE, ED2K_PROTOCOL_EDONKEY );
01153
01154 if ( m_bUnicode )
01155 {
01156 pPacket->WriteShortLE( pPacket->GetStringLenUTF8( pszText ) );
01157 pPacket->WriteStringUTF8( pszText, FALSE );
01158 }
01159 else
01160 {
01161 pPacket->WriteShortLE( pPacket->GetStringLen( strMessage ) );
01162 pPacket->WriteString( strMessage, FALSE );
01163 }
01164
01165
01166 ASSERT( m_nProtocol == PROTOCOL_ED2K );
01167 ASSERT( pPacket != NULL );
01168 ASSERT( pPacket->m_nEdProtocol == ED2K_PROTOCOL_EDONKEY );
01169
01170
01171 pPacket->ToBuffer( m_pOutput );
01172 pPacket->Release();
01173 }
01174 else
01175 {
01176
01177 CString str;
01178
01179 if ( ! m_bOld ) str += _T("MESSAGE ");
01180 if ( bAction ) str += _T("\001ACTION ");
01181 str += pszText;
01182 str += _T("\r\n");
01183
01184 Print( str );
01185 }
01186
01187 return TRUE;
01188 }
01189
01191
01192
01193 void CChatSession::StatusMessage(int nFlags, UINT nID, ...)
01194 {
01195 CString strFormat;
01196 va_list pArgs;
01197
01198 if ( nID )
01199 LoadString( strFormat, nID );
01200 else
01201 strFormat = _T("-");
01202
01203 va_start( pArgs, nID );
01204
01205 if ( strFormat.Find( _T("%1") ) >= 0 )
01206 {
01207 LPTSTR lpszTemp;
01208 if ( ::FormatMessage( FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER,
01209 strFormat, 0, 0, (LPTSTR)&lpszTemp, 0, &pArgs ) != 0 && lpszTemp != NULL )
01210 {
01211 if ( m_pWndPrivate != NULL ) m_pWndPrivate->OnStatusMessage( nFlags, lpszTemp );
01212 LocalFree( lpszTemp );
01213 }
01214 }
01215 else
01216 {
01217 TCHAR szMessageBuffer[1024];
01218 _vsntprintf( szMessageBuffer, sizeof( szMessageBuffer ) / sizeof( TCHAR ), strFormat, pArgs );
01219 szMessageBuffer[ 1023 ] = 0;
01220 if ( m_pWndPrivate != NULL ) m_pWndPrivate->OnStatusMessage( nFlags, szMessageBuffer );
01221 }
01222
01223 va_end( pArgs );
01224 }
01225
01227
01228
01229 void CChatSession::PostOpenWindow()
01230 {
01231 if ( m_pWndPrivate != NULL || m_pWndPublic != NULL ) return;
01232
01233 if ( CWnd* pWnd = (CWnd*)theApp.SafeMainWnd() )
01234 {
01235 pWnd->PostMessage( WM_OPENCHAT, (WPARAM)this );
01236 }
01237 }
01238
01239 void CChatSession::OnOpenWindow()
01240 {
01241 ASSERT( m_pWndPrivate == NULL && m_pWndPublic == NULL );
01242
01243 if ( m_bGUID )
01244 {
01245 m_pWndPrivate = ChatWindows.FindPrivate( &m_pGUID );
01246 }
01247 else
01248 {
01249 m_pWndPrivate = ChatWindows.FindPrivate( &m_pHost.sin_addr );
01250 }
01251
01252 if ( ( m_pWndPrivate == NULL ) && ( m_nProtocol == PROTOCOL_ED2K ) )
01253 {
01254 if ( m_bMustPush )
01255 m_pWndPrivate = ChatWindows.FindED2KFrame( m_nClientID, &m_pServer );
01256 else
01257 m_pWndPrivate = ChatWindows.FindED2KFrame( &m_pHost );
01258 }
01259
01260 if ( m_pWndPrivate == NULL )
01261 {
01262 m_pWndPrivate = new CPrivateChatFrame();
01263 }
01264
01265 if ( ! m_pWndPrivate->Accept( this ) )
01266 {
01267 m_pWndPrivate = new CPrivateChatFrame();
01268 m_pWndPrivate->Accept( this );
01269 }
01270
01271 m_pWndPrivate->OnProfileReceived();
01272
01273 StatusMessage( 2, IDS_CHAT_PRIVATE_ONLINE, (LPCTSTR)m_sUserNick );
01274 StatusMessage( 0, 0 );
01275
01276 PlaySound( _T("RAZA_IncomingChat"), NULL, SND_APPLICATION|SND_ALIAS|SND_ASYNC );
01277
01278 m_nState = cssActive;
01279
01280
01281
01282 CWnd* pParent = m_pWndPrivate->GetParent();
01283 if ( pParent->IsIconic() ) pParent->ShowWindow( SW_SHOWNORMAL );
01284 pParent->BringWindowToTop();
01285 pParent->SetForegroundWindow();
01286 }
01287
01288 void CChatSession::OnCloseWindow()
01289 {
01290 m_pWndPrivate = NULL;
01291 m_pWndPublic = NULL;
01292
01293 Close();
01294
01295 if ( m_nProtocol == PROTOCOL_ED2K )
01296 {
01297 if ( m_pProfile != NULL ) delete m_pProfile;
01298 delete this;
01299 }
01300 }
01301