2 // This file is part of the aMule Project.
4 // Copyright (c) 2003-2008 Kry ( elkry@sourceforge.net / http://www.amule.org )
5 // Copyright (c) 2003-2008 aMule Team ( admin@amule.org / http://www.amule.org )
7 // Any parts of this program derived from the xMule, lMule or eMule project,
8 // or contributed by third-party developers are copyrighted by their
11 // This program is free software; you can redistribute it and/or modify
12 // it under the terms of the GNU General Public License as published by
13 // the Free Software Foundation; either version 2 of the License, or
14 // (at your option) any later version.
16 // This program is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU General Public License for more details.
21 // You should have received a copy of the GNU General Public License
22 // along with this program; if not, write to the Free Software
23 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "config.h" // Needed for VERSION
30 #include <ec/cpp/ECMuleSocket.h> // Needed for CECSocket
32 #include <common/Format.h> // Needed for CFormat
34 #include <common/ClientVersion.h>
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 "IPFilter.h" // Needed for CIPFilter
46 #include "ClientList.h"
47 #include "Preferences.h" // Needed for CPreferences
49 #include "GuiEvents.h" // Needed for Notify_* macros
50 #include "Statistics.h" // Needed for theStats
51 #include "KnownFileList.h" // Needed for CKnownFileList
52 #include "kademlia/kademlia/Kademlia.h"
55 //-------------------- CECServerSocket --------------------
57 class CECServerSocket
: public CECMuleSocket
61 virtual ~CECServerSocket();
63 virtual const CECPacket
*OnPacketReceived(const CECPacket
*packet
);
64 virtual void OnLost();
68 CPartFile_Encoder_Map m_part_encoder
;
69 CKnownFile_Encoder_Map m_shared_encoder
;
70 CObjTagMap m_obj_tagmap
;
74 CECServerSocket::CECServerSocket()
77 m_authenticated(false),
82 wxASSERT(theApp
->ECServerHandler
);
83 theApp
->ECServerHandler
->AddSocket(this);
87 CECServerSocket::~CECServerSocket()
89 wxASSERT(theApp
->ECServerHandler
);
90 theApp
->ECServerHandler
->RemoveSocket(this);
94 const CECPacket
*CECServerSocket::OnPacketReceived(const CECPacket
*packet
)
96 const CECPacket
*reply
= NULL
;
98 if (!m_authenticated
) {
99 reply
= ExternalConn::Authenticate(packet
);
100 if (reply
->GetOpCode() != EC_OP_AUTH_OK
) {
102 AddLogLineM(false, _("Unauthorized access attempt. Connection closed."));
105 m_authenticated
= true;
108 reply
= ExternalConn::ProcessRequest2(
109 packet
, m_part_encoder
, m_shared_encoder
, m_obj_tagmap
);
115 void CECServerSocket::OnLost()
117 AddLogLineM(false,_("External connection closed."));
122 //-------------------- ExternalConn --------------------
130 BEGIN_EVENT_TABLE(ExternalConn
, wxEvtHandler
)
131 EVT_SOCKET(SERVER_ID
, ExternalConn::OnServerEvent
)
135 ExternalConn::ExternalConn(amuleIPV4Address addr
, wxString
*msg
)
139 // Are we allowed to accept External Connections?
140 if ( thePrefs::AcceptExternalConnections() ) {
141 // We must have a valid password, otherwise we will not allow EC connections
142 if (thePrefs::ECPassword().IsEmpty()) {
143 *msg
+= wxT("External connections disabled due to empty password!\n");
144 AddLogLineM(true, _("External connections disabled due to empty password!"));
149 m_ECServer
= new wxSocketServer(addr
, wxSOCKET_REUSEADDR
);
150 m_ECServer
->SetEventHandler(*this, SERVER_ID
);
151 m_ECServer
->SetNotify(wxSOCKET_CONNECTION_FLAG
);
152 m_ECServer
->Notify(true);
154 int port
= addr
.Service();
155 wxString ip
= addr
.IPAddress();
156 if (m_ECServer
->Ok()) {
157 msgLocal
= wxT("*** TCP socket (ECServer) listening on ") + ip
+
158 wxString::Format(wxT(":%d"), port
);
159 *msg
+= msgLocal
+ wxT("\n");
160 AddLogLineM(false, msgLocal
);
162 msgLocal
= wxT("Could not listen for external connections at ") + ip
+
163 wxString::Format(wxT(":%d!"), port
);
164 *msg
+= msgLocal
+ wxT("\n");
165 AddLogLineM(false, msgLocal
);
168 *msg
+= wxT("External connections disabled in config file\n");
169 AddLogLineM(false,_("External connections disabled in config file"));
174 ExternalConn::~ExternalConn()
181 void ExternalConn::AddSocket(CECServerSocket
*s
)
184 socket_list
.insert(s
);
188 void ExternalConn::RemoveSocket(CECServerSocket
*s
)
191 socket_list
.erase(s
);
195 void ExternalConn::KillAllSockets()
197 AddDebugLogLineM(false, logGeneral
,
198 CFormat(wxT("ExternalConn::KillAllSockets(): %d sockets to destroy.")) %
200 SocketSet::iterator it
= socket_list
.begin();
201 while (it
!= socket_list
.end()) {
202 CECServerSocket
*s
= *(it
++);
210 void ExternalConn::OnServerEvent(wxSocketEvent
& WXUNUSED(event
))
212 CECServerSocket
*sock
= new CECServerSocket
;
213 // Accept new connection if there is one in the pending
214 // connections queue, else exit. We use Accept(FALSE) for
215 // non-blocking accept (although if we got here, there
216 // should ALWAYS be a pending connection).
217 if ( m_ECServer
->AcceptWith(*sock
, false) ) {
218 AddLogLineM(false, _("New external connection accepted"));
221 AddLogLineM(false, _("Error: couldn't accept a new external connection"));
229 CECPacket
*ExternalConn::Authenticate(const CECPacket
*request
)
233 if (request
== NULL
) {
234 response
= new CECPacket(EC_OP_AUTH_FAIL
);
238 // Password must be specified if we are to allow remote connections
239 if ( thePrefs::ECPassword().IsEmpty() ) {
240 AddLogLineM(true, _("External connection refused due to empty password in preferences!"));
242 return new CECPacket(EC_OP_AUTH_FAIL
);
246 if (request
->GetOpCode() == EC_OP_AUTH_REQ
) {
247 const CECTag
*clientName
= request
->GetTagByName(EC_TAG_CLIENT_NAME
);
248 const CECTag
*clientVersion
= request
->GetTagByName(EC_TAG_CLIENT_VERSION
);
250 AddLogLineM(false, CFormat( _("Connecting client: %s %s") )
251 % ( clientName
? clientName
->GetStringData() : wxString(_("Unknown")) )
252 % ( clientVersion
? clientVersion
->GetStringData() : wxString(_("Unknown version")) ) );
253 const CECTag
*passwd
= request
->GetTagByName(EC_TAG_PASSWD_HASH
);
254 const CECTag
*protocol
= request
->GetTagByName(EC_TAG_PROTOCOL_VERSION
);
256 // For SVN versions, both client and server must use SVNDATE, and they must be the same
258 if (not vhash
.Decode(wxT(EC_VERSION_ID
))) {
259 response
= new CECPacket(EC_OP_AUTH_FAIL
);
260 response
->AddTag(CECTag(EC_TAG_STRING
, wxT("Fatal error, version hash is not a valid MD4-hash.")));
261 } else if (!request
->GetTagByName(EC_TAG_VERSION_ID
) || request
->GetTagByNameSafe(EC_TAG_VERSION_ID
)->GetMD4Data() != vhash
) {
262 response
= new CECPacket(EC_OP_AUTH_FAIL
);
263 response
->AddTag(CECTag(EC_TAG_STRING
, wxTRANSLATE("Incorrect EC version ID, there might be binary incompatibility. Use core and remote from same snapshot.")));
265 // For release versions, we don't want to allow connections from any arbitrary SVN client.
266 if (request
->GetTagByName(EC_TAG_VERSION_ID
)) {
267 response
= new CECPacket(EC_OP_AUTH_FAIL
);
268 response
->AddTag(CECTag(EC_TAG_STRING
, wxTRANSLATE("You cannot connect to a release version from an arbitrary SVN version! *sigh* possible crash prevented")));
270 } else if (protocol
!= NULL
) {
271 uint16 proto_version
= protocol
->GetInt();
272 if (proto_version
== EC_CURRENT_PROTOCOL_VERSION
) {
275 if (!passh
.Decode(thePrefs::ECPassword())) {
276 AddLogLineM(false, wxT("EC Auth failed, invalid hash specificed as EC password: ") + thePrefs::ECPassword());
277 response
= new CECPacket(EC_OP_AUTH_FAIL
);
278 response
->AddTag(CECTag(EC_TAG_STRING
, wxT("Authentication failed, invalid hash specified as EC password.")));
279 } else if (passwd
&& passwd
->GetMD4Data() == passh
) {
280 response
= new CECPacket(EC_OP_AUTH_OK
);
283 AddLogLineM(false, wxT("EC Auth failed: (") + passwd
->GetMD4Data().Encode() + wxT(" != ") + passh
.Encode() + wxT(")."));
285 AddLogLineM(false, wxT("EC Auth failed. Password tag missing."));
288 response
= new CECPacket(EC_OP_AUTH_FAIL
);
289 response
->AddTag(CECTag(EC_TAG_STRING
, wxTRANSLATE("Authentication failed.")));
292 response
= new CECPacket(EC_OP_AUTH_FAIL
);
293 response
->AddTag(CECTag(EC_TAG_STRING
, wxTRANSLATE("Invalid protocol version.") + wxString::Format(wxT("( %i != %i )"),proto_version
,EC_CURRENT_PROTOCOL_VERSION
)));
296 response
= new CECPacket(EC_OP_AUTH_FAIL
);
297 response
->AddTag(CECTag(EC_TAG_STRING
, wxTRANSLATE("Missing protocol version tag.")));
300 response
= new CECPacket(EC_OP_AUTH_FAIL
);
301 response
->AddTag(CECTag(EC_TAG_STRING
, wxTRANSLATE("Invalid request, you should first authenticate.")));
304 response
->AddTag(CECTag(EC_TAG_SERVER_VERSION
, wxT(VERSION
)));
306 if (response
->GetOpCode() == EC_OP_AUTH_OK
) {
307 AddLogLineM(false, _("Access granted."));
309 AddLogLineM(false, wxGetTranslation(response
->GetTagByIndex(0)->GetStringData()));
315 CECPacket
*Get_EC_Response_StatRequest(const CECPacket
*request
)
317 CECPacket
*response
= new CECPacket(EC_OP_STATS
);
319 switch (request
->GetDetailLevel()) {
321 response
->AddTag(CECTag(EC_TAG_STATS_UP_OVERHEAD
, (uint32
)theStats::GetUpOverheadRate()));
322 response
->AddTag(CECTag(EC_TAG_STATS_DOWN_OVERHEAD
, (uint32
)theStats::GetDownOverheadRate()));
323 response
->AddTag(CECTag(EC_TAG_STATS_BANNED_COUNT
, /*(uint32)*/theStats::GetBannedCount()));
326 response
->AddTag(CECTag(EC_TAG_STATS_UL_SPEED
, (uint32
)theStats::GetUploadRate()));
327 response
->AddTag(CECTag(EC_TAG_STATS_DL_SPEED
, (uint32
)(theStats::GetDownloadRate())));
328 response
->AddTag(CECTag(EC_TAG_STATS_UL_SPEED_LIMIT
, (uint32
)(thePrefs::GetMaxUpload()*1024.0)));
329 response
->AddTag(CECTag(EC_TAG_STATS_DL_SPEED_LIMIT
, (uint32
)(thePrefs::GetMaxDownload()*1024.0)));
330 response
->AddTag(CECTag(EC_TAG_STATS_UL_QUEUE_LEN
, /*(uint32)*/theStats::GetWaitingUserCount()));
331 response
->AddTag(CECTag(EC_TAG_STATS_TOTAL_SRC_COUNT
, /*(uint32)*/theStats::GetFoundSources()));
334 uint32 totaluser
= 0, totalfile
= 0;
335 theApp
->serverlist
->GetUserFileStatus( totaluser
, totalfile
);
336 response
->AddTag(CECTag(EC_TAG_STATS_ED2K_USERS
, totaluser
));
337 response
->AddTag(CECTag(EC_TAG_STATS_KAD_USERS
, Kademlia::CKademlia::GetKademliaUsers()));
338 response
->AddTag(CECTag(EC_TAG_STATS_ED2K_FILES
, totalfile
));
339 response
->AddTag(CECTag(EC_TAG_STATS_KAD_FILES
, Kademlia::CKademlia::GetKademliaFiles()));
341 case EC_DETAIL_UPDATE
:
342 case EC_DETAIL_INC_UPDATE
:
349 CECPacket
*Get_EC_Response_GetSharedFiles(const CECPacket
*request
, CKnownFile_Encoder_Map
&encoders
)
351 wxASSERT(request
->GetOpCode() == EC_OP_GET_SHARED_FILES
);
353 CECPacket
*response
= new CECPacket(EC_OP_SHARED_FILES
);
355 EC_DETAIL_LEVEL detail_level
= request
->GetDetailLevel();
357 // request can contain list of queried items
358 CTagSet
<CMD4Hash
, EC_TAG_KNOWNFILE
> queryitems(request
);
360 encoders
.UpdateEncoders(theApp
->sharedfiles
);
362 for (uint32 i
= 0; i
< theApp
->sharedfiles
->GetFileCount(); ++i
) {
363 CKnownFile
*cur_file
= (CKnownFile
*)theApp
->sharedfiles
->GetFileByIndex(i
);
365 if ( !cur_file
|| (!queryitems
.empty() && !queryitems
.count(cur_file
->GetFileHash())) ) {
369 CEC_SharedFile_Tag
filetag(cur_file
, detail_level
);
370 CKnownFile_Encoder
&enc
= encoders
[cur_file
];
371 if ( detail_level
!= EC_DETAIL_UPDATE
) {
374 enc
.Encode(&filetag
);
375 response
->AddTag(filetag
);
380 CECPacket
*Get_EC_Response_GetSharedFiles(CKnownFile_Encoder_Map
&encoders
, CObjTagMap
&tagmap
)
382 CECPacket
*response
= new CECPacket(EC_OP_SHARED_FILES
);
384 encoders
.UpdateEncoders(theApp
->sharedfiles
);
385 for (uint32 i
= 0; i
< theApp
->sharedfiles
->GetFileCount(); ++i
) {
386 CKnownFile
*cur_file
= (CKnownFile
*)theApp
->sharedfiles
->GetFileByIndex(i
);
389 // Hashes of tags are maintained on "per-object" basis. So, in this mode only
390 // same kind of objects can go into particular query type.
391 // Particulary here it means that files from download queue (aka partfiles)
392 // will not ne shown as shared files. Remote gui can do combine them if wishes
394 if ( !cur_file
|| cur_file
->IsPartFile() ) continue;
396 CValueMap
&valuemap
= tagmap
.GetValueMap(cur_file
);
397 CEC_SharedFile_Tag
filetag(cur_file
, valuemap
);
398 CKnownFile_Encoder
&enc
= encoders
[cur_file
];
399 enc
.Encode(&filetag
);
401 response
->AddTag(filetag
);
406 CECPacket
*Get_EC_Response_GetWaitQueue(const CECPacket
*request
)
408 wxASSERT(request
->GetOpCode() == EC_OP_GET_WAIT_QUEUE
);
410 CECPacket
*response
= new CECPacket(EC_OP_WAIT_QUEUE
);
412 EC_DETAIL_LEVEL detail_level
= request
->GetDetailLevel();
415 // request can contain list of queried items
416 CTagSet
<uint32
, EC_TAG_CLIENT
> queryitems(request
);
418 const CClientPtrList
& uploading
= theApp
->uploadqueue
->GetWaitingList();
419 CClientPtrList::const_iterator it
= uploading
.begin();
420 for (; it
!= uploading
.end(); ++it
) {
421 CUpDownClient
* cur_client
= *it
;
423 if ( !cur_client
|| (!queryitems
.empty() && !queryitems
.count(cur_client
->GetUserIDHybrid())) ) {
426 CEC_UpDownClient_Tag
cli_tag(cur_client
, detail_level
);
428 response
->AddTag(cli_tag
);
434 CECPacket
*Get_EC_Response_GetWaitQueue(CObjTagMap
&tagmap
)
436 CECPacket
*response
= new CECPacket(EC_OP_WAIT_QUEUE
);
438 const CClientPtrList
& uploading
= theApp
->uploadqueue
->GetWaitingList();
439 CClientPtrList::const_iterator it
= uploading
.begin();
440 for (; it
!= uploading
.end(); ++it
) {
441 CUpDownClient
* cur_client
= *it
;
443 CValueMap
&valuemap
= tagmap
.GetValueMap(cur_client
);
444 CEC_UpDownClient_Tag
cli_tag(cur_client
, valuemap
);
446 response
->AddTag(cli_tag
);
452 CECPacket
*Get_EC_Response_GetUpQueue(const CECPacket
*request
)
454 wxASSERT(request
->GetOpCode() == EC_OP_GET_ULOAD_QUEUE
);
456 CECPacket
*response
= new CECPacket(EC_OP_ULOAD_QUEUE
);
458 EC_DETAIL_LEVEL detail_level
= request
->GetDetailLevel();
461 // request can contain list of queried items
462 CTagSet
<uint32
, EC_TAG_CLIENT
> queryitems(request
);
465 const CClientPtrList
& uploading
= theApp
->uploadqueue
->GetUploadingList();
466 CClientPtrList::const_iterator it
= uploading
.begin();
467 for (; it
!= uploading
.end(); ++it
) {
468 CUpDownClient
* cur_client
= *it
;
470 if ( !cur_client
|| (!queryitems
.empty() && !queryitems
.count(cur_client
->GetUserIDHybrid())) ) {
474 CEC_UpDownClient_Tag
cli_tag(cur_client
, detail_level
);
475 response
->AddTag(cli_tag
);
482 CECPacket
*Get_EC_Response_GetUpQueue(CObjTagMap
&tagmap
)
484 CECPacket
*response
= new CECPacket(EC_OP_ULOAD_QUEUE
);
486 const CClientPtrList
& uploading
= theApp
->uploadqueue
->GetUploadingList();
487 CClientPtrList::const_iterator it
= uploading
.begin();
488 for (; it
!= uploading
.end(); ++it
) {
489 CUpDownClient
* cur_client
= *it
;
491 CValueMap
&valuemap
= tagmap
.GetValueMap(cur_client
);
492 CEC_UpDownClient_Tag
cli_tag(cur_client
, valuemap
);
494 response
->AddTag(cli_tag
);
501 CECPacket
*Get_EC_Response_GetDownloadQueue(CPartFile_Encoder_Map
&encoders
, CObjTagMap
&tagmap
)
503 CECPacket
*response
= new CECPacket(EC_OP_DLOAD_QUEUE
);
505 encoders
.UpdateEncoders(theApp
->downloadqueue
);
506 for (unsigned int i
= 0; i
< theApp
->downloadqueue
->GetFileCount(); i
++) {
507 CPartFile
*cur_file
= theApp
->downloadqueue
->GetFileByIndex(i
);
509 CValueMap
&valuemap
= tagmap
.GetValueMap(cur_file
);
510 CEC_PartFile_Tag
filetag(cur_file
, valuemap
);
511 CPartFile_Encoder
&enc
= encoders
[cur_file
];
512 enc
.Encode(&filetag
);
514 response
->AddTag(filetag
);
519 CECPacket
*Get_EC_Response_GetDownloadQueue(const CECPacket
*request
, CPartFile_Encoder_Map
&encoders
, bool detail
= false)
521 CECPacket
*response
= new CECPacket(EC_OP_DLOAD_QUEUE
);
523 EC_DETAIL_LEVEL detail_level
= request
->GetDetailLevel();
525 // request can contain list of queried items
526 CTagSet
<CMD4Hash
, EC_TAG_PARTFILE
> queryitems(request
);
528 encoders
.UpdateEncoders(theApp
->downloadqueue
);
530 for (unsigned int i
= 0; i
< theApp
->downloadqueue
->GetFileCount(); i
++) {
531 CPartFile
*cur_file
= theApp
->downloadqueue
->GetFileByIndex(i
);
533 if ( !queryitems
.empty() && !queryitems
.count(cur_file
->GetFileHash()) ) {
537 CEC_PartFile_Tag
filetag(cur_file
, detail_level
, detail
);
539 CPartFile_Encoder
&enc
= encoders
[cur_file
];
540 if ( detail_level
!= EC_DETAIL_UPDATE
) {
543 enc
.Encode(&filetag
);
545 response
->AddTag(filetag
);
551 CECPacket
*Get_EC_Response_PartFile_Cmd(const CECPacket
*request
)
553 CECPacket
*response
= NULL
;
555 // request can contain multiple files.
556 for (int i
= 0; i
< request
->GetTagCount(); ++i
) {
557 const CECTag
*hashtag
= request
->GetTagByIndex(i
);
559 wxASSERT(hashtag
->GetTagName() == EC_TAG_PARTFILE
);
561 CMD4Hash hash
= hashtag
->GetMD4Data();
562 CPartFile
*pfile
= theApp
->downloadqueue
->GetFileByID( hash
);
565 AddLogLineM(false,CFormat(_("Remote PartFile command failed: FileHash not found: %s")) % hash
.Encode());
566 response
= new CECPacket(EC_OP_FAILED
);
567 response
->AddTag(CECTag(EC_TAG_STRING
, CFormat(wxTRANSLATE("FileHash not found: %s")) % hash
.Encode()));
571 switch (request
->GetOpCode()) {
572 case EC_OP_PARTFILE_SWAP_A4AF_THIS
:
573 if ((pfile
->GetStatus(false) == PS_READY
) ||
574 (pfile
->GetStatus(false) == PS_EMPTY
)) {
575 CPartFile::SourceSet::const_iterator it
= pfile
->GetA4AFList().begin();
576 while ( it
!= pfile
->GetA4AFList().end() ) {
577 CUpDownClient
*cur_source
= *it
++;
579 cur_source
->SwapToAnotherFile(true, false, false, pfile
);
583 case EC_OP_PARTFILE_SWAP_A4AF_THIS_AUTO
:
584 pfile
->SetA4AFAuto(!pfile
->IsA4AFAuto());
586 case EC_OP_PARTFILE_SWAP_A4AF_OTHERS
:
587 if ((pfile
->GetStatus(false) == PS_READY
) ||
588 (pfile
->GetStatus(false) == PS_EMPTY
)) {
589 CPartFile::SourceSet::const_iterator it
= pfile
->GetSourceList().begin();
590 while ( it
!= pfile
->GetSourceList().end() ) {
591 CUpDownClient
* cur_source
= *it
++;
593 cur_source
->SwapToAnotherFile(false, false, false, NULL
);
597 case EC_OP_PARTFILE_PAUSE
:
600 case EC_OP_PARTFILE_RESUME
:
602 pfile
->SavePartFile();
604 case EC_OP_PARTFILE_STOP
:
607 case EC_OP_PARTFILE_PRIO_SET
: {
608 uint8 prio
= hashtag
->GetTagByIndexSafe(0)->GetInt();
609 if ( prio
== PR_AUTO
) {
610 pfile
->SetAutoDownPriority(1);
612 pfile
->SetAutoDownPriority(0);
613 pfile
->SetDownPriority(prio
);
617 case EC_OP_PARTFILE_DELETE
:
618 if ( thePrefs::StartNextFile() && (pfile
->GetStatus() != PS_PAUSED
) ) {
619 theApp
->downloadqueue
->StartNextFile(pfile
);
624 case EC_OP_PARTFILE_SET_CAT
:
625 pfile
->SetCategory(hashtag
->GetTagByIndexSafe(0)->GetInt());
629 response
= new CECPacket(EC_OP_FAILED
);
630 response
->AddTag(CECTag(EC_TAG_STRING
, wxTRANSLATE("OOPS! OpCode processing error!")));
635 response
= new CECPacket(EC_OP_NOOP
);
640 CECPacket
*Get_EC_Response_Server_Add(const CECPacket
*request
)
642 CECPacket
*response
= NULL
;
644 const CECTag
*srv_tag
= request
->GetTagByIndex(0);
646 wxString full_addr
= srv_tag
->GetTagByName(EC_TAG_SERVER_ADDRESS
)->GetStringData();
647 wxString name
= srv_tag
->GetTagByName(EC_TAG_SERVER_NAME
)->GetStringData();
649 wxString s_ip
= full_addr
.Left(full_addr
.Find(':'));
650 wxString s_port
= full_addr
.Mid(full_addr
.Find(':') + 1);
652 long port
= StrToULong(s_port
);
653 CServer
* toadd
= new CServer(port
, s_ip
);
654 toadd
->SetListName(name
.IsEmpty() ? full_addr
: name
);
656 if ( theApp
->AddServer(toadd
, true) ) {
657 response
= new CECPacket(EC_OP_NOOP
);
659 response
= new CECPacket(EC_OP_FAILED
);
660 response
->AddTag(CECTag(EC_TAG_STRING
, _("Server not added")));
667 CECPacket
*Get_EC_Response_Server(const CECPacket
*request
)
669 CECPacket
*response
= NULL
;
670 const CECTag
*srv_tag
= request
->GetTagByIndex(0);
673 srv
= theApp
->serverlist
->GetServerByIPTCP(srv_tag
->GetIPv4Data().IP(), srv_tag
->GetIPv4Data().m_port
);
674 // server tag passed, but server not found
676 response
= new CECPacket(EC_OP_FAILED
);
677 response
->AddTag(CECTag(EC_TAG_STRING
,
678 CFormat(wxTRANSLATE("server not found: %s")) % srv_tag
->GetIPv4Data().StringIP()));
682 switch (request
->GetOpCode()) {
683 case EC_OP_SERVER_DISCONNECT
:
684 theApp
->serverconnect
->Disconnect();
685 response
= new CECPacket(EC_OP_NOOP
);
687 case EC_OP_SERVER_REMOVE
:
689 theApp
->serverlist
->RemoveServer(srv
);
690 response
= new CECPacket(EC_OP_NOOP
);
692 response
= new CECPacket(EC_OP_FAILED
);
693 response
->AddTag(CECTag(EC_TAG_STRING
,
694 wxTRANSLATE("need to define server to be removed")));
697 case EC_OP_SERVER_CONNECT
:
698 if (thePrefs::GetNetworkED2K()) {
700 theApp
->serverconnect
->ConnectToServer(srv
);
701 response
= new CECPacket(EC_OP_NOOP
);
703 theApp
->serverconnect
->ConnectToAnyServer();
704 response
= new CECPacket(EC_OP_NOOP
);
707 response
= new CECPacket(EC_OP_FAILED
);
708 response
->AddTag(CECTag(EC_TAG_STRING
, wxTRANSLATE("ED2K is disabled in preferences.")));
713 response
= new CECPacket(EC_OP_FAILED
);
714 response
->AddTag(CECTag(EC_TAG_STRING
, wxTRANSLATE("OOPS! OpCode processing error!")));
719 CECPacket
*Get_EC_Response_Search_Results(const CECPacket
*request
)
721 CECPacket
*response
= new CECPacket(EC_OP_SEARCH_RESULTS
);
723 EC_DETAIL_LEVEL detail_level
= request
->GetDetailLevel();
725 // request can contain list of queried items
726 CTagSet
<CMD4Hash
, EC_TAG_SEARCHFILE
> queryitems(request
);
728 const CSearchResultList
& list
= theApp
->searchlist
->GetSearchResults(0xffffffff);
729 CSearchResultList::const_iterator it
= list
.begin();
730 while (it
!= list
.end()) {
731 CSearchFile
* sf
= *it
++;
732 if ( !queryitems
.empty() && !queryitems
.count(sf
->GetFileHash()) ) {
735 response
->AddTag(CEC_SearchFile_Tag(sf
, detail_level
));
740 CECPacket
*Get_EC_Response_Search_Results(CObjTagMap
&tagmap
)
742 CECPacket
*response
= new CECPacket(EC_OP_SEARCH_RESULTS
);
744 const CSearchResultList
& list
= theApp
->searchlist
->GetSearchResults(0xffffffff);
745 CSearchResultList::const_iterator it
= list
.begin();
746 while (it
!= list
.end()) {
747 CSearchFile
* sf
= *it
++;
748 CValueMap
&valuemap
= tagmap
.GetValueMap(sf
);
749 response
->AddTag(CEC_SearchFile_Tag(sf
, valuemap
));
754 CECPacket
*Get_EC_Response_Search_Results_Download(const CECPacket
*request
)
756 CECPacket
*response
= new CECPacket(EC_OP_STRINGS
);
757 for (int i
= 0;i
< request
->GetTagCount();i
++) {
758 const CECTag
*tag
= request
->GetTagByIndex(i
);
759 CMD4Hash hash
= tag
->GetMD4Data();
760 uint8 category
= tag
->GetTagByIndexSafe(0)->GetInt();
761 theApp
->searchlist
->AddFileToDownloadByHash(hash
, category
);
766 CECPacket
*Get_EC_Response_Search_Stop(const CECPacket
*WXUNUSED(request
))
768 CECPacket
*reply
= new CECPacket(EC_OP_MISC_DATA
);
769 theApp
->searchlist
->StopGlobalSearch();
773 CECPacket
*Get_EC_Response_Search(const CECPacket
*request
)
777 CEC_Search_Tag
*search_request
= (CEC_Search_Tag
*)request
->GetTagByIndex(0);
778 theApp
->searchlist
->RemoveResults(0xffffffff);
780 CSearchList::CSearchParams params
;
781 params
.searchString
= search_request
->SearchText();
782 params
.typeText
= search_request
->SearchFileType();
783 params
.extension
= search_request
->SearchExt();
784 params
.minSize
= search_request
->MinSize();
785 params
.maxSize
= search_request
->MaxSize();
786 params
.availability
= search_request
->Avail();
789 EC_SEARCH_TYPE search_type
= search_request
->SearchType();
790 SearchType core_search_type
= LocalSearch
;
791 switch (search_type
) {
792 case EC_SEARCH_GLOBAL
:
793 core_search_type
= GlobalSearch
;
795 if (core_search_type
!= GlobalSearch
) { // Not a global search obviously
796 core_search_type
= KadSearch
;
798 case EC_SEARCH_LOCAL
: {
799 uint32 search_id
= 0xffffffff;
800 wxString error
= theApp
->searchlist
->StartNewSearch(&search_id
, core_search_type
, params
);
801 if (!error
.IsEmpty()) {
804 response
= wxTRANSLATE("Search in progress. Refetch results in a moment!");
809 response
= wxTRANSLATE("WebSearch from remote interface makes no sense.");
813 CECPacket
*reply
= new CECPacket(EC_OP_FAILED
);
814 // error or search in progress
815 reply
->AddTag(CECTag(EC_TAG_STRING
, response
));
820 CECPacket
*Get_EC_Response_Set_SharedFile_Prio(const CECPacket
*request
)
822 CECPacket
*response
= new CECPacket(EC_OP_NOOP
);
823 for (int i
= 0;i
< request
->GetTagCount();i
++) {
824 const CECTag
*tag
= request
->GetTagByIndex(i
);
825 CMD4Hash hash
= tag
->GetMD4Data();
826 uint8 prio
= tag
->GetTagByIndexSafe(0)->GetInt();
827 CKnownFile
* cur_file
= theApp
->sharedfiles
->GetFileByID(hash
);
831 if (prio
== PR_AUTO
) {
832 cur_file
->SetAutoUpPriority(1);
833 cur_file
->UpdateAutoUpPriority();
835 cur_file
->SetAutoUpPriority(0);
836 cur_file
->SetUpPriority(prio
);
843 CECPacket
*Get_EC_Response_Kad_Connect(const CECPacket
*request
)
846 if (thePrefs::GetNetworkKademlia()) {
847 response
= new CECPacket(EC_OP_NOOP
);
848 if ( !Kademlia::CKademlia::IsRunning() ) {
849 Kademlia::CKademlia::Start();
850 theApp
->ShowConnectionState();
852 const CECTag
*addrtag
= request
->GetTagByIndex(0);
854 uint32 ip
= addrtag
->GetIPv4Data().IP();
855 uint16 port
= addrtag
->GetIPv4Data().m_port
;
856 Kademlia::CKademlia::Bootstrap(ip
, port
);
859 response
= new CECPacket(EC_OP_FAILED
);
860 response
->AddTag(CECTag(EC_TAG_STRING
, wxTRANSLATE("Kad is disabled in preferences.")));
866 // init with some default size
867 CPartFile_Encoder::GapBuffer
CPartFile_Encoder::m_gap_buffer(128);
870 CPartFile_Encoder::CPartFile_Encoder(CPartFile
*file
) :
871 m_enc_data(file
->GetPartCount(), file
->GetGapList().size() * 2)
877 CPartFile_Encoder::CPartFile_Encoder(int size
): m_enc_data(size
, 0)
882 CPartFile_Encoder::~CPartFile_Encoder()
887 CPartFile_Encoder::CPartFile_Encoder()
892 CPartFile_Encoder::CPartFile_Encoder(const CPartFile_Encoder
&obj
) : m_enc_data(obj
.m_enc_data
)
897 CPartFile_Encoder
&CPartFile_Encoder::operator=(const CPartFile_Encoder
&obj
)
900 m_enc_data
= obj
.m_enc_data
;
904 void CPartFile_Encoder::Encode(CECTag
*parent
)
906 const CPartFile::CGapPtrList
& gaplist
= m_file
->GetGapList();
907 const size_t gap_list_size
= gaplist
.size();
909 if ( m_gap_buffer
.size() < gap_list_size
* 2 ) {
910 m_gap_buffer
.clear();
911 m_gap_buffer
.resize(gap_list_size
* 2);
914 GapBuffer::iterator it
= m_gap_buffer
.begin();
916 CPartFile::CGapPtrList::const_iterator curr_pos
= gaplist
.begin();
917 for (; curr_pos
!= gaplist
.end(); ++curr_pos
) {
918 Gap_Struct
*curr
= *curr_pos
;
919 *it
++ = ENDIAN_HTONLL(curr
->start
);
920 *it
++ = ENDIAN_HTONLL(curr
->end
);
923 m_enc_data
.m_gap_status
.Realloc(gap_list_size
*2*sizeof(uint64
));
924 int gap_enc_size
= 0;
925 const unsigned char *gap_enc_data
= m_enc_data
.m_gap_status
.Encode((unsigned char *)&m_gap_buffer
[0], gap_enc_size
);
928 const unsigned char *part_enc_data
= m_enc_data
.m_part_status
.Encode(m_file
->m_SrcpartFrequency
, part_enc_size
);
931 parent
->AddTag(CECTag(EC_TAG_PARTFILE_PART_STATUS
, part_enc_size
, part_enc_data
));
934 // Put data inside of tag in following order:
935 // [num_of_gaps] [gap_enc_data]
937 unsigned char *tagdata
;
938 CECTag
etag(EC_TAG_PARTFILE_GAP_STATUS
,
939 sizeof(uint32
) + gap_enc_size
, (void **)&tagdata
);
941 // real number of gaps - so remote size can realloc
942 RawPokeUInt32( tagdata
, ENDIAN_HTONL( gap_list_size
) );
943 tagdata
+= sizeof(uint32
);
944 memcpy(tagdata
, gap_enc_data
, gap_enc_size
);
946 parent
->AddTag(etag
);
948 it
= m_gap_buffer
.begin();
950 const CPartFile::CReqBlockPtrList
& requestedblocks
= m_file
->GetRequestedBlockList();
951 CPartFile::CReqBlockPtrList::const_iterator curr_pos2
= requestedblocks
.begin();
953 wxASSERT(m_gap_buffer
.size() >= requestedblocks
.size() * 2);
954 for ( ; curr_pos2
!= requestedblocks
.end(); ++curr_pos2
) {
955 Requested_Block_Struct
* block
= *curr_pos2
;
956 *it
++ = ENDIAN_HTONLL(block
->StartOffset
);
957 *it
++ = ENDIAN_HTONLL(block
->EndOffset
);
959 parent
->AddTag(CECTag(EC_TAG_PARTFILE_REQ_STATUS
,
960 requestedblocks
.size() * 2 * sizeof(uint64
), (void *)&m_gap_buffer
[0]));
964 CKnownFile_Encoder::CKnownFile_Encoder(CKnownFile
*file
) :
965 m_enc_data(file
->GetPartCount(), true)
970 CKnownFile_Encoder::CKnownFile_Encoder()
975 CKnownFile_Encoder::~CKnownFile_Encoder()
979 CKnownFile_Encoder::CKnownFile_Encoder(const CKnownFile_Encoder
&obj
) : m_enc_data(obj
.m_enc_data
)
984 CKnownFile_Encoder
&CKnownFile_Encoder::operator=(const CKnownFile_Encoder
&obj
)
987 m_enc_data
= obj
.m_enc_data
;
991 void CKnownFile_Encoder::Encode(CECTag
*parent
)
994 const unsigned char *part_enc_data
= m_enc_data
.Encode(m_file
->m_AvailPartFrequency
, part_enc_size
);
996 parent
->AddTag(CECTag(EC_TAG_PARTFILE_PART_STATUS
, part_enc_size
, part_enc_data
));
999 CECPacket
*GetStatsGraphs(const CECPacket
*request
)
1001 CECPacket
*response
= NULL
;
1003 switch (request
->GetDetailLevel()) {
1005 case EC_DETAIL_FULL
: {
1006 double dTimestamp
= 0.0;
1007 if (request
->GetTagByName(EC_TAG_STATSGRAPH_LAST
) != NULL
) {
1008 dTimestamp
= request
->GetTagByName(EC_TAG_STATSGRAPH_LAST
)->GetDoubleData();
1010 uint16 nScale
= request
->GetTagByNameSafe(EC_TAG_STATSGRAPH_SCALE
)->GetInt();
1011 uint16 nMaxPoints
= request
->GetTagByNameSafe(EC_TAG_STATSGRAPH_WIDTH
)->GetInt();
1013 unsigned int numPoints
= theApp
->m_statistics
->GetHistoryForWeb(nMaxPoints
, (double)nScale
, &dTimestamp
, &graphData
);
1015 response
= new CECPacket(EC_OP_STATSGRAPHS
);
1016 response
->AddTag(CECTag(EC_TAG_STATSGRAPH_DATA
, 4 * numPoints
* sizeof(uint32
), graphData
));
1017 delete [] graphData
;
1018 response
->AddTag(CECTag(EC_TAG_STATSGRAPH_LAST
, dTimestamp
));
1020 response
= new CECPacket(EC_OP_FAILED
);
1021 response
->AddTag(CECTag(EC_TAG_STRING
, wxTRANSLATE("No points for graph.")));
1025 case EC_DETAIL_INC_UPDATE
:
1026 case EC_DETAIL_UPDATE
:
1029 response
= new CECPacket(EC_OP_FAILED
);
1030 response
->AddTag(CECTag(EC_TAG_STRING
, wxTRANSLATE("Your client is not configured for this detail level.")));
1034 response
= new CECPacket(EC_OP_FAILED
);
1041 CECPacket
*ExternalConn::ProcessRequest2(const CECPacket
*request
,
1042 CPartFile_Encoder_Map
&enc_part_map
, CKnownFile_Encoder_Map
&enc_shared_map
, CObjTagMap
&objmap
)
1049 CECPacket
*response
= NULL
;
1051 switch (request
->GetOpCode()) {
1055 case EC_OP_SHUTDOWN
:
1056 if (!theApp
->IsOnShutDown()) {
1057 response
= new CECPacket(EC_OP_NOOP
);
1058 AddLogLineM(true, _("ExternalConn: shutdown requested"));
1059 #ifndef AMULE_DAEMON
1062 evt
.SetCanVeto(false);
1063 theApp
->ShutDown(evt
);
1066 theApp
->ExitMainLoop();
1069 response
= new CECPacket(EC_OP_FAILED
);
1070 response
->AddTag(CECTag(EC_TAG_STRING
, wxTRANSLATE("Already shutting down.")));
1073 case EC_OP_ADD_LINK
:
1074 for(int i
= 0; i
< request
->GetTagCount();i
++) {
1075 const CECTag
*tag
= request
->GetTagByIndex(i
);
1076 wxString link
= tag
->GetStringData();
1077 int category
= tag
->GetTagByIndexSafe(0)->GetInt();
1078 AddLogLineM(true, CFormat(_("ExternalConn: adding link '%s'.")) % link
);
1079 if ( theApp
->downloadqueue
->AddLink(link
, category
) ) {
1080 response
= new CECPacket(EC_OP_NOOP
);
1082 // Error messages are printed by the add function.
1083 response
= new CECPacket(EC_OP_FAILED
);
1084 response
->AddTag(CECTag(EC_TAG_STRING
, wxTRANSLATE("Invalid link or already on list.")));
1091 case EC_OP_STAT_REQ
:
1092 response
= Get_EC_Response_StatRequest(request
);
1093 case EC_OP_GET_CONNSTATE
:
1095 response
= new CECPacket(EC_OP_MISC_DATA
);
1097 response
->AddTag(CEC_ConnState_Tag(request
->GetDetailLevel()));
1102 case EC_OP_GET_SHARED_FILES
:
1103 if ( request
->GetDetailLevel() == EC_DETAIL_INC_UPDATE
) {
1104 response
= Get_EC_Response_GetSharedFiles(enc_shared_map
, objmap
);
1106 response
= Get_EC_Response_GetSharedFiles(request
, enc_shared_map
);
1109 case EC_OP_GET_DLOAD_QUEUE
:
1110 if ( request
->GetDetailLevel() == EC_DETAIL_INC_UPDATE
) {
1111 response
= Get_EC_Response_GetDownloadQueue(enc_part_map
, objmap
);
1113 response
= Get_EC_Response_GetDownloadQueue(request
, enc_part_map
);
1116 // transmit source names and comments only if file detail dialog is open
1117 case EC_OP_GET_DLOAD_QUEUE_DETAIL
:
1118 if ( request
->GetDetailLevel() == EC_DETAIL_INC_UPDATE
) {
1119 response
= Get_EC_Response_GetDownloadQueue(enc_part_map
, objmap
);
1121 response
= Get_EC_Response_GetDownloadQueue(request
, enc_part_map
, true);
1124 case EC_OP_GET_ULOAD_QUEUE
:
1125 if ( request
->GetDetailLevel() == EC_DETAIL_INC_UPDATE
) {
1126 response
= Get_EC_Response_GetUpQueue(objmap
);
1128 response
= Get_EC_Response_GetUpQueue(request
);
1131 case EC_OP_GET_WAIT_QUEUE
:
1132 if ( request
->GetDetailLevel() == EC_DETAIL_INC_UPDATE
) {
1133 response
= Get_EC_Response_GetWaitQueue(objmap
);
1135 response
= Get_EC_Response_GetWaitQueue(request
);
1138 case EC_OP_PARTFILE_REMOVE_NO_NEEDED
:
1139 case EC_OP_PARTFILE_REMOVE_FULL_QUEUE
:
1140 case EC_OP_PARTFILE_REMOVE_HIGH_QUEUE
:
1141 case EC_OP_PARTFILE_CLEANUP_SOURCES
:
1142 case EC_OP_PARTFILE_SWAP_A4AF_THIS
:
1143 case EC_OP_PARTFILE_SWAP_A4AF_THIS_AUTO
:
1144 case EC_OP_PARTFILE_SWAP_A4AF_OTHERS
:
1145 case EC_OP_PARTFILE_PAUSE
:
1146 case EC_OP_PARTFILE_RESUME
:
1147 case EC_OP_PARTFILE_STOP
:
1148 case EC_OP_PARTFILE_PRIO_SET
:
1149 case EC_OP_PARTFILE_DELETE
:
1150 case EC_OP_PARTFILE_SET_CAT
:
1151 response
= Get_EC_Response_PartFile_Cmd(request
);
1153 case EC_OP_SHAREDFILES_RELOAD
:
1154 theApp
->sharedfiles
->Reload();
1155 response
= new CECPacket(EC_OP_NOOP
);
1157 case EC_OP_SHARED_SET_PRIO
:
1158 response
= Get_EC_Response_Set_SharedFile_Prio(request
);
1160 case EC_OP_RENAME_FILE
: {
1161 CMD4Hash fileHash
= request
->GetTagByNameSafe(EC_TAG_KNOWNFILE
)->GetMD4Data();
1162 CKnownFile
* file
= theApp
->knownfiles
->FindKnownFileByID(fileHash
);
1163 wxString newName
= request
->GetTagByNameSafe(EC_TAG_PARTFILE_NAME
)->GetStringData();
1165 file
= theApp
->downloadqueue
->GetFileByID(fileHash
);
1168 response
= new CECPacket(EC_OP_FAILED
);
1169 response
->AddTag(CECTag(EC_TAG_STRING
, wxTRANSLATE("File not found.")));
1172 if (newName
.IsEmpty()) {
1173 response
= new CECPacket(EC_OP_FAILED
);
1174 response
->AddTag(CECTag(EC_TAG_STRING
, wxTRANSLATE("Invalid file name.")));
1178 if (theApp
->sharedfiles
->RenameFile(file
, CPath(newName
))) {
1179 response
= new CECPacket(EC_OP_NOOP
);
1181 response
= new CECPacket(EC_OP_FAILED
);
1182 response
->AddTag(CECTag(EC_TAG_STRING
, wxTRANSLATE("Unable to rename file.")));
1192 case EC_OP_SERVER_ADD
:
1193 response
= Get_EC_Response_Server_Add(request
);
1195 case EC_OP_SERVER_DISCONNECT
:
1196 case EC_OP_SERVER_CONNECT
:
1197 case EC_OP_SERVER_REMOVE
:
1198 response
= Get_EC_Response_Server(request
);
1200 case EC_OP_GET_SERVER_LIST
: {
1201 response
= new CECPacket(EC_OP_SERVER_LIST
);
1202 EC_DETAIL_LEVEL detail_level
= request
->GetDetailLevel();
1203 std::vector
<const CServer
*> servers
= theApp
->serverlist
->CopySnapshot();
1205 std::vector
<const CServer
*>::const_iterator it
= servers
.begin();
1206 it
!= servers
.end();
1209 response
->AddTag(CEC_Server_Tag(*it
, detail_level
));
1213 case EC_OP_SERVER_UPDATE_FROM_URL
: {
1214 wxString url
= request
->GetTagByIndexSafe(0)->GetStringData();
1216 // Save the new url, and update the UI (if not amuled).
1217 Notify_ServersURLChanged(url
);
1218 thePrefs::SetEd2kServersUrl(url
);
1220 theApp
->serverlist
->UpdateServerMetFromURL(url
);
1221 response
= new CECPacket(EC_OP_NOOP
);
1227 case EC_OP_IPFILTER_RELOAD
:
1228 theApp
->ipfilter
->Reload();
1229 response
= new CECPacket(EC_OP_NOOP
);
1234 case EC_OP_SEARCH_START
:
1235 response
= Get_EC_Response_Search(request
);
1238 case EC_OP_SEARCH_STOP
:
1239 response
= Get_EC_Response_Search_Stop(request
);
1242 case EC_OP_SEARCH_RESULTS
:
1243 if ( request
->GetDetailLevel() == EC_DETAIL_INC_UPDATE
) {
1244 response
= Get_EC_Response_Search_Results(objmap
);
1246 response
= Get_EC_Response_Search_Results(request
);
1250 case EC_OP_SEARCH_PROGRESS
:
1251 response
= new CECPacket(EC_OP_SEARCH_PROGRESS
);
1252 response
->AddTag(CECTag(EC_TAG_SEARCH_STATUS
,
1253 theApp
->searchlist
->GetSearchProgress()));
1256 case EC_OP_DOWNLOAD_SEARCH_RESULT
:
1257 response
= Get_EC_Response_Search_Results_Download(request
);
1262 case EC_OP_GET_PREFERENCES
:
1263 response
= new CEC_Prefs_Packet(request
->GetTagByNameSafe(EC_TAG_SELECT_PREFS
)->GetInt(), request
->GetDetailLevel());
1265 case EC_OP_SET_PREFERENCES
:
1266 ((CEC_Prefs_Packet
*)request
)->Apply();
1267 theApp
->glob_prefs
->Save();
1268 if (thePrefs::IsFilteringClients()) {
1269 theApp
->clientlist
->FilterQueues();
1271 if (thePrefs::IsFilteringServers()) {
1272 theApp
->serverlist
->FilterServers();
1274 if (!thePrefs::GetNetworkED2K() && theApp
->IsConnectedED2K()) {
1275 theApp
->DisconnectED2K();
1277 if (!thePrefs::GetNetworkKademlia() && theApp
->IsConnectedKad()) {
1280 response
= new CECPacket(EC_OP_NOOP
);
1283 case EC_OP_CREATE_CATEGORY
:
1284 if ( request
->GetTagCount() == 1 ) {
1285 ((CEC_Category_Tag
*)request
->GetTagByIndex(0))->Create();
1286 Notify_CategoryAdded();
1288 response
= new CECPacket(EC_OP_NOOP
);
1290 case EC_OP_UPDATE_CATEGORY
:
1291 if ( request
->GetTagCount() == 1 ) {
1292 CEC_Category_Tag
*tag
= (CEC_Category_Tag
*)request
->GetTagByIndex(0);
1294 Notify_CategoryUpdate(tag
->GetInt());
1296 response
= new CECPacket(EC_OP_NOOP
);
1298 case EC_OP_DELETE_CATEGORY
:
1299 if ( request
->GetTagCount() == 1 ) {
1300 uint32 cat
= request
->GetTagByIndex(0)->GetInt();
1301 Notify_CategoryDelete(cat
);
1303 response
= new CECPacket(EC_OP_NOOP
);
1309 case EC_OP_ADDLOGLINE
:
1310 AddLogLineM( (request
->GetTagByName(EC_TAG_LOG_TO_STATUS
) != NULL
), request
->GetTagByNameSafe(EC_TAG_STRING
)->GetStringData() );
1311 response
= new CECPacket(EC_OP_NOOP
);
1313 case EC_OP_ADDDEBUGLOGLINE
:
1314 AddDebugLogLineM( (request
->GetTagByName(EC_TAG_LOG_TO_STATUS
) != NULL
), logGeneral
, request
->GetTagByNameSafe(EC_TAG_STRING
)->GetStringData() );
1315 response
= new CECPacket(EC_OP_NOOP
);
1318 response
= new CECPacket(EC_OP_LOG
);
1319 response
->AddTag(CECTag(EC_TAG_STRING
, theApp
->GetLog(false)));
1321 case EC_OP_GET_DEBUGLOG
:
1322 response
= new CECPacket(EC_OP_DEBUGLOG
);
1323 response
->AddTag(CECTag(EC_TAG_STRING
, theApp
->GetDebugLog(false)));
1325 case EC_OP_RESET_LOG
:
1326 theApp
->GetLog(true);
1327 response
= new CECPacket(EC_OP_NOOP
);
1329 case EC_OP_RESET_DEBUGLOG
:
1330 theApp
->GetDebugLog(true);
1331 response
= new CECPacket(EC_OP_NOOP
);
1333 case EC_OP_GET_LAST_LOG_ENTRY
:
1335 wxString tmp
= theApp
->GetLog(false);
1336 if (tmp
.Last() == '\n') {
1339 response
= new CECPacket(EC_OP_LOG
);
1340 response
->AddTag(CECTag(EC_TAG_STRING
, tmp
.AfterLast('\n')));
1343 case EC_OP_GET_SERVERINFO
:
1344 response
= new CECPacket(EC_OP_SERVERINFO
);
1345 response
->AddTag(CECTag(EC_TAG_STRING
, theApp
->GetServerLog(false)));
1347 case EC_OP_CLEAR_SERVERINFO
:
1348 theApp
->GetServerLog(true);
1349 response
= new CECPacket(EC_OP_NOOP
);
1354 case EC_OP_GET_STATSGRAPHS
:
1355 response
= GetStatsGraphs(request
);
1357 case EC_OP_GET_STATSTREE
: {
1358 theApp
->m_statistics
->UpdateStatsTree();
1359 response
= new CECPacket(EC_OP_STATSTREE
);
1360 CECTag
* tree
= theStats::GetECStatTree(request
->GetTagByNameSafe(EC_TAG_STATTREE_CAPPING
)->GetInt());
1362 response
->AddTag(*tree
);
1365 if (request
->GetDetailLevel() == EC_DETAIL_WEB
) {
1366 response
->AddTag(CECTag(EC_TAG_SERVER_VERSION
, wxT(VERSION
)));
1367 response
->AddTag(CECTag(EC_TAG_USER_NICK
, thePrefs::GetUserNick()));
1375 case EC_OP_KAD_START
:
1376 response
= Get_EC_Response_Kad_Connect(request
);
1378 case EC_OP_KAD_STOP
:
1380 response
= new CECPacket(EC_OP_NOOP
);
1382 case EC_OP_KAD_UPDATE_FROM_URL
: {
1383 wxString url
= request
->GetTagByIndexSafe(0)->GetStringData();
1385 // Save the new url, and update the UI (if not amuled).
1386 Notify_NodesURLChanged(url
);
1387 thePrefs::SetKadNodesUrl(url
);
1389 theApp
->UpdateNotesDat(url
);
1390 response
= new CECPacket(EC_OP_NOOP
);
1393 case EC_OP_KAD_BOOTSTRAP_FROM_IP
:
1394 theApp
->BootstrapKad(request
->GetTagByIndexSafe(0)->GetInt(),
1395 request
->GetTagByIndexSafe(1)->GetInt());
1396 response
= new CECPacket(EC_OP_NOOP
);
1403 if (thePrefs::GetNetworkED2K()) {
1404 response
= new CECPacket(EC_OP_STRINGS
);
1405 if (theApp
->IsConnectedED2K()) {
1406 response
->AddTag(CECTag(EC_TAG_STRING
, wxTRANSLATE("Already connected to ED2K.")));
1408 theApp
->serverconnect
->ConnectToAnyServer();
1409 response
->AddTag(CECTag(EC_TAG_STRING
, wxTRANSLATE("Connecting to ED2K...")));
1412 if (thePrefs::GetNetworkKademlia()) {
1414 response
= new CECPacket(EC_OP_STRINGS
);
1416 if (theApp
->IsConnectedKad()) {
1417 response
->AddTag(CECTag(EC_TAG_STRING
, wxTRANSLATE("Already connected to Kad.")));
1420 response
->AddTag(CECTag(EC_TAG_STRING
, wxTRANSLATE("Connecting to Kad...")));
1424 response
= new CECPacket(EC_OP_FAILED
);
1425 response
->AddTag(CECTag(EC_TAG_STRING
, wxTRANSLATE("All networks are disabled.")));
1428 case EC_OP_DISCONNECT
:
1429 if (theApp
->IsConnected()) {
1430 response
= new CECPacket(EC_OP_STRINGS
);
1431 if (theApp
->IsConnectedED2K()) {
1432 theApp
->serverconnect
->Disconnect();
1433 response
->AddTag(CECTag(EC_TAG_STRING
, wxTRANSLATE("Disconnected from ED2K.")));
1435 if (theApp
->IsConnectedKad()) {
1437 response
->AddTag(CECTag(EC_TAG_STRING
, wxTRANSLATE("Disconnected from Kad.")));
1440 response
= new CECPacket(EC_OP_NOOP
);
1445 AddLogLineM(false, wxString::Format(_("ExternalConn: invalid opcode received: %#x"), request
->GetOpCode()));
1447 response
= new CECPacket(EC_OP_FAILED
);
1448 response
->AddTag(CECTag(EC_TAG_STRING
, wxTRANSLATE("Invalid opcode (wrong protocol version?)")));
1453 // File_checked_for_headers