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 )
6 // Copyright (c) 2008 Froenchenko Leonid (lfroen@gmail.com)
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.
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.
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.
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
28 #include "config.h" // Needed for VERSION
31 #include <ec/cpp/ECMuleSocket.h> // Needed for CECSocket
33 #include <common/Format.h> // Needed for CFormat
35 #include <common/ClientVersion.h>
36 #include <common/MD5Sum.h>
38 #include "ExternalConn.h" // Interface declarations
39 #include "updownclient.h" // Needed for CUpDownClient
40 #include "Server.h" // Needed for CServer
41 #include "ServerList.h" // Needed for CServerList
42 #include "PartFile.h" // Needed for CPartFile
43 #include "ServerConnect.h" // Needed for CServerConnect
44 #include "UploadQueue.h" // Needed for CUploadQueue
45 #include "amule.h" // Needed for theApp
46 #include "SearchList.h" // Needed for GetSearchResults
47 #include "IPFilter.h" // Needed for CIPFilter
48 #include "ClientList.h"
49 #include "Preferences.h" // Needed for CPreferences
51 #include "GuiEvents.h" // Needed for Notify_* macros
52 #include "Statistics.h" // Needed for theStats
53 #include "KnownFileList.h" // Needed for CKnownFileList
54 #include "RandomFunctions.h"
55 #include "kademlia/kademlia/Kademlia.h"
56 #include "kademlia/kademlia/UDPFirewallTester.h"
59 //-------------------- CECServerSocket --------------------
61 class CECServerSocket
: public CECMuleSocket
64 CECServerSocket(ECNotifier
*notifier
);
65 virtual ~CECServerSocket();
67 virtual const CECPacket
*OnPacketReceived(const CECPacket
*packet
);
68 virtual void OnLost();
70 virtual void WriteDoneAndQueueEmpty();
72 ECNotifier
*m_ec_notifier
;
74 const CECPacket
*Authenticate(const CECPacket
*);
83 uint64_t m_passwd_salt
;
84 CLoggerAccess m_LoggerAccess
;
85 CPartFile_Encoder_Map m_part_encoder
;
86 CKnownFile_Encoder_Map m_shared_encoder
;
87 CObjTagMap m_obj_tagmap
;
88 CECPacket
*ProcessRequest2(
89 const CECPacket
*request
,
90 CPartFile_Encoder_Map
&,
91 CKnownFile_Encoder_Map
&,
97 CECServerSocket::CECServerSocket(ECNotifier
*notifier
)
100 m_conn_state(CONN_INIT
),
101 m_passwd_salt(GetRandomUint64()),
106 wxASSERT(theApp
->ECServerHandler
);
107 theApp
->ECServerHandler
->AddSocket(this);
108 m_ec_notifier
= notifier
;
112 CECServerSocket::~CECServerSocket()
114 wxASSERT(theApp
->ECServerHandler
);
115 theApp
->ECServerHandler
->RemoveSocket(this);
119 const CECPacket
*CECServerSocket::OnPacketReceived(const CECPacket
*packet
)
121 packet
->DebugPrint(true);
123 const CECPacket
*reply
= NULL
;
125 if (m_conn_state
== CONN_FAILED
) {
126 // Client didn't close the socket when authentication failed.
127 AddLogLineM(false, _("Client sent packet after authentication failed."));
131 if (m_conn_state
!= CONN_ESTABLISHED
) {
132 reply
= Authenticate(packet
);
133 if (reply
->GetOpCode() == EC_OP_AUTH_FAIL
) {
135 AddLogLineM(false, _("Unauthorized access attempt. Connection closed."));
136 m_conn_state
= CONN_FAILED
;
138 theApp
->ECServerHandler
->m_ec_notifier
->Add_EC_Client(this);
141 reply
= ProcessRequest2(
142 packet
, m_part_encoder
, m_shared_encoder
, m_obj_tagmap
);
148 void CECServerSocket::OnLost()
150 AddLogLineM(false,_("External connection closed."));
151 theApp
->ECServerHandler
->m_ec_notifier
->Remove_EC_Client(this);
155 void CECServerSocket::WriteDoneAndQueueEmpty()
157 if ( HaveNotificationSupport() && (m_conn_state
== CONN_ESTABLISHED
) ) {
158 CECPacket
*packet
= m_ec_notifier
->GetNextPacket(this);
163 //printf("[EC] %p: WriteDoneAndQueueEmpty but notification disabled\n", this);
167 //-------------------- ExternalConn --------------------
175 BEGIN_EVENT_TABLE(ExternalConn
, wxEvtHandler
)
176 EVT_SOCKET(SERVER_ID
, ExternalConn::OnServerEvent
)
180 ExternalConn::ExternalConn(amuleIPV4Address addr
, wxString
*msg
)
184 // Are we allowed to accept External Connections?
185 if ( thePrefs::AcceptExternalConnections() ) {
186 // We must have a valid password, otherwise we will not allow EC connections
187 if (thePrefs::ECPassword().IsEmpty()) {
188 *msg
+= wxT("External connections disabled due to empty password!\n");
189 AddLogLineM(true, _("External connections disabled due to empty password!"));
194 m_ECServer
= new wxSocketServer(addr
, wxSOCKET_REUSEADDR
);
195 m_ECServer
->SetEventHandler(*this, SERVER_ID
);
196 m_ECServer
->SetNotify(wxSOCKET_CONNECTION_FLAG
);
197 m_ECServer
->Notify(true);
199 int port
= addr
.Service();
200 wxString ip
= addr
.IPAddress();
201 if (m_ECServer
->Ok()) {
202 msgLocal
= wxT("*** TCP socket (ECServer) listening on ") + ip
+
203 wxString::Format(wxT(":%d"), port
);
204 *msg
+= msgLocal
+ wxT("\n");
205 AddLogLineM(false, msgLocal
);
207 msgLocal
= wxT("Could not listen for external connections at ") + ip
+
208 wxString::Format(wxT(":%d!"), port
);
209 *msg
+= msgLocal
+ wxT("\n");
210 AddLogLineM(false, msgLocal
);
213 *msg
+= wxT("External connections disabled in config file\n");
214 AddLogLineM(false,_("External connections disabled in config file"));
216 m_ec_notifier
= new ECNotifier();
220 ExternalConn::~ExternalConn()
224 delete m_ec_notifier
;
228 void ExternalConn::AddSocket(CECServerSocket
*s
)
231 socket_list
.insert(s
);
235 void ExternalConn::RemoveSocket(CECServerSocket
*s
)
238 socket_list
.erase(s
);
242 void ExternalConn::KillAllSockets()
244 AddDebugLogLineM(false, logGeneral
,
245 CFormat(wxT("ExternalConn::KillAllSockets(): %d sockets to destroy.")) %
247 SocketSet::iterator it
= socket_list
.begin();
248 while (it
!= socket_list
.end()) {
249 CECServerSocket
*s
= *(it
++);
257 void ExternalConn::OnServerEvent(wxSocketEvent
& WXUNUSED(event
))
259 CECServerSocket
*sock
= new CECServerSocket(m_ec_notifier
);
260 // Accept new connection if there is one in the pending
261 // connections queue, else exit. We use Accept(FALSE) for
262 // non-blocking accept (although if we got here, there
263 // should ALWAYS be a pending connection).
264 if ( m_ECServer
->AcceptWith(*sock
, false) ) {
265 AddLogLineM(false, _("New external connection accepted"));
268 AddLogLineM(false, _("ERROR: couldn't accept a new external connection"));
276 const CECPacket
*CECServerSocket::Authenticate(const CECPacket
*request
)
280 if (request
== NULL
) {
281 response
= new CECPacket(EC_OP_AUTH_FAIL
);
285 // Password must be specified if we are to allow remote connections
286 if ( thePrefs::ECPassword().IsEmpty() ) {
287 AddLogLineM(true, _("External connection refused due to empty password in preferences!"));
289 return new CECPacket(EC_OP_AUTH_FAIL
);
292 if ((m_conn_state
== CONN_INIT
) && (request
->GetOpCode() == EC_OP_AUTH_REQ
) ) {
293 const CECTag
*clientName
= request
->GetTagByName(EC_TAG_CLIENT_NAME
);
294 const CECTag
*clientVersion
= request
->GetTagByName(EC_TAG_CLIENT_VERSION
);
296 AddLogLineM(false, CFormat( _("Connecting client: %s %s") )
297 % ( clientName
? clientName
->GetStringData() : wxString(_("Unknown")) )
298 % ( clientVersion
? clientVersion
->GetStringData() : wxString(_("Unknown version")) ) );
299 const CECTag
*protocol
= request
->GetTagByName(EC_TAG_PROTOCOL_VERSION
);
301 // For SVN versions, both client and server must use SVNDATE, and they must be the same
303 if (!vhash
.Decode(wxT(EC_VERSION_ID
))) {
304 response
= new CECPacket(EC_OP_AUTH_FAIL
);
305 response
->AddTag(CECTag(EC_TAG_STRING
, wxT("Fatal error, version hash is not a valid MD4-hash.")));
306 } else if (!request
->GetTagByName(EC_TAG_VERSION_ID
) || request
->GetTagByNameSafe(EC_TAG_VERSION_ID
)->GetMD4Data() != vhash
) {
307 response
= new CECPacket(EC_OP_AUTH_FAIL
);
308 response
->AddTag(CECTag(EC_TAG_STRING
, wxTRANSLATE("Incorrect EC version ID, there might be binary incompatibility. Use core and remote from same snapshot.")));
310 // For release versions, we don't want to allow connections from any arbitrary SVN client.
311 if (request
->GetTagByName(EC_TAG_VERSION_ID
)) {
312 response
= new CECPacket(EC_OP_AUTH_FAIL
);
313 response
->AddTag(CECTag(EC_TAG_STRING
, wxTRANSLATE("You cannot connect to a release version from an arbitrary SVN version! *sigh* possible crash prevented")));
315 } else if (protocol
!= NULL
) {
316 uint16 proto_version
= protocol
->GetInt();
317 if (proto_version
== EC_CURRENT_PROTOCOL_VERSION
) {
318 response
= new CECPacket(EC_OP_AUTH_SALT
);
319 response
->AddTag(CECTag(EC_TAG_PASSWD_SALT
, m_passwd_salt
));
320 m_conn_state
= CONN_SALT_SENT
;
322 response
= new CECPacket(EC_OP_AUTH_FAIL
);
323 response
->AddTag(CECTag(EC_TAG_STRING
, wxTRANSLATE("Invalid protocol version.") + wxString::Format(wxT("( %i != %i )"),proto_version
,EC_CURRENT_PROTOCOL_VERSION
)));
326 response
= new CECPacket(EC_OP_AUTH_FAIL
);
327 response
->AddTag(CECTag(EC_TAG_STRING
, wxTRANSLATE("Missing protocol version tag.")));
329 } else if ((m_conn_state
== CONN_SALT_SENT
) && (request
->GetOpCode() == EC_OP_AUTH_PASSWD
)) {
330 const CECTag
*passwd
= request
->GetTagByName(EC_TAG_PASSWD_HASH
);
333 if (!passh
.Decode(thePrefs::ECPassword())) {
334 AddLogLineM(false, wxT("EC Auth failed, invalid hash specificed as EC password: ") + thePrefs::ECPassword());
335 response
= new CECPacket(EC_OP_AUTH_FAIL
);
336 response
->AddTag(CECTag(EC_TAG_STRING
, wxT("Authentication failed, invalid hash specified as EC password.")));
338 wxString saltHash
= MD5Sum(CFormat(wxT("%lX")) % m_passwd_salt
).GetHash();
339 wxString saltStr
= CFormat(wxT("%lX")) % m_passwd_salt
;
341 passh
.Decode(MD5Sum(thePrefs::ECPassword().Lower() + saltHash
).GetHash());
343 if (passwd
&& passwd
->GetMD4Data() == passh
) {
344 response
= new CECPacket(EC_OP_AUTH_OK
);
345 response
->AddTag(CECTag(EC_TAG_SERVER_VERSION
, wxT(VERSION
)));
348 AddLogLineM(false, wxT("EC Auth failed: (") + passwd
->GetMD4Data().Encode() + wxT(" != ") + passh
.Encode() + wxT(")."));
350 AddLogLineM(false, wxT("EC Auth failed. Password tag missing."));
353 response
= new CECPacket(EC_OP_AUTH_FAIL
);
354 response
->AddTag(CECTag(EC_TAG_STRING
, wxTRANSLATE("Authentication failed.")));
358 response
= new CECPacket(EC_OP_AUTH_FAIL
);
359 response
->AddTag(CECTag(EC_TAG_STRING
, wxTRANSLATE("Invalid request, please authenticate first.")));
362 if (response
->GetOpCode() == EC_OP_AUTH_OK
) {
363 m_conn_state
= CONN_ESTABLISHED
;
364 AddLogLineM(false, _("Access granted."));
365 } else if (response
->GetTagByIndex(0)->IsString()) {
366 AddLogLineM(false, wxGetTranslation(response
->GetTagByIndex(0)->GetStringData()));
372 // Make a Logger tag (if there are any logging messages) and add it to the response
373 static void AddLoggerTag(CECPacket
*response
, CLoggerAccess
&LoggerAccess
)
375 if (LoggerAccess
.HasString()) {
376 CECEmptyTag
tag(EC_TAG_STATS_LOGGER_MESSAGE
);
377 // Tag structure is fix: tag carries nothing, inside are the strings
378 // maximum of 200 log lines per message
381 while (entries
< 200 && LoggerAccess
.GetString(line
)) {
382 tag
.AddTag(CECTag(EC_TAG_STRING
, line
));
385 response
->AddTag(tag
);
386 //printf("send Log tag %d %d\n", FirstEntry, entries);
390 CECPacket
*Get_EC_Response_StatRequest(const CECPacket
*request
, CLoggerAccess
&LoggerAccess
)
392 CECPacket
*response
= new CECPacket(EC_OP_STATS
);
394 switch (request
->GetDetailLevel()) {
396 response
->AddTag(CECTag(EC_TAG_STATS_UP_OVERHEAD
, (uint32
)theStats::GetUpOverheadRate()));
397 response
->AddTag(CECTag(EC_TAG_STATS_DOWN_OVERHEAD
, (uint32
)theStats::GetDownOverheadRate()));
398 response
->AddTag(CECTag(EC_TAG_STATS_BANNED_COUNT
, /*(uint32)*/theStats::GetBannedCount()));
399 AddLoggerTag(response
, LoggerAccess
);
402 response
->AddTag(CECTag(EC_TAG_STATS_UL_SPEED
, (uint32
)theStats::GetUploadRate()));
403 response
->AddTag(CECTag(EC_TAG_STATS_DL_SPEED
, (uint32
)(theStats::GetDownloadRate())));
404 response
->AddTag(CECTag(EC_TAG_STATS_UL_SPEED_LIMIT
, (uint32
)(thePrefs::GetMaxUpload()*1024.0)));
405 response
->AddTag(CECTag(EC_TAG_STATS_DL_SPEED_LIMIT
, (uint32
)(thePrefs::GetMaxDownload()*1024.0)));
406 response
->AddTag(CECTag(EC_TAG_STATS_UL_QUEUE_LEN
, /*(uint32)*/theStats::GetWaitingUserCount()));
407 response
->AddTag(CECTag(EC_TAG_STATS_TOTAL_SRC_COUNT
, /*(uint32)*/theStats::GetFoundSources()));
410 uint32 totaluser
= 0, totalfile
= 0;
411 theApp
->serverlist
->GetUserFileStatus( totaluser
, totalfile
);
412 response
->AddTag(CECTag(EC_TAG_STATS_ED2K_USERS
, totaluser
));
413 response
->AddTag(CECTag(EC_TAG_STATS_KAD_USERS
, Kademlia::CKademlia::GetKademliaUsers()));
414 response
->AddTag(CECTag(EC_TAG_STATS_ED2K_FILES
, totalfile
));
415 response
->AddTag(CECTag(EC_TAG_STATS_KAD_FILES
, Kademlia::CKademlia::GetKademliaFiles()));
418 if (Kademlia::CKademlia::IsConnected()) {
419 response
->AddTag(CECTag(EC_TAG_STATS_KAD_FIREWALLED_UDP
, Kademlia::CUDPFirewallTester::IsFirewalledUDP(true)));
420 response
->AddTag(CECTag(EC_TAG_STATS_KAD_INDEXED_SOURCES
, Kademlia::CKademlia::GetIndexed()->m_totalIndexSource
));
421 response
->AddTag(CECTag(EC_TAG_STATS_KAD_INDEXED_KEYWORDS
, Kademlia::CKademlia::GetIndexed()->m_totalIndexKeyword
));
422 response
->AddTag(CECTag(EC_TAG_STATS_KAD_INDEXED_NOTES
, Kademlia::CKademlia::GetIndexed()->m_totalIndexNotes
));
423 response
->AddTag(CECTag(EC_TAG_STATS_KAD_INDEXED_LOAD
, Kademlia::CKademlia::GetIndexed()->m_totalIndexLoad
));
424 response
->AddTag(CECTag(EC_TAG_STATS_KAD_IP_ADRESS
, wxUINT32_SWAP_ALWAYS(Kademlia::CKademlia::GetPrefs()->GetIPAddress())));
425 response
->AddTag(CECTag(EC_TAG_STATS_BUDDY_STATUS
, theApp
->clientlist
->GetBuddyStatus()));
427 uint16 BuddyPort
= 0;
428 CUpDownClient
* Buddy
= theApp
->clientlist
->GetBuddy();
430 BuddyIP
= Buddy
->GetIP();
431 BuddyPort
= Buddy
->GetUDPPort();
433 response
->AddTag(CECTag(EC_TAG_STATS_BUDDY_IP
, BuddyIP
));
434 response
->AddTag(CECTag(EC_TAG_STATS_BUDDY_PORT
, BuddyPort
));
436 case EC_DETAIL_UPDATE
:
437 case EC_DETAIL_INC_UPDATE
:
444 CECPacket
*Get_EC_Response_GetSharedFiles(const CECPacket
*request
, CKnownFile_Encoder_Map
&encoders
)
446 wxASSERT(request
->GetOpCode() == EC_OP_GET_SHARED_FILES
);
448 CECPacket
*response
= new CECPacket(EC_OP_SHARED_FILES
);
450 EC_DETAIL_LEVEL detail_level
= request
->GetDetailLevel();
452 // request can contain list of queried items
453 CTagSet
<CMD4Hash
, EC_TAG_KNOWNFILE
> queryitems(request
);
455 encoders
.UpdateEncoders(theApp
->sharedfiles
);
457 for (uint32 i
= 0; i
< theApp
->sharedfiles
->GetFileCount(); ++i
) {
458 CKnownFile
*cur_file
= (CKnownFile
*)theApp
->sharedfiles
->GetFileByIndex(i
);
460 if ( !cur_file
|| (!queryitems
.empty() && !queryitems
.count(cur_file
->GetFileHash())) ) {
464 CEC_SharedFile_Tag
filetag(cur_file
, detail_level
);
465 CKnownFile_Encoder
&enc
= encoders
[cur_file
];
466 if ( detail_level
!= EC_DETAIL_UPDATE
) {
469 enc
.Encode(&filetag
);
470 response
->AddTag(filetag
);
475 CECPacket
*Get_EC_Response_GetSharedFiles(CKnownFile_Encoder_Map
&encoders
, CObjTagMap
&tagmap
)
477 CECPacket
*response
= new CECPacket(EC_OP_SHARED_FILES
);
479 encoders
.UpdateEncoders(theApp
->sharedfiles
);
480 for (uint32 i
= 0; i
< theApp
->sharedfiles
->GetFileCount(); ++i
) {
481 CKnownFile
*cur_file
= (CKnownFile
*)theApp
->sharedfiles
->GetFileByIndex(i
);
484 // Hashes of tags are maintained on "per-object" basis. So, in this mode only
485 // same kind of objects can go into particular query type.
486 // But files from download queue (aka partfiles) need to be listed both as downloads
487 // and as shares (with different tag content).
488 // So simply increment the object pointer - it's only a map key and never used for referencing.
490 void * mapKey
= cur_file
;
491 if (!cur_file
) continue;
492 if (cur_file
->IsPartFile()) {
493 mapKey
= (void *) ((uint64
) mapKey
+ 1);
496 CValueMap
&valuemap
= tagmap
.GetValueMap(mapKey
);
497 CEC_SharedFile_Tag
filetag(cur_file
, EC_DETAIL_INC_UPDATE
, &valuemap
);
498 CKnownFile_Encoder
&enc
= encoders
[cur_file
];
499 enc
.Encode(&filetag
);
501 response
->AddTag(filetag
);
506 CECPacket
*Get_EC_Response_GetWaitQueue(const CECPacket
*request
)
508 wxASSERT(request
->GetOpCode() == EC_OP_GET_WAIT_QUEUE
);
510 CECPacket
*response
= new CECPacket(EC_OP_WAIT_QUEUE
);
512 EC_DETAIL_LEVEL detail_level
= request
->GetDetailLevel();
515 // request can contain list of queried items
516 CTagSet
<uint32
, EC_TAG_CLIENT
> queryitems(request
);
518 const CClientPtrList
& uploading
= theApp
->uploadqueue
->GetWaitingList();
519 CClientPtrList::const_iterator it
= uploading
.begin();
520 for (; it
!= uploading
.end(); ++it
) {
521 CUpDownClient
* cur_client
= *it
;
523 if ( !cur_client
|| (!queryitems
.empty() && !queryitems
.count(cur_client
->GetUserIDHybrid())) ) {
526 CEC_UpDownClient_Tag
cli_tag(cur_client
, detail_level
);
528 response
->AddTag(cli_tag
);
534 CECPacket
*Get_EC_Response_GetWaitQueue(CObjTagMap
&tagmap
)
536 CECPacket
*response
= new CECPacket(EC_OP_WAIT_QUEUE
);
538 const CClientPtrList
& uploading
= theApp
->uploadqueue
->GetWaitingList();
539 CClientPtrList::const_iterator it
= uploading
.begin();
540 for (; it
!= uploading
.end(); ++it
) {
541 CUpDownClient
* cur_client
= *it
;
543 CValueMap
&valuemap
= tagmap
.GetValueMap(cur_client
);
544 CEC_UpDownClient_Tag
cli_tag(cur_client
, valuemap
);
546 response
->AddTag(cli_tag
);
552 CECPacket
*Get_EC_Response_GetUpQueue(const CECPacket
*request
)
554 wxASSERT(request
->GetOpCode() == EC_OP_GET_ULOAD_QUEUE
);
556 CECPacket
*response
= new CECPacket(EC_OP_ULOAD_QUEUE
);
558 EC_DETAIL_LEVEL detail_level
= request
->GetDetailLevel();
561 // request can contain list of queried items
562 CTagSet
<uint32
, EC_TAG_CLIENT
> queryitems(request
);
565 const CClientPtrList
& uploading
= theApp
->uploadqueue
->GetUploadingList();
566 CClientPtrList::const_iterator it
= uploading
.begin();
567 for (; it
!= uploading
.end(); ++it
) {
568 CUpDownClient
* cur_client
= *it
;
570 if ( !cur_client
|| (!queryitems
.empty() && !queryitems
.count(cur_client
->GetUserIDHybrid())) ) {
574 CEC_UpDownClient_Tag
cli_tag(cur_client
, detail_level
);
575 response
->AddTag(cli_tag
);
582 CECPacket
*Get_EC_Response_GetUpQueue(CObjTagMap
&tagmap
)
584 CECPacket
*response
= new CECPacket(EC_OP_ULOAD_QUEUE
);
586 const CClientPtrList
& uploading
= theApp
->uploadqueue
->GetUploadingList();
587 CClientPtrList::const_iterator it
= uploading
.begin();
588 for (; it
!= uploading
.end(); ++it
) {
589 CUpDownClient
* cur_client
= *it
;
591 CValueMap
&valuemap
= tagmap
.GetValueMap(cur_client
);
592 CEC_UpDownClient_Tag
cli_tag(cur_client
, valuemap
);
594 response
->AddTag(cli_tag
);
601 CECPacket
*Get_EC_Response_GetDownloadQueue(CPartFile_Encoder_Map
&encoders
, CObjTagMap
&tagmap
)
603 CECPacket
*response
= new CECPacket(EC_OP_DLOAD_QUEUE
);
605 encoders
.UpdateEncoders(theApp
->downloadqueue
);
606 for (unsigned int i
= 0; i
< theApp
->downloadqueue
->GetFileCount(); i
++) {
607 CPartFile
*cur_file
= theApp
->downloadqueue
->GetFileByIndex(i
);
609 CValueMap
&valuemap
= tagmap
.GetValueMap(cur_file
);
610 CEC_PartFile_Tag
filetag(cur_file
, EC_DETAIL_INC_UPDATE
, true, &valuemap
);
611 CPartFile_Encoder
&enc
= encoders
[cur_file
];
612 enc
.Encode(&filetag
);
614 response
->AddTag(filetag
);
619 CECPacket
*Get_EC_Response_GetDownloadQueue(const CECPacket
*request
, CPartFile_Encoder_Map
&encoders
, bool detail
= false)
621 CECPacket
*response
= new CECPacket(EC_OP_DLOAD_QUEUE
);
623 EC_DETAIL_LEVEL detail_level
= request
->GetDetailLevel();
625 // request can contain list of queried items
626 CTagSet
<CMD4Hash
, EC_TAG_PARTFILE
> queryitems(request
);
628 encoders
.UpdateEncoders(theApp
->downloadqueue
);
630 for (unsigned int i
= 0; i
< theApp
->downloadqueue
->GetFileCount(); i
++) {
631 CPartFile
*cur_file
= theApp
->downloadqueue
->GetFileByIndex(i
);
633 if ( !queryitems
.empty() && !queryitems
.count(cur_file
->GetFileHash()) ) {
637 CEC_PartFile_Tag
filetag(cur_file
, detail_level
, detail
);
639 CPartFile_Encoder
&enc
= encoders
[cur_file
];
640 if ( detail_level
!= EC_DETAIL_UPDATE
) {
643 enc
.Encode(&filetag
);
645 response
->AddTag(filetag
);
651 CECPacket
*Get_EC_Response_PartFile_Cmd(const CECPacket
*request
)
653 CECPacket
*response
= NULL
;
655 // request can contain multiple files.
656 for (unsigned int i
= 0; i
< request
->GetTagCount(); ++i
) {
657 const CECTag
*hashtag
= request
->GetTagByIndex(i
);
659 wxASSERT(hashtag
->GetTagName() == EC_TAG_PARTFILE
);
661 CMD4Hash hash
= hashtag
->GetMD4Data();
662 CPartFile
*pfile
= theApp
->downloadqueue
->GetFileByID( hash
);
665 AddLogLineM(false,CFormat(_("Remote PartFile command failed: FileHash not found: %s")) % hash
.Encode());
666 response
= new CECPacket(EC_OP_FAILED
);
667 response
->AddTag(CECTag(EC_TAG_STRING
, CFormat(wxString(wxTRANSLATE("FileHash not found: %s"))) % hash
.Encode()));
671 switch (request
->GetOpCode()) {
672 case EC_OP_PARTFILE_SWAP_A4AF_THIS
:
673 if ((pfile
->GetStatus(false) == PS_READY
) ||
674 (pfile
->GetStatus(false) == PS_EMPTY
)) {
675 CPartFile::SourceSet::const_iterator it
= pfile
->GetA4AFList().begin();
676 while ( it
!= pfile
->GetA4AFList().end() ) {
677 CUpDownClient
*cur_source
= *it
++;
679 cur_source
->SwapToAnotherFile(true, false, false, pfile
);
683 case EC_OP_PARTFILE_SWAP_A4AF_THIS_AUTO
:
684 pfile
->SetA4AFAuto(!pfile
->IsA4AFAuto());
686 case EC_OP_PARTFILE_SWAP_A4AF_OTHERS
:
687 if ((pfile
->GetStatus(false) == PS_READY
) ||
688 (pfile
->GetStatus(false) == PS_EMPTY
)) {
689 CPartFile::SourceSet::const_iterator it
= pfile
->GetSourceList().begin();
690 while ( it
!= pfile
->GetSourceList().end() ) {
691 CUpDownClient
* cur_source
= *it
++;
693 cur_source
->SwapToAnotherFile(false, false, false, NULL
);
697 case EC_OP_PARTFILE_PAUSE
:
700 case EC_OP_PARTFILE_RESUME
:
702 pfile
->SavePartFile();
704 case EC_OP_PARTFILE_STOP
:
707 case EC_OP_PARTFILE_PRIO_SET
: {
708 uint8 prio
= hashtag
->GetTagByIndexSafe(0)->GetInt();
709 if ( prio
== PR_AUTO
) {
710 pfile
->SetAutoDownPriority(1);
712 pfile
->SetAutoDownPriority(0);
713 pfile
->SetDownPriority(prio
);
717 case EC_OP_PARTFILE_DELETE
:
718 if ( thePrefs::StartNextFile() && (pfile
->GetStatus() != PS_PAUSED
) ) {
719 theApp
->downloadqueue
->StartNextFile(pfile
);
724 case EC_OP_PARTFILE_SET_CAT
:
725 pfile
->SetCategory(hashtag
->GetTagByIndexSafe(0)->GetInt());
729 response
= new CECPacket(EC_OP_FAILED
);
730 response
->AddTag(CECTag(EC_TAG_STRING
, wxTRANSLATE("OOPS! OpCode processing error!")));
735 response
= new CECPacket(EC_OP_NOOP
);
740 CECPacket
*Get_EC_Response_Server_Add(const CECPacket
*request
)
742 CECPacket
*response
= NULL
;
744 const CECTag
*srv_tag
= request
->GetTagByIndex(0);
746 wxString full_addr
= srv_tag
->GetTagByName(EC_TAG_SERVER_ADDRESS
)->GetStringData();
747 wxString name
= srv_tag
->GetTagByName(EC_TAG_SERVER_NAME
)->GetStringData();
749 wxString s_ip
= full_addr
.Left(full_addr
.Find(':'));
750 wxString s_port
= full_addr
.Mid(full_addr
.Find(':') + 1);
752 long port
= StrToULong(s_port
);
753 CServer
* toadd
= new CServer(port
, s_ip
);
754 toadd
->SetListName(name
.IsEmpty() ? full_addr
: name
);
756 if ( theApp
->AddServer(toadd
, true) ) {
757 response
= new CECPacket(EC_OP_NOOP
);
759 response
= new CECPacket(EC_OP_FAILED
);
760 response
->AddTag(CECTag(EC_TAG_STRING
, _("Server not added")));
767 CECPacket
*Get_EC_Response_Server(const CECPacket
*request
)
769 CECPacket
*response
= NULL
;
770 const CECTag
*srv_tag
= request
->GetTagByIndex(0);
773 srv
= theApp
->serverlist
->GetServerByIPTCP(srv_tag
->GetIPv4Data().IP(), srv_tag
->GetIPv4Data().m_port
);
774 // server tag passed, but server not found
776 response
= new CECPacket(EC_OP_FAILED
);
777 response
->AddTag(CECTag(EC_TAG_STRING
,
778 CFormat(wxString(wxTRANSLATE("server not found: %s"))) % srv_tag
->GetIPv4Data().StringIP()));
782 switch (request
->GetOpCode()) {
783 case EC_OP_SERVER_DISCONNECT
:
784 theApp
->serverconnect
->Disconnect();
785 response
= new CECPacket(EC_OP_NOOP
);
787 case EC_OP_SERVER_REMOVE
:
789 theApp
->serverlist
->RemoveServer(srv
);
790 response
= new CECPacket(EC_OP_NOOP
);
792 response
= new CECPacket(EC_OP_FAILED
);
793 response
->AddTag(CECTag(EC_TAG_STRING
,
794 wxTRANSLATE("need to define server to be removed")));
797 case EC_OP_SERVER_CONNECT
:
798 if (thePrefs::GetNetworkED2K()) {
800 theApp
->serverconnect
->ConnectToServer(srv
);
801 response
= new CECPacket(EC_OP_NOOP
);
803 theApp
->serverconnect
->ConnectToAnyServer();
804 response
= new CECPacket(EC_OP_NOOP
);
807 response
= new CECPacket(EC_OP_FAILED
);
808 response
->AddTag(CECTag(EC_TAG_STRING
, wxTRANSLATE("eD2k is disabled in preferences.")));
813 response
= new CECPacket(EC_OP_FAILED
);
814 response
->AddTag(CECTag(EC_TAG_STRING
, wxTRANSLATE("OOPS! OpCode processing error!")));
819 CECPacket
*Get_EC_Response_Search_Results(const CECPacket
*request
)
821 CECPacket
*response
= new CECPacket(EC_OP_SEARCH_RESULTS
);
823 EC_DETAIL_LEVEL detail_level
= request
->GetDetailLevel();
825 // request can contain list of queried items
826 CTagSet
<CMD4Hash
, EC_TAG_SEARCHFILE
> queryitems(request
);
828 const CSearchResultList
& list
= theApp
->searchlist
->GetSearchResults(0xffffffff);
829 CSearchResultList::const_iterator it
= list
.begin();
830 while (it
!= list
.end()) {
831 CSearchFile
* sf
= *it
++;
832 if ( !queryitems
.empty() && !queryitems
.count(sf
->GetFileHash()) ) {
835 response
->AddTag(CEC_SearchFile_Tag(sf
, detail_level
));
840 CECPacket
*Get_EC_Response_Search_Results(CObjTagMap
&tagmap
)
842 CECPacket
*response
= new CECPacket(EC_OP_SEARCH_RESULTS
);
844 const CSearchResultList
& list
= theApp
->searchlist
->GetSearchResults(0xffffffff);
845 CSearchResultList::const_iterator it
= list
.begin();
846 while (it
!= list
.end()) {
847 CSearchFile
* sf
= *it
++;
848 CValueMap
&valuemap
= tagmap
.GetValueMap(sf
);
849 response
->AddTag(CEC_SearchFile_Tag(sf
, valuemap
));
854 CECPacket
*Get_EC_Response_Search_Results_Download(const CECPacket
*request
)
856 CECPacket
*response
= new CECPacket(EC_OP_STRINGS
);
857 for (unsigned int i
= 0;i
< request
->GetTagCount();i
++) {
858 const CECTag
*tag
= request
->GetTagByIndex(i
);
859 CMD4Hash hash
= tag
->GetMD4Data();
860 uint8 category
= tag
->GetTagByIndexSafe(0)->GetInt();
861 theApp
->searchlist
->AddFileToDownloadByHash(hash
, category
);
866 CECPacket
*Get_EC_Response_Search_Stop(const CECPacket
*WXUNUSED(request
))
868 CECPacket
*reply
= new CECPacket(EC_OP_MISC_DATA
);
869 theApp
->searchlist
->StopGlobalSearch();
873 CECPacket
*Get_EC_Response_Search(const CECPacket
*request
)
877 CEC_Search_Tag
*search_request
= (CEC_Search_Tag
*)request
->GetTagByIndex(0);
878 theApp
->searchlist
->RemoveResults(0xffffffff);
880 CSearchList::CSearchParams params
;
881 params
.searchString
= search_request
->SearchText();
882 params
.typeText
= search_request
->SearchFileType();
883 params
.extension
= search_request
->SearchExt();
884 params
.minSize
= search_request
->MinSize();
885 params
.maxSize
= search_request
->MaxSize();
886 params
.availability
= search_request
->Avail();
889 EC_SEARCH_TYPE search_type
= search_request
->SearchType();
890 SearchType core_search_type
= LocalSearch
;
891 switch (search_type
) {
892 case EC_SEARCH_GLOBAL
:
893 core_search_type
= GlobalSearch
;
895 if (core_search_type
!= GlobalSearch
) { // Not a global search obviously
896 core_search_type
= KadSearch
;
898 case EC_SEARCH_LOCAL
: {
899 uint32 search_id
= 0xffffffff;
900 wxString error
= theApp
->searchlist
->StartNewSearch(&search_id
, core_search_type
, params
);
901 if (!error
.IsEmpty()) {
904 response
= wxTRANSLATE("Search in progress. Refetch results in a moment!");
909 response
= wxTRANSLATE("WebSearch from remote interface makes no sense.");
913 CECPacket
*reply
= new CECPacket(EC_OP_FAILED
);
914 // error or search in progress
915 reply
->AddTag(CECTag(EC_TAG_STRING
, response
));
920 CECPacket
*Get_EC_Response_Set_SharedFile_Prio(const CECPacket
*request
)
922 CECPacket
*response
= new CECPacket(EC_OP_NOOP
);
923 for (unsigned int i
= 0;i
< request
->GetTagCount();i
++) {
924 const CECTag
*tag
= request
->GetTagByIndex(i
);
925 CMD4Hash hash
= tag
->GetMD4Data();
926 uint8 prio
= tag
->GetTagByIndexSafe(0)->GetInt();
927 CKnownFile
* cur_file
= theApp
->sharedfiles
->GetFileByID(hash
);
931 if (prio
== PR_AUTO
) {
932 cur_file
->SetAutoUpPriority(1);
933 cur_file
->UpdateAutoUpPriority();
935 cur_file
->SetAutoUpPriority(0);
936 cur_file
->SetUpPriority(prio
);
943 CECPacket
*Get_EC_Response_Kad_Connect(const CECPacket
*request
)
946 if (thePrefs::GetNetworkKademlia()) {
947 response
= new CECPacket(EC_OP_NOOP
);
948 if ( !Kademlia::CKademlia::IsRunning() ) {
949 Kademlia::CKademlia::Start();
950 theApp
->ShowConnectionState();
952 const CECTag
*addrtag
= request
->GetTagByIndex(0);
954 uint32 ip
= addrtag
->GetIPv4Data().IP();
955 uint16 port
= addrtag
->GetIPv4Data().m_port
;
956 Kademlia::CKademlia::Bootstrap(ip
, port
, true);
959 response
= new CECPacket(EC_OP_FAILED
);
960 response
->AddTag(CECTag(EC_TAG_STRING
, wxTRANSLATE("Kad is disabled in preferences.")));
966 // init with some default size
967 CPartFile_Encoder::GapBuffer
CPartFile_Encoder::m_gap_buffer(128);
970 CPartFile_Encoder::CPartFile_Encoder(CPartFile
*file
) :
971 m_enc_data(file
->GetPartCount(), file
->GetGapList().size() * 2)
977 CPartFile_Encoder::CPartFile_Encoder(int size
): m_enc_data(size
, 0)
982 CPartFile_Encoder::~CPartFile_Encoder()
987 CPartFile_Encoder::CPartFile_Encoder()
992 CPartFile_Encoder::CPartFile_Encoder(const CPartFile_Encoder
&obj
) : m_enc_data(obj
.m_enc_data
)
997 CPartFile_Encoder
&CPartFile_Encoder::operator=(const CPartFile_Encoder
&obj
)
1000 m_enc_data
= obj
.m_enc_data
;
1004 void CPartFile_Encoder::Encode(CECTag
*parent
)
1006 const CGapList
& gaplist
= m_file
->GetNewGapList();
1007 const size_t gap_list_size
= gaplist
.size();
1009 if ( m_gap_buffer
.size() < gap_list_size
* 2 ) {
1010 m_gap_buffer
.clear();
1011 m_gap_buffer
.resize(gap_list_size
* 2);
1014 GapBuffer::iterator it
= m_gap_buffer
.begin();
1016 for (CGapList::const_iterator curr_pos
= gaplist
.begin(); curr_pos
!= gaplist
.end(); ++curr_pos
) {
1017 *it
++ = ENDIAN_HTONLL(curr_pos
.start());
1018 *it
++ = ENDIAN_HTONLL(curr_pos
.end());
1021 m_enc_data
.m_gap_status
.Realloc(gap_list_size
*2*sizeof(uint64
));
1022 int gap_enc_size
= 0;
1023 const unsigned char *gap_enc_data
= m_enc_data
.m_gap_status
.Encode((unsigned char *)&m_gap_buffer
[0], gap_enc_size
);
1026 const unsigned char *part_enc_data
= m_enc_data
.m_part_status
.Encode(m_file
->m_SrcpartFrequency
, part_enc_size
);
1029 parent
->AddTag(CECTag(EC_TAG_PARTFILE_PART_STATUS
, part_enc_size
, part_enc_data
));
1032 // Put data inside of tag in following order:
1033 // [num_of_gaps] [gap_enc_data]
1035 unsigned char *tagdata
;
1036 CECTag
etag(EC_TAG_PARTFILE_GAP_STATUS
,
1037 sizeof(uint32
) + gap_enc_size
, (void **)&tagdata
);
1039 // real number of gaps - so remote size can realloc
1040 RawPokeUInt32( tagdata
, ENDIAN_HTONL( gap_list_size
) );
1041 tagdata
+= sizeof(uint32
);
1042 memcpy(tagdata
, gap_enc_data
, gap_enc_size
);
1044 parent
->AddTag(etag
);
1046 it
= m_gap_buffer
.begin();
1048 const CPartFile::CReqBlockPtrList
& requestedblocks
= m_file
->GetRequestedBlockList();
1049 CPartFile::CReqBlockPtrList::const_iterator curr_pos2
= requestedblocks
.begin();
1051 wxASSERT(m_gap_buffer
.size() >= requestedblocks
.size() * 2);
1052 for ( ; curr_pos2
!= requestedblocks
.end(); ++curr_pos2
) {
1053 Requested_Block_Struct
* block
= *curr_pos2
;
1054 *it
++ = ENDIAN_HTONLL(block
->StartOffset
);
1055 *it
++ = ENDIAN_HTONLL(block
->EndOffset
);
1057 parent
->AddTag(CECTag(EC_TAG_PARTFILE_REQ_STATUS
,
1058 requestedblocks
.size() * 2 * sizeof(uint64
), (void *)&m_gap_buffer
[0]));
1062 CKnownFile_Encoder::CKnownFile_Encoder(CKnownFile
*file
) :
1063 m_enc_data(file
->GetPartCount(), true)
1068 CKnownFile_Encoder::CKnownFile_Encoder()
1073 CKnownFile_Encoder::~CKnownFile_Encoder()
1077 CKnownFile_Encoder::CKnownFile_Encoder(const CKnownFile_Encoder
&obj
) : m_enc_data(obj
.m_enc_data
)
1079 m_file
= obj
.m_file
;
1082 CKnownFile_Encoder
&CKnownFile_Encoder::operator=(const CKnownFile_Encoder
&obj
)
1084 m_file
= obj
.m_file
;
1085 m_enc_data
= obj
.m_enc_data
;
1089 void CKnownFile_Encoder::Encode(CECTag
*parent
)
1092 const unsigned char *part_enc_data
= m_enc_data
.Encode(m_file
->m_AvailPartFrequency
, part_enc_size
);
1094 parent
->AddTag(CECTag(EC_TAG_PARTFILE_PART_STATUS
, part_enc_size
, part_enc_data
));
1097 CECPacket
*GetStatsGraphs(const CECPacket
*request
)
1099 CECPacket
*response
= NULL
;
1101 switch (request
->GetDetailLevel()) {
1103 case EC_DETAIL_FULL
: {
1104 double dTimestamp
= 0.0;
1105 if (request
->GetTagByName(EC_TAG_STATSGRAPH_LAST
) != NULL
) {
1106 dTimestamp
= request
->GetTagByName(EC_TAG_STATSGRAPH_LAST
)->GetDoubleData();
1108 uint16 nScale
= request
->GetTagByNameSafe(EC_TAG_STATSGRAPH_SCALE
)->GetInt();
1109 uint16 nMaxPoints
= request
->GetTagByNameSafe(EC_TAG_STATSGRAPH_WIDTH
)->GetInt();
1111 unsigned int numPoints
= theApp
->m_statistics
->GetHistoryForWeb(nMaxPoints
, (double)nScale
, &dTimestamp
, &graphData
);
1113 response
= new CECPacket(EC_OP_STATSGRAPHS
);
1114 response
->AddTag(CECTag(EC_TAG_STATSGRAPH_DATA
, 4 * numPoints
* sizeof(uint32
), graphData
));
1115 delete [] graphData
;
1116 response
->AddTag(CECTag(EC_TAG_STATSGRAPH_LAST
, dTimestamp
));
1118 response
= new CECPacket(EC_OP_FAILED
);
1119 response
->AddTag(CECTag(EC_TAG_STRING
, wxTRANSLATE("No points for graph.")));
1123 case EC_DETAIL_INC_UPDATE
:
1124 case EC_DETAIL_UPDATE
:
1127 response
= new CECPacket(EC_OP_FAILED
);
1128 response
->AddTag(CECTag(EC_TAG_STRING
, wxTRANSLATE("Your client is not configured for this detail level.")));
1132 response
= new CECPacket(EC_OP_FAILED
);
1139 CECPacket
*CECServerSocket::ProcessRequest2(const CECPacket
*request
,
1140 CPartFile_Encoder_Map
&enc_part_map
, CKnownFile_Encoder_Map
&enc_shared_map
, CObjTagMap
&objmap
)
1147 CECPacket
*response
= NULL
;
1149 switch (request
->GetOpCode()) {
1153 case EC_OP_SHUTDOWN
:
1154 if (!theApp
->IsOnShutDown()) {
1155 response
= new CECPacket(EC_OP_NOOP
);
1156 AddLogLineM(true, _("External Connection: shutdown requested"));
1157 #ifndef AMULE_DAEMON
1160 evt
.SetCanVeto(false);
1161 theApp
->ShutDown(evt
);
1164 theApp
->ExitMainLoop();
1167 response
= new CECPacket(EC_OP_FAILED
);
1168 response
->AddTag(CECTag(EC_TAG_STRING
, wxTRANSLATE("Already shutting down.")));
1171 case EC_OP_ADD_LINK
:
1172 for(unsigned int i
= 0; i
< request
->GetTagCount();i
++) {
1173 const CECTag
*tag
= request
->GetTagByIndex(i
);
1174 wxString link
= tag
->GetStringData();
1176 const CECTag
*cattag
= tag
->GetTagByName(EC_TAG_PARTFILE_CAT
);
1178 category
= cattag
->GetInt();
1180 AddLogLineM(true, CFormat(_("ExternalConn: adding link '%s'.")) % link
);
1181 if ( theApp
->downloadqueue
->AddLink(link
, category
) ) {
1182 response
= new CECPacket(EC_OP_NOOP
);
1184 // Error messages are printed by the add function.
1185 response
= new CECPacket(EC_OP_FAILED
);
1186 response
->AddTag(CECTag(EC_TAG_STRING
, wxTRANSLATE("Invalid link or already on list.")));
1193 case EC_OP_STAT_REQ
:
1194 response
= Get_EC_Response_StatRequest(request
, m_LoggerAccess
);
1195 response
->AddTag(CEC_ConnState_Tag(request
->GetDetailLevel()));
1197 case EC_OP_GET_CONNSTATE
:
1198 response
= new CECPacket(EC_OP_MISC_DATA
);
1199 response
->AddTag(CEC_ConnState_Tag(request
->GetDetailLevel()));
1204 case EC_OP_GET_SHARED_FILES
:
1205 if ( request
->GetDetailLevel() == EC_DETAIL_INC_UPDATE
) {
1206 response
= Get_EC_Response_GetSharedFiles(enc_shared_map
, objmap
);
1208 response
= Get_EC_Response_GetSharedFiles(request
, enc_shared_map
);
1211 case EC_OP_GET_DLOAD_QUEUE
:
1212 if ( request
->GetDetailLevel() == EC_DETAIL_INC_UPDATE
) {
1213 response
= Get_EC_Response_GetDownloadQueue(enc_part_map
, objmap
);
1215 response
= Get_EC_Response_GetDownloadQueue(request
, enc_part_map
);
1218 // transmit source names and comments only if file detail dialog is open
1219 case EC_OP_GET_DLOAD_QUEUE_DETAIL
:
1220 if ( request
->GetDetailLevel() == EC_DETAIL_INC_UPDATE
) {
1221 response
= Get_EC_Response_GetDownloadQueue(enc_part_map
, objmap
);
1223 response
= Get_EC_Response_GetDownloadQueue(request
, enc_part_map
, true);
1226 case EC_OP_GET_ULOAD_QUEUE
:
1227 if ( request
->GetDetailLevel() == EC_DETAIL_INC_UPDATE
) {
1228 response
= Get_EC_Response_GetUpQueue(objmap
);
1230 response
= Get_EC_Response_GetUpQueue(request
);
1233 case EC_OP_GET_WAIT_QUEUE
:
1234 if ( request
->GetDetailLevel() == EC_DETAIL_INC_UPDATE
) {
1235 response
= Get_EC_Response_GetWaitQueue(objmap
);
1237 response
= Get_EC_Response_GetWaitQueue(request
);
1240 case EC_OP_PARTFILE_REMOVE_NO_NEEDED
:
1241 case EC_OP_PARTFILE_REMOVE_FULL_QUEUE
:
1242 case EC_OP_PARTFILE_REMOVE_HIGH_QUEUE
:
1243 case EC_OP_PARTFILE_CLEANUP_SOURCES
:
1244 case EC_OP_PARTFILE_SWAP_A4AF_THIS
:
1245 case EC_OP_PARTFILE_SWAP_A4AF_THIS_AUTO
:
1246 case EC_OP_PARTFILE_SWAP_A4AF_OTHERS
:
1247 case EC_OP_PARTFILE_PAUSE
:
1248 case EC_OP_PARTFILE_RESUME
:
1249 case EC_OP_PARTFILE_STOP
:
1250 case EC_OP_PARTFILE_PRIO_SET
:
1251 case EC_OP_PARTFILE_DELETE
:
1252 case EC_OP_PARTFILE_SET_CAT
:
1253 response
= Get_EC_Response_PartFile_Cmd(request
);
1255 case EC_OP_SHAREDFILES_RELOAD
:
1256 theApp
->sharedfiles
->Reload();
1257 response
= new CECPacket(EC_OP_NOOP
);
1259 case EC_OP_SHARED_SET_PRIO
:
1260 response
= Get_EC_Response_Set_SharedFile_Prio(request
);
1262 case EC_OP_RENAME_FILE
: {
1263 CMD4Hash fileHash
= request
->GetTagByNameSafe(EC_TAG_KNOWNFILE
)->GetMD4Data();
1264 CKnownFile
* file
= theApp
->knownfiles
->FindKnownFileByID(fileHash
);
1265 wxString newName
= request
->GetTagByNameSafe(EC_TAG_PARTFILE_NAME
)->GetStringData();
1267 file
= theApp
->downloadqueue
->GetFileByID(fileHash
);
1270 response
= new CECPacket(EC_OP_FAILED
);
1271 response
->AddTag(CECTag(EC_TAG_STRING
, wxTRANSLATE("File not found.")));
1274 if (newName
.IsEmpty()) {
1275 response
= new CECPacket(EC_OP_FAILED
);
1276 response
->AddTag(CECTag(EC_TAG_STRING
, wxTRANSLATE("Invalid file name.")));
1280 if (theApp
->sharedfiles
->RenameFile(file
, CPath(newName
))) {
1281 response
= new CECPacket(EC_OP_NOOP
);
1283 response
= new CECPacket(EC_OP_FAILED
);
1284 response
->AddTag(CECTag(EC_TAG_STRING
, wxTRANSLATE("Unable to rename file.")));
1294 case EC_OP_SERVER_ADD
:
1295 response
= Get_EC_Response_Server_Add(request
);
1297 case EC_OP_SERVER_DISCONNECT
:
1298 case EC_OP_SERVER_CONNECT
:
1299 case EC_OP_SERVER_REMOVE
:
1300 response
= Get_EC_Response_Server(request
);
1302 case EC_OP_GET_SERVER_LIST
: {
1303 response
= new CECPacket(EC_OP_SERVER_LIST
);
1304 if (!thePrefs::GetNetworkED2K()) {
1305 // Kad only: just send an empty list
1308 EC_DETAIL_LEVEL detail_level
= request
->GetDetailLevel();
1309 std::vector
<const CServer
*> servers
= theApp
->serverlist
->CopySnapshot();
1311 std::vector
<const CServer
*>::const_iterator it
= servers
.begin();
1312 it
!= servers
.end();
1315 response
->AddTag(CEC_Server_Tag(*it
, detail_level
));
1319 case EC_OP_SERVER_UPDATE_FROM_URL
: {
1320 wxString url
= request
->GetTagByIndexSafe(0)->GetStringData();
1322 // Save the new url, and update the UI (if not amuled).
1323 Notify_ServersURLChanged(url
);
1324 thePrefs::SetEd2kServersUrl(url
);
1326 theApp
->serverlist
->UpdateServerMetFromURL(url
);
1327 response
= new CECPacket(EC_OP_NOOP
);
1333 case EC_OP_IPFILTER_RELOAD
:
1334 theApp
->ipfilter
->Reload();
1335 response
= new CECPacket(EC_OP_NOOP
);
1340 case EC_OP_SEARCH_START
:
1341 response
= Get_EC_Response_Search(request
);
1344 case EC_OP_SEARCH_STOP
:
1345 response
= Get_EC_Response_Search_Stop(request
);
1348 case EC_OP_SEARCH_RESULTS
:
1349 if ( request
->GetDetailLevel() == EC_DETAIL_INC_UPDATE
) {
1350 response
= Get_EC_Response_Search_Results(objmap
);
1352 response
= Get_EC_Response_Search_Results(request
);
1356 case EC_OP_SEARCH_PROGRESS
:
1357 response
= new CECPacket(EC_OP_SEARCH_PROGRESS
);
1358 response
->AddTag(CECTag(EC_TAG_SEARCH_STATUS
,
1359 theApp
->searchlist
->GetSearchProgress()));
1362 case EC_OP_DOWNLOAD_SEARCH_RESULT
:
1363 response
= Get_EC_Response_Search_Results_Download(request
);
1368 case EC_OP_GET_PREFERENCES
:
1369 response
= new CEC_Prefs_Packet(request
->GetTagByNameSafe(EC_TAG_SELECT_PREFS
)->GetInt(), request
->GetDetailLevel());
1371 case EC_OP_SET_PREFERENCES
:
1372 ((CEC_Prefs_Packet
*)request
)->Apply();
1373 theApp
->glob_prefs
->Save();
1374 if (thePrefs::IsFilteringClients()) {
1375 theApp
->clientlist
->FilterQueues();
1377 if (thePrefs::IsFilteringServers()) {
1378 theApp
->serverlist
->FilterServers();
1380 if (!thePrefs::GetNetworkED2K() && theApp
->IsConnectedED2K()) {
1381 theApp
->DisconnectED2K();
1383 if (!thePrefs::GetNetworkKademlia() && theApp
->IsConnectedKad()) {
1386 response
= new CECPacket(EC_OP_NOOP
);
1389 case EC_OP_CREATE_CATEGORY
:
1390 if ( request
->GetTagCount() == 1 ) {
1391 CEC_Category_Tag
*tag
= (CEC_Category_Tag
*)request
->GetTagByIndex(0);
1392 if (tag
->Create()) {
1393 response
= new CECPacket(EC_OP_NOOP
);
1395 response
= new CECPacket(EC_OP_FAILED
);
1396 response
->AddTag(CECTag(EC_TAG_CATEGORY
, theApp
->glob_prefs
->GetCatCount() - 1));
1397 response
->AddTag(CECTag(EC_TAG_CATEGORY_PATH
, tag
->Path()));
1399 Notify_CategoryAdded();
1401 response
= new CECPacket(EC_OP_NOOP
);
1404 case EC_OP_UPDATE_CATEGORY
:
1405 if ( request
->GetTagCount() == 1 ) {
1406 CEC_Category_Tag
*tag
= (CEC_Category_Tag
*)request
->GetTagByIndex(0);
1408 response
= new CECPacket(EC_OP_NOOP
);
1410 response
= new CECPacket(EC_OP_FAILED
);
1411 response
->AddTag(CECTag(EC_TAG_CATEGORY
, tag
->GetInt()));
1412 response
->AddTag(CECTag(EC_TAG_CATEGORY_PATH
, tag
->Path()));
1414 Notify_CategoryUpdate(tag
->GetInt());
1416 response
= new CECPacket(EC_OP_NOOP
);
1419 case EC_OP_DELETE_CATEGORY
:
1420 if ( request
->GetTagCount() == 1 ) {
1421 uint32 cat
= request
->GetTagByIndex(0)->GetInt();
1422 // this noes not only update the gui, but actually deletes the cat
1423 Notify_CategoryDelete(cat
);
1425 response
= new CECPacket(EC_OP_NOOP
);
1431 case EC_OP_ADDLOGLINE
:
1432 AddLogLineM( (request
->GetTagByName(EC_TAG_LOG_TO_STATUS
) != NULL
), request
->GetTagByNameSafe(EC_TAG_STRING
)->GetStringData() );
1433 response
= new CECPacket(EC_OP_NOOP
);
1435 case EC_OP_ADDDEBUGLOGLINE
:
1436 AddDebugLogLineM( (request
->GetTagByName(EC_TAG_LOG_TO_STATUS
) != NULL
), logGeneral
, request
->GetTagByNameSafe(EC_TAG_STRING
)->GetStringData() );
1437 response
= new CECPacket(EC_OP_NOOP
);
1440 response
= new CECPacket(EC_OP_LOG
);
1441 response
->AddTag(CECTag(EC_TAG_STRING
, theApp
->GetLog(false)));
1443 case EC_OP_GET_DEBUGLOG
:
1444 response
= new CECPacket(EC_OP_DEBUGLOG
);
1445 response
->AddTag(CECTag(EC_TAG_STRING
, theApp
->GetDebugLog(false)));
1447 case EC_OP_RESET_LOG
:
1448 theApp
->GetLog(true);
1449 response
= new CECPacket(EC_OP_NOOP
);
1451 case EC_OP_RESET_DEBUGLOG
:
1452 theApp
->GetDebugLog(true);
1453 response
= new CECPacket(EC_OP_NOOP
);
1455 case EC_OP_GET_LAST_LOG_ENTRY
:
1457 wxString tmp
= theApp
->GetLog(false);
1458 if (tmp
.Last() == '\n') {
1461 response
= new CECPacket(EC_OP_LOG
);
1462 response
->AddTag(CECTag(EC_TAG_STRING
, tmp
.AfterLast('\n')));
1465 case EC_OP_GET_SERVERINFO
:
1466 response
= new CECPacket(EC_OP_SERVERINFO
);
1467 response
->AddTag(CECTag(EC_TAG_STRING
, theApp
->GetServerLog(false)));
1469 case EC_OP_CLEAR_SERVERINFO
:
1470 theApp
->GetServerLog(true);
1471 response
= new CECPacket(EC_OP_NOOP
);
1476 case EC_OP_GET_STATSGRAPHS
:
1477 response
= GetStatsGraphs(request
);
1479 case EC_OP_GET_STATSTREE
: {
1480 theApp
->m_statistics
->UpdateStatsTree();
1481 response
= new CECPacket(EC_OP_STATSTREE
);
1482 CECTag
* tree
= theStats::GetECStatTree(request
->GetTagByNameSafe(EC_TAG_STATTREE_CAPPING
)->GetInt());
1484 response
->AddTag(*tree
);
1487 if (request
->GetDetailLevel() == EC_DETAIL_WEB
) {
1488 response
->AddTag(CECTag(EC_TAG_SERVER_VERSION
, wxT(VERSION
)));
1489 response
->AddTag(CECTag(EC_TAG_USER_NICK
, thePrefs::GetUserNick()));
1497 case EC_OP_KAD_START
:
1498 response
= Get_EC_Response_Kad_Connect(request
);
1500 case EC_OP_KAD_STOP
:
1502 response
= new CECPacket(EC_OP_NOOP
);
1504 case EC_OP_KAD_UPDATE_FROM_URL
: {
1505 wxString url
= request
->GetTagByIndexSafe(0)->GetStringData();
1507 // Save the new url, and update the UI (if not amuled).
1508 Notify_NodesURLChanged(url
);
1509 thePrefs::SetKadNodesUrl(url
);
1511 theApp
->UpdateNotesDat(url
);
1512 response
= new CECPacket(EC_OP_NOOP
);
1515 case EC_OP_KAD_BOOTSTRAP_FROM_IP
:
1516 theApp
->BootstrapKad(request
->GetTagByIndexSafe(0)->GetInt(),
1517 request
->GetTagByIndexSafe(1)->GetInt());
1518 response
= new CECPacket(EC_OP_NOOP
);
1525 if (thePrefs::GetNetworkED2K()) {
1526 response
= new CECPacket(EC_OP_STRINGS
);
1527 if (theApp
->IsConnectedED2K()) {
1528 response
->AddTag(CECTag(EC_TAG_STRING
, wxTRANSLATE("Already connected to eD2k.")));
1530 theApp
->serverconnect
->ConnectToAnyServer();
1531 response
->AddTag(CECTag(EC_TAG_STRING
, wxTRANSLATE("Connecting to eD2k...")));
1534 if (thePrefs::GetNetworkKademlia()) {
1536 response
= new CECPacket(EC_OP_STRINGS
);
1538 if (theApp
->IsConnectedKad()) {
1539 response
->AddTag(CECTag(EC_TAG_STRING
, wxTRANSLATE("Already connected to Kad.")));
1542 response
->AddTag(CECTag(EC_TAG_STRING
, wxTRANSLATE("Connecting to Kad...")));
1546 response
= new CECPacket(EC_OP_FAILED
);
1547 response
->AddTag(CECTag(EC_TAG_STRING
, wxTRANSLATE("All networks are disabled.")));
1550 case EC_OP_DISCONNECT
:
1551 if (theApp
->IsConnected()) {
1552 response
= new CECPacket(EC_OP_STRINGS
);
1553 if (theApp
->IsConnectedED2K()) {
1554 theApp
->serverconnect
->Disconnect();
1555 response
->AddTag(CECTag(EC_TAG_STRING
, wxTRANSLATE("Disconnected from eD2k.")));
1557 if (theApp
->IsConnectedKad()) {
1559 response
->AddTag(CECTag(EC_TAG_STRING
, wxTRANSLATE("Disconnected from Kad.")));
1562 response
= new CECPacket(EC_OP_NOOP
);
1567 AddLogLineM(false, wxString::Format(_("External Connection: invalid opcode received: %#x"), request
->GetOpCode()));
1569 response
= new CECPacket(EC_OP_FAILED
);
1570 response
->AddTag(CECTag(EC_TAG_STRING
, wxTRANSLATE("Invalid opcode (wrong protocol version?)")));
1577 * Here notification-based EC. Notification will be sorted by priority for possible throttling.
1581 * Core general status
1583 ECStatusMsgSource::ECStatusMsgSource()
1585 m_last_ed2k_status_sent
= 0xffffffff;
1586 m_last_kad_status_sent
= 0xffffffff;
1587 m_server
= (void *)0xffffffff;
1590 uint32
ECStatusMsgSource::GetEd2kStatus()
1592 if ( theApp
->IsConnectedED2K() ) {
1593 return theApp
->GetED2KID();
1594 } else if ( theApp
->serverconnect
->IsConnecting() ) {
1601 uint32
ECStatusMsgSource::GetKadStatus()
1603 if ( theApp
->IsConnectedKad() ) {
1605 } else if ( Kademlia::CKademlia::IsFirewalled() ) {
1607 } else if ( Kademlia::CKademlia::IsRunning() ) {
1613 CECPacket
*ECStatusMsgSource::GetNextPacket()
1615 if ( (m_last_ed2k_status_sent
!= GetEd2kStatus()) ||
1616 (m_last_kad_status_sent
!= GetKadStatus()) ||
1617 (m_server
!= theApp
->serverconnect
->GetCurrentServer()) ) {
1619 m_last_ed2k_status_sent
= GetEd2kStatus();
1620 m_last_kad_status_sent
= GetKadStatus();
1621 m_server
= theApp
->serverconnect
->GetCurrentServer();
1623 CECPacket
*response
= new CECPacket(EC_OP_STATS
);
1624 response
->AddTag(CEC_ConnState_Tag(EC_DETAIL_UPDATE
));
1633 ECPartFileMsgSource::ECPartFileMsgSource()
1635 for (unsigned int i
= 0; i
< theApp
->downloadqueue
->GetFileCount(); i
++) {
1636 CPartFile
*cur_file
= theApp
->downloadqueue
->GetFileByIndex(i
);
1637 PARTFILE_STATUS status
= { true, false, false, false, true, cur_file
};
1638 m_dirty_status
[cur_file
->GetFileHash()] = status
;
1642 void ECPartFileMsgSource::SetDirty(CPartFile
*file
)
1644 CMD4Hash filehash
= file
->GetFileHash();
1645 if ( m_dirty_status
.find(filehash
) != m_dirty_status
.end() ) {
1646 m_dirty_status
[filehash
].m_dirty
= true;;
1650 void ECPartFileMsgSource::SetNew(CPartFile
*file
)
1652 CMD4Hash filehash
= file
->GetFileHash();
1653 wxASSERT ( m_dirty_status
.find(filehash
) == m_dirty_status
.end() );
1654 PARTFILE_STATUS status
= { true, false, false, false, true, file
};
1655 m_dirty_status
[filehash
] = status
;
1658 void ECPartFileMsgSource::SetCompleted(CPartFile
*file
)
1660 CMD4Hash filehash
= file
->GetFileHash();
1661 wxASSERT ( m_dirty_status
.find(filehash
) != m_dirty_status
.end() );
1663 m_dirty_status
[filehash
].m_finished
= true;
1666 void ECPartFileMsgSource::SetRemoved(CPartFile
*file
)
1668 CMD4Hash filehash
= file
->GetFileHash();
1669 wxASSERT ( m_dirty_status
.find(filehash
) != m_dirty_status
.end() );
1671 m_dirty_status
[filehash
].m_removed
= true;
1674 CECPacket
*ECPartFileMsgSource::GetNextPacket()
1676 for(std::map
<CMD4Hash
, PARTFILE_STATUS
>::iterator it
= m_dirty_status
.begin();
1677 it
!= m_dirty_status
.end(); it
++) {
1678 if ( it
->second
.m_new
|| it
->second
.m_dirty
|| it
->second
.m_removed
) {
1679 CMD4Hash filehash
= it
->first
;
1681 CPartFile
*partfile
= it
->second
.m_file
;
1683 CECPacket
*packet
= new CECPacket(EC_OP_DLOAD_QUEUE
);
1684 if ( it
->second
.m_removed
) {
1685 CECTag
tag(EC_TAG_PARTFILE
, filehash
);
1686 packet
->AddTag(tag
);
1687 m_dirty_status
.erase(it
);
1689 CEC_PartFile_Tag
tag(partfile
, it
->second
.m_new
? EC_DETAIL_FULL
: EC_DETAIL_UPDATE
);
1690 packet
->AddTag(tag
);
1692 m_dirty_status
[filehash
].m_new
= false;
1693 m_dirty_status
[filehash
].m_dirty
= false;
1702 * Shared files - similar to downloading
1704 ECKnownFileMsgSource::ECKnownFileMsgSource()
1706 for (unsigned int i
= 0; i
< theApp
->sharedfiles
->GetFileCount(); i
++) {
1707 CKnownFile
*cur_file
= (CKnownFile
*)theApp
->sharedfiles
->GetFileByIndex(i
);
1708 KNOWNFILE_STATUS status
= { true, false, false, true, cur_file
};
1709 m_dirty_status
[cur_file
->GetFileHash()] = status
;
1713 void ECKnownFileMsgSource::SetDirty(CKnownFile
*file
)
1715 CMD4Hash filehash
= file
->GetFileHash();
1716 if ( m_dirty_status
.find(filehash
) != m_dirty_status
.end() ) {
1717 m_dirty_status
[filehash
].m_dirty
= true;;
1721 void ECKnownFileMsgSource::SetNew(CKnownFile
*file
)
1723 CMD4Hash filehash
= file
->GetFileHash();
1724 wxASSERT ( m_dirty_status
.find(filehash
) == m_dirty_status
.end() );
1725 KNOWNFILE_STATUS status
= { true, false, false, true, file
};
1726 m_dirty_status
[filehash
] = status
;
1729 void ECKnownFileMsgSource::SetRemoved(CKnownFile
*file
)
1731 CMD4Hash filehash
= file
->GetFileHash();
1732 wxASSERT ( m_dirty_status
.find(filehash
) != m_dirty_status
.end() );
1734 m_dirty_status
[filehash
].m_removed
= true;
1737 CECPacket
*ECKnownFileMsgSource::GetNextPacket()
1739 for(std::map
<CMD4Hash
, KNOWNFILE_STATUS
>::iterator it
= m_dirty_status
.begin();
1740 it
!= m_dirty_status
.end(); it
++) {
1741 if ( it
->second
.m_new
|| it
->second
.m_dirty
|| it
->second
.m_removed
) {
1742 CMD4Hash filehash
= it
->first
;
1744 CKnownFile
*partfile
= it
->second
.m_file
;
1746 CECPacket
*packet
= new CECPacket(EC_OP_SHARED_FILES
);
1747 if ( it
->second
.m_removed
) {
1748 CECTag
tag(EC_TAG_PARTFILE
, filehash
);
1749 packet
->AddTag(tag
);
1750 m_dirty_status
.erase(it
);
1752 CEC_SharedFile_Tag
tag(partfile
, it
->second
.m_new
? EC_DETAIL_FULL
: EC_DETAIL_UPDATE
);
1753 packet
->AddTag(tag
);
1755 m_dirty_status
[filehash
].m_new
= false;
1756 m_dirty_status
[filehash
].m_dirty
= false;
1765 * Notification about search status
1767 ECSearchMsgSource::ECSearchMsgSource()
1771 CECPacket
*ECSearchMsgSource::GetNextPacket()
1773 if ( m_dirty_status
.empty() ) {
1777 CECPacket
*response
= new CECPacket(EC_OP_SEARCH_RESULTS
);
1778 for(std::map
<CMD4Hash
, SEARCHFILE_STATUS
>::iterator it
= m_dirty_status
.begin();
1779 it
!= m_dirty_status
.end(); it
++) {
1781 if ( it
->second
.m_new
) {
1782 response
->AddTag(CEC_SearchFile_Tag(it
->second
.m_file
, EC_DETAIL_FULL
));
1783 it
->second
.m_new
= false;
1784 } else if ( it
->second
.m_dirty
) {
1785 response
->AddTag(CEC_SearchFile_Tag(it
->second
.m_file
, EC_DETAIL_UPDATE
));
1793 void ECSearchMsgSource::FlushStatus()
1795 m_dirty_status
.clear();
1798 void ECSearchMsgSource::SetDirty(CSearchFile
*file
)
1800 if ( m_dirty_status
.count(file
->GetFileHash()) ) {
1801 m_dirty_status
[file
->GetFileHash()].m_dirty
= true;
1803 m_dirty_status
[file
->GetFileHash()].m_new
= true;
1804 m_dirty_status
[file
->GetFileHash()].m_dirty
= true;
1805 m_dirty_status
[file
->GetFileHash()].m_child_dirty
= true;
1806 m_dirty_status
[file
->GetFileHash()].m_file
= file
;
1810 void ECSearchMsgSource::SetChildDirty(CSearchFile
*file
)
1812 m_dirty_status
[file
->GetFileHash()].m_child_dirty
= true;
1816 * Notification about uploading clients
1818 CECPacket
*ECClientMsgSource::GetNextPacket()
1824 // Notification iface per-client
1826 ECNotifier::ECNotifier()
1830 CECPacket
*ECNotifier::GetNextPacket(ECUpdateMsgSource
*msg_source_array
[])
1832 CECPacket
*packet
= 0;
1834 // priority 0 is highest
1836 for(int i
= 0; i
< EC_STATUS_LAST_PRIO
; i
++) {
1837 if ( (packet
= msg_source_array
[i
]->GetNextPacket()) != 0 ) {
1844 CECPacket
*ECNotifier::GetNextPacket(CECServerSocket
*sock
)
1847 // OnOutput is called for a first time before
1848 // socket is registered
1850 if ( m_msg_source
.count(sock
) ) {
1851 ECUpdateMsgSource
**notifier_array
= m_msg_source
[sock
];
1852 if ( !notifier_array
) {
1855 CECPacket
*packet
= GetNextPacket(notifier_array
);
1856 printf("[EC] next update packet; opcode=%x\n",packet
? packet
->GetOpCode() : 0xff);
1864 // Interface to notification macros
1866 void ECNotifier::DownloadFile_SetDirty(CPartFile
*file
)
1868 for(std::map
<CECServerSocket
*, ECUpdateMsgSource
**>::iterator i
= m_msg_source
.begin();
1869 i
!= m_msg_source
.end(); i
++) {
1870 CECServerSocket
*sock
= i
->first
;
1871 if ( sock
->HaveNotificationSupport() ) {
1872 ECUpdateMsgSource
**notifier_array
= i
->second
;
1873 ((ECPartFileMsgSource
*)notifier_array
[EC_PARTFILE
])->SetDirty(file
);
1876 NextPacketToSocket();
1879 void ECNotifier::DownloadFile_RemoveFile(CPartFile
*file
)
1881 for(std::map
<CECServerSocket
*, ECUpdateMsgSource
**>::iterator i
= m_msg_source
.begin();
1882 i
!= m_msg_source
.end(); i
++) {
1883 ECUpdateMsgSource
**notifier_array
= i
->second
;
1884 ((ECPartFileMsgSource
*)notifier_array
[EC_PARTFILE
])->SetRemoved(file
);
1886 NextPacketToSocket();
1889 void ECNotifier::DownloadFile_RemoveSource(CPartFile
*)
1891 // per-partfile source list is not supported (yet), and IMHO quite useless
1894 void ECNotifier::DownloadFile_AddFile(CPartFile
*file
)
1896 for(std::map
<CECServerSocket
*, ECUpdateMsgSource
**>::iterator i
= m_msg_source
.begin();
1897 i
!= m_msg_source
.end(); i
++) {
1898 ECUpdateMsgSource
**notifier_array
= i
->second
;
1899 ((ECPartFileMsgSource
*)notifier_array
[EC_PARTFILE
])->SetNew(file
);
1901 NextPacketToSocket();
1904 void ECNotifier::DownloadFile_AddSource(CPartFile
*)
1906 // per-partfile source list is not supported (yet), and IMHO quite useless
1909 void ECNotifier::SharedFile_AddFile(CKnownFile
*file
)
1911 for(std::map
<CECServerSocket
*, ECUpdateMsgSource
**>::iterator i
= m_msg_source
.begin();
1912 i
!= m_msg_source
.end(); i
++) {
1913 ECUpdateMsgSource
**notifier_array
= i
->second
;
1914 ((ECKnownFileMsgSource
*)notifier_array
[EC_KNOWN
])->SetNew(file
);
1916 NextPacketToSocket();
1919 void ECNotifier::SharedFile_RemoveFile(CKnownFile
*file
)
1921 for(std::map
<CECServerSocket
*, ECUpdateMsgSource
**>::iterator i
= m_msg_source
.begin();
1922 i
!= m_msg_source
.end(); i
++) {
1923 ECUpdateMsgSource
**notifier_array
= i
->second
;
1924 ((ECKnownFileMsgSource
*)notifier_array
[EC_KNOWN
])->SetRemoved(file
);
1926 NextPacketToSocket();
1929 void ECNotifier::SharedFile_RemoveAllFiles()
1931 // need to figure out what to do here
1934 void ECNotifier::Add_EC_Client(CECServerSocket
*sock
)
1936 ECUpdateMsgSource
**notifier_array
= new ECUpdateMsgSource
*[EC_STATUS_LAST_PRIO
];
1937 notifier_array
[EC_STATUS
] = new ECStatusMsgSource();
1938 notifier_array
[EC_SEARCH
] = new ECSearchMsgSource();
1939 notifier_array
[EC_PARTFILE
] = new ECPartFileMsgSource();
1940 notifier_array
[EC_CLIENT
] = new ECClientMsgSource();
1941 notifier_array
[EC_KNOWN
] = new ECKnownFileMsgSource();
1943 m_msg_source
[sock
] = notifier_array
;
1946 void ECNotifier::Remove_EC_Client(CECServerSocket
*sock
)
1948 if (m_msg_source
.count(sock
)) {
1949 ECUpdateMsgSource
**notifier_array
= m_msg_source
[sock
];
1951 m_msg_source
.erase(sock
);
1953 for(int i
= 0; i
< EC_STATUS_LAST_PRIO
; i
++) {
1954 delete notifier_array
[i
];
1956 delete [] notifier_array
;
1960 void ECNotifier::NextPacketToSocket()
1962 for(std::map
<CECServerSocket
*, ECUpdateMsgSource
**>::iterator i
= m_msg_source
.begin();
1963 i
!= m_msg_source
.end(); i
++) {
1964 CECServerSocket
*sock
= i
->first
;
1965 if ( sock
->HaveNotificationSupport() && !sock
->DataPending() ) {
1966 ECUpdateMsgSource
**notifier_array
= i
->second
;
1967 CECPacket
*packet
= GetNextPacket(notifier_array
);
1969 printf("[EC] sending update packet; opcode=%x\n",packet
->GetOpCode());
1970 sock
->SendPacket(packet
);
1976 // File_checked_for_headers