2 // This file is part of the aMule Project.
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 )
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
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.
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
30 #include "amule.h" // Interface declarations.
33 #include <wx/process.h>
34 #include <wx/sstream.h>
37 #include "config.h" // Needed for HAVE_GETRLIMIT, HAVE_SETRLIMIT,
38 // HAVE_SYS_RESOURCE_H, HAVE_SYS_STATVFS_H, VERSION
42 #include <common/ClientVersion.h>
44 #include <wx/cmdline.h> // Needed for wxCmdLineParser
45 #include <wx/config.h> // Do_not_auto_remove (win32)
46 #include <wx/fileconf.h>
47 #include <wx/snglinst.h>
48 #include <wx/tokenzr.h>
49 #include <wx/wfstream.h>
52 #include <common/Format.h> // Needed for CFormat
53 #include "kademlia/kademlia/Kademlia.h"
54 #include "kademlia/kademlia/Prefs.h"
55 #include "ClientCreditsList.h" // Needed for CClientCreditsList
56 #include "ClientList.h" // Needed for CClientList
57 #include "ClientUDPSocket.h" // Needed for CClientUDPSocket & CMuleUDPSocket
58 #include "ExternalConn.h" // Needed for ExternalConn & MuleConnection
59 #include <common/FileFunctions.h> // Needed for CDirIterator
60 #include "FriendList.h" // Needed for CFriendList
61 #include "HTTPDownload.h" // Needed for CHTTPDownloadThread
62 #include "InternalEvents.h" // Needed for CMuleInternalEvent
63 #include "IPFilter.h" // Needed for CIPFilter
64 #include "KnownFileList.h" // Needed for CKnownFileList
65 #include "ListenSocket.h" // Needed for CListenSocket
66 #include "Logger.h" // Needed for CLogger // Do_not_auto_remove
67 #include "MagnetURI.h" // Needed for CMagnetURI
68 #include "OtherFunctions.h"
69 #include "PartFile.h" // Needed for CPartFile
70 #include "Preferences.h" // Needed for CPreferences
71 #include "SearchList.h" // Needed for CSearchList
72 #include "Server.h" // Needed for GetListName
73 #include "ServerList.h" // Needed for CServerList
74 #include "ServerConnect.h" // Needed for CServerConnect
75 #include "ServerUDPSocket.h" // Needed for CServerUDPSocket
76 #include "Statistics.h" // Needed for CStatistics
77 #include "TerminationProcessAmuleweb.h" // Needed for CTerminationProcessAmuleweb
78 #include "ThreadTasks.h"
79 #include "updownclient.h" // Needed for CUpDownClient
80 #include "UploadQueue.h" // Needed for CUploadQueue
81 #include "UploadBandwidthThrottler.h"
82 #include "UserEvents.h"
85 #include "UPnP.h" // Needed for UPnP
89 #include <wx/sysopt.h> // Do_not_auto_remove
94 #include <CoreFoundation/CFBundle.h> // Do_not_auto_remove
95 #include <wx/mac/corefoundation/cfstring.h> // Do_not_auto_remove
97 #include <wx/msgdlg.h>
103 #ifdef HAVE_SYS_RESOURCE_H
104 #include <sys/resource.h>
107 #ifdef HAVE_SYS_STATVFS_H
108 #include <sys/statvfs.h> // Do_not_auto_remove
113 # define RLIMIT_RESOURCE __rlimit_resource
115 # define RLIMIT_RESOURCE int
118 static void UnlimitResource(RLIMIT_RESOURCE resType
)
120 #if defined(HAVE_GETRLIMIT) && defined(HAVE_SETRLIMIT)
122 getrlimit(resType
, &rl
);
123 rl
.rlim_cur
= rl
.rlim_max
;
124 setrlimit(resType
, &rl
);
129 static void SetResourceLimits()
131 #ifdef HAVE_SYS_RESOURCE_H
132 UnlimitResource(RLIMIT_DATA
);
133 UnlimitResource(RLIMIT_FSIZE
);
134 UnlimitResource(RLIMIT_NOFILE
);
136 UnlimitResource(RLIMIT_RSS
);
141 // We store the received signal in order to avoid race-conditions
142 // in the signal handler.
143 bool g_shutdownSignal
= false;
145 void OnShutdownSignal( int /* sig */ )
147 signal(SIGINT
, SIG_DFL
);
148 signal(SIGTERM
, SIG_DFL
);
150 g_shutdownSignal
= true;
153 theApp
->ExitMainLoop();
158 CamuleApp::CamuleApp()
160 // Madcat - Initialize timer as the VERY FIRST thing to avoid any issues later.
161 // Kry - I love to init the vars on init, even before timer.
165 m_app_state
= APP_STATE_STARTING
;
167 theApp
= &wxGetApp();
173 serverconnect
= NULL
;
177 clientcredits
= NULL
;
179 downloadqueue
= NULL
;
182 ECServerHandler
= NULL
;
183 m_singleInstance
= NULL
;
186 uploadBandwidthThrottler
= NULL
;
189 m_upnpMappings
.resize(4);
198 enable_stdout_log
= false;
199 enable_daemon_fork
= false;
201 strFullMuleVersion
= NULL
;
202 strOSDescription
= NULL
;
204 // Apprently needed for *BSD
208 CamuleApp::~CamuleApp()
210 // Closing the log-file as the very last thing, since
211 // wxWidgets log-events are saved in it as well.
216 int CamuleApp::OnExit()
218 if (m_app_state
!=APP_STATE_STARTING
) {
219 printf("Now, exiting main app...\n");
222 // From wxWidgets docs, wxConfigBase:
224 // Note that you must delete this object (usually in wxApp::OnExit)
225 // in order to avoid memory leaks, wxWidgets won't do it automatically.
227 // As it happens, you may even further simplify the procedure described
228 // above: you may forget about calling Set(). When Get() is called and
229 // there is no current object, it will create one using Create() function.
230 // To disable this behaviour DontCreateOnDemand() is provided.
231 delete wxConfigBase::Set((wxConfigBase
*)NULL
);
234 clientcredits
->SaveList();
236 // Kill amuleweb if running
238 printf("Killing amuleweb instance with pid `%ld' ... ", webserver_pid
);
240 wxKill(webserver_pid
, wxSIGTERM
, &rc
);
244 if (m_app_state
!=APP_STATE_STARTING
) {
245 printf("aMule OnExit: Terminating core.\n");
254 delete clientcredits
;
255 clientcredits
= NULL
;
260 // Destroying CDownloadQueue calls destructor for CPartFile
261 // calling CSharedFileList::SafeAddKFile occasionally.
265 delete serverconnect
;
266 serverconnect
= NULL
;
283 delete downloadqueue
;
284 downloadqueue
= NULL
;
294 delete ECServerHandler
;
295 ECServerHandler
= NULL
;
302 CPreferences::EraseItemList();
304 #if defined(__WXMAC__) && defined(AMULE_DAEMON)
305 //#warning TODO: fix wxSingleInstanceChecker for amuled on Mac (wx link problems)
307 delete m_singleInstance
;
309 m_singleInstance
= NULL
;
311 delete uploadBandwidthThrottler
;
312 uploadBandwidthThrottler
= NULL
;
314 if (m_app_state
!=APP_STATE_STARTING
) {
315 printf("aMule shutdown completed.\n");
318 #if wxUSE_MEMORY_TRACING
319 printf("Memory debug results for aMule exit:\n");
320 // Log mem debug mesages to wxLogStderr
321 wxLog
* oldLog
= wxLog::SetActiveTarget(new wxLogStderr
);
323 printf("**************Classes**************\n");
324 wxDebugContext::PrintClasses();
326 //printf("***************Dump***************\n");
327 //wxDebugContext::Dump();
328 printf("***************Stats**************\n");
329 wxDebugContext::PrintStatistics(true);
331 // Set back to wxLogGui
332 delete wxLog::SetActiveTarget(oldLog
);
337 // Return 0 for succesful program termination
338 return AMULE_APP_BASE::OnExit();
342 int CamuleApp::InitGui(bool, wxString
&)
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
)
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'"))
367 } else if (CPath::MakeDir(directory
)) {
368 return std::pair
<bool, CPath
>(true, directory
);
370 msg
<< CFormat(wxT("Could not create the %s directory at '%s'."))
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, wxString
>(false, wxEmptyString
);
390 // Application initialization
392 bool CamuleApp::OnInit()
394 #if wxUSE_MEMORY_TRACING
395 printf("Checkpoint set on app init for memory debug\n");
396 wxDebugContext::SetCheckpoint();
399 // Forward wxLog events to CLogger
400 wxLog::SetActiveTarget(new CLoggerTarget
);
402 m_localip
= StringHosttoUint32(::wxGetFullHostName());
405 // get rid of sigpipe
406 signal(SIGPIPE
, SIG_IGN
);
407 // Handle sigint and sigterm
408 signal(SIGINT
, OnShutdownSignal
);
409 signal(SIGTERM
, OnShutdownSignal
);
413 // For listctrl's to behave on Mac
414 wxSystemOptions::SetOption(wxT("mac.listctrl.always_use_generic"), 1);
417 // This can't be on constructor or wx2.4.2 doesn't set it.
418 #if !wxCHECK_VERSION(2, 9, 0)
419 SetVendorName(wxT("TikuWarez"));
421 SetAppName(wxT("aMule"));
423 wxString FullMuleVersion
= GetFullMuleVersion();
424 wxString OSDescription
= wxGetOsDescription();
425 strFullMuleVersion
= strdup((const char *)unicode2char(FullMuleVersion
));
426 strOSDescription
= strdup((const char *)unicode2char(OSDescription
));
427 OSType
= OSDescription
.BeforeFirst( wxT(' ') );
428 if ( OSType
.IsEmpty() ) {
429 OSType
= wxT("Unknown");
432 // Handle uncaught exceptions
433 InstallMuleExceptionHandler();
435 // Parse cmdline arguments.
436 wxCmdLineParser
cmdline(AMULE_APP_BASE::argc
, AMULE_APP_BASE::argv
);
438 // Handle these arguments.
439 cmdline
.AddSwitch(wxT("v"), wxT("version"), wxT("Displays the current version number."));
440 cmdline
.AddSwitch(wxT("h"), wxT("help"), wxT("Displays this information."));
441 cmdline
.AddSwitch(wxT("i"), wxT("enable-stdin"), wxT("Does not disable stdin."));
443 cmdline
.AddSwitch(wxT("f"), wxT("full-daemon"), wxT("Fork to background."));
444 cmdline
.AddOption(wxT("c"), wxT("config-dir"), wxT("read config from <dir> instead of home"));
445 cmdline
.AddSwitch(wxT("e"), wxT("ec-config"), wxT("Configure EC (External Connections)."));
447 cmdline
.AddOption(wxT("geometry"), wxEmptyString
,
448 wxT("Sets the geometry of the app.\n")
449 wxT("\t\t\t<str> uses the same format as standard X11 apps:\n")
450 wxT("\t\t\t[=][<width>{xX}<height>][{+-}<xoffset>{+-}<yoffset>]"));
452 cmdline
.AddSwitch(wxT("d"), wxT("disable-fatal"), wxT("Does not handle fatal exception."));
453 cmdline
.AddSwitch(wxT("o"), wxT("log-stdout"), wxT("Print log messages to stdout."));
454 cmdline
.AddSwitch(wxT("r"), wxT("reset-config"), wxT("Resets config to default values."));
456 // Show help on --help or invalid commands
457 if ( cmdline
.Parse() ) {
459 } else if ( cmdline
.Found(wxT("help")) ) {
464 bool ec_config
= false;
467 ec_config
= cmdline
.Found(wxT("ec-config"));
468 if ( cmdline
.Found(wxT("config-dir"), &ConfigDir
) ) {
469 if (ConfigDir
.Last() != wxFileName::GetPathSeparator()) {
470 ConfigDir
+= wxFileName::GetPathSeparator();
473 ConfigDir
= GetConfigDir();
476 ConfigDir
= GetConfigDir();
479 if ( !cmdline
.Found(wxT("disable-fatal")) ) {
481 // catch fatal exceptions
482 wxHandleFatalExceptions(true);
486 bool reset_config
= cmdline
.Found(wxT("reset-config"));
488 enable_stdout_log
= cmdline
.Found(wxT("log-stdout"));
490 enable_daemon_fork
= cmdline
.Found(wxT("full-daemon"));
492 enable_daemon_fork
= false;
495 if ( enable_stdout_log
) {
496 if ( enable_daemon_fork
) {
497 printf("Daemon will fork to background - log to stdout disabled\n");
498 enable_stdout_log
= false;
500 printf("Logging to stdout enabled\n");
504 if ( cmdline
.Found(wxT("version")) ) {
505 printf("%s (OS: %s)\n",
506 (const char*)unicode2char(GetFullMuleVersion()),
507 (const char*)unicode2char(OSType
));
512 // Default geometry of the GUI. Can be changed with a cmdline argument...
513 bool geometry_enabled
= false;
514 wxString geom_string
;
516 if ( cmdline
.Found(wxT("geometry"), &geom_string
) ) {
517 geometry_enabled
= true;
522 printf("Initialising aMule\n");
524 // Ensure that "~/.aMule/" is accessible.
525 if (!CheckMuleDirectory(wxT("configuration"), CPath(ConfigDir
), wxEmptyString
).first
) {
530 // Make a backup first.
531 wxRemoveFile(ConfigDir
+ wxT("amule.conf.backup"));
532 wxRenameFile(ConfigDir
+ wxT("amule.conf"), ConfigDir
+ wxT("amule.conf.backup"));
533 printf("Your settings have ben resetted to default values.\nOld config file has been saved as amule.conf.backup\n");
536 #if defined(__WXMAC__) && defined(AMULE_DAEMON)
537 //#warning TODO: fix wxSingleInstanceChecker for amuled on Mac (wx link problems)
538 printf("WARNING: The check for other instances is currently disabled in amuled.\n"
539 "Please make sure that no other instance of aMule is running or your files might be corrupted.\n");
541 printf("Checking if there is an instance already running...\n");
543 m_singleInstance
= new wxSingleInstanceChecker(wxT("muleLock"), ConfigDir
);
544 if (m_singleInstance
->IsAnotherRunning()) {
545 printf("There is an instance of aMule already running\n");
547 // This is very tricky. The most secure way to communicate is via ED2K links file
548 wxTextFile
ed2kFile(ConfigDir
+ wxT("ED2KLinks"));
549 if (!ed2kFile
.Exists()) {
553 if (ed2kFile
.Open()) {
554 ed2kFile
.AddLine(wxT("RAISE_DIALOG"));
557 printf("Raising current running instance.\n");
559 printf("Failed to open 'ED2KFile', cannot signal running instance.\n");
564 printf("No other instances are running.\n");
568 // Close standard-input
569 if ( !cmdline
.Found(wxT("enable-stdin")) ) {
570 // The full daemon will close all std file-descriptors by itself,
571 // so closing it here would lead to the closing on the first open
572 // file, which is the logfile opened below
573 if (!enable_daemon_fork
) {
578 // This creates the CFG file we shall use
579 wxConfigBase
* cfg
= new wxFileConfig( wxEmptyString
, wxEmptyString
, ConfigDir
+ wxT("amule.conf") );
581 // Set the config object as the global cfg file
582 wxConfig::Set( cfg
);
584 // Make a backup of the log file
585 CPath logfileName
= CPath(ConfigDir
+ wxT("logfile"));
586 if (logfileName
.FileExists()) {
587 CPath::BackupFile(logfileName
, wxT(".bak"));
591 applog
= new wxFFileOutputStream(logfileName
.GetRaw());
593 // use std err as last resolt to indicate problem
594 fputs("ERROR: unable to open log file\n", stderr
);
597 // failure to open log is serious problem
602 CPreferences::BuildItemList(ConfigDir
);
603 CPreferences::LoadAllItems( wxConfigBase::Get() );
605 glob_prefs
= new CPreferences();
607 std::pair
<bool, CPath
> checkResult
;
608 checkResult
= CheckMuleDirectory(wxT("temp"), thePrefs::GetTempDir(), ConfigDir
+ wxT("Temp"));
609 if (checkResult
.first
) {
610 thePrefs::SetTempDir(checkResult
.second
);
615 checkResult
= CheckMuleDirectory(wxT("incoming"), thePrefs::GetIncomingDir(), ConfigDir
+ wxT("Incoming"));
616 if (checkResult
.first
) {
617 thePrefs::SetIncomingDir(checkResult
.second
);
623 if (!thePrefs::UseTrayIcon()) {
624 thePrefs::SetMinToTray(false);
627 // Build the filenames for the two OS files
628 SetOSFiles(thePrefs::GetOSDir().GetRaw());
631 // Load localization settings
635 // Configure EC for amuled when invoked with ec-config
637 printf("\nEC configuration\n");
638 thePrefs::SetECPass(GetPassword());
639 thePrefs::EnableExternalConnections(true);
640 printf("Password set and external connections enabled.\n");
643 // Display notification on new version or first run
644 wxTextFile
vfile( ConfigDir
+ wxT("lastversion") );
645 wxString
newMule(wxT( VERSION
));
647 // Test if there's any new version
648 if (thePrefs::CheckNewVersion()) {
649 // We use the thread base because I don't want a dialog to pop up.
650 CHTTPDownloadThread
* version_check
=
651 new CHTTPDownloadThread(wxT("http://amule.sourceforge.net/lastversion"),
652 theApp
->ConfigDir
+ wxT("last_version_check"), HTTP_VersionCheck
, false);
653 version_check
->Create();
654 version_check
->Run();
657 if ( !wxFileExists( vfile
.GetName() ) ) {
664 wxT("Warning! You are running aMule as root.\n")
665 wxT("Doing so is not recommended for security reasons,\n")
666 wxT("and you are advised to run aMule as an normal\n")
667 wxT("user instead.");
669 ShowAlert(msg
, _("Warning"), wxCENTRE
| wxOK
| wxICON_ERROR
);
671 fprintf(stderr
, "\n--------------------------------------------------\n");
672 fprintf(stderr
, "%s", (const char*)unicode2UTF8(msg
));
673 fprintf(stderr
, "\n--------------------------------------------------\n\n");
677 if ( vfile
.Open() ) {
678 // Check if this version has been run before
680 for ( size_t i
= 0; i
< vfile
.GetLineCount(); i
++ ) {
681 // Check if this version has been run before
682 if ( vfile
.GetLine(i
) == newMule
) {
688 // We havent run this version before?
690 // Insert new at top to provide faster searches
691 vfile
.InsertLine( newMule
, 0 );
693 Trigger_New_version( newMule
);
696 // Keep at most 10 entires
697 while ( vfile
.GetLineCount() > 10 )
698 vfile
.RemoveLine( vfile
.GetLineCount() - 1 );
704 // Check if we have the old style locale config
705 wxString langId
= thePrefs::GetLanguageID();
706 if (!langId
.IsEmpty() && (langId
.GetChar(0) >= '0' && langId
.GetChar(0) <= '9')) {
707 wxString
info(_("Your locale has been changed to System Default due to a configuration change. Sorry."));
708 thePrefs::SetLanguageID(wxLang2Str(wxLANGUAGE_DEFAULT
));
709 ShowAlert(info
, _("Info"), wxCENTRE
| wxOK
| wxICON_ERROR
);
712 m_statistics
= new CStatistics();
714 clientlist
= new CClientList();
715 friendlist
= new CFriendList();
716 searchlist
= new CSearchList();
717 knownfiles
= new CKnownFileList();
718 serverlist
= new CServerList();
720 sharedfiles
= new CSharedFileList(knownfiles
);
721 clientcredits
= new CClientCreditsList();
723 // bugfix - do this before creating the uploadqueue
724 downloadqueue
= new CDownloadQueue();
725 uploadqueue
= new CUploadQueue();
726 ipfilter
= new CIPFilter();
728 // Creates all needed listening sockets
730 if (!ReinitializeNetwork(&msg
)) {
731 printf("\n%s\n", (const char *)unicode2char(msg
));
734 // Create main dialog, or fork to background (daemon).
735 InitGui(geometry_enabled
, geom_string
);
737 // Has to be created after the call to InitGui, as fork
738 // (when using posix threads) only replicates the mainthread,
739 // and the UBT constructor creates a thread.
740 uploadBandwidthThrottler
= new UploadBandwidthThrottler();
742 // These must be initialized after the gui is loaded.
744 downloadqueue
->LoadMetFiles(thePrefs::GetTempDir());
745 sharedfiles
->Reload();
747 if (thePrefs::IPFilterAutoLoad()) {
748 ipfilter
->Update(thePrefs::IPFilterURL());
752 // Ensure that the up/down ratio is used
753 CPreferences::CheckUlDlRatio();
755 // The user can start pressing buttons like mad if he feels like it.
756 m_app_state
= APP_STATE_RUNNING
;
758 // Kry - Load the sources seeds on app init
759 if (thePrefs::GetSrcSeedsOn()) {
760 downloadqueue
->LoadSourceSeeds();
763 if (!serverlist
->GetServerCount() && thePrefs::GetNetworkED2K()) {
764 // There are no servers and ED2K active -> ask for download.
765 // As we cannot ask in amuled, we just update there
766 // Kry TODO: Store server.met URL on preferences and use it here and in GUI.
768 if (wxYES
== wxMessageBox(
770 _("You don't have any server in the server list.\nDo you want aMule to download a new list now?")),
771 wxString(_("Server list download")),
773 static_cast<wxWindow
*>(theApp
->amuledlg
)))
776 // workaround amuled crash
778 serverlist
->UpdateServerMetFromURL(
779 wxT("http://gruk.org/server.met.gz"));
785 // Autoconnect if that option is enabled
786 if (thePrefs::DoAutoConnect() && (thePrefs::GetNetworkED2K() || thePrefs::GetNetworkKademlia())) {
787 AddLogLineM(true, _("Connecting"));
788 if (thePrefs::GetNetworkED2K()) {
789 theApp
->serverconnect
->ConnectToAnyServer();
796 // No webserver on Win at all (yet)
799 if (thePrefs::GetWSIsEnabled()) {
800 wxString aMuleConfigFile
= ConfigDir
+ wxT("amule.conf");
801 wxString amulewebPath
= wxT("amuleweb");
803 #if defined(__WXMAC__) && !defined(AMULE_DAEMON)
804 // For the Mac GUI application, look for amuleweb in the bundle
805 CFURLRef amulewebUrl
= CFBundleCopyAuxiliaryExecutableURL(
806 CFBundleGetMainBundle(), CFSTR("amuleweb"));
809 CFURLRef absoluteUrl
= CFURLCopyAbsoluteURL(amulewebUrl
);
810 CFRelease(amulewebUrl
);
813 CFStringRef amulewebCfstr
= CFURLCopyFileSystemPath(absoluteUrl
, kCFURLPOSIXPathStyle
);
814 CFRelease(absoluteUrl
);
815 amulewebPath
= wxMacCFStringHolder(amulewebCfstr
).AsString(wxLocale::GetSystemEncoding());
823 wxT("' '--amule-config-file=") +
826 CTerminationProcessAmuleweb
*p
= new CTerminationProcessAmuleweb(cmd
, &webserver_pid
);
827 webserver_pid
= wxExecute(cmd
, wxEXEC_ASYNC
, p
);
828 bool webserver_ok
= webserver_pid
> 0;
830 AddLogLineM(true, CFormat(_("webserver running on pid %d")) % webserver_pid
);
834 "You requested to run webserver from startup, "
835 "but the amuleweb binary cannot be run. "
836 "Please install the package containing aMule webserver, "
837 "or compile aMule using --enable-webserver and run make install"),
838 _("Error"), wxOK
| wxICON_ERROR
);
841 #endif /* ! __WXMSW__ */
843 // Start performing background tasks
844 CThreadScheduler::Start();
849 bool CamuleApp::ReinitializeNetwork(wxString
* msg
)
852 static bool firstTime
= true;
855 // TODO: Destroy previously created sockets
859 // Some sanity checks first
860 if (thePrefs::ECPort() == thePrefs::GetPort()) {
861 // Select a random usable port in the range 1025 ... 2^16 - 1
862 uint16 port
= thePrefs::ECPort();
863 while ( port
< 1024 || port
== thePrefs::GetPort() ) {
864 port
= (uint16
)rand();
866 thePrefs::SetECPort( port
);
869 wxT("Network configuration failed! You cannot use the same port\n")
870 wxT("for the main TCP port and the External Connections port.\n")
871 wxT("The EC port has been changed to avoid conflict, see the\n")
872 wxT("preferences for the new value.\n");
875 AddLogLineM( false, wxEmptyString
);
876 AddLogLineM( true, err
);
877 AddLogLineM( false, wxEmptyString
);
882 if (thePrefs::GetUDPPort() == thePrefs::GetPort() + 3) {
883 // Select a random usable value in the range 1025 ... 2^16 - 1
884 uint16 port
= thePrefs::GetUDPPort();
885 while ( port
< 1024 || port
== thePrefs::GetPort() + 3 ) {
886 port
= (uint16
)rand();
888 thePrefs::SetUDPPort( port
);
891 wxT("Network configuration failed! You set your UDP port to\n")
892 wxT("the value of the main TCP port plus 3.\n")
893 wxT("This port has been reserved for the Server-UDP port. The\n")
894 wxT("port value has been changed to avoid conflict, see the\n")
895 wxT("preferences for the new value\n");
898 AddLogLineM( false, wxEmptyString
);
899 AddLogLineM( true, err
);
900 AddLogLineM( false, wxEmptyString
);
905 // Create the address where we are going to listen
906 // TODO: read this from configuration file
907 amuleIPV4Address myaddr
[4];
909 // Create the External Connections Socket.
911 // Get ready to handle connections from apps like amulecmd
912 if (thePrefs::GetECAddress().IsEmpty() || !myaddr
[0].Hostname(thePrefs::GetECAddress())) {
913 myaddr
[0].AnyAddress();
915 myaddr
[0].Service(thePrefs::ECPort());
916 ECServerHandler
= new ExternalConn(myaddr
[0], msg
);
918 // Create the UDP socket TCP+3.
919 // Used for source asking on servers.
920 if (thePrefs::GetAddress().IsEmpty()) {
921 myaddr
[1].AnyAddress();
922 } else if (!myaddr
[1].Hostname(thePrefs::GetAddress())) {
923 myaddr
[1].AnyAddress();
924 AddLogLineM(true, CFormat(_("Could not bind ports to the specified address: %s"))
925 % thePrefs::GetAddress());
928 wxString ip
= myaddr
[1].IPAddress();
929 myaddr
[1].Service(thePrefs::GetPort()+3);
930 serverconnect
= new CServerConnect(serverlist
, myaddr
[1]);
931 *msg
<< CFormat( wxT("*** Server UDP socket (TCP+3) at %s:%u\n") )
932 % ip
% ((unsigned int)thePrefs::GetPort() + 3u);
934 // Create the ListenSocket (aMule TCP socket).
935 // Used for Client Port / Connections from other clients,
936 // Client to Client Source Exchange.
938 myaddr
[2] = myaddr
[1];
939 myaddr
[2].Service(thePrefs::GetPort());
940 listensocket
= new CListenSocket(myaddr
[2]);
941 *msg
<< CFormat( wxT("*** TCP socket (TCP) listening on %s:%u\n") )
942 % ip
% (unsigned int)(thePrefs::GetPort());
943 // This command just sets a flag to control maximum number of connections.
944 // Notify(true) has already been called to the ListenSocket, so events may
945 // be already comming in.
946 if (listensocket
->Ok()) {
947 listensocket
->StartListening();
949 // If we wern't able to start listening, we need to warn the user
951 err
= CFormat(_("Port %u is not available. You will be LOWID\n")) %
952 (unsigned int)(thePrefs::GetPort());
954 AddLogLineM(true, err
);
957 _("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.")) %
958 (unsigned int)(thePrefs::GetPort());
959 ShowAlert(err
, _("Error"), wxOK
| wxICON_ERROR
);
962 // Create the UDP socket.
963 // Used for extended eMule protocol, Queue Rating, File Reask Ping.
964 // Also used for Kademlia.
965 // Default is port 4672.
966 myaddr
[3] = myaddr
[1];
967 myaddr
[3].Service(thePrefs::GetUDPPort());
968 clientudp
= new CClientUDPSocket(myaddr
[3], thePrefs::GetProxyData());
969 if (!thePrefs::IsUDPDisabled()) {
970 *msg
<< CFormat( wxT("*** Client UDP socket (extended eMule) at %s:%u") )
971 % ip
% thePrefs::GetUDPPort();
973 *msg
<< wxT("*** Client UDP socket (extended eMule) disabled on preferences");
977 if (thePrefs::GetUPnPEnabled()) {
979 m_upnpMappings
[0] = CUPnPPortMapping(
982 thePrefs::GetUPnPECEnabled(),
983 "aMule TCP External Connections Socket");
984 m_upnpMappings
[1] = CUPnPPortMapping(
987 thePrefs::GetUPnPEnabled(),
988 "aMule UDP socket (TCP+3)");
989 m_upnpMappings
[2] = CUPnPPortMapping(
992 thePrefs::GetUPnPEnabled(),
993 "aMule TCP Listen Socket");
994 m_upnpMappings
[3] = CUPnPPortMapping(
997 thePrefs::GetUPnPEnabled(),
998 "aMule UDP Extended eMule Socket");
999 m_upnp
= new CUPnPControlPoint(thePrefs::GetUPnPTCPPort());
1000 m_upnp
->AddPortMappings(m_upnpMappings
);
1001 } catch(CUPnPException
&e
) {
1003 error_msg
<< e
.what();
1004 AddLogLineM(true, error_msg
);
1005 fprintf(stderr
, "%s\n", (const char *)unicode2char(error_msg
));
1013 // Returns a magnet ed2k URI
1014 wxString
CamuleApp::CreateMagnetLink(const CAbstractFile
*f
)
1018 uri
.AddField(wxT("dn"), f
->GetFileName().Cleanup(false).GetPrintable());
1019 uri
.AddField(wxT("xt"), wxString(wxT("urn:ed2k:")) + f
->GetFileHash().Encode().Lower());
1020 uri
.AddField(wxT("xl"), wxString::Format(wxT("%") wxLongLongFmtSpec
wxT("u"), f
->GetFileSize()));
1022 return uri
.GetLink();
1025 // Returns a ed2k file URL
1026 wxString
CamuleApp::CreateED2kLink(const CAbstractFile
*f
, bool add_source
, bool use_hostname
, bool addcryptoptions
)
1028 wxASSERT(!(!add_source
&& (use_hostname
|| addcryptoptions
)));
1029 // Construct URL like this: ed2k://|file|<filename>|<size>|<hash>|/
1030 wxString strURL
= CFormat(wxT("ed2k://|file|%s|%i|%s|/"))
1031 % f
->GetFileName().Cleanup(false)
1032 % f
->GetFileSize() % f
->GetFileHash().Encode();
1034 if (add_source
&& IsConnected() && !IsFirewalled()) {
1035 // Create the first part of the URL
1036 strURL
<< wxT("|sources,");
1038 strURL
<< thePrefs::GetYourHostname();
1040 uint32 clientID
= GetID();
1041 strURL
<< (uint8
) clientID
<< wxT(".") <<
1042 (uint8
)(clientID
>> 8) << wxT(".") <<
1043 (uint8
)(clientID
>> 16) << wxT(".") <<
1044 (uint8
)(clientID
>> 24);
1047 strURL
<< wxT(":") <<
1048 thePrefs::GetPort();
1050 if (addcryptoptions
) {
1051 const uint8 uSupportsCryptLayer
= thePrefs::IsClientCryptLayerSupported() ? 1 : 0;
1052 const uint8 uRequestsCryptLayer
= thePrefs::IsClientCryptLayerRequested() ? 1 : 0;
1053 const uint8 uRequiresCryptLayer
= thePrefs::IsClientCryptLayerRequired() ? 1 : 0;
1054 const uint8 byCryptOptions
= (uRequiresCryptLayer
<< 2) | (uRequestsCryptLayer
<< 1) | (uSupportsCryptLayer
<< 0) | (uSupportsCryptLayer
? 0x80 : 0x00);
1056 strURL
<< wxT(":") << byCryptOptions
;
1058 if (byCryptOptions
& 0x80) {
1059 strURL
<< wxT(":") << thePrefs::GetUserHash().Encode();
1062 strURL
<< wxT("|/");
1063 } else if (add_source
) {
1064 AddLogLineM(true, _("WARNING: You can't add yourself as a source for a ed2k link while being lowid."));
1067 // Result is "ed2k://|file|<filename>|<size>|<hash>|/|sources,[(<ip>|<hostname>):<port>[:cryptoptions[:hash]]]|/"
1071 // Returns a ed2k link with AICH info if available
1072 wxString
CamuleApp::CreateED2kAICHLink(const CKnownFile
* f
)
1074 // Create the first part of the URL
1075 wxString strURL
= CreateED2kLink(f
);
1076 // Append the AICH info
1077 if (f
->HasProperAICHHashSet()) {
1078 strURL
<< wxT("|h=") << f
->GetAICHMasterHash() << wxT("|/");
1081 // Result is "ed2k://|file|<filename>|<size>|<hash>|/|h=<AICH master hash>|/"
1085 /* Original implementation by Bouc7 of the eMule Project.
1086 aMule Signature idea was designed by BigBob and implemented
1087 by Un-Thesis, with design inputs and suggestions from bothie.
1089 void CamuleApp::OnlineSig(bool zero
/* reset stats (used on shutdown) */)
1091 // Do not do anything if online signature is disabled in Preferences
1092 if (!thePrefs::IsOnlineSignatureEnabled() || m_emulesig_path
.IsEmpty()) {
1093 // We do not need to check m_amulesig_path because if m_emulesig_path is empty,
1094 // that means m_amulesig_path is empty too.
1098 // Remove old signature files
1099 if ( wxFileExists( m_emulesig_path
) ) { wxRemoveFile( m_emulesig_path
); }
1100 if ( wxFileExists( m_amulesig_path
) ) { wxRemoveFile( m_amulesig_path
); }
1103 wxTextFile amulesig_out
;
1104 wxTextFile emulesig_out
;
1106 // Open both files if needed
1107 if ( !emulesig_out
.Create( m_emulesig_path
) ) {
1108 AddLogLineM(true, _("Failed to create OnlineSig File"));
1109 // Will never try again.
1110 m_amulesig_path
.Clear();
1111 m_emulesig_path
.Clear();
1115 if ( !amulesig_out
.Create(m_amulesig_path
) ) {
1116 AddLogLineM(true, _("Failed to create aMule OnlineSig File"));
1117 // Will never try again.
1118 m_amulesig_path
.Clear();
1119 m_emulesig_path
.Clear();
1123 wxString emulesig_string
;
1127 emulesig_string
= wxT("0\xA0.0|0.0|0");
1128 amulesig_out
.AddLine(wxT("0\n0\n0\n0\n0\n0\n0.0\n0.0\n0\n0"));
1130 if (IsConnectedED2K()) {
1132 temp
= wxString::Format(wxT("%d"),serverconnect
->GetCurrentServer()->GetPort());
1139 + serverconnect
->GetCurrentServer()->GetListName()
1141 // IP and port of the server
1142 + serverconnect
->GetCurrentServer()->GetFullIP()
1147 // Now for amule sig
1149 // Connected. State 1, full info
1150 amulesig_out
.AddLine(wxT("1"));
1152 amulesig_out
.AddLine(serverconnect
->GetCurrentServer()->GetListName());
1154 amulesig_out
.AddLine(serverconnect
->GetCurrentServer()->GetFullIP());
1156 amulesig_out
.AddLine(temp
);
1158 if (serverconnect
->IsLowID()) {
1159 amulesig_out
.AddLine(wxT("L"));
1161 amulesig_out
.AddLine(wxT("H"));
1164 } else if (serverconnect
->IsConnecting()) {
1165 emulesig_string
= wxT("0");
1167 // Connecting. State 2, No info.
1168 amulesig_out
.AddLine(wxT("2\n0\n0\n0\n0"));
1170 // Not connected to a server
1171 emulesig_string
= wxT("0");
1173 // Not connected, state 0, no info
1174 amulesig_out
.AddLine(wxT("0\n0\n0\n0\n0"));
1176 if (IsConnectedKad()) {
1177 if(Kademlia::CKademlia::IsFirewalled()) {
1178 // Connected. Firewalled. State 1.
1179 amulesig_out
.AddLine(wxT("1"));
1181 // Connected. State 2.
1182 amulesig_out
.AddLine(wxT("2"));
1185 // Not connected.State 0.
1186 amulesig_out
.AddLine(wxT("0"));
1188 emulesig_string
+= wxT("\xA");
1190 // Datarate for downloads
1191 temp
= wxString::Format(wxT("%.1f"), theStats::GetDownloadRate() / 1024.0);
1193 emulesig_string
+= temp
+ wxT("|");
1194 amulesig_out
.AddLine(temp
);
1196 // Datarate for uploads
1197 temp
= wxString::Format(wxT("%.1f"), theStats::GetUploadRate() / 1024.0);
1199 emulesig_string
+= temp
+ wxT("|");
1200 amulesig_out
.AddLine(temp
);
1202 // Number of users waiting for upload
1203 temp
= wxString::Format(wxT("%d"), theStats::GetWaitingUserCount());
1205 emulesig_string
+= temp
;
1206 amulesig_out
.AddLine(temp
);
1208 // Number of shared files (not on eMule)
1209 amulesig_out
.AddLine(wxString::Format(wxT("%d"), theStats::GetSharedFileCount()));
1212 // eMule signature finished here. Write the line to the wxTextFile.
1213 emulesig_out
.AddLine(emulesig_string
);
1215 // Now for aMule signature extras
1217 // Nick on the network
1218 amulesig_out
.AddLine(thePrefs::GetUserNick());
1220 // Total received in bytes
1221 amulesig_out
.AddLine( CFormat( wxT("%llu") ) % (theStats::GetSessionReceivedBytes() + thePrefs::GetTotalDownloaded()) );
1223 // Total sent in bytes
1224 amulesig_out
.AddLine( CFormat( wxT("%llu") ) % (theStats::GetSessionSentBytes() + thePrefs::GetTotalUploaded()) );
1228 amulesig_out
.AddLine(wxT(VERSION
" " SVNDATE
));
1230 amulesig_out
.AddLine(wxT(VERSION
));
1234 amulesig_out
.AddLine(wxT("0"));
1235 amulesig_out
.AddLine(wxT("0"));
1236 amulesig_out
.AddLine(wxT("0"));
1238 // Total received bytes in session
1239 amulesig_out
.AddLine( CFormat( wxT("%llu") ) %
1240 theStats::GetSessionReceivedBytes() );
1242 // Total sent bytes in session
1243 amulesig_out
.AddLine( CFormat( wxT("%llu") ) %
1244 theStats::GetSessionSentBytes() );
1247 amulesig_out
.AddLine(CFormat(wxT("%llu")) % theStats::GetUptimeSeconds());
1251 emulesig_out
.Write();
1252 amulesig_out
.Write();
1253 } //End Added By Bouc7
1256 // Gracefully handle fatal exceptions and print backtrace if possible
1257 void CamuleApp::OnFatalException()
1259 /* Print the backtrace */
1260 fprintf(stderr
, "\n--------------------------------------------------------------------------------\n");
1261 fprintf(stderr
, "A fatal error has occurred and aMule has crashed.\n");
1262 fprintf(stderr
, "Please assist us in fixing this problem by posting the backtrace below in our\n");
1263 fprintf(stderr
, "'aMule Crashes' forum and include as much information as possible regarding the\n");
1264 fprintf(stderr
, "circumstances of this crash. The forum is located here:\n");
1265 fprintf(stderr
, " http://forum.amule.org/index.php?board=67.0\n");
1266 fprintf(stderr
, "If possible, please try to generate a real backtrace of this crash:\n");
1267 fprintf(stderr
, " http://www.amule.org/wiki/index.php/Backtraces\n\n");
1268 fprintf(stderr
, "----------------------------=| BACKTRACE FOLLOWS: |=----------------------------\n");
1269 fprintf(stderr
, "Current version is: %s\n", strFullMuleVersion
);
1270 fprintf(stderr
, "Running on: %s\n\n", strOSDescription
);
1272 print_backtrace(1); // 1 == skip this function.
1274 fprintf(stderr
, "\n--------------------------------------------------------------------------------\n");
1278 // Sets the localization of aMule
1279 void CamuleApp::Localize_mule()
1281 InitCustomLanguages();
1282 InitLocale(m_locale
, StrLang2wx(thePrefs::GetLanguageID()));
1283 if (!m_locale
.IsOk()) {
1284 AddLogLineM(false,_("The selected locale seems not to be installed on your box. (Note: I'll try to set it anyway)"));
1289 // Displays information related to important changes in aMule.
1290 // Is called when the user runs a new version of aMule
1291 void CamuleApp::Trigger_New_version(wxString new_version
)
1293 wxString info
= wxT(" --- ") + CFormat(_("This is the first time you run aMule %s")) % new_version
+ wxT(" ---\n\n");
1294 if (new_version
== wxT("SVN")) {
1295 info
+= _("This version is a testing version, updated daily, and\n");
1296 info
+= _("we give no warranty it won't break anything, burn your house,\n");
1297 info
+= _("or kill your dog. But it *should* be safe to use anyway.\n");
1298 } else if (new_version
== wxT("2.2.0")) {
1299 thePrefs::SetAddServersFromServer(false);
1300 thePrefs::SetAddServersFromClient(false);
1301 info
+= _("The following options have been changed in this release for security reasons:\n");
1302 info
+= _("\n* Enabled Protocol Obfuscation support for incoming and outgoing connections.\n");
1303 info
+= _("\n* Disabled updating the server list from other server and clients.\n");
1304 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.");
1309 info
+= _("More information, support and new releases can found at our homepage,\n");
1310 info
+= _("at www.aMule.org, or in our IRC channel #aMule at irc.freenode.net.\n");
1312 info
+= _("Feel free to report any bugs to http://forum.amule.org");
1314 ShowAlert(info
, _("Info"), wxCENTRE
| wxOK
| wxICON_ERROR
);
1318 void CamuleApp::SetOSFiles(const wxString new_path
)
1320 if ( thePrefs::IsOnlineSignatureEnabled() ) {
1321 if ( ::wxDirExists(new_path
) ) {
1322 m_emulesig_path
= JoinPaths(new_path
, wxT("onlinesig.dat"));
1323 m_amulesig_path
= JoinPaths(new_path
, wxT("amulesig.dat"));
1325 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
);
1326 m_emulesig_path
.Clear();
1327 m_amulesig_path
.Clear();
1330 m_emulesig_path
.Clear();
1331 m_amulesig_path
.Clear();
1337 #ifndef wxUSE_STACKWALKER
1338 #define wxUSE_STACKWALKER 0
1340 void CamuleApp::OnAssertFailure(const wxChar
* file
, int line
,
1341 const wxChar
* func
, const wxChar
* cond
, const wxChar
* msg
)
1343 if (!wxUSE_STACKWALKER
|| !wxThread::IsMain() || !IsRunning()) {
1344 wxString errmsg
= CFormat( wxT("%s:%s:%d: Assertion '%s' failed. %s") )
1345 % file
% func
% line
% cond
% ( msg
? msg
: wxT("") );
1347 fprintf(stderr
, "Assertion failed: %s\n", (const char*)unicode2char(errmsg
));
1349 // Skip the function-calls directly related to the assert call.
1350 fprintf(stderr
, "\nBacktrace follows:\n");
1352 fprintf(stderr
, "\n");
1355 if (wxThread::IsMain() && IsRunning()) {
1356 AMULE_APP_BASE::OnAssertFailure(file
, line
, func
, cond
, msg
);
1358 // Abort, allows gdb to catch the assertion
1365 void CamuleApp::OnUDPDnsDone(CMuleInternalEvent
& evt
)
1367 CServerUDPSocket
* socket
=(CServerUDPSocket
*)evt
.GetClientData();
1368 socket
->OnHostnameResolved(evt
.GetExtraLong());
1372 void CamuleApp::OnSourceDnsDone(CMuleInternalEvent
& evt
)
1374 downloadqueue
->OnHostnameResolved(evt
.GetExtraLong());
1378 void CamuleApp::OnServerDnsDone(CMuleInternalEvent
& evt
)
1380 printf("Server hostname notified\n");
1381 serverconnect
->OnServerHostnameResolved(evt
.GetClientData(), evt
.GetExtraLong());
1385 void CamuleApp::OnTCPTimer(CTimerEvent
& WXUNUSED(evt
))
1390 serverconnect
->StopConnectionTry();
1391 if (IsConnectedED2K() ) {
1394 serverconnect
->ConnectToAnyServer();
1398 void CamuleApp::OnCoreTimer(CTimerEvent
& WXUNUSED(evt
))
1400 // Former TimerProc section
1401 static uint64 msPrev1
, msPrev5
, msPrevSave
, msPrevHist
, msPrevOS
, msPrevKnownMet
;
1402 uint64 msCur
= theStats::GetUptimeMillis();
1408 #ifndef AMULE_DAEMON
1409 // Check if we should terminate the app
1410 if ( g_shutdownSignal
) {
1411 wxWindow
* top
= GetTopWindow();
1416 // No top-window, have to force termination.
1422 CLogger::FlushPendingEntries();
1424 uploadqueue
->Process();
1425 downloadqueue
->Process();
1426 //theApp->clientcredits->Process();
1427 theStats::CalculateRates();
1429 if (msCur
-msPrevHist
> 1000) {
1430 // unlike the other loop counters in this function this one will sometimes
1431 // produce two calls in quick succession (if there was a gap of more than one
1432 // second between calls to TimerProc) - this is intentional! This way the
1433 // history list keeps an average of one node per second and gets thinned out
1434 // correctly as time progresses.
1437 m_statistics
->RecordHistory();
1442 if (msCur
-msPrev1
> 1000) { // approximately every second
1444 clientcredits
->Process();
1445 clientlist
->Process();
1447 // Publish files to server if needed.
1448 sharedfiles
->Process();
1450 if( Kademlia::CKademlia::IsRunning() ) {
1451 Kademlia::CKademlia::Process();
1452 if(Kademlia::CKademlia::GetPrefs()->HasLostConnection()) {
1456 if (thePrefs::Reconnect()) {
1462 if( serverconnect
->IsConnecting() && !serverconnect
->IsSingleConnect() ) {
1463 serverconnect
->TryAnotherConnectionrequest();
1465 if (serverconnect
->IsConnecting()) {
1466 serverconnect
->CheckForTimeout();
1468 listensocket
->UpdateConnectionsStatus();
1473 if (msCur
-msPrev5
> 5000) { // every 5 seconds
1475 listensocket
->Process();
1478 if (msCur
-msPrevSave
>= 60000) {
1482 // Save total upload/download to preferences
1483 wxConfigBase
* cfg
= wxConfigBase::Get();
1484 buffer
= CFormat(wxT("%llu")) % (theStats::GetSessionReceivedBytes() + thePrefs::GetTotalDownloaded());
1485 cfg
->Write(wxT("/Statistics/TotalDownloadedBytes"), buffer
);
1487 buffer
= CFormat(wxT("%llu")) % (theStats::GetSessionSentBytes() + thePrefs::GetTotalUploaded());
1488 cfg
->Write(wxT("/Statistics/TotalUploadedBytes"), buffer
);
1490 // Write changes to file
1496 if (msCur
- msPrevOS
>= thePrefs::GetOSUpdate() * 1000ull) {
1497 OnlineSig(); // Added By Bouc7
1501 if (msCur
- msPrevKnownMet
>= 30*60*1000/*There must be a prefs option for this*/) {
1502 // Save Shared Files data
1504 msPrevKnownMet
= msCur
;
1508 // Recomended by lugdunummaster himself - from emule 0.30c
1509 serverconnect
->KeepConnectionAlive();
1514 void CamuleApp::OnFinishedHashing(CHashingEvent
& evt
)
1516 wxCHECK_RET(evt
.GetResult(), wxT("No result of hashing"));
1518 CKnownFile
* owner
= const_cast<CKnownFile
*>(evt
.GetOwner());
1519 CKnownFile
* result
= evt
.GetResult();
1522 // Check if the partfile still exists, as it might have
1523 // been deleted in the mean time.
1524 if (downloadqueue
->IsPartFile(owner
)) {
1525 // This cast must not be done before the IsPartFile
1526 // call, as dynamic_cast will barf on dangling pointers.
1527 dynamic_cast<CPartFile
*>(owner
)->PartFileHashFinished(result
);
1530 static int filecount
;
1531 static uint64 bytecount
;
1533 if (knownfiles
->SafeAddKFile(result
)) {
1534 AddDebugLogLineM(false, logKnownFiles
,
1535 CFormat(wxT("Safe adding file to sharedlist: %s")) % result
->GetFileName());
1536 sharedfiles
->SafeAddKFile(result
);
1539 bytecount
+= result
->GetFileSize();
1540 // If we have added 30 files or files with a total size of ~300mb
1541 if ( ( filecount
== 30 ) || ( bytecount
>= 314572800 ) ) {
1542 AddDebugLogLineM(false, logKnownFiles
, wxT("Failsafe for crash on file hashing creation"));
1543 if ( m_app_state
!= APP_STATE_SHUTTINGDOWN
) {
1550 AddDebugLogLineM(false, logKnownFiles
,
1551 CFormat(wxT("File not added to sharedlist: %s")) % result
->GetFileName());
1558 void CamuleApp::OnFinishedAICHHashing(CHashingEvent
& evt
)
1560 wxCHECK_RET(evt
.GetResult(), wxT("No result of AICH-hashing"));
1562 CKnownFile
* owner
= const_cast<CKnownFile
*>(evt
.GetOwner());
1563 std::auto_ptr
<CKnownFile
> result(evt
.GetResult());
1565 // Check that the owner is still valid
1566 if (knownfiles
->IsKnownFile(owner
)) {
1567 if (result
->GetAICHHashset()->GetStatus() == AICH_HASHSETCOMPLETE
) {
1568 CAICHHashSet
* oldSet
= owner
->GetAICHHashset();
1569 CAICHHashSet
* newSet
= result
->GetAICHHashset();
1571 owner
->SetAICHHashset(newSet
);
1572 newSet
->SetOwner(owner
);
1574 result
->SetAICHHashset(oldSet
);
1575 oldSet
->SetOwner(result
.get());
1581 void CamuleApp::OnFinishedCompletion(CCompletionEvent
& evt
)
1583 CPartFile
* completed
= const_cast<CPartFile
*>(evt
.GetOwner());
1584 wxCHECK_RET(completed
, wxT("Completion event sent for unspecified file"));
1585 wxASSERT_MSG(downloadqueue
->IsPartFile(completed
), wxT("CCompletionEvent for unknown partfile."));
1587 completed
->CompleteFileEnded(evt
.ErrorOccured(), evt
.GetFullPath());
1588 if (evt
.ErrorOccured()) {
1589 CUserEvents::ProcessEvent(CUserEvents::ErrorOnCompletion
, completed
);
1592 // Check if we should execute an script/app/whatever.
1593 CUserEvents::ProcessEvent(CUserEvents::DownloadCompleted
, completed
);
1597 void CamuleApp::OnNotifyEvent(CMuleGUIEvent
& evt
)
1599 #if defined(AMULE_DAEMON)
1602 if (theApp
->amuledlg
) {
1609 void CamuleApp::ShutDown()
1612 AddDebugLogLineM(false, logGeneral
, wxT("CamuleApp::ShutDown() has started."));
1614 // Signal the hashing thread to terminate
1615 m_app_state
= APP_STATE_SHUTTINGDOWN
;
1619 // Kry - Save the sources seeds on app exit
1620 if (thePrefs::GetSrcSeedsOn()) {
1621 downloadqueue
->SaveSourceSeeds();
1624 OnlineSig(true); // Added By Bouc7
1626 // Close sockets to avoid new clients coming in
1628 listensocket
->Close();
1629 listensocket
->KillAllSockets();
1632 if (serverconnect
) {
1633 serverconnect
->Disconnect();
1636 ECServerHandler
->KillAllSockets();
1639 if (thePrefs::GetUPnPEnabled()) {
1641 m_upnp
->DeletePortMappings(m_upnpMappings
);
1646 // saving data & stuff
1651 thePrefs::Add2TotalDownloaded(theStats::GetSessionReceivedBytes());
1652 thePrefs::Add2TotalUploaded(theStats::GetSessionSentBytes());
1659 clientlist
->DeleteAll();
1662 CThreadScheduler::Terminate();
1664 theApp
->uploadBandwidthThrottler
->EndThread();
1667 AddDebugLogLineM(false, logGeneral
, wxT("CamuleApp::ShutDown() has ended."));
1671 bool CamuleApp::AddServer(CServer
*srv
, bool fromUser
)
1673 if ( serverlist
->AddServer(srv
, fromUser
) ) {
1674 Notify_ServerAdd(srv
);
1681 void CamuleApp::AddLogLine(const wxString
&msg
)
1683 // At most one trailing new-line, which we add
1684 wxString message
= msg
;
1685 while ( !message
.IsEmpty() && message
.Last() == wxT('\n') ) {
1686 message
.RemoveLast();
1689 wxString full_line
= wxDateTime::Now().FormatISODate() + wxT(" ") +
1690 wxDateTime::Now().FormatISOTime() + wxT(": ") + message
+ wxT("\n");
1692 wxStringInputStream
stream(full_line
);
1694 if (applog
) { // This check is needed, because if we assert before the logger is created, it will crash.
1695 (*applog
) << stream
;
1699 if (enable_stdout_log
) {
1700 printf("%s", (const char*)unicode2char(full_line
));
1705 uint32
CamuleApp::GetPublicIP(bool ignorelocal
) const
1707 if (m_dwPublicIP
== 0) {
1708 if (Kademlia::CKademlia::IsConnected() && Kademlia::CKademlia::GetIPAddress() ) {
1709 return wxUINT32_SWAP_ALWAYS(Kademlia::CKademlia::GetIPAddress());
1711 return ignorelocal
? 0 : m_localip
;
1715 return m_dwPublicIP
;
1719 void CamuleApp::SetPublicIP(const uint32 dwIP
)
1721 wxASSERT((dwIP
== 0) || !IsLowID(dwIP
));
1723 if (dwIP
!= 0 && dwIP
!= m_dwPublicIP
&& serverlist
!= NULL
) {
1724 m_dwPublicIP
= dwIP
;
1725 serverlist
->CheckForExpiredUDPKeys();
1727 m_dwPublicIP
= dwIP
;
1732 wxString
CamuleApp::GetLog(bool reset
)
1734 ConfigDir
= GetConfigDir();
1736 logfile
.Open(ConfigDir
+ wxT("logfile"));
1737 if ( !logfile
.IsOpened() ) {
1738 return wxTRANSLATE("ERROR: can't open logfile");
1740 int len
= logfile
.Length();
1742 return wxTRANSLATE("WARNING: logfile is empty. Something is wrong.");
1744 char *tmp_buffer
= new char[len
+ sizeof(wxChar
)];
1745 logfile
.Read(tmp_buffer
, len
);
1746 memset(tmp_buffer
+ len
, 0, sizeof(wxChar
));
1748 // try to guess file format
1750 if (tmp_buffer
[0] && tmp_buffer
[1]) {
1751 str
= wxString(UTF82unicode(tmp_buffer
));
1753 str
= wxString((wxWCharBuffer
&)tmp_buffer
);
1756 delete [] tmp_buffer
;
1759 applog
= new wxFFileOutputStream(ConfigDir
+ wxT("logfile"));
1760 if ( applog
->Ok() ) {
1761 AddLogLine(_("Log has been reset"));
1771 wxString
CamuleApp::GetServerLog(bool reset
)
1773 wxString ret
= server_msg
;
1780 wxString
CamuleApp::GetDebugLog(bool reset
)
1782 return GetLog(reset
);
1786 void CamuleApp::AddServerMessageLine(wxString
&msg
)
1788 server_msg
+= msg
+ wxT("\n");
1789 AddLogLine(CFormat(_("ServerMessage: %s")) % msg
);
1794 void CamuleApp::OnFinishedHTTPDownload(CMuleInternalEvent
& event
)
1796 switch (event
.GetInt()) {
1798 ipfilter
->DownloadFinished(event
.GetExtraLong());
1800 case HTTP_ServerMet
:
1801 serverlist
->DownloadFinished(event
.GetExtraLong());
1803 case HTTP_ServerMetAuto
:
1804 serverlist
->AutoDownloadFinished(event
.GetExtraLong());
1806 case HTTP_VersionCheck
:
1807 CheckNewVersion(event
.GetExtraLong());
1810 if (event
.GetExtraLong() != -1) {
1812 wxString file
= ConfigDir
+ wxT("nodes.dat");
1813 if (wxFileExists(file
)) {
1817 if ( Kademlia::CKademlia::IsRunning() ) {
1818 Kademlia::CKademlia::Stop();
1821 wxRenameFile(file
+ wxT(".download"),file
);
1823 Kademlia::CKademlia::Start();
1824 theApp
->ShowConnectionState();
1827 AddLogLineM(true, _("Failed to download the nodes list."));
1833 void CamuleApp::CheckNewVersion(uint32 result
)
1836 wxString filename
= ConfigDir
+ wxT("last_version_check");
1839 if (!file
.Open(filename
)) {
1840 AddLogLineM(true, _("Failed to open the downloaded version check file") );
1842 } else if (!file
.GetLineCount()) {
1843 AddLogLineM(true, _("Corrupted version check file"));
1845 wxString versionLine
= file
.GetFirstLine();
1846 wxStringTokenizer
tkz(versionLine
, wxT("."));
1848 AddDebugLogLineM(false, logGeneral
, wxString(wxT("Running: ")) + wxT(VERSION
) + wxT(", Version check: ") + versionLine
);
1850 long fields
[] = {0, 0, 0};
1851 for (int i
= 0; i
< 3; ++i
) {
1852 if (!tkz
.HasMoreTokens()) {
1853 AddLogLineM(true, _("Corrupted version check file"));
1856 wxString token
= tkz
.GetNextToken();
1858 if (!token
.ToLong(&fields
[i
])) {
1859 AddLogLineM(true, _("Corrupted version check file"));
1865 long curVer
= make_full_ed2k_version(VERSION_MJR
, VERSION_MIN
, VERSION_UPDATE
);
1866 long newVer
= make_full_ed2k_version(fields
[0], fields
[1], fields
[2]);
1868 if (curVer
< newVer
) {
1869 AddLogLineM(true, _("You are using an outdated version of aMule!"));
1870 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]));
1871 AddLogLineM(false, _("The latest version can always be found at http://www.amule.org"));
1873 printf("%s\n", (const char*)unicode2UTF8(wxString::Format(
1874 _("WARNING: Your aMuled version is outdated: %i.%i.%i < %li.%li.%li"),
1875 VERSION_MJR
, VERSION_MIN
, VERSION_UPDATE
, fields
[0], fields
[1], fields
[2])));
1878 AddLogLineM(false, _("Your copy of aMule is up to date."));
1883 wxRemoveFile(filename
);
1885 AddLogLineM(true, _("Failed to download the version check file") );
1891 bool CamuleApp::IsConnected()
1893 return (IsConnectedED2K() || IsConnectedKad());
1897 bool CamuleApp::IsConnectedED2K()
1899 return serverconnect
&& serverconnect
->IsConnected();
1903 bool CamuleApp::IsConnectedKad()
1905 return Kademlia::CKademlia::IsConnected();
1909 bool CamuleApp::IsFirewalled()
1911 if (theApp
->IsConnectedED2K() && !theApp
->serverconnect
->IsLowID()) {
1912 return false; // we have an eD2K HighID -> not firewalled
1915 return IsFirewalledKad(); // If kad says ok, it's ok.
1918 bool CamuleApp::IsFirewalledKad()
1920 if (Kademlia::CKademlia::IsConnected() && !Kademlia::CKademlia::IsFirewalled()) {
1921 return false; // we have an Kad HighID -> not firewalled
1924 return true; // firewalled
1927 bool CamuleApp::IsKadRunning()
1929 return Kademlia::CKademlia::IsRunning();
1932 bool CamuleApp::DoCallback( CUpDownClient
*client
)
1934 if(Kademlia::CKademlia::IsConnected()) {
1935 if(IsConnectedED2K()) {
1936 if(serverconnect
->IsLowID()) {
1937 if(Kademlia::CKademlia::IsFirewalled()) {
1938 //Both Connected - Both Firewalled
1941 if(client
->GetServerIP() == theApp
->serverconnect
->GetCurrentServer()->GetIP() &&
1942 client
->GetServerPort() == theApp
->serverconnect
->GetCurrentServer()->GetPort()) {
1943 // Both Connected - Server lowID, Kad Open - Client on same server
1944 // We prevent a callback to the server as this breaks the protocol
1945 // and will get you banned.
1948 // Both Connected - Server lowID, Kad Open - Client on remote server
1953 //Both Connected - Server HighID, Kad don't care
1957 if(Kademlia::CKademlia::IsFirewalled()) {
1958 //Only Kad Connected - Kad Firewalled
1961 //Only Kad Conected - Kad Open
1966 if( IsConnectedED2K() ) {
1967 if( serverconnect
->IsLowID() ) {
1968 //Only Server Connected - Server LowID
1971 //Only Server Connected - Server HighID
1975 //We are not connected at all!
1981 void CamuleApp::ShowUserCount() {
1982 uint32 totaluser
= 0, totalfile
= 0;
1984 theApp
->serverlist
->GetUserFileStatus( totaluser
, totalfile
);
1988 static const wxString s_singlenetstatusformat
= _("Users: %s | Files: %s");
1989 static const wxString s_bothnetstatusformat
= _("Users: E: %s K: %s | Files: E: %s K: %s");
1991 if (thePrefs::GetNetworkED2K() && thePrefs::GetNetworkKademlia()) {
1992 buffer
= CFormat(s_bothnetstatusformat
) % CastItoIShort(totaluser
) % CastItoIShort(Kademlia::CKademlia::GetKademliaUsers()) % CastItoIShort(totalfile
) % CastItoIShort(Kademlia::CKademlia::GetKademliaFiles());
1993 } else if (thePrefs::GetNetworkED2K()) {
1994 buffer
= CFormat(s_singlenetstatusformat
) % CastItoIShort(totaluser
) % CastItoIShort(totalfile
);
1995 } else if (thePrefs::GetNetworkKademlia()) {
1996 buffer
= CFormat(s_singlenetstatusformat
) % CastItoIShort(Kademlia::CKademlia::GetKademliaUsers()) % CastItoIShort(Kademlia::CKademlia::GetKademliaFiles());
1998 buffer
= _("No networks selected");
2001 Notify_ShowUserCount(buffer
);
2005 void CamuleApp::ListenSocketHandler(wxSocketEvent
& event
)
2007 wxCHECK_RET(listensocket
, wxT("Connection-event for NULL'd listen-socket"));
2008 wxCHECK_RET(event
.GetSocketEvent() == wxSOCKET_CONNECTION
,
2009 wxT("Invalid event received for listen-socket"));
2011 if (m_app_state
== APP_STATE_RUNNING
) {
2012 listensocket
->OnAccept(0);
2013 } else if (m_app_state
== APP_STATE_STARTING
) {
2014 // When starting up, connection may be made before we are able
2015 // to handle them. However, if these are ignored, no futher
2016 // connection-events will be triggered, so we have to accept it.
2017 wxSocketBase
* socket
= listensocket
->Accept(false);
2019 wxCHECK_RET(socket
, wxT("NULL returned by Accept() during startup"));
2026 void CamuleApp::ShowConnectionState()
2028 static uint8 old_state
= (1<<7); // This flag doesn't exist
2032 if (theApp
->serverconnect
->IsConnected()) {
2033 state
|= CONNECTED_ED2K
;
2036 if (Kademlia::CKademlia::IsRunning()) {
2037 if (Kademlia::CKademlia::IsConnected()) {
2038 if (!Kademlia::CKademlia::IsFirewalled()) {
2039 state
|= CONNECTED_KAD_OK
;
2041 state
|= CONNECTED_KAD_FIREWALLED
;
2044 state
|= CONNECTED_KAD_NOT
;
2048 Notify_ShowConnState(state
);
2050 if (old_state
!= state
) {
2051 // Get the changed value
2052 int changed_flags
= old_state
^ state
;
2054 if (changed_flags
& CONNECTED_ED2K
) {
2055 // ED2K status changed
2056 wxString connected_server
;
2057 CServer
* ed2k_server
= theApp
->serverconnect
->GetCurrentServer();
2059 connected_server
= ed2k_server
->GetListName();
2061 if (state
& CONNECTED_ED2K
) {
2062 // We connected to some server
2063 const wxString id
= theApp
->serverconnect
->IsLowID() ? _("with LowID") : _("with HighID");
2065 AddLogLine(CFormat(_("Connected to %s %s")) % connected_server
% id
);
2067 if ( theApp
->serverconnect
->IsConnecting() ) {
2068 AddLogLine(CFormat(_("Connecting to %s")) % connected_server
);
2070 AddLogLine(_("Disconnected from ED2K"));
2075 if (changed_flags
& CONNECTED_KAD_NOT
) {
2076 if (state
& CONNECTED_KAD_NOT
) {
2077 AddLogLine(_("Kad started."));
2079 AddLogLine(_("Kad stopped."));
2083 if (changed_flags
& (CONNECTED_KAD_OK
| CONNECTED_KAD_FIREWALLED
)) {
2084 if (state
& (CONNECTED_KAD_OK
| CONNECTED_KAD_FIREWALLED
)) {
2085 if (state
& CONNECTED_KAD_OK
) {
2086 AddLogLine(_("Connected to Kad (ok)"));
2088 AddLogLine(_("Connected to Kad (firewalled)"));
2091 AddLogLine(_("Disconnected from Kad"));
2097 theApp
->downloadqueue
->OnConnectionState(IsConnected());
2101 Notify_ShowConnState(state
);
2105 void CamuleApp::UDPSocketHandler(wxSocketEvent
& event
)
2107 CMuleUDPSocket
* socket
= (CMuleUDPSocket
*)(event
.GetClientData());
2108 wxCHECK_RET(socket
, wxT("No socket owner specified."));
2110 if (IsOnShutDown() || thePrefs::IsUDPDisabled()) return;
2113 if (event
.GetSocketEvent() == wxSOCKET_INPUT
) {
2114 // Back to the queue!
2115 theApp
->AddPendingEvent(event
);
2120 switch (event
.GetSocketEvent()) {
2121 case wxSOCKET_INPUT
:
2122 socket
->OnReceive(0);
2125 case wxSOCKET_OUTPUT
:
2130 socket
->OnDisconnected(0);
2140 void CamuleApp::OnUnhandledException()
2142 // Call the generic exception-handler.
2143 fprintf(stderr
, "\taMule Version: %s\n", (const char*)unicode2char(GetFullMuleVersion()));
2144 ::OnUnhandledException();
2147 void CamuleApp::StartKad()
2149 if (!Kademlia::CKademlia::IsRunning() && thePrefs::GetNetworkKademlia()) {
2150 // Kad makes no sense without the Client-UDP socket.
2151 if (!thePrefs::IsUDPDisabled()) {
2152 Kademlia::CKademlia::Start();
2154 AddLogLineM(true,_("Kad network cannot be used if UDP port is disabled on preferences, not starting."));
2156 } else if (!thePrefs::GetNetworkKademlia()) {
2157 AddLogLineM(true,_("Kad network disabled on preferences, not connecting."));
2161 void CamuleApp::StopKad()
2163 // Stop Kad if it's running
2164 if (Kademlia::CKademlia::IsRunning()) {
2165 Kademlia::CKademlia::Stop();
2170 void CamuleApp::BootstrapKad(uint32 ip
, uint16 port
)
2172 if (!Kademlia::CKademlia::IsRunning()) {
2173 Kademlia::CKademlia::Start();
2174 theApp
->ShowConnectionState();
2177 Kademlia::CKademlia::Bootstrap(ip
, port
, true);
2181 void CamuleApp::UpdateNotesDat(const wxString
& url
)
2183 wxString
strTempFilename(theApp
->ConfigDir
+ wxT("nodes.dat.download"));
2185 CHTTPDownloadThread
*downloader
= new CHTTPDownloadThread(url
, strTempFilename
, HTTP_NodesDat
);
2186 downloader
->Create();
2191 void CamuleApp::DisconnectED2K()
2193 // Stop ED2K if it's running
2194 if (IsConnectedED2K()) {
2195 serverconnect
->Disconnect();
2199 bool CamuleApp::CryptoAvailable() const
2201 return clientcredits
&& clientcredits
->CryptoAvailable();
2204 uint32
CamuleApp::GetED2KID() const {
2205 return serverconnect
? serverconnect
->GetClientID() : 0;
2208 uint32
CamuleApp::GetID() const {
2211 if( Kademlia::CKademlia::IsConnected() && !Kademlia::CKademlia::IsFirewalled() ) {
2212 // We trust Kad above ED2K
2213 ID
= ENDIAN_NTOHL(Kademlia::CKademlia::GetIPAddress());
2214 } else if( theApp
->serverconnect
->IsConnected() ) {
2215 ID
= theApp
->serverconnect
->GetClientID();
2216 } else if ( Kademlia::CKademlia::IsConnected() && Kademlia::CKademlia::IsFirewalled() ) {
2217 // A firewalled Kad client get's a "1"
2226 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_FINISHED_HTTP_DOWNLOAD
)
2227 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_SOURCE_DNS_DONE
)
2228 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_UDP_DNS_DONE
)
2229 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_SERVER_DNS_DONE
)
2230 // File_checked_for_headers