2 // This file is part of the aMule Project.
4 // Copyright (c) 2005-2008 aMule Team ( admin@amule.org / http://www.amule.org )
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
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.
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.
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
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
32 #include <common/Format.h>
33 #include <common/StringFunctions.h>
34 #include <common/MD5Sum.h>
37 #include <include/common/EventIDs.h>
40 #include "amule.h" // Interface declarations.
41 #include "amuleDlg.h" // Needed for CamuleDlg
42 #include "ClientCredits.h"
43 #include "SourceListCtrl.h"
45 #include "DataToText.h" // Needed for GetSoftName()
46 #include "DownloadListCtrl.h" // Needed for CDownloadListCtrl
48 #include "GetTickCount.h" // Needed for GetTickCount
49 #include "GuiEvents.h"
50 #ifdef ENABLE_IP2COUNTRY
51 #include "IP2Country.h" // Needed for IP2Country
53 #include "InternalEvents.h" // Needed for wxEVT_CORE_FINISHED_HTTP_DOWNLOAD
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
69 CEConnectDlg::CEConnectDlg()
71 wxDialog(theApp
->amuledlg
, -1, _("Connect to remote amule"), wxDefaultPosition
)
73 CoreConnect(this, true);
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
);
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
);
88 wxString
CEConnectDlg::PassHash()
94 BEGIN_EVENT_TABLE(CEConnectDlg
, wxDialog
)
95 EVT_BUTTON(wxID_OK
, CEConnectDlg::OnOK
)
99 void CEConnectDlg::OnOK(wxCommandEvent
& evt
)
101 wxString s_port
= CastChild(ID_REMOTE_PORT
, wxTextCtrl
)->GetValue();
102 port
= StrToLong(s_port
);
104 host
= CastChild(ID_REMOTE_HOST
, wxTextCtrl
)->GetValue();
105 passwd
= CastChild(ID_EC_PASSWD
, wxTextCtrl
)->GetValue();
107 if (passwd
!= pwd_hash
) {
108 pwd_hash
= MD5Sum(passwd
).GetHash();
110 m_save_user_pass
= CastChild(ID_EC_SAVE
, wxCheckBox
)->IsChecked();
115 DEFINE_LOCAL_EVENT_TYPE(wxEVT_EC_INIT_DONE
)
118 BEGIN_EVENT_TABLE(CamuleRemoteGuiApp
, wxApp
)
120 EVT_TIMER(ID_CORE_TIMER_EVENT
, CamuleRemoteGuiApp::OnPollTimer
)
122 EVT_CUSTOM(wxEVT_EC_CONNECTION
, -1, CamuleRemoteGuiApp::OnECConnection
)
123 EVT_CUSTOM(wxEVT_EC_INIT_DONE
, -1, CamuleRemoteGuiApp::OnECInitDone
)
125 EVT_MULE_NOTIFY(CamuleRemoteGuiApp::OnNotifyEvent
)
127 #ifdef ENABLE_IP2COUNTRY
128 // HTTPDownload finished
129 EVT_MULE_INTERNAL(wxEVT_CORE_FINISHED_HTTP_DOWNLOAD
, -1, CamuleRemoteGuiApp::OnFinishedHTTPDownload
)
134 IMPLEMENT_APP(CamuleRemoteGuiApp
)
137 int CamuleRemoteGuiApp::OnExit()
141 return wxApp::OnExit();
145 void CamuleRemoteGuiApp::OnPollTimer(wxTimerEvent
&)
147 static int request_step
= 0;
148 static uint32 msPrevStats
= 0;
150 if (m_connect
->RequestFifoFull()) {
154 switch (request_step
) {
156 serverconnect
->ReQuery();
160 CECPacket
stats_req(EC_OP_STAT_REQ
);
161 m_connect
->SendRequest(&m_stats_updater
, &stats_req
);
162 amuledlg
->ShowTransferRate();
167 if (amuledlg
->m_sharedfileswnd
->IsShown()
168 || amuledlg
->m_chatwnd
->IsShown()
169 || amuledlg
->m_serverwnd
->IsShown()) {
170 // update downloads, shared files and servers
171 knownfiles
->DoRequery(EC_OP_GET_UPDATE
, EC_TAG_KNOWNFILE
);
172 } else if (amuledlg
->m_transferwnd
->IsShown()) {
173 // update both downloads and shared files
174 knownfiles
->DoRequery(EC_OP_GET_UPDATE
, EC_TAG_KNOWNFILE
);
175 } else if (amuledlg
->m_searchwnd
->IsShown()) {
176 if (searchlist
->m_curr_search
!= -1) {
177 searchlist
->DoRequery(EC_OP_SEARCH_RESULTS
, EC_TAG_SEARCHFILE
);
179 } else if (amuledlg
->m_statisticswnd
->IsShown()) {
180 int sStatsUpdate
= thePrefs::GetStatsInterval();
181 uint32 msCur
= theStats::GetUptimeMillis();
182 if ((sStatsUpdate
> 0) && ((int)(msCur
- msPrevStats
) > sStatsUpdate
*1000)) {
184 stattree
->DoRequery();
195 // Check for new links once per second.
196 static uint32 lastED2KLinkCheck
= 0;
197 if (GetTickCount() - lastED2KLinkCheck
>= 1000) {
199 lastED2KLinkCheck
= GetTickCount();
204 void CamuleRemoteGuiApp::OnFinishedHTTPDownload(CMuleInternalEvent
& event
)
206 if (event
.GetInt() == HTTP_GeoIP
) {
207 amuledlg
->IP2CountryDownloadFinished(event
.GetExtraLong());
208 // If we updated, the dialog is already up. Redraw it to show the flags.
214 void CamuleRemoteGuiApp::ShutDown(wxCloseEvent
&WXUNUSED(evt
))
216 // Stop the Core Timer
220 // Destroy the EC socket
221 m_connect
->Destroy();
226 amuledlg
->DlgShutDown();
230 delete m_allUploadingKnownFile
;
235 bool CamuleRemoteGuiApp::OnInit()
241 theApp
= &wxGetApp();
243 // Handle uncaught exceptions
244 InstallMuleExceptionHandler();
246 // Parse cmdline arguments.
247 if (!InitCommon(AMULE_APP_BASE::argc
, AMULE_APP_BASE::argv
)) {
251 // Create the polling timer
252 poll_timer
= new wxTimer(this,ID_CORE_TIMER_EVENT
);
254 AddLogLineCS(_("Fatal Error: Failed to create Poll Timer"));
258 m_connect
= new CRemoteConnect(this);
260 glob_prefs
= new CPreferencesRem(m_connect
);
262 wxConfig::Get()->Read(wxT("/EC/ZLIB"), &enableZLIB
, 1);
263 m_connect
->SetCapabilities(enableZLIB
!= 0, true, false); // ZLIB, UTF8 numbers, notification
265 InitCustomLanguages();
266 InitLocale(m_locale
, StrLang2wx(thePrefs::GetLanguageID()));
268 if (ShowConnectionDialog()) {
269 AddLogLineNS(_("Going to event loop..."));
277 bool CamuleRemoteGuiApp::CryptoAvailable() const
279 return thePrefs::IsSecureIdentEnabled(); // good enough
283 bool CamuleRemoteGuiApp::ShowConnectionDialog()
285 dialog
= new CEConnectDlg
;
287 if (m_skipConnectionDialog
) {
290 } else if (dialog
->ShowModal() != wxID_OK
) {
295 AddLogLineNS(_("Connecting..."));
296 if (!m_connect
->ConnectToCore(dialog
->Host(), dialog
->Port(),
297 dialog
->Login(), dialog
->PassHash(),
298 wxT("amule-remote"), wxT("0x0001"))) {
299 wxMessageBox(_("Connection failed "),_("ERROR"),wxOK
);
308 void CamuleRemoteGuiApp::OnECConnection(wxEvent
& event
) {
309 wxECSocketEvent
& evt
= *((wxECSocketEvent
*)&event
);
310 AddLogLineNS(_("Remote GUI EC event handler"));
311 wxString reply
= evt
.GetServerReply();
313 if (evt
.GetResult() == true) {
314 // Connected - go to next init step
315 glob_prefs
->LoadRemote();
317 AddLogLineNS(_("Going down"));
318 if (dialog
) { // connect failed
320 (CFormat(_("Connection Failed. Unable to connect to %s:%d\n")) % dialog
->Host() % dialog
->Port()) + reply
,
322 } else { // server disconnected (probably terminated) later
323 wxMessageBox(_("Connection closed - aMule has terminated probably."), _("ERROR"), wxOK
);
330 void CamuleRemoteGuiApp::OnECInitDone(wxEvent
& )
336 void CamuleRemoteGuiApp::OnNotifyEvent(CMuleGUIEvent
& evt
)
342 void CamuleRemoteGuiApp::Startup() {
344 if (dialog
->SaveUserPass()) {
345 wxConfig::Get()->Write(wxT("/EC/Host"), dialog
->Host());
346 wxConfig::Get()->Write(wxT("/EC/Port"), dialog
->Port());
347 wxConfig::Get()->Write(wxT("/EC/Password"), dialog
->PassHash());
355 serverconnect
= new CServerConnectRem(m_connect
);
356 m_statistics
= new CStatistics(*m_connect
);
357 stattree
= new CStatTreeRem(m_connect
);
359 clientlist
= new CUpDownClientListRem(m_connect
);
360 searchlist
= new CSearchListRem(m_connect
);
361 serverlist
= new CServerListRem(m_connect
);
362 friendlist
= new CFriendListRem(m_connect
);
365 sharedfiles
= new CSharedFilesRem(m_connect
);
366 knownfiles
= new CKnownFilesRem(m_connect
);
368 downloadqueue
= new CDownQueueRem(m_connect
);
369 ipfilter
= new CIPFilterRem(m_connect
);
371 m_allUploadingKnownFile
= new CKnownFile
;
373 // Create main dialog
374 InitGui(m_geometryEnabled
, m_geometryString
);
376 // Forward wxLog events to CLogger
377 wxLog::SetActiveTarget(new CLoggerTarget
);
378 knownfiles
->DoRequery(EC_OP_GET_UPDATE
, EC_TAG_KNOWNFILE
);
380 // Start the Poll Timer
381 poll_timer
->Start(1000);
382 amuledlg
->StartGuiTimer();
384 // Now activate GeoIP, so that the download dialog doesn't get destroyed immediately
385 #ifdef ENABLE_IP2COUNTRY
386 if (thePrefs::IsGeoIPEnabled()) {
387 amuledlg
->m_IP2Country
->Enable();
393 int CamuleRemoteGuiApp::ShowAlert(wxString msg
, wxString title
, int flags
)
395 return CamuleGuiBase::ShowAlert(msg
, title
, flags
);
399 void CamuleRemoteGuiApp::AddRemoteLogLine(const wxString
& line
)
401 amuledlg
->AddLogLine(line
);
404 int CamuleRemoteGuiApp::InitGui(bool geometry_enabled
, wxString
&geom_string
)
406 CamuleGuiBase::InitGui(geometry_enabled
, geom_string
);
407 SetTopWindow(amuledlg
);
408 AddLogLineN(_("Ready")); // The first log line after the window is up triggers output of all the ones before
413 bool CamuleRemoteGuiApp::CopyTextToClipboard(wxString strText
)
415 return CamuleGuiBase::CopyTextToClipboard(strText
);
419 uint32
CamuleRemoteGuiApp::GetPublicIP()
425 wxString
CamuleRemoteGuiApp::GetLog(bool reset
)
428 amuledlg
->ResetLog(ID_LOGVIEW
);
429 CECPacket
req(EC_OP_RESET_LOG
);
430 m_connect
->SendPacket(&req
);
432 return wxEmptyString
;
436 wxString
CamuleRemoteGuiApp::GetServerLog(bool)
438 return wxEmptyString
;
442 bool CamuleRemoteGuiApp::AddServer(CServer
* server
, bool)
444 CECPacket
req(EC_OP_SERVER_ADD
);
445 req
.AddTag(CECTag(EC_TAG_SERVER_ADDRESS
, CFormat(wxT("%s:%d")) % server
->GetAddress() % server
->GetPort()));
446 req
.AddTag(CECTag(EC_TAG_SERVER_NAME
, server
->GetListName()));
447 m_connect
->SendPacket(&req
);
453 bool CamuleRemoteGuiApp::IsFirewalled() const
455 if (IsConnectedED2K() && !serverconnect
->IsLowID()) {
459 return IsFirewalledKad();
463 bool CamuleRemoteGuiApp::IsConnectedED2K() const {
464 return serverconnect
&& serverconnect
->IsConnected();
468 void CamuleRemoteGuiApp::StartKad() {
469 m_connect
->StartKad();
473 void CamuleRemoteGuiApp::StopKad() {
474 m_connect
->StopKad();
478 void CamuleRemoteGuiApp::BootstrapKad(uint32 ip
, uint16 port
)
480 CECPacket
req(EC_OP_KAD_BOOTSTRAP_FROM_IP
);
481 req
.AddTag(CECTag(EC_TAG_BOOTSTRAP_IP
, ip
));
482 req
.AddTag(CECTag(EC_TAG_BOOTSTRAP_PORT
, port
));
484 m_connect
->SendPacket(&req
);
488 void CamuleRemoteGuiApp::UpdateNotesDat(const wxString
& url
)
490 CECPacket
req(EC_OP_KAD_UPDATE_FROM_URL
);
491 req
.AddTag(CECTag(EC_TAG_KADEMLIA_UPDATE_URL
, url
));
493 m_connect
->SendPacket(&req
);
497 void CamuleRemoteGuiApp::DisconnectED2K() {
498 if (IsConnectedED2K()) {
499 m_connect
->DisconnectED2K();
504 uint32
CamuleRemoteGuiApp::GetED2KID() const
506 return serverconnect
? serverconnect
->GetClientID() : 0;
510 uint32
CamuleRemoteGuiApp::GetID() const
516 void CamuleRemoteGuiApp::ShowUserCount() {
519 static const wxString s_singlenetstatusformat
= _("Users: %s | Files: %s");
520 static const wxString s_bothnetstatusformat
= _("Users: E: %s K: %s | Files: E: %s K: %s");
522 if (thePrefs::GetNetworkED2K() && thePrefs::GetNetworkKademlia()) {
523 buffer
= CFormat(s_bothnetstatusformat
) % CastItoIShort(theStats::GetED2KUsers()) % CastItoIShort(theStats::GetKadUsers()) % CastItoIShort(theStats::GetED2KFiles()) % CastItoIShort(theStats::GetKadFiles());
524 } else if (thePrefs::GetNetworkED2K()) {
525 buffer
= CFormat(s_singlenetstatusformat
) % CastItoIShort(theStats::GetED2KUsers()) % CastItoIShort(theStats::GetED2KFiles());
526 } else if (thePrefs::GetNetworkKademlia()) {
527 buffer
= CFormat(s_singlenetstatusformat
) % CastItoIShort(theStats::GetKadUsers()) % CastItoIShort(theStats::GetKadFiles());
529 buffer
= _("No networks selected");
532 Notify_ShowUserCount(buffer
);
537 * Preferences: holds both local and remote settings.
539 * First, everything is loaded from local config file. Later, settings
540 * that are relevant on remote side only are loaded thru EC
542 CPreferencesRem::CPreferencesRem(CRemoteConnect
*conn
)
547 // Settings queried from remote side
549 m_exchange_send_selected_prefs
=
551 EC_PREFS_CONNECTIONS
|
552 EC_PREFS_MESSAGEFILTER
|
557 EC_PREFS_DIRECTORIES
|
559 EC_PREFS_CORETWEAKS
|
560 EC_PREFS_REMOTECONTROLS
|
562 m_exchange_recv_selected_prefs
=
563 m_exchange_send_selected_prefs
|
568 void CPreferencesRem::HandlePacket(const CECPacket
*packet
)
570 ((CEC_Prefs_Packet
*)packet
)->Apply();
572 const CECTag
*cat_tags
= packet
->GetTagByName(EC_TAG_PREFS_CATEGORIES
);
574 for (CECTag::const_iterator it
= cat_tags
->begin(); it
!= cat_tags
->end(); it
++) {
575 const CECTag
&cat_tag
= *it
;
576 Category_Struct
*cat
= new Category_Struct
;
577 cat
->title
= cat_tag
.GetTagByName(EC_TAG_CATEGORY_TITLE
)->GetStringData();
578 cat
->path
= CPath(cat_tag
.GetTagByName(EC_TAG_CATEGORY_PATH
)->GetStringData());
579 cat
->comment
= cat_tag
.GetTagByName(EC_TAG_CATEGORY_COMMENT
)->GetStringData();
580 cat
->color
= cat_tag
.GetTagByName(EC_TAG_CATEGORY_COLOR
)->GetInt();
581 cat
->prio
= cat_tag
.GetTagByName(EC_TAG_CATEGORY_PRIO
)->GetInt();
582 theApp
->glob_prefs
->AddCat(cat
);
585 Category_Struct
*cat
= new Category_Struct
;
586 cat
->title
= _("All");
588 cat
->prio
= PR_NORMAL
;
589 theApp
->glob_prefs
->AddCat(cat
);
591 wxECInitDoneEvent event
;
592 theApp
->AddPendingEvent(event
);
597 bool CPreferencesRem::LoadRemote()
600 // override local settings with remote
601 CECPacket
req(EC_OP_GET_PREFERENCES
, EC_DETAIL_UPDATE
);
603 // bring categories too
604 req
.AddTag(CECTag(EC_TAG_SELECT_PREFS
, m_exchange_recv_selected_prefs
));
606 m_conn
->SendRequest(this, &req
);
612 void CPreferencesRem::SendToRemote()
614 CEC_Prefs_Packet
pref_packet(m_exchange_send_selected_prefs
, EC_DETAIL_UPDATE
, EC_DETAIL_FULL
);
615 m_conn
->SendPacket(&pref_packet
);
619 class CCatHandler
: public CECPacketHandlerBase
{
620 virtual void HandlePacket(const CECPacket
*packet
);
624 void CCatHandler::HandlePacket(const CECPacket
*packet
)
626 if (packet
->GetOpCode() == EC_OP_FAILED
) {
627 const CECTag
* catTag
= packet
->GetTagByName(EC_TAG_CATEGORY
);
628 const CECTag
* pathTag
= packet
->GetTagByName(EC_TAG_CATEGORY_PATH
);
629 if (catTag
&& pathTag
&& catTag
->GetInt() < theApp
->glob_prefs
->GetCatCount()) {
630 int cat
= catTag
->GetInt();
631 Category_Struct
* cs
= theApp
->glob_prefs
->GetCategory(cat
);
632 wxMessageBox(CFormat(_("Can't create directory '%s' for category '%s', keeping directory '%s'."))
633 % cs
->path
.GetPrintable() % cs
->title
% pathTag
->GetStringData(),
635 cs
->path
= CPath(pathTag
->GetStringData());
636 theApp
->amuledlg
->m_transferwnd
->UpdateCategory(cat
);
637 theApp
->amuledlg
->m_transferwnd
->downloadlistctrl
->Refresh();
644 bool CPreferencesRem::CreateCategory(
645 Category_Struct
*& category
,
646 const wxString
& name
,
648 const wxString
& comment
,
652 CECPacket
req(EC_OP_CREATE_CATEGORY
);
653 CEC_Category_Tag
tag(0xffffffff, name
, path
.GetRaw(), comment
, color
, prio
);
655 m_conn
->SendRequest(new CCatHandler
, &req
);
657 category
= new Category_Struct();
658 category
->path
= path
;
659 category
->title
= name
;
660 category
->comment
= comment
;
661 category
->color
= color
;
662 category
->prio
= prio
;
670 bool CPreferencesRem::UpdateCategory(
672 const wxString
& name
,
674 const wxString
& comment
,
678 CECPacket
req(EC_OP_UPDATE_CATEGORY
);
679 CEC_Category_Tag
tag(cat
, name
, path
.GetRaw(), comment
, color
, prio
);
681 m_conn
->SendRequest(new CCatHandler
, &req
);
683 Category_Struct
*category
= m_CatList
[cat
];
684 category
->path
= path
;
685 category
->title
= name
;
686 category
->comment
= comment
;
687 category
->color
= color
;
688 category
->prio
= prio
;
694 void CPreferencesRem::RemoveCat(uint8 cat
)
696 CECPacket
req(EC_OP_DELETE_CATEGORY
);
697 CEC_Category_Tag
tag(cat
, EC_DETAIL_CMD
);
699 m_conn
->SendPacket(&req
);
700 CPreferences::RemoveCat(cat
);
705 // Container implementation
707 CServerConnectRem::CServerConnectRem(CRemoteConnect
*conn
)
714 void CServerConnectRem::ConnectToAnyServer()
716 CECPacket
req(EC_OP_SERVER_CONNECT
);
717 m_Conn
->SendPacket(&req
);
721 void CServerConnectRem::StopConnectionTry()
723 // lfroen: isn't Disconnect the same ?
727 void CServerConnectRem::Disconnect()
729 CECPacket
req(EC_OP_SERVER_DISCONNECT
);
730 m_Conn
->SendPacket(&req
);
734 void CServerConnectRem::ConnectToServer(CServer
*server
)
736 m_Conn
->ConnectED2K(server
->GetIP(), server
->GetPort());
740 bool CServerConnectRem::ReQuery()
742 CECPacket
stat_req(EC_OP_GET_CONNSTATE
);
743 m_Conn
->SendRequest(this, &stat_req
);
749 void CServerConnectRem::HandlePacket(const CECPacket
*packet
)
751 CEC_ConnState_Tag
*tag
=
752 (CEC_ConnState_Tag
*)packet
->GetTagByName(EC_TAG_CONNSTATE
);
757 theApp
->m_ConnState
= 0;
759 m_ID
= tag
->GetEd2kId();
760 theApp
->m_clientID
= tag
->GetClientId();
762 if (tag
->IsConnectedED2K()) {
763 CECTag
*srvtag
= tag
->GetTagByName(EC_TAG_SERVER
);
765 server
= theApp
->serverlist
->GetByID(srvtag
->GetInt());
766 if (server
!= m_CurrServer
) {
767 theApp
->amuledlg
->m_serverwnd
->serverlistctrl
->HighlightServer(server
, true);
768 m_CurrServer
= server
;
771 theApp
->m_ConnState
|= CONNECTED_ED2K
;
772 } else if ( m_CurrServer
) {
773 theApp
->amuledlg
->m_serverwnd
->serverlistctrl
->HighlightServer(m_CurrServer
, false);
777 if (tag
->IsConnectedKademlia()) {
778 if (tag
->IsKadFirewalled()) {
779 theApp
->m_ConnState
|= CONNECTED_KAD_FIREWALLED
;
781 theApp
->m_ConnState
|= CONNECTED_KAD_OK
;
784 if (tag
->IsKadRunning()) {
785 theApp
->m_ConnState
|= CONNECTED_KAD_NOT
;
789 theApp
->amuledlg
->ShowConnectionState();
794 * Server list: host list of ed2k servers.
796 CServerListRem::CServerListRem(CRemoteConnect
*conn
)
798 CRemoteContainer
<CServer
, uint32
, CEC_Server_Tag
>(conn
, true)
803 void CServerListRem::HandlePacket(const CECPacket
*)
805 // There is no packet for the server list, it is part of the general update packet
807 // CRemoteContainer<CServer, uint32, CEC_Server_Tag>::HandlePacket(packet);
811 void CServerListRem::UpdateServerMetFromURL(wxString url
)
813 CECPacket
req(EC_OP_SERVER_UPDATE_FROM_URL
);
814 req
.AddTag(CECTag(EC_TAG_SERVERS_UPDATE_URL
, url
));
816 m_conn
->SendPacket(&req
);
820 void CServerListRem::SetStaticServer(CServer
* server
, bool isStatic
)
822 // update display right away
823 server
->SetIsStaticMember(isStatic
);
824 Notify_ServerRefresh(server
);
826 CECPacket
req(EC_OP_SERVER_SET_STATIC_PRIO
);
827 req
.AddTag(CECTag(EC_TAG_SERVER
, server
->ECID()));
828 req
.AddTag(CECTag(EC_TAG_SERVER_STATIC
, isStatic
));
830 m_conn
->SendPacket(&req
);
834 void CServerListRem::SetServerPrio(CServer
* server
, uint32 prio
)
836 // update display right away
837 server
->SetPreference(prio
);
838 Notify_ServerRefresh(server
);
840 CECPacket
req(EC_OP_SERVER_SET_STATIC_PRIO
);
841 req
.AddTag(CECTag(EC_TAG_SERVER
, server
->ECID()));
842 req
.AddTag(CECTag(EC_TAG_SERVER_PRIO
, prio
));
844 m_conn
->SendPacket(&req
);
848 void CServerListRem::RemoveServer(CServer
* server
)
850 m_conn
->RemoveServer(server
->GetIP(),server
->GetPort());
854 void CServerListRem::UpdateUserFileStatus(CServer
*server
)
857 m_TotalUser
= server
->GetUsers();
858 m_TotalFile
= server
->GetFiles();
863 CServer
*CServerListRem::GetServerByAddress(const wxString
& WXUNUSED(address
), uint16
WXUNUSED(port
)) const
865 // It's ok to return 0 for context where this code is used in remote gui
869 CServer
*CServerListRem::GetServerByIPTCP(uint32
WXUNUSED(nIP
), uint16
WXUNUSED(nPort
)) const
871 // It's ok to return 0 for context where this code is used in remote gui
875 CServer
*CServerListRem::CreateItem(CEC_Server_Tag
*tag
)
877 CServer
* server
= new CServer(tag
);
878 ProcessItemUpdate(tag
, server
);
883 void CServerListRem::DeleteItem(CServer
*in_srv
)
885 CScopedPtr
<CServer
> srv(in_srv
);
886 theApp
->amuledlg
->m_serverwnd
->serverlistctrl
->RemoveServer(srv
.get());
890 uint32
CServerListRem::GetItemID(CServer
*server
)
892 return server
->ECID();
896 void CServerListRem::ProcessItemUpdate(CEC_Server_Tag
* tag
, CServer
* server
)
898 if (!tag
->HasChildTags()) {
901 tag
->ServerName(& server
->listname
);
902 tag
->ServerDesc(& server
->description
);
903 tag
->ServerVersion(& server
->m_strVersion
);
904 tag
->GetMaxUsers(& server
->maxusers
);
906 tag
->GetFiles(& server
->files
);
907 tag
->GetUsers(& server
->users
);
909 tag
->GetPrio(& server
->preferences
); // SRV_PR_NORMAL = 0, so it's ok
910 tag
->GetStatic(& server
->staticservermember
);
912 tag
->GetPing(& server
->ping
);
913 tag
->GetFailed(& server
->failedcount
);
915 theApp
->amuledlg
->m_serverwnd
->serverlistctrl
->RefreshServer(server
);
919 CServer::CServer(CEC_Server_Tag
*tag
) : CECID(tag
->GetInt())
921 ip
= tag
->GetTagByNameSafe(EC_TAG_SERVER_IP
)->GetInt();
922 port
= tag
->GetTagByNameSafe(EC_TAG_SERVER_PORT
)->GetInt();
931 CIPFilterRem::CIPFilterRem(CRemoteConnect
* conn
)
937 void CIPFilterRem::Reload()
939 CECPacket
req(EC_OP_IPFILTER_RELOAD
);
940 m_conn
->SendPacket(&req
);
944 void CIPFilterRem::Update(wxString url
)
946 CECPacket
req(EC_OP_IPFILTER_UPDATE
);
947 req
.AddTag(CECTag(EC_TAG_STRING
, url
));
949 m_conn
->SendPacket(&req
);
956 CSharedFilesRem::CSharedFilesRem(CRemoteConnect
*conn
)
962 void CSharedFilesRem::Reload(bool, bool)
964 CECPacket
req(EC_OP_SHAREDFILES_RELOAD
);
966 m_conn
->SendPacket(&req
);
970 void CSharedFilesRem::AddFilesFromDirectory(const CPath
& path
)
972 CECPacket
req(EC_OP_SHAREDFILES_ADD_DIRECTORY
);
974 req
.AddTag(CECTag(EC_TAG_PREFS_DIRECTORIES
, path
.GetRaw()));
976 m_conn
->SendPacket(&req
);
980 bool CSharedFilesRem::RenameFile(CKnownFile
* file
, const CPath
& newName
)
982 // We use the printable name, as the filename originated from user input,
983 // and the filesystem name might not be valid on the remote host.
984 const wxString strNewName
= newName
.GetPrintable();
986 CECPacket
request(EC_OP_RENAME_FILE
);
987 request
.AddTag(CECTag(EC_TAG_KNOWNFILE
, file
->GetFileHash()));
988 request
.AddTag(CECTag(EC_TAG_PARTFILE_NAME
, strNewName
));
990 m_conn
->SendPacket(&request
);
996 void CSharedFilesRem::SetFileCommentRating(CKnownFile
* file
, const wxString
& newComment
, int8 newRating
)
998 CECPacket
request(EC_OP_SHARED_FILE_SET_COMMENT
);
999 request
.AddTag(CECTag(EC_TAG_KNOWNFILE
, file
->GetFileHash()));
1000 request
.AddTag(CECTag(EC_TAG_KNOWNFILE_COMMENT
, newComment
));
1001 request
.AddTag(CECTag(EC_TAG_KNOWNFILE_RATING
, newRating
));
1003 m_conn
->SendPacket(&request
);
1007 void CKnownFilesRem::DeleteItem(CKnownFile
* file
)
1009 uint32 id
= file
->ECID();
1010 if (theApp
->sharedfiles
->count(id
)) {
1011 theApp
->amuledlg
->m_sharedfileswnd
->sharedfilesctrl
->RemoveFile(file
);
1012 theApp
->sharedfiles
->erase(id
);
1014 if (theApp
->downloadqueue
->count(id
)) {
1015 theApp
->amuledlg
->m_transferwnd
->downloadlistctrl
->RemoveFile((CPartFile
*) file
);
1016 theApp
->downloadqueue
->erase(id
);
1022 uint32
CKnownFilesRem::GetItemID(CKnownFile
*file
)
1024 return file
->ECID();
1028 void CKnownFilesRem::ProcessItemUpdate(CEC_SharedFile_Tag
*tag
, CKnownFile
*file
)
1030 CECTag
*parttag
= tag
->GetTagByName(EC_TAG_PARTFILE_PART_STATUS
);
1032 const uint8
*data
= file
->m_partStatus
.Decode(
1033 (uint8
*)parttag
->GetTagData(),
1034 parttag
->GetTagDataLen());
1035 for(int i
= 0; i
< file
->GetPartCount(); ++i
) {
1036 file
->m_AvailPartFrequency
[i
] = data
[i
];
1040 if (tag
->FileName(fileName
)) {
1041 file
->SetFileName(CPath(fileName
));
1043 if (tag
->FilePath(fileName
)) {
1044 file
->m_filePath
= CPath(fileName
);
1046 tag
->UpPrio(&file
->m_iUpPriorityEC
);
1047 tag
->GetAICHHash(file
->m_AICHMasterHash
);
1048 tag
->GetRequests(&file
->statistic
.requested
);
1049 tag
->GetAllRequests(&file
->statistic
.alltimerequested
);
1050 tag
->GetAccepts(&file
->statistic
.accepted
);
1051 tag
->GetAllAccepts(&file
->statistic
.alltimeaccepted
);
1052 tag
->GetXferred(&file
->statistic
.transferred
);
1053 tag
->GetAllXferred(&file
->statistic
.alltimetransferred
);
1054 tag
->UpPrio(&file
->m_iUpPriorityEC
);
1055 if (file
->m_iUpPriorityEC
>= 10) {
1056 file
->m_iUpPriority
= file
->m_iUpPriorityEC
- 10;
1057 file
->m_bAutoUpPriority
= true;
1059 file
->m_iUpPriority
= file
->m_iUpPriorityEC
;
1060 file
->m_bAutoUpPriority
= false;
1062 tag
->GetCompleteSourcesLow(&file
->m_nCompleteSourcesCountLo
);
1063 tag
->GetCompleteSourcesHigh(&file
->m_nCompleteSourcesCountHi
);
1064 tag
->GetCompleteSources(&file
->m_nCompleteSourcesCount
);
1066 tag
->GetOnQueue(&file
->m_queuedCount
);
1068 tag
->GetComment(file
->m_strComment
);
1069 tag
->GetRating(file
->m_iRating
);
1071 requested
+= file
->statistic
.requested
;
1072 transferred
+= file
->statistic
.transferred
;
1073 accepted
+= file
->statistic
.transferred
;
1075 theApp
->amuledlg
->m_sharedfileswnd
->sharedfilesctrl
->UpdateItem(file
);
1077 if (file
->IsPartFile()) {
1078 ProcessItemUpdatePartfile((CEC_PartFile_Tag
*) tag
, (CPartFile
*) file
);
1082 void CSharedFilesRem::SetFilePrio(CKnownFile
*file
, uint8 prio
)
1084 CECPacket
req(EC_OP_SHARED_SET_PRIO
);
1086 CECTag
hashtag(EC_TAG_PARTFILE
, file
->GetFileHash());
1087 hashtag
.AddTag(CECTag(EC_TAG_PARTFILE_PRIO
, prio
));
1089 req
.AddTag(hashtag
);
1091 m_conn
->SendPacket(&req
);
1094 void CKnownFilesRem::ProcessUpdate(const CECTag
*reply
, CECPacket
*, int)
1100 std::set
<uint32
> core_files
;
1101 for (CECPacket::const_iterator it
= reply
->begin(); it
!= reply
->end(); it
++) {
1102 const CECTag
* curTag
= &*it
;
1103 ec_tagname_t tagname
= curTag
->GetTagName();
1104 if (tagname
== EC_TAG_CLIENT
) {
1105 theApp
->clientlist
->ProcessUpdate(curTag
, NULL
, EC_TAG_CLIENT
);
1106 } else if (tagname
== EC_TAG_SERVER
) {
1107 theApp
->serverlist
->ProcessUpdate(curTag
, NULL
, EC_TAG_SERVER
);
1108 } else if (tagname
== EC_TAG_FRIEND
) {
1109 theApp
->friendlist
->ProcessUpdate(curTag
, NULL
, EC_TAG_FRIEND
);
1110 } else if (tagname
== EC_TAG_KNOWNFILE
|| tagname
== EC_TAG_PARTFILE
) {
1111 CEC_SharedFile_Tag
*tag
= (CEC_SharedFile_Tag
*) curTag
;
1112 uint32 id
= tag
->ID();
1113 core_files
.insert(id
);
1114 if ( m_items_hash
.count(id
) ) {
1115 // Item already known: update it
1116 ProcessItemUpdate(tag
, m_items_hash
[id
]);
1118 CKnownFile
* newFile
;
1119 if (tag
->GetTagName() == EC_TAG_PARTFILE
) {
1120 CPartFile
*file
= new CPartFile((CEC_PartFile_Tag
*) tag
);
1121 ProcessItemUpdate(tag
, file
);
1122 (*theApp
->downloadqueue
)[id
] = file
;
1123 theApp
->amuledlg
->m_transferwnd
->downloadlistctrl
->AddFile(file
);
1126 newFile
= new CKnownFile(tag
);
1127 ProcessItemUpdate(tag
, newFile
);
1128 (*theApp
->sharedfiles
)[id
] = newFile
;
1129 theApp
->amuledlg
->m_sharedfileswnd
->sharedfilesctrl
->ShowFile(newFile
);
1135 // remove items no longer present
1136 for(iterator it
= begin(); it
!= end();) {
1137 iterator it2
= it
++;
1138 if (!core_files
.count(GetItemID(*it2
))) {
1139 RemoveItem(it2
); // This calls DeleteItem, where it is removed from lists and views.
1144 CKnownFilesRem::CKnownFilesRem(CRemoteConnect
* conn
) : CRemoteContainer
<CKnownFile
, uint32
, CEC_SharedFile_Tag
>(conn
, true)
1153 * List of uploading and waiting clients.
1155 CUpDownClientListRem::CUpDownClientListRem(CRemoteConnect
*conn
)
1157 CRemoteContainer
<CClientRef
, uint32
, CEC_UpDownClient_Tag
>(conn
, true)
1162 CClientRef::CClientRef(CEC_UpDownClient_Tag
*tag
)
1164 m_client
= new CUpDownClient(tag
);
1165 #ifdef DEBUG_ZOMBIE_CLIENTS
1166 m_client
->Link(wxT("TAG"));
1173 CUpDownClient::CUpDownClient(CEC_UpDownClient_Tag
*tag
) : CECID(tag
->ID())
1176 #ifdef DEBUG_ZOMBIE_CLIENTS
1177 m_linkedDebug
= false;
1179 // Clients start up empty, then get asked for their data.
1180 // So all data here is processed in ProcessItemUpdate and thus updatable.
1181 m_bEmuleProtocol
= false;
1182 m_AvailPartCount
= 0;
1184 m_nDownloadState
= 0;
1186 m_bFriendSlot
= false;
1190 m_lastDownloadingPart
= 0xffff;
1191 m_nextRequestedPart
= 0xffff;
1192 m_obfuscationStatus
= 0;
1193 m_nOldRemoteQueueRank
= 0;
1194 m_nRemoteQueueRank
= 0;
1199 m_nSourceFrom
= SF_NONE
;
1200 m_nTransferredDown
= 0;
1201 m_nTransferredUp
= 0;
1203 m_uploadingfile
= NULL
;
1204 m_waitingPosition
= 0;
1206 m_nUserIDHybrid
= 0;
1208 m_nClientVersion
= 0;
1209 m_fNoViewSharedFiles
= false;
1210 m_identState
= IS_NOTAVAILABLE
;
1211 m_bRemoteQueueFull
= false;
1213 credits
= new CClientCredits(new CreditStruct());
1216 #ifdef DEBUG_ZOMBIE_CLIENTS
1217 void CUpDownClient::Unlink(const wxString
& from
)
1219 std::multiset
<wxString
>::iterator it
= m_linkedFrom
.find(from
);
1220 if (it
!= m_linkedFrom
.end()) {
1221 m_linkedFrom
.erase(it
);
1225 if (m_linkedDebug
) {
1226 AddLogLineN(CFormat(wxT("Last reference to client %d %p unlinked, delete it.")) % ECID() % this);
1234 void CUpDownClient::Unlink()
1244 uint64
CUpDownClient::GetDownloadedTotal() const
1246 return credits
->GetDownloadedTotal();
1250 uint64
CUpDownClient::GetUploadedTotal() const
1252 return credits
->GetUploadedTotal();
1256 double CUpDownClient::GetScoreRatio() const
1258 return credits
->GetScoreRatio(GetIP(), theApp
->CryptoAvailable());
1264 CUpDownClient::~CUpDownClient()
1270 CClientRef
*CUpDownClientListRem::CreateItem(CEC_UpDownClient_Tag
*tag
)
1272 CClientRef
*client
= new CClientRef(tag
);
1273 ProcessItemUpdate(tag
, client
);
1279 void CUpDownClientListRem::DeleteItem(CClientRef
*clientref
)
1281 CUpDownClient
* client
= clientref
->GetClient();
1282 if (client
->m_reqfile
) {
1283 client
->m_reqfile
->DelSource(client
);
1284 client
->m_reqfile
= NULL
;
1286 Notify_SourceCtrlRemoveSource(client
->ECID(), (CPartFile
*) NULL
);
1288 if (client
->m_uploadingfile
) {
1289 client
->m_uploadingfile
->RemoveUploadingClient(client
); // this notifies
1290 client
->m_uploadingfile
= NULL
;
1292 theApp
->m_allUploadingKnownFile
->RemoveUploadingClient(client
); // in case it vanished directly while uploading
1293 Notify_SharedCtrlRemoveClient(client
->ECID(), (CKnownFile
*) NULL
);
1295 if (client
->m_Friend
) {
1296 client
->m_Friend
->UnLinkClient(); // this notifies
1297 client
->m_Friend
= NULL
;
1300 #ifdef DEBUG_ZOMBIE_CLIENTS
1301 if (client
->m_linked
> 1) {
1302 AddLogLineC(CFormat(wxT("Client %d still linked in %d places: %s")) % client
->ECID() % (client
->m_linked
- 1) % client
->GetLinkedFrom());
1303 client
->m_linkedDebug
= true;
1311 uint32
CUpDownClientListRem::GetItemID(CClientRef
*client
)
1313 return client
->ECID();
1317 void CUpDownClientListRem::ProcessItemUpdate(
1318 CEC_UpDownClient_Tag
*tag
,
1319 CClientRef
*clientref
)
1321 if (!tag
->HasChildTags()) {
1322 return; // speed exit for clients without any change
1324 CUpDownClient
*client
= clientref
->GetClient();
1326 tag
->UserID(&client
->m_nUserIDHybrid
);
1327 tag
->ClientName(&client
->m_Username
);
1329 bool sw_updated
= false;
1330 if (tag
->ClientSoftware(client
->m_clientSoft
)) {
1331 client
->m_clientSoftString
= GetSoftName(client
->m_clientSoft
);
1334 if (tag
->SoftVerStr(client
->m_clientVerString
) || sw_updated
) {
1335 if (client
->m_clientSoftString
== _("Unknown")) {
1336 client
->m_fullClientVerString
= client
->m_clientSoftString
;
1338 client
->m_fullClientVerString
= client
->m_clientSoftString
+ wxT(" ") + client
->m_clientVerString
;
1342 tag
->UserHash(&client
->m_UserHash
);
1345 tag
->UserIP(client
->m_dwUserIP
);
1346 tag
->UserPort(&client
->m_nUserPort
);
1349 tag
->ServerIP(&client
->m_dwServerIP
);
1350 tag
->ServerPort(&client
->m_nServerPort
);
1351 tag
->ServerName(&client
->m_ServerName
);
1353 tag
->KadPort(client
->m_nKadPort
);
1354 tag
->FriendSlot(client
->m_bFriendSlot
);
1356 tag
->GetCurrentIdentState(&client
->m_identState
);
1357 tag
->ObfuscationStatus(client
->m_obfuscationStatus
);
1358 tag
->HasExtendedProtocol(&client
->m_bEmuleProtocol
);
1360 tag
->WaitingPosition(&client
->m_waitingPosition
);
1361 tag
->RemoteQueueRank(&client
->m_nRemoteQueueRank
);
1362 client
->m_bRemoteQueueFull
= client
->m_nRemoteQueueRank
== 0xffff;
1363 tag
->OldRemoteQueueRank(&client
->m_nOldRemoteQueueRank
);
1365 tag
->ClientDownloadState(client
->m_nDownloadState
);
1366 if (tag
->ClientUploadState(client
->m_nUploadState
)) {
1367 if (client
->m_nUploadState
== US_UPLOADING
) {
1368 theApp
->m_allUploadingKnownFile
->AddUploadingClient(client
);
1370 theApp
->m_allUploadingKnownFile
->RemoveUploadingClient(client
);
1374 tag
->SpeedUp(&client
->m_nUpDatarate
);
1375 if ( client
->m_nDownloadState
== DS_DOWNLOADING
) {
1376 tag
->SpeedDown(&client
->m_kBpsDown
);
1378 client
->m_kBpsDown
= 0;
1381 //tag->WaitTime(&client->m_WaitTime);
1382 //tag->XferTime(&client->m_UpStartTimeDelay);
1383 //tag->LastReqTime(&client->m_dwLastUpRequest);
1384 //tag->QueueTime(&client->m_WaitStartTime);
1386 CreditStruct
*credit_struct
=
1387 (CreditStruct
*)client
->credits
->GetDataStruct();
1388 tag
->XferUp(&credit_struct
->uploaded
);
1389 tag
->XferUpSession(&client
->m_nTransferredUp
);
1391 tag
->XferDown(&credit_struct
->downloaded
);
1392 tag
->XferDownSession(&client
->m_nTransferredDown
);
1394 tag
->Score(&client
->m_score
);
1396 tag
->NextRequestedPart(client
->m_nextRequestedPart
);
1397 tag
->LastDownloadingPart(client
->m_lastDownloadingPart
);
1399 uint8 sourceFrom
= 0;
1400 if (tag
->GetSourceFrom(sourceFrom
)) {
1401 client
->m_nSourceFrom
= (ESourceFrom
)sourceFrom
;
1404 tag
->RemoteFilename(client
->m_clientFilename
);
1405 tag
->DisableViewShared(client
->m_fNoViewSharedFiles
);
1406 tag
->Version(client
->m_nClientVersion
);
1407 tag
->ModVersion(client
->m_strModVersion
);
1408 tag
->OSInfo(client
->m_sClientOSInfo
);
1409 tag
->AvailableParts(client
->m_AvailPartCount
);
1413 bool notified
= false;
1414 if (tag
->RequestFile(fileID
)) {
1415 if (client
->m_reqfile
) {
1416 Notify_SourceCtrlRemoveSource(client
->ECID(), client
->m_reqfile
);
1417 client
->m_reqfile
->DelSource(client
);
1418 client
->m_reqfile
= NULL
;
1419 client
->m_downPartStatus
.clear();
1421 CKnownFile
* kf
= theApp
->knownfiles
->GetByID(fileID
);
1422 if (kf
&& kf
->IsCPartFile()) {
1423 client
->m_reqfile
= (CPartFile
*) kf
;
1424 client
->m_reqfile
->AddSource(client
);
1425 client
->m_downPartStatus
.setsize(kf
->GetPartCount(), 0);
1426 Notify_SourceCtrlAddSource(client
->m_reqfile
, CCLIENTREF(client
, wxT("AddSource")), A4AF_SOURCE
);
1432 CECTag
* partStatusTag
= tag
->GetTagByName(EC_TAG_CLIENT_PART_STATUS
);
1433 if (partStatusTag
) {
1434 if (partStatusTag
->GetTagDataLen() == 0) {
1435 // empty tag means full source
1436 client
->m_downPartStatus
.SetAllTrue();
1437 } else if (partStatusTag
->GetTagDataLen() == client
->m_downPartStatus
.SizeBuffer()) {
1438 client
->m_downPartStatus
.SetBuffer(partStatusTag
->GetTagData());
1443 if (!notified
&& client
->m_reqfile
&& client
->m_reqfile
->ShowSources()) {
1444 SourceItemType type
;
1445 switch (client
->GetDownloadState()) {
1446 case DS_DOWNLOADING
:
1448 // We will send A4AF, which will be checked.
1452 type
= UNAVAILABLE_SOURCE
;
1456 Notify_SourceCtrlUpdateSource(client
->ECID(), type
);
1461 if (tag
->UploadFile(fileID
)) {
1462 if (client
->m_uploadingfile
) {
1463 client
->m_uploadingfile
->RemoveUploadingClient(client
); // this notifies
1465 client
->m_uploadingfile
= NULL
;
1467 CKnownFile
* kf
= theApp
->knownfiles
->GetByID(fileID
);
1469 client
->m_uploadingfile
= kf
;
1470 client
->m_upPartStatus
.setsize(kf
->GetPartCount(), 0);
1471 client
->m_uploadingfile
->AddUploadingClient(client
); // this notifies
1477 partStatusTag
= tag
->GetTagByName(EC_TAG_CLIENT_UPLOAD_PART_STATUS
);
1478 if (partStatusTag
) {
1479 if (partStatusTag
->GetTagDataLen() == client
->m_upPartStatus
.SizeBuffer()) {
1480 client
->m_upPartStatus
.SetBuffer(partStatusTag
->GetTagData());
1485 if (!notified
&& client
->m_uploadingfile
1486 && (client
->m_uploadingfile
->ShowPeers() || (client
->m_nUploadState
== US_UPLOADING
))) {
1487 // notify if KnowFile is selected, or if it's uploading (in case clients are in show uploading mode)
1488 SourceItemType type
;
1489 switch (client
->GetUploadState()) {
1491 case US_ONUPLOADQUEUE
:
1492 type
= AVAILABLE_SOURCE
;
1495 type
= UNAVAILABLE_SOURCE
;
1498 Notify_SharedCtrlRefreshClient(client
->ECID(), type
);
1504 * Download queue container: hold PartFiles with progress status
1509 bool CDownQueueRem::AddLink(const wxString
&link
, uint8 cat
)
1511 CECPacket
req(EC_OP_ADD_LINK
);
1512 CECTag
link_tag(EC_TAG_STRING
, link
);
1513 link_tag
.AddTag(CECTag(EC_TAG_PARTFILE_CAT
, cat
));
1514 req
.AddTag(link_tag
);
1516 m_conn
->SendPacket(&req
);
1521 void CDownQueueRem::ResetCatParts(int cat
)
1523 // Called when category is deleted. Command will be performed on the remote side,
1524 // but files still should be updated here right away, or drawing errors (colour not available)
1526 for (iterator it
= begin(); it
!= end(); it
++) {
1527 CPartFile
* file
= it
->second
;
1528 file
->RemoveCategory(cat
);
1534 void CKnownFilesRem::ProcessItemUpdatePartfile(CEC_PartFile_Tag
*tag
, CPartFile
*file
)
1539 tag
->Speed(&file
->m_kbpsDown
);
1540 file
->kBpsDown
= file
->m_kbpsDown
/ 1024.0;
1542 tag
->SizeXfer(&file
->transferred
);
1543 tag
->SizeDone(&file
->completedsize
);
1544 tag
->SourceXferCount(&file
->transferingsrc
);
1545 tag
->SourceNotCurrCount(&file
->m_notCurrentSources
);
1546 tag
->SourceCount(&file
->m_source_count
);
1547 tag
->SourceCountA4AF(&file
->m_a4af_source_count
);
1548 tag
->FileStatus(&file
->status
);
1549 tag
->Stopped(&file
->m_stopped
);
1551 tag
->LastSeenComplete(&file
->lastseencomplete
);
1552 tag
->LastDateChanged(&file
->m_lastDateChanged
);
1553 tag
->DownloadActiveTime(&file
->m_nDlActiveTime
);
1554 tag
->AvailablePartCount(&file
->m_availablePartsCount
);
1555 tag
->Shared(&file
->m_isShared
);
1556 tag
->A4AFAuto(file
->m_is_A4AF_auto
);
1558 tag
->GetLostDueToCorruption(&file
->m_iLostDueToCorruption
);
1559 tag
->GetGainDueToCompression(&file
->m_iGainDueToCompression
);
1560 tag
->TotalPacketsSavedDueToICH(&file
->m_iTotalPacketsSavedDueToICH
);
1562 tag
->FileCat(&file
->m_category
);
1564 tag
->DownPrio(&file
->m_iDownPriorityEC
);
1565 if ( file
->m_iDownPriorityEC
>= 10 ) {
1566 file
->m_iDownPriority
= file
->m_iDownPriorityEC
- 10;
1567 file
->m_bAutoDownPriority
= true;
1569 file
->m_iDownPriority
= file
->m_iDownPriorityEC
;
1570 file
->m_bAutoDownPriority
= false;
1573 file
->percentcompleted
= (100.0*file
->GetCompletedSize()) / file
->GetFileSize();
1576 // Copy part/gap status
1578 CECTag
*gaptag
= tag
->GetTagByName(EC_TAG_PARTFILE_GAP_STATUS
);
1579 CECTag
*parttag
= tag
->GetTagByName(EC_TAG_PARTFILE_PART_STATUS
);
1580 CECTag
*reqtag
= tag
->GetTagByName(EC_TAG_PARTFILE_REQ_STATUS
);
1581 if (gaptag
|| parttag
|| reqtag
) {
1582 PartFileEncoderData
&encoder
= file
->m_PartFileEncoderData
;
1585 ArrayOfUInts64 gaps
;
1586 encoder
.DecodeGaps(gaptag
, gaps
);
1587 int gap_size
= gaps
.size() / 2;
1589 file
->m_gaplist
.Init(file
->GetFileSize(), false);
1592 for (int j
= 0; j
< gap_size
; j
++) {
1593 file
->m_gaplist
.AddGap(gaps
[2*j
], gaps
[2*j
+1]);
1597 encoder
.DecodeParts(parttag
, file
->m_SrcpartFrequency
);
1599 wxASSERT (file
->m_SrcpartFrequency
.size() == file
->GetPartCount());
1602 ArrayOfUInts64 reqs
;
1603 encoder
.DecodeReqs(reqtag
, reqs
);
1604 int req_size
= reqs
.size() / 2;
1606 DeleteContents(file
->m_requestedblocks_list
);
1609 for (int j
= 0; j
< req_size
; j
++) {
1610 Requested_Block_Struct
* block
= new Requested_Block_Struct
;
1611 block
->StartOffset
= reqs
[2*j
];
1612 block
->EndOffset
= reqs
[2*j
+1];
1613 file
->m_requestedblocks_list
.push_back(block
);
1618 // Get source names and counts
1619 CECTag
*srcnametag
= tag
->GetTagByName(EC_TAG_PARTFILE_SOURCE_NAMES
);
1621 SourcenameItemMap
&map
= file
->GetSourcenameItemMap();
1622 for (CECTag::const_iterator it
= srcnametag
->begin(); it
!= srcnametag
->end(); it
++) {
1623 uint32 key
= it
->GetInt();
1624 int count
= it
->GetTagByNameSafe(EC_TAG_PARTFILE_SOURCE_NAMES_COUNTS
)->GetInt();
1628 SourcenameItem
&item
= map
[key
];
1630 const CECTag
*nametag
= it
->GetTagByName(EC_TAG_PARTFILE_SOURCE_NAMES
);
1632 item
.name
= nametag
->GetStringData();
1639 CECTag
*commenttag
= tag
->GetTagByName(EC_TAG_PARTFILE_COMMENTS
);
1641 file
->ClearFileRatingList();
1642 for (CECTag::const_iterator it
= commenttag
->begin(); it
!= commenttag
->end(); ) {
1643 wxString u
= (it
++)->GetStringData();
1644 wxString f
= (it
++)->GetStringData();
1645 int r
= (it
++)->GetInt();
1646 wxString c
= (it
++)->GetStringData();
1647 file
->AddFileRatingList(u
, f
, r
, c
);
1649 file
->UpdateFileRatingCommentAvail();
1652 // Update A4AF sources
1653 ListOfUInts32
& clientIDs
= file
->GetA4AFClientIDs();
1654 CECTag
*a4aftag
= tag
->GetTagByName(EC_TAG_PARTFILE_A4AF_SOURCES
);
1656 file
->ClearA4AFList();
1658 for (CECTag::const_iterator it
= a4aftag
->begin(); it
!= a4aftag
->end(); it
++) {
1659 if (it
->GetTagName() != EC_TAG_ECID
) { // should always be this
1662 uint32 id
= it
->GetInt();
1663 CClientRef
* src
= theApp
->clientlist
->GetByID(id
);
1665 file
->AddA4AFSource(src
->GetClient());
1667 // client wasn't transmitted yet, try it later
1668 clientIDs
.push_back(id
);
1671 } else if (!clientIDs
.empty()) {
1672 // Process clients from the last pass whose ids were still unknown then
1673 for (ListOfUInts32::iterator it
= clientIDs
.begin(); it
!= clientIDs
.end(); ) {
1674 ListOfUInts32::iterator it1
= it
++;
1676 CClientRef
* src
= theApp
->clientlist
->GetByID(id
);
1678 file
->AddA4AFSource(src
->GetClient());
1679 clientIDs
.erase(it1
);
1684 theApp
->amuledlg
->m_transferwnd
->downloadlistctrl
->UpdateItem(file
);
1686 // If file is shared check if it is already listed in shared files.
1687 // If not, add it and show it.
1688 if (file
->IsShared() && !theApp
->sharedfiles
->count(file
->ECID())) {
1689 (*theApp
->sharedfiles
)[file
->ECID()] = file
;
1690 theApp
->amuledlg
->m_sharedfileswnd
->sharedfilesctrl
->ShowFile(file
);
1695 void CDownQueueRem::SendFileCommand(CPartFile
*file
, ec_tagname_t cmd
)
1698 req
.AddTag(CECTag(EC_TAG_PARTFILE
, file
->GetFileHash()));
1700 m_conn
->SendPacket(&req
);
1704 void CDownQueueRem::Prio(CPartFile
*file
, uint8 prio
)
1706 CECPacket
req(EC_OP_PARTFILE_PRIO_SET
);
1708 CECTag
hashtag(EC_TAG_PARTFILE
, file
->GetFileHash());
1709 hashtag
.AddTag(CECTag(EC_TAG_PARTFILE_PRIO
, prio
));
1710 req
.AddTag(hashtag
);
1712 m_conn
->SendPacket(&req
);
1716 void CDownQueueRem::AutoPrio(CPartFile
*file
, bool flag
)
1718 CECPacket
req(EC_OP_PARTFILE_PRIO_SET
);
1720 CECTag
hashtag(EC_TAG_PARTFILE
, file
->GetFileHash());
1722 hashtag
.AddTag(CECTag(EC_TAG_PARTFILE_PRIO
,
1723 (uint8
)(flag
? PR_AUTO
: file
->GetDownPriority())));
1724 req
.AddTag(hashtag
);
1726 m_conn
->SendPacket(&req
);
1730 void CDownQueueRem::Category(CPartFile
*file
, uint8 cat
)
1732 CECPacket
req(EC_OP_PARTFILE_SET_CAT
);
1733 file
->SetCategory(cat
);
1735 CECTag
hashtag(EC_TAG_PARTFILE
, file
->GetFileHash());
1736 hashtag
.AddTag(CECTag(EC_TAG_PARTFILE_CAT
, cat
));
1737 req
.AddTag(hashtag
);
1739 m_conn
->SendPacket(&req
);
1743 void CDownQueueRem::AddSearchToDownload(CSearchFile
* file
, uint8 category
)
1745 CECPacket
req(EC_OP_DOWNLOAD_SEARCH_RESULT
);
1746 CECTag
hashtag(EC_TAG_PARTFILE
, file
->GetFileHash());
1747 hashtag
.AddTag(CECTag(EC_TAG_PARTFILE_CAT
, category
));
1748 req
.AddTag(hashtag
);
1750 m_conn
->SendPacket(&req
);
1754 void CDownQueueRem::ClearCompleted(const ListOfUInts32
& ecids
)
1756 CECPacket
req(EC_OP_CLEAR_COMPLETED
);
1757 for (ListOfUInts32::const_iterator it
= ecids
.begin(); it
!= ecids
.end(); it
++) {
1758 req
.AddTag(CECTag(EC_TAG_ECID
, *it
));
1761 m_conn
->SendPacket(&req
);
1768 CFriendListRem::CFriendListRem(CRemoteConnect
*conn
)
1770 CRemoteContainer
<CFriend
, uint32
, CEC_Friend_Tag
>(conn
, true)
1775 void CFriendListRem::HandlePacket(const CECPacket
*)
1777 wxFAIL
; // not needed
1781 CFriend
* CFriendListRem::CreateItem(CEC_Friend_Tag
* tag
)
1783 CFriend
* Friend
= new CFriend(tag
->ID());
1784 ProcessItemUpdate(tag
, Friend
);
1789 void CFriendListRem::DeleteItem(CFriend
* Friend
)
1791 Friend
->UnLinkClient(false);
1792 Notify_ChatRemoveFriend(Friend
);
1796 uint32
CFriendListRem::GetItemID(CFriend
* Friend
)
1798 return Friend
->ECID();
1802 void CFriendListRem::ProcessItemUpdate(CEC_Friend_Tag
* tag
, CFriend
* Friend
)
1804 if (!tag
->HasChildTags()) {
1807 tag
->Name(Friend
->m_strName
);
1808 tag
->UserHash(Friend
->m_UserHash
);
1809 tag
->IP(Friend
->m_dwLastUsedIP
);
1810 tag
->Port(Friend
->m_nLastUsedPort
);
1812 bool notified
= false;
1813 if (tag
->Client(clientID
)) {
1815 CClientRef
* client
= theApp
->clientlist
->GetByID(clientID
);
1817 Friend
->LinkClient(*client
); // this notifies
1822 Friend
->UnLinkClient(false);
1826 Notify_ChatUpdateFriend(Friend
);
1831 void CFriendListRem::AddFriend(const CClientRef
& toadd
)
1833 CECPacket
req(EC_OP_FRIEND
);
1835 CECEmptyTag
addtag(EC_TAG_FRIEND_ADD
);
1836 addtag
.AddTag(CECTag(EC_TAG_CLIENT
, toadd
.ECID()));
1839 m_conn
->SendPacket(&req
);
1843 void CFriendListRem::AddFriend(const CMD4Hash
& userhash
, uint32 lastUsedIP
, uint32 lastUsedPort
, const wxString
& name
)
1845 CECPacket
req(EC_OP_FRIEND
);
1847 CECEmptyTag
addtag(EC_TAG_FRIEND_ADD
);
1848 addtag
.AddTag(CECTag(EC_TAG_FRIEND_HASH
, userhash
));
1849 addtag
.AddTag(CECTag(EC_TAG_FRIEND_IP
, lastUsedIP
));
1850 addtag
.AddTag(CECTag(EC_TAG_FRIEND_PORT
, lastUsedPort
));
1851 addtag
.AddTag(CECTag(EC_TAG_FRIEND_NAME
, name
));
1854 m_conn
->SendPacket(&req
);
1858 void CFriendListRem::RemoveFriend(CFriend
* toremove
)
1860 CECPacket
req(EC_OP_FRIEND
);
1862 CECEmptyTag
removetag(EC_TAG_FRIEND_REMOVE
);
1863 removetag
.AddTag(CECTag(EC_TAG_FRIEND
, toremove
->ECID()));
1864 req
.AddTag(removetag
);
1866 m_conn
->SendPacket(&req
);
1870 void CFriendListRem::SetFriendSlot(CFriend
* Friend
, bool new_state
)
1872 CECPacket
req(EC_OP_FRIEND
);
1874 CECTag
slottag(EC_TAG_FRIEND_FRIENDSLOT
, new_state
);
1875 slottag
.AddTag(CECTag(EC_TAG_FRIEND
, Friend
->ECID()));
1876 req
.AddTag(slottag
);
1878 m_conn
->SendPacket(&req
);
1882 void CFriendListRem::RequestSharedFileList(CFriend
* Friend
)
1884 CECPacket
req(EC_OP_FRIEND
);
1886 CECEmptyTag
sharedtag(EC_TAG_FRIEND_SHARED
);
1887 sharedtag
.AddTag(CECTag(EC_TAG_FRIEND
, Friend
->ECID()));
1888 req
.AddTag(sharedtag
);
1890 m_conn
->SendPacket(&req
);
1894 void CFriendListRem::RequestSharedFileList(CClientRef
& client
)
1896 CECPacket
req(EC_OP_FRIEND
);
1898 CECEmptyTag
sharedtag(EC_TAG_FRIEND_SHARED
);
1899 sharedtag
.AddTag(CECTag(EC_TAG_CLIENT
, client
.ECID()));
1900 req
.AddTag(sharedtag
);
1902 m_conn
->SendPacket(&req
);
1910 CSearchListRem::CSearchListRem(CRemoteConnect
*conn
) : CRemoteContainer
<CSearchFile
, uint32
, CEC_SearchFile_Tag
>(conn
, true)
1916 wxString
CSearchListRem::StartNewSearch(
1917 uint32
* nSearchID
, SearchType search_type
,
1918 const CSearchList::CSearchParams
& params
)
1920 CECPacket
search_req(EC_OP_SEARCH_START
);
1921 EC_SEARCH_TYPE ec_search_type
= EC_SEARCH_LOCAL
;
1922 switch(search_type
) {
1923 case LocalSearch
: ec_search_type
= EC_SEARCH_LOCAL
; break;
1924 case GlobalSearch
: ec_search_type
= EC_SEARCH_GLOBAL
; break;
1925 case KadSearch
: ec_search_type
= EC_SEARCH_KAD
; break;
1928 CEC_Search_Tag(params
.searchString
, ec_search_type
,
1929 params
.typeText
, params
.extension
, params
.availability
,
1930 params
.minSize
, params
.maxSize
));
1932 m_conn
->SendPacket(&search_req
);
1933 m_curr_search
= *(nSearchID
); // No kad remote search yet.
1937 return wxEmptyString
; // EC reply will have the error mesg is needed.
1941 void CSearchListRem::StopSearch(bool)
1943 if (m_curr_search
!= -1) {
1944 CECPacket
search_req(EC_OP_SEARCH_STOP
);
1945 m_conn
->SendPacket(&search_req
);
1950 void CSearchListRem::HandlePacket(const CECPacket
*packet
)
1952 if ( packet
->GetOpCode() == EC_OP_SEARCH_PROGRESS
) {
1953 CoreNotify_Search_Update_Progress(packet
->GetFirstTagSafe()->GetInt());
1955 CRemoteContainer
<CSearchFile
, uint32
, CEC_SearchFile_Tag
>::HandlePacket(packet
);
1960 CSearchFile::CSearchFile(CEC_SearchFile_Tag
*tag
)
1964 m_showChildren(false),
1966 m_completeSourceCount(0),
1968 m_downloadStatus(NEW
),
1973 SetFileName(CPath(tag
->FileName()));
1974 m_abyFileHash
= tag
->FileHash();
1975 SetFileSize(tag
->SizeFull());
1977 m_searchID
= theApp
->searchlist
->m_curr_search
;
1978 uint32 parentID
= tag
->ParentID();
1980 CSearchFile
* parent
= theApp
->searchlist
->GetByID(parentID
);
1982 parent
->AddChild(this);
1988 void CSearchFile::AddChild(CSearchFile
* file
)
1990 m_children
.push_back(file
);
1991 file
->m_parent
= this;
1995 // dtor is virtual - must be implemented
1996 CSearchFile::~CSearchFile()
2001 CSearchFile
*CSearchListRem::CreateItem(CEC_SearchFile_Tag
*tag
)
2003 CSearchFile
*file
= new CSearchFile(tag
);
2004 ProcessItemUpdate(tag
, file
);
2006 theApp
->amuledlg
->m_searchwnd
->AddResult(file
);
2012 void CSearchListRem::DeleteItem(CSearchFile
*file
)
2018 uint32
CSearchListRem::GetItemID(CSearchFile
*file
)
2020 return file
->ECID();
2024 void CSearchListRem::ProcessItemUpdate(CEC_SearchFile_Tag
*tag
, CSearchFile
*file
)
2026 uint32 sourceCount
= file
->m_sourceCount
;
2027 uint32 completeSourceCount
= file
->m_completeSourceCount
;
2028 CSearchFile::DownloadStatus status
= file
->m_downloadStatus
;
2029 tag
->SourceCount(&file
->m_sourceCount
);
2030 tag
->CompleteSourceCount(&file
->m_completeSourceCount
);
2031 tag
->DownloadStatus((uint32
*) &file
->m_downloadStatus
);
2033 if (file
->m_sourceCount
!= sourceCount
2034 || file
->m_completeSourceCount
!= completeSourceCount
2035 || file
->m_downloadStatus
!= status
) {
2036 if (theApp
->amuledlg
&& theApp
->amuledlg
->m_searchwnd
) {
2037 theApp
->amuledlg
->m_searchwnd
->UpdateResult(file
);
2043 bool CSearchListRem::Phase1Done(const CECPacket
*WXUNUSED(reply
))
2045 CECPacket
progress_req(EC_OP_SEARCH_PROGRESS
);
2046 m_conn
->SendRequest(this, &progress_req
);
2052 void CSearchListRem::RemoveResults(long nSearchID
)
2054 ResultMap::iterator it
= m_results
.find(nSearchID
);
2055 if (it
!= m_results
.end()) {
2056 CSearchResultList
& list
= it
->second
;
2057 for (unsigned int i
= 0; i
< list
.size(); ++i
) {
2060 m_results
.erase(it
);
2065 const CSearchResultList
& CSearchListRem::GetSearchResults(long nSearchID
)
2067 ResultMap::const_iterator it
= m_results
.find(nSearchID
);
2068 if (it
!= m_results
.end()) {
2072 // TODO: Should we assert in this case?
2073 static CSearchResultList list
;
2078 void CStatsUpdaterRem::HandlePacket(const CECPacket
*packet
)
2080 theStats::UpdateStats(packet
);
2081 theApp
->ShowUserCount(); // maybe there should be a check if a usercount changed ?
2085 void CUpDownClient::RequestSharedFileList()
2087 CClientRef ref
= CCLIENTREF(this, wxEmptyString
);
2088 theApp
->friendlist
->RequestSharedFileList(ref
);
2092 bool CUpDownClient::SwapToAnotherFile(
2093 bool WXUNUSED(bIgnoreNoNeeded
),
2094 bool WXUNUSED(ignoreSuspensions
),
2095 bool WXUNUSED(bRemoveCompletely
),
2098 CECPacket
req(EC_OP_CLIENT_SWAP_TO_ANOTHER_FILE
);
2099 req
.AddTag(CECTag(EC_TAG_CLIENT
, ECID()));
2100 req
.AddTag(CECTag(EC_TAG_PARTFILE
, toFile
->GetFileHash()));
2101 theApp
->m_connect
->SendPacket(&req
);
2107 wxString
CAICHHash::GetString() const
2109 return EncodeBase32(m_abyBuffer
, HASHSIZE
);
2114 // Those functions are virtual. So even they don't get called they must
2115 // be defined so linker will be happy
2117 CPacket
* CKnownFile::CreateSrcInfoPacket(const CUpDownClient
*, uint8
/*byRequestedVersion*/, uint16
/*nRequestedOptions*/)
2124 bool CKnownFile::LoadFromFile(const class CFileDataIO
*)
2131 void CKnownFile::UpdatePartsInfo()
2137 CPacket
* CPartFile::CreateSrcInfoPacket(CUpDownClient
const *, uint8
/*byRequestedVersion*/, uint16
/*nRequestedOptions*/)
2144 void CPartFile::UpdatePartsInfo()
2151 void CPartFile::UpdateFileRatingCommentAvail()
2153 bool prevComment
= m_hasComment
;
2154 int prevRating
= m_iUserRating
;
2156 m_hasComment
= false;
2158 int ratingCount
= 0;
2160 FileRatingList::iterator it
= m_FileRatingList
.begin();
2161 for (; it
!= m_FileRatingList
.end(); ++it
) {
2162 SFileRating
& cur_rat
= *it
;
2164 if (!cur_rat
.Comment
.IsEmpty()) {
2165 m_hasComment
= true;
2168 uint8 rating
= cur_rat
.Rating
;
2170 wxASSERT(rating
<= 5);
2173 m_iUserRating
+= rating
;
2178 m_iUserRating
/= ratingCount
;
2179 wxASSERT(m_iUserRating
> 0 && m_iUserRating
<= 5);
2182 if ((prevComment
!= m_hasComment
) || (prevRating
!= m_iUserRating
)) {
2183 UpdateDisplayedInfo();
2188 void CStatTreeRem::DoRequery()
2190 CECPacket
request(EC_OP_GET_STATSTREE
);
2191 if (thePrefs::GetMaxClientVersions() != 0) {
2192 request
.AddTag(CECTag(EC_TAG_STATTREE_CAPPING
, (uint8
)thePrefs::GetMaxClientVersions()));
2194 m_conn
->SendRequest(this, &request
);
2197 void CStatTreeRem::HandlePacket(const CECPacket
* p
)
2199 const CECTag
* treeRoot
= p
->GetTagByName(EC_TAG_STATTREE_NODE
);
2201 theApp
->amuledlg
->m_statisticswnd
->RebuildStatTreeRemote(treeRoot
);
2202 theApp
->amuledlg
->m_statisticswnd
->ShowStatistics();
2206 CamuleRemoteGuiApp
*theApp
;
2209 // since gui is not linked with amule.cpp - define events here
2211 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_FINISHED_HTTP_DOWNLOAD
)
2212 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_SOURCE_DNS_DONE
)
2213 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_UDP_DNS_DONE
)
2214 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_SERVER_DNS_DONE
)
2215 // File_checked_for_headers