Upstream tarball 9882
[amule.git] / src / amule.cpp
blob0b705aeab32d7cf8b789e424d98649a8faeba1bd
1 //
2 // This file is part of the aMule Project.
3 //
4 // Copyright (c) 2003-2008 aMule Team ( admin@amule.org / http://www.amule.org )
5 // Copyright (c) 2002-2008 Merkur ( devs@emule-project.net / http://www.emule-project.net )
6 //
7 // Any parts of this program derived from the xMule, lMule or eMule project,
8 // or contributed by third-party developers are copyrighted by their
9 // respective authors.
11 // This program is free software; you can redistribute it and/or modify
12 // it under the terms of the GNU General Public License as published by
13 // the Free Software Foundation; either version 2 of the License, or
14 // (at your option) any later version.
16 // This program is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU General Public License for more details.
20 //
21 // You should have received a copy of the GNU General Public License
22 // along with this program; if not, write to the Free Software
23 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #define AMULE_CPP
30 #include "amule.h" // Interface declarations.
32 #include <csignal>
33 #include <cstring>
34 #include <wx/process.h>
35 #include <wx/sstream.h>
37 #ifdef HAVE_CONFIG_H
38 #include "config.h" // Needed for HAVE_GETRLIMIT, HAVE_SETRLIMIT,
39 // HAVE_SYS_RESOURCE_H, HAVE_SYS_STATVFS_H, VERSION
40 // and ENABLE_NLS
41 #endif
43 #include <common/ClientVersion.h>
45 #include <wx/cmdline.h> // Needed for wxCmdLineParser
46 #include <wx/config.h> // Do_not_auto_remove (win32)
47 #include <wx/fileconf.h>
48 #include <wx/snglinst.h>
49 #include <wx/tokenzr.h>
50 #include <wx/wfstream.h>
53 #include <common/Format.h> // Needed for CFormat
54 #include "kademlia/kademlia/Kademlia.h"
55 #include "kademlia/kademlia/Prefs.h"
56 #include "kademlia/kademlia/UDPFirewallTester.h"
57 #include "ClientCreditsList.h" // Needed for CClientCreditsList
58 #include "ClientList.h" // Needed for CClientList
59 #include "ClientUDPSocket.h" // Needed for CClientUDPSocket & CMuleUDPSocket
60 #include "ED2KLink.h" // Needed for command line passing of links
61 #include "ExternalConn.h" // Needed for ExternalConn & MuleConnection
62 #include <common/FileFunctions.h> // Needed for CDirIterator
63 #include "FriendList.h" // Needed for CFriendList
64 #include "HTTPDownload.h" // Needed for CHTTPDownloadThread
65 #include "InternalEvents.h" // Needed for CMuleInternalEvent
66 #include "IPFilter.h" // Needed for CIPFilter
67 #include "KnownFileList.h" // Needed for CKnownFileList
68 #include "ListenSocket.h" // Needed for CListenSocket
69 #include "Logger.h" // Needed for CLogger // Do_not_auto_remove
70 #include "MagnetURI.h" // Needed for CMagnetURI
71 #include "OtherFunctions.h"
72 #include "PartFile.h" // Needed for CPartFile
73 #include "Preferences.h" // Needed for CPreferences
74 #include "SearchList.h" // Needed for CSearchList
75 #include "Server.h" // Needed for GetListName
76 #include "ServerList.h" // Needed for CServerList
77 #include "ServerConnect.h" // Needed for CServerConnect
78 #include "ServerUDPSocket.h" // Needed for CServerUDPSocket
79 #include "Statistics.h" // Needed for CStatistics
80 #include "TerminationProcessAmuleweb.h" // Needed for CTerminationProcessAmuleweb
81 #include "ThreadTasks.h"
82 #include "updownclient.h" // Needed for CUpDownClient
83 #include "UploadQueue.h" // Needed for CUploadQueue
84 #include "UploadBandwidthThrottler.h"
85 #include "UserEvents.h"
86 #include "ScopedPtr.h"
88 #ifdef ENABLE_UPNP
89 #include "UPnPBase.h" // Needed for UPnP
90 #endif
92 #ifdef __WXMAC__
93 #include <wx/sysopt.h> // Do_not_auto_remove
94 #endif
96 #ifndef AMULE_DAEMON
97 #ifdef __WXMAC__
98 #include <CoreFoundation/CFBundle.h> // Do_not_auto_remove
99 #if wxCHECK_VERSION(2, 9, 0)
100 #include <wx/osx/core/cfstring.h> // Do_not_auto_remove
101 #else
102 #include <wx/mac/corefoundation/cfstring.h> // Do_not_auto_remove
103 #endif
104 #endif
105 #include <wx/msgdlg.h>
107 #include "amuleDlg.h"
108 #endif
111 #ifdef HAVE_SYS_RESOURCE_H
112 #include <sys/resource.h>
113 #endif
115 #ifdef HAVE_SYS_STATVFS_H
116 #include <sys/statvfs.h> // Do_not_auto_remove
117 #endif
120 #ifdef __GLIBC__
121 # define RLIMIT_RESOURCE __rlimit_resource
122 #else
123 # define RLIMIT_RESOURCE int
124 #endif
126 static void UnlimitResource(RLIMIT_RESOURCE resType)
128 #if defined(HAVE_GETRLIMIT) && defined(HAVE_SETRLIMIT)
129 struct rlimit rl;
130 getrlimit(resType, &rl);
131 rl.rlim_cur = rl.rlim_max;
132 setrlimit(resType, &rl);
133 #endif
137 static void SetResourceLimits()
139 #ifdef HAVE_SYS_RESOURCE_H
140 UnlimitResource(RLIMIT_DATA);
141 #ifndef __UCLIBC__
142 UnlimitResource(RLIMIT_FSIZE);
143 #endif
144 UnlimitResource(RLIMIT_NOFILE);
145 #ifdef RLIMIT_RSS
146 UnlimitResource(RLIMIT_RSS);
147 #endif
148 #endif
151 // We store the received signal in order to avoid race-conditions
152 // in the signal handler.
153 bool g_shutdownSignal = false;
155 void OnShutdownSignal( int /* sig */ )
157 signal(SIGINT, SIG_DFL);
158 signal(SIGTERM, SIG_DFL);
160 g_shutdownSignal = true;
162 #ifdef AMULE_DAEMON
163 theApp->ExitMainLoop();
164 #endif
168 CamuleApp::CamuleApp()
170 // Madcat - Initialize timer as the VERY FIRST thing to avoid any issues later.
171 // Kry - I love to init the vars on init, even before timer.
172 StartTickTimer();
174 // Initialization
175 m_app_state = APP_STATE_STARTING;
177 theApp = &wxGetApp();
179 clientlist = NULL;
180 searchlist = NULL;
181 knownfiles = NULL;
182 serverlist = NULL;
183 serverconnect = NULL;
184 sharedfiles = NULL;
185 listensocket = NULL;
186 clientudp = NULL;
187 clientcredits = NULL;
188 friendlist = NULL;
189 downloadqueue = NULL;
190 uploadqueue = NULL;
191 ipfilter = NULL;
192 ECServerHandler = NULL;
193 m_singleInstance= NULL;
194 glob_prefs = NULL;
195 m_statistics = NULL;
196 uploadBandwidthThrottler = NULL;
197 #ifdef ENABLE_UPNP
198 m_upnp = NULL;
199 m_upnpMappings.resize(4);
200 #endif
201 core_timer = NULL;
203 m_localip = 0;
204 m_dwPublicIP = 0;
205 webserver_pid = 0;
207 enable_daemon_fork = false;
209 strFullMuleVersion = NULL;
210 strOSDescription = NULL;
212 // Apprently needed for *BSD
213 SetResourceLimits();
216 CamuleApp::~CamuleApp()
218 // Closing the log-file as the very last thing, since
219 // wxWidgets log-events are saved in it as well.
220 theLogger.CloseLogfile();
222 free(strFullMuleVersion);
223 free(strOSDescription);
226 int CamuleApp::OnExit()
228 if (m_app_state!=APP_STATE_STARTING) {
229 AddLogLineMS(false, _("Now, exiting main app..."));
232 // From wxWidgets docs, wxConfigBase:
233 // ...
234 // Note that you must delete this object (usually in wxApp::OnExit)
235 // in order to avoid memory leaks, wxWidgets won't do it automatically.
237 // As it happens, you may even further simplify the procedure described
238 // above: you may forget about calling Set(). When Get() is called and
239 // there is no current object, it will create one using Create() function.
240 // To disable this behaviour DontCreateOnDemand() is provided.
241 delete wxConfigBase::Set((wxConfigBase *)NULL);
243 // Save credits
244 clientcredits->SaveList();
246 // Kill amuleweb if running
247 if (webserver_pid) {
248 AddLogLineMS(false, CFormat(_("Killing amuleweb instance with pid `%ld' ... ")) % webserver_pid);
249 wxKillError rc;
250 wxKill(webserver_pid, wxSIGTERM, &rc);
251 AddLogLineMS(false, _("Killed!"));
254 if (m_app_state!=APP_STATE_STARTING) {
255 AddLogLineMS(false, _("aMule OnExit: Terminating core."));
258 delete serverlist;
259 serverlist = NULL;
261 delete searchlist;
262 searchlist = NULL;
264 delete clientcredits;
265 clientcredits = NULL;
267 delete friendlist;
268 friendlist = NULL;
270 // Destroying CDownloadQueue calls destructor for CPartFile
271 // calling CSharedFileList::SafeAddKFile occasionally.
272 delete sharedfiles;
273 sharedfiles = NULL;
275 delete serverconnect;
276 serverconnect = NULL;
278 delete listensocket;
279 listensocket = NULL;
281 delete clientudp;
282 clientudp = NULL;
284 delete knownfiles;
285 knownfiles = NULL;
287 delete clientlist;
288 clientlist = NULL;
290 delete uploadqueue;
291 uploadqueue = NULL;
293 delete downloadqueue;
294 downloadqueue = NULL;
296 delete ipfilter;
297 ipfilter = NULL;
299 #ifdef ENABLE_UPNP
300 delete m_upnp;
301 m_upnp = NULL;
302 #endif
304 delete ECServerHandler;
305 ECServerHandler = NULL;
307 delete m_statistics;
308 m_statistics = NULL;
310 delete glob_prefs;
311 glob_prefs = NULL;
312 CPreferences::EraseItemList();
314 #if defined(__WXMAC__) && defined(AMULE_DAEMON)
315 //#warning TODO: fix wxSingleInstanceChecker for amuled on Mac (wx link problems)
316 #else
317 delete m_singleInstance;
318 #endif
319 m_singleInstance = NULL;
321 delete uploadBandwidthThrottler;
322 uploadBandwidthThrottler = NULL;
324 if (m_app_state!=APP_STATE_STARTING) {
325 AddLogLineNS(_("aMule shutdown completed."));
328 #if wxUSE_MEMORY_TRACING
329 AddLogLineNS(_("Memory debug results for aMule exit:"));
330 // Log mem debug mesages to wxLogStderr
331 wxLog* oldLog = wxLog::SetActiveTarget(new wxLogStderr);
332 //AddLogLineNS(wxT("**************Classes**************");
333 //wxDebugContext::PrintClasses();
334 //AddLogLineNS(wxT("***************Dump***************");
335 //wxDebugContext::Dump();
336 AddLogLineNS(wxT("***************Stats**************"));
337 wxDebugContext::PrintStatistics(true);
339 // Set back to wxLogGui
340 delete wxLog::SetActiveTarget(oldLog);
341 #endif
343 StopTickTimer();
345 // Return 0 for succesful program termination
346 return AMULE_APP_BASE::OnExit();
350 int CamuleApp::InitGui(bool, wxString &)
352 return 0;
357 * Checks permissions on a aMule directory, creating if needed.
359 * @param desc A description of the directory in question, used for error messages.
360 * @param directory The directory in question.
361 * @param fallback If the dir specified with 'directory' could not be created, try this instead.
362 * @return The bool is false on error. The wxString contains the used path.
364 std::pair<bool, CPath> CheckMuleDirectory(const wxString& desc, const CPath& directory, const wxString& alternative)
366 wxString msg;
368 if (directory.IsDir(CPath::readwritable)) {
369 return std::pair<bool, CPath>(true, directory);
370 } else if (directory.DirExists()) {
371 // Strings are not translated here because translation isn't up yet.
372 msg = CFormat(wxT("Permissions on the %s directory too strict!\n")
373 wxT("aMule cannot proceed. To fix this, you must set read/write/exec\n")
374 wxT("permissions for the folder '%s'"))
375 % desc % directory;
376 } else if (CPath::MakeDir(directory)) {
377 return std::pair<bool, CPath>(true, directory);
378 } else {
379 msg << CFormat(wxT("Could not create the %s directory at '%s'."))
380 % desc % directory;
383 // Attempt to use fallback directory.
384 const CPath fallback(alternative);
385 if (fallback.IsOk() && (directory != fallback)) {
386 msg << wxT("\nAttempting to use default directory at location \n'")
387 << alternative << wxT("'.");
388 if (theApp->ShowAlert(msg, wxT("Error accessing directory."), wxICON_ERROR | wxOK | wxCANCEL) == wxCANCEL) {
389 return std::pair<bool, CPath>(false, CPath(wxEmptyString));
392 return CheckMuleDirectory(desc, fallback, wxEmptyString);
395 theApp->ShowAlert(msg, wxT("Fatal error."), wxICON_ERROR | wxOK);
396 return std::pair<bool, CPath>(false, CPath(wxEmptyString));
401 // Application initialization
403 bool CamuleApp::OnInit()
405 #if wxUSE_MEMORY_TRACING
406 // any text before call of Localize_mule needs not to be translated.
407 AddLogLineMS(false, wxT("Checkpoint set on app init for memory debug"));
408 wxDebugContext::SetCheckpoint();
409 #endif
411 // Forward wxLog events to CLogger
412 wxLog::SetActiveTarget(new CLoggerTarget);
414 m_localip = StringHosttoUint32(::wxGetFullHostName());
416 #ifndef __WXMSW__
417 // get rid of sigpipe
418 signal(SIGPIPE, SIG_IGN);
419 #else
420 // Handle CTRL-Break
421 signal(SIGBREAK, OnShutdownSignal);
422 #endif
423 // Handle sigint and sigterm
424 signal(SIGINT, OnShutdownSignal);
425 signal(SIGTERM, OnShutdownSignal);
427 #ifdef __WXMAC__
428 // For listctrl's to behave on Mac
429 wxSystemOptions::SetOption(wxT("mac.listctrl.always_use_generic"), 1);
430 #endif
432 // This can't be on constructor or wx2.4.2 doesn't set it.
433 #if !wxCHECK_VERSION(2, 9, 0)
434 SetVendorName(wxT("TikuWarez"));
435 #endif
436 SetAppName(wxT("aMule"));
438 wxString FullMuleVersion = GetFullMuleVersion();
439 wxString OSDescription = wxGetOsDescription();
440 strFullMuleVersion = strdup((const char *)unicode2char(FullMuleVersion));
441 strOSDescription = strdup((const char *)unicode2char(OSDescription));
442 OSType = OSDescription.BeforeFirst( wxT(' ') );
443 if ( OSType.IsEmpty() ) {
444 OSType = wxT("Unknown");
447 // Handle uncaught exceptions
448 InstallMuleExceptionHandler();
450 // Parse cmdline arguments.
451 wxCmdLineParser cmdline(AMULE_APP_BASE::argc, AMULE_APP_BASE::argv);
453 // Handle these arguments.
454 cmdline.AddSwitch(wxT("v"), wxT("version"), wxT("Displays the current version number."));
455 cmdline.AddSwitch(wxT("h"), wxT("help"), wxT("Displays this information."));
456 cmdline.AddSwitch(wxT("i"), wxT("enable-stdin"), wxT("Does not disable stdin."));
457 #ifdef AMULE_DAEMON
458 cmdline.AddSwitch(wxT("f"), wxT("full-daemon"), wxT("Fork to background."));
459 cmdline.AddOption(wxT("p"), wxT("pid-file"), wxT("After fork, create a pid-file in the given fullname file."));
460 cmdline.AddOption(wxT("c"), wxT("config-dir"), wxT("read config from <dir> instead of home"));
461 cmdline.AddSwitch(wxT("e"), wxT("ec-config"), wxT("Configure EC (External Connections)."));
462 #else
463 cmdline.AddOption(wxT("geometry"), wxEmptyString,
464 wxT("Sets the geometry of the app.\n")
465 wxT("\t\t\t<str> uses the same format as standard X11 apps:\n")
466 wxT("\t\t\t[=][<width>{xX}<height>][{+-}<xoffset>{+-}<yoffset>]"));
467 #endif
468 cmdline.AddSwitch(wxT("d"), wxT("disable-fatal"), wxT("Does not handle fatal exception."));
469 cmdline.AddSwitch(wxT("o"), wxT("log-stdout"), wxT("Print log messages to stdout."));
470 cmdline.AddSwitch(wxT("r"), wxT("reset-config"), wxT("Resets config to default values."));
471 #ifndef __WXMSW__
472 // Change webserver path, not available on Windows
473 cmdline.AddOption(wxT("w"), wxT("use-amuleweb"), wxT("Specify location of amuleweb binary."));
474 #endif
475 // Allow passing of links to the app
476 cmdline.AddOption(wxT("c"), wxT("category"), wxT("Set category for passed ED2K links."), wxCMD_LINE_VAL_NUMBER);
477 cmdline.AddParam(wxT("ED2K link"), wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL | wxCMD_LINE_PARAM_MULTIPLE);
479 // Show help on --help or invalid commands
480 if ( cmdline.Parse() ) {
481 return false;
482 } else if ( cmdline.Found(wxT("help")) ) {
483 cmdline.Usage();
484 return false;
487 bool ec_config = false;
489 #ifdef AMULE_DAEMON
490 ec_config = cmdline.Found(wxT("ec-config"));
491 if ( cmdline.Found(wxT("config-dir"), &ConfigDir) ) {
492 if (ConfigDir.Last() != wxFileName::GetPathSeparator()) {
493 ConfigDir += wxFileName::GetPathSeparator();
495 } else {
496 ConfigDir = GetConfigDir();
498 #else
499 ConfigDir = GetConfigDir();
500 #endif
502 if ( !cmdline.Found(wxT("disable-fatal")) ) {
503 #ifndef __WXMSW__
504 // catch fatal exceptions
505 wxHandleFatalExceptions(true);
506 #endif
509 bool reset_config = cmdline.Found(wxT("reset-config"));
511 theLogger.SetEnabledStdoutLog(cmdline.Found(wxT("log-stdout")));
512 #ifdef AMULE_DAEMON
513 enable_daemon_fork = cmdline.Found(wxT("full-daemon"));
514 if ( cmdline.Found(wxT("pid-file"), &PidFile) ) {
515 // Remove any existing PidFile
516 if ( wxFileExists (PidFile) ) wxRemoveFile (PidFile);
518 #else
519 enable_daemon_fork = false;
520 PidFile.Clear();
521 #endif
523 if (theLogger.IsEnabledStdoutLog()) {
524 if ( enable_daemon_fork ) {
525 AddLogLineMS(false, wxT("Daemon will fork to background - log to stdout disabled"));
526 theLogger.SetEnabledStdoutLog(false);
527 } else {
528 AddLogLineMS(false, wxT("Logging to stdout enabled"));
532 if ( cmdline.Found(wxT("version")) ) {
533 AddLogLineMS(false, CFormat(wxT("%s (OS: %s)")) % FullMuleVersion % OSType);
535 return false;
538 // Default geometry of the GUI. Can be changed with a cmdline argument...
539 bool geometry_enabled = false;
540 wxString geom_string;
541 #ifndef AMULE_DAEMON
542 if ( cmdline.Found(wxT("geometry"), &geom_string) ) {
543 geometry_enabled = true;
545 #endif
547 AddLogLineMS(false, wxT("Initialising ") + FullMuleVersion);
549 // Ensure that "~/.aMule/" is accessible.
550 if (!CheckMuleDirectory(wxT("configuration"), CPath(ConfigDir), wxEmptyString).first) {
551 return false;
554 if (reset_config) {
555 // Make a backup first.
556 wxRemoveFile(ConfigDir + wxT("amule.conf.backup"));
557 wxRenameFile(ConfigDir + wxT("amule.conf"), ConfigDir + wxT("amule.conf.backup"));
558 AddLogLineMS(false, wxT("Your settings have been reset to default values.\nThe old config file has been saved as amule.conf.backup\n"));
561 size_t linksPassed = cmdline.GetParamCount(); // number of links from the command line
562 int linksActuallyPassed = 0; // number of links that pass the syntax check
563 if (linksPassed) {
564 long cat = 0;
565 if (!cmdline.Found(wxT("c"), &cat)) {
566 cat = 0;
569 wxTextFile ed2kFile(ConfigDir + wxT("ED2KLinks"));
570 if (!ed2kFile.Exists()) {
571 ed2kFile.Create();
573 if (ed2kFile.Open()) {
574 for (size_t i = 0; i < linksPassed; i++) {
575 wxString link;
576 if (CheckPassedLink(cmdline.GetParam(i), link, cat)) {
577 ed2kFile.AddLine(link);
578 linksActuallyPassed++;
581 ed2kFile.Write();
582 } else {
583 AddLogLineCS(wxT("Failed to open 'ED2KFile', cannot add links."));
587 #if defined(__WXMAC__) && defined(AMULE_DAEMON)
588 //#warning TODO: fix wxSingleInstanceChecker for amuled on Mac (wx link problems)
589 AddLogLineMS(true, wxT("WARNING: The check for other instances is currently disabled in amuled.\n"
590 "Please make sure that no other instance of aMule is running or your files might be corrupted.\n"));
591 #else
592 AddLogLineMS(false, wxT("Checking if there is an instance already running..."));
594 m_singleInstance = new wxSingleInstanceChecker();
595 if (m_singleInstance->Create(wxT("muleLock"), ConfigDir)
596 && m_singleInstance->IsAnotherRunning()) {
597 AddLogLineMS(true, wxT("There is an instance of aMule already running"));
598 AddLogLineNS(CFormat(wxT("(lock file: %s%s)")) % ConfigDir % wxT("muleLock"));
599 if (linksPassed) {
600 AddLogLineNS(CFormat(wxT("passed %d %s to it, finished")) % linksActuallyPassed
601 % (linksPassed == 1 ? wxT("link") : wxT("links")));
602 return false;
605 // This is very tricky. The most secure way to communicate is via ED2K links file
606 wxTextFile ed2kFile(ConfigDir + wxT("ED2KLinks"));
607 if (!ed2kFile.Exists()) {
608 ed2kFile.Create();
611 if (ed2kFile.Open()) {
612 ed2kFile.AddLine(wxT("RAISE_DIALOG"));
613 ed2kFile.Write();
615 AddLogLineMS(false, wxT("Raising current running instance."));
616 } else {
617 AddLogLineMS(true, wxT("Failed to open 'ED2KFile', cannot signal running instance."));
620 return false;
621 } else {
622 AddLogLineMS(false, wxT("No other instances are running."));
624 #endif
626 // Close standard-input
627 if ( !cmdline.Found(wxT("enable-stdin")) ) {
628 // The full daemon will close all std file-descriptors by itself,
629 // so closing it here would lead to the closing on the first open
630 // file, which is the logfile opened below
631 if (!enable_daemon_fork) {
632 close(0);
636 // This creates the CFG file we shall use
637 wxConfigBase* cfg = new wxFileConfig( wxEmptyString, wxEmptyString, ConfigDir + wxT("amule.conf") );
639 // Set the config object as the global cfg file
640 wxConfig::Set( cfg );
642 // Make a backup of the log file
643 CPath logfileName = CPath(ConfigDir + wxT("logfile"));
644 if (logfileName.FileExists()) {
645 CPath::BackupFile(logfileName, wxT(".bak"));
648 // Open the log file
649 if (!theLogger.OpenLogfile(logfileName.GetRaw())) {
650 // use std err as last resolt to indicate problem
651 fputs("ERROR: unable to open log file\n", stderr);
652 // failure to open log is serious problem
653 return false;
656 // Load Preferences
657 CPreferences::BuildItemList(ConfigDir);
658 CPreferences::LoadAllItems( wxConfigBase::Get() );
660 glob_prefs = new CPreferences();
662 std::pair<bool, CPath> checkResult;
663 checkResult = CheckMuleDirectory(wxT("temp"), thePrefs::GetTempDir(), ConfigDir + wxT("Temp"));
664 if (checkResult.first) {
665 thePrefs::SetTempDir(checkResult.second);
666 } else {
667 return false;
670 checkResult = CheckMuleDirectory(wxT("incoming"), thePrefs::GetIncomingDir(), ConfigDir + wxT("Incoming"));
671 if (checkResult.first) {
672 thePrefs::SetIncomingDir(checkResult.second);
673 } else {
674 return false;
677 // Some sanity check
678 if (!thePrefs::UseTrayIcon()) {
679 thePrefs::SetMinToTray(false);
682 // Build the filenames for the two OS files
683 SetOSFiles(thePrefs::GetOSDir().GetRaw());
685 #ifdef ENABLE_NLS
686 // Load localization settings
687 Localize_mule();
688 #endif
690 // Configure EC for amuled when invoked with ec-config
691 if (ec_config) {
692 AddLogLineMS(false, _("\nEC configuration"));
693 thePrefs::SetECPass(GetPassword());
694 thePrefs::EnableExternalConnections(true);
695 AddLogLineMS(false, _("Password set and external connections enabled."));
698 #ifndef __WXMSW__
699 if (getuid() == 0) {
700 wxString msg =
701 wxT("Warning! You are running aMule as root.\n")
702 wxT("Doing so is not recommended for security reasons,\n")
703 wxT("and you are advised to run aMule as an normal\n")
704 wxT("user instead.");
706 ShowAlert(msg, _("WARNING"), wxCENTRE | wxOK | wxICON_ERROR);
708 fprintf(stderr, "\n--------------------------------------------------\n");
709 fprintf(stderr, "%s", (const char*)unicode2UTF8(msg));
710 fprintf(stderr, "\n--------------------------------------------------\n\n");
712 #endif
714 // Display notification on new version or first run
715 wxTextFile vfile( ConfigDir + wxT("lastversion") );
716 wxString newMule(wxT( VERSION ));
718 if ( !wxFileExists( vfile.GetName() ) ) {
719 vfile.Create();
722 if ( vfile.Open() ) {
723 // Check if this version has been run before
724 bool found = false;
725 for ( size_t i = 0; i < vfile.GetLineCount(); i++ ) {
726 // Check if this version has been run before
727 if ( vfile.GetLine(i) == newMule ) {
728 found = true;
729 break;
733 // We havent run this version before?
734 if ( !found ) {
735 // Insert new at top to provide faster searches
736 vfile.InsertLine( newMule, 0 );
738 Trigger_New_version( newMule );
741 // Keep at most 10 entires
742 while ( vfile.GetLineCount() > 10 )
743 vfile.RemoveLine( vfile.GetLineCount() - 1 );
745 vfile.Write();
746 vfile.Close();
749 // Check if we have the old style locale config
750 wxString langId = thePrefs::GetLanguageID();
751 if (!langId.IsEmpty() && (langId.GetChar(0) >= '0' && langId.GetChar(0) <= '9')) {
752 wxString info(_("Your locale has been changed to System Default due to a configuration change. Sorry."));
753 thePrefs::SetLanguageID(wxLang2Str(wxLANGUAGE_DEFAULT));
754 ShowAlert(info, _("Info"), wxCENTRE | wxOK | wxICON_ERROR);
757 m_statistics = new CStatistics();
759 clientlist = new CClientList();
760 friendlist = new CFriendList();
761 searchlist = new CSearchList();
762 knownfiles = new CKnownFileList();
763 serverlist = new CServerList();
765 sharedfiles = new CSharedFileList(knownfiles);
766 clientcredits = new CClientCreditsList();
768 // bugfix - do this before creating the uploadqueue
769 downloadqueue = new CDownloadQueue();
770 uploadqueue = new CUploadQueue();
771 ipfilter = new CIPFilter();
773 // Creates all needed listening sockets
774 wxString msg;
775 if (!ReinitializeNetwork(&msg)) {
776 AddLogLineMS(false, wxT("\n"));
777 AddLogLineMS(false, msg);
780 // Test if there's any new version
781 if (thePrefs::CheckNewVersion()) {
782 // We use the thread base because I don't want a dialog to pop up.
783 CHTTPDownloadThread* version_check =
784 new CHTTPDownloadThread(wxT("http://amule.sourceforge.net/lastversion"),
785 theApp->ConfigDir + wxT("last_version_check"), HTTP_VersionCheck, false);
786 version_check->Create();
787 version_check->Run();
790 // Create main dialog, or fork to background (daemon).
791 InitGui(geometry_enabled, geom_string);
793 #if !defined(__WXMAC__) && defined(AMULE_DAEMON)
794 // Need to refresh wxSingleInstanceChecker after the daemon fork() !
795 if (enable_daemon_fork) {
796 //#warning TODO: fix wxSingleInstanceChecker for amuled on Mac (wx link problems)
797 delete m_singleInstance;
798 m_singleInstance = new wxSingleInstanceChecker(wxT("muleLock"), ConfigDir);
799 // No need to check IsAnotherRunning() - we've done it before.
801 #endif
803 // Has to be created after the call to InitGui, as fork
804 // (when using posix threads) only replicates the mainthread,
805 // and the UBT constructor creates a thread.
806 uploadBandwidthThrottler = new UploadBandwidthThrottler();
808 // These must be initialized after the gui is loaded.
809 serverlist->Init();
810 downloadqueue->LoadMetFiles(thePrefs::GetTempDir());
811 sharedfiles->Reload();
813 if (thePrefs::IPFilterAutoLoad()) {
814 ipfilter->Update(thePrefs::IPFilterURL());
818 // Ensure that the up/down ratio is used
819 CPreferences::CheckUlDlRatio();
821 // The user can start pressing buttons like mad if he feels like it.
822 m_app_state = APP_STATE_RUNNING;
824 // Kry - Load the sources seeds on app init
825 if (thePrefs::GetSrcSeedsOn()) {
826 downloadqueue->LoadSourceSeeds();
829 if (!serverlist->GetServerCount() && thePrefs::GetNetworkED2K()) {
830 // There are no servers and ED2K active -> ask for download.
831 // As we cannot ask in amuled, we just update there
832 // Kry TODO: Store server.met URL on preferences and use it here and in GUI.
833 #ifndef AMULE_DAEMON
834 if (wxYES == wxMessageBox(
835 wxString(
836 _("You don't have any server in the server list.\nDo you want aMule to download a new list now?")),
837 wxString(_("Server list download")),
838 wxYES_NO,
839 static_cast<wxWindow*>(theApp->amuledlg)))
840 #endif
842 // workaround amuled crash
843 #ifndef AMULE_DAEMON
844 serverlist->UpdateServerMetFromURL(
845 wxT("http://gruk.org/server.met.gz"));
846 #endif
851 // Autoconnect if that option is enabled
852 if (thePrefs::DoAutoConnect() && (thePrefs::GetNetworkED2K() || thePrefs::GetNetworkKademlia())) {
853 AddLogLineM(true, _("Connecting"));
854 if (thePrefs::GetNetworkED2K()) {
855 theApp->serverconnect->ConnectToAnyServer();
858 StartKad();
862 // Enable GeoIP
863 #ifdef ENABLE_IP2COUNTRY
864 theApp->amuledlg->EnableIP2Country();
865 #endif
867 // No webserver on Win at all (yet)
868 #ifndef __WXMSW__
869 // Run webserver?
870 if (thePrefs::GetWSIsEnabled()) {
871 wxString aMuleConfigFile = ConfigDir + wxT("amule.conf");
872 wxString amulewebPath = wxT("amuleweb");
873 if(true == cmdline.Found(wxT("use-amuleweb"), &amulewebPath)) {
874 AddLogLineNS(CFormat(_("Using amuleweb in '%s'.")) % amulewebPath);
877 #if defined(__WXMAC__) && !defined(AMULE_DAEMON)
878 // For the Mac GUI application, look for amuleweb in the bundle
879 CFURLRef amulewebUrl = CFBundleCopyAuxiliaryExecutableURL(
880 CFBundleGetMainBundle(), CFSTR("amuleweb"));
882 if (amulewebUrl) {
883 CFURLRef absoluteUrl = CFURLCopyAbsoluteURL(amulewebUrl);
884 CFRelease(amulewebUrl);
886 if (absoluteUrl) {
887 CFStringRef amulewebCfstr = CFURLCopyFileSystemPath(absoluteUrl, kCFURLPOSIXPathStyle);
888 CFRelease(absoluteUrl);
889 #if wxCHECK_VERSION(2, 9, 0)
890 amulewebPath = wxCFStringRef(amulewebCfstr).AsString(wxLocale::GetSystemEncoding());
891 #else
892 amulewebPath = wxMacCFStringHolder(amulewebCfstr).AsString(wxLocale::GetSystemEncoding());
893 #endif
896 #endif
898 wxString cmd =
899 wxT("'") +
900 amulewebPath +
901 wxT("' '--amule-config-file=") +
902 aMuleConfigFile +
903 wxT("'");
904 CTerminationProcessAmuleweb *p = new CTerminationProcessAmuleweb(cmd, &webserver_pid);
905 webserver_pid = wxExecute(cmd, wxEXEC_ASYNC, p);
906 bool webserver_ok = webserver_pid > 0;
907 if (webserver_ok) {
908 AddLogLineM(true, CFormat(_("web server running on pid %d")) % webserver_pid);
909 } else {
910 delete p;
911 ShowAlert(_(
912 "You requested to run web server on startup, but the amuleweb binary cannot be run. Please install the package containing aMule web server, or compile aMule using --enable-webserver and run make install"),
913 _("ERROR"), wxOK | wxICON_ERROR);
916 #endif /* ! __WXMSW__ */
918 // Start performing background tasks
919 CThreadScheduler::Start();
921 return true;
924 bool CamuleApp::CheckPassedLink(const wxString &in, wxString &out, int cat)
926 wxString link(in);
928 if (link.compare(0, 7, wxT("magnet:")) == 0) {
929 link = CMagnetED2KConverter(link);
930 if (link.empty()) {
931 AddLogLineCS(CFormat(wxT("Cannot convert magnet link to eD2k: %s")) % in);
932 return false;
936 try {
937 CScopedPtr<CED2KLink> uri(CED2KLink::CreateLinkFromUrl(link));
938 out = uri.get()->GetLink();
939 if (cat && uri.get()->GetKind() == CED2KLink::kFile) {
940 out += CFormat(wxT(":%d")) % cat;
942 return true;
943 } catch ( const wxString& err ) {
944 AddLogLineCS(CFormat(wxT("Invalid eD2k link \"%s\" - ERROR: %s")) % link % err);
946 return false;
949 bool CamuleApp::ReinitializeNetwork(wxString* msg)
951 bool ok = true;
952 static bool firstTime = true;
954 if (!firstTime) {
955 // TODO: Destroy previously created sockets
957 firstTime = false;
959 // Some sanity checks first
960 if (thePrefs::ECPort() == thePrefs::GetPort()) {
961 // Select a random usable port in the range 1025 ... 2^16 - 1
962 uint16 port = thePrefs::ECPort();
963 while ( port < 1024 || port == thePrefs::GetPort() ) {
964 port = (uint16)rand();
966 thePrefs::SetECPort( port );
968 wxString err =
969 wxT("Network configuration failed! You cannot use the same port\n")
970 wxT("for the main TCP port and the External Connections port.\n")
971 wxT("The EC port has been changed to avoid conflict, see the\n")
972 wxT("preferences for the new value.\n");
973 *msg << err;
975 AddLogLineM( false, wxEmptyString );
976 AddLogLineM( true, err );
977 AddLogLineM( false, wxEmptyString );
979 ok = false;
982 if (thePrefs::GetUDPPort() == thePrefs::GetPort() + 3) {
983 // Select a random usable value in the range 1025 ... 2^16 - 1
984 uint16 port = thePrefs::GetUDPPort();
985 while ( port < 1024 || port == thePrefs::GetPort() + 3 ) {
986 port = (uint16)rand();
988 thePrefs::SetUDPPort( port );
990 wxString err =
991 wxT("Network configuration failed! You set your UDP port to\n")
992 wxT("the value of the main TCP port plus 3.\n")
993 wxT("This port has been reserved for the Server-UDP port. The\n")
994 wxT("port value has been changed to avoid conflict, see the\n")
995 wxT("preferences for the new value\n");
996 *msg << err;
998 AddLogLineM( false, wxEmptyString );
999 AddLogLineM( true, err );
1000 AddLogLineM( false, wxEmptyString );
1002 ok = false;
1005 // Create the address where we are going to listen
1006 // TODO: read this from configuration file
1007 amuleIPV4Address myaddr[4];
1009 // Create the External Connections Socket.
1010 // Default is 4712.
1011 // Get ready to handle connections from apps like amulecmd
1012 if (thePrefs::GetECAddress().IsEmpty() || !myaddr[0].Hostname(thePrefs::GetECAddress())) {
1013 myaddr[0].AnyAddress();
1015 myaddr[0].Service(thePrefs::ECPort());
1016 ECServerHandler = new ExternalConn(myaddr[0], msg);
1018 // Create the UDP socket TCP+3.
1019 // Used for source asking on servers.
1020 if (thePrefs::GetAddress().IsEmpty()) {
1021 myaddr[1].AnyAddress();
1022 } else if (!myaddr[1].Hostname(thePrefs::GetAddress())) {
1023 myaddr[1].AnyAddress();
1024 AddLogLineM(true, CFormat(_("Could not bind ports to the specified address: %s"))
1025 % thePrefs::GetAddress());
1028 wxString ip = myaddr[1].IPAddress();
1029 myaddr[1].Service(thePrefs::GetPort()+3);
1030 serverconnect = new CServerConnect(serverlist, myaddr[1]);
1031 *msg << CFormat( wxT("*** Server UDP socket (TCP+3) at %s:%u\n") )
1032 % ip % ((unsigned int)thePrefs::GetPort() + 3u);
1034 // Create the ListenSocket (aMule TCP socket).
1035 // Used for Client Port / Connections from other clients,
1036 // Client to Client Source Exchange.
1037 // Default is 4662.
1038 myaddr[2] = myaddr[1];
1039 myaddr[2].Service(thePrefs::GetPort());
1040 listensocket = new CListenSocket(myaddr[2]);
1041 *msg << CFormat( wxT("*** TCP socket (TCP) listening on %s:%u\n") )
1042 % ip % (unsigned int)(thePrefs::GetPort());
1043 // This command just sets a flag to control maximum number of connections.
1044 // Notify(true) has already been called to the ListenSocket, so events may
1045 // be already comming in.
1046 if (listensocket->Ok()) {
1047 listensocket->StartListening();
1048 } else {
1049 // If we wern't able to start listening, we need to warn the user
1050 wxString err;
1051 err = CFormat(_("Port %u is not available. You will be LOWID\n")) %
1052 (unsigned int)(thePrefs::GetPort());
1053 *msg << err;
1054 AddLogLineM(true, err);
1055 err.Clear();
1056 err = CFormat(
1057 _("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.")) %
1058 (unsigned int)(thePrefs::GetPort());
1059 ShowAlert(err, _("ERROR"), wxOK | wxICON_ERROR);
1062 // Create the UDP socket.
1063 // Used for extended eMule protocol, Queue Rating, File Reask Ping.
1064 // Also used for Kademlia.
1065 // Default is port 4672.
1066 myaddr[3] = myaddr[1];
1067 myaddr[3].Service(thePrefs::GetUDPPort());
1068 clientudp = new CClientUDPSocket(myaddr[3], thePrefs::GetProxyData());
1069 if (!thePrefs::IsUDPDisabled()) {
1070 *msg << CFormat( wxT("*** Client UDP socket (extended eMule) at %s:%u") )
1071 % ip % thePrefs::GetUDPPort();
1072 } else {
1073 *msg << wxT("*** Client UDP socket (extended eMule) disabled on preferences");
1076 #ifdef ENABLE_UPNP
1077 if (thePrefs::GetUPnPEnabled()) {
1078 try {
1079 m_upnpMappings[0] = CUPnPPortMapping(
1080 myaddr[0].Service(),
1081 "TCP",
1082 thePrefs::GetUPnPECEnabled(),
1083 "aMule TCP External Connections Socket");
1084 m_upnpMappings[1] = CUPnPPortMapping(
1085 myaddr[1].Service(),
1086 "UDP",
1087 thePrefs::GetUPnPEnabled(),
1088 "aMule UDP socket (TCP+3)");
1089 m_upnpMappings[2] = CUPnPPortMapping(
1090 myaddr[2].Service(),
1091 "TCP",
1092 thePrefs::GetUPnPEnabled(),
1093 "aMule TCP Listen Socket");
1094 m_upnpMappings[3] = CUPnPPortMapping(
1095 myaddr[3].Service(),
1096 "UDP",
1097 thePrefs::GetUPnPEnabled(),
1098 "aMule UDP Extended eMule Socket");
1099 m_upnp = new CUPnPControlPoint(thePrefs::GetUPnPTCPPort());
1100 m_upnp->AddPortMappings(m_upnpMappings);
1101 } catch(CUPnPException &e) {
1102 wxString error_msg;
1103 error_msg << e.what();
1104 AddLogLineM(true, error_msg);
1105 fprintf(stderr, "%s\n", (const char *)unicode2char(error_msg));
1108 #endif
1110 return ok;
1113 /* Original implementation by Bouc7 of the eMule Project.
1114 aMule Signature idea was designed by BigBob and implemented
1115 by Un-Thesis, with design inputs and suggestions from bothie.
1117 void CamuleApp::OnlineSig(bool zero /* reset stats (used on shutdown) */)
1119 // Do not do anything if online signature is disabled in Preferences
1120 if (!thePrefs::IsOnlineSignatureEnabled() || m_emulesig_path.IsEmpty()) {
1121 // We do not need to check m_amulesig_path because if m_emulesig_path is empty,
1122 // that means m_amulesig_path is empty too.
1123 return;
1126 // Remove old signature files
1127 if ( wxFileExists( m_emulesig_path ) ) { wxRemoveFile( m_emulesig_path ); }
1128 if ( wxFileExists( m_amulesig_path ) ) { wxRemoveFile( m_amulesig_path ); }
1131 wxTextFile amulesig_out;
1132 wxTextFile emulesig_out;
1134 // Open both files if needed
1135 if ( !emulesig_out.Create( m_emulesig_path) ) {
1136 AddLogLineM(true, _("Failed to create OnlineSig File"));
1137 // Will never try again.
1138 m_amulesig_path.Clear();
1139 m_emulesig_path.Clear();
1140 return;
1143 if ( !amulesig_out.Create(m_amulesig_path) ) {
1144 AddLogLineM(true, _("Failed to create aMule OnlineSig File"));
1145 // Will never try again.
1146 m_amulesig_path.Clear();
1147 m_emulesig_path.Clear();
1148 return;
1151 wxString emulesig_string;
1152 wxString temp;
1154 if (zero) {
1155 emulesig_string = wxT("0\xA0.0|0.0|0");
1156 amulesig_out.AddLine(wxT("0\n0\n0\n0\n0\n0\n0.0\n0.0\n0\n0"));
1157 } else {
1158 if (IsConnectedED2K()) {
1160 temp = wxString::Format(wxT("%d"),serverconnect->GetCurrentServer()->GetPort());
1162 // We are online
1163 emulesig_string =
1164 // Connected
1165 wxT("1|")
1166 //Server name
1167 + serverconnect->GetCurrentServer()->GetListName()
1168 + wxT("|")
1169 // IP and port of the server
1170 + serverconnect->GetCurrentServer()->GetFullIP()
1171 + wxT("|")
1172 + temp;
1175 // Now for amule sig
1177 // Connected. State 1, full info
1178 amulesig_out.AddLine(wxT("1"));
1179 // Server Name
1180 amulesig_out.AddLine(serverconnect->GetCurrentServer()->GetListName());
1181 // Server IP
1182 amulesig_out.AddLine(serverconnect->GetCurrentServer()->GetFullIP());
1183 // Server Port
1184 amulesig_out.AddLine(temp);
1186 if (serverconnect->IsLowID()) {
1187 amulesig_out.AddLine(wxT("L"));
1188 } else {
1189 amulesig_out.AddLine(wxT("H"));
1192 } else if (serverconnect->IsConnecting()) {
1193 emulesig_string = wxT("0");
1195 // Connecting. State 2, No info.
1196 amulesig_out.AddLine(wxT("2\n0\n0\n0\n0"));
1197 } else {
1198 // Not connected to a server
1199 emulesig_string = wxT("0");
1201 // Not connected, state 0, no info
1202 amulesig_out.AddLine(wxT("0\n0\n0\n0\n0"));
1204 if (IsConnectedKad()) {
1205 if(Kademlia::CKademlia::IsFirewalled()) {
1206 // Connected. Firewalled. State 1.
1207 amulesig_out.AddLine(wxT("1"));
1208 } else {
1209 // Connected. State 2.
1210 amulesig_out.AddLine(wxT("2"));
1212 } else {
1213 // Not connected.State 0.
1214 amulesig_out.AddLine(wxT("0"));
1216 emulesig_string += wxT("\xA");
1218 // Datarate for downloads
1219 temp = wxString::Format(wxT("%.1f"), theStats::GetDownloadRate() / 1024.0);
1221 emulesig_string += temp + wxT("|");
1222 amulesig_out.AddLine(temp);
1224 // Datarate for uploads
1225 temp = wxString::Format(wxT("%.1f"), theStats::GetUploadRate() / 1024.0);
1227 emulesig_string += temp + wxT("|");
1228 amulesig_out.AddLine(temp);
1230 // Number of users waiting for upload
1231 temp = wxString::Format(wxT("%d"), theStats::GetWaitingUserCount());
1233 emulesig_string += temp;
1234 amulesig_out.AddLine(temp);
1236 // Number of shared files (not on eMule)
1237 amulesig_out.AddLine(wxString::Format(wxT("%d"), theStats::GetSharedFileCount()));
1240 // eMule signature finished here. Write the line to the wxTextFile.
1241 emulesig_out.AddLine(emulesig_string);
1243 // Now for aMule signature extras
1245 // Nick on the network
1246 amulesig_out.AddLine(thePrefs::GetUserNick());
1248 // Total received in bytes
1249 amulesig_out.AddLine( CFormat( wxT("%llu") ) % (theStats::GetSessionReceivedBytes() + thePrefs::GetTotalDownloaded()) );
1251 // Total sent in bytes
1252 amulesig_out.AddLine( CFormat( wxT("%llu") ) % (theStats::GetSessionSentBytes() + thePrefs::GetTotalUploaded()) );
1254 // amule version
1255 #ifdef SVNDATE
1256 amulesig_out.AddLine(wxT(VERSION) wxT(" ") wxT(SVNDATE));
1257 #else
1258 amulesig_out.AddLine(wxT(VERSION));
1259 #endif
1261 if (zero) {
1262 amulesig_out.AddLine(wxT("0"));
1263 amulesig_out.AddLine(wxT("0"));
1264 amulesig_out.AddLine(wxT("0"));
1265 } else {
1266 // Total received bytes in session
1267 amulesig_out.AddLine( CFormat( wxT("%llu") ) %
1268 theStats::GetSessionReceivedBytes() );
1270 // Total sent bytes in session
1271 amulesig_out.AddLine( CFormat( wxT("%llu") ) %
1272 theStats::GetSessionSentBytes() );
1274 // Uptime
1275 amulesig_out.AddLine(CFormat(wxT("%llu")) % theStats::GetUptimeSeconds());
1278 // Flush the files
1279 emulesig_out.Write();
1280 amulesig_out.Write();
1281 } //End Added By Bouc7
1284 // Gracefully handle fatal exceptions and print backtrace if possible
1285 void CamuleApp::OnFatalException()
1287 /* Print the backtrace */
1288 fprintf(stderr, "\n--------------------------------------------------------------------------------\n");
1289 fprintf(stderr, "A fatal error has occurred and aMule has crashed.\n");
1290 fprintf(stderr, "Please assist us in fixing this problem by posting the backtrace below in our\n");
1291 fprintf(stderr, "'aMule Crashes' forum and include as much information as possible regarding the\n");
1292 fprintf(stderr, "circumstances of this crash. The forum is located here:\n");
1293 fprintf(stderr, " http://forum.amule.org/index.php?board=67.0\n");
1294 fprintf(stderr, "If possible, please try to generate a real backtrace of this crash:\n");
1295 fprintf(stderr, " http://wiki.amule.org/index.php/Backtraces\n\n");
1296 fprintf(stderr, "----------------------------=| BACKTRACE FOLLOWS: |=----------------------------\n");
1297 fprintf(stderr, "Current version is: %s\n", strFullMuleVersion);
1298 fprintf(stderr, "Running on: %s\n\n", strOSDescription);
1300 print_backtrace(1); // 1 == skip this function.
1302 fprintf(stderr, "\n--------------------------------------------------------------------------------\n");
1306 // Sets the localization of aMule
1307 void CamuleApp::Localize_mule()
1309 InitCustomLanguages();
1310 InitLocale(m_locale, StrLang2wx(thePrefs::GetLanguageID()));
1311 if (!m_locale.IsOk()) {
1312 AddLogLineM(false,_("The selected locale seems not to be installed on your box. (Note: I'll try to set it anyway)"));
1317 // Displays information related to important changes in aMule.
1318 // Is called when the user runs a new version of aMule
1319 void CamuleApp::Trigger_New_version(wxString new_version)
1321 wxString info = wxT(" --- ") + CFormat(_("This is the first time you run aMule %s")) % new_version + wxT(" ---\n\n");
1322 if (new_version == wxT("SVN")) {
1323 info += _("This version is a testing version, updated daily, and\n");
1324 info += _("we give no warranty it won't break anything, burn your house,\n");
1325 info += _("or kill your dog. But it *should* be safe to use anyway.\n");
1326 } else if (new_version == wxT("2.2.1")) {
1327 thePrefs::SetAddServersFromServer(false);
1328 thePrefs::SetAddServersFromClient(false);
1329 info += _("The following options have been changed in this release for security reasons:\n");
1330 info += _("\n* Enabled Protocol Obfuscation support for incoming and outgoing connections.\n");
1331 info += _("\n* Disabled updating the server list from other server and clients.\n");
1332 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.");
1333 info += _("\n\nAdditionally, the browser settings have been reset to the system default. Please configure your browser options again if needed.\n");
1336 // General info
1337 info += wxT("\n");
1338 info += _("More information, support and new releases can found at our homepage,\n");
1339 info += _("at www.aMule.org, or in our IRC channel #aMule at irc.freenode.net.\n");
1340 info += wxT("\n");
1341 info += _("Feel free to report any bugs to http://forum.amule.org");
1343 ShowAlert(info, _("Info"), wxCENTRE | wxOK | wxICON_ERROR);
1347 void CamuleApp::SetOSFiles(const wxString new_path)
1349 if ( thePrefs::IsOnlineSignatureEnabled() ) {
1350 if ( ::wxDirExists(new_path) ) {
1351 m_emulesig_path = JoinPaths(new_path, wxT("onlinesig.dat"));
1352 m_amulesig_path = JoinPaths(new_path, wxT("amulesig.dat"));
1353 } else {
1354 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);
1355 m_emulesig_path.Clear();
1356 m_amulesig_path.Clear();
1358 } else {
1359 m_emulesig_path.Clear();
1360 m_amulesig_path.Clear();
1365 #ifdef __WXDEBUG__
1366 #ifndef wxUSE_STACKWALKER
1367 #define wxUSE_STACKWALKER 0
1368 #endif
1369 void CamuleApp::OnAssertFailure(const wxChar* file, int line,
1370 const wxChar* func, const wxChar* cond, const wxChar* msg)
1372 if (!wxUSE_STACKWALKER || !wxThread::IsMain() || !IsRunning()) {
1373 wxString errmsg = CFormat( wxT("%s:%s:%d: Assertion '%s' failed. %s") )
1374 % file % func % line % cond % ( msg ? msg : wxT("") );
1376 fprintf(stderr, "Assertion failed: %s\n", (const char*)unicode2char(errmsg));
1378 // Skip the function-calls directly related to the assert call.
1379 fprintf(stderr, "\nBacktrace follows:\n");
1380 print_backtrace(3);
1381 fprintf(stderr, "\n");
1384 if (wxThread::IsMain() && IsRunning()) {
1385 AMULE_APP_BASE::OnAssertFailure(file, line, func, cond, msg);
1386 } else {
1387 // Abort, allows gdb to catch the assertion
1388 raise( SIGABRT );
1391 #endif
1394 void CamuleApp::OnUDPDnsDone(CMuleInternalEvent& evt)
1396 CServerUDPSocket* socket =(CServerUDPSocket*)evt.GetClientData();
1397 socket->OnHostnameResolved(evt.GetExtraLong());
1401 void CamuleApp::OnSourceDnsDone(CMuleInternalEvent& evt)
1403 downloadqueue->OnHostnameResolved(evt.GetExtraLong());
1407 void CamuleApp::OnServerDnsDone(CMuleInternalEvent& evt)
1409 AddLogLineMS(false, _("Server hostname notified"));
1410 serverconnect->OnServerHostnameResolved(evt.GetClientData(), evt.GetExtraLong());
1414 void CamuleApp::OnTCPTimer(CTimerEvent& WXUNUSED(evt))
1416 if(!IsRunning()) {
1417 return;
1419 serverconnect->StopConnectionTry();
1420 if (IsConnectedED2K() ) {
1421 return;
1423 serverconnect->ConnectToAnyServer();
1427 void CamuleApp::OnCoreTimer(CTimerEvent& WXUNUSED(evt))
1429 // Former TimerProc section
1430 static uint64 msPrev1, msPrev5, msPrevSave, msPrevHist, msPrevOS, msPrevKnownMet;
1431 uint64 msCur = theStats::GetUptimeMillis();
1432 TheTime = msCur / 1000;
1434 if (!IsRunning()) {
1435 return;
1438 #ifndef AMULE_DAEMON
1439 // Check if we should terminate the app
1440 if ( g_shutdownSignal ) {
1441 wxWindow* top = GetTopWindow();
1443 if ( top ) {
1444 top->Close(true);
1445 } else {
1446 // No top-window, have to force termination.
1447 wxExit();
1450 #endif
1452 uploadqueue->Process();
1453 downloadqueue->Process();
1454 //theApp->clientcredits->Process();
1455 theStats::CalculateRates();
1457 if (msCur-msPrevHist > 1000) {
1458 // unlike the other loop counters in this function this one will sometimes
1459 // produce two calls in quick succession (if there was a gap of more than one
1460 // second between calls to TimerProc) - this is intentional! This way the
1461 // history list keeps an average of one node per second and gets thinned out
1462 // correctly as time progresses.
1463 msPrevHist += 1000;
1465 m_statistics->RecordHistory();
1470 if (msCur-msPrev1 > 1000) { // approximately every second
1471 msPrev1 = msCur;
1472 clientcredits->Process();
1473 clientlist->Process();
1475 // Publish files to server if needed.
1476 sharedfiles->Process();
1478 if( Kademlia::CKademlia::IsRunning() ) {
1479 Kademlia::CKademlia::Process();
1480 if(Kademlia::CKademlia::GetPrefs()->HasLostConnection()) {
1481 StopKad();
1482 clientudp->Close();
1483 clientudp->Open();
1484 if (thePrefs::Reconnect()) {
1485 StartKad();
1490 if( serverconnect->IsConnecting() && !serverconnect->IsSingleConnect() ) {
1491 serverconnect->TryAnotherConnectionrequest();
1493 if (serverconnect->IsConnecting()) {
1494 serverconnect->CheckForTimeout();
1496 listensocket->UpdateConnectionsStatus();
1501 if (msCur-msPrev5 > 5000) { // every 5 seconds
1502 msPrev5 = msCur;
1503 listensocket->Process();
1506 if (msCur-msPrevSave >= 60000) {
1507 msPrevSave = msCur;
1508 wxString buffer;
1510 // Save total upload/download to preferences
1511 wxConfigBase* cfg = wxConfigBase::Get();
1512 buffer = CFormat(wxT("%llu")) % (theStats::GetSessionReceivedBytes() + thePrefs::GetTotalDownloaded());
1513 cfg->Write(wxT("/Statistics/TotalDownloadedBytes"), buffer);
1515 buffer = CFormat(wxT("%llu")) % (theStats::GetSessionSentBytes() + thePrefs::GetTotalUploaded());
1516 cfg->Write(wxT("/Statistics/TotalUploadedBytes"), buffer);
1518 // Write changes to file
1519 cfg->Flush();
1523 // Special
1524 if (msCur - msPrevOS >= thePrefs::GetOSUpdate() * 1000ull) {
1525 OnlineSig(); // Added By Bouc7
1526 msPrevOS = msCur;
1529 if (msCur - msPrevKnownMet >= 30*60*1000/*There must be a prefs option for this*/) {
1530 // Save Shared Files data
1531 knownfiles->Save();
1532 msPrevKnownMet = msCur;
1536 // Recomended by lugdunummaster himself - from emule 0.30c
1537 serverconnect->KeepConnectionAlive();
1542 void CamuleApp::OnFinishedHashing(CHashingEvent& evt)
1544 wxCHECK_RET(evt.GetResult(), wxT("No result of hashing"));
1546 CKnownFile* owner = const_cast<CKnownFile*>(evt.GetOwner());
1547 CKnownFile* result = evt.GetResult();
1549 if (owner) {
1550 // Check if the partfile still exists, as it might have
1551 // been deleted in the mean time.
1552 if (downloadqueue->IsPartFile(owner)) {
1553 // This cast must not be done before the IsPartFile
1554 // call, as dynamic_cast will barf on dangling pointers.
1555 dynamic_cast<CPartFile*>(owner)->PartFileHashFinished(result);
1557 } else {
1558 static int filecount;
1559 static uint64 bytecount;
1561 if (knownfiles->SafeAddKFile(result)) {
1562 AddDebugLogLineM(false, logKnownFiles,
1563 CFormat(wxT("Safe adding file to sharedlist: %s")) % result->GetFileName());
1564 sharedfiles->SafeAddKFile(result);
1566 filecount++;
1567 bytecount += result->GetFileSize();
1568 // If we have added 30 files or files with a total size of ~300mb
1569 if ( ( filecount == 30 ) || ( bytecount >= 314572800 ) ) {
1570 AddDebugLogLineM(false, logKnownFiles, wxT("Failsafe for crash on file hashing creation"));
1571 if ( m_app_state != APP_STATE_SHUTTINGDOWN ) {
1572 knownfiles->Save();
1573 filecount = 0;
1574 bytecount = 0;
1577 } else {
1578 AddDebugLogLineM(false, logKnownFiles,
1579 CFormat(wxT("File not added to sharedlist: %s")) % result->GetFileName());
1580 delete result;
1586 void CamuleApp::OnFinishedAICHHashing(CHashingEvent& evt)
1588 wxCHECK_RET(evt.GetResult(), wxT("No result of AICH-hashing"));
1590 CKnownFile* owner = const_cast<CKnownFile*>(evt.GetOwner());
1591 CScopedPtr<CKnownFile> result(evt.GetResult());
1593 // Check that the owner is still valid
1594 if (knownfiles->IsKnownFile(owner)) {
1595 if (result->GetAICHHashset()->GetStatus() == AICH_HASHSETCOMPLETE) {
1596 CAICHHashSet* oldSet = owner->GetAICHHashset();
1597 CAICHHashSet* newSet = result->GetAICHHashset();
1599 owner->SetAICHHashset(newSet);
1600 newSet->SetOwner(owner);
1602 result->SetAICHHashset(oldSet);
1603 oldSet->SetOwner(result.get());
1609 void CamuleApp::OnFinishedCompletion(CCompletionEvent& evt)
1611 CPartFile* completed = const_cast<CPartFile*>(evt.GetOwner());
1612 wxCHECK_RET(completed, wxT("Completion event sent for unspecified file"));
1613 wxASSERT_MSG(downloadqueue->IsPartFile(completed), wxT("CCompletionEvent for unknown partfile."));
1615 completed->CompleteFileEnded(evt.ErrorOccured(), evt.GetFullPath());
1616 if (evt.ErrorOccured()) {
1617 CUserEvents::ProcessEvent(CUserEvents::ErrorOnCompletion, completed);
1620 // Check if we should execute an script/app/whatever.
1621 CUserEvents::ProcessEvent(CUserEvents::DownloadCompleted, completed);
1624 void CamuleApp::OnFinishedAllocation(CAllocFinishedEvent& evt)
1626 CPartFile *file = evt.GetFile();
1627 wxCHECK_RET(file, wxT("Allocation finished event sent for unspecified file"));
1628 wxASSERT_MSG(downloadqueue->IsPartFile(file), wxT("CAllocFinishedEvent for unknown partfile"));
1630 file->SetPartFileStatus(PS_EMPTY);
1632 if (evt.Succeeded()) {
1633 if (evt.IsPaused()) {
1634 file->StopFile();
1635 } else {
1636 file->ResumeFile();
1638 } else {
1639 AddLogLineM(false, CFormat(_("Disk space preallocation for file '%s' failed: %s")) % file->GetFileName() % wxString(UTF82unicode(std::strerror(evt.GetResult()))));
1640 file->StopFile();
1643 file->AllocationFinished();
1646 void CamuleApp::OnNotifyEvent(CMuleGUIEvent& evt)
1648 #if defined(AMULE_DAEMON)
1649 evt.Notify();
1650 #else
1651 if (theApp->amuledlg) {
1652 evt.Notify();
1654 #endif
1658 void CamuleApp::ShutDown()
1660 // Log
1661 AddDebugLogLineM(false, logGeneral, wxT("CamuleApp::ShutDown() has started."));
1663 // Signal the hashing thread to terminate
1664 m_app_state = APP_STATE_SHUTTINGDOWN;
1666 StopKad();
1668 // Kry - Save the sources seeds on app exit
1669 if (thePrefs::GetSrcSeedsOn()) {
1670 downloadqueue->SaveSourceSeeds();
1673 OnlineSig(true); // Added By Bouc7
1675 // Close sockets to avoid new clients coming in
1676 if (listensocket) {
1677 listensocket->Close();
1678 listensocket->KillAllSockets();
1681 if (serverconnect) {
1682 serverconnect->Disconnect();
1685 ECServerHandler->KillAllSockets();
1687 #ifdef ENABLE_UPNP
1688 if (thePrefs::GetUPnPEnabled()) {
1689 if (m_upnp) {
1690 m_upnp->DeletePortMappings(m_upnpMappings);
1693 #endif
1695 // saving data & stuff
1696 if (knownfiles) {
1697 knownfiles->Save();
1700 thePrefs::Add2TotalDownloaded(theStats::GetSessionReceivedBytes());
1701 thePrefs::Add2TotalUploaded(theStats::GetSessionSentBytes());
1703 if (glob_prefs) {
1704 glob_prefs->Save();
1707 CPath configFileName = CPath(ConfigDir + wxT("amule.conf"));
1708 CPath::BackupFile(configFileName, wxT(".bak"));
1710 if (clientlist) {
1711 clientlist->DeleteAll();
1714 // Now we have tried to delete all our clients and sockets,
1715 // but wx 2.9 has only scheduled them for deletion.
1716 // Force deletion now, or it will occur when we wait for a locket mutex,
1717 // and the uploadBandwidthThrottler will crash on invalid objects.
1718 AddDebugLogLineN(logGeneral, wxT("Cleanup pending objects."));
1719 ProcessPendingEvents();
1721 CThreadScheduler::Terminate();
1723 AddDebugLogLineN(logGeneral, wxT("Terminate upload thread."));
1724 uploadBandwidthThrottler->EndThread();
1726 // Log
1727 AddDebugLogLineM(false, logGeneral, wxT("CamuleApp::ShutDown() has ended."));
1731 bool CamuleApp::AddServer(CServer *srv, bool fromUser)
1733 if ( serverlist->AddServer(srv, fromUser) ) {
1734 Notify_ServerAdd(srv);
1735 return true;
1737 return false;
1741 uint32 CamuleApp::GetPublicIP(bool ignorelocal) const
1743 if (m_dwPublicIP == 0) {
1744 if (Kademlia::CKademlia::IsConnected() && Kademlia::CKademlia::GetIPAddress() ) {
1745 return wxUINT32_SWAP_ALWAYS(Kademlia::CKademlia::GetIPAddress());
1746 } else {
1747 return ignorelocal ? 0 : m_localip;
1751 return m_dwPublicIP;
1755 void CamuleApp::SetPublicIP(const uint32 dwIP)
1757 wxASSERT((dwIP == 0) || !IsLowID(dwIP));
1759 if (dwIP != 0 && dwIP != m_dwPublicIP && serverlist != NULL) {
1760 m_dwPublicIP = dwIP;
1761 serverlist->CheckForExpiredUDPKeys();
1762 } else {
1763 m_dwPublicIP = dwIP;
1768 wxString CamuleApp::GetLog(bool reset)
1770 ConfigDir = GetConfigDir();
1771 wxFile logfile;
1772 logfile.Open(ConfigDir + wxT("logfile"));
1773 if ( !logfile.IsOpened() ) {
1774 return _("ERROR: can't open logfile");
1776 int len = logfile.Length();
1777 if ( len == 0 ) {
1778 return _("WARNING: logfile is empty. Something is wrong.");
1780 char *tmp_buffer = new char[len + sizeof(wxChar)];
1781 logfile.Read(tmp_buffer, len);
1782 memset(tmp_buffer + len, 0, sizeof(wxChar));
1784 // try to guess file format
1785 wxString str;
1786 if (tmp_buffer[0] && tmp_buffer[1]) {
1787 str = wxString(UTF82unicode(tmp_buffer));
1788 } else {
1789 str = wxWCharBuffer((wchar_t *)tmp_buffer);
1792 delete [] tmp_buffer;
1793 if ( reset ) {
1794 theLogger.CloseLogfile();
1795 if (theLogger.OpenLogfile(ConfigDir + wxT("logfile"))) {
1796 AddLogLineM(false, _("Log has been reset"));
1799 return str;
1803 wxString CamuleApp::GetServerLog(bool reset)
1805 wxString ret = server_msg;
1806 if ( reset ) {
1807 server_msg.Clear();
1809 return ret;
1812 wxString CamuleApp::GetDebugLog(bool reset)
1814 return GetLog(reset);
1818 void CamuleApp::AddServerMessageLine(wxString &msg)
1820 server_msg += msg + wxT("\n");
1821 AddLogLineM(false, CFormat(_("ServerMessage: %s")) % msg);
1826 void CamuleApp::OnFinishedHTTPDownload(CMuleInternalEvent& event)
1828 switch (event.GetInt()) {
1829 case HTTP_IPFilter:
1830 ipfilter->DownloadFinished(event.GetExtraLong());
1831 break;
1832 case HTTP_ServerMet:
1833 serverlist->DownloadFinished(event.GetExtraLong());
1834 break;
1835 case HTTP_ServerMetAuto:
1836 serverlist->AutoDownloadFinished(event.GetExtraLong());
1837 break;
1838 case HTTP_VersionCheck:
1839 CheckNewVersion(event.GetExtraLong());
1840 break;
1841 case HTTP_NodesDat:
1842 if (event.GetExtraLong() != -1) {
1844 wxString file = ConfigDir + wxT("nodes.dat");
1845 if (wxFileExists(file)) {
1846 wxRemoveFile(file);
1849 if ( Kademlia::CKademlia::IsRunning() ) {
1850 Kademlia::CKademlia::Stop();
1853 wxRenameFile(file + wxT(".download"),file);
1855 Kademlia::CKademlia::Start();
1856 theApp->ShowConnectionState();
1858 } else {
1859 AddLogLineM(true, _("Failed to download the nodes list."));
1861 break;
1862 #ifdef ENABLE_IP2COUNTRY
1863 case HTTP_GeoIP:
1864 theApp->amuledlg->IP2CountryDownloadFinished(event.GetExtraLong());
1865 // If we updated, the dialog is already up. Redraw it to show the flags.
1866 theApp->amuledlg->Refresh();
1867 break;
1868 #endif
1872 void CamuleApp::CheckNewVersion(uint32 result)
1874 if (result == 1) {
1875 wxString filename = ConfigDir + wxT("last_version_check");
1876 wxTextFile file;
1878 if (!file.Open(filename)) {
1879 AddLogLineM(true, _("Failed to open the downloaded version check file") );
1880 return;
1881 } else if (!file.GetLineCount()) {
1882 AddLogLineM(true, _("Corrupted version check file"));
1883 } else {
1884 wxString versionLine = file.GetFirstLine();
1885 wxStringTokenizer tkz(versionLine, wxT("."));
1887 AddDebugLogLineM(false, logGeneral, wxString(wxT("Running: ")) + wxT(VERSION) + wxT(", Version check: ") + versionLine);
1889 long fields[] = {0, 0, 0};
1890 for (int i = 0; i < 3; ++i) {
1891 if (!tkz.HasMoreTokens()) {
1892 AddLogLineM(true, _("Corrupted version check file"));
1893 return;
1894 } else {
1895 wxString token = tkz.GetNextToken();
1897 if (!token.ToLong(&fields[i])) {
1898 AddLogLineM(true, _("Corrupted version check file"));
1899 return;
1904 long curVer = make_full_ed2k_version(VERSION_MJR, VERSION_MIN, VERSION_UPDATE);
1905 long newVer = make_full_ed2k_version(fields[0], fields[1], fields[2]);
1907 if (curVer < newVer) {
1908 AddLogLineM(true, _("You are using an outdated version of aMule!"));
1909 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]));
1910 AddLogLineM(false, _("The latest version can always be found at http://www.amule.org"));
1911 #ifdef AMULE_DAEMON
1912 AddLogLineMS(true, CFormat(_("WARNING: Your aMuled version is outdated: %i.%i.%i < %li.%li.%li"))
1913 % VERSION_MJR % VERSION_MIN % VERSION_UPDATE % fields[0] % fields[1] % fields[2]);
1914 #endif
1915 } else {
1916 AddLogLineM(false, _("Your copy of aMule is up to date."));
1920 file.Close();
1921 wxRemoveFile(filename);
1922 } else {
1923 AddLogLineM(true, _("Failed to download the version check file") );
1929 bool CamuleApp::IsConnected() const
1931 return (IsConnectedED2K() || IsConnectedKad());
1935 bool CamuleApp::IsConnectedED2K() const
1937 return serverconnect && serverconnect->IsConnected();
1941 bool CamuleApp::IsConnectedKad() const
1943 return Kademlia::CKademlia::IsConnected();
1947 bool CamuleApp::IsFirewalled() const
1949 if (theApp->IsConnectedED2K() && !theApp->serverconnect->IsLowID()) {
1950 return false; // we have an eD2K HighID -> not firewalled
1953 return IsFirewalledKad(); // If kad says ok, it's ok.
1956 bool CamuleApp::IsFirewalledKad() const
1958 return !Kademlia::CKademlia::IsConnected() // not connected counts as firewalled
1959 || Kademlia::CKademlia::IsFirewalled();
1962 bool CamuleApp::IsFirewalledKadUDP() const
1964 return !Kademlia::CKademlia::IsConnected() // not connected counts as firewalled
1965 || Kademlia::CUDPFirewallTester::IsFirewalledUDP(true);
1968 bool CamuleApp::IsKadRunning() const
1970 return Kademlia::CKademlia::IsRunning();
1973 // Kad stats
1974 uint32 CamuleApp::GetKadUsers() const
1976 return Kademlia::CKademlia::GetKademliaUsers();
1979 uint32 CamuleApp::GetKadFiles() const
1981 return Kademlia::CKademlia::GetKademliaFiles();
1984 uint32 CamuleApp::GetKadIndexedSources() const
1986 return Kademlia::CKademlia::GetIndexed()->m_totalIndexSource;
1989 uint32 CamuleApp::GetKadIndexedKeywords() const
1991 return Kademlia::CKademlia::GetIndexed()->m_totalIndexKeyword;
1994 uint32 CamuleApp::GetKadIndexedNotes() const
1996 return Kademlia::CKademlia::GetIndexed()->m_totalIndexNotes;
1999 uint32 CamuleApp::GetKadIndexedLoad() const
2001 return Kademlia::CKademlia::GetIndexed()->m_totalIndexLoad;
2005 // True IP of machine
2006 uint32 CamuleApp::GetKadIPAdress() const
2008 return wxUINT32_SWAP_ALWAYS(Kademlia::CKademlia::GetPrefs()->GetIPAddress());
2011 // Buddy status
2012 uint8 CamuleApp::GetBuddyStatus() const
2014 return clientlist->GetBuddyStatus();
2017 uint32 CamuleApp::GetBuddyIP() const
2019 return clientlist->GetBuddy()->GetIP();
2022 uint32 CamuleApp::GetBuddyPort() const
2024 return clientlist->GetBuddy()->GetUDPPort();
2027 bool CamuleApp::CanDoCallback(CUpDownClient *client)
2029 if (Kademlia::CKademlia::IsConnected()) {
2030 if (IsConnectedED2K()) {
2031 if (serverconnect->IsLowID()) {
2032 if (Kademlia::CKademlia::IsFirewalled()) {
2033 //Both Connected - Both Firewalled
2034 return false;
2035 } else {
2036 if (client->GetServerIP() == theApp->serverconnect->GetCurrentServer()->GetIP() &&
2037 client->GetServerPort() == theApp->serverconnect->GetCurrentServer()->GetPort()) {
2038 // Both Connected - Server lowID, Kad Open - Client on same server
2039 // We prevent a callback to the server as this breaks the protocol
2040 // and will get you banned.
2041 return false;
2042 } else {
2043 // Both Connected - Server lowID, Kad Open - Client on remote server
2044 return true;
2047 } else {
2048 //Both Connected - Server HighID, Kad don't care
2049 return true;
2051 } else {
2052 if (Kademlia::CKademlia::IsFirewalled()) {
2053 //Only Kad Connected - Kad Firewalled
2054 return false;
2055 } else {
2056 //Only Kad Conected - Kad Open
2057 return true;
2060 } else {
2061 if (IsConnectedED2K()) {
2062 if (serverconnect->IsLowID()) {
2063 //Only Server Connected - Server LowID
2064 return false;
2065 } else {
2066 //Only Server Connected - Server HighID
2067 return true;
2069 } else {
2070 //We are not connected at all!
2071 return false;
2076 void CamuleApp::ShowUserCount() {
2077 uint32 totaluser = 0, totalfile = 0;
2079 theApp->serverlist->GetUserFileStatus( totaluser, totalfile );
2081 wxString buffer;
2083 static const wxString s_singlenetstatusformat = _("Users: %s | Files: %s");
2084 static const wxString s_bothnetstatusformat = _("Users: E: %s K: %s | Files: E: %s K: %s");
2086 if (thePrefs::GetNetworkED2K() && thePrefs::GetNetworkKademlia()) {
2087 buffer = CFormat(s_bothnetstatusformat) % CastItoIShort(totaluser) % CastItoIShort(Kademlia::CKademlia::GetKademliaUsers()) % CastItoIShort(totalfile) % CastItoIShort(Kademlia::CKademlia::GetKademliaFiles());
2088 } else if (thePrefs::GetNetworkED2K()) {
2089 buffer = CFormat(s_singlenetstatusformat) % CastItoIShort(totaluser) % CastItoIShort(totalfile);
2090 } else if (thePrefs::GetNetworkKademlia()) {
2091 buffer = CFormat(s_singlenetstatusformat) % CastItoIShort(Kademlia::CKademlia::GetKademliaUsers()) % CastItoIShort(Kademlia::CKademlia::GetKademliaFiles());
2092 } else {
2093 buffer = _("No networks selected");
2096 Notify_ShowUserCount(buffer);
2100 void CamuleApp::ListenSocketHandler(wxSocketEvent& event)
2102 wxCHECK_RET(listensocket, wxT("Connection-event for NULL'd listen-socket"));
2103 wxCHECK_RET(event.GetSocketEvent() == wxSOCKET_CONNECTION,
2104 wxT("Invalid event received for listen-socket"));
2106 if (m_app_state == APP_STATE_RUNNING) {
2107 listensocket->OnAccept(0);
2108 } else if (m_app_state == APP_STATE_STARTING) {
2109 // When starting up, connection may be made before we are able
2110 // to handle them. However, if these are ignored, no futher
2111 // connection-events will be triggered, so we have to accept it.
2112 wxSocketBase* socket = listensocket->Accept(false);
2114 wxCHECK_RET(socket, wxT("NULL returned by Accept() during startup"));
2116 socket->Destroy();
2121 void CamuleApp::ShowConnectionState()
2123 static uint8 old_state = (1<<7); // This flag doesn't exist
2125 uint8 state = 0;
2127 if (theApp->serverconnect->IsConnected()) {
2128 state |= CONNECTED_ED2K;
2131 if (Kademlia::CKademlia::IsRunning()) {
2132 if (Kademlia::CKademlia::IsConnected()) {
2133 if (!Kademlia::CKademlia::IsFirewalled()) {
2134 state |= CONNECTED_KAD_OK;
2135 } else {
2136 state |= CONNECTED_KAD_FIREWALLED;
2138 } else {
2139 state |= CONNECTED_KAD_NOT;
2143 Notify_ShowConnState(state);
2145 if (old_state != state) {
2146 // Get the changed value
2147 int changed_flags = old_state ^ state;
2149 if (changed_flags & CONNECTED_ED2K) {
2150 // ED2K status changed
2151 wxString connected_server;
2152 CServer* ed2k_server = theApp->serverconnect->GetCurrentServer();
2153 if (ed2k_server) {
2154 connected_server = ed2k_server->GetListName();
2156 if (state & CONNECTED_ED2K) {
2157 // We connected to some server
2158 const wxString id = theApp->serverconnect->IsLowID() ? _("with LowID") : _("with HighID");
2160 AddLogLineM(true, CFormat(_("Connected to %s %s")) % connected_server % id);
2161 } else {
2162 if ( theApp->serverconnect->IsConnecting() ) {
2163 AddLogLineM(true, CFormat(_("Connecting to %s")) % connected_server);
2164 } else {
2165 AddLogLineM(true, _("Disconnected from eD2k"));
2170 if (changed_flags & CONNECTED_KAD_NOT) {
2171 if (state & CONNECTED_KAD_NOT) {
2172 AddLogLineM(true, _("Kad started."));
2173 } else {
2174 AddLogLineM(true, _("Kad stopped."));
2178 if (changed_flags & (CONNECTED_KAD_OK | CONNECTED_KAD_FIREWALLED)) {
2179 if (state & (CONNECTED_KAD_OK | CONNECTED_KAD_FIREWALLED)) {
2180 if (state & CONNECTED_KAD_OK) {
2181 AddLogLineM(true, _("Connected to Kad (ok)"));
2182 } else {
2183 AddLogLineM(true, _("Connected to Kad (firewalled)"));
2185 } else {
2186 AddLogLineM(true, _("Disconnected from Kad"));
2190 old_state = state;
2192 theApp->downloadqueue->OnConnectionState(IsConnected());
2195 ShowUserCount();
2196 Notify_ShowConnState(state);
2200 void CamuleApp::UDPSocketHandler(wxSocketEvent& event)
2202 CMuleUDPSocket* socket = (CMuleUDPSocket*)(event.GetClientData());
2203 wxCHECK_RET(socket, wxT("No socket owner specified."));
2205 if (IsOnShutDown() || thePrefs::IsUDPDisabled()) return;
2207 if (!IsRunning()) {
2208 if (event.GetSocketEvent() == wxSOCKET_INPUT) {
2209 // Back to the queue!
2210 theApp->AddPendingEvent(event);
2211 return;
2215 switch (event.GetSocketEvent()) {
2216 case wxSOCKET_INPUT:
2217 socket->OnReceive(0);
2218 break;
2220 case wxSOCKET_OUTPUT:
2221 socket->OnSend(0);
2222 break;
2224 case wxSOCKET_LOST:
2225 socket->OnDisconnected(0);
2226 break;
2228 default:
2229 wxFAIL;
2230 break;
2235 void CamuleApp::OnUnhandledException()
2237 // Call the generic exception-handler.
2238 fprintf(stderr, "\taMule Version: %s\n", (const char*)unicode2char(GetFullMuleVersion()));
2239 ::OnUnhandledException();
2242 void CamuleApp::StartKad()
2244 if (!Kademlia::CKademlia::IsRunning() && thePrefs::GetNetworkKademlia()) {
2245 // Kad makes no sense without the Client-UDP socket.
2246 if (!thePrefs::IsUDPDisabled()) {
2247 Kademlia::CKademlia::Start();
2248 } else {
2249 AddLogLineM(true,_("Kad network cannot be used if UDP port is disabled on preferences, not starting."));
2251 } else if (!thePrefs::GetNetworkKademlia()) {
2252 AddLogLineM(true,_("Kad network disabled on preferences, not connecting."));
2256 void CamuleApp::StopKad()
2258 // Stop Kad if it's running
2259 if (Kademlia::CKademlia::IsRunning()) {
2260 Kademlia::CKademlia::Stop();
2265 void CamuleApp::BootstrapKad(uint32 ip, uint16 port)
2267 if (!Kademlia::CKademlia::IsRunning()) {
2268 Kademlia::CKademlia::Start();
2269 theApp->ShowConnectionState();
2272 Kademlia::CKademlia::Bootstrap(ip, port, true);
2276 void CamuleApp::UpdateNotesDat(const wxString& url)
2278 wxString strTempFilename(theApp->ConfigDir + wxT("nodes.dat.download"));
2280 CHTTPDownloadThread *downloader = new CHTTPDownloadThread(url, strTempFilename, HTTP_NodesDat);
2281 downloader->Create();
2282 downloader->Run();
2286 void CamuleApp::DisconnectED2K()
2288 // Stop ED2K if it's running
2289 if (IsConnectedED2K()) {
2290 serverconnect->Disconnect();
2294 bool CamuleApp::CryptoAvailable() const
2296 return clientcredits && clientcredits->CryptoAvailable();
2299 uint32 CamuleApp::GetED2KID() const {
2300 return serverconnect ? serverconnect->GetClientID() : 0;
2303 uint32 CamuleApp::GetID() const {
2304 uint32 ID;
2306 if( Kademlia::CKademlia::IsConnected() && !Kademlia::CKademlia::IsFirewalled() ) {
2307 // We trust Kad above ED2K
2308 ID = ENDIAN_NTOHL(Kademlia::CKademlia::GetIPAddress());
2309 } else if( theApp->serverconnect->IsConnected() ) {
2310 ID = theApp->serverconnect->GetClientID();
2311 } else if ( Kademlia::CKademlia::IsConnected() && Kademlia::CKademlia::IsFirewalled() ) {
2312 // A firewalled Kad client get's a "1"
2313 ID = 1;
2314 } else {
2315 ID = 0;
2318 return ID;
2321 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_FINISHED_HTTP_DOWNLOAD)
2322 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_SOURCE_DNS_DONE)
2323 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_UDP_DNS_DONE)
2324 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_SERVER_DNS_DONE)
2325 // File_checked_for_headers