Bug Summary

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

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name ExternalConn.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/rootdir/src -fcoverage-compilation-dir=/rootdir/src -resource-dir /usr/lib/llvm-19/lib/clang/19 -D HAVE_CONFIG_H -I . -I .. -D USE_WX_EXTENSIONS -I /usr/include/upnp -D ENABLE_UPNP=1 -I /usr/lib/x86_64-linux-gnu/wx/include/gtk3-unicode-3.2 -I /usr/include/wx-3.2 -D _FILE_OFFSET_BITS=64 -D WXUSINGDLL -D __WXGTK__ -D ENABLE_IP2COUNTRY=1 -I ./libs -I libs -I ./include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/x86_64-linux-gnu/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/backward -internal-isystem /usr/lib/llvm-19/lib/clang/19/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-register -fdeprecated-macro -ferror-limit 19 -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fcxx-exceptions -fexceptions -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2025-01-14-142857-17216-1 -x c++ ExternalConn.cpp

ExternalConn.cpp

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 */
65class CKnownFile_Encoder {
66 // number of sources for each part for progress bar colouring
67 RLE_Data m_enc_data;
68protected:
69 const CKnownFile *m_file;
70public:
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 */
97class 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); }
111public:
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
132class CFileEncoderMap : public std::map<uint32, CKnownFile_Encoder*> {
133 typedef std::set<uint32> IDSet;
134public:
135 ~CFileEncoderMap();
136 void UpdateEncoders();
137};
138
139CFileEncoderMap::~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.
149void 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
198class CECServerSocket : public CECMuleSocket
199{
200public:
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(); }
210private:
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
232CECServerSocket::CECServerSocket(ECNotifier *notifier)
233:
234CECMuleSocket(true),
235m_conn_state(CONN_INIT),
236m_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
244CECServerSocket::~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
251const 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) {
1
Assuming field 'm_conn_state' is not equal to CONN_FAILED
2
Taking false branch
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) {
3
Assuming field 'm_conn_state' is not equal to CONN_ESTABLISHED
4
Taking true branch
264 // This is called twice:
265 // 1) send salt
266 // 2) verify password
267 reply = Authenticate(packet);
5
Calling 'CECServerSocket::Authenticate'
268 } else {
269 reply = ProcessRequest2(packet);
270 }
271 return reply;
272}
273
274
275void 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
282void 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_SOCKETS1
297enum
298{ // id for sockets
299 SERVER_ID = 1000
300};
301
302
303BEGIN_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)
305END_EVENT_TABLE()wxEventTableEntry(wxEVT_NULL, 0, 0, __null, __null) };
306#endif
307
308
309ExternalConn::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_REUSEADDR, this);
324#ifndef ASIO_SOCKETS1
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
349ExternalConn::~ExternalConn()
350{
351 KillAllSockets();
352 delete m_ECServer;
353 delete m_ec_notifier;
354}
355
356
357void 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
364void 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
371void 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
386void 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_SOCKETS1
397void ExternalConn::OnServerEvent(wxSocketEvent& WXUNUSED(event))
398{
399 m_ECServer->OnAccept();
400}
401#endif
402
403
404void 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//
423const CECPacket *CECServerSocket::Authenticate(const CECPacket *request)
424{
425 CECPacket *response;
426
427 if (request
5.1
'request' is not equal to NULL
5.1
'request' is not equal to NULL
== NULL__null) {
6
Taking false branch
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() ) {
7
Assuming the condition is false
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) ) {
8
Assuming field 'm_conn_state' is not equal to CONN_INIT
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)) {
9
Assuming field 'm_conn_state' is not equal to CONN_SALT_SENT
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) {
10
Assuming the condition is true
11
Taking true branch
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()) {
12
Assuming the condition is true
13
Taking true branch
534 theApp->ECServerHandler->m_ec_notifier->Add_EC_Client(this);
14
Calling 'ECNotifier::Add_EC_Client'
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
550static 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
567static 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
631static 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
662static 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
728static 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
763static 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
795static 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
868static 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
893static 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
946static 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
1017static 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
1038static 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
1061static 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
1073static 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
1080static 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
1131static 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
1155void 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
1268void CPartFile_Encoder::ResetEncoder()
1269{
1270 CKnownFile_Encoder::ResetEncoder();
1271 m_gap_status.ResetEncoder();
1272 m_req_status.ResetEncoder();
1273}
1274
1275void 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
1296static 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
1338CECPacket *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 */
1861ECStatusMsgSource::ECStatusMsgSource()
1862{
1863 m_last_ed2k_status_sent = 0xffffffff;
1864 m_last_kad_status_sent = 0xffffffff;
1865 m_server = (void *)0xffffffff;
16
Using a fixed address is not portable because that address will probably not be valid in all environments or platforms
1866}
1867
1868uint32 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
1879uint32 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
1891CECPacket *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*/
1911ECPartFileMsgSource::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
1920void 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
1928void 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
1936void 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
1944void 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
1952CECPacket *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 */
1982ECKnownFileMsgSource::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
1991void 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
1999void 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
2007void 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
2015CECPacket *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*/
2045ECSearchMsgSource::ECSearchMsgSource()
2046{
2047}
2048
2049CECPacket *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
2071void ECSearchMsgSource::FlushStatus()
2072{
2073 m_dirty_status.clear();
2074}
2075
2076void 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
2088void 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 */
2096CECPacket *ECClientMsgSource::GetNextPacket()
2097{
2098 return 0;
2099}
2100
2101//
2102// Notification iface per-client
2103//
2104ECNotifier::ECNotifier()
2105{
2106}
2107
2108ECNotifier::~ECNotifier()
2109{
2110 while (m_msg_source.begin() != m_msg_source.end())
2111 Remove_EC_Client(m_msg_source.begin()->first);
2112}
2113
2114CECPacket *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
2128CECPacket *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//
2150void 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
2163void 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
2173void ECNotifier::DownloadFile_RemoveSource(const CPartFile *)
2174{
2175 // per-partfile source list is not supported (yet), and IMHO quite useless
2176}
2177
2178void 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
2188void ECNotifier::DownloadFile_AddSource(const CPartFile *)
2189{
2190 // per-partfile source list is not supported (yet), and IMHO quite useless
2191}
2192
2193void 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
2203void 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
2213void ECNotifier::SharedFile_RemoveAllFiles()
2214{
2215 // need to figure out what to do here
2216}
2217
2218void ECNotifier::Add_EC_Client(CECServerSocket *sock)
2219{
2220 ECUpdateMsgSource **notifier_array = new ECUpdateMsgSource *[EC_STATUS_LAST_PRIO];
2221 notifier_array[EC_STATUS] = new ECStatusMsgSource();
15
Calling default constructor for '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
2230void 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
2244void 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

/usr/include/wx-3.2/wx/translation.h

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
73class WXDLLIMPEXP_FWD_BASE wxArrayString;
74class WXDLLIMPEXP_FWD_BASE wxTranslationsLoader;
75class WXDLLIMPEXP_FWD_BASE wxLocale;
76
77class wxPluralFormsCalculator;
78wxDECLARE_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
84class WXDLLIMPEXP_BASE__attribute__ ((visibility("default"))) wxMsgCatalog
85{
86public:
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
107protected:
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
115private:
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
137class WXDLLIMPEXP_BASE__attribute__ ((visibility("default"))) wxTranslations
138{
139public:
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
210private:
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
232private:
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
247class WXDLLIMPEXP_BASE__attribute__ ((visibility("default"))) wxTranslationsLoader
248{
249public:
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
261class WXDLLIMPEXP_BASE__attribute__ ((visibility("default"))) wxFileTranslationsLoader
262 : public wxTranslationsLoader
263{
264public:
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
276class WXDLLIMPEXP_BASE__attribute__ ((visibility("default"))) wxResourceTranslationsLoader
277 : public wxTranslationsLoader
278{
279public:
280 virtual wxMsgCatalog *LoadCatalog(const wxString& domain,
281 const wxString& lang) wxOVERRIDEoverride;
282
283 virtual wxArrayString GetAvailableTranslations(const wxString& domain) const wxOVERRIDEoverride;
284
285protected:
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
300inline 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
315inline 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 */
340inline 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
348inline 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
386template<typename TString>
387inline TString wxGetTranslation(TString str)
388 { return str; }
389
390template<typename TString, typename TDomain>
391inline TString wxGetTranslation(TString str, TDomain WXUNUSED(domain))
392 { return str; }
393
394template<typename TString, typename TDomain, typename TContext>
395inline TString wxGetTranslation(TString str, TDomain WXUNUSED(domain), TContext WXUNUSED(context))
396 { return str; }
397
398template<typename TString, typename TDomain>
399inline TString wxGetTranslation(TString str1, TString str2, size_t n)
400 { return n == 1 ? str1 : str2; }
401
402template<typename TString, typename TDomain>
403inline TString wxGetTranslation(TString str1, TString str2, size_t n,
404 TDomain WXUNUSED(domain))
405 { return n == 1 ? str1 : str2; }
406
407template<typename TString, typename TDomain, typename TContext>
408inline 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_