| File: | rootdir/src/ExternalConn.cpp |
| Warning: | line 1865, column 11 Using a fixed address is not portable because that address will probably not be valid in all environments or platforms |
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
| ||||
| 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))) { | ||||
| 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 |
| 1 | ///////////////////////////////////////////////////////////////////////////// |
| 2 | // Name: wx/translation.h |
| 3 | // Purpose: Internationalization and localisation for wxWidgets |
| 4 | // Author: Vadim Zeitlin, Vaclav Slavik, |
| 5 | // Michael N. Filippov <michael@idisys.iae.nsk.su> |
| 6 | // Created: 2010-04-23 |
| 7 | // Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr> |
| 8 | // (c) 2010 Vaclav Slavik <vslavik@fastmail.fm> |
| 9 | // Licence: wxWindows licence |
| 10 | ///////////////////////////////////////////////////////////////////////////// |
| 11 | |
| 12 | #ifndef _WX_TRANSLATION_H_ |
| 13 | #define _WX_TRANSLATION_H_ |
| 14 | |
| 15 | #include "wx/defs.h" |
| 16 | #include "wx/string.h" |
| 17 | |
| 18 | #if wxUSE_INTL1 |
| 19 | |
| 20 | #include "wx/buffer.h" |
| 21 | #include "wx/language.h" |
| 22 | #include "wx/hashmap.h" |
| 23 | #include "wx/strconv.h" |
| 24 | #include "wx/scopedptr.h" |
| 25 | |
| 26 | // ============================================================================ |
| 27 | // global decls |
| 28 | // ============================================================================ |
| 29 | |
| 30 | // ---------------------------------------------------------------------------- |
| 31 | // macros |
| 32 | // ---------------------------------------------------------------------------- |
| 33 | |
| 34 | // gettext() style macros (notice that xgettext should be invoked with |
| 35 | // --keyword="_" --keyword="wxPLURAL:1,2" options |
| 36 | // to extract the strings from the sources) |
| 37 | #ifndef WXINTL_NO_GETTEXT_MACRO |
| 38 | #ifndef wxNO_IMPLICIT_WXSTRING_ENCODING |
| 39 | #define _(s)wxGetTranslation((s)) wxGetTranslation((s)) |
| 40 | #else |
| 41 | #define _(s)wxGetTranslation((s)) wxGetTranslation(wxASCII_STR(s)wxString::FromAscii(s)) |
| 42 | #endif |
| 43 | #define wxPLURAL(sing, plur, n)wxGetTranslation((sing), (plur), n) wxGetTranslation((sing), (plur), n) |
| 44 | #endif |
| 45 | |
| 46 | // wx-specific macro for translating strings in the given context: if you use |
| 47 | // them, you need to also add |
| 48 | // --keyword="wxGETTEXT_IN_CONTEXT:1c,2" --keyword="wxGETTEXT_IN_CONTEXT_PLURAL:1c,2,3" |
| 49 | // options to xgettext invocation. |
| 50 | #ifndef wxNO_IMPLICIT_WXSTRING_ENCODING |
| 51 | #define wxGETTEXT_IN_CONTEXT(c, s)wxGetTranslation((s), wxString(), c) \ |
| 52 | wxGetTranslation((s), wxString(), c) |
| 53 | #else |
| 54 | #define wxGETTEXT_IN_CONTEXT(c, s)wxGetTranslation((s), wxString(), c) \ |
| 55 | wxGetTranslation(wxASCII_STR(s)wxString::FromAscii(s), wxString(), c) |
| 56 | #endif |
| 57 | #define wxGETTEXT_IN_CONTEXT_PLURAL(c, sing, plur, n)wxGetTranslation((sing), (plur), n, wxString(), c) \ |
| 58 | wxGetTranslation((sing), (plur), n, wxString(), c) |
| 59 | |
| 60 | // another one which just marks the strings for extraction, but doesn't |
| 61 | // perform the translation (use -kwxTRANSLATE with xgettext!) |
| 62 | #define wxTRANSLATE(str)str str |
| 63 | |
| 64 | // another one which just marks the strings, with a context, for extraction, |
| 65 | // but doesn't perform the translation (use -kwxTRANSLATE_IN_CONTEXT:1c,2 with |
| 66 | // xgettext!) |
| 67 | #define wxTRANSLATE_IN_CONTEXT(c, str)str str |
| 68 | |
| 69 | // ---------------------------------------------------------------------------- |
| 70 | // forward decls |
| 71 | // ---------------------------------------------------------------------------- |
| 72 | |
| 73 | class WXDLLIMPEXP_FWD_BASE wxArrayString; |
| 74 | class WXDLLIMPEXP_FWD_BASE wxTranslationsLoader; |
| 75 | class WXDLLIMPEXP_FWD_BASE wxLocale; |
| 76 | |
| 77 | class wxPluralFormsCalculator; |
| 78 | wxDECLARE_SCOPED_PTR(wxPluralFormsCalculator, wxPluralFormsCalculatorPtr)class wxPluralFormsCalculatorPtr { private: wxPluralFormsCalculator * m_ptr; wxPluralFormsCalculatorPtr(wxPluralFormsCalculatorPtr const &); wxPluralFormsCalculatorPtr & operator=(wxPluralFormsCalculatorPtr const &); public: explicit wxPluralFormsCalculatorPtr(wxPluralFormsCalculator * ptr = __null) : m_ptr(ptr) { } ~wxPluralFormsCalculatorPtr (); void reset(wxPluralFormsCalculator * ptr = __null); wxPluralFormsCalculator *release() { wxPluralFormsCalculator *ptr = m_ptr; m_ptr = __null ; return ptr; } wxPluralFormsCalculator & operator*() const { do { if ( m_ptr != __null ) { } else if ( wxTheAssertHandler && (wxOnAssert("/usr/include/wx-3.2/wx/translation.h" , 78, __FUNCTION__, "m_ptr != __null", (const char*)__null), wxTrapInAssert ) ) { wxTrapInAssert = false; asm volatile ("int $3"); } } while ( (void)0, 0 ); return *m_ptr; } wxPluralFormsCalculator * operator ->() const { do { if ( m_ptr != __null ) { } else if ( wxTheAssertHandler && (wxOnAssert("/usr/include/wx-3.2/wx/translation.h" , 78, __FUNCTION__, "m_ptr != __null", (const char*)__null), wxTrapInAssert ) ) { wxTrapInAssert = false; asm volatile ("int $3"); } } while ( (void)0, 0 ); return m_ptr; } wxPluralFormsCalculator * get () const { return m_ptr; } void swap(wxPluralFormsCalculatorPtr & ot) { wxPluralFormsCalculator * tmp = ot.m_ptr; ot.m_ptr = m_ptr; m_ptr = tmp; } }; |
| 79 | |
| 80 | // ---------------------------------------------------------------------------- |
| 81 | // wxMsgCatalog corresponds to one loaded message catalog. |
| 82 | // ---------------------------------------------------------------------------- |
| 83 | |
| 84 | class WXDLLIMPEXP_BASE__attribute__ ((visibility("default"))) wxMsgCatalog |
| 85 | { |
| 86 | public: |
| 87 | // Ctor is protected, because CreateFromXXX functions must be used, |
| 88 | // but destruction should be unrestricted |
| 89 | #if !wxUSE_UNICODE1 |
| 90 | ~wxMsgCatalog(); |
| 91 | #endif |
| 92 | |
| 93 | // load the catalog from disk or from data; caller is responsible for |
| 94 | // deleting them if not NULL |
| 95 | static wxMsgCatalog *CreateFromFile(const wxString& filename, |
| 96 | const wxString& domain); |
| 97 | |
| 98 | static wxMsgCatalog *CreateFromData(const wxScopedCharBuffer& data, |
| 99 | const wxString& domain); |
| 100 | |
| 101 | // get name of the catalog |
| 102 | wxString GetDomain() const { return m_domain; } |
| 103 | |
| 104 | // get the translated string: returns NULL if not found |
| 105 | const wxString *GetString(const wxString& sz, unsigned n = UINT_MAX(2147483647 *2U +1U), const wxString& ct = wxEmptyString) const; |
| 106 | |
| 107 | protected: |
| 108 | wxMsgCatalog(const wxString& domain) |
| 109 | : m_pNext(NULL__null), m_domain(domain) |
| 110 | #if !wxUSE_UNICODE1 |
| 111 | , m_conv(NULL__null) |
| 112 | #endif |
| 113 | {} |
| 114 | |
| 115 | private: |
| 116 | // variable pointing to the next element in a linked list (or NULL) |
| 117 | wxMsgCatalog *m_pNext; |
| 118 | friend class wxTranslations; |
| 119 | |
| 120 | wxStringToStringHashMap m_messages; // all messages in the catalog |
| 121 | wxString m_domain; // name of the domain |
| 122 | |
| 123 | #if !wxUSE_UNICODE1 |
| 124 | // the conversion corresponding to this catalog charset if we installed it |
| 125 | // as the global one |
| 126 | wxCSConv *m_conv; |
| 127 | #endif |
| 128 | |
| 129 | wxPluralFormsCalculatorPtr m_pluralFormsCalculator; |
| 130 | }; |
| 131 | |
| 132 | // ---------------------------------------------------------------------------- |
| 133 | // wxTranslations: message catalogs |
| 134 | // ---------------------------------------------------------------------------- |
| 135 | |
| 136 | // this class allows to get translations for strings |
| 137 | class WXDLLIMPEXP_BASE__attribute__ ((visibility("default"))) wxTranslations |
| 138 | { |
| 139 | public: |
| 140 | wxTranslations(); |
| 141 | ~wxTranslations(); |
| 142 | |
| 143 | // returns current translations object, may return NULL |
| 144 | static wxTranslations *Get(); |
| 145 | // sets current translations object (takes ownership; may be NULL) |
| 146 | static void Set(wxTranslations *t); |
| 147 | |
| 148 | // changes loader to non-default one; takes ownership of 'loader' |
| 149 | void SetLoader(wxTranslationsLoader *loader); |
| 150 | |
| 151 | void SetLanguage(wxLanguage lang); |
| 152 | void SetLanguage(const wxString& lang); |
| 153 | |
| 154 | // get languages available for this app |
| 155 | wxArrayString GetAvailableTranslations(const wxString& domain) const; |
| 156 | |
| 157 | #if wxABI_VERSION( 3 * 10000 + 2 * 100 + 99 ) >= 30203 |
| 158 | // find best available translation language for given domain |
| 159 | wxString GetBestAvailableTranslation(const wxString& domain); |
| 160 | #endif // wxABI_VERSION >= 3.2.3 |
| 161 | |
| 162 | wxString GetBestTranslation(const wxString& domain, wxLanguage msgIdLanguage); |
| 163 | wxString GetBestTranslation(const wxString& domain, |
| 164 | const wxString& msgIdLanguage = wxASCII_STR("en")wxString::FromAscii("en")); |
| 165 | |
| 166 | #if wxABI_VERSION( 3 * 10000 + 2 * 100 + 99 ) >= 30203 |
| 167 | // add catalog for the given domain returning true if it could be found by |
| 168 | // wxTranslationsLoader |
| 169 | bool AddAvailableCatalog(const wxString& domain); |
| 170 | #endif // wxABI_VERSION >= 3.2.3 |
| 171 | #if wxABI_VERSION( 3 * 10000 + 2 * 100 + 99 ) >= 30206 |
| 172 | bool AddAvailableCatalog(const wxString& domain, wxLanguage msgIdLanguage); |
| 173 | #endif // wxABI_VERSION >= 3.2.5 |
| 174 | |
| 175 | // add standard wxWidgets catalog ("wxstd") |
| 176 | bool AddStdCatalog(); |
| 177 | |
| 178 | // add catalog with given domain name and language, looking it up via |
| 179 | // wxTranslationsLoader -- unlike AddAvailableCatalog(), this function also |
| 180 | // returns true if this catalog is not needed at all because msgIdLanguage |
| 181 | // is an acceptable language to use directly |
| 182 | bool AddCatalog(const wxString& domain, |
| 183 | wxLanguage msgIdLanguage = wxLANGUAGE_ENGLISH_US); |
| 184 | #if !wxUSE_UNICODE1 |
| 185 | bool AddCatalog(const wxString& domain, |
| 186 | wxLanguage msgIdLanguage, |
| 187 | const wxString& msgIdCharset); |
| 188 | #endif |
| 189 | |
| 190 | // check if the given catalog is loaded |
| 191 | bool IsLoaded(const wxString& domain) const; |
| 192 | |
| 193 | // access to translations |
| 194 | const wxString *GetTranslatedString(const wxString& origString, |
| 195 | const wxString& domain = wxEmptyString, |
| 196 | const wxString& context = wxEmptyString) const; |
| 197 | const wxString *GetTranslatedString(const wxString& origString, |
| 198 | unsigned n, |
| 199 | const wxString& domain = wxEmptyString, |
| 200 | const wxString& context = wxEmptyString) const; |
| 201 | |
| 202 | wxString GetHeaderValue(const wxString& header, |
| 203 | const wxString& domain = wxEmptyString) const; |
| 204 | |
| 205 | // this is hack to work around a problem with wxGetTranslation() which |
| 206 | // returns const wxString& and not wxString, so when it returns untranslated |
| 207 | // string, it needs to have a copy of it somewhere |
| 208 | static const wxString& GetUntranslatedString(const wxString& str); |
| 209 | |
| 210 | private: |
| 211 | enum Translations |
| 212 | { |
| 213 | Translations_NotNeeded = -1, |
| 214 | Translations_NotFound = 0, |
| 215 | Translations_Found = 1 |
| 216 | }; |
| 217 | |
| 218 | Translations DoAddCatalog(const wxString& domain, wxLanguage msgIdLanguage); |
| 219 | |
| 220 | // perform loading of the catalog via m_loader |
| 221 | bool LoadCatalog(const wxString& domain, const wxString& lang, const wxString& msgIdLang); |
| 222 | |
| 223 | // find catalog by name in a linked list, return NULL if !found |
| 224 | wxMsgCatalog *FindCatalog(const wxString& domain) const; |
| 225 | |
| 226 | // same as Set(), without taking ownership; only for wxLocale |
| 227 | static void SetNonOwned(wxTranslations *t); |
| 228 | friend class wxLocale; |
| 229 | |
| 230 | wxString DoGetBestAvailableTranslation(const wxString& domain, const wxString& additionalAvailableLanguage); |
| 231 | |
| 232 | private: |
| 233 | wxString m_lang; |
| 234 | wxTranslationsLoader *m_loader; |
| 235 | |
| 236 | wxMsgCatalog *m_pMsgCat; // pointer to linked list of catalogs |
| 237 | |
| 238 | // In addition to keeping all the catalogs in the linked list, we also |
| 239 | // store them in a hash map indexed by the domain name to allow finding |
| 240 | // them by name efficiently. |
| 241 | WX_DECLARE_HASH_MAP(wxString, wxMsgCatalog *, wxStringHash, wxStringEqual, wxMsgCatalogMap)class wxMsgCatalogMap_wxImplementation_Pair { public: typedef wxString first_type; typedef wxMsgCatalog * second_type; typedef wxString t1; typedef wxMsgCatalog * t2; typedef const wxString const_t1; typedef const wxMsgCatalog * const_t2; wxMsgCatalogMap_wxImplementation_Pair (const const_t1& f, const const_t2& s) : first(const_cast <t1&>(f)), second(const_cast<t2&>(s)) {} t1 first; t2 second; }; class wxMsgCatalogMap_wxImplementation_KeyEx { typedef wxString key_type; typedef wxMsgCatalogMap_wxImplementation_Pair pair_type; typedef const key_type const_key_type; typedef const pair_type const_pair_type; typedef const_key_type& const_key_reference ; typedef const_pair_type& const_pair_reference; public: wxMsgCatalogMap_wxImplementation_KeyEx () { } const_key_reference operator()( const_pair_reference pair ) const { return pair.first; }}; class wxMsgCatalogMap_wxImplementation_HashTable : protected _wxHashTableBase2 { public: typedef wxString key_type ; typedef wxMsgCatalogMap_wxImplementation_Pair value_type; typedef wxStringHash hasher; typedef wxStringEqual key_equal; typedef size_t size_type; typedef ptrdiff_t difference_type; typedef value_type* pointer; typedef const value_type* const_pointer ; typedef value_type& reference; typedef const value_type & const_reference; typedef const wxString const_key_type; typedef const wxMsgCatalogMap_wxImplementation_Pair const_mapped_type ; public: typedef wxMsgCatalogMap_wxImplementation_KeyEx key_extractor ; typedef wxMsgCatalogMap_wxImplementation_HashTable Self; protected : _wxHashTable_NodeBase** m_table; size_t m_tableBuckets; size_t m_items; hasher m_hasher; key_equal m_equals; key_extractor m_getKey ; public: struct Node:public _wxHashTable_NodeBase { public: Node ( const value_type& value ) : m_value( value ) {} Node* next () { return static_cast<Node*>(m_next); } value_type m_value ; }; protected: static void DeleteNode( _wxHashTable_NodeBase * node ) { delete static_cast<Node*>(node); } public: class Iterator { public: Node* m_node; Self* m_ht; Iterator() : m_node (__null), m_ht(__null) {} Iterator( Node* node, const Self* ht ) : m_node(node), m_ht(const_cast<Self*>(ht)) {} bool operator ==( const Iterator& it ) const { return m_node == it.m_node ; } bool operator !=( const Iterator& it ) const { return m_node != it.m_node; } protected: Node* GetNextNode() { size_type bucket = GetBucketForNode(m_ht,m_node); for( size_type i = bucket + 1; i < m_ht->m_tableBuckets; ++i ) { if( m_ht->m_table [i] ) return static_cast<Node*>(m_ht->m_table[i]); } return __null; } void PlusPlus() { Node* next = m_node->next (); m_node = next ? next : GetNextNode(); } }; friend class Iterator ; public: class iterator : public Iterator { public: iterator () : Iterator() {} iterator( Node* node, Self* ht ) : Iterator ( node, ht ) {} iterator& operator++() { PlusPlus(); return *this; } iterator operator++(int) { iterator it=*this;PlusPlus ();return it; } reference operator *() const { return m_node-> m_value; } pointer operator ->() const { return &(m_node ->m_value); } }; class const_iterator : public Iterator { public : const_iterator() : Iterator() {} const_iterator(iterator i) : Iterator(i) {} const_iterator( Node* node, const Self* ht ) : Iterator(node, const_cast<Self*>(ht)) {} const_iterator & operator++() { PlusPlus();return *this; } const_iterator operator++(int) { const_iterator it=*this;PlusPlus();return it ; } const_reference operator *() const { return m_node->m_value ; } const_pointer operator ->() const { return &(m_node ->m_value); } }; wxMsgCatalogMap_wxImplementation_HashTable ( size_type sz = 10, const hasher& hfun = hasher(), const key_equal& k_eq = key_equal(), const key_extractor& k_ex = key_extractor() ) : m_tableBuckets( GetNextPrime( (unsigned long) sz ) ), m_items( 0 ), m_hasher( hfun ), m_equals( k_eq ), m_getKey( k_ex ) { m_table = (_wxHashTable_NodeBase**)AllocTable (m_tableBuckets); } wxMsgCatalogMap_wxImplementation_HashTable ( const Self& ht ) : m_table(__null), m_tableBuckets( 0 ) , m_items( ht.m_items ), m_hasher( ht.m_hasher ), m_equals( ht .m_equals ), m_getKey( ht.m_getKey ) { HashCopy( ht ); } const Self& operator=( const Self& ht ) { if (&ht != this ) { clear(); m_hasher = ht.m_hasher; m_equals = ht.m_equals; m_getKey = ht.m_getKey; m_items = ht.m_items; HashCopy( ht ); } return *this; } ~wxMsgCatalogMap_wxImplementation_HashTable() { clear (); FreeTable(m_table); } hasher hash_funct() { return m_hasher ; } key_equal key_eq() { return m_equals; } void clear() { DeleteNodes (m_tableBuckets, m_table, DeleteNode); m_items = 0; } size_type size() const { return m_items; } size_type max_size() const { return size_type(-1); } bool empty() const { return size() == 0; } const_iterator end() const { return const_iterator(__null , this); } iterator end() { return iterator(__null, this); } const_iterator begin() const { return const_iterator(static_cast<Node*> (GetFirstNode(m_tableBuckets, m_table)), this); } iterator begin () { return iterator(static_cast<Node*>(GetFirstNode(m_tableBuckets , m_table)), this); } size_type erase( const const_key_type& key ) { _wxHashTable_NodeBase** node = GetNodePtr(key); if( ! node ) return 0; --m_items; _wxHashTable_NodeBase* temp = (*node )->m_next; delete static_cast<Node*>(*node); (*node) = temp; if( never_shrink( m_tableBuckets, m_items ) ) ResizeTable ( GetPreviousPrime( (unsigned long) m_tableBuckets ) - 1 ); return 1; } protected: static size_type GetBucketForNode( Self* ht, Node* node ) { return ht->m_hasher( ht->m_getKey( node ->m_value ) ) % ht->m_tableBuckets; } static Node* CopyNode ( Node* node ) { return new Node( *node ); } Node* GetOrCreateNode ( const value_type& value, bool& created ) { const const_key_type & key = m_getKey( value ); size_t bucket = m_hasher( key ) % m_tableBuckets; Node* node = static_cast<Node*>(m_table [bucket]); while( node ) { if( m_equals( m_getKey( node->m_value ), key ) ) { created = false; return node; } node = node-> next(); } created = true; return CreateNode( value, bucket); } Node * CreateNode( const value_type& value, size_t bucket ) { Node* node = new Node( value ); node->m_next = m_table [bucket]; m_table[bucket] = node; ++m_items; if( grow_lf70( m_tableBuckets , m_items ) ) ResizeTable( m_tableBuckets ); return node; } void CreateNode( const value_type& value ) { CreateNode(value , m_hasher( m_getKey(value) ) % m_tableBuckets ); } _wxHashTable_NodeBase ** GetNodePtr(const const_key_type& key) const { size_t bucket = m_hasher( key ) % m_tableBuckets; _wxHashTable_NodeBase** node = &m_table[bucket]; while( *node ) { if (m_equals(m_getKey (static_cast<Node*>(*node)->m_value), key)) return node ; node = &(*node)->m_next; } return __null; } Node* GetNode ( const const_key_type& key ) const { size_t bucket = m_hasher ( key ) % m_tableBuckets; Node* node = static_cast<Node*> (m_table[bucket]); while( node ) { if( m_equals( m_getKey( node ->m_value ), key ) ) return node; node = node->next(); } return __null; } void ResizeTable( size_t newSize ) { newSize = GetNextPrime( (unsigned long)newSize ); _wxHashTable_NodeBase ** srcTable = m_table; size_t srcBuckets = m_tableBuckets; m_table = (_wxHashTable_NodeBase**)AllocTable( newSize ); m_tableBuckets = newSize; CopyHashTable( srcTable, srcBuckets, this, m_table , (BucketFromNode)GetBucketForNode, (ProcessNode)&DummyProcessNode ); FreeTable(srcTable); } void HashCopy( const Self& ht ) { ResizeTable( ht.size() ); CopyHashTable( ht.m_table, ht.m_tableBuckets , (_wxHashTableBase2*)this, m_table, (BucketFromNode)GetBucketForNode , (ProcessNode)CopyNode ); } }; class wxMsgCatalogMap:public wxMsgCatalogMap_wxImplementation_HashTable { public: typedef wxMsgCatalog * mapped_type; class Insert_Result { public: typedef iterator first_type; typedef bool second_type ; typedef iterator t1; typedef bool t2; typedef const iterator const_t1; typedef const bool const_t2; Insert_Result(const const_t1 & f, const const_t2& s) : first(const_cast<t1& >(f)), second(const_cast<t2&>(s)) {} t1 first; t2 second; }; explicit wxMsgCatalogMap( size_type hint = 100, hasher hf = hasher(), key_equal eq = key_equal() ) : wxMsgCatalogMap_wxImplementation_HashTable ( hint, hf, eq, wxMsgCatalogMap_wxImplementation_KeyEx() ) {} mapped_type& operator[]( const const_key_type& key ) { bool created; return GetOrCreateNode( wxMsgCatalogMap_wxImplementation_Pair ( key, mapped_type() ), created)->m_value.second; } const_iterator find( const const_key_type& key ) const { return const_iterator ( GetNode( key ), this ); } iterator find( const const_key_type & key ) { return iterator( GetNode( key ), this ); } Insert_Result insert( const value_type& v ) { bool created; Node *node = GetOrCreateNode( wxMsgCatalogMap_wxImplementation_Pair( v. first, v.second ), created); return Insert_Result(iterator(node , this), created); } size_type erase( const key_type& k ) { return wxMsgCatalogMap_wxImplementation_HashTable::erase( k ); } void erase( const iterator& it ) { erase( (*it).first ); } size_type count( const const_key_type& key ) { return GetNode( key ) ? 1u : 0u; } }; |
| 242 | wxMsgCatalogMap m_catalogMap; |
| 243 | }; |
| 244 | |
| 245 | |
| 246 | // abstraction of translations discovery and loading |
| 247 | class WXDLLIMPEXP_BASE__attribute__ ((visibility("default"))) wxTranslationsLoader |
| 248 | { |
| 249 | public: |
| 250 | wxTranslationsLoader() {} |
| 251 | virtual ~wxTranslationsLoader() {} |
| 252 | |
| 253 | virtual wxMsgCatalog *LoadCatalog(const wxString& domain, |
| 254 | const wxString& lang) = 0; |
| 255 | |
| 256 | virtual wxArrayString GetAvailableTranslations(const wxString& domain) const = 0; |
| 257 | }; |
| 258 | |
| 259 | |
| 260 | // standard wxTranslationsLoader implementation, using filesystem |
| 261 | class WXDLLIMPEXP_BASE__attribute__ ((visibility("default"))) wxFileTranslationsLoader |
| 262 | : public wxTranslationsLoader |
| 263 | { |
| 264 | public: |
| 265 | static void AddCatalogLookupPathPrefix(const wxString& prefix); |
| 266 | |
| 267 | virtual wxMsgCatalog *LoadCatalog(const wxString& domain, |
| 268 | const wxString& lang) wxOVERRIDEoverride; |
| 269 | |
| 270 | virtual wxArrayString GetAvailableTranslations(const wxString& domain) const wxOVERRIDEoverride; |
| 271 | }; |
| 272 | |
| 273 | |
| 274 | #ifdef __WINDOWS__ |
| 275 | // loads translations from win32 resources |
| 276 | class WXDLLIMPEXP_BASE__attribute__ ((visibility("default"))) wxResourceTranslationsLoader |
| 277 | : public wxTranslationsLoader |
| 278 | { |
| 279 | public: |
| 280 | virtual wxMsgCatalog *LoadCatalog(const wxString& domain, |
| 281 | const wxString& lang) wxOVERRIDEoverride; |
| 282 | |
| 283 | virtual wxArrayString GetAvailableTranslations(const wxString& domain) const wxOVERRIDEoverride; |
| 284 | |
| 285 | protected: |
| 286 | // returns resource type to use for translations |
| 287 | virtual wxString GetResourceType() const { return wxASCII_STR("MOFILE")wxString::FromAscii("MOFILE"); } |
| 288 | |
| 289 | // returns module to load resources from |
| 290 | virtual WXHINSTANCE GetModule() const { return NULL__null; } |
| 291 | }; |
| 292 | #endif // __WINDOWS__ |
| 293 | |
| 294 | |
| 295 | // ---------------------------------------------------------------------------- |
| 296 | // global functions |
| 297 | // ---------------------------------------------------------------------------- |
| 298 | |
| 299 | // get the translation of the string in the current locale |
| 300 | inline const wxString& wxGetTranslation(const wxString& str, |
| 301 | const wxString& domain = wxString(), |
| 302 | const wxString& context = wxString()) |
| 303 | { |
| 304 | wxTranslations *trans = wxTranslations::Get(); |
| 305 | const wxString *transStr = trans ? trans->GetTranslatedString(str, domain, context) |
| 306 | : NULL__null; |
| 307 | if ( transStr ) |
| 308 | return *transStr; |
| 309 | else |
| 310 | // NB: this function returns reference to a string, so we have to keep |
| 311 | // a copy of it somewhere |
| 312 | return wxTranslations::GetUntranslatedString(str); |
| 313 | } |
| 314 | |
| 315 | inline const wxString& wxGetTranslation(const wxString& str1, |
| 316 | const wxString& str2, |
| 317 | unsigned n, |
| 318 | const wxString& domain = wxString(), |
| 319 | const wxString& context = wxString()) |
| 320 | { |
| 321 | wxTranslations *trans = wxTranslations::Get(); |
| 322 | const wxString *transStr = trans ? trans->GetTranslatedString(str1, n, domain, context) |
| 323 | : NULL__null; |
| 324 | if ( transStr ) |
| 325 | return *transStr; |
| 326 | else |
| 327 | // NB: this function returns reference to a string, so we have to keep |
| 328 | // a copy of it somewhere |
| 329 | return n == 1 |
| 330 | ? wxTranslations::GetUntranslatedString(str1) |
| 331 | : wxTranslations::GetUntranslatedString(str2); |
| 332 | } |
| 333 | |
| 334 | #ifdef wxNO_IMPLICIT_WXSTRING_ENCODING |
| 335 | |
| 336 | /* |
| 337 | * It must always be possible to call wxGetTranslation() with const |
| 338 | * char* arguments. |
| 339 | */ |
| 340 | inline const wxString& wxGetTranslation(const char *str, |
| 341 | const char *domain = "", |
| 342 | const char *context = "") { |
| 343 | const wxMBConv &conv = wxConvWhateverWorkswxGet_wxConvWhateverWorks(); |
| 344 | return wxGetTranslation(wxString(str, conv), wxString(domain, conv), |
| 345 | wxString(context, conv)); |
| 346 | } |
| 347 | |
| 348 | inline const wxString& wxGetTranslation(const char *str1, |
| 349 | const char *str2, |
| 350 | unsigned n, |
| 351 | const char *domain = "", |
| 352 | const char *context = "") { |
| 353 | const wxMBConv &conv = wxConvWhateverWorkswxGet_wxConvWhateverWorks(); |
| 354 | return wxGetTranslation(wxString(str1, conv), wxString(str2, conv), n, |
| 355 | wxString(domain, conv), |
| 356 | wxString(context, conv)); |
| 357 | } |
| 358 | |
| 359 | #endif // wxNO_IMPLICIT_WXSTRING_ENCODING |
| 360 | |
| 361 | #else // !wxUSE_INTL |
| 362 | |
| 363 | // the macros should still be defined - otherwise compilation would fail |
| 364 | |
| 365 | #if !defined(WXINTL_NO_GETTEXT_MACRO) |
| 366 | #if !defined(_) |
| 367 | #ifndef wxNO_IMPLICIT_WXSTRING_ENCODING |
| 368 | #define _(s)wxGetTranslation((s)) (s) |
| 369 | #else |
| 370 | #define _(s)wxGetTranslation((s)) wxASCII_STR(s)wxString::FromAscii(s) |
| 371 | #endif |
| 372 | #endif |
| 373 | #define wxPLURAL(sing, plur, n)wxGetTranslation((sing), (plur), n) ((n) == 1 ? (sing) : (plur)) |
| 374 | #define wxGETTEXT_IN_CONTEXT(c, s)wxGetTranslation((s), wxString(), c) (s) |
| 375 | #define wxGETTEXT_IN_CONTEXT_PLURAL(c, sing, plur, n)wxGetTranslation((sing), (plur), n, wxString(), c) wxPLURAL(sing, plur, n)wxGetTranslation((sing), (plur), n) |
| 376 | #endif |
| 377 | |
| 378 | #define wxTRANSLATE(str)str str |
| 379 | #define wxTRANSLATE_IN_CONTEXT(c, str)str str |
| 380 | |
| 381 | // NB: we use a template here in order to avoid using |
| 382 | // wxLocale::GetUntranslatedString() above, which would be required if |
| 383 | // we returned const wxString&; this way, the compiler should be able to |
| 384 | // optimize wxGetTranslation() away |
| 385 | |
| 386 | template<typename TString> |
| 387 | inline TString wxGetTranslation(TString str) |
| 388 | { return str; } |
| 389 | |
| 390 | template<typename TString, typename TDomain> |
| 391 | inline TString wxGetTranslation(TString str, TDomain WXUNUSED(domain)) |
| 392 | { return str; } |
| 393 | |
| 394 | template<typename TString, typename TDomain, typename TContext> |
| 395 | inline TString wxGetTranslation(TString str, TDomain WXUNUSED(domain), TContext WXUNUSED(context)) |
| 396 | { return str; } |
| 397 | |
| 398 | template<typename TString, typename TDomain> |
| 399 | inline TString wxGetTranslation(TString str1, TString str2, size_t n) |
| 400 | { return n == 1 ? str1 : str2; } |
| 401 | |
| 402 | template<typename TString, typename TDomain> |
| 403 | inline TString wxGetTranslation(TString str1, TString str2, size_t n, |
| 404 | TDomain WXUNUSED(domain)) |
| 405 | { return n == 1 ? str1 : str2; } |
| 406 | |
| 407 | template<typename TString, typename TDomain, typename TContext> |
| 408 | inline TString wxGetTranslation(TString str1, TString str2, size_t n, |
| 409 | TDomain WXUNUSED(domain), |
| 410 | TContext WXUNUSED(context)) |
| 411 | { return n == 1 ? str1 : str2; } |
| 412 | |
| 413 | #endif // wxUSE_INTL/!wxUSE_INTL |
| 414 | |
| 415 | // define this one just in case it occurs somewhere (instead of preferred |
| 416 | // wxTRANSLATE) too |
| 417 | #if !defined(WXINTL_NO_GETTEXT_MACRO) |
| 418 | #if !defined(gettext_noop) |
| 419 | #define gettext_noop(str)(str) (str) |
| 420 | #endif |
| 421 | #if !defined(N_) |
| 422 | #define N_(s)(s) (s) |
| 423 | #endif |
| 424 | #endif |
| 425 | |
| 426 | #endif // _WX_TRANSLATION_H_ |