Upstream tarball 20080603
[amule.git] / src / amule.cpp
blobac0df96ebce197fc0623b050e04304be8a66c613
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 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 "ClientCreditsList.h" // Needed for CClientCreditsList
57 #include "ClientList.h" // Needed for CClientList
58 #include "ClientUDPSocket.h" // Needed for CClientUDPSocket & CMuleUDPSocket
59 #include "ExternalConn.h" // Needed for ExternalConn & MuleConnection
60 #include <common/FileFunctions.h> // Needed for CDirIterator
61 #include "FriendList.h" // Needed for CFriendList
62 #include "HTTPDownload.h" // Needed for CHTTPDownloadThread
63 #include "InternalEvents.h" // Needed for CMuleInternalEvent
64 #include "IPFilter.h" // Needed for CIPFilter
65 #include "KnownFileList.h" // Needed for CKnownFileList
66 #include "ListenSocket.h" // Needed for CListenSocket
67 #include "Logger.h" // Needed for CLogger // Do_not_auto_remove
68 #include "MagnetURI.h" // Needed for CMagnetURI
69 #include "OtherFunctions.h"
70 #include "PartFile.h" // Needed for CPartFile
71 #include "Preferences.h" // Needed for CPreferences
72 #include "SearchList.h" // Needed for CSearchList
73 #include "Server.h" // Needed for GetListName
74 #include "ServerList.h" // Needed for CServerList
75 #include "ServerConnect.h" // Needed for CServerConnect
76 #include "ServerUDPSocket.h" // Needed for CServerUDPSocket
77 #include "Statistics.h" // Needed for CStatistics
78 #include "TerminationProcessAmuleweb.h" // Needed for CTerminationProcessAmuleweb
79 #include "ThreadTasks.h"
80 #include "updownclient.h" // Needed for CUpDownClient
81 #include "UploadQueue.h" // Needed for CUploadQueue
82 #include "UploadBandwidthThrottler.h"
83 #include "UserEvents.h"
85 #ifdef ENABLE_UPNP
86 #include "UPnP.h" // Needed for UPnP
87 #endif
89 #ifdef __WXMAC__
90 #include <wx/sysopt.h> // Do_not_auto_remove
91 #endif
93 #ifndef AMULE_DAEMON
94 #ifdef __WXMAC__
95 #include <CoreFoundation/CFBundle.h> // Do_not_auto_remove
96 #include <wx/mac/corefoundation/cfstring.h> // Do_not_auto_remove
97 #endif
98 #include <wx/msgdlg.h>
100 #include "amuleDlg.h"
101 #endif
104 #ifdef HAVE_SYS_RESOURCE_H
105 #include <sys/resource.h>
106 #endif
108 #ifdef HAVE_SYS_STATVFS_H
109 #include <sys/statvfs.h> // Do_not_auto_remove
110 #endif
113 #ifdef __GLIBC__
114 # define RLIMIT_RESOURCE __rlimit_resource
115 #else
116 # define RLIMIT_RESOURCE int
117 #endif
119 static void UnlimitResource(RLIMIT_RESOURCE resType)
121 #if defined(HAVE_GETRLIMIT) && defined(HAVE_SETRLIMIT)
122 struct rlimit rl;
123 getrlimit(resType, &rl);
124 rl.rlim_cur = rl.rlim_max;
125 setrlimit(resType, &rl);
126 #endif
130 static void SetResourceLimits()
132 #ifdef HAVE_SYS_RESOURCE_H
133 UnlimitResource(RLIMIT_DATA);
134 UnlimitResource(RLIMIT_FSIZE);
135 UnlimitResource(RLIMIT_NOFILE);
136 #ifdef RLIMIT_RSS
137 UnlimitResource(RLIMIT_RSS);
138 #endif
139 #endif
142 // We store the received signal in order to avoid race-conditions
143 // in the signal handler.
144 bool g_shutdownSignal = false;
146 void OnShutdownSignal( int /* sig */ )
148 signal(SIGINT, SIG_DFL);
149 signal(SIGTERM, SIG_DFL);
151 g_shutdownSignal = true;
153 #ifdef AMULE_DAEMON
154 theApp->ExitMainLoop();
155 #endif
159 CamuleApp::CamuleApp()
161 // Madcat - Initialize timer as the VERY FIRST thing to avoid any issues later.
162 // Kry - I love to init the vars on init, even before timer.
163 StartTickTimer();
165 // Initialization
166 m_app_state = APP_STATE_STARTING;
168 theApp = &wxGetApp();
170 clientlist = NULL;
171 searchlist = NULL;
172 knownfiles = NULL;
173 serverlist = NULL;
174 serverconnect = NULL;
175 sharedfiles = NULL;
176 listensocket = NULL;
177 clientudp = NULL;
178 clientcredits = NULL;
179 friendlist = NULL;
180 downloadqueue = NULL;
181 uploadqueue = NULL;
182 ipfilter = NULL;
183 ECServerHandler = NULL;
184 m_singleInstance= NULL;
185 glob_prefs = NULL;
186 m_statistics = NULL;
187 uploadBandwidthThrottler = NULL;
188 #ifdef ENABLE_UPNP
189 m_upnp = NULL;
190 m_upnpMappings.resize(4);
191 #endif
192 core_timer = NULL;
193 applog = NULL;
195 m_localip = 0;
196 m_dwPublicIP = 0;
197 webserver_pid = 0;
199 enable_stdout_log = false;
200 enable_daemon_fork = false;
202 strFullMuleVersion = NULL;
203 strOSDescription = NULL;
205 // Apprently needed for *BSD
206 SetResourceLimits();
209 CamuleApp::~CamuleApp()
211 // Closing the log-file as the very last thing, since
212 // wxWidgets log-events are saved in it as well.
213 delete applog;
214 applog = NULL;
216 free(strFullMuleVersion);
217 free(strOSDescription);
220 int CamuleApp::OnExit()
222 if (m_app_state!=APP_STATE_STARTING) {
223 printf("Now, exiting main app...\n");
226 // From wxWidgets docs, wxConfigBase:
227 // ...
228 // Note that you must delete this object (usually in wxApp::OnExit)
229 // in order to avoid memory leaks, wxWidgets won't do it automatically.
231 // As it happens, you may even further simplify the procedure described
232 // above: you may forget about calling Set(). When Get() is called and
233 // there is no current object, it will create one using Create() function.
234 // To disable this behaviour DontCreateOnDemand() is provided.
235 delete wxConfigBase::Set((wxConfigBase *)NULL);
237 // Save credits
238 clientcredits->SaveList();
240 // Kill amuleweb if running
241 if (webserver_pid) {
242 printf("Killing amuleweb instance with pid `%ld' ... ", webserver_pid);
243 wxKillError rc;
244 wxKill(webserver_pid, wxSIGTERM, &rc);
245 printf("Killed!\n");
248 if (m_app_state!=APP_STATE_STARTING) {
249 printf("aMule OnExit: Terminating core.\n");
252 delete serverlist;
253 serverlist = NULL;
255 delete searchlist;
256 searchlist = NULL;
258 delete clientcredits;
259 clientcredits = NULL;
261 delete friendlist;
262 friendlist = NULL;
264 // Destroying CDownloadQueue calls destructor for CPartFile
265 // calling CSharedFileList::SafeAddKFile occasionally.
266 delete sharedfiles;
267 sharedfiles = NULL;
269 delete serverconnect;
270 serverconnect = NULL;
272 delete listensocket;
273 listensocket = NULL;
275 delete clientudp;
276 clientudp = NULL;
278 delete knownfiles;
279 knownfiles = NULL;
281 delete clientlist;
282 clientlist = NULL;
284 delete uploadqueue;
285 uploadqueue = NULL;
287 delete downloadqueue;
288 downloadqueue = NULL;
290 delete ipfilter;
291 ipfilter = NULL;
293 #ifdef ENABLE_UPNP
294 delete m_upnp;
295 m_upnp = NULL;
296 #endif
298 delete ECServerHandler;
299 ECServerHandler = NULL;
301 delete m_statistics;
302 m_statistics = NULL;
304 delete glob_prefs;
305 glob_prefs = NULL;
306 CPreferences::EraseItemList();
308 #if defined(__WXMAC__) && defined(AMULE_DAEMON)
309 //#warning TODO: fix wxSingleInstanceChecker for amuled on Mac (wx link problems)
310 #else
311 delete m_singleInstance;
312 #endif
313 m_singleInstance = NULL;
315 delete uploadBandwidthThrottler;
316 uploadBandwidthThrottler = NULL;
318 if (m_app_state!=APP_STATE_STARTING) {
319 printf("aMule shutdown completed.\n");
322 #if wxUSE_MEMORY_TRACING
323 printf("Memory debug results for aMule exit:\n");
324 // Log mem debug mesages to wxLogStderr
325 wxLog* oldLog = wxLog::SetActiveTarget(new wxLogStderr);
327 printf("**************Classes**************\n");
328 wxDebugContext::PrintClasses();
330 //printf("***************Dump***************\n");
331 //wxDebugContext::Dump();
332 printf("***************Stats**************\n");
333 wxDebugContext::PrintStatistics(true);
335 // Set back to wxLogGui
336 delete wxLog::SetActiveTarget(oldLog);
337 #endif
339 StopTickTimer();
341 // Return 0 for succesful program termination
342 return AMULE_APP_BASE::OnExit();
346 int CamuleApp::InitGui(bool, wxString &)
348 return 0;
353 * Checks permissions on a aMule directory, creating if needed.
355 * @param desc A description of the directory in question, used for error messages.
356 * @param directory The directory in question.
357 * @param fallback If the dir specified with 'directory' could not be created, try this instead.
358 * @return The bool is false on error. The wxString contains the used path.
360 std::pair<bool, CPath> CheckMuleDirectory(const wxString& desc, const CPath& directory, const wxString& alternative)
362 wxString msg;
364 if (directory.IsDir(CPath::readwritable)) {
365 return std::pair<bool, CPath>(true, directory);
366 } else if (directory.DirExists()) {
367 msg = CFormat(wxT("Permissions on the %s directory too strict!\n")
368 wxT("aMule cannot proceed. To fix this, you must set read/write/exec\n")
369 wxT("permissions for the folder '%s'"))
370 % desc % directory;
371 } else if (CPath::MakeDir(directory)) {
372 return std::pair<bool, CPath>(true, directory);
373 } else {
374 msg << CFormat(wxT("Could not create the %s directory at '%s'."))
375 % desc % directory;
378 // Attempt to use fallback directory.
379 const CPath fallback = CPath(alternative);
380 if (fallback.IsOk() && (directory != fallback)) {
381 msg << wxT("\nAttempting to use default directory at location \n'")
382 << alternative << wxT("'.");
383 theApp->ShowAlert(msg, wxT("Error accessing directory."), wxICON_ERROR | wxOK);
385 return CheckMuleDirectory(desc, fallback, wxEmptyString);
388 theApp->ShowAlert(msg, wxT("Fatal error."), wxICON_ERROR | wxOK);
389 return std::pair<bool, wxString>(false, wxEmptyString);
394 // Application initialization
396 bool CamuleApp::OnInit()
398 #if wxUSE_MEMORY_TRACING
399 printf("Checkpoint set on app init for memory debug\n");
400 wxDebugContext::SetCheckpoint();
401 #endif
403 // Forward wxLog events to CLogger
404 wxLog::SetActiveTarget(new CLoggerTarget);
406 m_localip = StringHosttoUint32(::wxGetFullHostName());
408 #ifndef __WXMSW__
409 // get rid of sigpipe
410 signal(SIGPIPE, SIG_IGN);
411 // Handle sigint and sigterm
412 signal(SIGINT, OnShutdownSignal);
413 signal(SIGTERM, OnShutdownSignal);
414 #endif
416 #ifdef __WXMAC__
417 // For listctrl's to behave on Mac
418 wxSystemOptions::SetOption(wxT("mac.listctrl.always_use_generic"), 1);
419 #endif
421 // This can't be on constructor or wx2.4.2 doesn't set it.
422 #if !wxCHECK_VERSION(2, 9, 0)
423 SetVendorName(wxT("TikuWarez"));
424 #endif
425 SetAppName(wxT("aMule"));
427 wxString FullMuleVersion = GetFullMuleVersion();
428 wxString OSDescription = wxGetOsDescription();
429 strFullMuleVersion = strdup((const char *)unicode2char(FullMuleVersion));
430 strOSDescription = strdup((const char *)unicode2char(OSDescription));
431 OSType = OSDescription.BeforeFirst( wxT(' ') );
432 if ( OSType.IsEmpty() ) {
433 OSType = wxT("Unknown");
436 // Handle uncaught exceptions
437 InstallMuleExceptionHandler();
439 // Parse cmdline arguments.
440 wxCmdLineParser cmdline(AMULE_APP_BASE::argc, AMULE_APP_BASE::argv);
442 // Handle these arguments.
443 cmdline.AddSwitch(wxT("v"), wxT("version"), wxT("Displays the current version number."));
444 cmdline.AddSwitch(wxT("h"), wxT("help"), wxT("Displays this information."));
445 cmdline.AddSwitch(wxT("i"), wxT("enable-stdin"), wxT("Does not disable stdin."));
446 #ifdef AMULE_DAEMON
447 cmdline.AddSwitch(wxT("f"), wxT("full-daemon"), wxT("Fork to background."));
448 cmdline.AddOption(wxT("c"), wxT("config-dir"), wxT("read config from <dir> instead of home"));
449 cmdline.AddSwitch(wxT("e"), wxT("ec-config"), wxT("Configure EC (External Connections)."));
450 #else
451 cmdline.AddOption(wxT("geometry"), wxEmptyString,
452 wxT("Sets the geometry of the app.\n")
453 wxT("\t\t\t<str> uses the same format as standard X11 apps:\n")
454 wxT("\t\t\t[=][<width>{xX}<height>][{+-}<xoffset>{+-}<yoffset>]"));
455 #endif
456 cmdline.AddSwitch(wxT("d"), wxT("disable-fatal"), wxT("Does not handle fatal exception."));
457 cmdline.AddSwitch(wxT("o"), wxT("log-stdout"), wxT("Print log messages to stdout."));
458 cmdline.AddSwitch(wxT("r"), wxT("reset-config"), wxT("Resets config to default values."));
460 // Show help on --help or invalid commands
461 if ( cmdline.Parse() ) {
462 return false;
463 } else if ( cmdline.Found(wxT("help")) ) {
464 cmdline.Usage();
465 return false;
468 bool ec_config = false;
470 #ifdef AMULE_DAEMON
471 ec_config = cmdline.Found(wxT("ec-config"));
472 if ( cmdline.Found(wxT("config-dir"), &ConfigDir) ) {
473 if (ConfigDir.Last() != wxFileName::GetPathSeparator()) {
474 ConfigDir += wxFileName::GetPathSeparator();
476 } else {
477 ConfigDir = GetConfigDir();
479 #else
480 ConfigDir = GetConfigDir();
481 #endif
483 if ( !cmdline.Found(wxT("disable-fatal")) ) {
484 #ifndef __WXMSW__
485 // catch fatal exceptions
486 wxHandleFatalExceptions(true);
487 #endif
490 bool reset_config = cmdline.Found(wxT("reset-config"));
492 enable_stdout_log = cmdline.Found(wxT("log-stdout"));
493 #ifdef AMULE_DAEMON
494 enable_daemon_fork = cmdline.Found(wxT("full-daemon"));
495 #else
496 enable_daemon_fork = false;
497 #endif
499 if ( enable_stdout_log ) {
500 if ( enable_daemon_fork ) {
501 printf("Daemon will fork to background - log to stdout disabled\n");
502 enable_stdout_log = false;
503 } else {
504 printf("Logging to stdout enabled\n");
508 if ( cmdline.Found(wxT("version")) ) {
509 printf("%s (OS: %s)\n",
510 (const char*)unicode2char(GetFullMuleVersion()),
511 (const char*)unicode2char(OSType));
513 return false;
516 // Default geometry of the GUI. Can be changed with a cmdline argument...
517 bool geometry_enabled = false;
518 wxString geom_string;
519 #ifndef AMULE_DAEMON
520 if ( cmdline.Found(wxT("geometry"), &geom_string) ) {
521 geometry_enabled = true;
523 #endif
526 printf("Initialising aMule\n");
528 // Ensure that "~/.aMule/" is accessible.
529 if (!CheckMuleDirectory(wxT("configuration"), CPath(ConfigDir), wxEmptyString).first) {
530 return false;
533 if (reset_config) {
534 // Make a backup first.
535 wxRemoveFile(ConfigDir + wxT("amule.conf.backup"));
536 wxRenameFile(ConfigDir + wxT("amule.conf"), ConfigDir + wxT("amule.conf.backup"));
537 printf("Your settings have ben resetted to default values.\nOld config file has been saved as amule.conf.backup\n");
540 #if defined(__WXMAC__) && defined(AMULE_DAEMON)
541 //#warning TODO: fix wxSingleInstanceChecker for amuled on Mac (wx link problems)
542 printf("WARNING: The check for other instances is currently disabled in amuled.\n"
543 "Please make sure that no other instance of aMule is running or your files might be corrupted.\n");
544 #else
545 printf("Checking if there is an instance already running...\n");
547 m_singleInstance = new wxSingleInstanceChecker(wxT("muleLock"), ConfigDir);
548 if (m_singleInstance->IsAnotherRunning()) {
549 printf("There is an instance of aMule already running\n");
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 printf("Raising current running instance.\n");
562 } else {
563 printf("Failed to open 'ED2KFile', cannot signal running instance.\n");
566 return false;
567 } else {
568 printf("No other instances are running.\n");
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 applog = new wxFFileOutputStream(logfileName.GetRaw());
596 if (!applog->Ok()) {
597 // use std err as last resolt to indicate problem
598 fputs("ERROR: unable to open log file\n", stderr);
599 delete applog;
600 applog = NULL;
601 // failure to open log is serious problem
602 return false;
605 // Load Preferences
606 CPreferences::BuildItemList(ConfigDir);
607 CPreferences::LoadAllItems( wxConfigBase::Get() );
609 glob_prefs = new CPreferences();
611 std::pair<bool, CPath> checkResult;
612 checkResult = CheckMuleDirectory(wxT("temp"), thePrefs::GetTempDir(), ConfigDir + wxT("Temp"));
613 if (checkResult.first) {
614 thePrefs::SetTempDir(checkResult.second);
615 } else {
616 return false;
619 checkResult = CheckMuleDirectory(wxT("incoming"), thePrefs::GetIncomingDir(), ConfigDir + wxT("Incoming"));
620 if (checkResult.first) {
621 thePrefs::SetIncomingDir(checkResult.second);
622 } else {
623 return false;
626 // Some sanity check
627 if (!thePrefs::UseTrayIcon()) {
628 thePrefs::SetMinToTray(false);
631 // Build the filenames for the two OS files
632 SetOSFiles(thePrefs::GetOSDir().GetRaw());
634 #ifdef ENABLE_NLS
635 // Load localization settings
636 Localize_mule();
637 #endif
639 // Configure EC for amuled when invoked with ec-config
640 if (ec_config) {
641 printf("\nEC configuration\n");
642 thePrefs::SetECPass(GetPassword());
643 thePrefs::EnableExternalConnections(true);
644 printf("Password set and external connections enabled.\n");
647 // Display notification on new version or first run
648 wxTextFile vfile( ConfigDir + wxT("lastversion") );
649 wxString newMule(wxT( VERSION ));
651 // Test if there's any new version
652 if (thePrefs::CheckNewVersion()) {
653 // We use the thread base because I don't want a dialog to pop up.
654 CHTTPDownloadThread* version_check =
655 new CHTTPDownloadThread(wxT("http://amule.sourceforge.net/lastversion"),
656 theApp->ConfigDir + wxT("last_version_check"), HTTP_VersionCheck, false);
657 version_check->Create();
658 version_check->Run();
661 if ( !wxFileExists( vfile.GetName() ) ) {
662 vfile.Create();
665 #ifndef __WXMSW__
666 if (getuid() == 0) {
667 wxString msg =
668 wxT("Warning! You are running aMule as root.\n")
669 wxT("Doing so is not recommended for security reasons,\n")
670 wxT("and you are advised to run aMule as an normal\n")
671 wxT("user instead.");
673 ShowAlert(msg, _("Warning"), wxCENTRE | wxOK | wxICON_ERROR);
675 fprintf(stderr, "\n--------------------------------------------------\n");
676 fprintf(stderr, "%s", (const char*)unicode2UTF8(msg));
677 fprintf(stderr, "\n--------------------------------------------------\n\n");
679 #endif
681 if ( vfile.Open() ) {
682 // Check if this version has been run before
683 bool found = false;
684 for ( size_t i = 0; i < vfile.GetLineCount(); i++ ) {
685 // Check if this version has been run before
686 if ( vfile.GetLine(i) == newMule ) {
687 found = true;
688 break;
692 // We havent run this version before?
693 if ( !found ) {
694 // Insert new at top to provide faster searches
695 vfile.InsertLine( newMule, 0 );
697 Trigger_New_version( newMule );
700 // Keep at most 10 entires
701 while ( vfile.GetLineCount() > 10 )
702 vfile.RemoveLine( vfile.GetLineCount() - 1 );
704 vfile.Write();
705 vfile.Close();
708 // Check if we have the old style locale config
709 wxString langId = thePrefs::GetLanguageID();
710 if (!langId.IsEmpty() && (langId.GetChar(0) >= '0' && langId.GetChar(0) <= '9')) {
711 wxString info(_("Your locale has been changed to System Default due to a configuration change. Sorry."));
712 thePrefs::SetLanguageID(wxLang2Str(wxLANGUAGE_DEFAULT));
713 ShowAlert(info, _("Info"), wxCENTRE | wxOK | wxICON_ERROR);
716 m_statistics = new CStatistics();
718 clientlist = new CClientList();
719 friendlist = new CFriendList();
720 searchlist = new CSearchList();
721 knownfiles = new CKnownFileList();
722 serverlist = new CServerList();
724 sharedfiles = new CSharedFileList(knownfiles);
725 clientcredits = new CClientCreditsList();
727 // bugfix - do this before creating the uploadqueue
728 downloadqueue = new CDownloadQueue();
729 uploadqueue = new CUploadQueue();
730 ipfilter = new CIPFilter();
732 // Creates all needed listening sockets
733 wxString msg;
734 if (!ReinitializeNetwork(&msg)) {
735 printf("\n%s\n", (const char *)unicode2char(msg));
738 // Create main dialog, or fork to background (daemon).
739 InitGui(geometry_enabled, geom_string);
741 #if !defined(__WXMAC__) && defined(AMULE_DAEMON)
742 // Need to refresh wxSingleInstanceChecker after the daemon fork() !
743 if (enable_daemon_fork) {
744 //#warning TODO: fix wxSingleInstanceChecker for amuled on Mac (wx link problems)
745 delete m_singleInstance;
746 m_singleInstance = new wxSingleInstanceChecker(wxT("muleLock"), ConfigDir);
747 // No need to check IsAnotherRunning() - we've done it before.
749 #endif
751 // Has to be created after the call to InitGui, as fork
752 // (when using posix threads) only replicates the mainthread,
753 // and the UBT constructor creates a thread.
754 uploadBandwidthThrottler = new UploadBandwidthThrottler();
756 // These must be initialized after the gui is loaded.
757 serverlist->Init();
758 downloadqueue->LoadMetFiles(thePrefs::GetTempDir());
759 sharedfiles->Reload();
761 if (thePrefs::IPFilterAutoLoad()) {
762 ipfilter->Update(thePrefs::IPFilterURL());
766 // Ensure that the up/down ratio is used
767 CPreferences::CheckUlDlRatio();
769 // The user can start pressing buttons like mad if he feels like it.
770 m_app_state = APP_STATE_RUNNING;
772 // Kry - Load the sources seeds on app init
773 if (thePrefs::GetSrcSeedsOn()) {
774 downloadqueue->LoadSourceSeeds();
777 if (!serverlist->GetServerCount() && thePrefs::GetNetworkED2K()) {
778 // There are no servers and ED2K active -> ask for download.
779 // As we cannot ask in amuled, we just update there
780 // Kry TODO: Store server.met URL on preferences and use it here and in GUI.
781 #ifndef AMULE_DAEMON
782 if (wxYES == wxMessageBox(
783 wxString(
784 _("You don't have any server in the server list.\nDo you want aMule to download a new list now?")),
785 wxString(_("Server list download")),
786 wxYES_NO,
787 static_cast<wxWindow*>(theApp->amuledlg)))
788 #endif
790 // workaround amuled crash
791 #ifndef AMULE_DAEMON
792 serverlist->UpdateServerMetFromURL(
793 wxT("http://gruk.org/server.met.gz"));
794 #endif
799 // Autoconnect if that option is enabled
800 if (thePrefs::DoAutoConnect() && (thePrefs::GetNetworkED2K() || thePrefs::GetNetworkKademlia())) {
801 AddLogLineM(true, _("Connecting"));
802 if (thePrefs::GetNetworkED2K()) {
803 theApp->serverconnect->ConnectToAnyServer();
806 StartKad();
810 // No webserver on Win at all (yet)
811 #ifndef __WXMSW__
812 // Run webserver?
813 if (thePrefs::GetWSIsEnabled()) {
814 wxString aMuleConfigFile = ConfigDir + wxT("amule.conf");
815 wxString amulewebPath = wxT("amuleweb");
817 #if defined(__WXMAC__) && !defined(AMULE_DAEMON)
818 // For the Mac GUI application, look for amuleweb in the bundle
819 CFURLRef amulewebUrl = CFBundleCopyAuxiliaryExecutableURL(
820 CFBundleGetMainBundle(), CFSTR("amuleweb"));
822 if (amulewebUrl) {
823 CFURLRef absoluteUrl = CFURLCopyAbsoluteURL(amulewebUrl);
824 CFRelease(amulewebUrl);
826 if (absoluteUrl) {
827 CFStringRef amulewebCfstr = CFURLCopyFileSystemPath(absoluteUrl, kCFURLPOSIXPathStyle);
828 CFRelease(absoluteUrl);
829 amulewebPath = wxMacCFStringHolder(amulewebCfstr).AsString(wxLocale::GetSystemEncoding());
832 #endif
834 wxString cmd =
835 wxT("'") +
836 amulewebPath +
837 wxT("' '--amule-config-file=") +
838 aMuleConfigFile +
839 wxT("'");
840 CTerminationProcessAmuleweb *p = new CTerminationProcessAmuleweb(cmd, &webserver_pid);
841 webserver_pid = wxExecute(cmd, wxEXEC_ASYNC, p);
842 bool webserver_ok = webserver_pid > 0;
843 if (webserver_ok) {
844 AddLogLineM(true, CFormat(_("webserver running on pid %d")) % webserver_pid);
845 } else {
846 delete p;
847 ShowAlert(_(
848 "You requested to run webserver from startup, "
849 "but the amuleweb binary cannot be run. "
850 "Please install the package containing aMule webserver, "
851 "or compile aMule using --enable-webserver and run make install"),
852 _("Error"), wxOK | wxICON_ERROR);
855 #endif /* ! __WXMSW__ */
857 // Start performing background tasks
858 CThreadScheduler::Start();
860 return true;
863 bool CamuleApp::ReinitializeNetwork(wxString* msg)
865 bool ok = true;
866 static bool firstTime = true;
868 if (!firstTime) {
869 // TODO: Destroy previously created sockets
871 firstTime = false;
873 // Some sanity checks first
874 if (thePrefs::ECPort() == thePrefs::GetPort()) {
875 // Select a random usable port in the range 1025 ... 2^16 - 1
876 uint16 port = thePrefs::ECPort();
877 while ( port < 1024 || port == thePrefs::GetPort() ) {
878 port = (uint16)rand();
880 thePrefs::SetECPort( port );
882 wxString err =
883 wxT("Network configuration failed! You cannot use the same port\n")
884 wxT("for the main TCP port and the External Connections port.\n")
885 wxT("The EC port has been changed to avoid conflict, see the\n")
886 wxT("preferences for the new value.\n");
887 *msg << err;
889 AddLogLineM( false, wxEmptyString );
890 AddLogLineM( true, err );
891 AddLogLineM( false, wxEmptyString );
893 ok = false;
896 if (thePrefs::GetUDPPort() == thePrefs::GetPort() + 3) {
897 // Select a random usable value in the range 1025 ... 2^16 - 1
898 uint16 port = thePrefs::GetUDPPort();
899 while ( port < 1024 || port == thePrefs::GetPort() + 3 ) {
900 port = (uint16)rand();
902 thePrefs::SetUDPPort( port );
904 wxString err =
905 wxT("Network configuration failed! You set your UDP port to\n")
906 wxT("the value of the main TCP port plus 3.\n")
907 wxT("This port has been reserved for the Server-UDP port. The\n")
908 wxT("port value has been changed to avoid conflict, see the\n")
909 wxT("preferences for the new value\n");
910 *msg << err;
912 AddLogLineM( false, wxEmptyString );
913 AddLogLineM( true, err );
914 AddLogLineM( false, wxEmptyString );
916 ok = false;
919 // Create the address where we are going to listen
920 // TODO: read this from configuration file
921 amuleIPV4Address myaddr[4];
923 // Create the External Connections Socket.
924 // Default is 4712.
925 // Get ready to handle connections from apps like amulecmd
926 if (thePrefs::GetECAddress().IsEmpty() || !myaddr[0].Hostname(thePrefs::GetECAddress())) {
927 myaddr[0].AnyAddress();
929 myaddr[0].Service(thePrefs::ECPort());
930 ECServerHandler = new ExternalConn(myaddr[0], msg);
932 // Create the UDP socket TCP+3.
933 // Used for source asking on servers.
934 if (thePrefs::GetAddress().IsEmpty()) {
935 myaddr[1].AnyAddress();
936 } else if (!myaddr[1].Hostname(thePrefs::GetAddress())) {
937 myaddr[1].AnyAddress();
938 AddLogLineM(true, CFormat(_("Could not bind ports to the specified address: %s"))
939 % thePrefs::GetAddress());
942 wxString ip = myaddr[1].IPAddress();
943 myaddr[1].Service(thePrefs::GetPort()+3);
944 serverconnect = new CServerConnect(serverlist, myaddr[1]);
945 *msg << CFormat( wxT("*** Server UDP socket (TCP+3) at %s:%u\n") )
946 % ip % ((unsigned int)thePrefs::GetPort() + 3u);
948 // Create the ListenSocket (aMule TCP socket).
949 // Used for Client Port / Connections from other clients,
950 // Client to Client Source Exchange.
951 // Default is 4662.
952 myaddr[2] = myaddr[1];
953 myaddr[2].Service(thePrefs::GetPort());
954 listensocket = new CListenSocket(myaddr[2]);
955 *msg << CFormat( wxT("*** TCP socket (TCP) listening on %s:%u\n") )
956 % ip % (unsigned int)(thePrefs::GetPort());
957 // This command just sets a flag to control maximum number of connections.
958 // Notify(true) has already been called to the ListenSocket, so events may
959 // be already comming in.
960 if (listensocket->Ok()) {
961 listensocket->StartListening();
962 } else {
963 // If we wern't able to start listening, we need to warn the user
964 wxString err;
965 err = CFormat(_("Port %u is not available. You will be LOWID\n")) %
966 (unsigned int)(thePrefs::GetPort());
967 *msg << err;
968 AddLogLineM(true, err);
969 err.Clear();
970 err = CFormat(
971 _("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.")) %
972 (unsigned int)(thePrefs::GetPort());
973 ShowAlert(err, _("Error"), wxOK | wxICON_ERROR);
976 // Create the UDP socket.
977 // Used for extended eMule protocol, Queue Rating, File Reask Ping.
978 // Also used for Kademlia.
979 // Default is port 4672.
980 myaddr[3] = myaddr[1];
981 myaddr[3].Service(thePrefs::GetUDPPort());
982 clientudp = new CClientUDPSocket(myaddr[3], thePrefs::GetProxyData());
983 if (!thePrefs::IsUDPDisabled()) {
984 *msg << CFormat( wxT("*** Client UDP socket (extended eMule) at %s:%u") )
985 % ip % thePrefs::GetUDPPort();
986 } else {
987 *msg << wxT("*** Client UDP socket (extended eMule) disabled on preferences");
990 #ifdef ENABLE_UPNP
991 if (thePrefs::GetUPnPEnabled()) {
992 try {
993 m_upnpMappings[0] = CUPnPPortMapping(
994 myaddr[0].Service(),
995 "TCP",
996 thePrefs::GetUPnPECEnabled(),
997 "aMule TCP External Connections Socket");
998 m_upnpMappings[1] = CUPnPPortMapping(
999 myaddr[1].Service(),
1000 "UDP",
1001 thePrefs::GetUPnPEnabled(),
1002 "aMule UDP socket (TCP+3)");
1003 m_upnpMappings[2] = CUPnPPortMapping(
1004 myaddr[2].Service(),
1005 "TCP",
1006 thePrefs::GetUPnPEnabled(),
1007 "aMule TCP Listen Socket");
1008 m_upnpMappings[3] = CUPnPPortMapping(
1009 myaddr[3].Service(),
1010 "UDP",
1011 thePrefs::GetUPnPEnabled(),
1012 "aMule UDP Extended eMule Socket");
1013 m_upnp = new CUPnPControlPoint(thePrefs::GetUPnPTCPPort());
1014 m_upnp->AddPortMappings(m_upnpMappings);
1015 } catch(CUPnPException &e) {
1016 wxString error_msg;
1017 error_msg << e.what();
1018 AddLogLineM(true, error_msg);
1019 fprintf(stderr, "%s\n", (const char *)unicode2char(error_msg));
1022 #endif
1024 return ok;
1027 // Returns a magnet ed2k URI
1028 wxString CamuleApp::CreateMagnetLink(const CAbstractFile *f)
1030 CMagnetURI uri;
1032 uri.AddField(wxT("dn"), f->GetFileName().Cleanup(false).GetPrintable());
1033 uri.AddField(wxT("xt"), wxString(wxT("urn:ed2k:")) + f->GetFileHash().Encode().Lower());
1034 uri.AddField(wxT("xl"), wxString::Format(wxT("%") wxLongLongFmtSpec wxT("u"), f->GetFileSize()));
1036 return uri.GetLink();
1039 // Returns a ed2k file URL
1040 wxString CamuleApp::CreateED2kLink(const CAbstractFile *f, bool add_source, bool use_hostname, bool addcryptoptions)
1042 wxASSERT(!(!add_source && (use_hostname || addcryptoptions)));
1043 // Construct URL like this: ed2k://|file|<filename>|<size>|<hash>|/
1044 wxString strURL = CFormat(wxT("ed2k://|file|%s|%i|%s|/"))
1045 % f->GetFileName().Cleanup(false)
1046 % f->GetFileSize() % f->GetFileHash().Encode();
1048 if (add_source && IsConnected() && !IsFirewalled()) {
1049 // Create the first part of the URL
1050 strURL << wxT("|sources,");
1051 if (use_hostname) {
1052 strURL << thePrefs::GetYourHostname();
1053 } else {
1054 uint32 clientID = GetID();
1055 strURL << (uint8) clientID << wxT(".") <<
1056 (uint8)(clientID >> 8) << wxT(".") <<
1057 (uint8)(clientID >> 16) << wxT(".") <<
1058 (uint8)(clientID >> 24);
1061 strURL << wxT(":") <<
1062 thePrefs::GetPort();
1064 if (addcryptoptions) {
1065 const uint8 uSupportsCryptLayer = thePrefs::IsClientCryptLayerSupported() ? 1 : 0;
1066 const uint8 uRequestsCryptLayer = thePrefs::IsClientCryptLayerRequested() ? 1 : 0;
1067 const uint8 uRequiresCryptLayer = thePrefs::IsClientCryptLayerRequired() ? 1 : 0;
1068 const uint8 byCryptOptions = (uRequiresCryptLayer << 2) | (uRequestsCryptLayer << 1) | (uSupportsCryptLayer << 0) | (uSupportsCryptLayer ? 0x80 : 0x00);
1070 strURL << wxT(":") << byCryptOptions;
1072 if (byCryptOptions & 0x80) {
1073 strURL << wxT(":") << thePrefs::GetUserHash().Encode();
1076 strURL << wxT("|/");
1077 } else if (add_source) {
1078 AddLogLineM(true, _("WARNING: You can't add yourself as a source for a ed2k link while being lowid."));
1081 // Result is "ed2k://|file|<filename>|<size>|<hash>|/|sources,[(<ip>|<hostname>):<port>[:cryptoptions[:hash]]]|/"
1082 return strURL;
1085 // Returns a ed2k link with AICH info if available
1086 wxString CamuleApp::CreateED2kAICHLink(const CKnownFile* f)
1088 // Create the first part of the URL
1089 wxString strURL = CreateED2kLink(f);
1090 // Append the AICH info
1091 if (f->HasProperAICHHashSet()) {
1092 strURL << wxT("|h=") << f->GetAICHMasterHash() << wxT("|/");
1095 // Result is "ed2k://|file|<filename>|<size>|<hash>|/|h=<AICH master hash>|/"
1096 return strURL;
1099 /* Original implementation by Bouc7 of the eMule Project.
1100 aMule Signature idea was designed by BigBob and implemented
1101 by Un-Thesis, with design inputs and suggestions from bothie.
1103 void CamuleApp::OnlineSig(bool zero /* reset stats (used on shutdown) */)
1105 // Do not do anything if online signature is disabled in Preferences
1106 if (!thePrefs::IsOnlineSignatureEnabled() || m_emulesig_path.IsEmpty()) {
1107 // We do not need to check m_amulesig_path because if m_emulesig_path is empty,
1108 // that means m_amulesig_path is empty too.
1109 return;
1112 // Remove old signature files
1113 if ( wxFileExists( m_emulesig_path ) ) { wxRemoveFile( m_emulesig_path ); }
1114 if ( wxFileExists( m_amulesig_path ) ) { wxRemoveFile( m_amulesig_path ); }
1117 wxTextFile amulesig_out;
1118 wxTextFile emulesig_out;
1120 // Open both files if needed
1121 if ( !emulesig_out.Create( m_emulesig_path) ) {
1122 AddLogLineM(true, _("Failed to create OnlineSig File"));
1123 // Will never try again.
1124 m_amulesig_path.Clear();
1125 m_emulesig_path.Clear();
1126 return;
1129 if ( !amulesig_out.Create(m_amulesig_path) ) {
1130 AddLogLineM(true, _("Failed to create aMule OnlineSig File"));
1131 // Will never try again.
1132 m_amulesig_path.Clear();
1133 m_emulesig_path.Clear();
1134 return;
1137 wxString emulesig_string;
1138 wxString temp;
1140 if (zero) {
1141 emulesig_string = wxT("0\xA0.0|0.0|0");
1142 amulesig_out.AddLine(wxT("0\n0\n0\n0\n0\n0\n0.0\n0.0\n0\n0"));
1143 } else {
1144 if (IsConnectedED2K()) {
1146 temp = wxString::Format(wxT("%d"),serverconnect->GetCurrentServer()->GetPort());
1148 // We are online
1149 emulesig_string =
1150 // Connected
1151 wxT("1|")
1152 //Server name
1153 + serverconnect->GetCurrentServer()->GetListName()
1154 + wxT("|")
1155 // IP and port of the server
1156 + serverconnect->GetCurrentServer()->GetFullIP()
1157 + wxT("|")
1158 + temp;
1161 // Now for amule sig
1163 // Connected. State 1, full info
1164 amulesig_out.AddLine(wxT("1"));
1165 // Server Name
1166 amulesig_out.AddLine(serverconnect->GetCurrentServer()->GetListName());
1167 // Server IP
1168 amulesig_out.AddLine(serverconnect->GetCurrentServer()->GetFullIP());
1169 // Server Port
1170 amulesig_out.AddLine(temp);
1172 if (serverconnect->IsLowID()) {
1173 amulesig_out.AddLine(wxT("L"));
1174 } else {
1175 amulesig_out.AddLine(wxT("H"));
1178 } else if (serverconnect->IsConnecting()) {
1179 emulesig_string = wxT("0");
1181 // Connecting. State 2, No info.
1182 amulesig_out.AddLine(wxT("2\n0\n0\n0\n0"));
1183 } else {
1184 // Not connected to a server
1185 emulesig_string = wxT("0");
1187 // Not connected, state 0, no info
1188 amulesig_out.AddLine(wxT("0\n0\n0\n0\n0"));
1190 if (IsConnectedKad()) {
1191 if(Kademlia::CKademlia::IsFirewalled()) {
1192 // Connected. Firewalled. State 1.
1193 amulesig_out.AddLine(wxT("1"));
1194 } else {
1195 // Connected. State 2.
1196 amulesig_out.AddLine(wxT("2"));
1198 } else {
1199 // Not connected.State 0.
1200 amulesig_out.AddLine(wxT("0"));
1202 emulesig_string += wxT("\xA");
1204 // Datarate for downloads
1205 temp = wxString::Format(wxT("%.1f"), theStats::GetDownloadRate() / 1024.0);
1207 emulesig_string += temp + wxT("|");
1208 amulesig_out.AddLine(temp);
1210 // Datarate for uploads
1211 temp = wxString::Format(wxT("%.1f"), theStats::GetUploadRate() / 1024.0);
1213 emulesig_string += temp + wxT("|");
1214 amulesig_out.AddLine(temp);
1216 // Number of users waiting for upload
1217 temp = wxString::Format(wxT("%d"), theStats::GetWaitingUserCount());
1219 emulesig_string += temp;
1220 amulesig_out.AddLine(temp);
1222 // Number of shared files (not on eMule)
1223 amulesig_out.AddLine(wxString::Format(wxT("%d"), theStats::GetSharedFileCount()));
1226 // eMule signature finished here. Write the line to the wxTextFile.
1227 emulesig_out.AddLine(emulesig_string);
1229 // Now for aMule signature extras
1231 // Nick on the network
1232 amulesig_out.AddLine(thePrefs::GetUserNick());
1234 // Total received in bytes
1235 amulesig_out.AddLine( CFormat( wxT("%llu") ) % (theStats::GetSessionReceivedBytes() + thePrefs::GetTotalDownloaded()) );
1237 // Total sent in bytes
1238 amulesig_out.AddLine( CFormat( wxT("%llu") ) % (theStats::GetSessionSentBytes() + thePrefs::GetTotalUploaded()) );
1240 // amule version
1241 #ifdef SVNDATE
1242 amulesig_out.AddLine(wxT(VERSION " " SVNDATE));
1243 #else
1244 amulesig_out.AddLine(wxT(VERSION));
1245 #endif
1247 if (zero) {
1248 amulesig_out.AddLine(wxT("0"));
1249 amulesig_out.AddLine(wxT("0"));
1250 amulesig_out.AddLine(wxT("0"));
1251 } else {
1252 // Total received bytes in session
1253 amulesig_out.AddLine( CFormat( wxT("%llu") ) %
1254 theStats::GetSessionReceivedBytes() );
1256 // Total sent bytes in session
1257 amulesig_out.AddLine( CFormat( wxT("%llu") ) %
1258 theStats::GetSessionSentBytes() );
1260 // Uptime
1261 amulesig_out.AddLine(CFormat(wxT("%llu")) % theStats::GetUptimeSeconds());
1264 // Flush the files
1265 emulesig_out.Write();
1266 amulesig_out.Write();
1267 } //End Added By Bouc7
1270 // Gracefully handle fatal exceptions and print backtrace if possible
1271 void CamuleApp::OnFatalException()
1273 /* Print the backtrace */
1274 fprintf(stderr, "\n--------------------------------------------------------------------------------\n");
1275 fprintf(stderr, "A fatal error has occurred and aMule has crashed.\n");
1276 fprintf(stderr, "Please assist us in fixing this problem by posting the backtrace below in our\n");
1277 fprintf(stderr, "'aMule Crashes' forum and include as much information as possible regarding the\n");
1278 fprintf(stderr, "circumstances of this crash. The forum is located here:\n");
1279 fprintf(stderr, " http://forum.amule.org/index.php?board=67.0\n");
1280 fprintf(stderr, "If possible, please try to generate a real backtrace of this crash:\n");
1281 fprintf(stderr, " http://www.amule.org/wiki/index.php/Backtraces\n\n");
1282 fprintf(stderr, "----------------------------=| BACKTRACE FOLLOWS: |=----------------------------\n");
1283 fprintf(stderr, "Current version is: %s\n", strFullMuleVersion);
1284 fprintf(stderr, "Running on: %s\n\n", strOSDescription);
1286 print_backtrace(1); // 1 == skip this function.
1288 fprintf(stderr, "\n--------------------------------------------------------------------------------\n");
1292 // Sets the localization of aMule
1293 void CamuleApp::Localize_mule()
1295 InitCustomLanguages();
1296 InitLocale(m_locale, StrLang2wx(thePrefs::GetLanguageID()));
1297 if (!m_locale.IsOk()) {
1298 AddLogLineM(false,_("The selected locale seems not to be installed on your box. (Note: I'll try to set it anyway)"));
1303 // Displays information related to important changes in aMule.
1304 // Is called when the user runs a new version of aMule
1305 void CamuleApp::Trigger_New_version(wxString new_version)
1307 wxString info = wxT(" --- ") + CFormat(_("This is the first time you run aMule %s")) % new_version + wxT(" ---\n\n");
1308 if (new_version == wxT("SVN")) {
1309 info += _("This version is a testing version, updated daily, and\n");
1310 info += _("we give no warranty it won't break anything, burn your house,\n");
1311 info += _("or kill your dog. But it *should* be safe to use anyway.\n");
1312 } else if (new_version == wxT("2.2.0")) {
1313 thePrefs::SetAddServersFromServer(false);
1314 thePrefs::SetAddServersFromClient(false);
1315 info += _("The following options have been changed in this release for security reasons:\n");
1316 info += _("\n* Enabled Protocol Obfuscation support for incoming and outgoing connections.\n");
1317 info += _("\n* Disabled updating the server list from other server and clients.\n");
1318 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.");
1321 // General info
1322 info += wxT("\n");
1323 info += _("More information, support and new releases can found at our homepage,\n");
1324 info += _("at www.aMule.org, or in our IRC channel #aMule at irc.freenode.net.\n");
1325 info += wxT("\n");
1326 info += _("Feel free to report any bugs to http://forum.amule.org");
1328 ShowAlert(info, _("Info"), wxCENTRE | wxOK | wxICON_ERROR);
1332 void CamuleApp::SetOSFiles(const wxString new_path)
1334 if ( thePrefs::IsOnlineSignatureEnabled() ) {
1335 if ( ::wxDirExists(new_path) ) {
1336 m_emulesig_path = JoinPaths(new_path, wxT("onlinesig.dat"));
1337 m_amulesig_path = JoinPaths(new_path, wxT("amulesig.dat"));
1338 } else {
1339 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);
1340 m_emulesig_path.Clear();
1341 m_amulesig_path.Clear();
1343 } else {
1344 m_emulesig_path.Clear();
1345 m_amulesig_path.Clear();
1350 #ifdef __WXDEBUG__
1351 #ifndef wxUSE_STACKWALKER
1352 #define wxUSE_STACKWALKER 0
1353 #endif
1354 void CamuleApp::OnAssertFailure(const wxChar* file, int line,
1355 const wxChar* func, const wxChar* cond, const wxChar* msg)
1357 if (!wxUSE_STACKWALKER || !wxThread::IsMain() || !IsRunning()) {
1358 wxString errmsg = CFormat( wxT("%s:%s:%d: Assertion '%s' failed. %s") )
1359 % file % func % line % cond % ( msg ? msg : wxT("") );
1361 fprintf(stderr, "Assertion failed: %s\n", (const char*)unicode2char(errmsg));
1363 // Skip the function-calls directly related to the assert call.
1364 fprintf(stderr, "\nBacktrace follows:\n");
1365 print_backtrace(3);
1366 fprintf(stderr, "\n");
1369 if (wxThread::IsMain() && IsRunning()) {
1370 AMULE_APP_BASE::OnAssertFailure(file, line, func, cond, msg);
1371 } else {
1372 // Abort, allows gdb to catch the assertion
1373 raise( SIGABRT );
1376 #endif
1379 void CamuleApp::OnUDPDnsDone(CMuleInternalEvent& evt)
1381 CServerUDPSocket* socket =(CServerUDPSocket*)evt.GetClientData();
1382 socket->OnHostnameResolved(evt.GetExtraLong());
1386 void CamuleApp::OnSourceDnsDone(CMuleInternalEvent& evt)
1388 downloadqueue->OnHostnameResolved(evt.GetExtraLong());
1392 void CamuleApp::OnServerDnsDone(CMuleInternalEvent& evt)
1394 printf("Server hostname notified\n");
1395 serverconnect->OnServerHostnameResolved(evt.GetClientData(), evt.GetExtraLong());
1399 void CamuleApp::OnTCPTimer(CTimerEvent& WXUNUSED(evt))
1401 if(!IsRunning()) {
1402 return;
1404 serverconnect->StopConnectionTry();
1405 if (IsConnectedED2K() ) {
1406 return;
1408 serverconnect->ConnectToAnyServer();
1412 void CamuleApp::OnCoreTimer(CTimerEvent& WXUNUSED(evt))
1414 // Former TimerProc section
1415 static uint64 msPrev1, msPrev5, msPrevSave, msPrevHist, msPrevOS, msPrevKnownMet;
1416 uint64 msCur = theStats::GetUptimeMillis();
1418 if (!IsRunning()) {
1419 return;
1422 #ifndef AMULE_DAEMON
1423 // Check if we should terminate the app
1424 if ( g_shutdownSignal ) {
1425 wxWindow* top = GetTopWindow();
1427 if ( top ) {
1428 top->Close(true);
1429 } else {
1430 // No top-window, have to force termination.
1431 wxExit();
1434 #endif
1436 CLogger::FlushPendingEntries();
1438 uploadqueue->Process();
1439 downloadqueue->Process();
1440 //theApp->clientcredits->Process();
1441 theStats::CalculateRates();
1443 if (msCur-msPrevHist > 1000) {
1444 // unlike the other loop counters in this function this one will sometimes
1445 // produce two calls in quick succession (if there was a gap of more than one
1446 // second between calls to TimerProc) - this is intentional! This way the
1447 // history list keeps an average of one node per second and gets thinned out
1448 // correctly as time progresses.
1449 msPrevHist += 1000;
1451 m_statistics->RecordHistory();
1456 if (msCur-msPrev1 > 1000) { // approximately every second
1457 msPrev1 = msCur;
1458 clientcredits->Process();
1459 clientlist->Process();
1461 // Publish files to server if needed.
1462 sharedfiles->Process();
1464 if( Kademlia::CKademlia::IsRunning() ) {
1465 Kademlia::CKademlia::Process();
1466 if(Kademlia::CKademlia::GetPrefs()->HasLostConnection()) {
1467 StopKad();
1468 clientudp->Close();
1469 clientudp->Open();
1470 if (thePrefs::Reconnect()) {
1471 StartKad();
1476 if( serverconnect->IsConnecting() && !serverconnect->IsSingleConnect() ) {
1477 serverconnect->TryAnotherConnectionrequest();
1479 if (serverconnect->IsConnecting()) {
1480 serverconnect->CheckForTimeout();
1482 listensocket->UpdateConnectionsStatus();
1487 if (msCur-msPrev5 > 5000) { // every 5 seconds
1488 msPrev5 = msCur;
1489 listensocket->Process();
1492 if (msCur-msPrevSave >= 60000) {
1493 msPrevSave = msCur;
1494 wxString buffer;
1496 // Save total upload/download to preferences
1497 wxConfigBase* cfg = wxConfigBase::Get();
1498 buffer = CFormat(wxT("%llu")) % (theStats::GetSessionReceivedBytes() + thePrefs::GetTotalDownloaded());
1499 cfg->Write(wxT("/Statistics/TotalDownloadedBytes"), buffer);
1501 buffer = CFormat(wxT("%llu")) % (theStats::GetSessionSentBytes() + thePrefs::GetTotalUploaded());
1502 cfg->Write(wxT("/Statistics/TotalUploadedBytes"), buffer);
1504 // Write changes to file
1505 cfg->Flush();
1509 // Special
1510 if (msCur - msPrevOS >= thePrefs::GetOSUpdate() * 1000ull) {
1511 OnlineSig(); // Added By Bouc7
1512 msPrevOS = msCur;
1515 if (msCur - msPrevKnownMet >= 30*60*1000/*There must be a prefs option for this*/) {
1516 // Save Shared Files data
1517 knownfiles->Save();
1518 msPrevKnownMet = msCur;
1522 // Recomended by lugdunummaster himself - from emule 0.30c
1523 serverconnect->KeepConnectionAlive();
1528 void CamuleApp::OnFinishedHashing(CHashingEvent& evt)
1530 wxCHECK_RET(evt.GetResult(), wxT("No result of hashing"));
1532 CKnownFile* owner = const_cast<CKnownFile*>(evt.GetOwner());
1533 CKnownFile* result = evt.GetResult();
1535 if (owner) {
1536 // Check if the partfile still exists, as it might have
1537 // been deleted in the mean time.
1538 if (downloadqueue->IsPartFile(owner)) {
1539 // This cast must not be done before the IsPartFile
1540 // call, as dynamic_cast will barf on dangling pointers.
1541 dynamic_cast<CPartFile*>(owner)->PartFileHashFinished(result);
1543 } else {
1544 static int filecount;
1545 static uint64 bytecount;
1547 if (knownfiles->SafeAddKFile(result)) {
1548 AddDebugLogLineM(false, logKnownFiles,
1549 CFormat(wxT("Safe adding file to sharedlist: %s")) % result->GetFileName());
1550 sharedfiles->SafeAddKFile(result);
1552 filecount++;
1553 bytecount += result->GetFileSize();
1554 // If we have added 30 files or files with a total size of ~300mb
1555 if ( ( filecount == 30 ) || ( bytecount >= 314572800 ) ) {
1556 AddDebugLogLineM(false, logKnownFiles, wxT("Failsafe for crash on file hashing creation"));
1557 if ( m_app_state != APP_STATE_SHUTTINGDOWN ) {
1558 knownfiles->Save();
1559 filecount = 0;
1560 bytecount = 0;
1563 } else {
1564 AddDebugLogLineM(false, logKnownFiles,
1565 CFormat(wxT("File not added to sharedlist: %s")) % result->GetFileName());
1566 delete result;
1572 void CamuleApp::OnFinishedAICHHashing(CHashingEvent& evt)
1574 wxCHECK_RET(evt.GetResult(), wxT("No result of AICH-hashing"));
1576 CKnownFile* owner = const_cast<CKnownFile*>(evt.GetOwner());
1577 std::auto_ptr<CKnownFile> result(evt.GetResult());
1579 // Check that the owner is still valid
1580 if (knownfiles->IsKnownFile(owner)) {
1581 if (result->GetAICHHashset()->GetStatus() == AICH_HASHSETCOMPLETE) {
1582 CAICHHashSet* oldSet = owner->GetAICHHashset();
1583 CAICHHashSet* newSet = result->GetAICHHashset();
1585 owner->SetAICHHashset(newSet);
1586 newSet->SetOwner(owner);
1588 result->SetAICHHashset(oldSet);
1589 oldSet->SetOwner(result.get());
1595 void CamuleApp::OnFinishedCompletion(CCompletionEvent& evt)
1597 CPartFile* completed = const_cast<CPartFile*>(evt.GetOwner());
1598 wxCHECK_RET(completed, wxT("Completion event sent for unspecified file"));
1599 wxASSERT_MSG(downloadqueue->IsPartFile(completed), wxT("CCompletionEvent for unknown partfile."));
1601 completed->CompleteFileEnded(evt.ErrorOccured(), evt.GetFullPath());
1602 if (evt.ErrorOccured()) {
1603 CUserEvents::ProcessEvent(CUserEvents::ErrorOnCompletion, completed);
1606 // Check if we should execute an script/app/whatever.
1607 CUserEvents::ProcessEvent(CUserEvents::DownloadCompleted, completed);
1610 void CamuleApp::OnFinishedAllocation(CAllocFinishedEvent& evt)
1612 CPartFile *file = evt.GetFile();
1613 wxCHECK_RET(file, wxT("Allocation finished event sent for unspecified file"));
1614 wxASSERT_MSG(downloadqueue->IsPartFile(file), wxT("CAllocFinishedEvent for unknown partfile"));
1616 file->SetPartFileStatus(PS_EMPTY);
1618 if (evt.Succeeded()) {
1619 if (evt.IsPaused()) {
1620 file->StopFile();
1621 } else {
1622 file->ResumeFile();
1624 } else {
1625 AddLogLineM(false, CFormat(_("Disk space preallocation for file '%s' failed: %s")) % file->GetFileName() % wxString(UTF82unicode(std::strerror(evt.GetResult()))));
1626 file->StopFile();
1629 file->AllocationFinished();
1632 void CamuleApp::OnNotifyEvent(CMuleGUIEvent& evt)
1634 #if defined(AMULE_DAEMON)
1635 evt.Notify();
1636 #else
1637 if (theApp->amuledlg) {
1638 evt.Notify();
1640 #endif
1644 void CamuleApp::ShutDown()
1646 // Log
1647 AddDebugLogLineM(false, logGeneral, wxT("CamuleApp::ShutDown() has started."));
1649 // Signal the hashing thread to terminate
1650 m_app_state = APP_STATE_SHUTTINGDOWN;
1652 StopKad();
1654 // Kry - Save the sources seeds on app exit
1655 if (thePrefs::GetSrcSeedsOn()) {
1656 downloadqueue->SaveSourceSeeds();
1659 OnlineSig(true); // Added By Bouc7
1661 // Close sockets to avoid new clients coming in
1662 if (listensocket) {
1663 listensocket->Close();
1664 listensocket->KillAllSockets();
1667 if (serverconnect) {
1668 serverconnect->Disconnect();
1671 ECServerHandler->KillAllSockets();
1673 #ifdef ENABLE_UPNP
1674 if (thePrefs::GetUPnPEnabled()) {
1675 if (m_upnp) {
1676 m_upnp->DeletePortMappings(m_upnpMappings);
1679 #endif
1681 // saving data & stuff
1682 if (knownfiles) {
1683 knownfiles->Save();
1686 thePrefs::Add2TotalDownloaded(theStats::GetSessionReceivedBytes());
1687 thePrefs::Add2TotalUploaded(theStats::GetSessionSentBytes());
1689 if (glob_prefs) {
1690 glob_prefs->Save();
1693 if (clientlist) {
1694 clientlist->DeleteAll();
1697 CThreadScheduler::Terminate();
1699 theApp->uploadBandwidthThrottler->EndThread();
1701 // Log
1702 AddDebugLogLineM(false, logGeneral, wxT("CamuleApp::ShutDown() has ended."));
1706 bool CamuleApp::AddServer(CServer *srv, bool fromUser)
1708 if ( serverlist->AddServer(srv, fromUser) ) {
1709 Notify_ServerAdd(srv);
1710 return true;
1712 return false;
1716 void CamuleApp::AddLogLine(const wxString &msg)
1718 // At most one trailing new-line, which we add
1719 wxString message = msg;
1720 while ( !message.IsEmpty() && message.Last() == wxT('\n') ) {
1721 message.RemoveLast();
1724 wxString full_line = wxDateTime::Now().FormatISODate() + wxT(" ") +
1725 wxDateTime::Now().FormatISOTime() + wxT(": ") + message + wxT("\n");
1727 wxStringInputStream stream(full_line);
1729 if (applog) { // This check is needed, because if we assert before the logger is created, it will crash.
1730 (*applog) << stream;
1731 applog->Sync();
1734 if (enable_stdout_log) {
1735 printf("%s", (const char*)unicode2char(full_line));
1740 uint32 CamuleApp::GetPublicIP(bool ignorelocal) const
1742 if (m_dwPublicIP == 0) {
1743 if (Kademlia::CKademlia::IsConnected() && Kademlia::CKademlia::GetIPAddress() ) {
1744 return wxUINT32_SWAP_ALWAYS(Kademlia::CKademlia::GetIPAddress());
1745 } else {
1746 return ignorelocal ? 0 : m_localip;
1750 return m_dwPublicIP;
1754 void CamuleApp::SetPublicIP(const uint32 dwIP)
1756 wxASSERT((dwIP == 0) || !IsLowID(dwIP));
1758 if (dwIP != 0 && dwIP != m_dwPublicIP && serverlist != NULL) {
1759 m_dwPublicIP = dwIP;
1760 serverlist->CheckForExpiredUDPKeys();
1761 } else {
1762 m_dwPublicIP = dwIP;
1767 wxString CamuleApp::GetLog(bool reset)
1769 ConfigDir = GetConfigDir();
1770 wxFile logfile;
1771 logfile.Open(ConfigDir + wxT("logfile"));
1772 if ( !logfile.IsOpened() ) {
1773 return wxTRANSLATE("ERROR: can't open logfile");
1775 int len = logfile.Length();
1776 if ( len == 0 ) {
1777 return wxTRANSLATE("WARNING: logfile is empty. Something is wrong.");
1779 char *tmp_buffer = new char[len + sizeof(wxChar)];
1780 logfile.Read(tmp_buffer, len);
1781 memset(tmp_buffer + len, 0, sizeof(wxChar));
1783 // try to guess file format
1784 wxString str;
1785 if (tmp_buffer[0] && tmp_buffer[1]) {
1786 str = wxString(UTF82unicode(tmp_buffer));
1787 } else {
1788 str = wxString((wxWCharBuffer&)tmp_buffer);
1791 delete [] tmp_buffer;
1792 if ( reset ) {
1793 delete applog;
1794 applog = new wxFFileOutputStream(ConfigDir + wxT("logfile"));
1795 if ( applog->Ok() ) {
1796 AddLogLine(_("Log has been reset"));
1797 } else {
1798 delete applog;
1799 applog = 0;
1802 return str;
1806 wxString CamuleApp::GetServerLog(bool reset)
1808 wxString ret = server_msg;
1809 if ( reset ) {
1810 server_msg.Clear();
1812 return ret;
1815 wxString CamuleApp::GetDebugLog(bool reset)
1817 return GetLog(reset);
1821 void CamuleApp::AddServerMessageLine(wxString &msg)
1823 server_msg += msg + wxT("\n");
1824 AddLogLine(CFormat(_("ServerMessage: %s")) % msg);
1829 void CamuleApp::OnFinishedHTTPDownload(CMuleInternalEvent& event)
1831 switch (event.GetInt()) {
1832 case HTTP_IPFilter:
1833 ipfilter->DownloadFinished(event.GetExtraLong());
1834 break;
1835 case HTTP_ServerMet:
1836 serverlist->DownloadFinished(event.GetExtraLong());
1837 break;
1838 case HTTP_ServerMetAuto:
1839 serverlist->AutoDownloadFinished(event.GetExtraLong());
1840 break;
1841 case HTTP_VersionCheck:
1842 CheckNewVersion(event.GetExtraLong());
1843 break;
1844 case HTTP_NodesDat:
1845 if (event.GetExtraLong() != -1) {
1847 wxString file = ConfigDir + wxT("nodes.dat");
1848 if (wxFileExists(file)) {
1849 wxRemoveFile(file);
1852 if ( Kademlia::CKademlia::IsRunning() ) {
1853 Kademlia::CKademlia::Stop();
1856 wxRenameFile(file + wxT(".download"),file);
1858 Kademlia::CKademlia::Start();
1859 theApp->ShowConnectionState();
1861 } else {
1862 AddLogLineM(true, _("Failed to download the nodes list."));
1864 break;
1868 void CamuleApp::CheckNewVersion(uint32 result)
1870 if (result == 1) {
1871 wxString filename = ConfigDir + wxT("last_version_check");
1872 wxTextFile file;
1874 if (!file.Open(filename)) {
1875 AddLogLineM(true, _("Failed to open the downloaded version check file") );
1876 return;
1877 } else if (!file.GetLineCount()) {
1878 AddLogLineM(true, _("Corrupted version check file"));
1879 } else {
1880 wxString versionLine = file.GetFirstLine();
1881 wxStringTokenizer tkz(versionLine, wxT("."));
1883 AddDebugLogLineM(false, logGeneral, wxString(wxT("Running: ")) + wxT(VERSION) + wxT(", Version check: ") + versionLine);
1885 long fields[] = {0, 0, 0};
1886 for (int i = 0; i < 3; ++i) {
1887 if (!tkz.HasMoreTokens()) {
1888 AddLogLineM(true, _("Corrupted version check file"));
1889 return;
1890 } else {
1891 wxString token = tkz.GetNextToken();
1893 if (!token.ToLong(&fields[i])) {
1894 AddLogLineM(true, _("Corrupted version check file"));
1895 return;
1900 long curVer = make_full_ed2k_version(VERSION_MJR, VERSION_MIN, VERSION_UPDATE);
1901 long newVer = make_full_ed2k_version(fields[0], fields[1], fields[2]);
1903 if (curVer < newVer) {
1904 AddLogLineM(true, _("You are using an outdated version of aMule!"));
1905 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]));
1906 AddLogLineM(false, _("The latest version can always be found at http://www.amule.org"));
1907 #ifdef AMULE_DAEMON
1908 printf("%s\n", (const char*)unicode2UTF8(wxString::Format(
1909 _("WARNING: Your aMuled version is outdated: %i.%i.%i < %li.%li.%li"),
1910 VERSION_MJR, VERSION_MIN, VERSION_UPDATE, fields[0], fields[1], fields[2])));
1911 #endif
1912 } else {
1913 AddLogLineM(false, _("Your copy of aMule is up to date."));
1917 file.Close();
1918 wxRemoveFile(filename);
1919 } else {
1920 AddLogLineM(true, _("Failed to download the version check file") );
1926 bool CamuleApp::IsConnected()
1928 return (IsConnectedED2K() || IsConnectedKad());
1932 bool CamuleApp::IsConnectedED2K()
1934 return serverconnect && serverconnect->IsConnected();
1938 bool CamuleApp::IsConnectedKad()
1940 return Kademlia::CKademlia::IsConnected();
1944 bool CamuleApp::IsFirewalled()
1946 if (theApp->IsConnectedED2K() && !theApp->serverconnect->IsLowID()) {
1947 return false; // we have an eD2K HighID -> not firewalled
1950 return IsFirewalledKad(); // If kad says ok, it's ok.
1953 bool CamuleApp::IsFirewalledKad()
1955 if (Kademlia::CKademlia::IsConnected() && !Kademlia::CKademlia::IsFirewalled()) {
1956 return false; // we have an Kad HighID -> not firewalled
1959 return true; // firewalled
1962 bool CamuleApp::IsKadRunning()
1964 return Kademlia::CKademlia::IsRunning();
1967 bool CamuleApp::DoCallback( CUpDownClient *client )
1969 if(Kademlia::CKademlia::IsConnected()) {
1970 if(IsConnectedED2K()) {
1971 if(serverconnect->IsLowID()) {
1972 if(Kademlia::CKademlia::IsFirewalled()) {
1973 //Both Connected - Both Firewalled
1974 return false;
1975 } else {
1976 if(client->GetServerIP() == theApp->serverconnect->GetCurrentServer()->GetIP() &&
1977 client->GetServerPort() == theApp->serverconnect->GetCurrentServer()->GetPort()) {
1978 // Both Connected - Server lowID, Kad Open - Client on same server
1979 // We prevent a callback to the server as this breaks the protocol
1980 // and will get you banned.
1981 return false;
1982 } else {
1983 // Both Connected - Server lowID, Kad Open - Client on remote server
1984 return true;
1987 } else {
1988 //Both Connected - Server HighID, Kad don't care
1989 return true;
1991 } else {
1992 if(Kademlia::CKademlia::IsFirewalled()) {
1993 //Only Kad Connected - Kad Firewalled
1994 return false;
1995 } else {
1996 //Only Kad Conected - Kad Open
1997 return true;
2000 } else {
2001 if( IsConnectedED2K() ) {
2002 if( serverconnect->IsLowID() ) {
2003 //Only Server Connected - Server LowID
2004 return false;
2005 } else {
2006 //Only Server Connected - Server HighID
2007 return true;
2009 } else {
2010 //We are not connected at all!
2011 return false;
2016 void CamuleApp::ShowUserCount() {
2017 uint32 totaluser = 0, totalfile = 0;
2019 theApp->serverlist->GetUserFileStatus( totaluser, totalfile );
2021 wxString buffer;
2023 static const wxString s_singlenetstatusformat = _("Users: %s | Files: %s");
2024 static const wxString s_bothnetstatusformat = _("Users: E: %s K: %s | Files: E: %s K: %s");
2026 if (thePrefs::GetNetworkED2K() && thePrefs::GetNetworkKademlia()) {
2027 buffer = CFormat(s_bothnetstatusformat) % CastItoIShort(totaluser) % CastItoIShort(Kademlia::CKademlia::GetKademliaUsers()) % CastItoIShort(totalfile) % CastItoIShort(Kademlia::CKademlia::GetKademliaFiles());
2028 } else if (thePrefs::GetNetworkED2K()) {
2029 buffer = CFormat(s_singlenetstatusformat) % CastItoIShort(totaluser) % CastItoIShort(totalfile);
2030 } else if (thePrefs::GetNetworkKademlia()) {
2031 buffer = CFormat(s_singlenetstatusformat) % CastItoIShort(Kademlia::CKademlia::GetKademliaUsers()) % CastItoIShort(Kademlia::CKademlia::GetKademliaFiles());
2032 } else {
2033 buffer = _("No networks selected");
2036 Notify_ShowUserCount(buffer);
2040 void CamuleApp::ListenSocketHandler(wxSocketEvent& event)
2042 wxCHECK_RET(listensocket, wxT("Connection-event for NULL'd listen-socket"));
2043 wxCHECK_RET(event.GetSocketEvent() == wxSOCKET_CONNECTION,
2044 wxT("Invalid event received for listen-socket"));
2046 if (m_app_state == APP_STATE_RUNNING) {
2047 listensocket->OnAccept(0);
2048 } else if (m_app_state == APP_STATE_STARTING) {
2049 // When starting up, connection may be made before we are able
2050 // to handle them. However, if these are ignored, no futher
2051 // connection-events will be triggered, so we have to accept it.
2052 wxSocketBase* socket = listensocket->Accept(false);
2054 wxCHECK_RET(socket, wxT("NULL returned by Accept() during startup"));
2056 socket->Destroy();
2061 void CamuleApp::ShowConnectionState()
2063 static uint8 old_state = (1<<7); // This flag doesn't exist
2065 uint8 state = 0;
2067 if (theApp->serverconnect->IsConnected()) {
2068 state |= CONNECTED_ED2K;
2071 if (Kademlia::CKademlia::IsRunning()) {
2072 if (Kademlia::CKademlia::IsConnected()) {
2073 if (!Kademlia::CKademlia::IsFirewalled()) {
2074 state |= CONNECTED_KAD_OK;
2075 } else {
2076 state |= CONNECTED_KAD_FIREWALLED;
2078 } else {
2079 state |= CONNECTED_KAD_NOT;
2083 Notify_ShowConnState(state);
2085 if (old_state != state) {
2086 // Get the changed value
2087 int changed_flags = old_state ^ state;
2089 if (changed_flags & CONNECTED_ED2K) {
2090 // ED2K status changed
2091 wxString connected_server;
2092 CServer* ed2k_server = theApp->serverconnect->GetCurrentServer();
2093 if (ed2k_server) {
2094 connected_server = ed2k_server->GetListName();
2096 if (state & CONNECTED_ED2K) {
2097 // We connected to some server
2098 const wxString id = theApp->serverconnect->IsLowID() ? _("with LowID") : _("with HighID");
2100 AddLogLine(CFormat(_("Connected to %s %s")) % connected_server % id);
2101 } else {
2102 if ( theApp->serverconnect->IsConnecting() ) {
2103 AddLogLine(CFormat(_("Connecting to %s")) % connected_server);
2104 } else {
2105 AddLogLine(_("Disconnected from ED2K"));
2110 if (changed_flags & CONNECTED_KAD_NOT) {
2111 if (state & CONNECTED_KAD_NOT) {
2112 AddLogLine(_("Kad started."));
2113 } else {
2114 AddLogLine(_("Kad stopped."));
2118 if (changed_flags & (CONNECTED_KAD_OK | CONNECTED_KAD_FIREWALLED)) {
2119 if (state & (CONNECTED_KAD_OK | CONNECTED_KAD_FIREWALLED)) {
2120 if (state & CONNECTED_KAD_OK) {
2121 AddLogLine(_("Connected to Kad (ok)"));
2122 } else {
2123 AddLogLine(_("Connected to Kad (firewalled)"));
2125 } else {
2126 AddLogLine(_("Disconnected from Kad"));
2130 old_state = state;
2132 theApp->downloadqueue->OnConnectionState(IsConnected());
2135 ShowUserCount();
2136 Notify_ShowConnState(state);
2140 void CamuleApp::UDPSocketHandler(wxSocketEvent& event)
2142 CMuleUDPSocket* socket = (CMuleUDPSocket*)(event.GetClientData());
2143 wxCHECK_RET(socket, wxT("No socket owner specified."));
2145 if (IsOnShutDown() || thePrefs::IsUDPDisabled()) return;
2147 if (!IsRunning()) {
2148 if (event.GetSocketEvent() == wxSOCKET_INPUT) {
2149 // Back to the queue!
2150 theApp->AddPendingEvent(event);
2151 return;
2155 switch (event.GetSocketEvent()) {
2156 case wxSOCKET_INPUT:
2157 socket->OnReceive(0);
2158 break;
2160 case wxSOCKET_OUTPUT:
2161 socket->OnSend(0);
2162 break;
2164 case wxSOCKET_LOST:
2165 socket->OnDisconnected(0);
2166 break;
2168 default:
2169 wxASSERT(0);
2170 break;
2175 void CamuleApp::OnUnhandledException()
2177 // Call the generic exception-handler.
2178 fprintf(stderr, "\taMule Version: %s\n", (const char*)unicode2char(GetFullMuleVersion()));
2179 ::OnUnhandledException();
2182 void CamuleApp::StartKad()
2184 if (!Kademlia::CKademlia::IsRunning() && thePrefs::GetNetworkKademlia()) {
2185 // Kad makes no sense without the Client-UDP socket.
2186 if (!thePrefs::IsUDPDisabled()) {
2187 Kademlia::CKademlia::Start();
2188 } else {
2189 AddLogLineM(true,_("Kad network cannot be used if UDP port is disabled on preferences, not starting."));
2191 } else if (!thePrefs::GetNetworkKademlia()) {
2192 AddLogLineM(true,_("Kad network disabled on preferences, not connecting."));
2196 void CamuleApp::StopKad()
2198 // Stop Kad if it's running
2199 if (Kademlia::CKademlia::IsRunning()) {
2200 Kademlia::CKademlia::Stop();
2205 void CamuleApp::BootstrapKad(uint32 ip, uint16 port)
2207 if (!Kademlia::CKademlia::IsRunning()) {
2208 Kademlia::CKademlia::Start();
2209 theApp->ShowConnectionState();
2212 Kademlia::CKademlia::Bootstrap(ip, port, true);
2216 void CamuleApp::UpdateNotesDat(const wxString& url)
2218 wxString strTempFilename(theApp->ConfigDir + wxT("nodes.dat.download"));
2220 CHTTPDownloadThread *downloader = new CHTTPDownloadThread(url, strTempFilename, HTTP_NodesDat);
2221 downloader->Create();
2222 downloader->Run();
2226 void CamuleApp::DisconnectED2K()
2228 // Stop ED2K if it's running
2229 if (IsConnectedED2K()) {
2230 serverconnect->Disconnect();
2234 bool CamuleApp::CryptoAvailable() const
2236 return clientcredits && clientcredits->CryptoAvailable();
2239 uint32 CamuleApp::GetED2KID() const {
2240 return serverconnect ? serverconnect->GetClientID() : 0;
2243 uint32 CamuleApp::GetID() const {
2244 uint32 ID;
2246 if( Kademlia::CKademlia::IsConnected() && !Kademlia::CKademlia::IsFirewalled() ) {
2247 // We trust Kad above ED2K
2248 ID = ENDIAN_NTOHL(Kademlia::CKademlia::GetIPAddress());
2249 } else if( theApp->serverconnect->IsConnected() ) {
2250 ID = theApp->serverconnect->GetClientID();
2251 } else if ( Kademlia::CKademlia::IsConnected() && Kademlia::CKademlia::IsFirewalled() ) {
2252 // A firewalled Kad client get's a "1"
2253 ID = 1;
2254 } else {
2255 ID = 0;
2258 return ID;
2261 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_FINISHED_HTTP_DOWNLOAD)
2262 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_SOURCE_DNS_DONE)
2263 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_UDP_DNS_DONE)
2264 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_SERVER_DNS_DONE)
2265 // File_checked_for_headers