1//
2// This file is part of the aMule Project.
3//
4// Copyright (c) 2005-2011 aMule Team ( admin@amule.org / http://www.amule.org )
5//
6// Any parts of this program derived from the xMule, lMule or eMule project,
7// or contributed by third-party developers are copyrighted by their
8// respective authors.
9//
10// This program is free software; you can redistribute it and/or modify
11// it under the terms of the GNU General Public License as published by
12// the Free Software Foundation; either version 2 of the License, or
13// (at your option) any later version.
14//
15// This program is distributed in the hope that it will be useful,
16// but WITHOUT ANY WARRANTY; without even the implied warranty of
17// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18// GNU General Public License for more details.
19//
20// You should have received a copy of the GNU General Public License
21// along with this program; if not, write to the Free Software
22// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA
23//
24
25
26#include <wx/ipc.h>
27#include <wx/cmdline.h>			// Needed for wxCmdLineParser
28#include <wx/config.h>			// Do_not_auto_remove (win32)
29#include <wx/fileconf.h>		// Needed for wxFileConfig
30
31
32#include <common/Format.h>
33#include <common/StringFunctions.h>
34#include <common/MD5Sum.h>
35
36
37#include <include/common/EventIDs.h>
38
39
40#include "amule.h"			// Interface declarations.
41#include "amuleDlg.h"			// Needed for CamuleDlg
42#include "ClientCredits.h"
43#include "SourceListCtrl.h"
44#include "ChatWnd.h"
45#include "DataToText.h"			// Needed for GetSoftName()
46#include "DownloadListCtrl.h"		// Needed for CDownloadListCtrl
47#include "Friend.h"
48#include "GetTickCount.h"	// Needed for GetTickCount
49#include "GuiEvents.h"
50#ifdef ENABLE_IP2COUNTRY
51	#include "IP2Country.h"		// Needed for IP2Country
52#endif
53#include "InternalEvents.h"	// Needed for wxEVT_CORE_FINISHED_HTTP_DOWNLOAD
54#include "Logger.h"
55#include "muuli_wdr.h"			// Needed for IDs
56#include "PartFile.h"			// Needed for CPartFile
57#include "SearchDlg.h"			// Needed for CSearchDlg
58#include "Server.h"			// Needed for GetListName
59#include "ServerWnd.h"			// Needed for CServerWnd
60#include "SharedFilesCtrl.h"		// Needed for CSharedFilesCtrl
61#include "SharedFilesWnd.h"		// Needed for CSharedFilesWnd
62#include "TransferWnd.h"		// Needed for CTransferWnd
63#include "UpDownClientEC.h"		// Needed for CUpDownClient
64#include "ServerListCtrl.h"		// Needed for CServerListCtrl
65#include "ScopedPtr.h"
66#include "StatisticsDlg.h"	// Needed for CStatisticsDlg
67
68
69CEConnectDlg::CEConnectDlg()
70:
71wxDialog(theApp->amuledlg, -1, _("Connect to remote amule"), wxDefaultPosition)
72{
73	CoreConnect(this, true);
74
75	wxString pref_host, pref_port;
76	wxConfig::Get()->Read(wxT("/EC/Host"), &pref_host, wxT("localhost"));
77	wxConfig::Get()->Read(wxT("/EC/Port"), &pref_port, wxT("4712"));
78	wxConfig::Get()->Read(wxT("/EC/Password"), &pwd_hash);
79
80	CastChild(ID_REMOTE_HOST, wxTextCtrl)->SetValue(pref_host);
81	CastChild(ID_REMOTE_PORT, wxTextCtrl)->SetValue(pref_port);
82	CastChild(ID_EC_PASSWD, wxTextCtrl)->SetValue(pwd_hash);
83
84	CentreOnParent();
85}
86
87
88wxString CEConnectDlg::PassHash()
89{
90	return pwd_hash;
91}
92
93
94BEGIN_EVENT_TABLE(CEConnectDlg, wxDialog)
95  EVT_BUTTON(wxID_OK, CEConnectDlg::OnOK)
96END_EVENT_TABLE()
97
98
99void CEConnectDlg::OnOK(wxCommandEvent& evt)
100{
101	wxString s_port = CastChild(ID_REMOTE_PORT, wxTextCtrl)->GetValue();
102	port = StrToLong(s_port);
103
104	host = CastChild(ID_REMOTE_HOST, wxTextCtrl)->GetValue();
105	passwd = CastChild(ID_EC_PASSWD, wxTextCtrl)->GetValue();
106
107	if (passwd != pwd_hash) {
108		pwd_hash = MD5Sum(passwd).GetHash();
109	}
110	m_save_user_pass = CastChild(ID_EC_SAVE, wxCheckBox)->IsChecked();
111	evt.Skip();
112}
113
114
115DEFINE_LOCAL_EVENT_TYPE(wxEVT_EC_INIT_DONE)
116
117
118BEGIN_EVENT_TABLE(CamuleRemoteGuiApp, wxApp)
119	// Core timer
120	EVT_TIMER(ID_CORE_TIMER_EVENT, CamuleRemoteGuiApp::OnPollTimer)
121
122	EVT_CUSTOM(wxEVT_EC_CONNECTION, -1, CamuleRemoteGuiApp::OnECConnection)
123	EVT_CUSTOM(wxEVT_EC_INIT_DONE, -1, CamuleRemoteGuiApp::OnECInitDone)
124
125	EVT_MULE_NOTIFY(CamuleRemoteGuiApp::OnNotifyEvent)
126
127#ifdef ENABLE_IP2COUNTRY
128	// HTTPDownload finished
129	EVT_MULE_INTERNAL(wxEVT_CORE_FINISHED_HTTP_DOWNLOAD, -1, CamuleRemoteGuiApp::OnFinishedHTTPDownload)
130#endif
131END_EVENT_TABLE()
132
133
134IMPLEMENT_APP(CamuleRemoteGuiApp)
135
136
137int CamuleRemoteGuiApp::OnExit()
138{
139	StopTickTimer();
140
141	return wxApp::OnExit();
142}
143
144
145void CamuleRemoteGuiApp::OnPollTimer(wxTimerEvent&)
146{
147	static int request_step = 0;
148	static uint32 msPrevStats = 0;
149
150	if (m_connect->RequestFifoFull()) {
151		return;
152	}
153
154	switch (request_step) {
155	case 0:
156		// We used to update the connection state here, but that's done with the stats in the next step now.
157		request_step++;
158		break;
159	case 1: {
160		CECPacket stats_req(EC_OP_STAT_REQ, EC_DETAIL_INC_UPDATE);
161		m_connect->SendRequest(&m_stats_updater, &stats_req);
162		request_step++;
163		break;
164	}
165	case 2:
166		if (amuledlg->m_sharedfileswnd->IsShown()
167			|| amuledlg->m_chatwnd->IsShown()
168			|| amuledlg->m_serverwnd->IsShown()) {
169			// update downloads, shared files and servers
170			knownfiles->DoRequery(EC_OP_GET_UPDATE, EC_TAG_KNOWNFILE);
171		} else if (amuledlg->m_transferwnd->IsShown()) {
172			// update both downloads and shared files
173			knownfiles->DoRequery(EC_OP_GET_UPDATE, EC_TAG_KNOWNFILE);
174		} else if (amuledlg->m_searchwnd->IsShown()) {
175			if (searchlist->m_curr_search != -1) {
176				searchlist->DoRequery(EC_OP_SEARCH_RESULTS, EC_TAG_SEARCHFILE);
177			}
178		} else if (amuledlg->m_statisticswnd->IsShown()) {
179			int sStatsUpdate = thePrefs::GetStatsInterval();
180			uint32 msCur = theStats::GetUptimeMillis();
181			if ((sStatsUpdate > 0) && ((int)(msCur - msPrevStats) > sStatsUpdate*1000)) {
182				msPrevStats = msCur;
183				stattree->DoRequery();
184			}
185		}
186		// Back to the roots
187		request_step = 0;
188		break;
189	default:
190		wxFAIL;
191		request_step = 0;
192	}
193
194	// Check for new links once per second.
195	static uint32 lastED2KLinkCheck = 0;
196	if (GetTickCount() - lastED2KLinkCheck >= 1000) {
197		AddLinksFromFile();
198		lastED2KLinkCheck = GetTickCount();
199	}
200}
201
202
203void CamuleRemoteGuiApp::OnFinishedHTTPDownload(CMuleInternalEvent& event)
204{
205	if (event.GetInt() == HTTP_GeoIP) {
206		amuledlg->IP2CountryDownloadFinished(event.GetExtraLong());
207		// If we updated, the dialog is already up. Redraw it to show the flags.
208		amuledlg->Refresh();
209	}
210}
211
212
213void CamuleRemoteGuiApp::ShutDown(wxCloseEvent &WXUNUSED(evt))
214{
215	// Stop the Core Timer
216	delete poll_timer;
217	poll_timer = NULL;
218
219	// Destroy the EC socket
220	m_connect->Destroy();
221	m_connect = NULL;
222
223	//
224	if (amuledlg) {
225		amuledlg->DlgShutDown();
226		amuledlg->Destroy();
227		amuledlg = NULL;
228	}
229	delete m_allUploadingKnownFile;
230	delete stattree;
231}
232
233
234bool CamuleRemoteGuiApp::OnInit()
235{
236	StartTickTimer();
237	amuledlg = NULL;
238
239	// Get theApp
240	theApp = &wxGetApp();
241
242	// Handle uncaught exceptions
243	InstallMuleExceptionHandler();
244
245	// Parse cmdline arguments.
246	if (!InitCommon(AMULE_APP_BASE::argc, AMULE_APP_BASE::argv)) {
247		return false;
248	}
249
250	// Create the polling timer
251	poll_timer = new wxTimer(this,ID_CORE_TIMER_EVENT);
252	if (!poll_timer) {
253		AddLogLineCS(_("Fatal Error: Failed to create Poll Timer"));
254		OnExit();
255	}
256
257	m_connect = new CRemoteConnect(this);
258
259	glob_prefs = new CPreferencesRem(m_connect);
260	long enableZLIB;
261	wxConfig::Get()->Read(wxT("/EC/ZLIB"), &enableZLIB, 1);
262	m_connect->SetCapabilities(enableZLIB != 0, true, false);	// ZLIB, UTF8 numbers, notification
263
264	InitCustomLanguages();
265	InitLocale(m_locale, StrLang2wx(thePrefs::GetLanguageID()));
266
267	if (ShowConnectionDialog()) {
268		AddLogLineNS(_("Going to event loop..."));
269		return true;
270	}
271
272	return false;
273}
274
275
276bool CamuleRemoteGuiApp::CryptoAvailable() const
277{
278	return thePrefs::IsSecureIdentEnabled(); // good enough
279}
280
281
282bool CamuleRemoteGuiApp::ShowConnectionDialog()
283{
284	dialog = new CEConnectDlg;
285
286	if (m_skipConnectionDialog) {
287		wxCommandEvent evt;
288		dialog->OnOK(evt);
289	} else if (dialog->ShowModal() != wxID_OK) {
290		dialog->Destroy();
291
292		return false;
293	}
294	AddLogLineNS(_("Connecting..."));
295	if (!m_connect->ConnectToCore(dialog->Host(), dialog->Port(),
296		dialog->Login(), dialog->PassHash(),
297		wxT("amule-remote"), wxT("0x0001"))) {
298		wxMessageBox(_("Connection failed "),_("ERROR"),wxOK);
299
300		return false;
301	}
302
303	return true;
304}
305
306
307void CamuleRemoteGuiApp::OnECConnection(wxEvent& event) {
308	wxECSocketEvent& evt = *((wxECSocketEvent*)&event);
309	AddLogLineNS(_("Remote GUI EC event handler"));
310	wxString reply = evt.GetServerReply();
311	AddLogLineC(reply);
312	if (evt.GetResult() == true) {
313		// Connected - go to next init step
314		glob_prefs->LoadRemote();
315	} else {
316		AddLogLineNS(_("Going down"));
317		if (dialog) {	// connect failed
318			wxMessageBox(
319			(CFormat(_("Connection Failed. Unable to connect to %s:%d\n")) % dialog->Host() % dialog->Port()) + reply,
320			_("ERROR"), wxOK);
321		} else {		// server disconnected (probably terminated) later
322			wxMessageBox(_("Connection closed - aMule has terminated probably."), _("ERROR"), wxOK);
323		}
324		ExitMainLoop();
325	}
326}
327
328
329void CamuleRemoteGuiApp::OnECInitDone(wxEvent& )
330{
331	Startup();
332}
333
334
335void CamuleRemoteGuiApp::OnNotifyEvent(CMuleGUIEvent& evt)
336{
337	evt.Notify();
338}
339
340
341void CamuleRemoteGuiApp::Startup() {
342
343	if (dialog->SaveUserPass()) {
344		wxConfig::Get()->Write(wxT("/EC/Host"), dialog->Host());
345		wxConfig::Get()->Write(wxT("/EC/Port"), dialog->Port());
346		wxConfig::Get()->Write(wxT("/EC/Password"), dialog->PassHash());
347	}
348	dialog->Destroy();
349	dialog = NULL;
350
351	m_ConnState = 0;
352	m_clientID  = 0;
353
354	serverconnect = new CServerConnectRem(m_connect);
355	m_statistics = new CStatistics(*m_connect);
356	stattree = new CStatTreeRem(m_connect);
357
358	clientlist = new CUpDownClientListRem(m_connect);
359	searchlist = new CSearchListRem(m_connect);
360	serverlist = new CServerListRem(m_connect);
361	friendlist = new CFriendListRem(m_connect);
362
363
364	sharedfiles	= new CSharedFilesRem(m_connect);
365	knownfiles = new CKnownFilesRem(m_connect);
366
367	downloadqueue = new CDownQueueRem(m_connect);
368	ipfilter = new CIPFilterRem(m_connect);
369
370	m_allUploadingKnownFile = new CKnownFile;
371
372	// Create main dialog
373	InitGui(m_geometryEnabled, m_geometryString);
374
375	// Forward wxLog events to CLogger
376	wxLog::SetActiveTarget(new CLoggerTarget);
377	knownfiles->DoRequery(EC_OP_GET_UPDATE, EC_TAG_KNOWNFILE);
378
379	// Start the Poll Timer
380	poll_timer->Start(1000);
381	amuledlg->StartGuiTimer();
382
383	// Now activate GeoIP, so that the download dialog doesn't get destroyed immediately
384#ifdef ENABLE_IP2COUNTRY
385	if (thePrefs::IsGeoIPEnabled()) {
386		amuledlg->m_IP2Country->Enable();
387	}
388#endif
389}
390
391
392int CamuleRemoteGuiApp::ShowAlert(wxString msg, wxString title, int flags)
393{
394	return CamuleGuiBase::ShowAlert(msg, title, flags);
395}
396
397
398void CamuleRemoteGuiApp::AddRemoteLogLine(const wxString& line)
399{
400	amuledlg->AddLogLine(line);
401}
402
403int CamuleRemoteGuiApp::InitGui(bool geometry_enabled, wxString &geom_string)
404{
405	CamuleGuiBase::InitGui(geometry_enabled, geom_string);
406	SetTopWindow(amuledlg);
407	AddLogLineN(_("Ready")); // The first log line after the window is up triggers output of all the ones before
408	return 0;
409}
410
411
412bool CamuleRemoteGuiApp::CopyTextToClipboard(wxString strText)
413{
414	return CamuleGuiBase::CopyTextToClipboard(strText);
415}
416
417
418uint32 CamuleRemoteGuiApp::GetPublicIP()
419{
420	return 0;
421}
422
423
424wxString CamuleRemoteGuiApp::GetLog(bool reset)
425{
426	if (reset) {
427		amuledlg->ResetLog(ID_LOGVIEW);
428		CECPacket req(EC_OP_RESET_LOG);
429		m_connect->SendPacket(&req);
430	}
431	return wxEmptyString;
432}
433
434
435wxString CamuleRemoteGuiApp::GetServerLog(bool)
436{
437	return wxEmptyString;
438}
439
440
441bool CamuleRemoteGuiApp::AddServer(CServer * server, bool)
442{
443	CECPacket req(EC_OP_SERVER_ADD);
444	req.AddTag(CECTag(EC_TAG_SERVER_ADDRESS, CFormat(wxT("%s:%d")) % server->GetAddress() % server->GetPort()));
445	req.AddTag(CECTag(EC_TAG_SERVER_NAME, server->GetListName()));
446	m_connect->SendPacket(&req);
447
448	return true;
449}
450
451
452bool CamuleRemoteGuiApp::IsFirewalled() const
453{
454	if (IsConnectedED2K() && !serverconnect->IsLowID()) {
455		return false;
456	}
457
458	return IsFirewalledKad();
459}
460
461
462bool CamuleRemoteGuiApp::IsConnectedED2K() const {
463	return serverconnect && serverconnect->IsConnected();
464}
465
466
467void CamuleRemoteGuiApp::StartKad() {
468	m_connect->StartKad();
469}
470
471
472void CamuleRemoteGuiApp::StopKad() {
473	m_connect->StopKad();
474}
475
476
477void CamuleRemoteGuiApp::BootstrapKad(uint32 ip, uint16 port)
478{
479	CECPacket req(EC_OP_KAD_BOOTSTRAP_FROM_IP);
480	req.AddTag(CECTag(EC_TAG_BOOTSTRAP_IP, ip));
481	req.AddTag(CECTag(EC_TAG_BOOTSTRAP_PORT, port));
482
483	m_connect->SendPacket(&req);
484}
485
486
487void CamuleRemoteGuiApp::UpdateNotesDat(const wxString& url)
488{
489	CECPacket req(EC_OP_KAD_UPDATE_FROM_URL);
490	req.AddTag(CECTag(EC_TAG_KADEMLIA_UPDATE_URL, url));
491
492	m_connect->SendPacket(&req);
493}
494
495
496void CamuleRemoteGuiApp::DisconnectED2K() {
497	if (IsConnectedED2K()) {
498		m_connect->DisconnectED2K();
499	}
500}
501
502
503uint32 CamuleRemoteGuiApp::GetED2KID() const
504{
505	return serverconnect ? serverconnect->GetClientID() : 0;
506}
507
508
509uint32 CamuleRemoteGuiApp::GetID() const
510{
511	return m_clientID;
512}
513
514
515void CamuleRemoteGuiApp::ShowUserCount() {
516	wxString buffer;
517
518	static const wxString s_singlenetstatusformat = _("Users: %s | Files: %s");
519	static const wxString s_bothnetstatusformat = _("Users: E: %s K: %s | Files: E: %s K: %s");
520
521	if (thePrefs::GetNetworkED2K() && thePrefs::GetNetworkKademlia()) {
522		buffer = CFormat(s_bothnetstatusformat) % CastItoIShort(theStats::GetED2KUsers()) % CastItoIShort(theStats::GetKadUsers()) % CastItoIShort(theStats::GetED2KFiles()) % CastItoIShort(theStats::GetKadFiles());
523	} else if (thePrefs::GetNetworkED2K()) {
524		buffer = CFormat(s_singlenetstatusformat) % CastItoIShort(theStats::GetED2KUsers()) % CastItoIShort(theStats::GetED2KFiles());
525	} else if (thePrefs::GetNetworkKademlia()) {
526		buffer = CFormat(s_singlenetstatusformat) % CastItoIShort(theStats::GetKadUsers()) % CastItoIShort(theStats::GetKadFiles());
527	} else {
528		buffer = _("No networks selected");
529	}
530
531	Notify_ShowUserCount(buffer);
532}
533
534
535/*
536 * Preferences: holds both local and remote settings.
537 *
538 * First, everything is loaded from local config file. Later, settings
539 * that are relevant on remote side only are loaded thru EC
540 */
541CPreferencesRem::CPreferencesRem(CRemoteConnect *conn)
542{
543	m_conn = conn;
544
545	//
546	// Settings queried from remote side
547	//
548	m_exchange_send_selected_prefs =
549		EC_PREFS_GENERAL |
550		EC_PREFS_CONNECTIONS |
551		EC_PREFS_MESSAGEFILTER |
552		EC_PREFS_ONLINESIG |
553		EC_PREFS_SERVERS |
554		EC_PREFS_FILES |
555		EC_PREFS_SRCDROP |
556		EC_PREFS_DIRECTORIES |
557		EC_PREFS_SECURITY |
558		EC_PREFS_CORETWEAKS |
559		EC_PREFS_REMOTECONTROLS |
560		EC_PREFS_KADEMLIA;
561	m_exchange_recv_selected_prefs =
562		m_exchange_send_selected_prefs |
563		EC_PREFS_CATEGORIES;
564}
565
566
567void CPreferencesRem::HandlePacket(const CECPacket *packet)
568{
569	((CEC_Prefs_Packet *)packet)->Apply();
570
571	const CECTag *cat_tags = packet->GetTagByName(EC_TAG_PREFS_CATEGORIES);
572	if (cat_tags) {
573		for (CECTag::const_iterator it = cat_tags->begin(); it != cat_tags->end(); it++) {
574			const CECTag &cat_tag = *it;
575			Category_Struct *cat = new Category_Struct;
576			cat->title = cat_tag.GetTagByName(EC_TAG_CATEGORY_TITLE)->GetStringData();
577			cat->path = CPath(cat_tag.GetTagByName(EC_TAG_CATEGORY_PATH)->GetStringData());
578			cat->comment = cat_tag.GetTagByName(EC_TAG_CATEGORY_COMMENT)->GetStringData();
579			cat->color =  cat_tag.GetTagByName(EC_TAG_CATEGORY_COLOR)->GetInt();
580			cat->prio = cat_tag.GetTagByName(EC_TAG_CATEGORY_PRIO)->GetInt();
581			theApp->glob_prefs->AddCat(cat);
582		}
583	} else {
584		Category_Struct *cat = new Category_Struct;
585		cat->title = _("All");
586		cat->color =  0;
587		cat->prio = PR_NORMAL;
588		theApp->glob_prefs->AddCat(cat);
589	}
590	wxECInitDoneEvent event;
591	theApp->AddPendingEvent(event);
592
593}
594
595
596bool CPreferencesRem::LoadRemote()
597{
598	//
599	// override local settings with remote
600	CECPacket req(EC_OP_GET_PREFERENCES, EC_DETAIL_UPDATE);
601
602	// bring categories too
603	req.AddTag(CECTag(EC_TAG_SELECT_PREFS, m_exchange_recv_selected_prefs));
604
605	m_conn->SendRequest(this, &req);
606
607	return true;
608}
609
610
611void CPreferencesRem::SendToRemote()
612{
613	CEC_Prefs_Packet pref_packet(m_exchange_send_selected_prefs, EC_DETAIL_UPDATE, EC_DETAIL_FULL);
614	m_conn->SendPacket(&pref_packet);
615}
616
617
618class CCatHandler : public CECPacketHandlerBase {
619	virtual void HandlePacket(const CECPacket *packet);
620};
621
622
623void CCatHandler::HandlePacket(const CECPacket *packet)
624{
625	if (packet->GetOpCode() == EC_OP_FAILED) {
626		const CECTag * catTag = packet->GetTagByName(EC_TAG_CATEGORY);
627		const CECTag * pathTag = packet->GetTagByName(EC_TAG_CATEGORY_PATH);
628		if (catTag && pathTag && catTag->GetInt() < theApp->glob_prefs->GetCatCount()) {
629			int cat = catTag->GetInt();
630			Category_Struct* cs = theApp->glob_prefs->GetCategory(cat);
631			wxMessageBox(CFormat(_("Can't create directory '%s' for category '%s', keeping directory '%s'."))
632				% cs->path.GetPrintable() % cs->title % pathTag->GetStringData(),
633				_("ERROR"), wxOK);
634			cs->path = CPath(pathTag->GetStringData());
635			theApp->amuledlg->m_transferwnd->UpdateCategory(cat);
636			theApp->amuledlg->m_transferwnd->downloadlistctrl->Refresh();
637		}
638	}
639	delete this;
640}
641
642
643bool CPreferencesRem::CreateCategory(
644	Category_Struct *& category,
645	const wxString& name,
646	const CPath& path,
647	const wxString& comment,
648	uint32 color,
649	uint8 prio)
650{
651	CECPacket req(EC_OP_CREATE_CATEGORY);
652	CEC_Category_Tag tag(0xffffffff, name, path.GetRaw(), comment, color, prio);
653	req.AddTag(tag);
654	m_conn->SendRequest(new CCatHandler, &req);
655
656	category = new Category_Struct();
657	category->path		= path;
658	category->title		= name;
659	category->comment	= comment;
660	category->color		= color;
661	category->prio		= prio;
662
663	AddCat(category);
664
665	return true;
666}
667
668
669bool CPreferencesRem::UpdateCategory(
670	uint8 cat,
671	const wxString& name,
672	const CPath& path,
673	const wxString& comment,
674	uint32 color,
675	uint8 prio)
676{
677	CECPacket req(EC_OP_UPDATE_CATEGORY);
678	CEC_Category_Tag tag(cat, name, path.GetRaw(), comment, color, prio);
679	req.AddTag(tag);
680	m_conn->SendRequest(new CCatHandler, &req);
681
682	Category_Struct *category = m_CatList[cat];
683	category->path		= path;
684	category->title		= name;
685	category->comment	= comment;
686	category->color		= color;
687	category->prio		= prio;
688
689	return true;
690}
691
692
693void CPreferencesRem::RemoveCat(uint8 cat)
694{
695	CECPacket req(EC_OP_DELETE_CATEGORY);
696	CEC_Category_Tag tag(cat, EC_DETAIL_CMD);
697	req.AddTag(tag);
698	m_conn->SendPacket(&req);
699	CPreferences::RemoveCat(cat);
700}
701
702
703//
704// Container implementation
705//
706CServerConnectRem::CServerConnectRem(CRemoteConnect *conn)
707{
708	m_CurrServer = 0;
709	m_Conn = conn;
710}
711
712
713void CServerConnectRem::ConnectToAnyServer()
714{
715	CECPacket req(EC_OP_SERVER_CONNECT);
716	m_Conn->SendPacket(&req);
717}
718
719
720void CServerConnectRem::StopConnectionTry()
721{
722	// lfroen: isn't Disconnect the same ?
723}
724
725
726void CServerConnectRem::Disconnect()
727{
728	CECPacket req(EC_OP_SERVER_DISCONNECT);
729	m_Conn->SendPacket(&req);
730}
731
732
733void CServerConnectRem::ConnectToServer(CServer *server)
734{
735	m_Conn->ConnectED2K(server->GetIP(), server->GetPort());
736}
737
738
739void CServerConnectRem::HandlePacket(const CECPacket *packet)
740{
741	CEC_ConnState_Tag *tag =
742		(CEC_ConnState_Tag *)packet->GetTagByName(EC_TAG_CONNSTATE);
743	if (!tag) {
744		return;
745	}
746
747	theApp->m_ConnState = 0;
748	CServer *server;
749	m_ID = tag->GetEd2kId();
750	theApp->m_clientID = tag->GetClientId();
751
752	if (tag->IsConnectedED2K()) {
753		CECTag *srvtag = tag->GetTagByName(EC_TAG_SERVER);
754		if (srvtag) {
755			server = theApp->serverlist->GetByID(srvtag->GetInt());
756			if (server != m_CurrServer) {
757				theApp->amuledlg->m_serverwnd->serverlistctrl->HighlightServer(server, true);
758				m_CurrServer = server;
759			}
760		}
761		theApp->m_ConnState |= CONNECTED_ED2K;
762	} else if ( m_CurrServer ) {
763	    theApp->amuledlg->m_serverwnd->serverlistctrl->HighlightServer(m_CurrServer, false);
764	    m_CurrServer = 0;
765	}
766
767	if (tag->IsConnectedKademlia()) {
768		if (tag->IsKadFirewalled()) {
769			theApp->m_ConnState |= CONNECTED_KAD_FIREWALLED;
770		} else {
771			theApp->m_ConnState |= CONNECTED_KAD_OK;
772		}
773	} else {
774		if (tag->IsKadRunning()) {
775			theApp->m_ConnState |= CONNECTED_KAD_NOT;
776		}
777	}
778
779	theApp->amuledlg->ShowConnectionState();
780}
781
782
783/*
784 * Server list: host list of ed2k servers.
785 */
786CServerListRem::CServerListRem(CRemoteConnect *conn)
787:
788CRemoteContainer<CServer, uint32, CEC_Server_Tag>(conn, true)
789{
790}
791
792
793void CServerListRem::HandlePacket(const CECPacket *)
794{
795	// There is no packet for the server list, it is part of the general update packet
796	wxFAIL;
797	// CRemoteContainer<CServer, uint32, CEC_Server_Tag>::HandlePacket(packet);
798}
799
800
801void CServerListRem::UpdateServerMetFromURL(wxString url)
802{
803	CECPacket req(EC_OP_SERVER_UPDATE_FROM_URL);
804	req.AddTag(CECTag(EC_TAG_SERVERS_UPDATE_URL, url));
805
806	m_conn->SendPacket(&req);
807}
808
809
810void CServerListRem::SetStaticServer(CServer* server, bool isStatic)
811{
812	// update display right away
813	server->SetIsStaticMember(isStatic);
814	Notify_ServerRefresh(server);
815
816	CECPacket req(EC_OP_SERVER_SET_STATIC_PRIO);
817	req.AddTag(CECTag(EC_TAG_SERVER, server->ECID()));
818	req.AddTag(CECTag(EC_TAG_SERVER_STATIC, isStatic));
819
820	m_conn->SendPacket(&req);
821}
822
823
824void CServerListRem::SetServerPrio(CServer* server, uint32 prio)
825{
826	// update display right away
827	server->SetPreference(prio);
828	Notify_ServerRefresh(server);
829
830	CECPacket req(EC_OP_SERVER_SET_STATIC_PRIO);
831	req.AddTag(CECTag(EC_TAG_SERVER, server->ECID()));
832	req.AddTag(CECTag(EC_TAG_SERVER_PRIO, prio));
833
834	m_conn->SendPacket(&req);
835}
836
837
838void CServerListRem::RemoveServer(CServer* server)
839{
840	m_conn->RemoveServer(server->GetIP(),server->GetPort());
841}
842
843
844void CServerListRem::UpdateUserFileStatus(CServer *server)
845{
846	if (server) {
847		m_TotalUser = server->GetUsers();
848		m_TotalFile = server->GetFiles();
849	}
850}
851
852
853CServer *CServerListRem::GetServerByAddress(const wxString& WXUNUSED(address), uint16 WXUNUSED(port)) const
854{
855	// It's ok to return 0 for context where this code is used in remote gui
856	return 0;
857}
858
859CServer *CServerListRem::GetServerByIPTCP(uint32 WXUNUSED(nIP), uint16 WXUNUSED(nPort)) const
860{
861	// It's ok to return 0 for context where this code is used in remote gui
862	return 0;
863}
864
865CServer *CServerListRem::CreateItem(CEC_Server_Tag *tag)
866{
867	CServer * server = new CServer(tag);
868	ProcessItemUpdate(tag, server);
869	return server;
870}
871
872
873void CServerListRem::DeleteItem(CServer *in_srv)
874{
875	CScopedPtr<CServer> srv(in_srv);
876	theApp->amuledlg->m_serverwnd->serverlistctrl->RemoveServer(srv.get());
877}
878
879
880uint32 CServerListRem::GetItemID(CServer *server)
881{
882	return server->ECID();
883}
884
885
886void CServerListRem::ProcessItemUpdate(CEC_Server_Tag * tag, CServer * server)
887{
888	if (!tag->HasChildTags()) {
889		return;
890	}
891	tag->ServerName(& server->listname);
892	tag->ServerDesc(& server->description);
893	tag->ServerVersion(& server->m_strVersion);
894	tag->GetMaxUsers(& server->maxusers);
895
896	tag->GetFiles(& server->files);
897	tag->GetUsers(& server->users);
898
899	tag->GetPrio(& server->preferences); // SRV_PR_NORMAL = 0, so it's ok
900    tag->GetStatic(& server->staticservermember);
901
902	tag->GetPing(& server->ping);
903	tag->GetFailed(& server->failedcount);
904
905	theApp->amuledlg->m_serverwnd->serverlistctrl->RefreshServer(server);
906}
907
908
909CServer::CServer(CEC_Server_Tag *tag) : CECID(tag->GetInt())
910{
911	ip = tag->GetTagByNameSafe(EC_TAG_SERVER_IP)->GetInt();
912	port = tag->GetTagByNameSafe(EC_TAG_SERVER_PORT)->GetInt();
913
914	Init();
915}
916
917
918/*
919 * IP filter
920 */
921CIPFilterRem::CIPFilterRem(CRemoteConnect* conn)
922{
923	m_conn = conn;
924}
925
926
927void CIPFilterRem::Reload()
928{
929	CECPacket req(EC_OP_IPFILTER_RELOAD);
930	m_conn->SendPacket(&req);
931}
932
933
934void CIPFilterRem::Update(wxString url)
935{
936	CECPacket req(EC_OP_IPFILTER_UPDATE);
937	req.AddTag(CECTag(EC_TAG_STRING, url));
938
939	m_conn->SendPacket(&req);
940}
941
942
943/*
944 * Shared files list
945 */
946CSharedFilesRem::CSharedFilesRem(CRemoteConnect *conn)
947{
948	m_conn = conn;
949}
950
951
952void CSharedFilesRem::Reload(bool, bool)
953{
954	CECPacket req(EC_OP_SHAREDFILES_RELOAD);
955
956	m_conn->SendPacket(&req);
957}
958
959
960bool CSharedFilesRem::RenameFile(CKnownFile* file, const CPath& newName)
961{
962	// We use the printable name, as the filename originated from user input,
963	// and the filesystem name might not be valid on the remote host.
964	const wxString strNewName = newName.GetPrintable();
965
966	CECPacket request(EC_OP_RENAME_FILE);
967	request.AddTag(CECTag(EC_TAG_KNOWNFILE, file->GetFileHash()));
968	request.AddTag(CECTag(EC_TAG_PARTFILE_NAME, strNewName));
969
970	m_conn->SendPacket(&request);
971
972	return true;
973}
974
975
976void CSharedFilesRem::SetFileCommentRating(CKnownFile* file, const wxString& newComment, int8 newRating)
977{
978	CECPacket request(EC_OP_SHARED_FILE_SET_COMMENT);
979	request.AddTag(CECTag(EC_TAG_KNOWNFILE, file->GetFileHash()));
980	request.AddTag(CECTag(EC_TAG_KNOWNFILE_COMMENT, newComment));
981	request.AddTag(CECTag(EC_TAG_KNOWNFILE_RATING, newRating));
982
983	m_conn->SendPacket(&request);
984}
985
986
987void CSharedFilesRem::CopyFileList(std::vector<CKnownFile*>& out_list) const
988{
989	out_list.reserve(size());
990	for (const_iterator it = begin(); it != end(); it++) {
991		out_list.push_back(it->second);
992	}
993}
994
995
996void CKnownFilesRem::DeleteItem(CKnownFile * file)
997{
998	uint32 id = file->ECID();
999	if (theApp->sharedfiles->count(id)) {
1000		theApp->amuledlg->m_sharedfileswnd->sharedfilesctrl->RemoveFile(file);
1001		theApp->sharedfiles->erase(id);
1002	}
1003	if (theApp->downloadqueue->count(id)) {
1004		theApp->amuledlg->m_transferwnd->downloadlistctrl->RemoveFile((CPartFile *) file);
1005		theApp->downloadqueue->erase(id);
1006	}
1007	delete file;
1008}
1009
1010
1011uint32 CKnownFilesRem::GetItemID(CKnownFile *file)
1012{
1013	return file->ECID();
1014}
1015
1016
1017void CKnownFilesRem::ProcessItemUpdate(CEC_SharedFile_Tag *tag, CKnownFile *file)
1018{
1019	CECTag *parttag = tag->GetTagByName(EC_TAG_PARTFILE_PART_STATUS);
1020	if (parttag) {
1021		const uint8 *data =	file->m_partStatus.Decode(
1022				(uint8 *)parttag->GetTagData(),
1023				parttag->GetTagDataLen());
1024		for(int i = 0; i < file->GetPartCount(); ++i) {
1025			file->m_AvailPartFrequency[i] = data[i];
1026		}
1027	}
1028	wxString fileName;
1029	if (tag->FileName(fileName)) {
1030		file->SetFileName(CPath(fileName));
1031	}
1032	if (tag->FilePath(fileName)) {
1033		file->m_filePath = CPath(fileName);
1034	}
1035	tag->UpPrio(&file->m_iUpPriorityEC);
1036	tag->GetAICHHash(file->m_AICHMasterHash);
1037	tag->GetRequests(&file->statistic.requested);
1038	tag->GetAllRequests(&file->statistic.alltimerequested);
1039	tag->GetAccepts(&file->statistic.accepted);
1040	tag->GetAllAccepts(&file->statistic.alltimeaccepted);
1041	tag->GetXferred(&file->statistic.transferred);
1042	tag->GetAllXferred(&file->statistic.alltimetransferred);
1043	tag->UpPrio(&file->m_iUpPriorityEC);
1044	if (file->m_iUpPriorityEC >= 10) {
1045		file->m_iUpPriority = file->m_iUpPriorityEC - 10;
1046		file->m_bAutoUpPriority = true;
1047	} else {
1048		file->m_iUpPriority = file->m_iUpPriorityEC;
1049		file->m_bAutoUpPriority = false;
1050	}
1051	tag->GetCompleteSourcesLow(&file->m_nCompleteSourcesCountLo);
1052	tag->GetCompleteSourcesHigh(&file->m_nCompleteSourcesCountHi);
1053	tag->GetCompleteSources(&file->m_nCompleteSourcesCount);
1054
1055	tag->GetOnQueue(&file->m_queuedCount);
1056
1057	tag->GetComment(file->m_strComment);
1058	tag->GetRating(file->m_iRating);
1059
1060	requested += file->statistic.requested;
1061	transferred += file->statistic.transferred;
1062	accepted += file->statistic.transferred;
1063
1064	if (!m_initialUpdate) {
1065		theApp->amuledlg->m_sharedfileswnd->sharedfilesctrl->UpdateItem(file);
1066	}
1067
1068	if (file->IsPartFile()) {
1069		ProcessItemUpdatePartfile((CEC_PartFile_Tag *) tag, (CPartFile *) file);
1070	}
1071}
1072
1073void CSharedFilesRem::SetFilePrio(CKnownFile *file, uint8 prio)
1074{
1075	CECPacket req(EC_OP_SHARED_SET_PRIO);
1076
1077	CECTag hashtag(EC_TAG_PARTFILE, file->GetFileHash());
1078	hashtag.AddTag(CECTag(EC_TAG_PARTFILE_PRIO, prio));
1079
1080	req.AddTag(hashtag);
1081
1082	m_conn->SendPacket(&req);
1083}
1084
1085void CKnownFilesRem::ProcessUpdate(const CECTag *reply, CECPacket *, int)
1086{
1087	requested = 0;
1088	transferred = 0;
1089	accepted = 0;
1090
1091	std::set<uint32> core_files;
1092	for (CECPacket::const_iterator it = reply->begin(); it != reply->end(); it++) {
1093		const CECTag * curTag = &*it;
1094		ec_tagname_t tagname = curTag->GetTagName();
1095		if (tagname == EC_TAG_CLIENT) {
1096			theApp->clientlist->ProcessUpdate(curTag, NULL, EC_TAG_CLIENT);
1097		} else if (tagname == EC_TAG_SERVER) {
1098			theApp->serverlist->ProcessUpdate(curTag, NULL, EC_TAG_SERVER);
1099		} else if (tagname == EC_TAG_FRIEND) {
1100			theApp->friendlist->ProcessUpdate(curTag, NULL, EC_TAG_FRIEND);
1101		} else if (tagname == EC_TAG_KNOWNFILE || tagname == EC_TAG_PARTFILE) {
1102			CEC_SharedFile_Tag *tag = (CEC_SharedFile_Tag *) curTag;
1103			uint32 id = tag->ID();
1104			bool isNew = true;
1105			if (!m_initialUpdate) {
1106				core_files.insert(id);
1107				std::map<uint32, CKnownFile*>::iterator it2 = m_items_hash.find(id);
1108				if (it2 != m_items_hash.end() ) {
1109					// Item already known: update it
1110					if (tag->HasChildTags()) {
1111						ProcessItemUpdate(tag, it2->second);
1112					}
1113					isNew = false;
1114				}
1115			}
1116			if (isNew) {
1117				CKnownFile * newFile;
1118				if (tag->GetTagName() == EC_TAG_PARTFILE) {
1119					CPartFile *file = new CPartFile((CEC_PartFile_Tag *) tag);
1120					ProcessItemUpdate(tag, file);
1121					(*theApp->downloadqueue)[id] = file;
1122					theApp->amuledlg->m_transferwnd->downloadlistctrl->AddFile(file);
1123					newFile = file;
1124				} else {
1125					newFile = new CKnownFile(tag);
1126					ProcessItemUpdate(tag, newFile);
1127					(*theApp->sharedfiles)[id] = newFile;
1128					if (!m_initialUpdate) {
1129						theApp->amuledlg->m_sharedfileswnd->sharedfilesctrl->ShowFile(newFile);
1130					}
1131				}
1132				AddItem(newFile);
1133			}
1134		}
1135	}
1136
1137	if (m_initialUpdate) {
1138		theApp->amuledlg->m_sharedfileswnd->sharedfilesctrl->ShowFileList();
1139		m_initialUpdate = false;
1140	} else {
1141		// remove items no longer present
1142		for(iterator it = begin(); it != end();) {
1143			iterator it2 = it++;
1144			if (!core_files.count(GetItemID(*it2))) {
1145				RemoveItem(it2);	// This calls DeleteItem, where it is removed from lists and views.
1146			}
1147		}
1148	}
1149}
1150
1151CKnownFilesRem::CKnownFilesRem(CRemoteConnect * conn) : CRemoteContainer<CKnownFile, uint32, CEC_SharedFile_Tag>(conn, true)
1152{
1153	requested = 0;
1154	transferred = 0;
1155	accepted = 0;
1156	m_initialUpdate = true;
1157}
1158
1159
1160/*
1161 * List of uploading and waiting clients.
1162 */
1163CUpDownClientListRem::CUpDownClientListRem(CRemoteConnect *conn)
1164:
1165CRemoteContainer<CClientRef, uint32, CEC_UpDownClient_Tag>(conn, true)
1166{
1167}
1168
1169
1170CClientRef::CClientRef(CEC_UpDownClient_Tag *tag)
1171{
1172	m_client = new CUpDownClient(tag);
1173#ifdef DEBUG_ZOMBIE_CLIENTS
1174	m_client->Link(wxT("TAG"));
1175#else
1176	m_client->Link();
1177#endif
1178}
1179
1180
1181CUpDownClient::CUpDownClient(CEC_UpDownClient_Tag *tag) : CECID(tag->ID())
1182{
1183	m_linked = 0;
1184#ifdef DEBUG_ZOMBIE_CLIENTS
1185	m_linkedDebug = false;
1186#endif
1187	// Clients start up empty, then get asked for their data.
1188	// So all data here is processed in ProcessItemUpdate and thus updatable.
1189	m_bEmuleProtocol		= false;
1190	m_AvailPartCount		= 0;
1191	m_clientSoft			= 0;
1192	m_nDownloadState		= 0;
1193	m_Friend				= NULL;
1194	m_bFriendSlot			= false;
1195	m_nKadPort				= 0;
1196	m_kBpsDown				= 0;
1197	m_dwUserIP				= 0;
1198	m_lastDownloadingPart	= 0xffff;
1199	m_nextRequestedPart		= 0xffff;
1200	m_obfuscationStatus		= 0;
1201	m_nOldRemoteQueueRank	= 0;
1202	m_nRemoteQueueRank		= 0;
1203	m_reqfile				= NULL;
1204	m_score					= 0;
1205	m_dwServerIP			= 0;
1206	m_nServerPort			= 0;
1207	m_nSourceFrom			= SF_NONE;
1208	m_nTransferredDown		= 0;
1209	m_nTransferredUp		= 0;
1210	m_nUpDatarate			= 0;
1211	m_uploadingfile			= NULL;
1212	m_waitingPosition		= 0;
1213	m_nUploadState			= 0;
1214	m_nUserIDHybrid			= 0;
1215	m_nUserPort				= 0;
1216	m_nClientVersion		= 0;
1217	m_fNoViewSharedFiles	= true;
1218	m_identState			= IS_NOTAVAILABLE;
1219	m_bRemoteQueueFull		= false;
1220
1221	credits = new CClientCredits(new CreditStruct());
1222}
1223
1224#ifdef DEBUG_ZOMBIE_CLIENTS
1225void CUpDownClient::Unlink(const wxString& from)
1226{
1227	std::multiset<wxString>::iterator it = m_linkedFrom.find(from);
1228	if (it != m_linkedFrom.end()) {
1229		m_linkedFrom.erase(it);
1230	}
1231	m_linked--;
1232	if (!m_linked) {
1233		if (m_linkedDebug) {
1234			AddLogLineN(CFormat(wxT("Last reference to client %d %p unlinked, delete it.")) % ECID() % this);
1235		}
1236		delete this;
1237	}
1238}
1239
1240#else
1241
1242void CUpDownClient::Unlink()
1243{
1244	m_linked--;
1245	if (!m_linked) {
1246		delete this;
1247	}
1248}
1249#endif
1250
1251
1252uint64 CUpDownClient::GetDownloadedTotal() const
1253{
1254	return credits->GetDownloadedTotal();
1255}
1256
1257
1258uint64 CUpDownClient::GetUploadedTotal() const
1259{
1260	return credits->GetUploadedTotal();
1261}
1262
1263
1264double CUpDownClient::GetScoreRatio() const
1265{
1266	return credits->GetScoreRatio(GetIP(), theApp->CryptoAvailable());
1267}
1268
1269/* End Warning */
1270
1271
1272CUpDownClient::~CUpDownClient()
1273{
1274	delete credits;
1275}
1276
1277
1278CClientRef *CUpDownClientListRem::CreateItem(CEC_UpDownClient_Tag *tag)
1279{
1280	CClientRef *client = new CClientRef(tag);
1281	ProcessItemUpdate(tag, client);
1282
1283	return client;
1284}
1285
1286
1287void CUpDownClientListRem::DeleteItem(CClientRef *clientref)
1288{
1289	CUpDownClient* client = clientref->GetClient();
1290	if (client->m_reqfile) {
1291		client->m_reqfile->DelSource(client);
1292		client->m_reqfile = NULL;
1293	}
1294	Notify_SourceCtrlRemoveSource(client->ECID(), (CPartFile*) NULL);
1295
1296	if (client->m_uploadingfile) {
1297		client->m_uploadingfile->RemoveUploadingClient(client);	// this notifies
1298		client->m_uploadingfile = NULL;
1299	}
1300	theApp->m_allUploadingKnownFile->RemoveUploadingClient(client);	// in case it vanished directly while uploading
1301	Notify_SharedCtrlRemoveClient(client->ECID(), (CKnownFile*) NULL);
1302
1303	if (client->m_Friend) {
1304		client->m_Friend->UnLinkClient();	// this notifies
1305		client->m_Friend = NULL;
1306	}
1307
1308#ifdef DEBUG_ZOMBIE_CLIENTS
1309	if (client->m_linked > 1) {
1310		AddLogLineC(CFormat(wxT("Client %d still linked in %d places: %s")) % client->ECID() % (client->m_linked - 1) % client->GetLinkedFrom());
1311		client->m_linkedDebug = true;
1312	}
1313#endif
1314
1315	delete clientref;
1316}
1317
1318
1319uint32 CUpDownClientListRem::GetItemID(CClientRef *client)
1320{
1321	return client->ECID();
1322}
1323
1324
1325void CUpDownClientListRem::ProcessItemUpdate(
1326	CEC_UpDownClient_Tag *tag,
1327	CClientRef *clientref)
1328{
1329	if (!tag->HasChildTags()) {
1330		return;		// speed exit for clients without any change
1331	}
1332	CUpDownClient *client = clientref->GetClient();
1333
1334	tag->UserID(&client->m_nUserIDHybrid);
1335	tag->ClientName(&client->m_Username);
1336	// Client Software
1337	bool sw_updated = false;
1338	if (tag->ClientSoftware(client->m_clientSoft)) {
1339		client->m_clientSoftString = GetSoftName(client->m_clientSoft);
1340		sw_updated = true;
1341	}
1342	if (tag->SoftVerStr(client->m_clientVerString) || sw_updated) {
1343		if (client->m_clientSoftString == _("Unknown")) {
1344			client->m_fullClientVerString = client->m_clientSoftString;
1345		} else {
1346			client->m_fullClientVerString = client->m_clientSoftString + wxT(" ") + client->m_clientVerString;
1347		}
1348	}
1349	// User hash
1350	tag->UserHash(&client->m_UserHash);
1351
1352	// User IP:Port
1353	tag->UserIP(client->m_dwUserIP);
1354	tag->UserPort(&client->m_nUserPort);
1355
1356	// Server IP:Port
1357	tag->ServerIP(&client->m_dwServerIP);
1358	tag->ServerPort(&client->m_nServerPort);
1359	tag->ServerName(&client->m_ServerName);
1360
1361	tag->KadPort(client->m_nKadPort);
1362	tag->FriendSlot(client->m_bFriendSlot);
1363
1364	tag->GetCurrentIdentState(&client->m_identState);
1365	tag->ObfuscationStatus(client->m_obfuscationStatus);
1366	tag->HasExtendedProtocol(&client->m_bEmuleProtocol);
1367
1368	tag->WaitingPosition(&client->m_waitingPosition);
1369	tag->RemoteQueueRank(&client->m_nRemoteQueueRank);
1370	client->m_bRemoteQueueFull = client->m_nRemoteQueueRank == 0xffff;
1371	tag->OldRemoteQueueRank(&client->m_nOldRemoteQueueRank);
1372
1373	tag->ClientDownloadState(client->m_nDownloadState);
1374	if (tag->ClientUploadState(client->m_nUploadState)) {
1375		if (client->m_nUploadState == US_UPLOADING) {
1376			theApp->m_allUploadingKnownFile->AddUploadingClient(client);
1377		} else {
1378			theApp->m_allUploadingKnownFile->RemoveUploadingClient(client);
1379		}
1380	}
1381
1382	tag->SpeedUp(&client->m_nUpDatarate);
1383	if ( client->m_nDownloadState == DS_DOWNLOADING ) {
1384		tag->SpeedDown(&client->m_kBpsDown);
1385	} else {
1386		client->m_kBpsDown = 0;
1387	}
1388
1389	//tag->WaitTime(&client->m_WaitTime);
1390	//tag->XferTime(&client->m_UpStartTimeDelay);
1391	//tag->LastReqTime(&client->m_dwLastUpRequest);
1392	//tag->QueueTime(&client->m_WaitStartTime);
1393
1394	CreditStruct *credit_struct =
1395		(CreditStruct *)client->credits->GetDataStruct();
1396	tag->XferUp(&credit_struct->uploaded);
1397	tag->XferUpSession(&client->m_nTransferredUp);
1398
1399	tag->XferDown(&credit_struct->downloaded);
1400	tag->XferDownSession(&client->m_nTransferredDown);
1401
1402	tag->Score(&client->m_score);
1403
1404	tag->NextRequestedPart(client->m_nextRequestedPart);
1405	tag->LastDownloadingPart(client->m_lastDownloadingPart);
1406
1407	uint8 sourceFrom = 0;
1408	if (tag->GetSourceFrom(sourceFrom)) {
1409		client->m_nSourceFrom = (ESourceFrom)sourceFrom;
1410	}
1411
1412	tag->RemoteFilename(client->m_clientFilename);
1413	tag->DisableViewShared(client->m_fNoViewSharedFiles);
1414	tag->Version(client->m_nClientVersion);
1415	tag->ModVersion(client->m_strModVersion);
1416	tag->OSInfo(client->m_sClientOSInfo);
1417	tag->AvailableParts(client->m_AvailPartCount);
1418
1419	// Download client
1420	uint32 fileID;
1421	bool notified = false;
1422	if (tag->RequestFile(fileID)) {
1423		if (client->m_reqfile) {
1424			Notify_SourceCtrlRemoveSource(client->ECID(), client->m_reqfile);
1425			client->m_reqfile->DelSource(client);
1426			client->m_reqfile = NULL;
1427			client->m_downPartStatus.clear();
1428		}
1429		CKnownFile * kf = theApp->knownfiles->GetByID(fileID);
1430		if (kf && kf->IsCPartFile()) {
1431			client->m_reqfile = (CPartFile *) kf;
1432			client->m_reqfile->AddSource(client);
1433			client->m_downPartStatus.setsize(kf->GetPartCount(), 0);
1434			Notify_SourceCtrlAddSource(client->m_reqfile, CCLIENTREF(client, wxT("AddSource")), A4AF_SOURCE);
1435			notified = true;
1436		}
1437	}
1438
1439	// Part status
1440	CECTag * partStatusTag = tag->GetTagByName(EC_TAG_CLIENT_PART_STATUS);
1441	if (partStatusTag) {
1442		if (partStatusTag->GetTagDataLen() == 0) {
1443			// empty tag means full source
1444			client->m_downPartStatus.SetAllTrue();
1445		} else if (partStatusTag->GetTagDataLen() == client->m_downPartStatus.SizeBuffer()) {
1446			client->m_downPartStatus.SetBuffer(partStatusTag->GetTagData());
1447		}
1448		notified = false;
1449	}
1450
1451	if (!notified && client->m_reqfile && client->m_reqfile->ShowSources()) {
1452		SourceItemType type;
1453		switch (client->GetDownloadState()) {
1454			case DS_DOWNLOADING:
1455			case DS_ONQUEUE:
1456				// We will send A4AF, which will be checked.
1457				type = A4AF_SOURCE;
1458				break;
1459			default:
1460				type = UNAVAILABLE_SOURCE;
1461				break;
1462		}
1463
1464		Notify_SourceCtrlUpdateSource(client->ECID(), type);
1465	}
1466
1467	// Upload client
1468	notified = false;
1469	if (tag->UploadFile(fileID)) {
1470		if (client->m_uploadingfile) {
1471			client->m_uploadingfile->RemoveUploadingClient(client);	// this notifies
1472			notified = true;
1473			client->m_uploadingfile = NULL;
1474		}
1475		CKnownFile * kf = theApp->knownfiles->GetByID(fileID);
1476		if (kf) {
1477			client->m_uploadingfile = kf;
1478			client->m_upPartStatus.setsize(kf->GetPartCount(), 0);
1479			client->m_uploadingfile->AddUploadingClient(client);	// this notifies
1480			notified = true;
1481		}
1482	}
1483
1484	// Part status
1485	partStatusTag = tag->GetTagByName(EC_TAG_CLIENT_UPLOAD_PART_STATUS);
1486	if (partStatusTag) {
1487		if (partStatusTag->GetTagDataLen() == client->m_upPartStatus.SizeBuffer()) {
1488			client->m_upPartStatus.SetBuffer(partStatusTag->GetTagData());
1489		}
1490		notified = false;
1491	}
1492
1493	if (!notified && client->m_uploadingfile
1494		&& (client->m_uploadingfile->ShowPeers() || (client->m_nUploadState == US_UPLOADING))) {
1495			// notify if KnowFile is selected, or if it's uploading (in case clients are in show uploading mode)
1496		SourceItemType type;
1497		switch (client->GetUploadState()) {
1498			case US_UPLOADING:
1499			case US_ONUPLOADQUEUE:
1500				type = AVAILABLE_SOURCE;
1501				break;
1502			default:
1503				type = UNAVAILABLE_SOURCE;
1504				break;
1505		}
1506		Notify_SharedCtrlRefreshClient(client->ECID(), type);
1507	}
1508}
1509
1510
1511/*
1512 * Download queue container: hold PartFiles with progress status
1513 *
1514 */
1515
1516
1517bool CDownQueueRem::AddLink(const wxString &link, uint8 cat)
1518{
1519	CECPacket req(EC_OP_ADD_LINK);
1520	CECTag link_tag(EC_TAG_STRING, link);
1521	link_tag.AddTag(CECTag(EC_TAG_PARTFILE_CAT, cat));
1522	req.AddTag(link_tag);
1523
1524	m_conn->SendPacket(&req);
1525	return true;
1526}
1527
1528
1529void CDownQueueRem::ResetCatParts(int cat)
1530{
1531	// Called when category is deleted. Command will be performed on the remote side,
1532	// but files still should be updated here right away, or drawing errors (colour not available)
1533	// will happen.
1534	for (iterator it = begin(); it != end(); it++) {
1535		CPartFile* file = it->second;
1536		file->RemoveCategory(cat);
1537	}
1538}
1539
1540
1541
1542void CKnownFilesRem::ProcessItemUpdatePartfile(CEC_PartFile_Tag *tag, CPartFile *file)
1543{
1544	//
1545	// update status
1546	//
1547	tag->Speed(&file->m_kbpsDown);
1548	file->kBpsDown = file->m_kbpsDown / 1024.0;
1549
1550	tag->SizeXfer(&file->transferred);
1551	tag->SizeDone(&file->completedsize);
1552	tag->SourceXferCount(&file->transferingsrc);
1553	tag->SourceNotCurrCount(&file->m_notCurrentSources);
1554	tag->SourceCount(&file->m_source_count);
1555	tag->SourceCountA4AF(&file->m_a4af_source_count);
1556	tag->FileStatus(&file->status);
1557	tag->Stopped(&file->m_stopped);
1558
1559	tag->LastSeenComplete(&file->lastseencomplete);
1560	tag->LastDateChanged(&file->m_lastDateChanged);
1561	tag->DownloadActiveTime(&file->m_nDlActiveTime);
1562	tag->AvailablePartCount(&file->m_availablePartsCount);
1563	tag->Shared(&file->m_isShared);
1564	tag->A4AFAuto(file->m_is_A4AF_auto);
1565
1566	tag->GetLostDueToCorruption(&file->m_iLostDueToCorruption);
1567	tag->GetGainDueToCompression(&file->m_iGainDueToCompression);
1568	tag->TotalPacketsSavedDueToICH(&file->m_iTotalPacketsSavedDueToICH);
1569
1570	tag->FileCat(&file->m_category);
1571
1572	tag->DownPrio(&file->m_iDownPriorityEC);
1573	if ( file->m_iDownPriorityEC >= 10 ) {
1574		file->m_iDownPriority = file->m_iDownPriorityEC - 10;
1575		file->m_bAutoDownPriority = true;
1576	} else {
1577		file->m_iDownPriority = file->m_iDownPriorityEC;
1578		file->m_bAutoDownPriority = false;
1579	}
1580
1581	file->percentcompleted = (100.0*file->GetCompletedSize()) / file->GetFileSize();
1582
1583	//
1584	// Copy part/gap status
1585	//
1586	CECTag *gaptag = tag->GetTagByName(EC_TAG_PARTFILE_GAP_STATUS);
1587	CECTag *parttag = tag->GetTagByName(EC_TAG_PARTFILE_PART_STATUS);
1588	CECTag *reqtag = tag->GetTagByName(EC_TAG_PARTFILE_REQ_STATUS);
1589	if (gaptag || parttag || reqtag) {
1590		PartFileEncoderData &encoder = file->m_PartFileEncoderData;
1591
1592		if (gaptag) {
1593			ArrayOfUInts64 gaps;
1594			encoder.DecodeGaps(gaptag, gaps);
1595			int gap_size = gaps.size() / 2;
1596			// clear gaplist
1597			file->m_gaplist.Init(file->GetFileSize(), false);
1598
1599			// and refill it
1600			for (int j = 0; j < gap_size; j++) {
1601				file->m_gaplist.AddGap(gaps[2*j], gaps[2*j+1]);
1602			}
1603		}
1604		if (parttag) {
1605			encoder.DecodeParts(parttag, file->m_SrcpartFrequency);
1606			// sanity check
1607			wxASSERT (file->m_SrcpartFrequency.size() == file->GetPartCount());
1608		}
1609		if (reqtag) {
1610			ArrayOfUInts64 reqs;
1611			encoder.DecodeReqs(reqtag, reqs);
1612			int req_size = reqs.size() / 2;
1613			// clear reqlist
1614			DeleteContents(file->m_requestedblocks_list);
1615
1616			// and refill it
1617			for (int j = 0; j < req_size; j++) {
1618				Requested_Block_Struct* block = new Requested_Block_Struct;
1619				block->StartOffset = reqs[2*j];
1620				block->EndOffset   = reqs[2*j+1];
1621				file->m_requestedblocks_list.push_back(block);
1622			}
1623		}
1624	}
1625
1626	// Get source names and counts
1627	CECTag *srcnametag = tag->GetTagByName(EC_TAG_PARTFILE_SOURCE_NAMES);
1628	if (srcnametag) {
1629		SourcenameItemMap &map = file->GetSourcenameItemMap();
1630		for (CECTag::const_iterator it = srcnametag->begin(); it != srcnametag->end(); it++) {
1631			uint32 key = it->GetInt();
1632			int count = it->GetTagByNameSafe(EC_TAG_PARTFILE_SOURCE_NAMES_COUNTS)->GetInt();
1633			if (count == 0) {
1634				map.erase(key);
1635			} else {
1636				SourcenameItem &item = map[key];
1637				item.count = count;
1638				const CECTag *nametag = it->GetTagByName(EC_TAG_PARTFILE_SOURCE_NAMES);
1639				if (nametag) {
1640					item.name = nametag->GetStringData();
1641				}
1642			}
1643		}
1644	}
1645
1646	// Get comments
1647	CECTag *commenttag = tag->GetTagByName(EC_TAG_PARTFILE_COMMENTS);
1648	if (commenttag) {
1649		file->ClearFileRatingList();
1650		for (CECTag::const_iterator it = commenttag->begin(); it != commenttag->end(); ) {
1651			wxString u = (it++)->GetStringData();
1652			wxString f = (it++)->GetStringData();
1653			int r = (it++)->GetInt();
1654			wxString c = (it++)->GetStringData();
1655			file->AddFileRatingList(u, f, r, c);
1656		}
1657		file->UpdateFileRatingCommentAvail();
1658	}
1659
1660	// Update A4AF sources
1661	ListOfUInts32 & clientIDs = file->GetA4AFClientIDs();
1662	CECTag *a4aftag = tag->GetTagByName(EC_TAG_PARTFILE_A4AF_SOURCES);
1663	if (a4aftag) {
1664		file->ClearA4AFList();
1665		clientIDs.clear();
1666		for (CECTag::const_iterator it = a4aftag->begin(); it != a4aftag->end(); it++) {
1667			if (it->GetTagName() != EC_TAG_ECID) {	// should always be this
1668				continue;
1669			}
1670			uint32 id = it->GetInt();
1671			CClientRef * src = theApp->clientlist->GetByID(id);
1672			if (src) {
1673				file->AddA4AFSource(src->GetClient());
1674			} else {
1675				// client wasn't transmitted yet, try it later
1676				clientIDs.push_back(id);
1677			}
1678		}
1679	} else if (!clientIDs.empty()) {
1680		// Process clients from the last pass whose ids were still unknown then
1681		for (ListOfUInts32::iterator it = clientIDs.begin(); it != clientIDs.end(); ) {
1682			ListOfUInts32::iterator it1 = it++;
1683			uint32 id = *it1;
1684			CClientRef * src = theApp->clientlist->GetByID(id);
1685			if (src) {
1686				file->AddA4AFSource(src->GetClient());
1687				clientIDs.erase(it1);
1688			}
1689		}
1690	}
1691
1692	theApp->amuledlg->m_transferwnd->downloadlistctrl->UpdateItem(file);
1693
1694	// If file is shared check if it is already listed in shared files.
1695	// If not, add it and show it.
1696	if (file->IsShared() && !theApp->sharedfiles->count(file->ECID())) {
1697		(*theApp->sharedfiles)[file->ECID()] = file;
1698		theApp->amuledlg->m_sharedfileswnd->sharedfilesctrl->ShowFile(file);
1699	}
1700}
1701
1702
1703void CDownQueueRem::SendFileCommand(CPartFile *file, ec_tagname_t cmd)
1704{
1705	CECPacket req(cmd);
1706	req.AddTag(CECTag(EC_TAG_PARTFILE, file->GetFileHash()));
1707
1708	m_conn->SendPacket(&req);
1709}
1710
1711
1712void CDownQueueRem::Prio(CPartFile *file, uint8 prio)
1713{
1714	CECPacket req(EC_OP_PARTFILE_PRIO_SET);
1715
1716	CECTag hashtag(EC_TAG_PARTFILE, file->GetFileHash());
1717	hashtag.AddTag(CECTag(EC_TAG_PARTFILE_PRIO, prio));
1718	req.AddTag(hashtag);
1719
1720	m_conn->SendPacket(&req);
1721}
1722
1723
1724void CDownQueueRem::AutoPrio(CPartFile *file, bool flag)
1725{
1726	CECPacket req(EC_OP_PARTFILE_PRIO_SET);
1727
1728	CECTag hashtag(EC_TAG_PARTFILE, file->GetFileHash());
1729
1730	hashtag.AddTag(CECTag(EC_TAG_PARTFILE_PRIO,
1731		(uint8)(flag ? PR_AUTO : file->GetDownPriority())));
1732	req.AddTag(hashtag);
1733
1734	m_conn->SendPacket(&req);
1735}
1736
1737
1738void CDownQueueRem::Category(CPartFile *file, uint8 cat)
1739{
1740	CECPacket req(EC_OP_PARTFILE_SET_CAT);
1741	file->SetCategory(cat);
1742
1743	CECTag hashtag(EC_TAG_PARTFILE, file->GetFileHash());
1744	hashtag.AddTag(CECTag(EC_TAG_PARTFILE_CAT, cat));
1745	req.AddTag(hashtag);
1746
1747	m_conn->SendPacket(&req);
1748}
1749
1750
1751void CDownQueueRem::AddSearchToDownload(CSearchFile* file, uint8 category)
1752{
1753	CECPacket req(EC_OP_DOWNLOAD_SEARCH_RESULT);
1754	CECTag hashtag(EC_TAG_PARTFILE, file->GetFileHash());
1755	hashtag.AddTag(CECTag(EC_TAG_PARTFILE_CAT, category));
1756	req.AddTag(hashtag);
1757
1758	m_conn->SendPacket(&req);
1759}
1760
1761
1762void CDownQueueRem::ClearCompleted(const ListOfUInts32 & ecids)
1763{
1764	CECPacket req(EC_OP_CLEAR_COMPLETED);
1765	for (ListOfUInts32::const_iterator it = ecids.begin(); it != ecids.end(); it++) {
1766		req.AddTag(CECTag(EC_TAG_ECID, *it));
1767	}
1768
1769	m_conn->SendPacket(&req);
1770}
1771
1772
1773/*
1774 * List of friends.
1775 */
1776CFriendListRem::CFriendListRem(CRemoteConnect *conn)
1777:
1778CRemoteContainer<CFriend, uint32, CEC_Friend_Tag>(conn, true)
1779{
1780}
1781
1782
1783void CFriendListRem::HandlePacket(const CECPacket *)
1784{
1785	wxFAIL;		// not needed
1786}
1787
1788
1789CFriend * CFriendListRem::CreateItem(CEC_Friend_Tag * tag)
1790{
1791	CFriend * Friend = new CFriend(tag->ID());
1792	ProcessItemUpdate(tag, Friend);
1793	return Friend;
1794}
1795
1796
1797void CFriendListRem::DeleteItem(CFriend * Friend)
1798{
1799	Friend->UnLinkClient(false);
1800	Notify_ChatRemoveFriend(Friend);
1801}
1802
1803
1804uint32 CFriendListRem::GetItemID(CFriend * Friend)
1805{
1806	return Friend->ECID();
1807}
1808
1809
1810void CFriendListRem::ProcessItemUpdate(CEC_Friend_Tag * tag, CFriend * Friend)
1811{
1812	if (!tag->HasChildTags()) {
1813		return;
1814	}
1815	tag->Name(Friend->m_strName);
1816	tag->UserHash(Friend->m_UserHash);
1817	tag->IP(Friend->m_dwLastUsedIP);
1818	tag->Port(Friend->m_nLastUsedPort);
1819	uint32 clientID;
1820	bool notified = false;
1821	if (tag->Client(clientID)) {
1822		if (clientID) {
1823			CClientRef * client = theApp->clientlist->GetByID(clientID);
1824			if (client) {
1825				Friend->LinkClient(*client);	// this notifies
1826				notified = true;
1827			}
1828		} else {
1829			// Unlink
1830			Friend->UnLinkClient(false);
1831		}
1832	}
1833	if (!notified) {
1834		Notify_ChatUpdateFriend(Friend);
1835	}
1836}
1837
1838
1839void CFriendListRem::AddFriend(const CClientRef& toadd)
1840{
1841	CECPacket req(EC_OP_FRIEND);
1842
1843	CECEmptyTag addtag(EC_TAG_FRIEND_ADD);
1844	addtag.AddTag(CECTag(EC_TAG_CLIENT, toadd.ECID()));
1845	req.AddTag(addtag);
1846
1847	m_conn->SendPacket(&req);
1848}
1849
1850
1851void CFriendListRem::AddFriend(const CMD4Hash& userhash, uint32 lastUsedIP, uint32 lastUsedPort, const wxString& name)
1852{
1853	CECPacket req(EC_OP_FRIEND);
1854
1855	CECEmptyTag addtag(EC_TAG_FRIEND_ADD);
1856	addtag.AddTag(CECTag(EC_TAG_FRIEND_HASH, userhash));
1857	addtag.AddTag(CECTag(EC_TAG_FRIEND_IP, lastUsedIP));
1858	addtag.AddTag(CECTag(EC_TAG_FRIEND_PORT, lastUsedPort));
1859	addtag.AddTag(CECTag(EC_TAG_FRIEND_NAME, name));
1860	req.AddTag(addtag);
1861
1862	m_conn->SendPacket(&req);
1863}
1864
1865
1866void CFriendListRem::RemoveFriend(CFriend* toremove)
1867{
1868	CECPacket req(EC_OP_FRIEND);
1869
1870	CECEmptyTag removetag(EC_TAG_FRIEND_REMOVE);
1871	removetag.AddTag(CECTag(EC_TAG_FRIEND, toremove->ECID()));
1872	req.AddTag(removetag);
1873
1874	m_conn->SendPacket(&req);
1875}
1876
1877
1878void CFriendListRem::SetFriendSlot(CFriend* Friend, bool new_state)
1879{
1880	CECPacket req(EC_OP_FRIEND);
1881
1882	CECTag slottag(EC_TAG_FRIEND_FRIENDSLOT, new_state);
1883	slottag.AddTag(CECTag(EC_TAG_FRIEND, Friend->ECID()));
1884	req.AddTag(slottag);
1885
1886	m_conn->SendPacket(&req);
1887}
1888
1889
1890void CFriendListRem::RequestSharedFileList(CFriend* Friend)
1891{
1892	CECPacket req(EC_OP_FRIEND);
1893
1894	CECEmptyTag sharedtag(EC_TAG_FRIEND_SHARED);
1895	sharedtag.AddTag(CECTag(EC_TAG_FRIEND, Friend->ECID()));
1896	req.AddTag(sharedtag);
1897
1898	m_conn->SendPacket(&req);
1899}
1900
1901
1902void CFriendListRem::RequestSharedFileList(CClientRef& client)
1903{
1904	CECPacket req(EC_OP_FRIEND);
1905
1906	CECEmptyTag sharedtag(EC_TAG_FRIEND_SHARED);
1907	sharedtag.AddTag(CECTag(EC_TAG_CLIENT, client.ECID()));
1908	req.AddTag(sharedtag);
1909
1910	m_conn->SendPacket(&req);
1911}
1912
1913
1914
1915/*
1916 * Search results
1917 */
1918CSearchListRem::CSearchListRem(CRemoteConnect *conn) : CRemoteContainer<CSearchFile, uint32, CEC_SearchFile_Tag>(conn, true)
1919{
1920	m_curr_search = -1;
1921}
1922
1923
1924wxString CSearchListRem::StartNewSearch(
1925	uint32* nSearchID, SearchType search_type,
1926	const CSearchList::CSearchParams& params)
1927{
1928	CECPacket search_req(EC_OP_SEARCH_START);
1929	EC_SEARCH_TYPE ec_search_type = EC_SEARCH_LOCAL;
1930	switch(search_type) {
1931		case LocalSearch: ec_search_type = EC_SEARCH_LOCAL; break;
1932		case GlobalSearch: ec_search_type =  EC_SEARCH_GLOBAL; break;
1933		case KadSearch: ec_search_type =  EC_SEARCH_KAD; break;
1934	}
1935	search_req.AddTag(
1936		CEC_Search_Tag(params.searchString, ec_search_type,
1937		params.typeText, params.extension, params.availability,
1938		params.minSize, params.maxSize));
1939
1940	m_conn->SendPacket(&search_req);
1941	m_curr_search = *(nSearchID); // No kad remote search yet.
1942
1943	Flush();
1944
1945	return wxEmptyString; // EC reply will have the error mesg is needed.
1946}
1947
1948
1949void CSearchListRem::StopSearch(bool)
1950{
1951	if (m_curr_search != -1) {
1952		CECPacket search_req(EC_OP_SEARCH_STOP);
1953		m_conn->SendPacket(&search_req);
1954	}
1955}
1956
1957
1958void CSearchListRem::HandlePacket(const CECPacket *packet)
1959{
1960	if ( packet->GetOpCode() == EC_OP_SEARCH_PROGRESS ) {
1961		CoreNotify_Search_Update_Progress(packet->GetFirstTagSafe()->GetInt());
1962	} else {
1963		CRemoteContainer<CSearchFile, uint32, CEC_SearchFile_Tag>::HandlePacket(packet);
1964	}
1965}
1966
1967
1968CSearchFile::CSearchFile(CEC_SearchFile_Tag *tag)
1969:
1970CECID(tag->ID()),
1971m_parent(NULL),
1972m_showChildren(false),
1973m_sourceCount(0),
1974m_completeSourceCount(0),
1975m_kademlia(false),
1976m_downloadStatus(NEW),
1977m_clientID(0),
1978m_clientPort(0),
1979m_kadPublishInfo(0)
1980{
1981	SetFileName(CPath(tag->FileName()));
1982	m_abyFileHash = tag->FileHash();
1983	SetFileSize(tag->SizeFull());
1984
1985	m_searchID = theApp->searchlist->m_curr_search;
1986	uint32 parentID = tag->ParentID();
1987	if (parentID) {
1988		CSearchFile * parent = theApp->searchlist->GetByID(parentID);
1989		if (parent) {
1990			parent->AddChild(this);
1991		}
1992	}
1993}
1994
1995
1996void CSearchFile::AddChild(CSearchFile* file)
1997{
1998	m_children.push_back(file);
1999	file->m_parent = this;
2000}
2001
2002
2003// dtor is virtual - must be implemented
2004CSearchFile::~CSearchFile()
2005{
2006}
2007
2008
2009CSearchFile *CSearchListRem::CreateItem(CEC_SearchFile_Tag *tag)
2010{
2011	CSearchFile *file = new CSearchFile(tag);
2012	ProcessItemUpdate(tag, file);
2013
2014	theApp->amuledlg->m_searchwnd->AddResult(file);
2015
2016	return file;
2017}
2018
2019
2020void CSearchListRem::DeleteItem(CSearchFile *file)
2021{
2022	delete file;
2023}
2024
2025
2026uint32 CSearchListRem::GetItemID(CSearchFile *file)
2027{
2028	return file->ECID();
2029}
2030
2031
2032void CSearchListRem::ProcessItemUpdate(CEC_SearchFile_Tag *tag, CSearchFile *file)
2033{
2034	uint32 sourceCount = file->m_sourceCount;
2035	uint32 completeSourceCount = file->m_completeSourceCount;
2036	CSearchFile::DownloadStatus status = file->m_downloadStatus;
2037	tag->SourceCount(&file->m_sourceCount);
2038	tag->CompleteSourceCount(&file->m_completeSourceCount);
2039	tag->DownloadStatus((uint32 *) &file->m_downloadStatus);
2040
2041	if (file->m_sourceCount != sourceCount
2042			|| file->m_completeSourceCount != completeSourceCount
2043			|| file->m_downloadStatus != status) {
2044		if (theApp->amuledlg && theApp->amuledlg->m_searchwnd) {
2045			theApp->amuledlg->m_searchwnd->UpdateResult(file);
2046		}
2047	}
2048}
2049
2050
2051bool CSearchListRem::Phase1Done(const CECPacket *WXUNUSED(reply))
2052{
2053	CECPacket progress_req(EC_OP_SEARCH_PROGRESS);
2054	m_conn->SendRequest(this, &progress_req);
2055
2056	return true;
2057}
2058
2059
2060void CSearchListRem::RemoveResults(long nSearchID)
2061{
2062	ResultMap::iterator it = m_results.find(nSearchID);
2063	if (it != m_results.end()) {
2064		CSearchResultList& list = it->second;
2065		for (unsigned int i = 0; i < list.size(); ++i) {
2066			delete list[i];
2067		}
2068		m_results.erase(it);
2069	}
2070}
2071
2072
2073const CSearchResultList& CSearchListRem::GetSearchResults(long nSearchID)
2074{
2075	ResultMap::const_iterator it = m_results.find(nSearchID);
2076	if (it != m_results.end()) {
2077		return it->second;
2078	}
2079
2080	// TODO: Should we assert in this case?
2081	static CSearchResultList list;
2082	return list;
2083}
2084
2085
2086void CStatsUpdaterRem::HandlePacket(const CECPacket *packet)
2087{
2088	theStats::UpdateStats(packet);
2089	theApp->amuledlg->ShowTransferRate();
2090	theApp->ShowUserCount(); // maybe there should be a check if a usercount changed ?
2091	// handle the connstate tag which is included in the stats packet
2092	theApp->serverconnect->HandlePacket(packet);
2093}
2094
2095
2096void CUpDownClient::RequestSharedFileList()
2097{
2098	CClientRef ref = CCLIENTREF(this, wxEmptyString);
2099	theApp->friendlist->RequestSharedFileList(ref);
2100}
2101
2102
2103bool CUpDownClient::SwapToAnotherFile(
2104	bool WXUNUSED(bIgnoreNoNeeded),
2105	bool WXUNUSED(ignoreSuspensions),
2106	bool WXUNUSED(bRemoveCompletely),
2107	CPartFile* toFile)
2108{
2109	CECPacket req(EC_OP_CLIENT_SWAP_TO_ANOTHER_FILE);
2110	req.AddTag(CECTag(EC_TAG_CLIENT, ECID()));
2111	req.AddTag(CECTag(EC_TAG_PARTFILE, toFile->GetFileHash()));
2112	theApp->m_connect->SendPacket(&req);
2113
2114	return true;
2115}
2116
2117
2118wxString CAICHHash::GetString() const
2119{
2120	return EncodeBase32(m_abyBuffer, HASHSIZE);
2121}
2122
2123
2124//
2125// Those functions are virtual. So even they don't get called they must
2126// be defined so linker will be happy
2127//
2128CPacket* CKnownFile::CreateSrcInfoPacket(const CUpDownClient *, uint8 /*byRequestedVersion*/, uint16 /*nRequestedOptions*/)
2129{
2130	wxFAIL;
2131	return 0;
2132}
2133
2134
2135bool CKnownFile::LoadFromFile(const class CFileDataIO*)
2136{
2137	wxFAIL;
2138	return false;
2139}
2140
2141
2142void CKnownFile::UpdatePartsInfo()
2143{
2144	wxFAIL;
2145}
2146
2147
2148CPacket* CPartFile::CreateSrcInfoPacket(CUpDownClient const *, uint8 /*byRequestedVersion*/, uint16 /*nRequestedOptions*/)
2149{
2150	wxFAIL;
2151	return 0;
2152}
2153
2154
2155void CPartFile::UpdatePartsInfo()
2156{
2157	wxFAIL;
2158}
2159
2160
2161
2162void CPartFile::UpdateFileRatingCommentAvail()
2163{
2164	bool prevComment = m_hasComment;
2165	int prevRating = m_iUserRating;
2166
2167	m_hasComment = false;
2168	m_iUserRating = 0;
2169	int ratingCount = 0;
2170
2171	FileRatingList::iterator it = m_FileRatingList.begin();
2172	for (; it != m_FileRatingList.end(); ++it) {
2173		SFileRating& cur_rat = *it;
2174
2175		if (!cur_rat.Comment.IsEmpty()) {
2176			m_hasComment = true;
2177		}
2178
2179		uint8 rating = cur_rat.Rating;
2180		if (rating) {
2181			wxASSERT(rating <= 5);
2182
2183			ratingCount++;
2184			m_iUserRating += rating;
2185		}
2186	}
2187
2188	if (ratingCount) {
2189		m_iUserRating /= ratingCount;
2190		wxASSERT(m_iUserRating > 0 && m_iUserRating <= 5);
2191	}
2192
2193	if ((prevComment != m_hasComment) || (prevRating != m_iUserRating)) {
2194		UpdateDisplayedInfo();
2195	}
2196}
2197
2198
2199void CStatTreeRem::DoRequery()
2200{
2201	CECPacket request(EC_OP_GET_STATSTREE);
2202	if (thePrefs::GetMaxClientVersions() != 0) {
2203		request.AddTag(CECTag(EC_TAG_STATTREE_CAPPING, (uint8)thePrefs::GetMaxClientVersions()));
2204	}
2205	m_conn->SendRequest(this, &request);
2206}
2207
2208void CStatTreeRem::HandlePacket(const CECPacket * p)
2209{
2210	const CECTag* treeRoot = p->GetTagByName(EC_TAG_STATTREE_NODE);
2211	if (treeRoot) {
2212		theApp->amuledlg->m_statisticswnd->RebuildStatTreeRemote(treeRoot);
2213		theApp->amuledlg->m_statisticswnd->ShowStatistics();
2214	}
2215}
2216
2217CamuleRemoteGuiApp *theApp;
2218
2219//
2220// since gui is not linked with amule.cpp - define events here
2221//
2222DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_FINISHED_HTTP_DOWNLOAD)
2223DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_SOURCE_DNS_DONE)
2224DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_UDP_DNS_DONE)
2225DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_SERVER_DNS_DONE)
2226// File_checked_for_headers
2227