Upstream tarball 9440
[amule.git] / src / amule.cpp
blob501ae5b3ae809ff71c4c870ab22e9ce2d5d6a84b
1 //
2 // This file is part of the aMule Project.
3 //
4 // Copyright (c) 2003-2008 aMule Team ( admin@amule.org / http://www.amule.org )
5 // Copyright (c) 2002-2008 Merkur ( devs@emule-project.net / http://www.emule-project.net )
6 //
7 // Any parts of this program derived from the xMule, lMule or eMule project,
8 // or contributed by third-party developers are copyrighted by their
9 // respective authors.
11 // This program is free software; you can redistribute it and/or modify
12 // it under the terms of the GNU General Public License as published by
13 // the Free Software Foundation; either version 2 of the License, or
14 // (at your option) any later version.
16 // This program is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU General Public License for more details.
20 //
21 // You should have received a copy of the GNU General Public License
22 // along with this program; if not, write to the Free Software
23 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #define AMULE_CPP
30 #include "amule.h" // Interface declarations.
32 #include <csignal>
33 #include <cstring>
34 #include <wx/process.h>
35 #include <wx/sstream.h>
37 #ifdef HAVE_CONFIG_H
38 #include "config.h" // Needed for HAVE_GETRLIMIT, HAVE_SETRLIMIT,
39 // HAVE_SYS_RESOURCE_H, HAVE_SYS_STATVFS_H, VERSION
40 // and ENABLE_NLS
41 #endif
43 #include <common/ClientVersion.h>
45 #include <wx/cmdline.h> // Needed for wxCmdLineParser
46 #include <wx/config.h> // Do_not_auto_remove (win32)
47 #include <wx/fileconf.h>
48 #include <wx/snglinst.h>
49 #include <wx/tokenzr.h>
50 #include <wx/wfstream.h>
53 #include <common/Format.h> // Needed for CFormat
54 #include "kademlia/kademlia/Kademlia.h"
55 #include "kademlia/kademlia/Prefs.h"
56 #include "kademlia/kademlia/UDPFirewallTester.h"
57 #include "ClientCreditsList.h" // Needed for CClientCreditsList
58 #include "ClientList.h" // Needed for CClientList
59 #include "ClientUDPSocket.h" // Needed for CClientUDPSocket & CMuleUDPSocket
60 #include "ExternalConn.h" // Needed for ExternalConn & MuleConnection
61 #include <common/FileFunctions.h> // Needed for CDirIterator
62 #include "FriendList.h" // Needed for CFriendList
63 #include "HTTPDownload.h" // Needed for CHTTPDownloadThread
64 #include "InternalEvents.h" // Needed for CMuleInternalEvent
65 #include "IPFilter.h" // Needed for CIPFilter
66 #include "KnownFileList.h" // Needed for CKnownFileList
67 #include "ListenSocket.h" // Needed for CListenSocket
68 #include "Logger.h" // Needed for CLogger // Do_not_auto_remove
69 #include "MagnetURI.h" // Needed for CMagnetURI
70 #include "OtherFunctions.h"
71 #include "PartFile.h" // Needed for CPartFile
72 #include "Preferences.h" // Needed for CPreferences
73 #include "SearchList.h" // Needed for CSearchList
74 #include "Server.h" // Needed for GetListName
75 #include "ServerList.h" // Needed for CServerList
76 #include "ServerConnect.h" // Needed for CServerConnect
77 #include "ServerUDPSocket.h" // Needed for CServerUDPSocket
78 #include "Statistics.h" // Needed for CStatistics
79 #include "TerminationProcessAmuleweb.h" // Needed for CTerminationProcessAmuleweb
80 #include "ThreadTasks.h"
81 #include "updownclient.h" // Needed for CUpDownClient
82 #include "UploadQueue.h" // Needed for CUploadQueue
83 #include "UploadBandwidthThrottler.h"
84 #include "UserEvents.h"
86 #ifdef ENABLE_UPNP
87 #include "UPnPBase.h" // Needed for UPnP
88 #endif
90 #ifdef __WXMAC__
91 #include <wx/sysopt.h> // Do_not_auto_remove
92 #endif
94 #ifndef AMULE_DAEMON
95 #ifdef __WXMAC__
96 #include <CoreFoundation/CFBundle.h> // Do_not_auto_remove
97 #include <wx/mac/corefoundation/cfstring.h> // Do_not_auto_remove
98 #endif
99 #include <wx/msgdlg.h>
101 #include "amuleDlg.h"
102 #endif
105 #ifdef HAVE_SYS_RESOURCE_H
106 #include <sys/resource.h>
107 #endif
109 #ifdef HAVE_SYS_STATVFS_H
110 #include <sys/statvfs.h> // Do_not_auto_remove
111 #endif
114 #ifdef __GLIBC__
115 # define RLIMIT_RESOURCE __rlimit_resource
116 #else
117 # define RLIMIT_RESOURCE int
118 #endif
120 static void UnlimitResource(RLIMIT_RESOURCE resType)
122 #if defined(HAVE_GETRLIMIT) && defined(HAVE_SETRLIMIT)
123 struct rlimit rl;
124 getrlimit(resType, &rl);
125 rl.rlim_cur = rl.rlim_max;
126 setrlimit(resType, &rl);
127 #endif
131 static void SetResourceLimits()
133 #ifdef HAVE_SYS_RESOURCE_H
134 UnlimitResource(RLIMIT_DATA);
135 UnlimitResource(RLIMIT_FSIZE);
136 UnlimitResource(RLIMIT_NOFILE);
137 #ifdef RLIMIT_RSS
138 UnlimitResource(RLIMIT_RSS);
139 #endif
140 #endif
143 // We store the received signal in order to avoid race-conditions
144 // in the signal handler.
145 bool g_shutdownSignal = false;
147 void OnShutdownSignal( int /* sig */ )
149 signal(SIGINT, SIG_DFL);
150 signal(SIGTERM, SIG_DFL);
152 g_shutdownSignal = true;
154 #ifdef AMULE_DAEMON
155 theApp->ExitMainLoop();
156 #endif
160 CamuleApp::CamuleApp()
162 // Madcat - Initialize timer as the VERY FIRST thing to avoid any issues later.
163 // Kry - I love to init the vars on init, even before timer.
164 StartTickTimer();
166 // Initialization
167 m_app_state = APP_STATE_STARTING;
169 theApp = &wxGetApp();
171 clientlist = NULL;
172 searchlist = NULL;
173 knownfiles = NULL;
174 serverlist = NULL;
175 serverconnect = NULL;
176 sharedfiles = NULL;
177 listensocket = NULL;
178 clientudp = NULL;
179 clientcredits = NULL;
180 friendlist = NULL;
181 downloadqueue = NULL;
182 uploadqueue = NULL;
183 ipfilter = NULL;
184 ECServerHandler = NULL;
185 m_singleInstance= NULL;
186 glob_prefs = NULL;
187 m_statistics = NULL;
188 uploadBandwidthThrottler = NULL;
189 #ifdef ENABLE_UPNP
190 m_upnp = NULL;
191 m_upnpMappings.resize(4);
192 #endif
193 core_timer = NULL;
195 m_localip = 0;
196 m_dwPublicIP = 0;
197 webserver_pid = 0;
199 enable_daemon_fork = false;
201 strFullMuleVersion = NULL;
202 strOSDescription = NULL;
204 // Apprently needed for *BSD
205 SetResourceLimits();
208 CamuleApp::~CamuleApp()
210 // Closing the log-file as the very last thing, since
211 // wxWidgets log-events are saved in it as well.
212 theLogger.CloseLogfile();
214 free(strFullMuleVersion);
215 free(strOSDescription);
218 int CamuleApp::OnExit()
220 if (m_app_state!=APP_STATE_STARTING) {
221 AddLogLineMS(false, _("Now, exiting main app..."));
224 // From wxWidgets docs, wxConfigBase:
225 // ...
226 // Note that you must delete this object (usually in wxApp::OnExit)
227 // in order to avoid memory leaks, wxWidgets won't do it automatically.
229 // As it happens, you may even further simplify the procedure described
230 // above: you may forget about calling Set(). When Get() is called and
231 // there is no current object, it will create one using Create() function.
232 // To disable this behaviour DontCreateOnDemand() is provided.
233 delete wxConfigBase::Set((wxConfigBase *)NULL);
235 // Save credits
236 clientcredits->SaveList();
238 // Kill amuleweb if running
239 if (webserver_pid) {
240 AddLogLineMS(false, CFormat(_("Killing amuleweb instance with pid `%ld' ... ")) % webserver_pid);
241 wxKillError rc;
242 wxKill(webserver_pid, wxSIGTERM, &rc);
243 AddLogLineMS(false, _("Killed!"));
246 if (m_app_state!=APP_STATE_STARTING) {
247 AddLogLineMS(false, _("aMule OnExit: Terminating core."));
250 delete serverlist;
251 serverlist = NULL;
253 delete searchlist;
254 searchlist = NULL;
256 delete clientcredits;
257 clientcredits = NULL;
259 delete friendlist;
260 friendlist = NULL;
262 // Destroying CDownloadQueue calls destructor for CPartFile
263 // calling CSharedFileList::SafeAddKFile occasionally.
264 delete sharedfiles;
265 sharedfiles = NULL;
267 delete serverconnect;
268 serverconnect = NULL;
270 delete listensocket;
271 listensocket = NULL;
273 delete clientudp;
274 clientudp = NULL;
276 delete knownfiles;
277 knownfiles = NULL;
279 delete clientlist;
280 clientlist = NULL;
282 delete uploadqueue;
283 uploadqueue = NULL;
285 delete downloadqueue;
286 downloadqueue = NULL;
288 delete ipfilter;
289 ipfilter = NULL;
291 #ifdef ENABLE_UPNP
292 delete m_upnp;
293 m_upnp = NULL;
294 #endif
296 delete ECServerHandler;
297 ECServerHandler = NULL;
299 delete m_statistics;
300 m_statistics = NULL;
302 delete glob_prefs;
303 glob_prefs = NULL;
304 CPreferences::EraseItemList();
306 #if defined(__WXMAC__) && defined(AMULE_DAEMON)
307 //#warning TODO: fix wxSingleInstanceChecker for amuled on Mac (wx link problems)
308 #else
309 delete m_singleInstance;
310 #endif
311 m_singleInstance = NULL;
313 delete uploadBandwidthThrottler;
314 uploadBandwidthThrottler = NULL;
316 if (m_app_state!=APP_STATE_STARTING) {
317 AddLogLineNS(_("aMule shutdown completed."));
320 #if wxUSE_MEMORY_TRACING
321 AddLogLineNS(_("Memory debug results for aMule exit:"));
322 // Log mem debug mesages to wxLogStderr
323 wxLog* oldLog = wxLog::SetActiveTarget(new wxLogStderr);
324 //AddLogLineNS(wxT("**************Classes**************");
325 //wxDebugContext::PrintClasses();
326 //AddLogLineNS(wxT("***************Dump***************");
327 //wxDebugContext::Dump();
328 AddLogLineNS(wxT("***************Stats**************"));
329 wxDebugContext::PrintStatistics(true);
331 // Set back to wxLogGui
332 delete wxLog::SetActiveTarget(oldLog);
333 #endif
335 StopTickTimer();
337 // Return 0 for succesful program termination
338 return AMULE_APP_BASE::OnExit();
342 int CamuleApp::InitGui(bool, wxString &)
344 return 0;
349 * Checks permissions on a aMule directory, creating if needed.
351 * @param desc A description of the directory in question, used for error messages.
352 * @param directory The directory in question.
353 * @param fallback If the dir specified with 'directory' could not be created, try this instead.
354 * @return The bool is false on error. The wxString contains the used path.
356 std::pair<bool, CPath> CheckMuleDirectory(const wxString& desc, const CPath& directory, const wxString& alternative)
358 wxString msg;
360 if (directory.IsDir(CPath::readwritable)) {
361 return std::pair<bool, CPath>(true, directory);
362 } else if (directory.DirExists()) {
363 msg = CFormat(wxT("Permissions on the %s directory too strict!\n")
364 wxT("aMule cannot proceed. To fix this, you must set read/write/exec\n")
365 wxT("permissions for the folder '%s'"))
366 % desc % directory;
367 } else if (CPath::MakeDir(directory)) {
368 return std::pair<bool, CPath>(true, directory);
369 } else {
370 msg << CFormat(wxT("Could not create the %s directory at '%s'."))
371 % desc % directory;
374 // Attempt to use fallback directory.
375 const CPath fallback = CPath(alternative);
376 if (fallback.IsOk() && (directory != fallback)) {
377 msg << wxT("\nAttempting to use default directory at location \n'")
378 << alternative << wxT("'.");
379 theApp->ShowAlert(msg, wxT("Error accessing directory."), wxICON_ERROR | wxOK);
381 return CheckMuleDirectory(desc, fallback, wxEmptyString);
384 theApp->ShowAlert(msg, wxT("Fatal error."), wxICON_ERROR | wxOK);
385 return std::pair<bool, CPath>(false, CPath(wxEmptyString));
390 // Application initialization
392 bool CamuleApp::OnInit()
394 #if wxUSE_MEMORY_TRACING
395 // any text before call of Localize_mule needs not to be translated.
396 AddLogLineMS(false, wxT("Checkpoint set on app init for memory debug"));
397 wxDebugContext::SetCheckpoint();
398 #endif
400 // Forward wxLog events to CLogger
401 wxLog::SetActiveTarget(new CLoggerTarget);
403 m_localip = StringHosttoUint32(::wxGetFullHostName());
405 #ifndef __WXMSW__
406 // get rid of sigpipe
407 signal(SIGPIPE, SIG_IGN);
408 // Handle sigint and sigterm
409 signal(SIGINT, OnShutdownSignal);
410 signal(SIGTERM, OnShutdownSignal);
411 #endif
413 #ifdef __WXMAC__
414 // For listctrl's to behave on Mac
415 wxSystemOptions::SetOption(wxT("mac.listctrl.always_use_generic"), 1);
416 #endif
418 // This can't be on constructor or wx2.4.2 doesn't set it.
419 #if !wxCHECK_VERSION(2, 9, 0)
420 SetVendorName(wxT("TikuWarez"));
421 #endif
422 SetAppName(wxT("aMule"));
424 wxString FullMuleVersion = GetFullMuleVersion();
425 wxString OSDescription = wxGetOsDescription();
426 strFullMuleVersion = strdup((const char *)unicode2char(FullMuleVersion));
427 strOSDescription = strdup((const char *)unicode2char(OSDescription));
428 OSType = OSDescription.BeforeFirst( wxT(' ') );
429 if ( OSType.IsEmpty() ) {
430 OSType = wxT("Unknown");
433 // Handle uncaught exceptions
434 InstallMuleExceptionHandler();
436 // Parse cmdline arguments.
437 wxCmdLineParser cmdline(AMULE_APP_BASE::argc, AMULE_APP_BASE::argv);
439 // Handle these arguments.
440 cmdline.AddSwitch(wxT("v"), wxT("version"), wxT("Displays the current version number."));
441 cmdline.AddSwitch(wxT("h"), wxT("help"), wxT("Displays this information."));
442 cmdline.AddSwitch(wxT("i"), wxT("enable-stdin"), wxT("Does not disable stdin."));
443 #ifdef AMULE_DAEMON
444 cmdline.AddSwitch(wxT("f"), wxT("full-daemon"), wxT("Fork to background."));
445 cmdline.AddOption(wxT("c"), wxT("config-dir"), wxT("read config from <dir> instead of home"));
446 cmdline.AddSwitch(wxT("e"), wxT("ec-config"), wxT("Configure EC (External Connections)."));
447 #else
448 cmdline.AddOption(wxT("geometry"), wxEmptyString,
449 wxT("Sets the geometry of the app.\n")
450 wxT("\t\t\t<str> uses the same format as standard X11 apps:\n")
451 wxT("\t\t\t[=][<width>{xX}<height>][{+-}<xoffset>{+-}<yoffset>]"));
452 #endif
453 cmdline.AddSwitch(wxT("d"), wxT("disable-fatal"), wxT("Does not handle fatal exception."));
454 cmdline.AddSwitch(wxT("o"), wxT("log-stdout"), wxT("Print log messages to stdout."));
455 cmdline.AddSwitch(wxT("r"), wxT("reset-config"), wxT("Resets config to default values."));
456 #ifndef __WXMSW__
457 // Change webserver path, not available on Windows
458 cmdline.AddOption(wxT("w"), wxT("use-amuleweb"), wxT("Specify location of amuleweb binary."));
459 #endif
461 // Show help on --help or invalid commands
462 if ( cmdline.Parse() ) {
463 return false;
464 } else if ( cmdline.Found(wxT("help")) ) {
465 cmdline.Usage();
466 return false;
469 bool ec_config = false;
471 #ifdef AMULE_DAEMON
472 ec_config = cmdline.Found(wxT("ec-config"));
473 if ( cmdline.Found(wxT("config-dir"), &ConfigDir) ) {
474 if (ConfigDir.Last() != wxFileName::GetPathSeparator()) {
475 ConfigDir += wxFileName::GetPathSeparator();
477 } else {
478 ConfigDir = GetConfigDir();
480 #else
481 ConfigDir = GetConfigDir();
482 #endif
484 if ( !cmdline.Found(wxT("disable-fatal")) ) {
485 #ifndef __WXMSW__
486 // catch fatal exceptions
487 wxHandleFatalExceptions(true);
488 #endif
491 bool reset_config = cmdline.Found(wxT("reset-config"));
493 theLogger.SetEnabledStdoutLog(cmdline.Found(wxT("log-stdout")));
494 #ifdef AMULE_DAEMON
495 enable_daemon_fork = cmdline.Found(wxT("full-daemon"));
496 #else
497 enable_daemon_fork = false;
498 #endif
500 if (theLogger.IsEnabledStdoutLog()) {
501 if ( enable_daemon_fork ) {
502 AddLogLineMS(false, wxT("Daemon will fork to background - log to stdout disabled"));
503 theLogger.SetEnabledStdoutLog(false);
504 } else {
505 AddLogLineMS(false, wxT("Logging to stdout enabled"));
509 if ( cmdline.Found(wxT("version")) ) {
510 AddLogLineMS(false, CFormat(wxT("%s (OS: %s)")) % FullMuleVersion % OSType);
512 return false;
515 // Default geometry of the GUI. Can be changed with a cmdline argument...
516 bool geometry_enabled = false;
517 wxString geom_string;
518 #ifndef AMULE_DAEMON
519 if ( cmdline.Found(wxT("geometry"), &geom_string) ) {
520 geometry_enabled = true;
522 #endif
524 AddLogLineMS(false, wxT("Initialising ") + FullMuleVersion);
526 // Ensure that "~/.aMule/" is accessible.
527 if (!CheckMuleDirectory(wxT("configuration"), CPath(ConfigDir), wxEmptyString).first) {
528 return false;
531 if (reset_config) {
532 // Make a backup first.
533 wxRemoveFile(ConfigDir + wxT("amule.conf.backup"));
534 wxRenameFile(ConfigDir + wxT("amule.conf"), ConfigDir + wxT("amule.conf.backup"));
535 AddLogLineMS(false, wxT("Your settings have ben resetted to default values.\nOld config file has been saved as amule.conf.backup\n"));
538 #if defined(__WXMAC__) && defined(AMULE_DAEMON)
539 //#warning TODO: fix wxSingleInstanceChecker for amuled on Mac (wx link problems)
540 AddLogLineMS(true, wxT("WARNING: The check for other instances is currently disabled in amuled.\n"
541 "Please make sure that no other instance of aMule is running or your files might be corrupted.\n"));
542 #else
543 AddLogLineMS(false, wxT("Checking if there is an instance already running..."));
545 m_singleInstance = new wxSingleInstanceChecker();
546 if (m_singleInstance->Create(wxT("muleLock"), ConfigDir)
547 && m_singleInstance->IsAnotherRunning()) {
548 AddLogLineMS(true, wxT("There is an instance of aMule already running"));
549 AddLogLineNS(CFormat(wxT("(lock file: %s%s)")) % ConfigDir % wxT("muleLock"));
551 // This is very tricky. The most secure way to communicate is via ED2K links file
552 wxTextFile ed2kFile(ConfigDir + wxT("ED2KLinks"));
553 if (!ed2kFile.Exists()) {
554 ed2kFile.Create();
557 if (ed2kFile.Open()) {
558 ed2kFile.AddLine(wxT("RAISE_DIALOG"));
559 ed2kFile.Write();
561 AddLogLineMS(false, wxT("Raising current running instance."));
562 } else {
563 AddLogLineMS(true, wxT("Failed to open 'ED2KFile', cannot signal running instance."));
566 return false;
567 } else {
568 AddLogLineMS(false, wxT("No other instances are running."));
570 #endif
572 // Close standard-input
573 if ( !cmdline.Found(wxT("enable-stdin")) ) {
574 // The full daemon will close all std file-descriptors by itself,
575 // so closing it here would lead to the closing on the first open
576 // file, which is the logfile opened below
577 if (!enable_daemon_fork) {
578 close(0);
582 // This creates the CFG file we shall use
583 wxConfigBase* cfg = new wxFileConfig( wxEmptyString, wxEmptyString, ConfigDir + wxT("amule.conf") );
585 // Set the config object as the global cfg file
586 wxConfig::Set( cfg );
588 // Make a backup of the log file
589 CPath logfileName = CPath(ConfigDir + wxT("logfile"));
590 if (logfileName.FileExists()) {
591 CPath::BackupFile(logfileName, wxT(".bak"));
594 // Open the log file
595 if (!theLogger.OpenLogfile(logfileName.GetRaw())) {
596 // use std err as last resolt to indicate problem
597 fputs("ERROR: unable to open log file\n", stderr);
598 // failure to open log is serious problem
599 return false;
602 // Load Preferences
603 CPreferences::BuildItemList(ConfigDir);
604 CPreferences::LoadAllItems( wxConfigBase::Get() );
606 glob_prefs = new CPreferences();
608 std::pair<bool, CPath> checkResult;
609 checkResult = CheckMuleDirectory(wxT("temp"), thePrefs::GetTempDir(), ConfigDir + wxT("Temp"));
610 if (checkResult.first) {
611 thePrefs::SetTempDir(checkResult.second);
612 } else {
613 return false;
616 checkResult = CheckMuleDirectory(wxT("incoming"), thePrefs::GetIncomingDir(), ConfigDir + wxT("Incoming"));
617 if (checkResult.first) {
618 thePrefs::SetIncomingDir(checkResult.second);
619 } else {
620 return false;
623 // Some sanity check
624 if (!thePrefs::UseTrayIcon()) {
625 thePrefs::SetMinToTray(false);
628 // Build the filenames for the two OS files
629 SetOSFiles(thePrefs::GetOSDir().GetRaw());
631 #ifdef ENABLE_NLS
632 // Load localization settings
633 Localize_mule();
634 #endif
636 // Configure EC for amuled when invoked with ec-config
637 if (ec_config) {
638 AddLogLineMS(false, _("\nEC configuration"));
639 thePrefs::SetECPass(GetPassword());
640 thePrefs::EnableExternalConnections(true);
641 AddLogLineMS(false, _("Password set and external connections enabled."));
644 #ifndef __WXMSW__
645 if (getuid() == 0) {
646 wxString msg =
647 wxT("Warning! You are running aMule as root.\n")
648 wxT("Doing so is not recommended for security reasons,\n")
649 wxT("and you are advised to run aMule as an normal\n")
650 wxT("user instead.");
652 ShowAlert(msg, _("WARNING"), wxCENTRE | wxOK | wxICON_ERROR);
654 fprintf(stderr, "\n--------------------------------------------------\n");
655 fprintf(stderr, "%s", (const char*)unicode2UTF8(msg));
656 fprintf(stderr, "\n--------------------------------------------------\n\n");
658 #endif
660 // Display notification on new version or first run
661 wxTextFile vfile( ConfigDir + wxT("lastversion") );
662 wxString newMule(wxT( VERSION ));
664 if ( !wxFileExists( vfile.GetName() ) ) {
665 vfile.Create();
668 if ( vfile.Open() ) {
669 // Check if this version has been run before
670 bool found = false;
671 for ( size_t i = 0; i < vfile.GetLineCount(); i++ ) {
672 // Check if this version has been run before
673 if ( vfile.GetLine(i) == newMule ) {
674 found = true;
675 break;
679 // We havent run this version before?
680 if ( !found ) {
681 // Insert new at top to provide faster searches
682 vfile.InsertLine( newMule, 0 );
684 Trigger_New_version( newMule );
687 // Keep at most 10 entires
688 while ( vfile.GetLineCount() > 10 )
689 vfile.RemoveLine( vfile.GetLineCount() - 1 );
691 vfile.Write();
692 vfile.Close();
695 // Check if we have the old style locale config
696 wxString langId = thePrefs::GetLanguageID();
697 if (!langId.IsEmpty() && (langId.GetChar(0) >= '0' && langId.GetChar(0) <= '9')) {
698 wxString info(_("Your locale has been changed to System Default due to a configuration change. Sorry."));
699 thePrefs::SetLanguageID(wxLang2Str(wxLANGUAGE_DEFAULT));
700 ShowAlert(info, _("Info"), wxCENTRE | wxOK | wxICON_ERROR);
703 m_statistics = new CStatistics();
705 clientlist = new CClientList();
706 friendlist = new CFriendList();
707 searchlist = new CSearchList();
708 knownfiles = new CKnownFileList();
709 serverlist = new CServerList();
711 sharedfiles = new CSharedFileList(knownfiles);
712 clientcredits = new CClientCreditsList();
714 // bugfix - do this before creating the uploadqueue
715 downloadqueue = new CDownloadQueue();
716 uploadqueue = new CUploadQueue();
717 ipfilter = new CIPFilter();
719 // Creates all needed listening sockets
720 wxString msg;
721 if (!ReinitializeNetwork(&msg)) {
722 AddLogLineMS(false, wxT("\n"));
723 AddLogLineMS(false, msg);
726 // Test if there's any new version
727 if (thePrefs::CheckNewVersion()) {
728 // We use the thread base because I don't want a dialog to pop up.
729 CHTTPDownloadThread* version_check =
730 new CHTTPDownloadThread(wxT("http://amule.sourceforge.net/lastversion"),
731 theApp->ConfigDir + wxT("last_version_check"), HTTP_VersionCheck, false);
732 version_check->Create();
733 version_check->Run();
736 // Create main dialog, or fork to background (daemon).
737 InitGui(geometry_enabled, geom_string);
739 #if !defined(__WXMAC__) && defined(AMULE_DAEMON)
740 // Need to refresh wxSingleInstanceChecker after the daemon fork() !
741 if (enable_daemon_fork) {
742 //#warning TODO: fix wxSingleInstanceChecker for amuled on Mac (wx link problems)
743 delete m_singleInstance;
744 m_singleInstance = new wxSingleInstanceChecker(wxT("muleLock"), ConfigDir);
745 // No need to check IsAnotherRunning() - we've done it before.
747 #endif
749 // Has to be created after the call to InitGui, as fork
750 // (when using posix threads) only replicates the mainthread,
751 // and the UBT constructor creates a thread.
752 uploadBandwidthThrottler = new UploadBandwidthThrottler();
754 // These must be initialized after the gui is loaded.
755 serverlist->Init();
756 downloadqueue->LoadMetFiles(thePrefs::GetTempDir());
757 sharedfiles->Reload();
759 if (thePrefs::IPFilterAutoLoad()) {
760 ipfilter->Update(thePrefs::IPFilterURL());
764 // Ensure that the up/down ratio is used
765 CPreferences::CheckUlDlRatio();
767 // The user can start pressing buttons like mad if he feels like it.
768 m_app_state = APP_STATE_RUNNING;
770 // Kry - Load the sources seeds on app init
771 if (thePrefs::GetSrcSeedsOn()) {
772 downloadqueue->LoadSourceSeeds();
775 if (!serverlist->GetServerCount() && thePrefs::GetNetworkED2K()) {
776 // There are no servers and ED2K active -> ask for download.
777 // As we cannot ask in amuled, we just update there
778 // Kry TODO: Store server.met URL on preferences and use it here and in GUI.
779 #ifndef AMULE_DAEMON
780 if (wxYES == wxMessageBox(
781 wxString(
782 _("You don't have any server in the server list.\nDo you want aMule to download a new list now?")),
783 wxString(_("Server list download")),
784 wxYES_NO,
785 static_cast<wxWindow*>(theApp->amuledlg)))
786 #endif
788 // workaround amuled crash
789 #ifndef AMULE_DAEMON
790 serverlist->UpdateServerMetFromURL(
791 wxT("http://gruk.org/server.met.gz"));
792 #endif
797 // Autoconnect if that option is enabled
798 if (thePrefs::DoAutoConnect() && (thePrefs::GetNetworkED2K() || thePrefs::GetNetworkKademlia())) {
799 AddLogLineM(true, _("Connecting"));
800 if (thePrefs::GetNetworkED2K()) {
801 theApp->serverconnect->ConnectToAnyServer();
804 StartKad();
808 // Enable GeoIP
809 #ifdef ENABLE_IP2COUNTRY
810 theApp->amuledlg->EnableIP2Country();
811 #endif
813 // No webserver on Win at all (yet)
814 #ifndef __WXMSW__
815 // Run webserver?
816 if (thePrefs::GetWSIsEnabled()) {
817 wxString aMuleConfigFile = ConfigDir + wxT("amule.conf");
818 wxString amulewebPath = wxT("amuleweb");
819 if(true == cmdline.Found(wxT("use-amuleweb"), &amulewebPath)) {
820 AddLogLineNS(CFormat(_("Using amuleweb in '%s'.")) % amulewebPath);
823 #if defined(__WXMAC__) && !defined(AMULE_DAEMON)
824 // For the Mac GUI application, look for amuleweb in the bundle
825 CFURLRef amulewebUrl = CFBundleCopyAuxiliaryExecutableURL(
826 CFBundleGetMainBundle(), CFSTR("amuleweb"));
828 if (amulewebUrl) {
829 CFURLRef absoluteUrl = CFURLCopyAbsoluteURL(amulewebUrl);
830 CFRelease(amulewebUrl);
832 if (absoluteUrl) {
833 CFStringRef amulewebCfstr = CFURLCopyFileSystemPath(absoluteUrl, kCFURLPOSIXPathStyle);
834 CFRelease(absoluteUrl);
835 amulewebPath = wxMacCFStringHolder(amulewebCfstr).AsString(wxLocale::GetSystemEncoding());
838 #endif
840 wxString cmd =
841 wxT("'") +
842 amulewebPath +
843 wxT("' '--amule-config-file=") +
844 aMuleConfigFile +
845 wxT("'");
846 CTerminationProcessAmuleweb *p = new CTerminationProcessAmuleweb(cmd, &webserver_pid);
847 webserver_pid = wxExecute(cmd, wxEXEC_ASYNC, p);
848 bool webserver_ok = webserver_pid > 0;
849 if (webserver_ok) {
850 AddLogLineM(true, CFormat(_("web server running on pid %d")) % webserver_pid);
851 } else {
852 delete p;
853 ShowAlert(_(
854 "You requested to run web server on startup, but the amuleweb binary cannot be run. Please install the package containing aMule web server, or compile aMule using --enable-webserver and run make install"),
855 _("ERROR"), wxOK | wxICON_ERROR);
858 #endif /* ! __WXMSW__ */
860 // Start performing background tasks
861 CThreadScheduler::Start();
863 return true;
866 bool CamuleApp::ReinitializeNetwork(wxString* msg)
868 bool ok = true;
869 static bool firstTime = true;
871 if (!firstTime) {
872 // TODO: Destroy previously created sockets
874 firstTime = false;
876 // Some sanity checks first
877 if (thePrefs::ECPort() == thePrefs::GetPort()) {
878 // Select a random usable port in the range 1025 ... 2^16 - 1
879 uint16 port = thePrefs::ECPort();
880 while ( port < 1024 || port == thePrefs::GetPort() ) {
881 port = (uint16)rand();
883 thePrefs::SetECPort( port );
885 wxString err =
886 wxT("Network configuration failed! You cannot use the same port\n")
887 wxT("for the main TCP port and the External Connections port.\n")
888 wxT("The EC port has been changed to avoid conflict, see the\n")
889 wxT("preferences for the new value.\n");
890 *msg << err;
892 AddLogLineM( false, wxEmptyString );
893 AddLogLineM( true, err );
894 AddLogLineM( false, wxEmptyString );
896 ok = false;
899 if (thePrefs::GetUDPPort() == thePrefs::GetPort() + 3) {
900 // Select a random usable value in the range 1025 ... 2^16 - 1
901 uint16 port = thePrefs::GetUDPPort();
902 while ( port < 1024 || port == thePrefs::GetPort() + 3 ) {
903 port = (uint16)rand();
905 thePrefs::SetUDPPort( port );
907 wxString err =
908 wxT("Network configuration failed! You set your UDP port to\n")
909 wxT("the value of the main TCP port plus 3.\n")
910 wxT("This port has been reserved for the Server-UDP port. The\n")
911 wxT("port value has been changed to avoid conflict, see the\n")
912 wxT("preferences for the new value\n");
913 *msg << err;
915 AddLogLineM( false, wxEmptyString );
916 AddLogLineM( true, err );
917 AddLogLineM( false, wxEmptyString );
919 ok = false;
922 // Create the address where we are going to listen
923 // TODO: read this from configuration file
924 amuleIPV4Address myaddr[4];
926 // Create the External Connections Socket.
927 // Default is 4712.
928 // Get ready to handle connections from apps like amulecmd
929 if (thePrefs::GetECAddress().IsEmpty() || !myaddr[0].Hostname(thePrefs::GetECAddress())) {
930 myaddr[0].AnyAddress();
932 myaddr[0].Service(thePrefs::ECPort());
933 ECServerHandler = new ExternalConn(myaddr[0], msg);
935 // Create the UDP socket TCP+3.
936 // Used for source asking on servers.
937 if (thePrefs::GetAddress().IsEmpty()) {
938 myaddr[1].AnyAddress();
939 } else if (!myaddr[1].Hostname(thePrefs::GetAddress())) {
940 myaddr[1].AnyAddress();
941 AddLogLineM(true, CFormat(_("Could not bind ports to the specified address: %s"))
942 % thePrefs::GetAddress());
945 wxString ip = myaddr[1].IPAddress();
946 myaddr[1].Service(thePrefs::GetPort()+3);
947 serverconnect = new CServerConnect(serverlist, myaddr[1]);
948 *msg << CFormat( wxT("*** Server UDP socket (TCP+3) at %s:%u\n") )
949 % ip % ((unsigned int)thePrefs::GetPort() + 3u);
951 // Create the ListenSocket (aMule TCP socket).
952 // Used for Client Port / Connections from other clients,
953 // Client to Client Source Exchange.
954 // Default is 4662.
955 myaddr[2] = myaddr[1];
956 myaddr[2].Service(thePrefs::GetPort());
957 listensocket = new CListenSocket(myaddr[2]);
958 *msg << CFormat( wxT("*** TCP socket (TCP) listening on %s:%u\n") )
959 % ip % (unsigned int)(thePrefs::GetPort());
960 // This command just sets a flag to control maximum number of connections.
961 // Notify(true) has already been called to the ListenSocket, so events may
962 // be already comming in.
963 if (listensocket->Ok()) {
964 listensocket->StartListening();
965 } else {
966 // If we wern't able to start listening, we need to warn the user
967 wxString err;
968 err = CFormat(_("Port %u is not available. You will be LOWID\n")) %
969 (unsigned int)(thePrefs::GetPort());
970 *msg << err;
971 AddLogLineM(true, err);
972 err.Clear();
973 err = CFormat(
974 _("Port %u is not available!\n\nThis means that you will be LOWID.\n\nCheck your network to make sure the port is open for output and input.")) %
975 (unsigned int)(thePrefs::GetPort());
976 ShowAlert(err, _("ERROR"), wxOK | wxICON_ERROR);
979 // Create the UDP socket.
980 // Used for extended eMule protocol, Queue Rating, File Reask Ping.
981 // Also used for Kademlia.
982 // Default is port 4672.
983 myaddr[3] = myaddr[1];
984 myaddr[3].Service(thePrefs::GetUDPPort());
985 clientudp = new CClientUDPSocket(myaddr[3], thePrefs::GetProxyData());
986 if (!thePrefs::IsUDPDisabled()) {
987 *msg << CFormat( wxT("*** Client UDP socket (extended eMule) at %s:%u") )
988 % ip % thePrefs::GetUDPPort();
989 } else {
990 *msg << wxT("*** Client UDP socket (extended eMule) disabled on preferences");
993 #ifdef ENABLE_UPNP
994 if (thePrefs::GetUPnPEnabled()) {
995 try {
996 m_upnpMappings[0] = CUPnPPortMapping(
997 myaddr[0].Service(),
998 "TCP",
999 thePrefs::GetUPnPECEnabled(),
1000 "aMule TCP External Connections Socket");
1001 m_upnpMappings[1] = CUPnPPortMapping(
1002 myaddr[1].Service(),
1003 "UDP",
1004 thePrefs::GetUPnPEnabled(),
1005 "aMule UDP socket (TCP+3)");
1006 m_upnpMappings[2] = CUPnPPortMapping(
1007 myaddr[2].Service(),
1008 "TCP",
1009 thePrefs::GetUPnPEnabled(),
1010 "aMule TCP Listen Socket");
1011 m_upnpMappings[3] = CUPnPPortMapping(
1012 myaddr[3].Service(),
1013 "UDP",
1014 thePrefs::GetUPnPEnabled(),
1015 "aMule UDP Extended eMule Socket");
1016 m_upnp = new CUPnPControlPoint(thePrefs::GetUPnPTCPPort());
1017 m_upnp->AddPortMappings(m_upnpMappings);
1018 } catch(CUPnPException &e) {
1019 wxString error_msg;
1020 error_msg << e.what();
1021 AddLogLineM(true, error_msg);
1022 fprintf(stderr, "%s\n", (const char *)unicode2char(error_msg));
1025 #endif
1027 return ok;
1030 // Returns a magnet ed2k URI
1031 wxString CamuleApp::CreateMagnetLink(const CAbstractFile *f)
1033 CMagnetURI uri;
1035 uri.AddField(wxT("dn"), f->GetFileName().Cleanup(false).GetPrintable());
1036 uri.AddField(wxT("xt"), wxString(wxT("urn:ed2k:")) + f->GetFileHash().Encode().Lower());
1037 uri.AddField(wxT("xt"), wxString(wxT("urn:ed2khash:")) + f->GetFileHash().Encode().Lower());
1038 uri.AddField(wxT("xl"), wxString::Format(wxT("%") wxLongLongFmtSpec wxT("u"), f->GetFileSize()));
1040 return uri.GetLink();
1043 // Returns a ed2k file URL
1044 wxString CamuleApp::CreateED2kLink(const CAbstractFile *f, bool add_source, bool use_hostname, bool addcryptoptions)
1046 wxASSERT(!(!add_source && (use_hostname || addcryptoptions)));
1047 // Construct URL like this: ed2k://|file|<filename>|<size>|<hash>|/
1048 wxString strURL = CFormat(wxT("ed2k://|file|%s|%i|%s|/"))
1049 % f->GetFileName().Cleanup(false)
1050 % f->GetFileSize() % f->GetFileHash().Encode();
1052 if (add_source && IsConnected() && !IsFirewalled()) {
1053 // Create the first part of the URL
1054 strURL << wxT("|sources,");
1055 if (use_hostname) {
1056 strURL << thePrefs::GetYourHostname();
1057 } else {
1058 uint32 clientID = GetID();
1059 strURL << (uint8) clientID << wxT(".") <<
1060 (uint8)(clientID >> 8) << wxT(".") <<
1061 (uint8)(clientID >> 16) << wxT(".") <<
1062 (uint8)(clientID >> 24);
1065 strURL << wxT(":") <<
1066 thePrefs::GetPort();
1068 if (addcryptoptions) {
1069 const uint8 uSupportsCryptLayer = thePrefs::IsClientCryptLayerSupported() ? 1 : 0;
1070 const uint8 uRequestsCryptLayer = thePrefs::IsClientCryptLayerRequested() ? 1 : 0;
1071 const uint8 uRequiresCryptLayer = thePrefs::IsClientCryptLayerRequired() ? 1 : 0;
1072 const uint8 byCryptOptions = (uRequiresCryptLayer << 2) | (uRequestsCryptLayer << 1) | (uSupportsCryptLayer << 0) | (uSupportsCryptLayer ? 0x80 : 0x00);
1074 strURL << wxT(":") << byCryptOptions;
1076 if (byCryptOptions & 0x80) {
1077 strURL << wxT(":") << thePrefs::GetUserHash().Encode();
1080 strURL << wxT("|/");
1081 } else if (add_source) {
1082 AddLogLineM(true, _("WARNING: You can't add yourself as a source for an eD2k link while having a lowid."));
1085 // Result is "ed2k://|file|<filename>|<size>|<hash>|/|sources,[(<ip>|<hostname>):<port>[:cryptoptions[:hash]]]|/"
1086 return strURL;
1089 // Returns a ed2k link with AICH info if available
1090 wxString CamuleApp::CreateED2kAICHLink(const CKnownFile* f)
1092 // Create the first part of the URL
1093 wxString strURL = CreateED2kLink(f);
1094 // Append the AICH info
1095 if (f->HasProperAICHHashSet()) {
1096 strURL << wxT("|h=") << f->GetAICHMasterHash() << wxT("|/");
1099 // Result is "ed2k://|file|<filename>|<size>|<hash>|/|h=<AICH master hash>|/"
1100 return strURL;
1103 /* Original implementation by Bouc7 of the eMule Project.
1104 aMule Signature idea was designed by BigBob and implemented
1105 by Un-Thesis, with design inputs and suggestions from bothie.
1107 void CamuleApp::OnlineSig(bool zero /* reset stats (used on shutdown) */)
1109 // Do not do anything if online signature is disabled in Preferences
1110 if (!thePrefs::IsOnlineSignatureEnabled() || m_emulesig_path.IsEmpty()) {
1111 // We do not need to check m_amulesig_path because if m_emulesig_path is empty,
1112 // that means m_amulesig_path is empty too.
1113 return;
1116 // Remove old signature files
1117 if ( wxFileExists( m_emulesig_path ) ) { wxRemoveFile( m_emulesig_path ); }
1118 if ( wxFileExists( m_amulesig_path ) ) { wxRemoveFile( m_amulesig_path ); }
1121 wxTextFile amulesig_out;
1122 wxTextFile emulesig_out;
1124 // Open both files if needed
1125 if ( !emulesig_out.Create( m_emulesig_path) ) {
1126 AddLogLineM(true, _("Failed to create OnlineSig File"));
1127 // Will never try again.
1128 m_amulesig_path.Clear();
1129 m_emulesig_path.Clear();
1130 return;
1133 if ( !amulesig_out.Create(m_amulesig_path) ) {
1134 AddLogLineM(true, _("Failed to create aMule OnlineSig File"));
1135 // Will never try again.
1136 m_amulesig_path.Clear();
1137 m_emulesig_path.Clear();
1138 return;
1141 wxString emulesig_string;
1142 wxString temp;
1144 if (zero) {
1145 emulesig_string = wxT("0\xA0.0|0.0|0");
1146 amulesig_out.AddLine(wxT("0\n0\n0\n0\n0\n0\n0.0\n0.0\n0\n0"));
1147 } else {
1148 if (IsConnectedED2K()) {
1150 temp = wxString::Format(wxT("%d"),serverconnect->GetCurrentServer()->GetPort());
1152 // We are online
1153 emulesig_string =
1154 // Connected
1155 wxT("1|")
1156 //Server name
1157 + serverconnect->GetCurrentServer()->GetListName()
1158 + wxT("|")
1159 // IP and port of the server
1160 + serverconnect->GetCurrentServer()->GetFullIP()
1161 + wxT("|")
1162 + temp;
1165 // Now for amule sig
1167 // Connected. State 1, full info
1168 amulesig_out.AddLine(wxT("1"));
1169 // Server Name
1170 amulesig_out.AddLine(serverconnect->GetCurrentServer()->GetListName());
1171 // Server IP
1172 amulesig_out.AddLine(serverconnect->GetCurrentServer()->GetFullIP());
1173 // Server Port
1174 amulesig_out.AddLine(temp);
1176 if (serverconnect->IsLowID()) {
1177 amulesig_out.AddLine(wxT("L"));
1178 } else {
1179 amulesig_out.AddLine(wxT("H"));
1182 } else if (serverconnect->IsConnecting()) {
1183 emulesig_string = wxT("0");
1185 // Connecting. State 2, No info.
1186 amulesig_out.AddLine(wxT("2\n0\n0\n0\n0"));
1187 } else {
1188 // Not connected to a server
1189 emulesig_string = wxT("0");
1191 // Not connected, state 0, no info
1192 amulesig_out.AddLine(wxT("0\n0\n0\n0\n0"));
1194 if (IsConnectedKad()) {
1195 if(Kademlia::CKademlia::IsFirewalled()) {
1196 // Connected. Firewalled. State 1.
1197 amulesig_out.AddLine(wxT("1"));
1198 } else {
1199 // Connected. State 2.
1200 amulesig_out.AddLine(wxT("2"));
1202 } else {
1203 // Not connected.State 0.
1204 amulesig_out.AddLine(wxT("0"));
1206 emulesig_string += wxT("\xA");
1208 // Datarate for downloads
1209 temp = wxString::Format(wxT("%.1f"), theStats::GetDownloadRate() / 1024.0);
1211 emulesig_string += temp + wxT("|");
1212 amulesig_out.AddLine(temp);
1214 // Datarate for uploads
1215 temp = wxString::Format(wxT("%.1f"), theStats::GetUploadRate() / 1024.0);
1217 emulesig_string += temp + wxT("|");
1218 amulesig_out.AddLine(temp);
1220 // Number of users waiting for upload
1221 temp = wxString::Format(wxT("%d"), theStats::GetWaitingUserCount());
1223 emulesig_string += temp;
1224 amulesig_out.AddLine(temp);
1226 // Number of shared files (not on eMule)
1227 amulesig_out.AddLine(wxString::Format(wxT("%d"), theStats::GetSharedFileCount()));
1230 // eMule signature finished here. Write the line to the wxTextFile.
1231 emulesig_out.AddLine(emulesig_string);
1233 // Now for aMule signature extras
1235 // Nick on the network
1236 amulesig_out.AddLine(thePrefs::GetUserNick());
1238 // Total received in bytes
1239 amulesig_out.AddLine( CFormat( wxT("%llu") ) % (theStats::GetSessionReceivedBytes() + thePrefs::GetTotalDownloaded()) );
1241 // Total sent in bytes
1242 amulesig_out.AddLine( CFormat( wxT("%llu") ) % (theStats::GetSessionSentBytes() + thePrefs::GetTotalUploaded()) );
1244 // amule version
1245 #ifdef SVNDATE
1246 amulesig_out.AddLine(wxT(VERSION) wxT(" ") wxT(SVNDATE));
1247 #else
1248 amulesig_out.AddLine(wxT(VERSION));
1249 #endif
1251 if (zero) {
1252 amulesig_out.AddLine(wxT("0"));
1253 amulesig_out.AddLine(wxT("0"));
1254 amulesig_out.AddLine(wxT("0"));
1255 } else {
1256 // Total received bytes in session
1257 amulesig_out.AddLine( CFormat( wxT("%llu") ) %
1258 theStats::GetSessionReceivedBytes() );
1260 // Total sent bytes in session
1261 amulesig_out.AddLine( CFormat( wxT("%llu") ) %
1262 theStats::GetSessionSentBytes() );
1264 // Uptime
1265 amulesig_out.AddLine(CFormat(wxT("%llu")) % theStats::GetUptimeSeconds());
1268 // Flush the files
1269 emulesig_out.Write();
1270 amulesig_out.Write();
1271 } //End Added By Bouc7
1274 // Gracefully handle fatal exceptions and print backtrace if possible
1275 void CamuleApp::OnFatalException()
1277 /* Print the backtrace */
1278 fprintf(stderr, "\n--------------------------------------------------------------------------------\n");
1279 fprintf(stderr, "A fatal error has occurred and aMule has crashed.\n");
1280 fprintf(stderr, "Please assist us in fixing this problem by posting the backtrace below in our\n");
1281 fprintf(stderr, "'aMule Crashes' forum and include as much information as possible regarding the\n");
1282 fprintf(stderr, "circumstances of this crash. The forum is located here:\n");
1283 fprintf(stderr, " http://forum.amule.org/index.php?board=67.0\n");
1284 fprintf(stderr, "If possible, please try to generate a real backtrace of this crash:\n");
1285 fprintf(stderr, " http://www.amule.org/wiki/index.php/Backtraces\n\n");
1286 fprintf(stderr, "----------------------------=| BACKTRACE FOLLOWS: |=----------------------------\n");
1287 fprintf(stderr, "Current version is: %s\n", strFullMuleVersion);
1288 fprintf(stderr, "Running on: %s\n\n", strOSDescription);
1290 print_backtrace(1); // 1 == skip this function.
1292 fprintf(stderr, "\n--------------------------------------------------------------------------------\n");
1296 // Sets the localization of aMule
1297 void CamuleApp::Localize_mule()
1299 InitCustomLanguages();
1300 InitLocale(m_locale, StrLang2wx(thePrefs::GetLanguageID()));
1301 if (!m_locale.IsOk()) {
1302 AddLogLineM(false,_("The selected locale seems not to be installed on your box. (Note: I'll try to set it anyway)"));
1307 // Displays information related to important changes in aMule.
1308 // Is called when the user runs a new version of aMule
1309 void CamuleApp::Trigger_New_version(wxString new_version)
1311 wxString info = wxT(" --- ") + CFormat(_("This is the first time you run aMule %s")) % new_version + wxT(" ---\n\n");
1312 if (new_version == wxT("SVN")) {
1313 info += _("This version is a testing version, updated daily, and\n");
1314 info += _("we give no warranty it won't break anything, burn your house,\n");
1315 info += _("or kill your dog. But it *should* be safe to use anyway.\n");
1316 } else if (new_version == wxT("2.2.1")) {
1317 thePrefs::SetAddServersFromServer(false);
1318 thePrefs::SetAddServersFromClient(false);
1319 info += _("The following options have been changed in this release for security reasons:\n");
1320 info += _("\n* Enabled Protocol Obfuscation support for incoming and outgoing connections.\n");
1321 info += _("\n* Disabled updating the server list from other server and clients.\n");
1322 info += _("\nFor more information on the reason for this changes, seach\nthe aMule wiki at http://wiki.amule.org for \"fake servers\" info.\nIt's important that you clear any fake server from your server list for aMule to work properly.");
1323 info += _("\n\nAdditionally, the browser settings have been reset to the system default. Please configure your browser options again if needed.\n");
1326 // General info
1327 info += wxT("\n");
1328 info += _("More information, support and new releases can found at our homepage,\n");
1329 info += _("at www.aMule.org, or in our IRC channel #aMule at irc.freenode.net.\n");
1330 info += wxT("\n");
1331 info += _("Feel free to report any bugs to http://forum.amule.org");
1333 ShowAlert(info, _("Info"), wxCENTRE | wxOK | wxICON_ERROR);
1337 void CamuleApp::SetOSFiles(const wxString new_path)
1339 if ( thePrefs::IsOnlineSignatureEnabled() ) {
1340 if ( ::wxDirExists(new_path) ) {
1341 m_emulesig_path = JoinPaths(new_path, wxT("onlinesig.dat"));
1342 m_amulesig_path = JoinPaths(new_path, wxT("amulesig.dat"));
1343 } else {
1344 ShowAlert(_("The folder for Online Signature files you specified is INVALID!\n OnlineSignature will be DISABLED until you fix it on preferences."), _("ERROR"), wxOK | wxICON_ERROR);
1345 m_emulesig_path.Clear();
1346 m_amulesig_path.Clear();
1348 } else {
1349 m_emulesig_path.Clear();
1350 m_amulesig_path.Clear();
1355 #ifdef __WXDEBUG__
1356 #ifndef wxUSE_STACKWALKER
1357 #define wxUSE_STACKWALKER 0
1358 #endif
1359 void CamuleApp::OnAssertFailure(const wxChar* file, int line,
1360 const wxChar* func, const wxChar* cond, const wxChar* msg)
1362 if (!wxUSE_STACKWALKER || !wxThread::IsMain() || !IsRunning()) {
1363 wxString errmsg = CFormat( wxT("%s:%s:%d: Assertion '%s' failed. %s") )
1364 % file % func % line % cond % ( msg ? msg : wxT("") );
1366 fprintf(stderr, "Assertion failed: %s\n", (const char*)unicode2char(errmsg));
1368 // Skip the function-calls directly related to the assert call.
1369 fprintf(stderr, "\nBacktrace follows:\n");
1370 print_backtrace(3);
1371 fprintf(stderr, "\n");
1374 if (wxThread::IsMain() && IsRunning()) {
1375 AMULE_APP_BASE::OnAssertFailure(file, line, func, cond, msg);
1376 } else {
1377 // Abort, allows gdb to catch the assertion
1378 raise( SIGABRT );
1381 #endif
1384 void CamuleApp::OnUDPDnsDone(CMuleInternalEvent& evt)
1386 CServerUDPSocket* socket =(CServerUDPSocket*)evt.GetClientData();
1387 socket->OnHostnameResolved(evt.GetExtraLong());
1391 void CamuleApp::OnSourceDnsDone(CMuleInternalEvent& evt)
1393 downloadqueue->OnHostnameResolved(evt.GetExtraLong());
1397 void CamuleApp::OnServerDnsDone(CMuleInternalEvent& evt)
1399 AddLogLineMS(false, _("Server hostname notified"));
1400 serverconnect->OnServerHostnameResolved(evt.GetClientData(), evt.GetExtraLong());
1404 void CamuleApp::OnTCPTimer(CTimerEvent& WXUNUSED(evt))
1406 if(!IsRunning()) {
1407 return;
1409 serverconnect->StopConnectionTry();
1410 if (IsConnectedED2K() ) {
1411 return;
1413 serverconnect->ConnectToAnyServer();
1417 void CamuleApp::OnCoreTimer(CTimerEvent& WXUNUSED(evt))
1419 // Former TimerProc section
1420 static uint64 msPrev1, msPrev5, msPrevSave, msPrevHist, msPrevOS, msPrevKnownMet;
1421 uint64 msCur = theStats::GetUptimeMillis();
1423 if (!IsRunning()) {
1424 return;
1427 #ifndef AMULE_DAEMON
1428 // Check if we should terminate the app
1429 if ( g_shutdownSignal ) {
1430 wxWindow* top = GetTopWindow();
1432 if ( top ) {
1433 top->Close(true);
1434 } else {
1435 // No top-window, have to force termination.
1436 wxExit();
1439 #endif
1441 uploadqueue->Process();
1442 downloadqueue->Process();
1443 //theApp->clientcredits->Process();
1444 theStats::CalculateRates();
1446 if (msCur-msPrevHist > 1000) {
1447 // unlike the other loop counters in this function this one will sometimes
1448 // produce two calls in quick succession (if there was a gap of more than one
1449 // second between calls to TimerProc) - this is intentional! This way the
1450 // history list keeps an average of one node per second and gets thinned out
1451 // correctly as time progresses.
1452 msPrevHist += 1000;
1454 m_statistics->RecordHistory();
1459 if (msCur-msPrev1 > 1000) { // approximately every second
1460 msPrev1 = msCur;
1461 clientcredits->Process();
1462 clientlist->Process();
1464 // Publish files to server if needed.
1465 sharedfiles->Process();
1467 if( Kademlia::CKademlia::IsRunning() ) {
1468 Kademlia::CKademlia::Process();
1469 if(Kademlia::CKademlia::GetPrefs()->HasLostConnection()) {
1470 StopKad();
1471 clientudp->Close();
1472 clientudp->Open();
1473 if (thePrefs::Reconnect()) {
1474 StartKad();
1479 if( serverconnect->IsConnecting() && !serverconnect->IsSingleConnect() ) {
1480 serverconnect->TryAnotherConnectionrequest();
1482 if (serverconnect->IsConnecting()) {
1483 serverconnect->CheckForTimeout();
1485 listensocket->UpdateConnectionsStatus();
1490 if (msCur-msPrev5 > 5000) { // every 5 seconds
1491 msPrev5 = msCur;
1492 listensocket->Process();
1495 if (msCur-msPrevSave >= 60000) {
1496 msPrevSave = msCur;
1497 wxString buffer;
1499 // Save total upload/download to preferences
1500 wxConfigBase* cfg = wxConfigBase::Get();
1501 buffer = CFormat(wxT("%llu")) % (theStats::GetSessionReceivedBytes() + thePrefs::GetTotalDownloaded());
1502 cfg->Write(wxT("/Statistics/TotalDownloadedBytes"), buffer);
1504 buffer = CFormat(wxT("%llu")) % (theStats::GetSessionSentBytes() + thePrefs::GetTotalUploaded());
1505 cfg->Write(wxT("/Statistics/TotalUploadedBytes"), buffer);
1507 // Write changes to file
1508 cfg->Flush();
1512 // Special
1513 if (msCur - msPrevOS >= thePrefs::GetOSUpdate() * 1000ull) {
1514 OnlineSig(); // Added By Bouc7
1515 msPrevOS = msCur;
1518 if (msCur - msPrevKnownMet >= 30*60*1000/*There must be a prefs option for this*/) {
1519 // Save Shared Files data
1520 knownfiles->Save();
1521 msPrevKnownMet = msCur;
1525 // Recomended by lugdunummaster himself - from emule 0.30c
1526 serverconnect->KeepConnectionAlive();
1531 void CamuleApp::OnFinishedHashing(CHashingEvent& evt)
1533 wxCHECK_RET(evt.GetResult(), wxT("No result of hashing"));
1535 CKnownFile* owner = const_cast<CKnownFile*>(evt.GetOwner());
1536 CKnownFile* result = evt.GetResult();
1538 if (owner) {
1539 // Check if the partfile still exists, as it might have
1540 // been deleted in the mean time.
1541 if (downloadqueue->IsPartFile(owner)) {
1542 // This cast must not be done before the IsPartFile
1543 // call, as dynamic_cast will barf on dangling pointers.
1544 dynamic_cast<CPartFile*>(owner)->PartFileHashFinished(result);
1546 } else {
1547 static int filecount;
1548 static uint64 bytecount;
1550 if (knownfiles->SafeAddKFile(result)) {
1551 AddDebugLogLineM(false, logKnownFiles,
1552 CFormat(wxT("Safe adding file to sharedlist: %s")) % result->GetFileName());
1553 sharedfiles->SafeAddKFile(result);
1555 filecount++;
1556 bytecount += result->GetFileSize();
1557 // If we have added 30 files or files with a total size of ~300mb
1558 if ( ( filecount == 30 ) || ( bytecount >= 314572800 ) ) {
1559 AddDebugLogLineM(false, logKnownFiles, wxT("Failsafe for crash on file hashing creation"));
1560 if ( m_app_state != APP_STATE_SHUTTINGDOWN ) {
1561 knownfiles->Save();
1562 filecount = 0;
1563 bytecount = 0;
1566 } else {
1567 AddDebugLogLineM(false, logKnownFiles,
1568 CFormat(wxT("File not added to sharedlist: %s")) % result->GetFileName());
1569 delete result;
1575 void CamuleApp::OnFinishedAICHHashing(CHashingEvent& evt)
1577 wxCHECK_RET(evt.GetResult(), wxT("No result of AICH-hashing"));
1579 CKnownFile* owner = const_cast<CKnownFile*>(evt.GetOwner());
1580 std::auto_ptr<CKnownFile> result(evt.GetResult());
1582 // Check that the owner is still valid
1583 if (knownfiles->IsKnownFile(owner)) {
1584 if (result->GetAICHHashset()->GetStatus() == AICH_HASHSETCOMPLETE) {
1585 CAICHHashSet* oldSet = owner->GetAICHHashset();
1586 CAICHHashSet* newSet = result->GetAICHHashset();
1588 owner->SetAICHHashset(newSet);
1589 newSet->SetOwner(owner);
1591 result->SetAICHHashset(oldSet);
1592 oldSet->SetOwner(result.get());
1598 void CamuleApp::OnFinishedCompletion(CCompletionEvent& evt)
1600 CPartFile* completed = const_cast<CPartFile*>(evt.GetOwner());
1601 wxCHECK_RET(completed, wxT("Completion event sent for unspecified file"));
1602 wxASSERT_MSG(downloadqueue->IsPartFile(completed), wxT("CCompletionEvent for unknown partfile."));
1604 completed->CompleteFileEnded(evt.ErrorOccured(), evt.GetFullPath());
1605 if (evt.ErrorOccured()) {
1606 CUserEvents::ProcessEvent(CUserEvents::ErrorOnCompletion, completed);
1609 // Check if we should execute an script/app/whatever.
1610 CUserEvents::ProcessEvent(CUserEvents::DownloadCompleted, completed);
1613 void CamuleApp::OnFinishedAllocation(CAllocFinishedEvent& evt)
1615 CPartFile *file = evt.GetFile();
1616 wxCHECK_RET(file, wxT("Allocation finished event sent for unspecified file"));
1617 wxASSERT_MSG(downloadqueue->IsPartFile(file), wxT("CAllocFinishedEvent for unknown partfile"));
1619 file->SetPartFileStatus(PS_EMPTY);
1621 if (evt.Succeeded()) {
1622 if (evt.IsPaused()) {
1623 file->StopFile();
1624 } else {
1625 file->ResumeFile();
1627 } else {
1628 AddLogLineM(false, CFormat(_("Disk space preallocation for file '%s' failed: %s")) % file->GetFileName() % wxString(UTF82unicode(std::strerror(evt.GetResult()))));
1629 file->StopFile();
1632 file->AllocationFinished();
1635 void CamuleApp::OnNotifyEvent(CMuleGUIEvent& evt)
1637 #if defined(AMULE_DAEMON)
1638 evt.Notify();
1639 #else
1640 if (theApp->amuledlg) {
1641 evt.Notify();
1643 #endif
1647 void CamuleApp::ShutDown()
1649 // Log
1650 AddDebugLogLineM(false, logGeneral, wxT("CamuleApp::ShutDown() has started."));
1652 // Signal the hashing thread to terminate
1653 m_app_state = APP_STATE_SHUTTINGDOWN;
1655 StopKad();
1657 // Kry - Save the sources seeds on app exit
1658 if (thePrefs::GetSrcSeedsOn()) {
1659 downloadqueue->SaveSourceSeeds();
1662 OnlineSig(true); // Added By Bouc7
1664 // Close sockets to avoid new clients coming in
1665 if (listensocket) {
1666 listensocket->Close();
1667 listensocket->KillAllSockets();
1670 if (serverconnect) {
1671 serverconnect->Disconnect();
1674 ECServerHandler->KillAllSockets();
1676 #ifdef ENABLE_UPNP
1677 if (thePrefs::GetUPnPEnabled()) {
1678 if (m_upnp) {
1679 m_upnp->DeletePortMappings(m_upnpMappings);
1682 #endif
1684 // saving data & stuff
1685 if (knownfiles) {
1686 knownfiles->Save();
1689 thePrefs::Add2TotalDownloaded(theStats::GetSessionReceivedBytes());
1690 thePrefs::Add2TotalUploaded(theStats::GetSessionSentBytes());
1692 if (glob_prefs) {
1693 glob_prefs->Save();
1696 if (clientlist) {
1697 clientlist->DeleteAll();
1700 CThreadScheduler::Terminate();
1702 theApp->uploadBandwidthThrottler->EndThread();
1704 // Log
1705 AddDebugLogLineM(false, logGeneral, wxT("CamuleApp::ShutDown() has ended."));
1709 bool CamuleApp::AddServer(CServer *srv, bool fromUser)
1711 if ( serverlist->AddServer(srv, fromUser) ) {
1712 Notify_ServerAdd(srv);
1713 return true;
1715 return false;
1719 uint32 CamuleApp::GetPublicIP(bool ignorelocal) const
1721 if (m_dwPublicIP == 0) {
1722 if (Kademlia::CKademlia::IsConnected() && Kademlia::CKademlia::GetIPAddress() ) {
1723 return wxUINT32_SWAP_ALWAYS(Kademlia::CKademlia::GetIPAddress());
1724 } else {
1725 return ignorelocal ? 0 : m_localip;
1729 return m_dwPublicIP;
1733 void CamuleApp::SetPublicIP(const uint32 dwIP)
1735 wxASSERT((dwIP == 0) || !IsLowID(dwIP));
1737 if (dwIP != 0 && dwIP != m_dwPublicIP && serverlist != NULL) {
1738 m_dwPublicIP = dwIP;
1739 serverlist->CheckForExpiredUDPKeys();
1740 } else {
1741 m_dwPublicIP = dwIP;
1746 wxString CamuleApp::GetLog(bool reset)
1748 ConfigDir = GetConfigDir();
1749 wxFile logfile;
1750 logfile.Open(ConfigDir + wxT("logfile"));
1751 if ( !logfile.IsOpened() ) {
1752 return _("ERROR: can't open logfile");
1754 int len = logfile.Length();
1755 if ( len == 0 ) {
1756 return _("WARNING: logfile is empty. Something is wrong.");
1758 char *tmp_buffer = new char[len + sizeof(wxChar)];
1759 logfile.Read(tmp_buffer, len);
1760 memset(tmp_buffer + len, 0, sizeof(wxChar));
1762 // try to guess file format
1763 wxString str;
1764 if (tmp_buffer[0] && tmp_buffer[1]) {
1765 str = wxString(UTF82unicode(tmp_buffer));
1766 } else {
1767 str = wxString((wxWCharBuffer&)tmp_buffer);
1770 delete [] tmp_buffer;
1771 if ( reset ) {
1772 theLogger.CloseLogfile();
1773 if (theLogger.OpenLogfile(ConfigDir + wxT("logfile"))) {
1774 AddLogLineM(false, _("Log has been reset"));
1777 return str;
1781 wxString CamuleApp::GetServerLog(bool reset)
1783 wxString ret = server_msg;
1784 if ( reset ) {
1785 server_msg.Clear();
1787 return ret;
1790 wxString CamuleApp::GetDebugLog(bool reset)
1792 return GetLog(reset);
1796 void CamuleApp::AddServerMessageLine(wxString &msg)
1798 server_msg += msg + wxT("\n");
1799 AddLogLineM(false, CFormat(_("ServerMessage: %s")) % msg);
1804 void CamuleApp::OnFinishedHTTPDownload(CMuleInternalEvent& event)
1806 switch (event.GetInt()) {
1807 case HTTP_IPFilter:
1808 ipfilter->DownloadFinished(event.GetExtraLong());
1809 break;
1810 case HTTP_ServerMet:
1811 serverlist->DownloadFinished(event.GetExtraLong());
1812 break;
1813 case HTTP_ServerMetAuto:
1814 serverlist->AutoDownloadFinished(event.GetExtraLong());
1815 break;
1816 case HTTP_VersionCheck:
1817 CheckNewVersion(event.GetExtraLong());
1818 break;
1819 case HTTP_NodesDat:
1820 if (event.GetExtraLong() != -1) {
1822 wxString file = ConfigDir + wxT("nodes.dat");
1823 if (wxFileExists(file)) {
1824 wxRemoveFile(file);
1827 if ( Kademlia::CKademlia::IsRunning() ) {
1828 Kademlia::CKademlia::Stop();
1831 wxRenameFile(file + wxT(".download"),file);
1833 Kademlia::CKademlia::Start();
1834 theApp->ShowConnectionState();
1836 } else {
1837 AddLogLineM(true, _("Failed to download the nodes list."));
1839 break;
1840 #ifdef ENABLE_IP2COUNTRY
1841 case HTTP_GeoIP:
1842 theApp->amuledlg->IP2CountryDownloadFinished(event.GetExtraLong());
1843 // If we updated, the dialog is already up. Redraw it to show the flags.
1844 theApp->amuledlg->Refresh();
1845 break;
1846 #endif
1850 void CamuleApp::CheckNewVersion(uint32 result)
1852 if (result == 1) {
1853 wxString filename = ConfigDir + wxT("last_version_check");
1854 wxTextFile file;
1856 if (!file.Open(filename)) {
1857 AddLogLineM(true, _("Failed to open the downloaded version check file") );
1858 return;
1859 } else if (!file.GetLineCount()) {
1860 AddLogLineM(true, _("Corrupted version check file"));
1861 } else {
1862 wxString versionLine = file.GetFirstLine();
1863 wxStringTokenizer tkz(versionLine, wxT("."));
1865 AddDebugLogLineM(false, logGeneral, wxString(wxT("Running: ")) + wxT(VERSION) + wxT(", Version check: ") + versionLine);
1867 long fields[] = {0, 0, 0};
1868 for (int i = 0; i < 3; ++i) {
1869 if (!tkz.HasMoreTokens()) {
1870 AddLogLineM(true, _("Corrupted version check file"));
1871 return;
1872 } else {
1873 wxString token = tkz.GetNextToken();
1875 if (!token.ToLong(&fields[i])) {
1876 AddLogLineM(true, _("Corrupted version check file"));
1877 return;
1882 long curVer = make_full_ed2k_version(VERSION_MJR, VERSION_MIN, VERSION_UPDATE);
1883 long newVer = make_full_ed2k_version(fields[0], fields[1], fields[2]);
1885 if (curVer < newVer) {
1886 AddLogLineM(true, _("You are using an outdated version of aMule!"));
1887 AddLogLineM(false, wxString::Format(_("Your aMule version is %i.%i.%i and the latest version is %li.%li.%li"), VERSION_MJR, VERSION_MIN, VERSION_UPDATE, fields[0], fields[1], fields[2]));
1888 AddLogLineM(false, _("The latest version can always be found at http://www.amule.org"));
1889 #ifdef AMULE_DAEMON
1890 AddLogLineMS(true, CFormat(_("WARNING: Your aMuled version is outdated: %i.%i.%i < %li.%li.%li"))
1891 % VERSION_MJR % VERSION_MIN % VERSION_UPDATE % fields[0] % fields[1] % fields[2]);
1892 #endif
1893 } else {
1894 AddLogLineM(false, _("Your copy of aMule is up to date."));
1898 file.Close();
1899 wxRemoveFile(filename);
1900 } else {
1901 AddLogLineM(true, _("Failed to download the version check file") );
1907 bool CamuleApp::IsConnected() const
1909 return (IsConnectedED2K() || IsConnectedKad());
1913 bool CamuleApp::IsConnectedED2K() const
1915 return serverconnect && serverconnect->IsConnected();
1919 bool CamuleApp::IsConnectedKad() const
1921 return Kademlia::CKademlia::IsConnected();
1925 bool CamuleApp::IsFirewalled() const
1927 if (theApp->IsConnectedED2K() && !theApp->serverconnect->IsLowID()) {
1928 return false; // we have an eD2K HighID -> not firewalled
1931 return IsFirewalledKad(); // If kad says ok, it's ok.
1934 bool CamuleApp::IsFirewalledKad() const
1936 return !Kademlia::CKademlia::IsConnected() // not connected counts as firewalled
1937 || Kademlia::CKademlia::IsFirewalled();
1940 bool CamuleApp::IsFirewalledKadUDP() const
1942 return !Kademlia::CKademlia::IsConnected() // not connected counts as firewalled
1943 || Kademlia::CUDPFirewallTester::IsFirewalledUDP(true);
1946 bool CamuleApp::IsKadRunning() const
1948 return Kademlia::CKademlia::IsRunning();
1951 // Kad stats
1952 uint32 CamuleApp::GetKadUsers() const
1954 return Kademlia::CKademlia::GetKademliaUsers();
1957 uint32 CamuleApp::GetKadFiles() const
1959 return Kademlia::CKademlia::GetKademliaFiles();
1962 uint32 CamuleApp::GetKadIndexedSources() const
1964 return Kademlia::CKademlia::GetIndexed()->m_totalIndexSource;
1967 uint32 CamuleApp::GetKadIndexedKeywords() const
1969 return Kademlia::CKademlia::GetIndexed()->m_totalIndexKeyword;
1972 uint32 CamuleApp::GetKadIndexedNotes() const
1974 return Kademlia::CKademlia::GetIndexed()->m_totalIndexNotes;
1977 uint32 CamuleApp::GetKadIndexedLoad() const
1979 return Kademlia::CKademlia::GetIndexed()->m_totalIndexLoad;
1983 // True IP of machine
1984 uint32 CamuleApp::GetKadIPAdress() const
1986 return wxUINT32_SWAP_ALWAYS(Kademlia::CKademlia::GetPrefs()->GetIPAddress());
1989 // Buddy status
1990 uint8 CamuleApp::GetBuddyStatus() const
1992 return clientlist->GetBuddyStatus();
1995 uint32 CamuleApp::GetBuddyIP() const
1997 return clientlist->GetBuddy()->GetIP();
2000 uint32 CamuleApp::GetBuddyPort() const
2002 return clientlist->GetBuddy()->GetUDPPort();
2005 bool CamuleApp::DoCallback( CUpDownClient *client )
2007 if(Kademlia::CKademlia::IsConnected()) {
2008 if(IsConnectedED2K()) {
2009 if(serverconnect->IsLowID()) {
2010 if(Kademlia::CKademlia::IsFirewalled()) {
2011 //Both Connected - Both Firewalled
2012 return false;
2013 } else {
2014 if(client->GetServerIP() == theApp->serverconnect->GetCurrentServer()->GetIP() &&
2015 client->GetServerPort() == theApp->serverconnect->GetCurrentServer()->GetPort()) {
2016 // Both Connected - Server lowID, Kad Open - Client on same server
2017 // We prevent a callback to the server as this breaks the protocol
2018 // and will get you banned.
2019 return false;
2020 } else {
2021 // Both Connected - Server lowID, Kad Open - Client on remote server
2022 return true;
2025 } else {
2026 //Both Connected - Server HighID, Kad don't care
2027 return true;
2029 } else {
2030 if(Kademlia::CKademlia::IsFirewalled()) {
2031 //Only Kad Connected - Kad Firewalled
2032 return false;
2033 } else {
2034 //Only Kad Conected - Kad Open
2035 return true;
2038 } else {
2039 if( IsConnectedED2K() ) {
2040 if( serverconnect->IsLowID() ) {
2041 //Only Server Connected - Server LowID
2042 return false;
2043 } else {
2044 //Only Server Connected - Server HighID
2045 return true;
2047 } else {
2048 //We are not connected at all!
2049 return false;
2054 void CamuleApp::ShowUserCount() {
2055 uint32 totaluser = 0, totalfile = 0;
2057 theApp->serverlist->GetUserFileStatus( totaluser, totalfile );
2059 wxString buffer;
2061 static const wxString s_singlenetstatusformat = _("Users: %s | Files: %s");
2062 static const wxString s_bothnetstatusformat = _("Users: E: %s K: %s | Files: E: %s K: %s");
2064 if (thePrefs::GetNetworkED2K() && thePrefs::GetNetworkKademlia()) {
2065 buffer = CFormat(s_bothnetstatusformat) % CastItoIShort(totaluser) % CastItoIShort(Kademlia::CKademlia::GetKademliaUsers()) % CastItoIShort(totalfile) % CastItoIShort(Kademlia::CKademlia::GetKademliaFiles());
2066 } else if (thePrefs::GetNetworkED2K()) {
2067 buffer = CFormat(s_singlenetstatusformat) % CastItoIShort(totaluser) % CastItoIShort(totalfile);
2068 } else if (thePrefs::GetNetworkKademlia()) {
2069 buffer = CFormat(s_singlenetstatusformat) % CastItoIShort(Kademlia::CKademlia::GetKademliaUsers()) % CastItoIShort(Kademlia::CKademlia::GetKademliaFiles());
2070 } else {
2071 buffer = _("No networks selected");
2074 Notify_ShowUserCount(buffer);
2078 void CamuleApp::ListenSocketHandler(wxSocketEvent& event)
2080 wxCHECK_RET(listensocket, wxT("Connection-event for NULL'd listen-socket"));
2081 wxCHECK_RET(event.GetSocketEvent() == wxSOCKET_CONNECTION,
2082 wxT("Invalid event received for listen-socket"));
2084 if (m_app_state == APP_STATE_RUNNING) {
2085 listensocket->OnAccept(0);
2086 } else if (m_app_state == APP_STATE_STARTING) {
2087 // When starting up, connection may be made before we are able
2088 // to handle them. However, if these are ignored, no futher
2089 // connection-events will be triggered, so we have to accept it.
2090 wxSocketBase* socket = listensocket->Accept(false);
2092 wxCHECK_RET(socket, wxT("NULL returned by Accept() during startup"));
2094 socket->Destroy();
2099 void CamuleApp::ShowConnectionState()
2101 static uint8 old_state = (1<<7); // This flag doesn't exist
2103 uint8 state = 0;
2105 if (theApp->serverconnect->IsConnected()) {
2106 state |= CONNECTED_ED2K;
2109 if (Kademlia::CKademlia::IsRunning()) {
2110 if (Kademlia::CKademlia::IsConnected()) {
2111 if (!Kademlia::CKademlia::IsFirewalled()) {
2112 state |= CONNECTED_KAD_OK;
2113 } else {
2114 state |= CONNECTED_KAD_FIREWALLED;
2116 } else {
2117 state |= CONNECTED_KAD_NOT;
2121 Notify_ShowConnState(state);
2123 if (old_state != state) {
2124 // Get the changed value
2125 int changed_flags = old_state ^ state;
2127 if (changed_flags & CONNECTED_ED2K) {
2128 // ED2K status changed
2129 wxString connected_server;
2130 CServer* ed2k_server = theApp->serverconnect->GetCurrentServer();
2131 if (ed2k_server) {
2132 connected_server = ed2k_server->GetListName();
2134 if (state & CONNECTED_ED2K) {
2135 // We connected to some server
2136 const wxString id = theApp->serverconnect->IsLowID() ? _("with LowID") : _("with HighID");
2138 AddLogLineM(true, CFormat(_("Connected to %s %s")) % connected_server % id);
2139 } else {
2140 if ( theApp->serverconnect->IsConnecting() ) {
2141 AddLogLineM(true, CFormat(_("Connecting to %s")) % connected_server);
2142 } else {
2143 AddLogLineM(true, _("Disconnected from eD2k"));
2148 if (changed_flags & CONNECTED_KAD_NOT) {
2149 if (state & CONNECTED_KAD_NOT) {
2150 AddLogLineM(true, _("Kad started."));
2151 } else {
2152 AddLogLineM(true, _("Kad stopped."));
2156 if (changed_flags & (CONNECTED_KAD_OK | CONNECTED_KAD_FIREWALLED)) {
2157 if (state & (CONNECTED_KAD_OK | CONNECTED_KAD_FIREWALLED)) {
2158 if (state & CONNECTED_KAD_OK) {
2159 AddLogLineM(true, _("Connected to Kad (ok)"));
2160 } else {
2161 AddLogLineM(true, _("Connected to Kad (firewalled)"));
2163 } else {
2164 AddLogLineM(true, _("Disconnected from Kad"));
2168 old_state = state;
2170 theApp->downloadqueue->OnConnectionState(IsConnected());
2173 ShowUserCount();
2174 Notify_ShowConnState(state);
2178 void CamuleApp::UDPSocketHandler(wxSocketEvent& event)
2180 CMuleUDPSocket* socket = (CMuleUDPSocket*)(event.GetClientData());
2181 wxCHECK_RET(socket, wxT("No socket owner specified."));
2183 if (IsOnShutDown() || thePrefs::IsUDPDisabled()) return;
2185 if (!IsRunning()) {
2186 if (event.GetSocketEvent() == wxSOCKET_INPUT) {
2187 // Back to the queue!
2188 theApp->AddPendingEvent(event);
2189 return;
2193 switch (event.GetSocketEvent()) {
2194 case wxSOCKET_INPUT:
2195 socket->OnReceive(0);
2196 break;
2198 case wxSOCKET_OUTPUT:
2199 socket->OnSend(0);
2200 break;
2202 case wxSOCKET_LOST:
2203 socket->OnDisconnected(0);
2204 break;
2206 default:
2207 wxFAIL;
2208 break;
2213 void CamuleApp::OnUnhandledException()
2215 // Call the generic exception-handler.
2216 fprintf(stderr, "\taMule Version: %s\n", (const char*)unicode2char(GetFullMuleVersion()));
2217 ::OnUnhandledException();
2220 void CamuleApp::StartKad()
2222 if (!Kademlia::CKademlia::IsRunning() && thePrefs::GetNetworkKademlia()) {
2223 // Kad makes no sense without the Client-UDP socket.
2224 if (!thePrefs::IsUDPDisabled()) {
2225 Kademlia::CKademlia::Start();
2226 } else {
2227 AddLogLineM(true,_("Kad network cannot be used if UDP port is disabled on preferences, not starting."));
2229 } else if (!thePrefs::GetNetworkKademlia()) {
2230 AddLogLineM(true,_("Kad network disabled on preferences, not connecting."));
2234 void CamuleApp::StopKad()
2236 // Stop Kad if it's running
2237 if (Kademlia::CKademlia::IsRunning()) {
2238 Kademlia::CKademlia::Stop();
2243 void CamuleApp::BootstrapKad(uint32 ip, uint16 port)
2245 if (!Kademlia::CKademlia::IsRunning()) {
2246 Kademlia::CKademlia::Start();
2247 theApp->ShowConnectionState();
2250 Kademlia::CKademlia::Bootstrap(ip, port, true);
2254 void CamuleApp::UpdateNotesDat(const wxString& url)
2256 wxString strTempFilename(theApp->ConfigDir + wxT("nodes.dat.download"));
2258 CHTTPDownloadThread *downloader = new CHTTPDownloadThread(url, strTempFilename, HTTP_NodesDat);
2259 downloader->Create();
2260 downloader->Run();
2264 void CamuleApp::DisconnectED2K()
2266 // Stop ED2K if it's running
2267 if (IsConnectedED2K()) {
2268 serverconnect->Disconnect();
2272 bool CamuleApp::CryptoAvailable() const
2274 return clientcredits && clientcredits->CryptoAvailable();
2277 uint32 CamuleApp::GetED2KID() const {
2278 return serverconnect ? serverconnect->GetClientID() : 0;
2281 uint32 CamuleApp::GetID() const {
2282 uint32 ID;
2284 if( Kademlia::CKademlia::IsConnected() && !Kademlia::CKademlia::IsFirewalled() ) {
2285 // We trust Kad above ED2K
2286 ID = ENDIAN_NTOHL(Kademlia::CKademlia::GetIPAddress());
2287 } else if( theApp->serverconnect->IsConnected() ) {
2288 ID = theApp->serverconnect->GetClientID();
2289 } else if ( Kademlia::CKademlia::IsConnected() && Kademlia::CKademlia::IsFirewalled() ) {
2290 // A firewalled Kad client get's a "1"
2291 ID = 1;
2292 } else {
2293 ID = 0;
2296 return ID;
2299 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_FINISHED_HTTP_DOWNLOAD)
2300 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_SOURCE_DNS_DONE)
2301 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_UDP_DNS_DONE)
2302 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_SERVER_DNS_DONE)
2303 // File_checked_for_headers