| File: | rootdir/src/ExternalConn.cpp |
| Warning: | line 986, column 14 Although the value stored to 'tag' is used in the enclosing expression, the value is never actually read from 'tag' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | // |
| 2 | // This file is part of the aMule Project. |
| 3 | // |
| 4 | // Copyright (c) 2003-2011 Kry ( elkry@sourceforge.net / http://www.amule.org ) |
| 5 | // Copyright (c) 2003-2011 aMule Team ( admin@amule.org / http://www.amule.org ) |
| 6 | // Copyright (c) 2008-2011 Froenchenko Leonid (lfroen@gmail.com) |
| 7 | // |
| 8 | // Any parts of this program derived from the xMule, lMule or eMule project, |
| 9 | // or contributed by third-party developers are copyrighted by their |
| 10 | // respective authors. |
| 11 | // |
| 12 | // This program is free software; you can redistribute it and/or modify |
| 13 | // it under the terms of the GNU General Public License as published by |
| 14 | // the Free Software Foundation; either version 2 of the License, or |
| 15 | // (at your option) any later version. |
| 16 | // |
| 17 | // This program is distributed in the hope that it will be useful, |
| 18 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 19 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 20 | // GNU General Public License for more details. |
| 21 | // |
| 22 | // You should have received a copy of the GNU General Public License |
| 23 | // along with this program; if not, write to the Free Software |
| 24 | // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
| 25 | // |
| 26 | |
| 27 | #include "config.h" // Needed for VERSION |
| 28 | |
| 29 | #include <ec/cpp/ECMuleSocket.h> // Needed for CECSocket |
| 30 | |
| 31 | #include <common/Format.h> // Needed for CFormat |
| 32 | |
| 33 | #include <common/ClientVersion.h> |
| 34 | #include <common/MD5Sum.h> |
| 35 | |
| 36 | #include "ExternalConn.h" // Interface declarations |
| 37 | #include "updownclient.h" // Needed for CUpDownClient |
| 38 | #include "Server.h" // Needed for CServer |
| 39 | #include "ServerList.h" // Needed for CServerList |
| 40 | #include "PartFile.h" // Needed for CPartFile |
| 41 | #include "ServerConnect.h" // Needed for CServerConnect |
| 42 | #include "UploadQueue.h" // Needed for CUploadQueue |
| 43 | #include "amule.h" // Needed for theApp |
| 44 | #include "SearchList.h" // Needed for GetSearchResults |
| 45 | #include "ClientList.h" |
| 46 | #include "Preferences.h" // Needed for CPreferences |
| 47 | #include "Logger.h" |
| 48 | #include "GuiEvents.h" // Needed for Notify_* macros |
| 49 | #include "Statistics.h" // Needed for theStats |
| 50 | #include "KnownFileList.h" // Needed for CKnownFileList |
| 51 | #include "Friend.h" |
| 52 | #include "FriendList.h" |
| 53 | #include "RandomFunctions.h" |
| 54 | #include "kademlia/kademlia/Kademlia.h" |
| 55 | #include "kademlia/kademlia/UDPFirewallTester.h" |
| 56 | #include "Statistics.h" |
| 57 | |
| 58 | |
| 59 | //-------------------- File_Encoder -------------------- |
| 60 | |
| 61 | |
| 62 | /* |
| 63 | * Encode 'obtained parts' info to be sent to remote gui |
| 64 | */ |
| 65 | class CKnownFile_Encoder { |
| 66 | // number of sources for each part for progress bar colouring |
| 67 | RLE_Data m_enc_data; |
| 68 | protected: |
| 69 | const CKnownFile *m_file; |
| 70 | public: |
| 71 | CKnownFile_Encoder(const CKnownFile *file = 0) { m_file = file; } |
| 72 | |
| 73 | virtual ~CKnownFile_Encoder() {} |
| 74 | |
| 75 | virtual void Encode(CECTag *parent_tag); |
| 76 | |
| 77 | virtual void ResetEncoder() |
| 78 | { |
| 79 | m_enc_data.ResetEncoder(); |
| 80 | } |
| 81 | |
| 82 | virtual void SetShared() { } |
| 83 | virtual bool IsShared() { return true; } |
| 84 | virtual bool IsPartFile_Encoder() { return false; } |
| 85 | const CKnownFile * GetFile() { return m_file; } |
| 86 | }; |
| 87 | |
| 88 | /*! |
| 89 | * PartStatus strings and gap lists are quite long - RLE encoding will help. |
| 90 | * |
| 91 | * Instead of sending each time full part-status string, send |
| 92 | * RLE encoded difference from previous one. |
| 93 | * |
| 94 | * PartFileEncoderData class is used for decode only, |
| 95 | * while CPartFile_Encoder is used for encode only. |
| 96 | */ |
| 97 | class CPartFile_Encoder : public CKnownFile_Encoder { |
| 98 | // blocks requested for download |
| 99 | RLE_Data m_req_status; |
| 100 | // gap list |
| 101 | RLE_Data m_gap_status; |
| 102 | // source names |
| 103 | SourcenameItemMap m_sourcenameItemMap; |
| 104 | // counter for unique source name ids |
| 105 | int m_sourcenameID; |
| 106 | // not all part files are shared (only when at least one part is complete) |
| 107 | bool m_shared; |
| 108 | |
| 109 | // cast inherited member to CPartFile |
| 110 | const CPartFile * m_PartFile() { wxCHECK(m_file->IsCPartFile(), NULL)if ( m_file->IsCPartFile() ) {} else { do { if ( wxTheAssertHandler && (wxOnAssert("ExternalConn.cpp", 110, __FUNCTION__ , "\"m_file->IsCPartFile()\"", (const char*)__null), wxTrapInAssert ) ) { wxTrapInAssert = false; asm volatile ("int $3"); } } while ( (void)0, 0 ); return __null; } struct wxDummyCheckStruct110; return static_cast<const CPartFile *>(m_file); } |
| 111 | public: |
| 112 | // encoder side |
| 113 | CPartFile_Encoder(const CPartFile *file = 0) : CKnownFile_Encoder(file) |
| 114 | { |
| 115 | m_sourcenameID = 0; |
| 116 | m_shared = false; |
| 117 | } |
| 118 | |
| 119 | virtual ~CPartFile_Encoder() {} |
| 120 | |
| 121 | // encode - take data from m_file |
| 122 | virtual void Encode(CECTag *parent_tag); |
| 123 | |
| 124 | // Encoder may reset history if full info requested |
| 125 | virtual void ResetEncoder(); |
| 126 | |
| 127 | virtual void SetShared() { m_shared = true; } |
| 128 | virtual bool IsShared() { return m_shared; } |
| 129 | virtual bool IsPartFile_Encoder() { return true; } |
| 130 | }; |
| 131 | |
| 132 | class CFileEncoderMap : public std::map<uint32, CKnownFile_Encoder*> { |
| 133 | typedef std::set<uint32> IDSet; |
| 134 | public: |
| 135 | ~CFileEncoderMap(); |
| 136 | void UpdateEncoders(); |
| 137 | }; |
| 138 | |
| 139 | CFileEncoderMap::~CFileEncoderMap() |
| 140 | { |
| 141 | // DeleteContents() causes infinite recursion here! |
| 142 | for (iterator it = begin(); it != end(); ++it) { |
| 143 | delete it->second; |
| 144 | } |
| 145 | } |
| 146 | |
| 147 | // Check if encoder contains files that are no longer used |
| 148 | // or if we have new files without encoder yet. |
| 149 | void CFileEncoderMap::UpdateEncoders() |
| 150 | { |
| 151 | IDSet curr_files, dead_files; |
| 152 | // Downloads |
| 153 | std::vector<CPartFile*> downloads; |
| 154 | theApp->downloadqueue->CopyFileList(downloads, true); |
| 155 | for (uint32 i = downloads.size(); i--;) { |
| 156 | uint32 id = downloads[i]->ECID(); |
| 157 | curr_files.insert(id); |
| 158 | if (!count(id)) { |
| 159 | (*this)[id] = new CPartFile_Encoder(downloads[i]); |
| 160 | } |
| 161 | } |
| 162 | // Shares |
| 163 | std::vector<CKnownFile*> shares; |
| 164 | theApp->sharedfiles->CopyFileList(shares); |
| 165 | for (uint32 i = shares.size(); i--;) { |
| 166 | uint32 id = shares[i]->ECID(); |
| 167 | // Check if it is already there. |
| 168 | // The curr_files.count(id) is enough, the IsCPartFile() is just a speedup. |
| 169 | if (shares[i]->IsCPartFile() && curr_files.count(id)) { |
| 170 | (*this)[id]->SetShared(); |
| 171 | continue; |
| 172 | } |
| 173 | curr_files.insert(id); |
| 174 | if (!count(id)) { |
| 175 | (*this)[id] = new CKnownFile_Encoder(shares[i]); |
| 176 | } |
| 177 | } |
| 178 | // Check for removed files, and store them in a set for deletion. |
| 179 | // (std::map documentation is unclear if a construct like |
| 180 | // iterator to_del = it++; erase(to_del) ; |
| 181 | // works or invalidates it too.) |
| 182 | for (iterator it = begin(); it != end(); ++it) { |
| 183 | if (!curr_files.count(it->first)) { |
| 184 | dead_files.insert(it->first); |
| 185 | } |
| 186 | } |
| 187 | // then delete them |
| 188 | for (IDSet::iterator it = dead_files.begin(); it != dead_files.end(); ++it) { |
| 189 | iterator it2 = find(*it); |
| 190 | delete it2->second; |
| 191 | erase(it2); |
| 192 | } |
| 193 | } |
| 194 | |
| 195 | |
| 196 | //-------------------- CECServerSocket -------------------- |
| 197 | |
| 198 | class CECServerSocket : public CECMuleSocket |
| 199 | { |
| 200 | public: |
| 201 | CECServerSocket(ECNotifier *notifier); |
| 202 | virtual ~CECServerSocket(); |
| 203 | |
| 204 | virtual const CECPacket *OnPacketReceived(const CECPacket *packet, uint32 trueSize); |
| 205 | virtual void OnLost(); |
| 206 | |
| 207 | virtual void WriteDoneAndQueueEmpty(); |
| 208 | |
| 209 | void ResetLog() { m_LoggerAccess.Reset(); } |
| 210 | private: |
| 211 | ECNotifier *m_ec_notifier; |
| 212 | |
| 213 | const CECPacket *Authenticate(const CECPacket *); |
| 214 | |
| 215 | enum { |
| 216 | CONN_INIT, |
| 217 | CONN_SALT_SENT, |
| 218 | CONN_ESTABLISHED, |
| 219 | CONN_FAILED |
| 220 | } m_conn_state; |
| 221 | |
| 222 | uint64_t m_passwd_salt; |
| 223 | CLoggerAccess m_LoggerAccess; |
| 224 | CFileEncoderMap m_FileEncoder; |
| 225 | CObjTagMap m_obj_tagmap; |
| 226 | CECPacket *ProcessRequest2(const CECPacket *request); |
| 227 | |
| 228 | virtual bool IsAuthorized() { return m_conn_state == CONN_ESTABLISHED; } |
| 229 | }; |
| 230 | |
| 231 | |
| 232 | CECServerSocket::CECServerSocket(ECNotifier *notifier) |
| 233 | : |
| 234 | CECMuleSocket(true), |
| 235 | m_conn_state(CONN_INIT), |
| 236 | m_passwd_salt(GetRandomUint64()) |
| 237 | { |
| 238 | wxASSERT(theApp->ECServerHandler)do { if ( theApp->ECServerHandler ) { } else if ( wxTheAssertHandler && (wxOnAssert("ExternalConn.cpp", 238, __FUNCTION__ , "theApp->ECServerHandler", (const char*)__null), wxTrapInAssert ) ) { wxTrapInAssert = false; asm volatile ("int $3"); } } while ( (void)0, 0 ); |
| 239 | theApp->ECServerHandler->AddSocket(this); |
| 240 | m_ec_notifier = notifier; |
| 241 | } |
| 242 | |
| 243 | |
| 244 | CECServerSocket::~CECServerSocket() |
| 245 | { |
| 246 | wxASSERT(theApp->ECServerHandler)do { if ( theApp->ECServerHandler ) { } else if ( wxTheAssertHandler && (wxOnAssert("ExternalConn.cpp", 246, __FUNCTION__ , "theApp->ECServerHandler", (const char*)__null), wxTrapInAssert ) ) { wxTrapInAssert = false; asm volatile ("int $3"); } } while ( (void)0, 0 ); |
| 247 | theApp->ECServerHandler->RemoveSocket(this); |
| 248 | } |
| 249 | |
| 250 | |
| 251 | const CECPacket *CECServerSocket::OnPacketReceived(const CECPacket *packet, uint32 trueSize) |
| 252 | { |
| 253 | packet->DebugPrint(true, trueSize); |
| 254 | |
| 255 | const CECPacket *reply = NULL__null; |
| 256 | |
| 257 | if (m_conn_state == CONN_FAILED) { |
| 258 | // Client didn't close the socket when authentication failed. |
| 259 | AddLogLineN(_("Client sent packet after authentication failed."))theLogger.AddLogLine(L"ExternalConn.cpp", 259, false, logStandard , wxGetTranslation(("Client sent packet after authentication failed." ))); |
| 260 | CloseSocket(); |
| 261 | } |
| 262 | |
| 263 | if (m_conn_state != CONN_ESTABLISHED) { |
| 264 | // This is called twice: |
| 265 | // 1) send salt |
| 266 | // 2) verify password |
| 267 | reply = Authenticate(packet); |
| 268 | } else { |
| 269 | reply = ProcessRequest2(packet); |
| 270 | } |
| 271 | return reply; |
| 272 | } |
| 273 | |
| 274 | |
| 275 | void CECServerSocket::OnLost() |
| 276 | { |
| 277 | AddLogLineN(_("External connection closed."))theLogger.AddLogLine(L"ExternalConn.cpp", 277, false, logStandard , wxGetTranslation(("External connection closed."))); |
| 278 | theApp->ECServerHandler->m_ec_notifier->Remove_EC_Client(this); |
| 279 | DestroySocket(); |
| 280 | } |
| 281 | |
| 282 | void CECServerSocket::WriteDoneAndQueueEmpty() |
| 283 | { |
| 284 | if ( HaveNotificationSupport() && (m_conn_state == CONN_ESTABLISHED) ) { |
| 285 | CECPacket *packet = m_ec_notifier->GetNextPacket(this); |
| 286 | if ( packet ) { |
| 287 | SendPacket(packet); |
| 288 | } |
| 289 | } else { |
| 290 | //printf("[EC] %p: WriteDoneAndQueueEmpty but notification disabled\n", this); |
| 291 | } |
| 292 | } |
| 293 | |
| 294 | //-------------------- ExternalConn -------------------- |
| 295 | |
| 296 | #ifndef ASIO_SOCKETS |
| 297 | enum |
| 298 | { // id for sockets |
| 299 | SERVER_ID = 1000 |
| 300 | }; |
| 301 | |
| 302 | |
| 303 | BEGIN_EVENT_TABLE(ExternalConn, wxEvtHandler)const wxEventTable ExternalConn::sm_eventTable = { &wxEvtHandler ::sm_eventTable, &ExternalConn::sm_eventTableEntries[0] } ; const wxEventTable *ExternalConn::GetEventTable() const { return &ExternalConn::sm_eventTable; } wxEventHashTable ExternalConn ::sm_eventHashTable(ExternalConn::sm_eventTable); wxEventHashTable &ExternalConn::GetEventHashTable() const { return ExternalConn ::sm_eventHashTable; } const wxEventTableEntry ExternalConn:: sm_eventTableEntries[] = { |
| 304 | EVT_SOCKET(SERVER_ID, ExternalConn::OnServerEvent)wxEventTableEntry(wxEVT_SOCKET, SERVER_ID, wxID_ANY, wxNewEventTableFunctor (wxEVT_SOCKET, wxEventFunctionCast(wxPrivate::DoCast<wxPrivate ::EventArgOf<wxSocketEventFunction>::type>(&ExternalConn ::OnServerEvent))), __null), |
| 305 | END_EVENT_TABLE()wxEventTableEntry(wxEVT_NULL, 0, 0, __null, __null) }; |
| 306 | #endif |
| 307 | |
| 308 | |
| 309 | ExternalConn::ExternalConn(amuleIPV4Address addr, wxString *msg) |
| 310 | { |
| 311 | wxString msgLocal; |
| 312 | m_ECServer = NULL__null; |
| 313 | // Are we allowed to accept External Connections? |
| 314 | if ( thePrefs::AcceptExternalConnections() ) { |
| 315 | // We must have a valid password, otherwise we will not allow EC connections |
| 316 | if (thePrefs::ECPassword().IsEmpty()) { |
| 317 | *msg += wxT("External connections disabled due to empty password!\n")L"External connections disabled due to empty password!\n"; |
| 318 | AddLogLineC(_("External connections disabled due to empty password!"))theLogger.AddLogLine(L"ExternalConn.cpp", 318, true, logStandard , wxGetTranslation(("External connections disabled due to empty password!" ))); |
| 319 | return; |
| 320 | } |
| 321 | |
| 322 | // Create the socket |
| 323 | m_ECServer = new CExternalConnListener(addr, MULE_SOCKET_REUSEADDRwxSOCKET_REUSEADDR, this); |
| 324 | #ifndef ASIO_SOCKETS |
| 325 | m_ECServer->SetEventHandler(*this, SERVER_ID); |
| 326 | m_ECServer->SetNotify(wxSOCKET_CONNECTION_FLAG); |
| 327 | #endif |
| 328 | m_ECServer->Notify(true); |
| 329 | |
| 330 | int port = addr.Service(); |
| 331 | wxString ip = addr.IPAddress(); |
| 332 | if (m_ECServer->IsOk()) { |
| 333 | msgLocal = CFormat(wxT("*** TCP socket (ECServer) listening on %s:%d")L"*** TCP socket (ECServer) listening on %s:%d") % ip % port; |
| 334 | *msg += msgLocal + wxT("\n")L"\n"; |
| 335 | AddLogLineN(msgLocal)theLogger.AddLogLine(L"ExternalConn.cpp", 335, false, logStandard , msgLocal); |
| 336 | } else { |
| 337 | msgLocal = CFormat(wxT("Could not listen for external connections at %s:%d!")L"Could not listen for external connections at %s:%d!") % ip % port; |
| 338 | *msg += msgLocal + wxT("\n")L"\n"; |
| 339 | AddLogLineN(msgLocal)theLogger.AddLogLine(L"ExternalConn.cpp", 339, false, logStandard , msgLocal); |
| 340 | } |
| 341 | } else { |
| 342 | *msg += wxT("External connections disabled in config file\n")L"External connections disabled in config file\n"; |
| 343 | AddLogLineN(_("External connections disabled in config file"))theLogger.AddLogLine(L"ExternalConn.cpp", 343, false, logStandard , wxGetTranslation(("External connections disabled in config file" ))); |
| 344 | } |
| 345 | m_ec_notifier = new ECNotifier(); |
| 346 | } |
| 347 | |
| 348 | |
| 349 | ExternalConn::~ExternalConn() |
| 350 | { |
| 351 | KillAllSockets(); |
| 352 | delete m_ECServer; |
| 353 | delete m_ec_notifier; |
| 354 | } |
| 355 | |
| 356 | |
| 357 | void ExternalConn::AddSocket(CECServerSocket *s) |
| 358 | { |
| 359 | wxASSERT(s)do { if ( s ) { } else if ( wxTheAssertHandler && (wxOnAssert ("ExternalConn.cpp", 359, __FUNCTION__, "s", (const char*)__null ), wxTrapInAssert) ) { wxTrapInAssert = false; asm volatile ( "int $3"); } } while ( (void)0, 0 ); |
| 360 | socket_list.insert(s); |
| 361 | } |
| 362 | |
| 363 | |
| 364 | void ExternalConn::RemoveSocket(CECServerSocket *s) |
| 365 | { |
| 366 | wxASSERT(s)do { if ( s ) { } else if ( wxTheAssertHandler && (wxOnAssert ("ExternalConn.cpp", 366, __FUNCTION__, "s", (const char*)__null ), wxTrapInAssert) ) { wxTrapInAssert = false; asm volatile ( "int $3"); } } while ( (void)0, 0 ); |
| 367 | socket_list.erase(s); |
| 368 | } |
| 369 | |
| 370 | |
| 371 | void ExternalConn::KillAllSockets() |
| 372 | { |
| 373 | AddDebugLogLineN(logGeneral,do {} while (false) |
| 374 | CFormat(wxT("ExternalConn::KillAllSockets(): %d sockets to destroy.")) %do {} while (false) |
| 375 | socket_list.size())do {} while (false); |
| 376 | SocketSet::iterator it = socket_list.begin(); |
| 377 | while (it != socket_list.end()) { |
| 378 | CECServerSocket *s = *(it++); |
| 379 | s->Close(); |
| 380 | s->Destroy(); |
| 381 | } |
| 382 | socket_list.clear(); |
| 383 | } |
| 384 | |
| 385 | |
| 386 | void ExternalConn::ResetAllLogs() |
| 387 | { |
| 388 | SocketSet::iterator it = socket_list.begin(); |
| 389 | while (it != socket_list.end()) { |
| 390 | CECServerSocket *s = *(it++); |
| 391 | s->ResetLog(); |
| 392 | } |
| 393 | } |
| 394 | |
| 395 | |
| 396 | #ifndef ASIO_SOCKETS |
| 397 | void ExternalConn::OnServerEvent(wxSocketEvent& WXUNUSED(event)) |
| 398 | { |
| 399 | m_ECServer->OnAccept(); |
| 400 | } |
| 401 | #endif |
| 402 | |
| 403 | |
| 404 | void CExternalConnListener::OnAccept() |
| 405 | { |
| 406 | CECServerSocket *sock = new CECServerSocket(m_conn->m_ec_notifier); |
| 407 | // Accept new connection if there is one in the pending |
| 408 | // connections queue, else exit. We use Accept(FALSE) for |
| 409 | // non-blocking accept (although if we got here, there |
| 410 | // should ALWAYS be a pending connection). |
| 411 | if (AcceptWith(*sock, false)) { |
| 412 | AddLogLineN(_("New external connection accepted"))theLogger.AddLogLine(L"ExternalConn.cpp", 412, false, logStandard , wxGetTranslation(("New external connection accepted"))); |
| 413 | } else { |
| 414 | delete sock; |
| 415 | AddLogLineN(_("ERROR: couldn't accept a new external connection"))theLogger.AddLogLine(L"ExternalConn.cpp", 415, false, logStandard , wxGetTranslation(("ERROR: couldn't accept a new external connection" ))); |
| 416 | } |
| 417 | |
| 418 | } |
| 419 | |
| 420 | // |
| 421 | // Authentication |
| 422 | // |
| 423 | const CECPacket *CECServerSocket::Authenticate(const CECPacket *request) |
| 424 | { |
| 425 | CECPacket *response; |
| 426 | |
| 427 | if (request == NULL__null) { |
| 428 | return new CECPacket(EC_OP_AUTH_FAIL); |
| 429 | } |
| 430 | |
| 431 | // Password must be specified if we are to allow remote connections |
| 432 | if ( thePrefs::ECPassword().IsEmpty() ) { |
| 433 | AddLogLineC(_("External connection refused due to empty password in preferences!"))theLogger.AddLogLine(L"ExternalConn.cpp", 433, true, logStandard , wxGetTranslation(("External connection refused due to empty password in preferences!" ))); |
| 434 | |
| 435 | return new CECPacket(EC_OP_AUTH_FAIL); |
| 436 | } |
| 437 | |
| 438 | if ((m_conn_state == CONN_INIT) && (request->GetOpCode() == EC_OP_AUTH_REQ) ) { |
| 439 | // cppcheck-suppress unreadVariable |
| 440 | const CECTag *clientName = request->GetTagByName(EC_TAG_CLIENT_NAME); |
| 441 | // cppcheck-suppress unreadVariable |
| 442 | const CECTag *clientVersion = request->GetTagByName(EC_TAG_CLIENT_VERSION); |
| 443 | |
| 444 | AddLogLineN(CFormat( _("Connecting client: %s %s") )theLogger.AddLogLine(L"ExternalConn.cpp", 446, false, logStandard , CFormat( wxGetTranslation(("Connecting client: %s %s")) ) % ( clientName ? clientName->GetStringData() : wxString(wxGetTranslation (("Unknown"))) ) % ( clientVersion ? clientVersion->GetStringData () : wxString(wxGetTranslation(("Unknown version"))) )) |
| 445 | % ( clientName ? clientName->GetStringData() : wxString(_("Unknown")) )theLogger.AddLogLine(L"ExternalConn.cpp", 446, false, logStandard , CFormat( wxGetTranslation(("Connecting client: %s %s")) ) % ( clientName ? clientName->GetStringData() : wxString(wxGetTranslation (("Unknown"))) ) % ( clientVersion ? clientVersion->GetStringData () : wxString(wxGetTranslation(("Unknown version"))) )) |
| 446 | % ( clientVersion ? clientVersion->GetStringData() : wxString(_("Unknown version")) ) )theLogger.AddLogLine(L"ExternalConn.cpp", 446, false, logStandard , CFormat( wxGetTranslation(("Connecting client: %s %s")) ) % ( clientName ? clientName->GetStringData() : wxString(wxGetTranslation (("Unknown"))) ) % ( clientVersion ? clientVersion->GetStringData () : wxString(wxGetTranslation(("Unknown version"))) )); |
| 447 | const CECTag *protocol = request->GetTagByName(EC_TAG_PROTOCOL_VERSION); |
| 448 | #ifdef EC_VERSION_ID |
| 449 | // For SVN versions, both client and server must use SVNDATE, and they must be the same |
| 450 | CMD4Hash vhash; |
| 451 | if (!vhash.Decode(wxT(EC_VERSION_ID)LEC_VERSION_ID)) { |
| 452 | response = new CECPacket(EC_OP_AUTH_FAIL); |
| 453 | response->AddTag(CECTag(EC_TAG_STRING, wxT("Fatal error, version hash is not a valid MD4-hash.")L"Fatal error, version hash is not a valid MD4-hash.")); |
| 454 | } else if (!request->GetTagByName(EC_TAG_VERSION_ID) || request->GetTagByNameSafe(EC_TAG_VERSION_ID)->GetMD4Data() != vhash) { |
| 455 | response = new CECPacket(EC_OP_AUTH_FAIL); |
| 456 | response->AddTag(CECTag(EC_TAG_STRING, wxTRANSLATE("Incorrect EC version ID, there might be binary incompatibility. Use core and remote from same snapshot.")"Incorrect EC version ID, there might be binary incompatibility. Use core and remote from same snapshot.")); |
| 457 | #else |
| 458 | // For release versions, we don't want to allow connections from any arbitrary SVN client. |
| 459 | if (request->GetTagByName(EC_TAG_VERSION_ID)) { |
| 460 | response = new CECPacket(EC_OP_AUTH_FAIL); |
| 461 | response->AddTag(CECTag(EC_TAG_STRING, wxTRANSLATE("You cannot connect to a release version from an arbitrary development snapshot! *sigh* possible crash prevented")"You cannot connect to a release version from an arbitrary development snapshot! *sigh* possible crash prevented")); |
| 462 | #endif |
| 463 | } else if (protocol != NULL__null) { |
| 464 | uint16 proto_version = protocol->GetInt(); |
| 465 | if (proto_version == EC_CURRENT_PROTOCOL_VERSION) { |
| 466 | response = new CECPacket(EC_OP_AUTH_SALT); |
| 467 | response->AddTag(CECTag(EC_TAG_PASSWD_SALT, m_passwd_salt)); |
| 468 | m_conn_state = CONN_SALT_SENT; |
| 469 | // |
| 470 | // So far ok, check capabilities of client |
| 471 | // |
| 472 | if (request->GetTagByName(EC_TAG_CAN_ZLIB)) { |
| 473 | m_my_flags |= EC_FLAG_ZLIB; |
| 474 | } |
| 475 | if (request->GetTagByName(EC_TAG_CAN_UTF8_NUMBERS)) { |
| 476 | m_my_flags |= EC_FLAG_UTF8_NUMBERS; |
| 477 | } |
| 478 | m_haveNotificationSupport = request->GetTagByName(EC_TAG_CAN_NOTIFY) != NULL__null; |
| 479 | AddDebugLogLineN(logEC, CFormat(wxT("Client capabilities: ZLIB: %s UTF8 numbers: %s Push notification: %s") )do {} while (false) |
| 480 | % ((m_my_flags & EC_FLAG_ZLIB) ? wxT("yes") : wxT("no"))do {} while (false) |
| 481 | % ((m_my_flags & EC_FLAG_UTF8_NUMBERS) ? wxT("yes") : wxT("no"))do {} while (false) |
| 482 | % (m_haveNotificationSupport ? wxT("yes") : wxT("no")))do {} while (false); |
| 483 | } else { |
| 484 | response = new CECPacket(EC_OP_AUTH_FAIL); |
| 485 | response->AddTag(CECTag(EC_TAG_STRING, wxTRANSLATE("Invalid protocol version.")"Invalid protocol version." |
| 486 | + CFormat(wxT("( %#.4x != %#.4x )")L"( %#.4x != %#.4x )") % proto_version % (uint16_t)EC_CURRENT_PROTOCOL_VERSION)); |
| 487 | } |
| 488 | } else { |
| 489 | response = new CECPacket(EC_OP_AUTH_FAIL); |
| 490 | response->AddTag(CECTag(EC_TAG_STRING, wxTRANSLATE("Missing protocol version tag.")"Missing protocol version tag.")); |
| 491 | } |
| 492 | } else if ((m_conn_state == CONN_SALT_SENT) && (request->GetOpCode() == EC_OP_AUTH_PASSWD)) { |
| 493 | const CECTag *passwd = request->GetTagByName(EC_TAG_PASSWD_HASH); |
| 494 | CMD4Hash passh; |
| 495 | |
| 496 | if (!passh.Decode(thePrefs::ECPassword())) { |
| 497 | wxString err = wxTRANSLATE("Authentication failed: invalid hash specified as EC password.")"Authentication failed: invalid hash specified as EC password."; |
| 498 | AddLogLineN(wxString(wxGetTranslation(err))theLogger.AddLogLine(L"ExternalConn.cpp", 499, false, logStandard , wxString(wxGetTranslation(err)) + L" " + thePrefs::ECPassword ()) |
| 499 | + wxT(" ") + thePrefs::ECPassword())theLogger.AddLogLine(L"ExternalConn.cpp", 499, false, logStandard , wxString(wxGetTranslation(err)) + L" " + thePrefs::ECPassword ()); |
| 500 | response = new CECPacket(EC_OP_AUTH_FAIL); |
| 501 | response->AddTag(CECTag(EC_TAG_STRING, err)); |
| 502 | } else { |
| 503 | wxString saltHash = MD5Sum(CFormat(wxT("%lX")L"%lX") % m_passwd_salt).GetHash(); |
| 504 | wxString saltStr = CFormat(wxT("%lX")L"%lX") % m_passwd_salt; |
| 505 | |
| 506 | passh.Decode(MD5Sum(thePrefs::ECPassword().Lower() + saltHash).GetHash()); |
| 507 | |
| 508 | if (passwd && passwd->GetMD4Data() == passh) { |
| 509 | response = new CECPacket(EC_OP_AUTH_OK); |
| 510 | response->AddTag(CECTag(EC_TAG_SERVER_VERSION, wxT(VERSION)L"SVN")); |
| 511 | } else { |
| 512 | wxString err; |
| 513 | if (passwd) { |
| 514 | err = wxTRANSLATE("Authentication failed: wrong password.")"Authentication failed: wrong password."; |
| 515 | } else { |
| 516 | err = wxTRANSLATE("Authentication failed: missing password.")"Authentication failed: missing password."; |
| 517 | } |
| 518 | |
| 519 | response = new CECPacket(EC_OP_AUTH_FAIL); |
| 520 | response->AddTag(CECTag(EC_TAG_STRING, err)); |
| 521 | AddLogLineN(wxGetTranslation(err))theLogger.AddLogLine(L"ExternalConn.cpp", 521, false, logStandard , wxGetTranslation(err)); |
| 522 | } |
| 523 | } |
| 524 | } else { |
| 525 | response = new CECPacket(EC_OP_AUTH_FAIL); |
| 526 | response->AddTag(CECTag(EC_TAG_STRING, wxTRANSLATE("Invalid request, please authenticate first.")"Invalid request, please authenticate first.")); |
| 527 | } |
| 528 | |
| 529 | if (response->GetOpCode() == EC_OP_AUTH_OK) { |
| 530 | m_conn_state = CONN_ESTABLISHED; |
| 531 | AddLogLineN(_("Access granted."))theLogger.AddLogLine(L"ExternalConn.cpp", 531, false, logStandard , wxGetTranslation(("Access granted."))); |
| 532 | // Establish notification handler if client supports it |
| 533 | if (HaveNotificationSupport()) { |
| 534 | theApp->ECServerHandler->m_ec_notifier->Add_EC_Client(this); |
| 535 | } |
| 536 | } else if (response->GetOpCode() == EC_OP_AUTH_FAIL) { |
| 537 | // Log message sent to client |
| 538 | if (response->GetFirstTagSafe()->IsString()) { |
| 539 | AddLogLineN(CFormat(_("Sent error message \"%s\" to client.")) % wxGetTranslation(response->GetFirstTagSafe()->GetStringData()))theLogger.AddLogLine(L"ExternalConn.cpp", 539, false, logStandard , CFormat(wxGetTranslation(("Sent error message \"%s\" to client." ))) % wxGetTranslation(response->GetFirstTagSafe()->GetStringData ())); |
| 540 | } |
| 541 | // Access denied! |
| 542 | AddLogLineN(CFormat(_("Unauthorized access attempt from %s. Connection closed.")) % GetPeer() )theLogger.AddLogLine(L"ExternalConn.cpp", 542, false, logStandard , CFormat(wxGetTranslation(("Unauthorized access attempt from %s. Connection closed." ))) % GetPeer()); |
| 543 | m_conn_state = CONN_FAILED; |
| 544 | } |
| 545 | |
| 546 | return response; |
| 547 | } |
| 548 | |
| 549 | // Make a Logger tag (if there are any logging messages) and add it to the response |
| 550 | static void AddLoggerTag(CECPacket *response, CLoggerAccess &LoggerAccess) |
| 551 | { |
| 552 | if (LoggerAccess.HasString()) { |
| 553 | CECEmptyTag tag(EC_TAG_STATS_LOGGER_MESSAGE); |
| 554 | // Tag structure is fix: tag carries nothing, inside are the strings |
| 555 | // maximum of 200 log lines per message |
| 556 | int entries = 0; |
| 557 | wxString line; |
| 558 | while (entries < 200 && LoggerAccess.GetString(line)) { |
| 559 | tag.AddTag(CECTag(EC_TAG_STRING, line)); |
| 560 | entries++; |
| 561 | } |
| 562 | response->AddTag(tag); |
| 563 | //printf("send Log tag %d %d\n", FirstEntry, entries); |
| 564 | } |
| 565 | } |
| 566 | |
| 567 | static CECPacket *Get_EC_Response_StatRequest(const CECPacket *request, CLoggerAccess &LoggerAccess) |
| 568 | { |
| 569 | CECPacket *response = new CECPacket(EC_OP_STATS); |
| 570 | |
| 571 | switch (request->GetDetailLevel()) { |
| 572 | case EC_DETAIL_FULL: |
| 573 | // This is not an actual INC_UPDATE. |
| 574 | // amulegui only sets the detail level of the stats package to EC_DETAIL_INC_UPDATE |
| 575 | // so that the included conn state tag is created the way it is needed here. |
| 576 | case EC_DETAIL_INC_UPDATE: |
| 577 | response->AddTag(CECTag(EC_TAG_STATS_UP_OVERHEAD, (uint32)theStats::GetUpOverheadRate())); |
| 578 | response->AddTag(CECTag(EC_TAG_STATS_DOWN_OVERHEAD, (uint32)theStats::GetDownOverheadRate())); |
| 579 | response->AddTag(CECTag(EC_TAG_STATS_BANNED_COUNT, /*(uint32)*/theStats::GetBannedCount())); |
| 580 | AddLoggerTag(response, LoggerAccess); |
| 581 | // Needed only for the remote tray icon context menu |
| 582 | response->AddTag(CECTag(EC_TAG_STATS_TOTAL_SENT_BYTES, theStats::GetTotalSentBytes())); |
| 583 | response->AddTag(CECTag(EC_TAG_STATS_TOTAL_RECEIVED_BYTES, theStats::GetTotalReceivedBytes())); |
| 584 | response->AddTag(CECTag(EC_TAG_STATS_SHARED_FILE_COUNT, theStats::GetSharedFileCount())); |
| 585 | /* fall through */ |
| 586 | case EC_DETAIL_WEB: |
| 587 | case EC_DETAIL_CMD: |
| 588 | response->AddTag(CECTag(EC_TAG_STATS_UL_SPEED, (uint32)theStats::GetUploadRate())); |
| 589 | response->AddTag(CECTag(EC_TAG_STATS_DL_SPEED, (uint32)(theStats::GetDownloadRate()))); |
| 590 | response->AddTag(CECTag(EC_TAG_STATS_UL_SPEED_LIMIT, (uint32)(thePrefs::GetMaxUpload()*1024.0))); |
| 591 | response->AddTag(CECTag(EC_TAG_STATS_DL_SPEED_LIMIT, (uint32)(thePrefs::GetMaxDownload()*1024.0))); |
| 592 | response->AddTag(CECTag(EC_TAG_STATS_UL_QUEUE_LEN, /*(uint32)*/theStats::GetWaitingUserCount())); |
| 593 | response->AddTag(CECTag(EC_TAG_STATS_TOTAL_SRC_COUNT, /*(uint32)*/theStats::GetFoundSources())); |
| 594 | // User/Filecounts |
| 595 | { |
| 596 | uint32 totaluser = 0, totalfile = 0; |
| 597 | theApp->serverlist->GetUserFileStatus( totaluser, totalfile ); |
| 598 | response->AddTag(CECTag(EC_TAG_STATS_ED2K_USERS, totaluser)); |
| 599 | response->AddTag(CECTag(EC_TAG_STATS_KAD_USERS, Kademlia::CKademlia::GetKademliaUsers())); |
| 600 | response->AddTag(CECTag(EC_TAG_STATS_ED2K_FILES, totalfile)); |
| 601 | response->AddTag(CECTag(EC_TAG_STATS_KAD_FILES, Kademlia::CKademlia::GetKademliaFiles())); |
| 602 | response->AddTag(CECTag(EC_TAG_STATS_KAD_NODES, CStatistics::GetKadNodes())); |
| 603 | } |
| 604 | // Kad stats |
| 605 | if (Kademlia::CKademlia::IsConnected()) { |
| 606 | response->AddTag(CECTag(EC_TAG_STATS_KAD_FIREWALLED_UDP, Kademlia::CUDPFirewallTester::IsFirewalledUDP(true))); |
| 607 | response->AddTag(CECTag(EC_TAG_STATS_KAD_INDEXED_SOURCES, Kademlia::CKademlia::GetIndexed()->m_totalIndexSource)); |
| 608 | response->AddTag(CECTag(EC_TAG_STATS_KAD_INDEXED_KEYWORDS, Kademlia::CKademlia::GetIndexed()->m_totalIndexKeyword)); |
| 609 | response->AddTag(CECTag(EC_TAG_STATS_KAD_INDEXED_NOTES, Kademlia::CKademlia::GetIndexed()->m_totalIndexNotes)); |
| 610 | response->AddTag(CECTag(EC_TAG_STATS_KAD_INDEXED_LOAD, Kademlia::CKademlia::GetIndexed()->m_totalIndexLoad)); |
| 611 | response->AddTag(CECTag(EC_TAG_STATS_KAD_IP_ADRESS, wxUINT32_SWAP_ALWAYS(Kademlia::CKademlia::GetPrefs()->GetIPAddress())((wxUint32) ( (((wxUint32) (Kademlia::CKademlia::GetPrefs()-> GetIPAddress()) & (wxUint32) 0x000000ffU) << 24) | ( ((wxUint32) (Kademlia::CKademlia::GetPrefs()->GetIPAddress ()) & (wxUint32) 0x0000ff00U) << 8) | (((wxUint32) ( Kademlia::CKademlia::GetPrefs()->GetIPAddress()) & (wxUint32 ) 0x00ff0000U) >> 8) | (((wxUint32) (Kademlia::CKademlia ::GetPrefs()->GetIPAddress()) & (wxUint32) 0xff000000U ) >> 24))))); |
| 612 | response->AddTag(CECTag(EC_TAG_STATS_KAD_IN_LAN_MODE, Kademlia::CKademlia::IsRunningInLANMode())); |
| 613 | response->AddTag(CECTag(EC_TAG_STATS_BUDDY_STATUS, theApp->clientlist->GetBuddyStatus())); |
| 614 | uint32 BuddyIP = 0; |
| 615 | uint16 BuddyPort = 0; |
| 616 | CUpDownClient * Buddy = theApp->clientlist->GetBuddy(); |
| 617 | if (Buddy) { |
| 618 | BuddyIP = Buddy->GetIP(); |
| 619 | BuddyPort = Buddy->GetUDPPort(); |
| 620 | } |
| 621 | response->AddTag(CECTag(EC_TAG_STATS_BUDDY_IP, BuddyIP)); |
| 622 | response->AddTag(CECTag(EC_TAG_STATS_BUDDY_PORT, BuddyPort)); |
| 623 | } |
| 624 | case EC_DETAIL_UPDATE: |
| 625 | break; |
| 626 | }; |
| 627 | |
| 628 | return response; |
| 629 | } |
| 630 | |
| 631 | static CECPacket *Get_EC_Response_GetSharedFiles(const CECPacket *request, CFileEncoderMap &encoders) |
| 632 | { |
| 633 | wxASSERT(request->GetOpCode() == EC_OP_GET_SHARED_FILES)do { if ( request->GetOpCode() == EC_OP_GET_SHARED_FILES ) { } else if ( wxTheAssertHandler && (wxOnAssert("ExternalConn.cpp" , 633, __FUNCTION__, "request->GetOpCode() == EC_OP_GET_SHARED_FILES" , (const char*)__null), wxTrapInAssert) ) { wxTrapInAssert = false ; asm volatile ("int $3"); } } while ( (void)0, 0 ); |
| 634 | |
| 635 | CECPacket *response = new CECPacket(EC_OP_SHARED_FILES); |
| 636 | |
| 637 | EC_DETAIL_LEVEL detail_level = request->GetDetailLevel(); |
| 638 | // |
| 639 | // request can contain list of queried items |
| 640 | CTagSet<uint32, EC_TAG_KNOWNFILE> queryitems(request); |
| 641 | |
| 642 | encoders.UpdateEncoders(); |
| 643 | |
| 644 | for (uint32 i = 0; i < theApp->sharedfiles->GetFileCount(); ++i) { |
| 645 | const CKnownFile *cur_file = theApp->sharedfiles->GetFileByIndex(i); |
| 646 | |
| 647 | if ( !cur_file || (!queryitems.empty() && !queryitems.count(cur_file->ECID())) ) { |
| 648 | continue; |
| 649 | } |
| 650 | |
| 651 | CEC_SharedFile_Tag filetag(cur_file, detail_level); |
| 652 | CKnownFile_Encoder *enc = encoders[cur_file->ECID()]; |
| 653 | if ( detail_level != EC_DETAIL_UPDATE ) { |
| 654 | enc->ResetEncoder(); |
| 655 | } |
| 656 | enc->Encode(&filetag); |
| 657 | response->AddTag(filetag); |
| 658 | } |
| 659 | return response; |
| 660 | } |
| 661 | |
| 662 | static CECPacket *Get_EC_Response_GetUpdate(CFileEncoderMap &encoders, CObjTagMap &tagmap) |
| 663 | { |
| 664 | CECPacket *response = new CECPacket(EC_OP_SHARED_FILES); |
| 665 | |
| 666 | encoders.UpdateEncoders(); |
| 667 | for (CFileEncoderMap::iterator it = encoders.begin(); it != encoders.end(); ++it) { |
| 668 | const CKnownFile *cur_file = it->second->GetFile(); |
| 669 | CValueMap &valuemap = tagmap.GetValueMap(cur_file->ECID()); |
| 670 | // Completed cleared Partfiles are still stored as CPartfile, |
| 671 | // but encoded as KnownFile, so we have to check the encoder type |
| 672 | // instead of the file type. |
| 673 | if (it->second->IsPartFile_Encoder()) { |
| 674 | CEC_PartFile_Tag filetag(static_cast<const CPartFile*>(cur_file), EC_DETAIL_INC_UPDATE, &valuemap); |
| 675 | // Add information if partfile is shared |
| 676 | filetag.AddTag(EC_TAG_PARTFILE_SHARED, it->second->IsShared(), &valuemap); |
| 677 | |
| 678 | CPartFile_Encoder * enc = static_cast<CPartFile_Encoder *>(encoders[cur_file->ECID()]); |
| 679 | enc->Encode(&filetag); |
| 680 | response->AddTag(filetag); |
| 681 | } else { |
| 682 | CEC_SharedFile_Tag filetag(cur_file, EC_DETAIL_INC_UPDATE, &valuemap); |
| 683 | CKnownFile_Encoder * enc = encoders[cur_file->ECID()]; |
| 684 | enc->Encode(&filetag); |
| 685 | response->AddTag(filetag); |
| 686 | } |
| 687 | } |
| 688 | |
| 689 | // Add clients |
| 690 | CECEmptyTag clients(EC_TAG_CLIENT); |
| 691 | const CClientList::IDMap& clientList = theApp->clientlist->GetClientList(); |
| 692 | bool onlyTransmittingClients = thePrefs::IsTransmitOnlyUploadingClients(); |
| 693 | for (CClientList::IDMap::const_iterator it = clientList.begin(); it != clientList.end(); ++it) { |
| 694 | const CUpDownClient* cur_client = it->second.GetClient(); |
| 695 | if (onlyTransmittingClients && !cur_client->IsDownloading()) { |
| 696 | // For poor CPU cores only transmit uploading clients. This will save a lot of CPU. |
| 697 | // Set ExternalConnect/TransmitOnlyUploadingClients to 1 for it. |
| 698 | continue; |
| 699 | } |
| 700 | CValueMap &valuemap = tagmap.GetValueMap(cur_client->ECID()); |
| 701 | clients.AddTag(CEC_UpDownClient_Tag(cur_client, EC_DETAIL_INC_UPDATE, &valuemap)); |
| 702 | } |
| 703 | response->AddTag(clients); |
| 704 | |
| 705 | // Add servers |
| 706 | CECEmptyTag servers(EC_TAG_SERVER); |
| 707 | std::vector<const CServer*> serverlist = theApp->serverlist->CopySnapshot(); |
| 708 | uint32 nrServers = serverlist.size(); |
| 709 | for (uint32 i = 0; i < nrServers; i++) { |
| 710 | const CServer* cur_server = serverlist[i]; |
| 711 | CValueMap &valuemap = tagmap.GetValueMap(cur_server->ECID()); |
| 712 | servers.AddTag(CEC_Server_Tag(cur_server, &valuemap)); |
| 713 | } |
| 714 | response->AddTag(servers); |
| 715 | |
| 716 | // Add friends |
| 717 | CECEmptyTag friends(EC_TAG_FRIEND); |
| 718 | for (CFriendList::const_iterator it = theApp->friendlist->begin(); it != theApp->friendlist->end(); ++it) { |
| 719 | const CFriend* cur_friend = *it; |
| 720 | CValueMap &valuemap = tagmap.GetValueMap(cur_friend->ECID()); |
| 721 | friends.AddTag(CEC_Friend_Tag(cur_friend, &valuemap)); |
| 722 | } |
| 723 | response->AddTag(friends); |
| 724 | |
| 725 | return response; |
| 726 | } |
| 727 | |
| 728 | static CECPacket *Get_EC_Response_GetClientQueue(const CECPacket *request, CObjTagMap &tagmap, int op) |
| 729 | { |
| 730 | CECPacket *response = new CECPacket(op); |
| 731 | |
| 732 | EC_DETAIL_LEVEL detail_level = request->GetDetailLevel(); |
| 733 | |
| 734 | // |
| 735 | // request can contain list of queried items |
| 736 | // (not for incremental update of course) |
| 737 | CTagSet<uint32, EC_TAG_CLIENT> queryitems(request); |
| 738 | |
| 739 | const CClientRefList& clients = theApp->uploadqueue->GetUploadingList(); |
| 740 | CClientRefList::const_iterator it = clients.begin(); |
| 741 | for (; it != clients.end(); ++it) { |
| 742 | CUpDownClient* cur_client = it->GetClient(); |
| 743 | |
| 744 | if (!cur_client) { // shouldn't happen |
| 745 | continue; |
| 746 | } |
| 747 | if (!queryitems.empty() && !queryitems.count(cur_client->ECID())) { |
| 748 | continue; |
| 749 | } |
| 750 | CValueMap *valuemap = NULL__null; |
| 751 | if (detail_level == EC_DETAIL_INC_UPDATE) { |
| 752 | valuemap = &tagmap.GetValueMap(cur_client->ECID()); |
| 753 | } |
| 754 | CEC_UpDownClient_Tag cli_tag(cur_client, detail_level, valuemap); |
| 755 | |
| 756 | response->AddTag(cli_tag); |
| 757 | } |
| 758 | |
| 759 | return response; |
| 760 | } |
| 761 | |
| 762 | |
| 763 | static CECPacket *Get_EC_Response_GetDownloadQueue(const CECPacket *request, CFileEncoderMap &encoders) |
| 764 | { |
| 765 | CECPacket *response = new CECPacket(EC_OP_DLOAD_QUEUE); |
| 766 | |
| 767 | EC_DETAIL_LEVEL detail_level = request->GetDetailLevel(); |
| 768 | // |
| 769 | // request can contain list of queried items |
| 770 | CTagSet<uint32, EC_TAG_PARTFILE> queryitems(request); |
| 771 | |
| 772 | encoders.UpdateEncoders(); |
| 773 | |
| 774 | for (unsigned int i = 0; i < theApp->downloadqueue->GetFileCount(); i++) { |
| 775 | CPartFile *cur_file = theApp->downloadqueue->GetFileByIndex(i); |
| 776 | |
| 777 | if ( !queryitems.empty() && !queryitems.count(cur_file->ECID()) ) { |
| 778 | continue; |
| 779 | } |
| 780 | |
| 781 | CEC_PartFile_Tag filetag(cur_file, detail_level); |
| 782 | |
| 783 | CPartFile_Encoder * enc = static_cast<CPartFile_Encoder *>(encoders[cur_file->ECID()]); |
| 784 | if ( detail_level != EC_DETAIL_UPDATE ) { |
| 785 | enc->ResetEncoder(); |
| 786 | } |
| 787 | enc->Encode(&filetag); |
| 788 | |
| 789 | response->AddTag(filetag); |
| 790 | } |
| 791 | return response; |
| 792 | } |
| 793 | |
| 794 | |
| 795 | static CECPacket *Get_EC_Response_PartFile_Cmd(const CECPacket *request) |
| 796 | { |
| 797 | CECPacket *response = NULL__null; |
| 798 | |
| 799 | // request can contain multiple files. |
| 800 | for (CECPacket::const_iterator it1 = request->begin(); it1 != request->end(); ++it1) { |
| 801 | const CECTag &hashtag = *it1; |
| 802 | |
| 803 | wxASSERT(hashtag.GetTagName() == EC_TAG_PARTFILE)do { if ( hashtag.GetTagName() == EC_TAG_PARTFILE ) { } else if ( wxTheAssertHandler && (wxOnAssert("ExternalConn.cpp" , 803, __FUNCTION__, "hashtag.GetTagName() == EC_TAG_PARTFILE" , (const char*)__null), wxTrapInAssert) ) { wxTrapInAssert = false ; asm volatile ("int $3"); } } while ( (void)0, 0 ); |
| 804 | |
| 805 | CMD4Hash hash = hashtag.GetMD4Data(); |
| 806 | CPartFile *pfile = theApp->downloadqueue->GetFileByID( hash ); |
| 807 | |
| 808 | if ( !pfile ) { |
| 809 | AddLogLineN(CFormat(_("Remote PartFile command failed: FileHash not found: %s")) % hash.Encode())theLogger.AddLogLine(L"ExternalConn.cpp", 809, false, logStandard , CFormat(wxGetTranslation(("Remote PartFile command failed: FileHash not found: %s" ))) % hash.Encode()); |
| 810 | response = new CECPacket(EC_OP_FAILED); |
| 811 | response->AddTag(CECTag(EC_TAG_STRING, CFormat(wxString(wxTRANSLATE("FileHash not found: %s")"FileHash not found: %s")) % hash.Encode())); |
| 812 | //return response; |
| 813 | break; |
| 814 | } |
| 815 | switch (request->GetOpCode()) { |
| 816 | case EC_OP_PARTFILE_SWAP_A4AF_THIS: |
| 817 | CoreNotify_PartFile_Swap_A4AF(pfile)MuleNotify::DoNotify(&MuleNotify::PartFile_Swap_A4AF, pfile ); |
| 818 | break; |
| 819 | case EC_OP_PARTFILE_SWAP_A4AF_THIS_AUTO: |
| 820 | CoreNotify_PartFile_Swap_A4AF_Auto(pfile)MuleNotify::DoNotify(&MuleNotify::PartFile_Swap_A4AF_Auto , pfile); |
| 821 | break; |
| 822 | case EC_OP_PARTFILE_SWAP_A4AF_OTHERS: |
| 823 | CoreNotify_PartFile_Swap_A4AF_Others(pfile)MuleNotify::DoNotify(&MuleNotify::PartFile_Swap_A4AF_Others , pfile); |
| 824 | break; |
| 825 | case EC_OP_PARTFILE_PAUSE: |
| 826 | pfile->PauseFile(); |
| 827 | break; |
| 828 | case EC_OP_PARTFILE_RESUME: |
| 829 | pfile->ResumeFile(); |
| 830 | pfile->SavePartFile(); |
| 831 | break; |
| 832 | case EC_OP_PARTFILE_STOP: |
| 833 | pfile->StopFile(); |
| 834 | break; |
| 835 | case EC_OP_PARTFILE_PRIO_SET: { |
| 836 | uint8 prio = hashtag.GetFirstTagSafe()->GetInt(); |
| 837 | if ( prio == PR_AUTO5 ) { |
| 838 | pfile->SetAutoDownPriority(1); |
| 839 | } else { |
| 840 | pfile->SetAutoDownPriority(0); |
| 841 | pfile->SetDownPriority(prio); |
| 842 | } |
| 843 | } |
| 844 | break; |
| 845 | case EC_OP_PARTFILE_DELETE: |
| 846 | if ( thePrefs::StartNextFile() && (pfile->GetStatus() != PS_PAUSED7) ) { |
| 847 | theApp->downloadqueue->StartNextFile(pfile); |
| 848 | } |
| 849 | pfile->Delete(); |
| 850 | break; |
| 851 | |
| 852 | case EC_OP_PARTFILE_SET_CAT: |
| 853 | pfile->SetCategory(hashtag.GetFirstTagSafe()->GetInt()); |
| 854 | break; |
| 855 | |
| 856 | default: |
| 857 | response = new CECPacket(EC_OP_FAILED); |
| 858 | response->AddTag(CECTag(EC_TAG_STRING, wxTRANSLATE("OOPS! OpCode processing error!")"OOPS! OpCode processing error!")); |
| 859 | break; |
| 860 | } |
| 861 | } |
| 862 | if (!response) { |
| 863 | response = new CECPacket(EC_OP_NOOP); |
| 864 | } |
| 865 | return response; |
| 866 | } |
| 867 | |
| 868 | static CECPacket *Get_EC_Response_Server_Add(const CECPacket *request) |
| 869 | { |
| 870 | CECPacket *response = NULL__null; |
| 871 | |
| 872 | wxString full_addr = request->GetTagByNameSafe(EC_TAG_SERVER_ADDRESS)->GetStringData(); |
| 873 | wxString name = request->GetTagByNameSafe(EC_TAG_SERVER_NAME)->GetStringData(); |
| 874 | |
| 875 | wxString s_ip = full_addr.Left(full_addr.Find(':')); |
| 876 | wxString s_port = full_addr.Mid(full_addr.Find(':') + 1); |
| 877 | |
| 878 | long port = StrToULong(s_port); |
| 879 | CServer* toadd = new CServer(port, s_ip); |
| 880 | toadd->SetListName(name.IsEmpty() ? full_addr : name); |
| 881 | |
| 882 | if ( theApp->AddServer(toadd, true) ) { |
| 883 | response = new CECPacket(EC_OP_NOOP); |
| 884 | } else { |
| 885 | response = new CECPacket(EC_OP_FAILED); |
| 886 | response->AddTag(CECTag(EC_TAG_STRING, _("Server not added")wxGetTranslation(("Server not added")))); |
| 887 | delete toadd; |
| 888 | } |
| 889 | |
| 890 | return response; |
| 891 | } |
| 892 | |
| 893 | static CECPacket *Get_EC_Response_Server(const CECPacket *request) |
| 894 | { |
| 895 | CECPacket *response = NULL__null; |
| 896 | const CECTag *srv_tag = request->GetTagByName(EC_TAG_SERVER); |
| 897 | CServer *srv = 0; |
| 898 | if ( srv_tag ) { |
| 899 | srv = theApp->serverlist->GetServerByIPTCP(srv_tag->GetIPv4Data().IP(), srv_tag->GetIPv4Data().m_port); |
| 900 | // server tag passed, but server not found |
| 901 | if ( !srv ) { |
| 902 | response = new CECPacket(EC_OP_FAILED); |
| 903 | response->AddTag(CECTag(EC_TAG_STRING, |
| 904 | CFormat(wxString(wxTRANSLATE("server not found: %s")"server not found: %s")) % srv_tag->GetIPv4Data().StringIP())); |
| 905 | return response; |
| 906 | } |
| 907 | } |
| 908 | switch (request->GetOpCode()) { |
| 909 | case EC_OP_SERVER_DISCONNECT: |
| 910 | theApp->serverconnect->Disconnect(); |
| 911 | response = new CECPacket(EC_OP_NOOP); |
| 912 | break; |
| 913 | case EC_OP_SERVER_REMOVE: |
| 914 | if ( srv ) { |
| 915 | theApp->serverlist->RemoveServer(srv); |
| 916 | response = new CECPacket(EC_OP_NOOP); |
| 917 | } else { |
| 918 | response = new CECPacket(EC_OP_FAILED); |
| 919 | response->AddTag(CECTag(EC_TAG_STRING, |
| 920 | wxTRANSLATE("need to define server to be removed")"need to define server to be removed")); |
| 921 | } |
| 922 | break; |
| 923 | case EC_OP_SERVER_CONNECT: |
| 924 | if (thePrefs::GetNetworkED2K()) { |
| 925 | if ( srv ) { |
| 926 | theApp->serverconnect->ConnectToServer(srv); |
| 927 | response = new CECPacket(EC_OP_NOOP); |
| 928 | } else { |
| 929 | theApp->serverconnect->ConnectToAnyServer(); |
| 930 | response = new CECPacket(EC_OP_NOOP); |
| 931 | } |
| 932 | } else { |
| 933 | response = new CECPacket(EC_OP_FAILED); |
| 934 | response->AddTag(CECTag(EC_TAG_STRING, wxTRANSLATE("eD2k is disabled in preferences.")"eD2k is disabled in preferences.")); |
| 935 | } |
| 936 | break; |
| 937 | } |
| 938 | if (!response) { |
| 939 | response = new CECPacket(EC_OP_FAILED); |
| 940 | response->AddTag(CECTag(EC_TAG_STRING, wxTRANSLATE("OOPS! OpCode processing error!")"OOPS! OpCode processing error!")); |
| 941 | } |
| 942 | return response; |
| 943 | } |
| 944 | |
| 945 | |
| 946 | static CECPacket *Get_EC_Response_Friend(const CECPacket *request) |
| 947 | { |
| 948 | CECPacket *response = NULL__null; |
| 949 | const CECTag *tag = request->GetTagByName(EC_TAG_FRIEND_ADD); |
| 950 | if (tag) { |
| 951 | const CECTag *subtag = tag->GetTagByName(EC_TAG_CLIENT); |
| 952 | if (subtag) { |
| 953 | CUpDownClient * client = theApp->clientlist->FindClientByECID(subtag->GetInt()); |
| 954 | if (client) { |
| 955 | theApp->friendlist->AddFriend(CCLIENTREF(client, wxT("Get_EC_Response_Friend theApp->friendlist->AddFriend"))CClientRef(client)); |
| 956 | response = new CECPacket(EC_OP_NOOP); |
| 957 | } |
| 958 | } else { |
| 959 | const CECTag *hashtag = tag->GetTagByName(EC_TAG_FRIEND_HASH); |
| 960 | const CECTag *iptag = tag->GetTagByName(EC_TAG_FRIEND_IP); |
| 961 | const CECTag *porttag = tag->GetTagByName(EC_TAG_FRIEND_PORT); |
| 962 | const CECTag *nametag = tag->GetTagByName(EC_TAG_FRIEND_NAME); |
| 963 | if (hashtag && iptag && porttag && nametag) { |
| 964 | theApp->friendlist->AddFriend(hashtag->GetMD4Data(), iptag->GetInt(), porttag->GetInt(), nametag->GetStringData()); |
| 965 | response = new CECPacket(EC_OP_NOOP); |
| 966 | } |
| 967 | } |
| 968 | } else if ((tag = request->GetTagByName(EC_TAG_FRIEND_REMOVE))) { |
| 969 | const CECTag *subtag = tag->GetTagByName(EC_TAG_FRIEND); |
| 970 | if (subtag) { |
| 971 | CFriend * Friend = theApp->friendlist->FindFriend(subtag->GetInt()); |
| 972 | if (Friend) { |
| 973 | theApp->friendlist->RemoveFriend(Friend); |
| 974 | response = new CECPacket(EC_OP_NOOP); |
| 975 | } |
| 976 | } |
| 977 | } else if ((tag = request->GetTagByName(EC_TAG_FRIEND_FRIENDSLOT))) { |
| 978 | const CECTag *subtag = tag->GetTagByName(EC_TAG_FRIEND); |
| 979 | if (subtag) { |
| 980 | CFriend * Friend = theApp->friendlist->FindFriend(subtag->GetInt()); |
| 981 | if (Friend) { |
| 982 | theApp->friendlist->SetFriendSlot(Friend, tag->GetInt() != 0); |
| 983 | response = new CECPacket(EC_OP_NOOP); |
| 984 | } |
| 985 | } |
| 986 | } else if ((tag = request->GetTagByName(EC_TAG_FRIEND_SHARED))) { |
Although the value stored to 'tag' is used in the enclosing expression, the value is never actually read from 'tag' | |
| 987 | response = new CECPacket(EC_OP_FAILED); |
| 988 | response->AddTag(CECTag(EC_TAG_STRING, wxT("Request shared files list not implemented yet.")L"Request shared files list not implemented yet.")); |
| 989 | #if 0 |
| 990 | // This works fine - but there is no way atm to transfer the results to amulegui, so disable it for now. |
| 991 | |
| 992 | const CECTag *subtag = tag->GetTagByName(EC_TAG_FRIEND); |
| 993 | if (subtag) { |
| 994 | CFriend * Friend = theApp->friendlist->FindFriend(subtag->GetInt()); |
| 995 | if (Friend) { |
| 996 | theApp->friendlist->RequestSharedFileList(Friend); |
| 997 | response = new CECPacket(EC_OP_NOOP); |
| 998 | } |
| 999 | } else if ((subtag = tag->GetTagByName(EC_TAG_CLIENT))) { |
| 1000 | CUpDownClient * client = theApp->clientlist->FindClientByECID(subtag->GetInt()); |
| 1001 | if (client) { |
| 1002 | client->RequestSharedFileList(); |
| 1003 | response = new CECPacket(EC_OP_NOOP); |
| 1004 | } |
| 1005 | } |
| 1006 | #endif |
| 1007 | } |
| 1008 | |
| 1009 | if (!response) { |
| 1010 | response = new CECPacket(EC_OP_FAILED); |
| 1011 | response->AddTag(CECTag(EC_TAG_STRING, wxTRANSLATE("OOPS! OpCode processing error!")"OOPS! OpCode processing error!")); |
| 1012 | } |
| 1013 | return response; |
| 1014 | } |
| 1015 | |
| 1016 | |
| 1017 | static CECPacket *Get_EC_Response_Search_Results(const CECPacket *request) |
| 1018 | { |
| 1019 | CECPacket *response = new CECPacket(EC_OP_SEARCH_RESULTS); |
| 1020 | |
| 1021 | EC_DETAIL_LEVEL detail_level = request->GetDetailLevel(); |
| 1022 | // |
| 1023 | // request can contain list of queried items |
| 1024 | CTagSet<uint32, EC_TAG_SEARCHFILE> queryitems(request); |
| 1025 | |
| 1026 | const CSearchResultList& list = theApp->searchlist->GetSearchResults(0xffffffff); |
| 1027 | CSearchResultList::const_iterator it = list.begin(); |
| 1028 | while (it != list.end()) { |
| 1029 | CSearchFile* sf = *it++; |
| 1030 | if ( !queryitems.empty() && !queryitems.count(sf->ECID()) ) { |
| 1031 | continue; |
| 1032 | } |
| 1033 | response->AddTag(CEC_SearchFile_Tag(sf, detail_level)); |
| 1034 | } |
| 1035 | return response; |
| 1036 | } |
| 1037 | |
| 1038 | static CECPacket *Get_EC_Response_Search_Results(CObjTagMap &tagmap) |
| 1039 | { |
| 1040 | CECPacket *response = new CECPacket(EC_OP_SEARCH_RESULTS); |
| 1041 | |
| 1042 | const CSearchResultList& list = theApp->searchlist->GetSearchResults(0xffffffff); |
| 1043 | CSearchResultList::const_iterator it = list.begin(); |
| 1044 | while (it != list.end()) { |
| 1045 | CSearchFile* sf = *it++; |
| 1046 | CValueMap &valuemap = tagmap.GetValueMap(sf->ECID()); |
| 1047 | response->AddTag(CEC_SearchFile_Tag(sf, EC_DETAIL_INC_UPDATE, &valuemap)); |
| 1048 | // Add the children |
| 1049 | if (sf->HasChildren()) { |
| 1050 | const CSearchResultList& children = sf->GetChildren(); |
| 1051 | for (size_t i = 0; i < children.size(); ++i) { |
| 1052 | CSearchFile* sfc = children.at(i); |
| 1053 | CValueMap &valuemap1 = tagmap.GetValueMap(sfc->ECID()); |
| 1054 | response->AddTag(CEC_SearchFile_Tag(sfc, EC_DETAIL_INC_UPDATE, &valuemap1)); |
| 1055 | } |
| 1056 | } |
| 1057 | } |
| 1058 | return response; |
| 1059 | } |
| 1060 | |
| 1061 | static CECPacket *Get_EC_Response_Search_Results_Download(const CECPacket *request) |
| 1062 | { |
| 1063 | CECPacket *response = new CECPacket(EC_OP_STRINGS); |
| 1064 | for (CECPacket::const_iterator it = request->begin(); it != request->end(); ++it) { |
| 1065 | const CECTag &tag = *it; |
| 1066 | CMD4Hash hash = tag.GetMD4Data(); |
| 1067 | uint8 category = tag.GetFirstTagSafe()->GetInt(); |
| 1068 | theApp->searchlist->AddFileToDownloadByHash(hash, category); |
| 1069 | } |
| 1070 | return response; |
| 1071 | } |
| 1072 | |
| 1073 | static CECPacket *Get_EC_Response_Search_Stop(const CECPacket *WXUNUSED(request)) |
| 1074 | { |
| 1075 | CECPacket *reply = new CECPacket(EC_OP_MISC_DATA); |
| 1076 | theApp->searchlist->StopSearch(); |
| 1077 | return reply; |
| 1078 | } |
| 1079 | |
| 1080 | static CECPacket *Get_EC_Response_Search(const CECPacket *request) |
| 1081 | { |
| 1082 | wxString response; |
| 1083 | |
| 1084 | const CEC_Search_Tag *search_request = static_cast<const CEC_Search_Tag *>(request->GetFirstTagSafe()); |
| 1085 | theApp->searchlist->RemoveResults(0xffffffff); |
| 1086 | |
| 1087 | CSearchList::CSearchParams params; |
| 1088 | params.searchString = search_request->SearchText(); |
| 1089 | params.typeText = search_request->SearchFileType(); |
| 1090 | params.extension = search_request->SearchExt(); |
| 1091 | params.minSize = search_request->MinSize(); |
| 1092 | params.maxSize = search_request->MaxSize(); |
| 1093 | params.availability = search_request->Avail(); |
| 1094 | |
| 1095 | |
| 1096 | EC_SEARCH_TYPE search_type = search_request->SearchType(); |
| 1097 | SearchType core_search_type = LocalSearch; |
| 1098 | uint32 op = EC_OP_FAILED; |
| 1099 | switch (search_type) { |
| 1100 | case EC_SEARCH_GLOBAL: |
| 1101 | core_search_type = GlobalSearch; |
| 1102 | /* fall through */ |
| 1103 | case EC_SEARCH_KAD: |
| 1104 | if (core_search_type != GlobalSearch) { // Not a global search obviously |
| 1105 | core_search_type = KadSearch; |
| 1106 | } |
| 1107 | /* fall through */ |
| 1108 | case EC_SEARCH_LOCAL: { |
| 1109 | uint32 search_id = 0xffffffff; |
| 1110 | wxString error = theApp->searchlist->StartNewSearch(&search_id, core_search_type, params); |
| 1111 | if (!error.IsEmpty()) { |
| 1112 | response = error; |
| 1113 | } else { |
| 1114 | response = wxTRANSLATE("Search in progress. Refetch results in a moment!")"Search in progress. Refetch results in a moment!"; |
| 1115 | op = EC_OP_STRINGS; |
| 1116 | } |
| 1117 | break; |
| 1118 | } |
| 1119 | case EC_SEARCH_WEB: |
| 1120 | response = wxTRANSLATE("WebSearch from remote interface makes no sense.")"WebSearch from remote interface makes no sense."; |
| 1121 | break; |
| 1122 | } |
| 1123 | |
| 1124 | CECPacket *reply = new CECPacket(op); |
| 1125 | // error or search in progress |
| 1126 | reply->AddTag(CECTag(EC_TAG_STRING, response)); |
| 1127 | |
| 1128 | return reply; |
| 1129 | } |
| 1130 | |
| 1131 | static CECPacket *Get_EC_Response_Set_SharedFile_Prio(const CECPacket *request) |
| 1132 | { |
| 1133 | CECPacket *response = new CECPacket(EC_OP_NOOP); |
| 1134 | for (CECPacket::const_iterator it = request->begin(); it != request->end(); ++it) { |
| 1135 | const CECTag &tag = *it; |
| 1136 | CMD4Hash hash = tag.GetMD4Data(); |
| 1137 | uint8 prio = tag.GetFirstTagSafe()->GetInt(); |
| 1138 | CKnownFile* cur_file = theApp->sharedfiles->GetFileByID(hash); |
| 1139 | if ( !cur_file ) { |
| 1140 | continue; |
| 1141 | } |
| 1142 | if (prio == PR_AUTO5) { |
| 1143 | cur_file->SetAutoUpPriority(1); |
| 1144 | cur_file->UpdateAutoUpPriority(); |
| 1145 | } else { |
| 1146 | cur_file->SetAutoUpPriority(0); |
| 1147 | cur_file->SetUpPriority(prio); |
| 1148 | } |
| 1149 | Notify_SharedFilesUpdateItem(cur_file)MuleNotify::DoNotify(&MuleNotify::SharedFilesUpdateItem, cur_file ); |
| 1150 | } |
| 1151 | |
| 1152 | return response; |
| 1153 | } |
| 1154 | |
| 1155 | void CPartFile_Encoder::Encode(CECTag *parent) |
| 1156 | { |
| 1157 | // |
| 1158 | // Source part frequencies |
| 1159 | // |
| 1160 | CKnownFile_Encoder::Encode(parent); |
| 1161 | |
| 1162 | // |
| 1163 | // Gaps |
| 1164 | // |
| 1165 | const CGapList& gaplist = m_PartFile()->GetGapList(); |
| 1166 | const size_t gap_list_size = gaplist.size(); |
| 1167 | ArrayOfUInts64 gaps; |
| 1168 | gaps.reserve(gap_list_size * 2); |
| 1169 | |
| 1170 | for (CGapList::const_iterator curr_pos = gaplist.begin(); |
| 1171 | curr_pos != gaplist.end(); ++curr_pos) { |
| 1172 | gaps.push_back(curr_pos.start()); |
| 1173 | gaps.push_back(curr_pos.end()); |
| 1174 | } |
| 1175 | |
| 1176 | int gap_enc_size = 0; |
| 1177 | bool changed; |
| 1178 | const uint8 *gap_enc_data = m_gap_status.Encode(gaps, gap_enc_size, changed); |
| 1179 | if (changed) { |
| 1180 | parent->AddTag(CECTag(EC_TAG_PARTFILE_GAP_STATUS, gap_enc_size, (void *)gap_enc_data)); |
| 1181 | } |
| 1182 | delete[] gap_enc_data; |
| 1183 | |
| 1184 | // |
| 1185 | // Requested blocks |
| 1186 | // |
| 1187 | ArrayOfUInts64 req_buffer; |
| 1188 | const CPartFile::CReqBlockPtrList& requestedblocks = m_PartFile()->GetRequestedBlockList(); |
| 1189 | CPartFile::CReqBlockPtrList::const_iterator curr_pos2 = requestedblocks.begin(); |
| 1190 | |
| 1191 | for ( ; curr_pos2 != requestedblocks.end(); ++curr_pos2 ) { |
| 1192 | Requested_Block_Struct* block = *curr_pos2; |
| 1193 | req_buffer.push_back(block->StartOffset); |
| 1194 | req_buffer.push_back(block->EndOffset); |
| 1195 | } |
| 1196 | int req_enc_size = 0; |
| 1197 | const uint8 *req_enc_data = m_req_status.Encode(req_buffer, req_enc_size, changed); |
| 1198 | if (changed) { |
| 1199 | parent->AddTag(CECTag(EC_TAG_PARTFILE_REQ_STATUS, req_enc_size, (void *)req_enc_data)); |
| 1200 | } |
| 1201 | delete[] req_enc_data; |
| 1202 | |
| 1203 | // |
| 1204 | // Source names |
| 1205 | // |
| 1206 | // First count occurrence of all source names |
| 1207 | // |
| 1208 | CECEmptyTag sourceNames(EC_TAG_PARTFILE_SOURCE_NAMES); |
| 1209 | typedef std::map<wxString, int> strIntMap; |
| 1210 | strIntMap nameMap; |
| 1211 | const CPartFile::SourceSet &sources = m_PartFile()->GetSourceList(); |
| 1212 | for (CPartFile::SourceSet::const_iterator it = sources.begin(); it != sources.end(); ++it) { |
| 1213 | const CClientRef &cur_src = *it; |
| 1214 | if (cur_src.GetRequestFile() != m_file || cur_src.GetClientFilename().Length() == 0) { |
| 1215 | continue; |
| 1216 | } |
| 1217 | const wxString &name = cur_src.GetClientFilename(); |
| 1218 | strIntMap::iterator itm = nameMap.find(name); |
| 1219 | if (itm == nameMap.end()) { |
| 1220 | nameMap[name] = 1; |
| 1221 | } else { |
| 1222 | itm->second++; |
| 1223 | } |
| 1224 | } |
| 1225 | // |
| 1226 | // Go through our last list |
| 1227 | // |
| 1228 | for (SourcenameItemMap::iterator it1 = m_sourcenameItemMap.begin(); it1 != m_sourcenameItemMap.end();) { |
| 1229 | SourcenameItemMap::iterator it2 = it1++; |
| 1230 | strIntMap::iterator itm = nameMap.find(it2->second.name); |
| 1231 | if (itm == nameMap.end()) { |
| 1232 | // name doesn't exist anymore, tell client to forget it |
| 1233 | CECTag tag(EC_TAG_PARTFILE_SOURCE_NAMES, it2->first); |
| 1234 | tag.AddTag(CECIntTag(EC_TAG_PARTFILE_SOURCE_NAMES_COUNTS, 0)); |
| 1235 | sourceNames.AddTag(tag); |
| 1236 | // and forget it |
| 1237 | m_sourcenameItemMap.erase(it2); |
| 1238 | } else { |
| 1239 | // update count if it changed |
| 1240 | if (it2->second.count != itm->second) { |
| 1241 | CECTag tag(EC_TAG_PARTFILE_SOURCE_NAMES, it2->first); |
| 1242 | tag.AddTag(CECIntTag(EC_TAG_PARTFILE_SOURCE_NAMES_COUNTS, itm->second)); |
| 1243 | sourceNames.AddTag(tag); |
| 1244 | it2->second.count = itm->second; |
| 1245 | } |
| 1246 | // remove it from nameMap so that only new names are left there |
| 1247 | nameMap.erase(itm); |
| 1248 | } |
| 1249 | } |
| 1250 | // |
| 1251 | // Add new names |
| 1252 | // |
| 1253 | for (strIntMap::iterator it3 = nameMap.begin(); it3 != nameMap.end(); ++it3) { |
| 1254 | int id = ++m_sourcenameID; |
| 1255 | CECIntTag tag(EC_TAG_PARTFILE_SOURCE_NAMES, id); |
| 1256 | tag.AddTag(CECTag(EC_TAG_PARTFILE_SOURCE_NAMES, it3->first)); |
| 1257 | tag.AddTag(CECIntTag(EC_TAG_PARTFILE_SOURCE_NAMES_COUNTS, it3->second)); |
| 1258 | sourceNames.AddTag(tag); |
| 1259 | // remember it |
| 1260 | m_sourcenameItemMap[id] = SourcenameItem(it3->first, it3->second); |
| 1261 | } |
| 1262 | if (sourceNames.HasChildTags()) { |
| 1263 | parent->AddTag(sourceNames); |
| 1264 | } |
| 1265 | |
| 1266 | } |
| 1267 | |
| 1268 | void CPartFile_Encoder::ResetEncoder() |
| 1269 | { |
| 1270 | CKnownFile_Encoder::ResetEncoder(); |
| 1271 | m_gap_status.ResetEncoder(); |
| 1272 | m_req_status.ResetEncoder(); |
| 1273 | } |
| 1274 | |
| 1275 | void CKnownFile_Encoder::Encode(CECTag *parent) |
| 1276 | { |
| 1277 | // |
| 1278 | // Source part frequencies |
| 1279 | // |
| 1280 | // Reference to the availability list |
| 1281 | const ArrayOfUInts16& list = m_file->IsPartFile() ? |
| 1282 | static_cast<const CPartFile*>(m_file)->m_SrcpartFrequency : |
| 1283 | m_file->m_AvailPartFrequency; |
| 1284 | // Don't add tag if available parts aren't populated yet. |
| 1285 | if (!list.empty()) { |
| 1286 | int part_enc_size; |
| 1287 | bool changed; |
| 1288 | const uint8 *part_enc_data = m_enc_data.Encode(list, part_enc_size, changed); |
| 1289 | if (changed) { |
| 1290 | parent->AddTag(CECTag(EC_TAG_PARTFILE_PART_STATUS, part_enc_size, part_enc_data)); |
| 1291 | } |
| 1292 | delete[] part_enc_data; |
| 1293 | } |
| 1294 | } |
| 1295 | |
| 1296 | static CECPacket *GetStatsGraphs(const CECPacket *request) |
| 1297 | { |
| 1298 | CECPacket *response = NULL__null; |
| 1299 | |
| 1300 | switch (request->GetDetailLevel()) { |
| 1301 | case EC_DETAIL_WEB: |
| 1302 | case EC_DETAIL_FULL: { |
| 1303 | double dTimestamp = 0.0; |
| 1304 | if (request->GetTagByName(EC_TAG_STATSGRAPH_LAST) != NULL__null) { |
| 1305 | dTimestamp = request->GetTagByName(EC_TAG_STATSGRAPH_LAST)->GetDoubleData(); |
| 1306 | } |
| 1307 | uint16 nScale = request->GetTagByNameSafe(EC_TAG_STATSGRAPH_SCALE)->GetInt(); |
| 1308 | uint16 nMaxPoints = request->GetTagByNameSafe(EC_TAG_STATSGRAPH_WIDTH)->GetInt(); |
| 1309 | uint32 *graphData; |
| 1310 | unsigned int numPoints = theApp->m_statistics->GetHistoryForWeb(nMaxPoints, (double)nScale, &dTimestamp, &graphData); |
| 1311 | if (numPoints) { |
| 1312 | response = new CECPacket(EC_OP_STATSGRAPHS); |
| 1313 | response->AddTag(CECTag(EC_TAG_STATSGRAPH_DATA, 4 * numPoints * sizeof(uint32), graphData)); |
| 1314 | delete [] graphData; |
| 1315 | response->AddTag(CECTag(EC_TAG_STATSGRAPH_LAST, dTimestamp)); |
| 1316 | } else { |
| 1317 | response = new CECPacket(EC_OP_FAILED); |
| 1318 | response->AddTag(CECTag(EC_TAG_STRING, wxTRANSLATE("No points for graph.")"No points for graph.")); |
| 1319 | } |
| 1320 | break; |
| 1321 | } |
| 1322 | case EC_DETAIL_INC_UPDATE: |
| 1323 | case EC_DETAIL_UPDATE: |
| 1324 | case EC_DETAIL_CMD: |
| 1325 | // No graphs |
| 1326 | response = new CECPacket(EC_OP_FAILED); |
| 1327 | response->AddTag(CECTag(EC_TAG_STRING, wxTRANSLATE("Your client is not configured for this detail level.")"Your client is not configured for this detail level.")); |
| 1328 | break; |
| 1329 | } |
| 1330 | if (!response) { |
| 1331 | response = new CECPacket(EC_OP_FAILED); |
| 1332 | // Unknown reason |
| 1333 | } |
| 1334 | |
| 1335 | return response; |
| 1336 | } |
| 1337 | |
| 1338 | CECPacket *CECServerSocket::ProcessRequest2(const CECPacket *request) |
| 1339 | { |
| 1340 | |
| 1341 | if ( !request ) { |
| 1342 | return 0; |
| 1343 | } |
| 1344 | |
| 1345 | CECPacket *response = NULL__null; |
| 1346 | |
| 1347 | switch (request->GetOpCode()) { |
| 1348 | // |
| 1349 | // Misc commands |
| 1350 | // |
| 1351 | case EC_OP_SHUTDOWN: |
| 1352 | if (!theApp->IsOnShutDown()) { |
| 1353 | response = new CECPacket(EC_OP_NOOP); |
| 1354 | AddLogLineC(_("External Connection: shutdown requested"))theLogger.AddLogLine(L"ExternalConn.cpp", 1354, true, logStandard , wxGetTranslation(("External Connection: shutdown requested" ))); |
| 1355 | #ifndef AMULE_DAEMON |
| 1356 | { |
| 1357 | wxCloseEvent evt; |
| 1358 | evt.SetCanVeto(false); |
| 1359 | theApp->ShutDown(evt); |
| 1360 | } |
| 1361 | #else |
| 1362 | theApp->ExitMainLoop(); |
| 1363 | #endif |
| 1364 | } else { |
| 1365 | response = new CECPacket(EC_OP_FAILED); |
| 1366 | response->AddTag(CECTag(EC_TAG_STRING, wxTRANSLATE("Already shutting down.")"Already shutting down.")); |
| 1367 | } |
| 1368 | break; |
| 1369 | case EC_OP_ADD_LINK: |
| 1370 | for (CECPacket::const_iterator it = request->begin(); it != request->end(); ++it) { |
| 1371 | const CECTag &tag = *it; |
| 1372 | wxString link = tag.GetStringData(); |
| 1373 | int category = 0; |
| 1374 | const CECTag *cattag = tag.GetTagByName(EC_TAG_PARTFILE_CAT); |
| 1375 | if (cattag) { |
| 1376 | category = cattag->GetInt(); |
| 1377 | } |
| 1378 | AddLogLineC(CFormat(_("ExternalConn: adding link '%s'.")) % link)theLogger.AddLogLine(L"ExternalConn.cpp", 1378, true, logStandard , CFormat(wxGetTranslation(("ExternalConn: adding link '%s'." ))) % link); |
| 1379 | if (response) { |
| 1380 | delete response; |
| 1381 | } |
| 1382 | if ( theApp->downloadqueue->AddLink(link, category) ) { |
| 1383 | response = new CECPacket(EC_OP_NOOP); |
| 1384 | } else { |
| 1385 | // Error messages are printed by the add function. |
| 1386 | response = new CECPacket(EC_OP_FAILED); |
| 1387 | response->AddTag(CECTag(EC_TAG_STRING, wxTRANSLATE("Invalid link or already on list.")"Invalid link or already on list.")); |
| 1388 | } |
| 1389 | } |
| 1390 | break; |
| 1391 | // |
| 1392 | // Status requests |
| 1393 | // |
| 1394 | case EC_OP_STAT_REQ: |
| 1395 | response = Get_EC_Response_StatRequest(request, m_LoggerAccess); |
| 1396 | response->AddTag(CEC_ConnState_Tag(request->GetDetailLevel())); |
| 1397 | break; |
| 1398 | case EC_OP_GET_CONNSTATE: |
| 1399 | response = new CECPacket(EC_OP_MISC_DATA); |
| 1400 | response->AddTag(CEC_ConnState_Tag(request->GetDetailLevel())); |
| 1401 | break; |
| 1402 | // |
| 1403 | // |
| 1404 | // |
| 1405 | case EC_OP_GET_SHARED_FILES: |
| 1406 | if ( request->GetDetailLevel() != EC_DETAIL_INC_UPDATE ) { |
| 1407 | response = Get_EC_Response_GetSharedFiles(request, m_FileEncoder); |
| 1408 | } |
| 1409 | break; |
| 1410 | case EC_OP_GET_DLOAD_QUEUE: |
| 1411 | if ( request->GetDetailLevel() != EC_DETAIL_INC_UPDATE ) { |
| 1412 | response = Get_EC_Response_GetDownloadQueue(request, m_FileEncoder); |
| 1413 | } |
| 1414 | break; |
| 1415 | // |
| 1416 | // This will evolve into an update-all for inc tags |
| 1417 | // |
| 1418 | case EC_OP_GET_UPDATE: |
| 1419 | if ( request->GetDetailLevel() == EC_DETAIL_INC_UPDATE ) { |
| 1420 | response = Get_EC_Response_GetUpdate(m_FileEncoder, m_obj_tagmap); |
| 1421 | } |
| 1422 | break; |
| 1423 | case EC_OP_GET_ULOAD_QUEUE: |
| 1424 | response = Get_EC_Response_GetClientQueue(request, m_obj_tagmap, EC_OP_ULOAD_QUEUE); |
| 1425 | break; |
| 1426 | case EC_OP_PARTFILE_SWAP_A4AF_THIS: |
| 1427 | case EC_OP_PARTFILE_SWAP_A4AF_THIS_AUTO: |
| 1428 | case EC_OP_PARTFILE_SWAP_A4AF_OTHERS: |
| 1429 | case EC_OP_PARTFILE_PAUSE: |
| 1430 | case EC_OP_PARTFILE_RESUME: |
| 1431 | case EC_OP_PARTFILE_STOP: |
| 1432 | case EC_OP_PARTFILE_PRIO_SET: |
| 1433 | case EC_OP_PARTFILE_DELETE: |
| 1434 | case EC_OP_PARTFILE_SET_CAT: |
| 1435 | response = Get_EC_Response_PartFile_Cmd(request); |
| 1436 | break; |
| 1437 | case EC_OP_SHAREDFILES_RELOAD: |
| 1438 | theApp->sharedfiles->Reload(); |
| 1439 | response = new CECPacket(EC_OP_NOOP); |
| 1440 | break; |
| 1441 | case EC_OP_SHARED_SET_PRIO: |
| 1442 | response = Get_EC_Response_Set_SharedFile_Prio(request); |
| 1443 | break; |
| 1444 | case EC_OP_RENAME_FILE: { |
| 1445 | CMD4Hash fileHash = request->GetTagByNameSafe(EC_TAG_KNOWNFILE)->GetMD4Data(); |
| 1446 | wxString newName = request->GetTagByNameSafe(EC_TAG_PARTFILE_NAME)->GetStringData(); |
| 1447 | // search first in downloadqueue - it might be in known files as well |
| 1448 | CKnownFile* file = theApp->downloadqueue->GetFileByID(fileHash); |
| 1449 | if (!file) { |
| 1450 | file = theApp->knownfiles->FindKnownFileByID(fileHash); |
| 1451 | } |
| 1452 | if (!file) { |
| 1453 | response = new CECPacket(EC_OP_FAILED); |
| 1454 | response->AddTag(CECTag(EC_TAG_STRING, wxTRANSLATE("File not found.")"File not found.")); |
| 1455 | break; |
| 1456 | } |
| 1457 | if (newName.IsEmpty()) { |
| 1458 | response = new CECPacket(EC_OP_FAILED); |
| 1459 | response->AddTag(CECTag(EC_TAG_STRING, wxTRANSLATE("Invalid file name.")"Invalid file name.")); |
| 1460 | break; |
| 1461 | } |
| 1462 | |
| 1463 | if (theApp->sharedfiles->RenameFile(file, CPath(newName))) { |
| 1464 | response = new CECPacket(EC_OP_NOOP); |
| 1465 | } else { |
| 1466 | response = new CECPacket(EC_OP_FAILED); |
| 1467 | response->AddTag(CECTag(EC_TAG_STRING, wxTRANSLATE("Unable to rename file.")"Unable to rename file.")); |
| 1468 | } |
| 1469 | |
| 1470 | break; |
| 1471 | } |
| 1472 | case EC_OP_CLEAR_COMPLETED: { |
| 1473 | ListOfUInts32 toClear; |
| 1474 | for (CECTag::const_iterator it = request->begin(); it != request->end(); ++it) { |
| 1475 | if (it->GetTagName() == EC_TAG_ECID) { |
| 1476 | toClear.push_back(it->GetInt()); |
| 1477 | } |
| 1478 | } |
| 1479 | theApp->downloadqueue->ClearCompleted(toClear); |
| 1480 | response = new CECPacket(EC_OP_NOOP); |
| 1481 | break; |
| 1482 | } |
| 1483 | case EC_OP_CLIENT_SWAP_TO_ANOTHER_FILE: { |
| 1484 | theApp->sharedfiles->Reload(); |
| 1485 | uint32 idClient = request->GetTagByNameSafe(EC_TAG_CLIENT)->GetInt(); |
| 1486 | CUpDownClient * client = theApp->clientlist->FindClientByECID(idClient); |
| 1487 | CMD4Hash idFile = request->GetTagByNameSafe(EC_TAG_PARTFILE)->GetMD4Data(); |
| 1488 | CPartFile * file = theApp->downloadqueue->GetFileByID(idFile); |
| 1489 | if (client && file) { |
| 1490 | client->SwapToAnotherFile( true, false, false, file); |
| 1491 | } |
| 1492 | response = new CECPacket(EC_OP_NOOP); |
| 1493 | break; |
| 1494 | } |
| 1495 | case EC_OP_SHARED_FILE_SET_COMMENT: { |
| 1496 | CMD4Hash hash = request->GetTagByNameSafe(EC_TAG_KNOWNFILE)->GetMD4Data(); |
| 1497 | CKnownFile * file = theApp->sharedfiles->GetFileByID(hash); |
| 1498 | if (file) { |
| 1499 | wxString newComment = request->GetTagByNameSafe(EC_TAG_KNOWNFILE_COMMENT)->GetStringData(); |
| 1500 | uint8 newRating = request->GetTagByNameSafe(EC_TAG_KNOWNFILE_RATING)->GetInt(); |
| 1501 | CoreNotify_KnownFile_Comment_Set(file, newComment, newRating)MuleNotify::DoNotify(&MuleNotify::KnownFile_Comment_Set, file , newComment, newRating); |
| 1502 | } |
| 1503 | response = new CECPacket(EC_OP_NOOP); |
| 1504 | break; |
| 1505 | } |
| 1506 | |
| 1507 | // |
| 1508 | // Server commands |
| 1509 | // |
| 1510 | case EC_OP_SERVER_ADD: |
| 1511 | response = Get_EC_Response_Server_Add(request); |
| 1512 | break; |
| 1513 | case EC_OP_SERVER_DISCONNECT: |
| 1514 | case EC_OP_SERVER_CONNECT: |
| 1515 | case EC_OP_SERVER_REMOVE: |
| 1516 | response = Get_EC_Response_Server(request); |
| 1517 | break; |
| 1518 | case EC_OP_GET_SERVER_LIST: { |
| 1519 | response = new CECPacket(EC_OP_SERVER_LIST); |
| 1520 | if (!thePrefs::GetNetworkED2K()) { |
| 1521 | // Kad only: just send an empty list |
| 1522 | break; |
| 1523 | } |
| 1524 | EC_DETAIL_LEVEL detail_level = request->GetDetailLevel(); |
| 1525 | std::vector<const CServer*> servers = theApp->serverlist->CopySnapshot(); |
| 1526 | for ( |
| 1527 | std::vector<const CServer*>::const_iterator it = servers.begin(); |
| 1528 | it != servers.end(); |
| 1529 | ++it |
| 1530 | ) { |
| 1531 | response->AddTag(CEC_Server_Tag(*it, detail_level)); |
| 1532 | } |
| 1533 | } |
| 1534 | break; |
| 1535 | case EC_OP_SERVER_UPDATE_FROM_URL: { |
| 1536 | wxString url = request->GetFirstTagSafe()->GetStringData(); |
| 1537 | |
| 1538 | // Save the new url, and update the UI (if not amuled). |
| 1539 | Notify_ServersURLChanged(url)MuleNotify::DoNotify(&MuleNotify::ServersURLChanged, url); |
| 1540 | thePrefs::SetEd2kServersUrl(url); |
| 1541 | |
| 1542 | theApp->serverlist->UpdateServerMetFromURL(url); |
| 1543 | response = new CECPacket(EC_OP_NOOP); |
| 1544 | break; |
| 1545 | } |
| 1546 | case EC_OP_SERVER_SET_STATIC_PRIO: { |
| 1547 | uint32 ecid = request->GetTagByNameSafe(EC_TAG_SERVER)->GetInt(); |
| 1548 | CServer * server = theApp->serverlist->GetServerByECID(ecid); |
| 1549 | if (server) { |
| 1550 | const CECTag * staticTag = request->GetTagByName(EC_TAG_SERVER_STATIC); |
| 1551 | if (staticTag) { |
| 1552 | theApp->serverlist->SetStaticServer(server, staticTag->GetInt() > 0); |
| 1553 | } |
| 1554 | const CECTag * prioTag = request->GetTagByName(EC_TAG_SERVER_PRIO); |
| 1555 | if (prioTag) { |
| 1556 | theApp->serverlist->SetServerPrio(server, prioTag->GetInt()); |
| 1557 | } |
| 1558 | } |
| 1559 | response = new CECPacket(EC_OP_NOOP); |
| 1560 | break; |
| 1561 | } |
| 1562 | // |
| 1563 | // Friends |
| 1564 | // |
| 1565 | case EC_OP_FRIEND: |
| 1566 | response = Get_EC_Response_Friend(request); |
| 1567 | break; |
| 1568 | |
| 1569 | // |
| 1570 | // IPFilter |
| 1571 | // |
| 1572 | case EC_OP_IPFILTER_RELOAD: |
| 1573 | NotifyAlways_IPFilter_Reload()MuleNotify::DoNotifyAlways(&MuleNotify::IPFilter_Reload); |
| 1574 | response = new CECPacket(EC_OP_NOOP); |
| 1575 | break; |
| 1576 | |
| 1577 | case EC_OP_IPFILTER_UPDATE: { |
| 1578 | wxString url = request->GetFirstTagSafe()->GetStringData(); |
| 1579 | if (url.IsEmpty()) { |
| 1580 | url = thePrefs::IPFilterURL(); |
| 1581 | } |
| 1582 | NotifyAlways_IPFilter_Update(url)MuleNotify::DoNotifyAlways(&MuleNotify::IPFilter_Update, url ); |
| 1583 | response = new CECPacket(EC_OP_NOOP); |
| 1584 | break; |
| 1585 | } |
| 1586 | // |
| 1587 | // Search |
| 1588 | // |
| 1589 | case EC_OP_SEARCH_START: |
| 1590 | response = Get_EC_Response_Search(request); |
| 1591 | break; |
| 1592 | |
| 1593 | case EC_OP_SEARCH_STOP: |
| 1594 | response = Get_EC_Response_Search_Stop(request); |
| 1595 | break; |
| 1596 | |
| 1597 | case EC_OP_SEARCH_RESULTS: |
| 1598 | if ( request->GetDetailLevel() == EC_DETAIL_INC_UPDATE ) { |
| 1599 | response = Get_EC_Response_Search_Results(m_obj_tagmap); |
| 1600 | } else { |
| 1601 | response = Get_EC_Response_Search_Results(request); |
| 1602 | } |
| 1603 | break; |
| 1604 | |
| 1605 | case EC_OP_SEARCH_PROGRESS: |
| 1606 | response = new CECPacket(EC_OP_SEARCH_PROGRESS); |
| 1607 | response->AddTag(CECTag(EC_TAG_SEARCH_STATUS, |
| 1608 | theApp->searchlist->GetSearchProgress())); |
| 1609 | break; |
| 1610 | |
| 1611 | case EC_OP_DOWNLOAD_SEARCH_RESULT: |
| 1612 | response = Get_EC_Response_Search_Results_Download(request); |
| 1613 | break; |
| 1614 | // |
| 1615 | // Preferences |
| 1616 | // |
| 1617 | case EC_OP_GET_PREFERENCES: |
| 1618 | response = new CEC_Prefs_Packet(request->GetTagByNameSafe(EC_TAG_SELECT_PREFS)->GetInt(), request->GetDetailLevel()); |
| 1619 | break; |
| 1620 | case EC_OP_SET_PREFERENCES: |
| 1621 | static_cast<const CEC_Prefs_Packet *>(request)->Apply(); |
| 1622 | theApp->glob_prefs->Save(); |
| 1623 | if (thePrefs::IsFilteringClients()) { |
| 1624 | theApp->clientlist->FilterQueues(); |
| 1625 | } |
| 1626 | if (thePrefs::IsFilteringServers()) { |
| 1627 | theApp->serverlist->FilterServers(); |
| 1628 | } |
| 1629 | if (!thePrefs::GetNetworkED2K() && theApp->IsConnectedED2K()) { |
| 1630 | theApp->DisconnectED2K(); |
| 1631 | } |
| 1632 | if (!thePrefs::GetNetworkKademlia() && theApp->IsConnectedKad()) { |
| 1633 | theApp->StopKad(); |
| 1634 | } |
| 1635 | response = new CECPacket(EC_OP_NOOP); |
| 1636 | break; |
| 1637 | |
| 1638 | case EC_OP_CREATE_CATEGORY: |
| 1639 | if ( request->GetTagCount() == 1 ) { |
| 1640 | CEC_Category_Tag tag(*static_cast<const CEC_Category_Tag*>(request->GetFirstTagSafe())); |
| 1641 | if (tag.Create()) { |
| 1642 | response = new CECPacket(EC_OP_NOOP); |
| 1643 | } else { |
| 1644 | response = new CECPacket(EC_OP_FAILED); |
| 1645 | response->AddTag(CECTag(EC_TAG_CATEGORY, theApp->glob_prefs->GetCatCount() - 1)); |
| 1646 | response->AddTag(CECTag(EC_TAG_CATEGORY_PATH, tag.Path())); |
| 1647 | } |
| 1648 | Notify_CategoryAdded()MuleNotify::DoNotify(&MuleNotify::CategoryAdded); |
| 1649 | } else { |
| 1650 | response = new CECPacket(EC_OP_NOOP); |
| 1651 | } |
| 1652 | break; |
| 1653 | case EC_OP_UPDATE_CATEGORY: |
| 1654 | if ( request->GetTagCount() == 1 ) { |
| 1655 | CEC_Category_Tag tag(*static_cast<const CEC_Category_Tag*>(request->GetFirstTagSafe())); |
| 1656 | if (tag.Apply()) { |
| 1657 | response = new CECPacket(EC_OP_NOOP); |
| 1658 | } else { |
| 1659 | response = new CECPacket(EC_OP_FAILED); |
| 1660 | response->AddTag(CECTag(EC_TAG_CATEGORY, tag.GetInt())); |
| 1661 | response->AddTag(CECTag(EC_TAG_CATEGORY_PATH, tag.Path())); |
| 1662 | } |
| 1663 | Notify_CategoryUpdate(tag.GetInt())MuleNotify::DoNotify(&MuleNotify::CategoryUpdate, tag.GetInt ()); |
| 1664 | } else { |
| 1665 | response = new CECPacket(EC_OP_NOOP); |
| 1666 | } |
| 1667 | break; |
| 1668 | case EC_OP_DELETE_CATEGORY: |
| 1669 | if ( request->GetTagCount() == 1 ) { |
| 1670 | uint32 cat = request->GetFirstTagSafe()->GetInt(); |
| 1671 | // this does not only update the gui, but actually deletes the cat |
| 1672 | Notify_CategoryDelete(cat)MuleNotify::DoNotify(&MuleNotify::CategoryDelete, cat); |
| 1673 | } |
| 1674 | response = new CECPacket(EC_OP_NOOP); |
| 1675 | break; |
| 1676 | |
| 1677 | // |
| 1678 | // Logging |
| 1679 | // |
| 1680 | case EC_OP_ADDLOGLINE: |
| 1681 | // cppcheck-suppress duplicateBranch |
| 1682 | if (request->GetTagByName(EC_TAG_LOG_TO_STATUS) != NULL__null) { |
| 1683 | AddLogLineC(request->GetTagByNameSafe(EC_TAG_STRING)->GetStringData())theLogger.AddLogLine(L"ExternalConn.cpp", 1683, true, logStandard , request->GetTagByNameSafe(EC_TAG_STRING)->GetStringData ()); |
| 1684 | } else { |
| 1685 | AddLogLineN(request->GetTagByNameSafe(EC_TAG_STRING)->GetStringData())theLogger.AddLogLine(L"ExternalConn.cpp", 1685, false, logStandard , request->GetTagByNameSafe(EC_TAG_STRING)->GetStringData ()); |
| 1686 | } |
| 1687 | response = new CECPacket(EC_OP_NOOP); |
| 1688 | break; |
| 1689 | case EC_OP_ADDDEBUGLOGLINE: |
| 1690 | // cppcheck-suppress duplicateBranch |
| 1691 | if (request->GetTagByName(EC_TAG_LOG_TO_STATUS) != NULL__null) { |
| 1692 | AddDebugLogLineC(logGeneral, request->GetTagByNameSafe(EC_TAG_STRING)->GetStringData())theLogger.AddLogLine(L"ExternalConn.cpp", 1692, true, logGeneral , request->GetTagByNameSafe(EC_TAG_STRING)->GetStringData ()); |
| 1693 | } else { |
| 1694 | AddDebugLogLineN(logGeneral, request->GetTagByNameSafe(EC_TAG_STRING)->GetStringData())do {} while (false); |
| 1695 | } |
| 1696 | response = new CECPacket(EC_OP_NOOP); |
| 1697 | break; |
| 1698 | case EC_OP_GET_LOG: |
| 1699 | response = new CECPacket(EC_OP_LOG); |
| 1700 | response->AddTag(CECTag(EC_TAG_STRING, theApp->GetLog(false))); |
| 1701 | break; |
| 1702 | case EC_OP_GET_DEBUGLOG: |
| 1703 | response = new CECPacket(EC_OP_DEBUGLOG); |
| 1704 | response->AddTag(CECTag(EC_TAG_STRING, theApp->GetDebugLog(false))); |
| 1705 | break; |
| 1706 | case EC_OP_RESET_LOG: |
| 1707 | theApp->GetLog(true); |
| 1708 | response = new CECPacket(EC_OP_NOOP); |
| 1709 | break; |
| 1710 | case EC_OP_RESET_DEBUGLOG: |
| 1711 | theApp->GetDebugLog(true); |
| 1712 | response = new CECPacket(EC_OP_NOOP); |
| 1713 | break; |
| 1714 | case EC_OP_GET_LAST_LOG_ENTRY: |
| 1715 | { |
| 1716 | wxString tmp = theApp->GetLog(false); |
| 1717 | if (tmp.Last() == '\n') { |
| 1718 | tmp.RemoveLast(); |
| 1719 | } |
| 1720 | response = new CECPacket(EC_OP_LOG); |
| 1721 | response->AddTag(CECTag(EC_TAG_STRING, tmp.AfterLast('\n'))); |
| 1722 | } |
| 1723 | break; |
| 1724 | case EC_OP_GET_SERVERINFO: |
| 1725 | response = new CECPacket(EC_OP_SERVERINFO); |
| 1726 | response->AddTag(CECTag(EC_TAG_STRING, theApp->GetServerLog(false))); |
| 1727 | break; |
| 1728 | case EC_OP_CLEAR_SERVERINFO: |
| 1729 | theApp->GetServerLog(true); |
| 1730 | response = new CECPacket(EC_OP_NOOP); |
| 1731 | break; |
| 1732 | // |
| 1733 | // Statistics |
| 1734 | // |
| 1735 | case EC_OP_GET_STATSGRAPHS: |
| 1736 | response = GetStatsGraphs(request); |
| 1737 | break; |
| 1738 | case EC_OP_GET_STATSTREE: { |
| 1739 | theApp->m_statistics->UpdateStatsTree(); |
| 1740 | response = new CECPacket(EC_OP_STATSTREE); |
| 1741 | CECTag* tree = theStats::GetECStatTree(request->GetTagByNameSafe(EC_TAG_STATTREE_CAPPING)->GetInt()); |
| 1742 | if (tree) { |
| 1743 | response->AddTag(*tree); |
| 1744 | delete tree; |
| 1745 | } |
| 1746 | if (request->GetDetailLevel() == EC_DETAIL_WEB) { |
| 1747 | response->AddTag(CECTag(EC_TAG_SERVER_VERSION, wxT(VERSION)L"SVN")); |
| 1748 | response->AddTag(CECTag(EC_TAG_USER_NICK, thePrefs::GetUserNick())); |
| 1749 | } |
| 1750 | break; |
| 1751 | } |
| 1752 | |
| 1753 | // |
| 1754 | // Kad |
| 1755 | // |
| 1756 | case EC_OP_KAD_START: |
| 1757 | if (thePrefs::GetNetworkKademlia()) { |
| 1758 | response = new CECPacket(EC_OP_NOOP); |
| 1759 | if ( !Kademlia::CKademlia::IsRunning() ) { |
| 1760 | Kademlia::CKademlia::Start(); |
| 1761 | theApp->ShowConnectionState(); |
| 1762 | } |
| 1763 | } else { |
| 1764 | response = new CECPacket(EC_OP_FAILED); |
| 1765 | response->AddTag(CECTag(EC_TAG_STRING, wxTRANSLATE("Kad is disabled in preferences.")"Kad is disabled in preferences.")); |
| 1766 | } |
| 1767 | break; |
| 1768 | case EC_OP_KAD_STOP: |
| 1769 | theApp->StopKad(); |
| 1770 | theApp->ShowConnectionState(); |
| 1771 | response = new CECPacket(EC_OP_NOOP); |
| 1772 | break; |
| 1773 | case EC_OP_KAD_UPDATE_FROM_URL: { |
| 1774 | wxString url = request->GetFirstTagSafe()->GetStringData(); |
| 1775 | |
| 1776 | // Save the new url, and update the UI (if not amuled). |
| 1777 | Notify_NodesURLChanged(url)MuleNotify::DoNotify(&MuleNotify::NodesURLChanged, url); |
| 1778 | thePrefs::SetKadNodesUrl(url); |
| 1779 | |
| 1780 | theApp->UpdateNotesDat(url); |
| 1781 | response = new CECPacket(EC_OP_NOOP); |
| 1782 | break; |
| 1783 | } |
| 1784 | case EC_OP_KAD_BOOTSTRAP_FROM_IP: |
| 1785 | if (thePrefs::GetNetworkKademlia()) { |
| 1786 | theApp->BootstrapKad(request->GetTagByNameSafe(EC_TAG_BOOTSTRAP_IP)->GetInt(), |
| 1787 | request->GetTagByNameSafe(EC_TAG_BOOTSTRAP_PORT)->GetInt()); |
| 1788 | theApp->ShowConnectionState(); |
| 1789 | response = new CECPacket(EC_OP_NOOP); |
| 1790 | } else { |
| 1791 | response = new CECPacket(EC_OP_FAILED); |
| 1792 | response->AddTag(CECTag(EC_TAG_STRING, wxTRANSLATE("Kad is disabled in preferences.")"Kad is disabled in preferences.")); |
| 1793 | } |
| 1794 | break; |
| 1795 | |
| 1796 | // |
| 1797 | // Networks |
| 1798 | // These requests are currently used only in the text client |
| 1799 | // |
| 1800 | case EC_OP_CONNECT: |
| 1801 | if (thePrefs::GetNetworkED2K()) { |
| 1802 | response = new CECPacket(EC_OP_STRINGS); |
| 1803 | if (theApp->IsConnectedED2K()) { |
| 1804 | response->AddTag(CECTag(EC_TAG_STRING, wxTRANSLATE("Already connected to eD2k.")"Already connected to eD2k.")); |
| 1805 | } else { |
| 1806 | theApp->serverconnect->ConnectToAnyServer(); |
| 1807 | response->AddTag(CECTag(EC_TAG_STRING, wxTRANSLATE("Connecting to eD2k...")"Connecting to eD2k...")); |
| 1808 | } |
| 1809 | } |
| 1810 | if (thePrefs::GetNetworkKademlia()) { |
| 1811 | if (!response) { |
| 1812 | response = new CECPacket(EC_OP_STRINGS); |
| 1813 | } |
| 1814 | if (theApp->IsConnectedKad()) { |
| 1815 | response->AddTag(CECTag(EC_TAG_STRING, wxTRANSLATE("Already connected to Kad.")"Already connected to Kad.")); |
| 1816 | } else { |
| 1817 | theApp->StartKad(); |
| 1818 | response->AddTag(CECTag(EC_TAG_STRING, wxTRANSLATE("Connecting to Kad...")"Connecting to Kad...")); |
| 1819 | } |
| 1820 | } |
| 1821 | if (response) { |
| 1822 | theApp->ShowConnectionState(); |
| 1823 | } else { |
| 1824 | response = new CECPacket(EC_OP_FAILED); |
| 1825 | response->AddTag(CECTag(EC_TAG_STRING, wxTRANSLATE("All networks are disabled.")"All networks are disabled.")); |
| 1826 | } |
| 1827 | break; |
| 1828 | case EC_OP_DISCONNECT: |
| 1829 | if (theApp->IsConnected()) { |
| 1830 | response = new CECPacket(EC_OP_STRINGS); |
| 1831 | if (theApp->IsConnectedED2K()) { |
| 1832 | theApp->serverconnect->Disconnect(); |
| 1833 | response->AddTag(CECTag(EC_TAG_STRING, wxTRANSLATE("Disconnected from eD2k.")"Disconnected from eD2k.")); |
| 1834 | } |
| 1835 | if (theApp->IsConnectedKad()) { |
| 1836 | theApp->StopKad(); |
| 1837 | response->AddTag(CECTag(EC_TAG_STRING, wxTRANSLATE("Disconnected from Kad.")"Disconnected from Kad.")); |
| 1838 | } |
| 1839 | theApp->ShowConnectionState(); |
| 1840 | } else { |
| 1841 | response = new CECPacket(EC_OP_NOOP); |
| 1842 | } |
| 1843 | break; |
| 1844 | } |
| 1845 | if (!response) { |
| 1846 | AddLogLineN(CFormat(_("External Connection: invalid opcode received: %#x")) % request->GetOpCode())theLogger.AddLogLine(L"ExternalConn.cpp", 1846, false, logStandard , CFormat(wxGetTranslation(("External Connection: invalid opcode received: %#x" ))) % request->GetOpCode()); |
| 1847 | wxFAILdo { if ( wxTheAssertHandler && (wxOnAssert("ExternalConn.cpp" , 1847, __FUNCTION__, "\"Assert failure\"", (const char*)__null ), wxTrapInAssert) ) { wxTrapInAssert = false; asm volatile ( "int $3"); } } while ( (void)0, 0 ); |
| 1848 | response = new CECPacket(EC_OP_FAILED); |
| 1849 | response->AddTag(CECTag(EC_TAG_STRING, wxTRANSLATE("Invalid opcode (wrong protocol version?)")"Invalid opcode (wrong protocol version?)")); |
| 1850 | } |
| 1851 | return response; |
| 1852 | } |
| 1853 | |
| 1854 | /* |
| 1855 | * Here notification-based EC. Notification will be sorted by priority for possible throttling. |
| 1856 | */ |
| 1857 | |
| 1858 | /* |
| 1859 | * Core general status |
| 1860 | */ |
| 1861 | ECStatusMsgSource::ECStatusMsgSource() |
| 1862 | { |
| 1863 | m_last_ed2k_status_sent = 0xffffffff; |
| 1864 | m_last_kad_status_sent = 0xffffffff; |
| 1865 | m_server = (void *)0xffffffff; |
| 1866 | } |
| 1867 | |
| 1868 | uint32 ECStatusMsgSource::GetEd2kStatus() |
| 1869 | { |
| 1870 | if ( theApp->IsConnectedED2K() ) { |
| 1871 | return theApp->GetED2KID(); |
| 1872 | } else if ( theApp->serverconnect->IsConnecting() ) { |
| 1873 | return 1; |
| 1874 | } else { |
| 1875 | return 0; |
| 1876 | } |
| 1877 | } |
| 1878 | |
| 1879 | uint32 ECStatusMsgSource::GetKadStatus() |
| 1880 | { |
| 1881 | if ( theApp->IsConnectedKad() ) { |
| 1882 | return 1; |
| 1883 | } else if ( Kademlia::CKademlia::IsFirewalled() ) { |
| 1884 | return 2; |
| 1885 | } else if ( Kademlia::CKademlia::IsRunning() ) { |
| 1886 | return 3; |
| 1887 | } |
| 1888 | return 0; |
| 1889 | } |
| 1890 | |
| 1891 | CECPacket *ECStatusMsgSource::GetNextPacket() |
| 1892 | { |
| 1893 | if ( (m_last_ed2k_status_sent != GetEd2kStatus()) || |
| 1894 | (m_last_kad_status_sent != GetKadStatus()) || |
| 1895 | (m_server != theApp->serverconnect->GetCurrentServer()) ) { |
| 1896 | |
| 1897 | m_last_ed2k_status_sent = GetEd2kStatus(); |
| 1898 | m_last_kad_status_sent = GetKadStatus(); |
| 1899 | m_server = theApp->serverconnect->GetCurrentServer(); |
| 1900 | |
| 1901 | CECPacket *response = new CECPacket(EC_OP_STATS); |
| 1902 | response->AddTag(CEC_ConnState_Tag(EC_DETAIL_UPDATE)); |
| 1903 | return response; |
| 1904 | } |
| 1905 | return 0; |
| 1906 | } |
| 1907 | |
| 1908 | /* |
| 1909 | * Downloading files |
| 1910 | */ |
| 1911 | ECPartFileMsgSource::ECPartFileMsgSource() |
| 1912 | { |
| 1913 | for (unsigned int i = 0; i < theApp->downloadqueue->GetFileCount(); i++) { |
| 1914 | CPartFile *cur_file = theApp->downloadqueue->GetFileByIndex(i); |
| 1915 | PARTFILE_STATUS status = { true, false, false, false, true, cur_file }; |
| 1916 | m_dirty_status[cur_file->GetFileHash()] = status; |
| 1917 | } |
| 1918 | } |
| 1919 | |
| 1920 | void ECPartFileMsgSource::SetDirty(const CPartFile *file) |
| 1921 | { |
| 1922 | CMD4Hash filehash = file->GetFileHash(); |
| 1923 | if ( m_dirty_status.find(filehash) != m_dirty_status.end() ) { |
| 1924 | m_dirty_status[filehash].m_dirty = true;; |
| 1925 | } |
| 1926 | } |
| 1927 | |
| 1928 | void ECPartFileMsgSource::SetNew(const CPartFile *file) |
| 1929 | { |
| 1930 | CMD4Hash filehash = file->GetFileHash(); |
| 1931 | wxASSERT ( m_dirty_status.find(filehash) == m_dirty_status.end() )do { if ( m_dirty_status.find(filehash) == m_dirty_status.end () ) { } else if ( wxTheAssertHandler && (wxOnAssert( "ExternalConn.cpp", 1931, __FUNCTION__, "m_dirty_status.find(filehash) == m_dirty_status.end()" , (const char*)__null), wxTrapInAssert) ) { wxTrapInAssert = false ; asm volatile ("int $3"); } } while ( (void)0, 0 ); |
| 1932 | PARTFILE_STATUS status = { true, false, false, false, true, file }; |
| 1933 | m_dirty_status[filehash] = status; |
| 1934 | } |
| 1935 | |
| 1936 | void ECPartFileMsgSource::SetCompleted(const CPartFile *file) |
| 1937 | { |
| 1938 | CMD4Hash filehash = file->GetFileHash(); |
| 1939 | wxASSERT ( m_dirty_status.find(filehash) != m_dirty_status.end() )do { if ( m_dirty_status.find(filehash) != m_dirty_status.end () ) { } else if ( wxTheAssertHandler && (wxOnAssert( "ExternalConn.cpp", 1939, __FUNCTION__, "m_dirty_status.find(filehash) != m_dirty_status.end()" , (const char*)__null), wxTrapInAssert) ) { wxTrapInAssert = false ; asm volatile ("int $3"); } } while ( (void)0, 0 ); |
| 1940 | |
| 1941 | m_dirty_status[filehash].m_finished = true; |
| 1942 | } |
| 1943 | |
| 1944 | void ECPartFileMsgSource::SetRemoved(const CPartFile *file) |
| 1945 | { |
| 1946 | CMD4Hash filehash = file->GetFileHash(); |
| 1947 | wxASSERT ( m_dirty_status.find(filehash) != m_dirty_status.end() )do { if ( m_dirty_status.find(filehash) != m_dirty_status.end () ) { } else if ( wxTheAssertHandler && (wxOnAssert( "ExternalConn.cpp", 1947, __FUNCTION__, "m_dirty_status.find(filehash) != m_dirty_status.end()" , (const char*)__null), wxTrapInAssert) ) { wxTrapInAssert = false ; asm volatile ("int $3"); } } while ( (void)0, 0 ); |
| 1948 | |
| 1949 | m_dirty_status[filehash].m_removed = true; |
| 1950 | } |
| 1951 | |
| 1952 | CECPacket *ECPartFileMsgSource::GetNextPacket() |
| 1953 | { |
| 1954 | for(std::map<CMD4Hash, PARTFILE_STATUS>::iterator it = m_dirty_status.begin(); |
| 1955 | it != m_dirty_status.end(); it++) { |
| 1956 | if ( it->second.m_new || it->second.m_dirty || it->second.m_removed) { |
| 1957 | CMD4Hash filehash = it->first; |
| 1958 | |
| 1959 | const CPartFile *partfile = it->second.m_file; |
| 1960 | |
| 1961 | CECPacket *packet = new CECPacket(EC_OP_DLOAD_QUEUE); |
| 1962 | if ( it->second.m_removed ) { |
| 1963 | CECTag tag(EC_TAG_PARTFILE, filehash); |
| 1964 | packet->AddTag(tag); |
| 1965 | m_dirty_status.erase(it); |
| 1966 | } else { |
| 1967 | CEC_PartFile_Tag tag(partfile, it->second.m_new ? EC_DETAIL_FULL : EC_DETAIL_UPDATE); |
| 1968 | packet->AddTag(tag); |
| 1969 | } |
| 1970 | m_dirty_status[filehash].m_new = false; |
| 1971 | m_dirty_status[filehash].m_dirty = false; |
| 1972 | |
| 1973 | return packet; |
| 1974 | } |
| 1975 | } |
| 1976 | return 0; |
| 1977 | } |
| 1978 | |
| 1979 | /* |
| 1980 | * Shared files - similar to downloading |
| 1981 | */ |
| 1982 | ECKnownFileMsgSource::ECKnownFileMsgSource() |
| 1983 | { |
| 1984 | for (unsigned int i = 0; i < theApp->sharedfiles->GetFileCount(); i++) { |
| 1985 | const CKnownFile *cur_file = theApp->sharedfiles->GetFileByIndex(i); |
| 1986 | KNOWNFILE_STATUS status = { true, false, false, true, cur_file }; |
| 1987 | m_dirty_status[cur_file->GetFileHash()] = status; |
| 1988 | } |
| 1989 | } |
| 1990 | |
| 1991 | void ECKnownFileMsgSource::SetDirty(const CKnownFile *file) |
| 1992 | { |
| 1993 | CMD4Hash filehash = file->GetFileHash(); |
| 1994 | if ( m_dirty_status.find(filehash) != m_dirty_status.end() ) { |
| 1995 | m_dirty_status[filehash].m_dirty = true;; |
| 1996 | } |
| 1997 | } |
| 1998 | |
| 1999 | void ECKnownFileMsgSource::SetNew(const CKnownFile *file) |
| 2000 | { |
| 2001 | CMD4Hash filehash = file->GetFileHash(); |
| 2002 | wxASSERT ( m_dirty_status.find(filehash) == m_dirty_status.end() )do { if ( m_dirty_status.find(filehash) == m_dirty_status.end () ) { } else if ( wxTheAssertHandler && (wxOnAssert( "ExternalConn.cpp", 2002, __FUNCTION__, "m_dirty_status.find(filehash) == m_dirty_status.end()" , (const char*)__null), wxTrapInAssert) ) { wxTrapInAssert = false ; asm volatile ("int $3"); } } while ( (void)0, 0 ); |
| 2003 | KNOWNFILE_STATUS status = { true, false, false, true, file }; |
| 2004 | m_dirty_status[filehash] = status; |
| 2005 | } |
| 2006 | |
| 2007 | void ECKnownFileMsgSource::SetRemoved(const CKnownFile *file) |
| 2008 | { |
| 2009 | CMD4Hash filehash = file->GetFileHash(); |
| 2010 | wxASSERT ( m_dirty_status.find(filehash) != m_dirty_status.end() )do { if ( m_dirty_status.find(filehash) != m_dirty_status.end () ) { } else if ( wxTheAssertHandler && (wxOnAssert( "ExternalConn.cpp", 2010, __FUNCTION__, "m_dirty_status.find(filehash) != m_dirty_status.end()" , (const char*)__null), wxTrapInAssert) ) { wxTrapInAssert = false ; asm volatile ("int $3"); } } while ( (void)0, 0 ); |
| 2011 | |
| 2012 | m_dirty_status[filehash].m_removed = true; |
| 2013 | } |
| 2014 | |
| 2015 | CECPacket *ECKnownFileMsgSource::GetNextPacket() |
| 2016 | { |
| 2017 | for(std::map<CMD4Hash, KNOWNFILE_STATUS>::iterator it = m_dirty_status.begin(); |
| 2018 | it != m_dirty_status.end(); it++) { |
| 2019 | if ( it->second.m_new || it->second.m_dirty || it->second.m_removed) { |
| 2020 | CMD4Hash filehash = it->first; |
| 2021 | |
| 2022 | const CKnownFile *partfile = it->second.m_file; |
| 2023 | |
| 2024 | CECPacket *packet = new CECPacket(EC_OP_SHARED_FILES); |
| 2025 | if ( it->second.m_removed ) { |
| 2026 | CECTag tag(EC_TAG_PARTFILE, filehash); |
| 2027 | packet->AddTag(tag); |
| 2028 | m_dirty_status.erase(it); |
| 2029 | } else { |
| 2030 | CEC_SharedFile_Tag tag(partfile, it->second.m_new ? EC_DETAIL_FULL : EC_DETAIL_UPDATE); |
| 2031 | packet->AddTag(tag); |
| 2032 | } |
| 2033 | m_dirty_status[filehash].m_new = false; |
| 2034 | m_dirty_status[filehash].m_dirty = false; |
| 2035 | |
| 2036 | return packet; |
| 2037 | } |
| 2038 | } |
| 2039 | return 0; |
| 2040 | } |
| 2041 | |
| 2042 | /* |
| 2043 | * Notification about search status |
| 2044 | */ |
| 2045 | ECSearchMsgSource::ECSearchMsgSource() |
| 2046 | { |
| 2047 | } |
| 2048 | |
| 2049 | CECPacket *ECSearchMsgSource::GetNextPacket() |
| 2050 | { |
| 2051 | if ( m_dirty_status.empty() ) { |
| 2052 | return 0; |
| 2053 | } |
| 2054 | |
| 2055 | CECPacket *response = new CECPacket(EC_OP_SEARCH_RESULTS); |
| 2056 | for(std::map<CMD4Hash, SEARCHFILE_STATUS>::iterator it = m_dirty_status.begin(); |
| 2057 | it != m_dirty_status.end(); it++) { |
| 2058 | |
| 2059 | if ( it->second.m_new ) { |
| 2060 | response->AddTag(CEC_SearchFile_Tag(it->second.m_file, EC_DETAIL_FULL)); |
| 2061 | it->second.m_new = false; |
| 2062 | } else if ( it->second.m_dirty ) { |
| 2063 | response->AddTag(CEC_SearchFile_Tag(it->second.m_file, EC_DETAIL_UPDATE)); |
| 2064 | } |
| 2065 | |
| 2066 | } |
| 2067 | |
| 2068 | return response; |
| 2069 | } |
| 2070 | |
| 2071 | void ECSearchMsgSource::FlushStatus() |
| 2072 | { |
| 2073 | m_dirty_status.clear(); |
| 2074 | } |
| 2075 | |
| 2076 | void ECSearchMsgSource::SetDirty(const CSearchFile *file) |
| 2077 | { |
| 2078 | if ( m_dirty_status.count(file->GetFileHash()) ) { |
| 2079 | m_dirty_status[file->GetFileHash()].m_dirty = true; |
| 2080 | } else { |
| 2081 | m_dirty_status[file->GetFileHash()].m_new = true; |
| 2082 | m_dirty_status[file->GetFileHash()].m_dirty = true; |
| 2083 | m_dirty_status[file->GetFileHash()].m_child_dirty = true; |
| 2084 | m_dirty_status[file->GetFileHash()].m_file = file; |
| 2085 | } |
| 2086 | } |
| 2087 | |
| 2088 | void ECSearchMsgSource::SetChildDirty(const CSearchFile *file) |
| 2089 | { |
| 2090 | m_dirty_status[file->GetFileHash()].m_child_dirty = true; |
| 2091 | } |
| 2092 | |
| 2093 | /* |
| 2094 | * Notification about uploading clients |
| 2095 | */ |
| 2096 | CECPacket *ECClientMsgSource::GetNextPacket() |
| 2097 | { |
| 2098 | return 0; |
| 2099 | } |
| 2100 | |
| 2101 | // |
| 2102 | // Notification iface per-client |
| 2103 | // |
| 2104 | ECNotifier::ECNotifier() |
| 2105 | { |
| 2106 | } |
| 2107 | |
| 2108 | ECNotifier::~ECNotifier() |
| 2109 | { |
| 2110 | while (m_msg_source.begin() != m_msg_source.end()) |
| 2111 | Remove_EC_Client(m_msg_source.begin()->first); |
| 2112 | } |
| 2113 | |
| 2114 | CECPacket *ECNotifier::GetNextPacket(ECUpdateMsgSource *msg_source_array[]) |
| 2115 | { |
| 2116 | CECPacket *packet = 0; |
| 2117 | // |
| 2118 | // priority 0 is highest |
| 2119 | // |
| 2120 | for(int i = 0; i < EC_STATUS_LAST_PRIO; i++) { |
| 2121 | if ( (packet = msg_source_array[i]->GetNextPacket()) != 0 ) { |
| 2122 | break; |
| 2123 | } |
| 2124 | } |
| 2125 | return packet; |
| 2126 | } |
| 2127 | |
| 2128 | CECPacket *ECNotifier::GetNextPacket(CECServerSocket *sock) |
| 2129 | { |
| 2130 | // |
| 2131 | // OnOutput is called for a first time before |
| 2132 | // socket is registered |
| 2133 | // |
| 2134 | if ( m_msg_source.count(sock) ) { |
| 2135 | ECUpdateMsgSource **notifier_array = m_msg_source[sock]; |
| 2136 | if ( !notifier_array ) { |
| 2137 | return 0; |
| 2138 | } |
| 2139 | CECPacket *packet = GetNextPacket(notifier_array); |
| 2140 | //printf("[EC] next update packet; opcode=%x\n",packet ? packet->GetOpCode() : 0xff); |
| 2141 | return packet; |
| 2142 | } else { |
| 2143 | return 0; |
| 2144 | } |
| 2145 | } |
| 2146 | |
| 2147 | // |
| 2148 | // Interface to notification macros |
| 2149 | // |
| 2150 | void ECNotifier::DownloadFile_SetDirty(const CPartFile *file) |
| 2151 | { |
| 2152 | for(std::map<CECServerSocket *, ECUpdateMsgSource **>::iterator i = m_msg_source.begin(); |
| 2153 | i != m_msg_source.end(); ++i) { |
| 2154 | CECServerSocket *sock = i->first; |
| 2155 | if ( sock->HaveNotificationSupport() ) { |
| 2156 | ECUpdateMsgSource **notifier_array = i->second; |
| 2157 | static_cast<ECPartFileMsgSource *>(notifier_array[EC_PARTFILE])->SetDirty(file); |
| 2158 | } |
| 2159 | } |
| 2160 | NextPacketToSocket(); |
| 2161 | } |
| 2162 | |
| 2163 | void ECNotifier::DownloadFile_RemoveFile(const CPartFile *file) |
| 2164 | { |
| 2165 | for(std::map<CECServerSocket *, ECUpdateMsgSource **>::iterator i = m_msg_source.begin(); |
| 2166 | i != m_msg_source.end(); ++i) { |
| 2167 | ECUpdateMsgSource **notifier_array = i->second; |
| 2168 | static_cast<ECPartFileMsgSource *>(notifier_array[EC_PARTFILE])->SetRemoved(file); |
| 2169 | } |
| 2170 | NextPacketToSocket(); |
| 2171 | } |
| 2172 | |
| 2173 | void ECNotifier::DownloadFile_RemoveSource(const CPartFile *) |
| 2174 | { |
| 2175 | // per-partfile source list is not supported (yet), and IMHO quite useless |
| 2176 | } |
| 2177 | |
| 2178 | void ECNotifier::DownloadFile_AddFile(const CPartFile *file) |
| 2179 | { |
| 2180 | for(std::map<CECServerSocket *, ECUpdateMsgSource **>::iterator i = m_msg_source.begin(); |
| 2181 | i != m_msg_source.end(); ++i) { |
| 2182 | ECUpdateMsgSource **notifier_array = i->second; |
| 2183 | static_cast<ECPartFileMsgSource *>(notifier_array[EC_PARTFILE])->SetNew(file); |
| 2184 | } |
| 2185 | NextPacketToSocket(); |
| 2186 | } |
| 2187 | |
| 2188 | void ECNotifier::DownloadFile_AddSource(const CPartFile *) |
| 2189 | { |
| 2190 | // per-partfile source list is not supported (yet), and IMHO quite useless |
| 2191 | } |
| 2192 | |
| 2193 | void ECNotifier::SharedFile_AddFile(const CKnownFile *file) |
| 2194 | { |
| 2195 | for(std::map<CECServerSocket *, ECUpdateMsgSource **>::iterator i = m_msg_source.begin(); |
| 2196 | i != m_msg_source.end(); ++i) { |
| 2197 | ECUpdateMsgSource **notifier_array = i->second; |
| 2198 | static_cast<ECKnownFileMsgSource *>(notifier_array[EC_KNOWN])->SetNew(file); |
| 2199 | } |
| 2200 | NextPacketToSocket(); |
| 2201 | } |
| 2202 | |
| 2203 | void ECNotifier::SharedFile_RemoveFile(const CKnownFile *file) |
| 2204 | { |
| 2205 | for(std::map<CECServerSocket *, ECUpdateMsgSource **>::iterator i = m_msg_source.begin(); |
| 2206 | i != m_msg_source.end(); ++i) { |
| 2207 | ECUpdateMsgSource **notifier_array = i->second; |
| 2208 | static_cast<ECKnownFileMsgSource *>(notifier_array[EC_KNOWN])->SetRemoved(file); |
| 2209 | } |
| 2210 | NextPacketToSocket(); |
| 2211 | } |
| 2212 | |
| 2213 | void ECNotifier::SharedFile_RemoveAllFiles() |
| 2214 | { |
| 2215 | // need to figure out what to do here |
| 2216 | } |
| 2217 | |
| 2218 | void ECNotifier::Add_EC_Client(CECServerSocket *sock) |
| 2219 | { |
| 2220 | ECUpdateMsgSource **notifier_array = new ECUpdateMsgSource *[EC_STATUS_LAST_PRIO]; |
| 2221 | notifier_array[EC_STATUS] = new ECStatusMsgSource(); |
| 2222 | notifier_array[EC_SEARCH] = new ECSearchMsgSource(); |
| 2223 | notifier_array[EC_PARTFILE] = new ECPartFileMsgSource(); |
| 2224 | notifier_array[EC_CLIENT] = new ECClientMsgSource(); |
| 2225 | notifier_array[EC_KNOWN] = new ECKnownFileMsgSource(); |
| 2226 | |
| 2227 | m_msg_source[sock] = notifier_array; |
| 2228 | } |
| 2229 | |
| 2230 | void ECNotifier::Remove_EC_Client(CECServerSocket *sock) |
| 2231 | { |
| 2232 | if (m_msg_source.count(sock)) { |
| 2233 | ECUpdateMsgSource **notifier_array = m_msg_source[sock]; |
| 2234 | |
| 2235 | m_msg_source.erase(sock); |
| 2236 | |
| 2237 | for(int i = 0; i < EC_STATUS_LAST_PRIO; i++) { |
| 2238 | delete notifier_array[i]; |
| 2239 | } |
| 2240 | delete [] notifier_array; |
| 2241 | } |
| 2242 | } |
| 2243 | |
| 2244 | void ECNotifier::NextPacketToSocket() |
| 2245 | { |
| 2246 | for(std::map<CECServerSocket *, ECUpdateMsgSource **>::iterator i = m_msg_source.begin(); |
| 2247 | i != m_msg_source.end(); ++i) { |
| 2248 | CECServerSocket *sock = i->first; |
| 2249 | if ( sock->HaveNotificationSupport() && !sock->DataPending() ) { |
| 2250 | ECUpdateMsgSource **notifier_array = i->second; |
| 2251 | CECPacket *packet = GetNextPacket(notifier_array); |
| 2252 | if ( packet ) { |
| 2253 | //printf("[EC] sending update packet; opcode=%x\n",packet->GetOpCode()); |
| 2254 | sock->SendPacket(packet); |
| 2255 | } |
| 2256 | } |
| 2257 | } |
| 2258 | } |
| 2259 | |
| 2260 | // File_checked_for_headers |