Upstream tarball 9663
[amule.git] / src / amule.cpp
blobef3549ffb1f427fa9c11b2c0b980ae588af131d3
1 //
2 // This file is part of the aMule Project.
3 //
4 // Copyright (c) 2003-2008 aMule Team ( admin@amule.org / http://www.amule.org )
5 // Copyright (c) 2002-2008 Merkur ( devs@emule-project.net / http://www.emule-project.net )
6 //
7 // Any parts of this program derived from the xMule, lMule or eMule project,
8 // or contributed by third-party developers are copyrighted by their
9 // respective authors.
11 // This program is free software; you can redistribute it and/or modify
12 // it under the terms of the GNU General Public License as published by
13 // the Free Software Foundation; either version 2 of the License, or
14 // (at your option) any later version.
16 // This program is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU General Public License for more details.
20 //
21 // You should have received a copy of the GNU General Public License
22 // along with this program; if not, write to the Free Software
23 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #define AMULE_CPP
30 #include "amule.h" // Interface declarations.
32 #include <csignal>
33 #include <cstring>
34 #include <wx/process.h>
35 #include <wx/sstream.h>
37 #ifdef HAVE_CONFIG_H
38 #include "config.h" // Needed for HAVE_GETRLIMIT, HAVE_SETRLIMIT,
39 // HAVE_SYS_RESOURCE_H, HAVE_SYS_STATVFS_H, VERSION
40 // and ENABLE_NLS
41 #endif
43 #include <common/ClientVersion.h>
45 #include <wx/cmdline.h> // Needed for wxCmdLineParser
46 #include <wx/config.h> // Do_not_auto_remove (win32)
47 #include <wx/fileconf.h>
48 #include <wx/snglinst.h>
49 #include <wx/tokenzr.h>
50 #include <wx/wfstream.h>
53 #include <common/Format.h> // Needed for CFormat
54 #include "kademlia/kademlia/Kademlia.h"
55 #include "kademlia/kademlia/Prefs.h"
56 #include "kademlia/kademlia/UDPFirewallTester.h"
57 #include "ClientCreditsList.h" // Needed for CClientCreditsList
58 #include "ClientList.h" // Needed for CClientList
59 #include "ClientUDPSocket.h" // Needed for CClientUDPSocket & CMuleUDPSocket
60 #include "ExternalConn.h" // Needed for ExternalConn & MuleConnection
61 #include <common/FileFunctions.h> // Needed for CDirIterator
62 #include "FriendList.h" // Needed for CFriendList
63 #include "HTTPDownload.h" // Needed for CHTTPDownloadThread
64 #include "InternalEvents.h" // Needed for CMuleInternalEvent
65 #include "IPFilter.h" // Needed for CIPFilter
66 #include "KnownFileList.h" // Needed for CKnownFileList
67 #include "ListenSocket.h" // Needed for CListenSocket
68 #include "Logger.h" // Needed for CLogger // Do_not_auto_remove
69 #include "MagnetURI.h" // Needed for CMagnetURI
70 #include "OtherFunctions.h"
71 #include "PartFile.h" // Needed for CPartFile
72 #include "Preferences.h" // Needed for CPreferences
73 #include "SearchList.h" // Needed for CSearchList
74 #include "Server.h" // Needed for GetListName
75 #include "ServerList.h" // Needed for CServerList
76 #include "ServerConnect.h" // Needed for CServerConnect
77 #include "ServerUDPSocket.h" // Needed for CServerUDPSocket
78 #include "Statistics.h" // Needed for CStatistics
79 #include "TerminationProcessAmuleweb.h" // Needed for CTerminationProcessAmuleweb
80 #include "ThreadTasks.h"
81 #include "updownclient.h" // Needed for CUpDownClient
82 #include "UploadQueue.h" // Needed for CUploadQueue
83 #include "UploadBandwidthThrottler.h"
84 #include "UserEvents.h"
85 #include "ScopedPtr.h"
87 #ifdef ENABLE_UPNP
88 #include "UPnPBase.h" // Needed for UPnP
89 #endif
91 #ifdef __WXMAC__
92 #include <wx/sysopt.h> // Do_not_auto_remove
93 #endif
95 #ifndef AMULE_DAEMON
96 #ifdef __WXMAC__
97 #include <CoreFoundation/CFBundle.h> // Do_not_auto_remove
98 #include <wx/mac/corefoundation/cfstring.h> // Do_not_auto_remove
99 #endif
100 #include <wx/msgdlg.h>
102 #include "amuleDlg.h"
103 #endif
106 #ifdef HAVE_SYS_RESOURCE_H
107 #include <sys/resource.h>
108 #endif
110 #ifdef HAVE_SYS_STATVFS_H
111 #include <sys/statvfs.h> // Do_not_auto_remove
112 #endif
115 #ifdef __GLIBC__
116 # define RLIMIT_RESOURCE __rlimit_resource
117 #else
118 # define RLIMIT_RESOURCE int
119 #endif
121 static void UnlimitResource(RLIMIT_RESOURCE resType)
123 #if defined(HAVE_GETRLIMIT) && defined(HAVE_SETRLIMIT)
124 struct rlimit rl;
125 getrlimit(resType, &rl);
126 rl.rlim_cur = rl.rlim_max;
127 setrlimit(resType, &rl);
128 #endif
132 static void SetResourceLimits()
134 #ifdef HAVE_SYS_RESOURCE_H
135 UnlimitResource(RLIMIT_DATA);
136 #ifndef __UCLIBC__
137 UnlimitResource(RLIMIT_FSIZE);
138 #endif
139 UnlimitResource(RLIMIT_NOFILE);
140 #ifdef RLIMIT_RSS
141 UnlimitResource(RLIMIT_RSS);
142 #endif
143 #endif
146 // We store the received signal in order to avoid race-conditions
147 // in the signal handler.
148 bool g_shutdownSignal = false;
150 void OnShutdownSignal( int /* sig */ )
152 signal(SIGINT, SIG_DFL);
153 signal(SIGTERM, SIG_DFL);
155 g_shutdownSignal = true;
157 #ifdef AMULE_DAEMON
158 theApp->ExitMainLoop();
159 #endif
163 CamuleApp::CamuleApp()
165 // Madcat - Initialize timer as the VERY FIRST thing to avoid any issues later.
166 // Kry - I love to init the vars on init, even before timer.
167 StartTickTimer();
169 // Initialization
170 m_app_state = APP_STATE_STARTING;
172 theApp = &wxGetApp();
174 clientlist = NULL;
175 searchlist = NULL;
176 knownfiles = NULL;
177 serverlist = NULL;
178 serverconnect = NULL;
179 sharedfiles = NULL;
180 listensocket = NULL;
181 clientudp = NULL;
182 clientcredits = NULL;
183 friendlist = NULL;
184 downloadqueue = NULL;
185 uploadqueue = NULL;
186 ipfilter = NULL;
187 ECServerHandler = NULL;
188 m_singleInstance= NULL;
189 glob_prefs = NULL;
190 m_statistics = NULL;
191 uploadBandwidthThrottler = NULL;
192 #ifdef ENABLE_UPNP
193 m_upnp = NULL;
194 m_upnpMappings.resize(4);
195 #endif
196 core_timer = NULL;
198 m_localip = 0;
199 m_dwPublicIP = 0;
200 webserver_pid = 0;
202 enable_daemon_fork = false;
204 strFullMuleVersion = NULL;
205 strOSDescription = NULL;
207 // Apprently needed for *BSD
208 SetResourceLimits();
211 CamuleApp::~CamuleApp()
213 // Closing the log-file as the very last thing, since
214 // wxWidgets log-events are saved in it as well.
215 theLogger.CloseLogfile();
217 free(strFullMuleVersion);
218 free(strOSDescription);
221 int CamuleApp::OnExit()
223 if (m_app_state!=APP_STATE_STARTING) {
224 AddLogLineMS(false, _("Now, exiting main app..."));
227 // From wxWidgets docs, wxConfigBase:
228 // ...
229 // Note that you must delete this object (usually in wxApp::OnExit)
230 // in order to avoid memory leaks, wxWidgets won't do it automatically.
232 // As it happens, you may even further simplify the procedure described
233 // above: you may forget about calling Set(). When Get() is called and
234 // there is no current object, it will create one using Create() function.
235 // To disable this behaviour DontCreateOnDemand() is provided.
236 delete wxConfigBase::Set((wxConfigBase *)NULL);
238 // Save credits
239 clientcredits->SaveList();
241 // Kill amuleweb if running
242 if (webserver_pid) {
243 AddLogLineMS(false, CFormat(_("Killing amuleweb instance with pid `%ld' ... ")) % webserver_pid);
244 wxKillError rc;
245 wxKill(webserver_pid, wxSIGTERM, &rc);
246 AddLogLineMS(false, _("Killed!"));
249 if (m_app_state!=APP_STATE_STARTING) {
250 AddLogLineMS(false, _("aMule OnExit: Terminating core."));
253 delete serverlist;
254 serverlist = NULL;
256 delete searchlist;
257 searchlist = NULL;
259 delete clientcredits;
260 clientcredits = NULL;
262 delete friendlist;
263 friendlist = NULL;
265 // Destroying CDownloadQueue calls destructor for CPartFile
266 // calling CSharedFileList::SafeAddKFile occasionally.
267 delete sharedfiles;
268 sharedfiles = NULL;
270 delete serverconnect;
271 serverconnect = NULL;
273 delete listensocket;
274 listensocket = NULL;
276 delete clientudp;
277 clientudp = NULL;
279 delete knownfiles;
280 knownfiles = NULL;
282 delete clientlist;
283 clientlist = NULL;
285 delete uploadqueue;
286 uploadqueue = NULL;
288 delete downloadqueue;
289 downloadqueue = NULL;
291 delete ipfilter;
292 ipfilter = NULL;
294 #ifdef ENABLE_UPNP
295 delete m_upnp;
296 m_upnp = NULL;
297 #endif
299 delete ECServerHandler;
300 ECServerHandler = NULL;
302 delete m_statistics;
303 m_statistics = NULL;
305 delete glob_prefs;
306 glob_prefs = NULL;
307 CPreferences::EraseItemList();
309 #if defined(__WXMAC__) && defined(AMULE_DAEMON)
310 //#warning TODO: fix wxSingleInstanceChecker for amuled on Mac (wx link problems)
311 #else
312 delete m_singleInstance;
313 #endif
314 m_singleInstance = NULL;
316 delete uploadBandwidthThrottler;
317 uploadBandwidthThrottler = NULL;
319 if (m_app_state!=APP_STATE_STARTING) {
320 AddLogLineNS(_("aMule shutdown completed."));
323 #if wxUSE_MEMORY_TRACING
324 AddLogLineNS(_("Memory debug results for aMule exit:"));
325 // Log mem debug mesages to wxLogStderr
326 wxLog* oldLog = wxLog::SetActiveTarget(new wxLogStderr);
327 //AddLogLineNS(wxT("**************Classes**************");
328 //wxDebugContext::PrintClasses();
329 //AddLogLineNS(wxT("***************Dump***************");
330 //wxDebugContext::Dump();
331 AddLogLineNS(wxT("***************Stats**************"));
332 wxDebugContext::PrintStatistics(true);
334 // Set back to wxLogGui
335 delete wxLog::SetActiveTarget(oldLog);
336 #endif
338 StopTickTimer();
340 // Return 0 for succesful program termination
341 return AMULE_APP_BASE::OnExit();
345 int CamuleApp::InitGui(bool, wxString &)
347 return 0;
352 * Checks permissions on a aMule directory, creating if needed.
354 * @param desc A description of the directory in question, used for error messages.
355 * @param directory The directory in question.
356 * @param fallback If the dir specified with 'directory' could not be created, try this instead.
357 * @return The bool is false on error. The wxString contains the used path.
359 std::pair<bool, CPath> CheckMuleDirectory(const wxString& desc, const CPath& directory, const wxString& alternative)
361 wxString msg;
363 if (directory.IsDir(CPath::readwritable)) {
364 return std::pair<bool, CPath>(true, directory);
365 } else if (directory.DirExists()) {
366 msg = CFormat(wxT("Permissions on the %s directory too strict!\n")
367 wxT("aMule cannot proceed. To fix this, you must set read/write/exec\n")
368 wxT("permissions for the folder '%s'"))
369 % desc % directory;
370 } else if (CPath::MakeDir(directory)) {
371 return std::pair<bool, CPath>(true, directory);
372 } else {
373 msg << CFormat(wxT("Could not create the %s directory at '%s'."))
374 % desc % directory;
377 // Attempt to use fallback directory.
378 const CPath fallback = CPath(alternative);
379 if (fallback.IsOk() && (directory != fallback)) {
380 msg << wxT("\nAttempting to use default directory at location \n'")
381 << alternative << wxT("'.");
382 theApp->ShowAlert(msg, wxT("Error accessing directory."), wxICON_ERROR | wxOK);
384 return CheckMuleDirectory(desc, fallback, wxEmptyString);
387 theApp->ShowAlert(msg, wxT("Fatal error."), wxICON_ERROR | wxOK);
388 return std::pair<bool, CPath>(false, CPath(wxEmptyString));
393 // Application initialization
395 bool CamuleApp::OnInit()
397 #if wxUSE_MEMORY_TRACING
398 // any text before call of Localize_mule needs not to be translated.
399 AddLogLineMS(false, wxT("Checkpoint set on app init for memory debug"));
400 wxDebugContext::SetCheckpoint();
401 #endif
403 // Forward wxLog events to CLogger
404 wxLog::SetActiveTarget(new CLoggerTarget);
406 m_localip = StringHosttoUint32(::wxGetFullHostName());
408 #ifndef __WXMSW__
409 // get rid of sigpipe
410 signal(SIGPIPE, SIG_IGN);
411 #else
412 // Handle CTRL-Break
413 signal(SIGBREAK, OnShutdownSignal);
414 #endif
415 // Handle sigint and sigterm
416 signal(SIGINT, OnShutdownSignal);
417 signal(SIGTERM, OnShutdownSignal);
419 #ifdef __WXMAC__
420 // For listctrl's to behave on Mac
421 wxSystemOptions::SetOption(wxT("mac.listctrl.always_use_generic"), 1);
422 #endif
424 // This can't be on constructor or wx2.4.2 doesn't set it.
425 #if !wxCHECK_VERSION(2, 9, 0)
426 SetVendorName(wxT("TikuWarez"));
427 #endif
428 SetAppName(wxT("aMule"));
430 wxString FullMuleVersion = GetFullMuleVersion();
431 wxString OSDescription = wxGetOsDescription();
432 strFullMuleVersion = strdup((const char *)unicode2char(FullMuleVersion));
433 strOSDescription = strdup((const char *)unicode2char(OSDescription));
434 OSType = OSDescription.BeforeFirst( wxT(' ') );
435 if ( OSType.IsEmpty() ) {
436 OSType = wxT("Unknown");
439 // Handle uncaught exceptions
440 InstallMuleExceptionHandler();
442 // Parse cmdline arguments.
443 wxCmdLineParser cmdline(AMULE_APP_BASE::argc, AMULE_APP_BASE::argv);
445 // Handle these arguments.
446 cmdline.AddSwitch(wxT("v"), wxT("version"), wxT("Displays the current version number."));
447 cmdline.AddSwitch(wxT("h"), wxT("help"), wxT("Displays this information."));
448 cmdline.AddSwitch(wxT("i"), wxT("enable-stdin"), wxT("Does not disable stdin."));
449 #ifdef AMULE_DAEMON
450 cmdline.AddSwitch(wxT("f"), wxT("full-daemon"), wxT("Fork to background."));
451 cmdline.AddOption(wxT("p"), wxT("pid-file"), wxT("After fork, create a pid-file in the given fullname file."));
452 cmdline.AddOption(wxT("c"), wxT("config-dir"), wxT("read config from <dir> instead of home"));
453 cmdline.AddSwitch(wxT("e"), wxT("ec-config"), wxT("Configure EC (External Connections)."));
454 #else
455 cmdline.AddOption(wxT("geometry"), wxEmptyString,
456 wxT("Sets the geometry of the app.\n")
457 wxT("\t\t\t<str> uses the same format as standard X11 apps:\n")
458 wxT("\t\t\t[=][<width>{xX}<height>][{+-}<xoffset>{+-}<yoffset>]"));
459 #endif
460 cmdline.AddSwitch(wxT("d"), wxT("disable-fatal"), wxT("Does not handle fatal exception."));
461 cmdline.AddSwitch(wxT("o"), wxT("log-stdout"), wxT("Print log messages to stdout."));
462 cmdline.AddSwitch(wxT("r"), wxT("reset-config"), wxT("Resets config to default values."));
463 #ifndef __WXMSW__
464 // Change webserver path, not available on Windows
465 cmdline.AddOption(wxT("w"), wxT("use-amuleweb"), wxT("Specify location of amuleweb binary."));
466 #endif
468 // Show help on --help or invalid commands
469 if ( cmdline.Parse() ) {
470 return false;
471 } else if ( cmdline.Found(wxT("help")) ) {
472 cmdline.Usage();
473 return false;
476 bool ec_config = false;
478 #ifdef AMULE_DAEMON
479 ec_config = cmdline.Found(wxT("ec-config"));
480 if ( cmdline.Found(wxT("config-dir"), &ConfigDir) ) {
481 if (ConfigDir.Last() != wxFileName::GetPathSeparator()) {
482 ConfigDir += wxFileName::GetPathSeparator();
484 } else {
485 ConfigDir = GetConfigDir();
487 #else
488 ConfigDir = GetConfigDir();
489 #endif
491 if ( !cmdline.Found(wxT("disable-fatal")) ) {
492 #ifndef __WXMSW__
493 // catch fatal exceptions
494 wxHandleFatalExceptions(true);
495 #endif
498 bool reset_config = cmdline.Found(wxT("reset-config"));
500 theLogger.SetEnabledStdoutLog(cmdline.Found(wxT("log-stdout")));
501 #ifdef AMULE_DAEMON
502 enable_daemon_fork = cmdline.Found(wxT("full-daemon"));
503 if ( cmdline.Found(wxT("pid-file"), &PidFile) ) {
504 // Remove any existing PidFile
505 if ( wxFileExists (PidFile) ) wxRemoveFile (PidFile);
507 #else
508 enable_daemon_fork = false;
509 PidFile.Clear();
510 #endif
512 if (theLogger.IsEnabledStdoutLog()) {
513 if ( enable_daemon_fork ) {
514 AddLogLineMS(false, wxT("Daemon will fork to background - log to stdout disabled"));
515 theLogger.SetEnabledStdoutLog(false);
516 } else {
517 AddLogLineMS(false, wxT("Logging to stdout enabled"));
521 if ( cmdline.Found(wxT("version")) ) {
522 AddLogLineMS(false, CFormat(wxT("%s (OS: %s)")) % FullMuleVersion % OSType);
524 return false;
527 // Default geometry of the GUI. Can be changed with a cmdline argument...
528 bool geometry_enabled = false;
529 wxString geom_string;
530 #ifndef AMULE_DAEMON
531 if ( cmdline.Found(wxT("geometry"), &geom_string) ) {
532 geometry_enabled = true;
534 #endif
536 AddLogLineMS(false, wxT("Initialising ") + FullMuleVersion);
538 // Ensure that "~/.aMule/" is accessible.
539 if (!CheckMuleDirectory(wxT("configuration"), CPath(ConfigDir), wxEmptyString).first) {
540 return false;
543 if (reset_config) {
544 // Make a backup first.
545 wxRemoveFile(ConfigDir + wxT("amule.conf.backup"));
546 wxRenameFile(ConfigDir + wxT("amule.conf"), ConfigDir + wxT("amule.conf.backup"));
547 AddLogLineMS(false, wxT("Your settings have been reset to default values.\nThe old config file has been saved as amule.conf.backup\n"));
550 #if defined(__WXMAC__) && defined(AMULE_DAEMON)
551 //#warning TODO: fix wxSingleInstanceChecker for amuled on Mac (wx link problems)
552 AddLogLineMS(true, wxT("WARNING: The check for other instances is currently disabled in amuled.\n"
553 "Please make sure that no other instance of aMule is running or your files might be corrupted.\n"));
554 #else
555 AddLogLineMS(false, wxT("Checking if there is an instance already running..."));
557 m_singleInstance = new wxSingleInstanceChecker();
558 if (m_singleInstance->Create(wxT("muleLock"), ConfigDir)
559 && m_singleInstance->IsAnotherRunning()) {
560 AddLogLineMS(true, wxT("There is an instance of aMule already running"));
561 AddLogLineNS(CFormat(wxT("(lock file: %s%s)")) % ConfigDir % wxT("muleLock"));
563 // This is very tricky. The most secure way to communicate is via ED2K links file
564 wxTextFile ed2kFile(ConfigDir + wxT("ED2KLinks"));
565 if (!ed2kFile.Exists()) {
566 ed2kFile.Create();
569 if (ed2kFile.Open()) {
570 ed2kFile.AddLine(wxT("RAISE_DIALOG"));
571 ed2kFile.Write();
573 AddLogLineMS(false, wxT("Raising current running instance."));
574 } else {
575 AddLogLineMS(true, wxT("Failed to open 'ED2KFile', cannot signal running instance."));
578 return false;
579 } else {
580 AddLogLineMS(false, wxT("No other instances are running."));
582 #endif
584 // Close standard-input
585 if ( !cmdline.Found(wxT("enable-stdin")) ) {
586 // The full daemon will close all std file-descriptors by itself,
587 // so closing it here would lead to the closing on the first open
588 // file, which is the logfile opened below
589 if (!enable_daemon_fork) {
590 close(0);
594 // This creates the CFG file we shall use
595 wxConfigBase* cfg = new wxFileConfig( wxEmptyString, wxEmptyString, ConfigDir + wxT("amule.conf") );
597 // Set the config object as the global cfg file
598 wxConfig::Set( cfg );
600 // Make a backup of the log file
601 CPath logfileName = CPath(ConfigDir + wxT("logfile"));
602 if (logfileName.FileExists()) {
603 CPath::BackupFile(logfileName, wxT(".bak"));
606 // Open the log file
607 if (!theLogger.OpenLogfile(logfileName.GetRaw())) {
608 // use std err as last resolt to indicate problem
609 fputs("ERROR: unable to open log file\n", stderr);
610 // failure to open log is serious problem
611 return false;
614 // Load Preferences
615 CPreferences::BuildItemList(ConfigDir);
616 CPreferences::LoadAllItems( wxConfigBase::Get() );
618 glob_prefs = new CPreferences();
620 std::pair<bool, CPath> checkResult;
621 checkResult = CheckMuleDirectory(wxT("temp"), thePrefs::GetTempDir(), ConfigDir + wxT("Temp"));
622 if (checkResult.first) {
623 thePrefs::SetTempDir(checkResult.second);
624 } else {
625 return false;
628 checkResult = CheckMuleDirectory(wxT("incoming"), thePrefs::GetIncomingDir(), ConfigDir + wxT("Incoming"));
629 if (checkResult.first) {
630 thePrefs::SetIncomingDir(checkResult.second);
631 } else {
632 return false;
635 // Some sanity check
636 if (!thePrefs::UseTrayIcon()) {
637 thePrefs::SetMinToTray(false);
640 // Build the filenames for the two OS files
641 SetOSFiles(thePrefs::GetOSDir().GetRaw());
643 #ifdef ENABLE_NLS
644 // Load localization settings
645 Localize_mule();
646 #endif
648 // Configure EC for amuled when invoked with ec-config
649 if (ec_config) {
650 AddLogLineMS(false, _("\nEC configuration"));
651 thePrefs::SetECPass(GetPassword());
652 thePrefs::EnableExternalConnections(true);
653 AddLogLineMS(false, _("Password set and external connections enabled."));
656 #ifndef __WXMSW__
657 if (getuid() == 0) {
658 wxString msg =
659 wxT("Warning! You are running aMule as root.\n")
660 wxT("Doing so is not recommended for security reasons,\n")
661 wxT("and you are advised to run aMule as an normal\n")
662 wxT("user instead.");
664 ShowAlert(msg, _("WARNING"), wxCENTRE | wxOK | wxICON_ERROR);
666 fprintf(stderr, "\n--------------------------------------------------\n");
667 fprintf(stderr, "%s", (const char*)unicode2UTF8(msg));
668 fprintf(stderr, "\n--------------------------------------------------\n\n");
670 #endif
672 // Display notification on new version or first run
673 wxTextFile vfile( ConfigDir + wxT("lastversion") );
674 wxString newMule(wxT( VERSION ));
676 if ( !wxFileExists( vfile.GetName() ) ) {
677 vfile.Create();
680 if ( vfile.Open() ) {
681 // Check if this version has been run before
682 bool found = false;
683 for ( size_t i = 0; i < vfile.GetLineCount(); i++ ) {
684 // Check if this version has been run before
685 if ( vfile.GetLine(i) == newMule ) {
686 found = true;
687 break;
691 // We havent run this version before?
692 if ( !found ) {
693 // Insert new at top to provide faster searches
694 vfile.InsertLine( newMule, 0 );
696 Trigger_New_version( newMule );
699 // Keep at most 10 entires
700 while ( vfile.GetLineCount() > 10 )
701 vfile.RemoveLine( vfile.GetLineCount() - 1 );
703 vfile.Write();
704 vfile.Close();
707 // Check if we have the old style locale config
708 wxString langId = thePrefs::GetLanguageID();
709 if (!langId.IsEmpty() && (langId.GetChar(0) >= '0' && langId.GetChar(0) <= '9')) {
710 wxString info(_("Your locale has been changed to System Default due to a configuration change. Sorry."));
711 thePrefs::SetLanguageID(wxLang2Str(wxLANGUAGE_DEFAULT));
712 ShowAlert(info, _("Info"), wxCENTRE | wxOK | wxICON_ERROR);
715 m_statistics = new CStatistics();
717 clientlist = new CClientList();
718 friendlist = new CFriendList();
719 searchlist = new CSearchList();
720 knownfiles = new CKnownFileList();
721 serverlist = new CServerList();
723 sharedfiles = new CSharedFileList(knownfiles);
724 clientcredits = new CClientCreditsList();
726 // bugfix - do this before creating the uploadqueue
727 downloadqueue = new CDownloadQueue();
728 uploadqueue = new CUploadQueue();
729 ipfilter = new CIPFilter();
731 // Creates all needed listening sockets
732 wxString msg;
733 if (!ReinitializeNetwork(&msg)) {
734 AddLogLineMS(false, wxT("\n"));
735 AddLogLineMS(false, msg);
738 // Test if there's any new version
739 if (thePrefs::CheckNewVersion()) {
740 // We use the thread base because I don't want a dialog to pop up.
741 CHTTPDownloadThread* version_check =
742 new CHTTPDownloadThread(wxT("http://amule.sourceforge.net/lastversion"),
743 theApp->ConfigDir + wxT("last_version_check"), HTTP_VersionCheck, false);
744 version_check->Create();
745 version_check->Run();
748 // Create main dialog, or fork to background (daemon).
749 InitGui(geometry_enabled, geom_string);
751 #if !defined(__WXMAC__) && defined(AMULE_DAEMON)
752 // Need to refresh wxSingleInstanceChecker after the daemon fork() !
753 if (enable_daemon_fork) {
754 //#warning TODO: fix wxSingleInstanceChecker for amuled on Mac (wx link problems)
755 delete m_singleInstance;
756 m_singleInstance = new wxSingleInstanceChecker(wxT("muleLock"), ConfigDir);
757 // No need to check IsAnotherRunning() - we've done it before.
759 #endif
761 // Has to be created after the call to InitGui, as fork
762 // (when using posix threads) only replicates the mainthread,
763 // and the UBT constructor creates a thread.
764 uploadBandwidthThrottler = new UploadBandwidthThrottler();
766 // These must be initialized after the gui is loaded.
767 serverlist->Init();
768 downloadqueue->LoadMetFiles(thePrefs::GetTempDir());
769 sharedfiles->Reload();
771 if (thePrefs::IPFilterAutoLoad()) {
772 ipfilter->Update(thePrefs::IPFilterURL());
776 // Ensure that the up/down ratio is used
777 CPreferences::CheckUlDlRatio();
779 // The user can start pressing buttons like mad if he feels like it.
780 m_app_state = APP_STATE_RUNNING;
782 // Kry - Load the sources seeds on app init
783 if (thePrefs::GetSrcSeedsOn()) {
784 downloadqueue->LoadSourceSeeds();
787 if (!serverlist->GetServerCount() && thePrefs::GetNetworkED2K()) {
788 // There are no servers and ED2K active -> ask for download.
789 // As we cannot ask in amuled, we just update there
790 // Kry TODO: Store server.met URL on preferences and use it here and in GUI.
791 #ifndef AMULE_DAEMON
792 if (wxYES == wxMessageBox(
793 wxString(
794 _("You don't have any server in the server list.\nDo you want aMule to download a new list now?")),
795 wxString(_("Server list download")),
796 wxYES_NO,
797 static_cast<wxWindow*>(theApp->amuledlg)))
798 #endif
800 // workaround amuled crash
801 #ifndef AMULE_DAEMON
802 serverlist->UpdateServerMetFromURL(
803 wxT("http://gruk.org/server.met.gz"));
804 #endif
809 // Autoconnect if that option is enabled
810 if (thePrefs::DoAutoConnect() && (thePrefs::GetNetworkED2K() || thePrefs::GetNetworkKademlia())) {
811 AddLogLineM(true, _("Connecting"));
812 if (thePrefs::GetNetworkED2K()) {
813 theApp->serverconnect->ConnectToAnyServer();
816 StartKad();
820 // Enable GeoIP
821 #ifdef ENABLE_IP2COUNTRY
822 theApp->amuledlg->EnableIP2Country();
823 #endif
825 // No webserver on Win at all (yet)
826 #ifndef __WXMSW__
827 // Run webserver?
828 if (thePrefs::GetWSIsEnabled()) {
829 wxString aMuleConfigFile = ConfigDir + wxT("amule.conf");
830 wxString amulewebPath = wxT("amuleweb");
831 if(true == cmdline.Found(wxT("use-amuleweb"), &amulewebPath)) {
832 AddLogLineNS(CFormat(_("Using amuleweb in '%s'.")) % amulewebPath);
835 #if defined(__WXMAC__) && !defined(AMULE_DAEMON)
836 // For the Mac GUI application, look for amuleweb in the bundle
837 CFURLRef amulewebUrl = CFBundleCopyAuxiliaryExecutableURL(
838 CFBundleGetMainBundle(), CFSTR("amuleweb"));
840 if (amulewebUrl) {
841 CFURLRef absoluteUrl = CFURLCopyAbsoluteURL(amulewebUrl);
842 CFRelease(amulewebUrl);
844 if (absoluteUrl) {
845 CFStringRef amulewebCfstr = CFURLCopyFileSystemPath(absoluteUrl, kCFURLPOSIXPathStyle);
846 CFRelease(absoluteUrl);
847 amulewebPath = wxMacCFStringHolder(amulewebCfstr).AsString(wxLocale::GetSystemEncoding());
850 #endif
852 wxString cmd =
853 wxT("'") +
854 amulewebPath +
855 wxT("' '--amule-config-file=") +
856 aMuleConfigFile +
857 wxT("'");
858 CTerminationProcessAmuleweb *p = new CTerminationProcessAmuleweb(cmd, &webserver_pid);
859 webserver_pid = wxExecute(cmd, wxEXEC_ASYNC, p);
860 bool webserver_ok = webserver_pid > 0;
861 if (webserver_ok) {
862 AddLogLineM(true, CFormat(_("web server running on pid %d")) % webserver_pid);
863 } else {
864 delete p;
865 ShowAlert(_(
866 "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"),
867 _("ERROR"), wxOK | wxICON_ERROR);
870 #endif /* ! __WXMSW__ */
872 // Start performing background tasks
873 CThreadScheduler::Start();
875 return true;
878 bool CamuleApp::ReinitializeNetwork(wxString* msg)
880 bool ok = true;
881 static bool firstTime = true;
883 if (!firstTime) {
884 // TODO: Destroy previously created sockets
886 firstTime = false;
888 // Some sanity checks first
889 if (thePrefs::ECPort() == thePrefs::GetPort()) {
890 // Select a random usable port in the range 1025 ... 2^16 - 1
891 uint16 port = thePrefs::ECPort();
892 while ( port < 1024 || port == thePrefs::GetPort() ) {
893 port = (uint16)rand();
895 thePrefs::SetECPort( port );
897 wxString err =
898 wxT("Network configuration failed! You cannot use the same port\n")
899 wxT("for the main TCP port and the External Connections port.\n")
900 wxT("The EC port has been changed to avoid conflict, see the\n")
901 wxT("preferences for the new value.\n");
902 *msg << err;
904 AddLogLineM( false, wxEmptyString );
905 AddLogLineM( true, err );
906 AddLogLineM( false, wxEmptyString );
908 ok = false;
911 if (thePrefs::GetUDPPort() == thePrefs::GetPort() + 3) {
912 // Select a random usable value in the range 1025 ... 2^16 - 1
913 uint16 port = thePrefs::GetUDPPort();
914 while ( port < 1024 || port == thePrefs::GetPort() + 3 ) {
915 port = (uint16)rand();
917 thePrefs::SetUDPPort( port );
919 wxString err =
920 wxT("Network configuration failed! You set your UDP port to\n")
921 wxT("the value of the main TCP port plus 3.\n")
922 wxT("This port has been reserved for the Server-UDP port. The\n")
923 wxT("port value has been changed to avoid conflict, see the\n")
924 wxT("preferences for the new value\n");
925 *msg << err;
927 AddLogLineM( false, wxEmptyString );
928 AddLogLineM( true, err );
929 AddLogLineM( false, wxEmptyString );
931 ok = false;
934 // Create the address where we are going to listen
935 // TODO: read this from configuration file
936 amuleIPV4Address myaddr[4];
938 // Create the External Connections Socket.
939 // Default is 4712.
940 // Get ready to handle connections from apps like amulecmd
941 if (thePrefs::GetECAddress().IsEmpty() || !myaddr[0].Hostname(thePrefs::GetECAddress())) {
942 myaddr[0].AnyAddress();
944 myaddr[0].Service(thePrefs::ECPort());
945 ECServerHandler = new ExternalConn(myaddr[0], msg);
947 // Create the UDP socket TCP+3.
948 // Used for source asking on servers.
949 if (thePrefs::GetAddress().IsEmpty()) {
950 myaddr[1].AnyAddress();
951 } else if (!myaddr[1].Hostname(thePrefs::GetAddress())) {
952 myaddr[1].AnyAddress();
953 AddLogLineM(true, CFormat(_("Could not bind ports to the specified address: %s"))
954 % thePrefs::GetAddress());
957 wxString ip = myaddr[1].IPAddress();
958 myaddr[1].Service(thePrefs::GetPort()+3);
959 serverconnect = new CServerConnect(serverlist, myaddr[1]);
960 *msg << CFormat( wxT("*** Server UDP socket (TCP+3) at %s:%u\n") )
961 % ip % ((unsigned int)thePrefs::GetPort() + 3u);
963 // Create the ListenSocket (aMule TCP socket).
964 // Used for Client Port / Connections from other clients,
965 // Client to Client Source Exchange.
966 // Default is 4662.
967 myaddr[2] = myaddr[1];
968 myaddr[2].Service(thePrefs::GetPort());
969 listensocket = new CListenSocket(myaddr[2]);
970 *msg << CFormat( wxT("*** TCP socket (TCP) listening on %s:%u\n") )
971 % ip % (unsigned int)(thePrefs::GetPort());
972 // This command just sets a flag to control maximum number of connections.
973 // Notify(true) has already been called to the ListenSocket, so events may
974 // be already comming in.
975 if (listensocket->Ok()) {
976 listensocket->StartListening();
977 } else {
978 // If we wern't able to start listening, we need to warn the user
979 wxString err;
980 err = CFormat(_("Port %u is not available. You will be LOWID\n")) %
981 (unsigned int)(thePrefs::GetPort());
982 *msg << err;
983 AddLogLineM(true, err);
984 err.Clear();
985 err = CFormat(
986 _("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.")) %
987 (unsigned int)(thePrefs::GetPort());
988 ShowAlert(err, _("ERROR"), wxOK | wxICON_ERROR);
991 // Create the UDP socket.
992 // Used for extended eMule protocol, Queue Rating, File Reask Ping.
993 // Also used for Kademlia.
994 // Default is port 4672.
995 myaddr[3] = myaddr[1];
996 myaddr[3].Service(thePrefs::GetUDPPort());
997 clientudp = new CClientUDPSocket(myaddr[3], thePrefs::GetProxyData());
998 if (!thePrefs::IsUDPDisabled()) {
999 *msg << CFormat( wxT("*** Client UDP socket (extended eMule) at %s:%u") )
1000 % ip % thePrefs::GetUDPPort();
1001 } else {
1002 *msg << wxT("*** Client UDP socket (extended eMule) disabled on preferences");
1005 #ifdef ENABLE_UPNP
1006 if (thePrefs::GetUPnPEnabled()) {
1007 try {
1008 m_upnpMappings[0] = CUPnPPortMapping(
1009 myaddr[0].Service(),
1010 "TCP",
1011 thePrefs::GetUPnPECEnabled(),
1012 "aMule TCP External Connections Socket");
1013 m_upnpMappings[1] = CUPnPPortMapping(
1014 myaddr[1].Service(),
1015 "UDP",
1016 thePrefs::GetUPnPEnabled(),
1017 "aMule UDP socket (TCP+3)");
1018 m_upnpMappings[2] = CUPnPPortMapping(
1019 myaddr[2].Service(),
1020 "TCP",
1021 thePrefs::GetUPnPEnabled(),
1022 "aMule TCP Listen Socket");
1023 m_upnpMappings[3] = CUPnPPortMapping(
1024 myaddr[3].Service(),
1025 "UDP",
1026 thePrefs::GetUPnPEnabled(),
1027 "aMule UDP Extended eMule Socket");
1028 m_upnp = new CUPnPControlPoint(thePrefs::GetUPnPTCPPort());
1029 m_upnp->AddPortMappings(m_upnpMappings);
1030 } catch(CUPnPException &e) {
1031 wxString error_msg;
1032 error_msg << e.what();
1033 AddLogLineM(true, error_msg);
1034 fprintf(stderr, "%s\n", (const char *)unicode2char(error_msg));
1037 #endif
1039 return ok;
1042 // Returns a magnet ed2k URI
1043 wxString CamuleApp::CreateMagnetLink(const CAbstractFile *f)
1045 CMagnetURI uri;
1047 uri.AddField(wxT("dn"), f->GetFileName().Cleanup(false).GetPrintable());
1048 uri.AddField(wxT("xt"), wxString(wxT("urn:ed2k:")) + f->GetFileHash().Encode().Lower());
1049 uri.AddField(wxT("xt"), wxString(wxT("urn:ed2khash:")) + f->GetFileHash().Encode().Lower());
1050 uri.AddField(wxT("xl"), CFormat(wxT("%d")) % f->GetFileSize());
1052 return uri.GetLink();
1055 // Returns a ed2k file URL
1056 wxString CamuleApp::CreateED2kLink(const CAbstractFile *f, bool add_source, bool use_hostname, bool addcryptoptions)
1058 wxASSERT(!(!add_source && (use_hostname || addcryptoptions)));
1059 // Construct URL like this: ed2k://|file|<filename>|<size>|<hash>|/
1060 wxString strURL = CFormat(wxT("ed2k://|file|%s|%i|%s|/"))
1061 % f->GetFileName().Cleanup(false)
1062 % f->GetFileSize() % f->GetFileHash().Encode();
1064 if (add_source && IsConnected() && !IsFirewalled()) {
1065 // Create the first part of the URL
1066 strURL << wxT("|sources,");
1067 if (use_hostname) {
1068 strURL << thePrefs::GetYourHostname();
1069 } else {
1070 uint32 clientID = GetID();
1071 strURL << (uint8) clientID << wxT(".") <<
1072 (uint8)(clientID >> 8) << wxT(".") <<
1073 (uint8)(clientID >> 16) << wxT(".") <<
1074 (uint8)(clientID >> 24);
1077 strURL << wxT(":") <<
1078 thePrefs::GetPort();
1080 if (addcryptoptions) {
1081 const uint8 uSupportsCryptLayer = thePrefs::IsClientCryptLayerSupported() ? 1 : 0;
1082 const uint8 uRequestsCryptLayer = thePrefs::IsClientCryptLayerRequested() ? 1 : 0;
1083 const uint8 uRequiresCryptLayer = thePrefs::IsClientCryptLayerRequired() ? 1 : 0;
1084 const uint8 byCryptOptions = (uRequiresCryptLayer << 2) | (uRequestsCryptLayer << 1) | (uSupportsCryptLayer << 0) | (uSupportsCryptLayer ? 0x80 : 0x00);
1086 strURL << wxT(":") << byCryptOptions;
1088 if (byCryptOptions & 0x80) {
1089 strURL << wxT(":") << thePrefs::GetUserHash().Encode();
1092 strURL << wxT("|/");
1093 } else if (add_source) {
1094 AddLogLineM(true, _("WARNING: You can't add yourself as a source for an eD2k link while having a lowid."));
1097 // Result is "ed2k://|file|<filename>|<size>|<hash>|/|sources,[(<ip>|<hostname>):<port>[:cryptoptions[:hash]]]|/"
1098 return strURL;
1101 // Returns a ed2k link with AICH info if available
1102 wxString CamuleApp::CreateED2kAICHLink(const CKnownFile* f)
1104 // Create the first part of the URL
1105 wxString strURL = CreateED2kLink(f);
1106 // Append the AICH info
1107 if (f->HasProperAICHHashSet()) {
1108 strURL.RemoveLast(); // remove trailing '/'
1109 strURL << wxT("h=") << f->GetAICHMasterHash() << wxT("|/");
1112 // Result is "ed2k://|file|<filename>|<size>|<hash>|h=<AICH master hash>|/"
1113 return strURL;
1116 /* Original implementation by Bouc7 of the eMule Project.
1117 aMule Signature idea was designed by BigBob and implemented
1118 by Un-Thesis, with design inputs and suggestions from bothie.
1120 void CamuleApp::OnlineSig(bool zero /* reset stats (used on shutdown) */)
1122 // Do not do anything if online signature is disabled in Preferences
1123 if (!thePrefs::IsOnlineSignatureEnabled() || m_emulesig_path.IsEmpty()) {
1124 // We do not need to check m_amulesig_path because if m_emulesig_path is empty,
1125 // that means m_amulesig_path is empty too.
1126 return;
1129 // Remove old signature files
1130 if ( wxFileExists( m_emulesig_path ) ) { wxRemoveFile( m_emulesig_path ); }
1131 if ( wxFileExists( m_amulesig_path ) ) { wxRemoveFile( m_amulesig_path ); }
1134 wxTextFile amulesig_out;
1135 wxTextFile emulesig_out;
1137 // Open both files if needed
1138 if ( !emulesig_out.Create( m_emulesig_path) ) {
1139 AddLogLineM(true, _("Failed to create OnlineSig File"));
1140 // Will never try again.
1141 m_amulesig_path.Clear();
1142 m_emulesig_path.Clear();
1143 return;
1146 if ( !amulesig_out.Create(m_amulesig_path) ) {
1147 AddLogLineM(true, _("Failed to create aMule OnlineSig File"));
1148 // Will never try again.
1149 m_amulesig_path.Clear();
1150 m_emulesig_path.Clear();
1151 return;
1154 wxString emulesig_string;
1155 wxString temp;
1157 if (zero) {
1158 emulesig_string = wxT("0\xA0.0|0.0|0");
1159 amulesig_out.AddLine(wxT("0\n0\n0\n0\n0\n0\n0.0\n0.0\n0\n0"));
1160 } else {
1161 if (IsConnectedED2K()) {
1163 temp = wxString::Format(wxT("%d"),serverconnect->GetCurrentServer()->GetPort());
1165 // We are online
1166 emulesig_string =
1167 // Connected
1168 wxT("1|")
1169 //Server name
1170 + serverconnect->GetCurrentServer()->GetListName()
1171 + wxT("|")
1172 // IP and port of the server
1173 + serverconnect->GetCurrentServer()->GetFullIP()
1174 + wxT("|")
1175 + temp;
1178 // Now for amule sig
1180 // Connected. State 1, full info
1181 amulesig_out.AddLine(wxT("1"));
1182 // Server Name
1183 amulesig_out.AddLine(serverconnect->GetCurrentServer()->GetListName());
1184 // Server IP
1185 amulesig_out.AddLine(serverconnect->GetCurrentServer()->GetFullIP());
1186 // Server Port
1187 amulesig_out.AddLine(temp);
1189 if (serverconnect->IsLowID()) {
1190 amulesig_out.AddLine(wxT("L"));
1191 } else {
1192 amulesig_out.AddLine(wxT("H"));
1195 } else if (serverconnect->IsConnecting()) {
1196 emulesig_string = wxT("0");
1198 // Connecting. State 2, No info.
1199 amulesig_out.AddLine(wxT("2\n0\n0\n0\n0"));
1200 } else {
1201 // Not connected to a server
1202 emulesig_string = wxT("0");
1204 // Not connected, state 0, no info
1205 amulesig_out.AddLine(wxT("0\n0\n0\n0\n0"));
1207 if (IsConnectedKad()) {
1208 if(Kademlia::CKademlia::IsFirewalled()) {
1209 // Connected. Firewalled. State 1.
1210 amulesig_out.AddLine(wxT("1"));
1211 } else {
1212 // Connected. State 2.
1213 amulesig_out.AddLine(wxT("2"));
1215 } else {
1216 // Not connected.State 0.
1217 amulesig_out.AddLine(wxT("0"));
1219 emulesig_string += wxT("\xA");
1221 // Datarate for downloads
1222 temp = wxString::Format(wxT("%.1f"), theStats::GetDownloadRate() / 1024.0);
1224 emulesig_string += temp + wxT("|");
1225 amulesig_out.AddLine(temp);
1227 // Datarate for uploads
1228 temp = wxString::Format(wxT("%.1f"), theStats::GetUploadRate() / 1024.0);
1230 emulesig_string += temp + wxT("|");
1231 amulesig_out.AddLine(temp);
1233 // Number of users waiting for upload
1234 temp = wxString::Format(wxT("%d"), theStats::GetWaitingUserCount());
1236 emulesig_string += temp;
1237 amulesig_out.AddLine(temp);
1239 // Number of shared files (not on eMule)
1240 amulesig_out.AddLine(wxString::Format(wxT("%d"), theStats::GetSharedFileCount()));
1243 // eMule signature finished here. Write the line to the wxTextFile.
1244 emulesig_out.AddLine(emulesig_string);
1246 // Now for aMule signature extras
1248 // Nick on the network
1249 amulesig_out.AddLine(thePrefs::GetUserNick());
1251 // Total received in bytes
1252 amulesig_out.AddLine( CFormat( wxT("%llu") ) % (theStats::GetSessionReceivedBytes() + thePrefs::GetTotalDownloaded()) );
1254 // Total sent in bytes
1255 amulesig_out.AddLine( CFormat( wxT("%llu") ) % (theStats::GetSessionSentBytes() + thePrefs::GetTotalUploaded()) );
1257 // amule version
1258 #ifdef SVNDATE
1259 amulesig_out.AddLine(wxT(VERSION) wxT(" ") wxT(SVNDATE));
1260 #else
1261 amulesig_out.AddLine(wxT(VERSION));
1262 #endif
1264 if (zero) {
1265 amulesig_out.AddLine(wxT("0"));
1266 amulesig_out.AddLine(wxT("0"));
1267 amulesig_out.AddLine(wxT("0"));
1268 } else {
1269 // Total received bytes in session
1270 amulesig_out.AddLine( CFormat( wxT("%llu") ) %
1271 theStats::GetSessionReceivedBytes() );
1273 // Total sent bytes in session
1274 amulesig_out.AddLine( CFormat( wxT("%llu") ) %
1275 theStats::GetSessionSentBytes() );
1277 // Uptime
1278 amulesig_out.AddLine(CFormat(wxT("%llu")) % theStats::GetUptimeSeconds());
1281 // Flush the files
1282 emulesig_out.Write();
1283 amulesig_out.Write();
1284 } //End Added By Bouc7
1287 // Gracefully handle fatal exceptions and print backtrace if possible
1288 void CamuleApp::OnFatalException()
1290 /* Print the backtrace */
1291 fprintf(stderr, "\n--------------------------------------------------------------------------------\n");
1292 fprintf(stderr, "A fatal error has occurred and aMule has crashed.\n");
1293 fprintf(stderr, "Please assist us in fixing this problem by posting the backtrace below in our\n");
1294 fprintf(stderr, "'aMule Crashes' forum and include as much information as possible regarding the\n");
1295 fprintf(stderr, "circumstances of this crash. The forum is located here:\n");
1296 fprintf(stderr, " http://forum.amule.org/index.php?board=67.0\n");
1297 fprintf(stderr, "If possible, please try to generate a real backtrace of this crash:\n");
1298 fprintf(stderr, " http://www.amule.org/wiki/index.php/Backtraces\n\n");
1299 fprintf(stderr, "----------------------------=| BACKTRACE FOLLOWS: |=----------------------------\n");
1300 fprintf(stderr, "Current version is: %s\n", strFullMuleVersion);
1301 fprintf(stderr, "Running on: %s\n\n", strOSDescription);
1303 print_backtrace(1); // 1 == skip this function.
1305 fprintf(stderr, "\n--------------------------------------------------------------------------------\n");
1309 // Sets the localization of aMule
1310 void CamuleApp::Localize_mule()
1312 InitCustomLanguages();
1313 InitLocale(m_locale, StrLang2wx(thePrefs::GetLanguageID()));
1314 if (!m_locale.IsOk()) {
1315 AddLogLineM(false,_("The selected locale seems not to be installed on your box. (Note: I'll try to set it anyway)"));
1320 // Displays information related to important changes in aMule.
1321 // Is called when the user runs a new version of aMule
1322 void CamuleApp::Trigger_New_version(wxString new_version)
1324 wxString info = wxT(" --- ") + CFormat(_("This is the first time you run aMule %s")) % new_version + wxT(" ---\n\n");
1325 if (new_version == wxT("SVN")) {
1326 info += _("This version is a testing version, updated daily, and\n");
1327 info += _("we give no warranty it won't break anything, burn your house,\n");
1328 info += _("or kill your dog. But it *should* be safe to use anyway.\n");
1329 } else if (new_version == wxT("2.2.1")) {
1330 thePrefs::SetAddServersFromServer(false);
1331 thePrefs::SetAddServersFromClient(false);
1332 info += _("The following options have been changed in this release for security reasons:\n");
1333 info += _("\n* Enabled Protocol Obfuscation support for incoming and outgoing connections.\n");
1334 info += _("\n* Disabled updating the server list from other server and clients.\n");
1335 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.");
1336 info += _("\n\nAdditionally, the browser settings have been reset to the system default. Please configure your browser options again if needed.\n");
1339 // General info
1340 info += wxT("\n");
1341 info += _("More information, support and new releases can found at our homepage,\n");
1342 info += _("at www.aMule.org, or in our IRC channel #aMule at irc.freenode.net.\n");
1343 info += wxT("\n");
1344 info += _("Feel free to report any bugs to http://forum.amule.org");
1346 ShowAlert(info, _("Info"), wxCENTRE | wxOK | wxICON_ERROR);
1350 void CamuleApp::SetOSFiles(const wxString new_path)
1352 if ( thePrefs::IsOnlineSignatureEnabled() ) {
1353 if ( ::wxDirExists(new_path) ) {
1354 m_emulesig_path = JoinPaths(new_path, wxT("onlinesig.dat"));
1355 m_amulesig_path = JoinPaths(new_path, wxT("amulesig.dat"));
1356 } else {
1357 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);
1358 m_emulesig_path.Clear();
1359 m_amulesig_path.Clear();
1361 } else {
1362 m_emulesig_path.Clear();
1363 m_amulesig_path.Clear();
1368 #ifdef __WXDEBUG__
1369 #ifndef wxUSE_STACKWALKER
1370 #define wxUSE_STACKWALKER 0
1371 #endif
1372 void CamuleApp::OnAssertFailure(const wxChar* file, int line,
1373 const wxChar* func, const wxChar* cond, const wxChar* msg)
1375 if (!wxUSE_STACKWALKER || !wxThread::IsMain() || !IsRunning()) {
1376 wxString errmsg = CFormat( wxT("%s:%s:%d: Assertion '%s' failed. %s") )
1377 % file % func % line % cond % ( msg ? msg : wxT("") );
1379 fprintf(stderr, "Assertion failed: %s\n", (const char*)unicode2char(errmsg));
1381 // Skip the function-calls directly related to the assert call.
1382 fprintf(stderr, "\nBacktrace follows:\n");
1383 print_backtrace(3);
1384 fprintf(stderr, "\n");
1387 if (wxThread::IsMain() && IsRunning()) {
1388 AMULE_APP_BASE::OnAssertFailure(file, line, func, cond, msg);
1389 } else {
1390 // Abort, allows gdb to catch the assertion
1391 raise( SIGABRT );
1394 #endif
1397 void CamuleApp::OnUDPDnsDone(CMuleInternalEvent& evt)
1399 CServerUDPSocket* socket =(CServerUDPSocket*)evt.GetClientData();
1400 socket->OnHostnameResolved(evt.GetExtraLong());
1404 void CamuleApp::OnSourceDnsDone(CMuleInternalEvent& evt)
1406 downloadqueue->OnHostnameResolved(evt.GetExtraLong());
1410 void CamuleApp::OnServerDnsDone(CMuleInternalEvent& evt)
1412 AddLogLineMS(false, _("Server hostname notified"));
1413 serverconnect->OnServerHostnameResolved(evt.GetClientData(), evt.GetExtraLong());
1417 void CamuleApp::OnTCPTimer(CTimerEvent& WXUNUSED(evt))
1419 if(!IsRunning()) {
1420 return;
1422 serverconnect->StopConnectionTry();
1423 if (IsConnectedED2K() ) {
1424 return;
1426 serverconnect->ConnectToAnyServer();
1430 void CamuleApp::OnCoreTimer(CTimerEvent& WXUNUSED(evt))
1432 // Former TimerProc section
1433 static uint64 msPrev1, msPrev5, msPrevSave, msPrevHist, msPrevOS, msPrevKnownMet;
1434 uint64 msCur = theStats::GetUptimeMillis();
1435 TheTime = msCur / 1000;
1437 if (!IsRunning()) {
1438 return;
1441 #ifndef AMULE_DAEMON
1442 // Check if we should terminate the app
1443 if ( g_shutdownSignal ) {
1444 wxWindow* top = GetTopWindow();
1446 if ( top ) {
1447 top->Close(true);
1448 } else {
1449 // No top-window, have to force termination.
1450 wxExit();
1453 #endif
1455 uploadqueue->Process();
1456 downloadqueue->Process();
1457 //theApp->clientcredits->Process();
1458 theStats::CalculateRates();
1460 if (msCur-msPrevHist > 1000) {
1461 // unlike the other loop counters in this function this one will sometimes
1462 // produce two calls in quick succession (if there was a gap of more than one
1463 // second between calls to TimerProc) - this is intentional! This way the
1464 // history list keeps an average of one node per second and gets thinned out
1465 // correctly as time progresses.
1466 msPrevHist += 1000;
1468 m_statistics->RecordHistory();
1473 if (msCur-msPrev1 > 1000) { // approximately every second
1474 msPrev1 = msCur;
1475 clientcredits->Process();
1476 clientlist->Process();
1478 // Publish files to server if needed.
1479 sharedfiles->Process();
1481 if( Kademlia::CKademlia::IsRunning() ) {
1482 Kademlia::CKademlia::Process();
1483 if(Kademlia::CKademlia::GetPrefs()->HasLostConnection()) {
1484 StopKad();
1485 clientudp->Close();
1486 clientudp->Open();
1487 if (thePrefs::Reconnect()) {
1488 StartKad();
1493 if( serverconnect->IsConnecting() && !serverconnect->IsSingleConnect() ) {
1494 serverconnect->TryAnotherConnectionrequest();
1496 if (serverconnect->IsConnecting()) {
1497 serverconnect->CheckForTimeout();
1499 listensocket->UpdateConnectionsStatus();
1504 if (msCur-msPrev5 > 5000) { // every 5 seconds
1505 msPrev5 = msCur;
1506 listensocket->Process();
1509 if (msCur-msPrevSave >= 60000) {
1510 msPrevSave = msCur;
1511 wxString buffer;
1513 // Save total upload/download to preferences
1514 wxConfigBase* cfg = wxConfigBase::Get();
1515 buffer = CFormat(wxT("%llu")) % (theStats::GetSessionReceivedBytes() + thePrefs::GetTotalDownloaded());
1516 cfg->Write(wxT("/Statistics/TotalDownloadedBytes"), buffer);
1518 buffer = CFormat(wxT("%llu")) % (theStats::GetSessionSentBytes() + thePrefs::GetTotalUploaded());
1519 cfg->Write(wxT("/Statistics/TotalUploadedBytes"), buffer);
1521 // Write changes to file
1522 cfg->Flush();
1526 // Special
1527 if (msCur - msPrevOS >= thePrefs::GetOSUpdate() * 1000ull) {
1528 OnlineSig(); // Added By Bouc7
1529 msPrevOS = msCur;
1532 if (msCur - msPrevKnownMet >= 30*60*1000/*There must be a prefs option for this*/) {
1533 // Save Shared Files data
1534 knownfiles->Save();
1535 msPrevKnownMet = msCur;
1539 // Recomended by lugdunummaster himself - from emule 0.30c
1540 serverconnect->KeepConnectionAlive();
1545 void CamuleApp::OnFinishedHashing(CHashingEvent& evt)
1547 wxCHECK_RET(evt.GetResult(), wxT("No result of hashing"));
1549 CKnownFile* owner = const_cast<CKnownFile*>(evt.GetOwner());
1550 CKnownFile* result = evt.GetResult();
1552 if (owner) {
1553 // Check if the partfile still exists, as it might have
1554 // been deleted in the mean time.
1555 if (downloadqueue->IsPartFile(owner)) {
1556 // This cast must not be done before the IsPartFile
1557 // call, as dynamic_cast will barf on dangling pointers.
1558 dynamic_cast<CPartFile*>(owner)->PartFileHashFinished(result);
1560 } else {
1561 static int filecount;
1562 static uint64 bytecount;
1564 if (knownfiles->SafeAddKFile(result)) {
1565 AddDebugLogLineM(false, logKnownFiles,
1566 CFormat(wxT("Safe adding file to sharedlist: %s")) % result->GetFileName());
1567 sharedfiles->SafeAddKFile(result);
1569 filecount++;
1570 bytecount += result->GetFileSize();
1571 // If we have added 30 files or files with a total size of ~300mb
1572 if ( ( filecount == 30 ) || ( bytecount >= 314572800 ) ) {
1573 AddDebugLogLineM(false, logKnownFiles, wxT("Failsafe for crash on file hashing creation"));
1574 if ( m_app_state != APP_STATE_SHUTTINGDOWN ) {
1575 knownfiles->Save();
1576 filecount = 0;
1577 bytecount = 0;
1580 } else {
1581 AddDebugLogLineM(false, logKnownFiles,
1582 CFormat(wxT("File not added to sharedlist: %s")) % result->GetFileName());
1583 delete result;
1589 void CamuleApp::OnFinishedAICHHashing(CHashingEvent& evt)
1591 wxCHECK_RET(evt.GetResult(), wxT("No result of AICH-hashing"));
1593 CKnownFile* owner = const_cast<CKnownFile*>(evt.GetOwner());
1594 CScopedPtr<CKnownFile> result(evt.GetResult());
1596 // Check that the owner is still valid
1597 if (knownfiles->IsKnownFile(owner)) {
1598 if (result->GetAICHHashset()->GetStatus() == AICH_HASHSETCOMPLETE) {
1599 CAICHHashSet* oldSet = owner->GetAICHHashset();
1600 CAICHHashSet* newSet = result->GetAICHHashset();
1602 owner->SetAICHHashset(newSet);
1603 newSet->SetOwner(owner);
1605 result->SetAICHHashset(oldSet);
1606 oldSet->SetOwner(result.get());
1612 void CamuleApp::OnFinishedCompletion(CCompletionEvent& evt)
1614 CPartFile* completed = const_cast<CPartFile*>(evt.GetOwner());
1615 wxCHECK_RET(completed, wxT("Completion event sent for unspecified file"));
1616 wxASSERT_MSG(downloadqueue->IsPartFile(completed), wxT("CCompletionEvent for unknown partfile."));
1618 completed->CompleteFileEnded(evt.ErrorOccured(), evt.GetFullPath());
1619 if (evt.ErrorOccured()) {
1620 CUserEvents::ProcessEvent(CUserEvents::ErrorOnCompletion, completed);
1623 // Check if we should execute an script/app/whatever.
1624 CUserEvents::ProcessEvent(CUserEvents::DownloadCompleted, completed);
1627 void CamuleApp::OnFinishedAllocation(CAllocFinishedEvent& evt)
1629 CPartFile *file = evt.GetFile();
1630 wxCHECK_RET(file, wxT("Allocation finished event sent for unspecified file"));
1631 wxASSERT_MSG(downloadqueue->IsPartFile(file), wxT("CAllocFinishedEvent for unknown partfile"));
1633 file->SetPartFileStatus(PS_EMPTY);
1635 if (evt.Succeeded()) {
1636 if (evt.IsPaused()) {
1637 file->StopFile();
1638 } else {
1639 file->ResumeFile();
1641 } else {
1642 AddLogLineM(false, CFormat(_("Disk space preallocation for file '%s' failed: %s")) % file->GetFileName() % wxString(UTF82unicode(std::strerror(evt.GetResult()))));
1643 file->StopFile();
1646 file->AllocationFinished();
1649 void CamuleApp::OnNotifyEvent(CMuleGUIEvent& evt)
1651 #if defined(AMULE_DAEMON)
1652 evt.Notify();
1653 #else
1654 if (theApp->amuledlg) {
1655 evt.Notify();
1657 #endif
1661 void CamuleApp::ShutDown()
1663 // Log
1664 AddDebugLogLineM(false, logGeneral, wxT("CamuleApp::ShutDown() has started."));
1666 // Signal the hashing thread to terminate
1667 m_app_state = APP_STATE_SHUTTINGDOWN;
1669 StopKad();
1671 // Kry - Save the sources seeds on app exit
1672 if (thePrefs::GetSrcSeedsOn()) {
1673 downloadqueue->SaveSourceSeeds();
1676 OnlineSig(true); // Added By Bouc7
1678 // Close sockets to avoid new clients coming in
1679 if (listensocket) {
1680 listensocket->Close();
1681 listensocket->KillAllSockets();
1684 if (serverconnect) {
1685 serverconnect->Disconnect();
1688 ECServerHandler->KillAllSockets();
1690 #ifdef ENABLE_UPNP
1691 if (thePrefs::GetUPnPEnabled()) {
1692 if (m_upnp) {
1693 m_upnp->DeletePortMappings(m_upnpMappings);
1696 #endif
1698 // saving data & stuff
1699 if (knownfiles) {
1700 knownfiles->Save();
1703 thePrefs::Add2TotalDownloaded(theStats::GetSessionReceivedBytes());
1704 thePrefs::Add2TotalUploaded(theStats::GetSessionSentBytes());
1706 if (glob_prefs) {
1707 glob_prefs->Save();
1710 if (clientlist) {
1711 clientlist->DeleteAll();
1714 CThreadScheduler::Terminate();
1716 theApp->uploadBandwidthThrottler->EndThread();
1718 // Log
1719 AddDebugLogLineM(false, logGeneral, wxT("CamuleApp::ShutDown() has ended."));
1723 bool CamuleApp::AddServer(CServer *srv, bool fromUser)
1725 if ( serverlist->AddServer(srv, fromUser) ) {
1726 Notify_ServerAdd(srv);
1727 return true;
1729 return false;
1733 uint32 CamuleApp::GetPublicIP(bool ignorelocal) const
1735 if (m_dwPublicIP == 0) {
1736 if (Kademlia::CKademlia::IsConnected() && Kademlia::CKademlia::GetIPAddress() ) {
1737 return wxUINT32_SWAP_ALWAYS(Kademlia::CKademlia::GetIPAddress());
1738 } else {
1739 return ignorelocal ? 0 : m_localip;
1743 return m_dwPublicIP;
1747 void CamuleApp::SetPublicIP(const uint32 dwIP)
1749 wxASSERT((dwIP == 0) || !IsLowID(dwIP));
1751 if (dwIP != 0 && dwIP != m_dwPublicIP && serverlist != NULL) {
1752 m_dwPublicIP = dwIP;
1753 serverlist->CheckForExpiredUDPKeys();
1754 } else {
1755 m_dwPublicIP = dwIP;
1760 wxString CamuleApp::GetLog(bool reset)
1762 ConfigDir = GetConfigDir();
1763 wxFile logfile;
1764 logfile.Open(ConfigDir + wxT("logfile"));
1765 if ( !logfile.IsOpened() ) {
1766 return _("ERROR: can't open logfile");
1768 int len = logfile.Length();
1769 if ( len == 0 ) {
1770 return _("WARNING: logfile is empty. Something is wrong.");
1772 char *tmp_buffer = new char[len + sizeof(wxChar)];
1773 logfile.Read(tmp_buffer, len);
1774 memset(tmp_buffer + len, 0, sizeof(wxChar));
1776 // try to guess file format
1777 wxString str;
1778 if (tmp_buffer[0] && tmp_buffer[1]) {
1779 str = wxString(UTF82unicode(tmp_buffer));
1780 } else {
1781 str = wxString((wxWCharBuffer&)tmp_buffer);
1784 delete [] tmp_buffer;
1785 if ( reset ) {
1786 theLogger.CloseLogfile();
1787 if (theLogger.OpenLogfile(ConfigDir + wxT("logfile"))) {
1788 AddLogLineM(false, _("Log has been reset"));
1791 return str;
1795 wxString CamuleApp::GetServerLog(bool reset)
1797 wxString ret = server_msg;
1798 if ( reset ) {
1799 server_msg.Clear();
1801 return ret;
1804 wxString CamuleApp::GetDebugLog(bool reset)
1806 return GetLog(reset);
1810 void CamuleApp::AddServerMessageLine(wxString &msg)
1812 server_msg += msg + wxT("\n");
1813 AddLogLineM(false, CFormat(_("ServerMessage: %s")) % msg);
1818 void CamuleApp::OnFinishedHTTPDownload(CMuleInternalEvent& event)
1820 switch (event.GetInt()) {
1821 case HTTP_IPFilter:
1822 ipfilter->DownloadFinished(event.GetExtraLong());
1823 break;
1824 case HTTP_ServerMet:
1825 serverlist->DownloadFinished(event.GetExtraLong());
1826 break;
1827 case HTTP_ServerMetAuto:
1828 serverlist->AutoDownloadFinished(event.GetExtraLong());
1829 break;
1830 case HTTP_VersionCheck:
1831 CheckNewVersion(event.GetExtraLong());
1832 break;
1833 case HTTP_NodesDat:
1834 if (event.GetExtraLong() != -1) {
1836 wxString file = ConfigDir + wxT("nodes.dat");
1837 if (wxFileExists(file)) {
1838 wxRemoveFile(file);
1841 if ( Kademlia::CKademlia::IsRunning() ) {
1842 Kademlia::CKademlia::Stop();
1845 wxRenameFile(file + wxT(".download"),file);
1847 Kademlia::CKademlia::Start();
1848 theApp->ShowConnectionState();
1850 } else {
1851 AddLogLineM(true, _("Failed to download the nodes list."));
1853 break;
1854 #ifdef ENABLE_IP2COUNTRY
1855 case HTTP_GeoIP:
1856 theApp->amuledlg->IP2CountryDownloadFinished(event.GetExtraLong());
1857 // If we updated, the dialog is already up. Redraw it to show the flags.
1858 theApp->amuledlg->Refresh();
1859 break;
1860 #endif
1864 void CamuleApp::CheckNewVersion(uint32 result)
1866 if (result == 1) {
1867 wxString filename = ConfigDir + wxT("last_version_check");
1868 wxTextFile file;
1870 if (!file.Open(filename)) {
1871 AddLogLineM(true, _("Failed to open the downloaded version check file") );
1872 return;
1873 } else if (!file.GetLineCount()) {
1874 AddLogLineM(true, _("Corrupted version check file"));
1875 } else {
1876 wxString versionLine = file.GetFirstLine();
1877 wxStringTokenizer tkz(versionLine, wxT("."));
1879 AddDebugLogLineM(false, logGeneral, wxString(wxT("Running: ")) + wxT(VERSION) + wxT(", Version check: ") + versionLine);
1881 long fields[] = {0, 0, 0};
1882 for (int i = 0; i < 3; ++i) {
1883 if (!tkz.HasMoreTokens()) {
1884 AddLogLineM(true, _("Corrupted version check file"));
1885 return;
1886 } else {
1887 wxString token = tkz.GetNextToken();
1889 if (!token.ToLong(&fields[i])) {
1890 AddLogLineM(true, _("Corrupted version check file"));
1891 return;
1896 long curVer = make_full_ed2k_version(VERSION_MJR, VERSION_MIN, VERSION_UPDATE);
1897 long newVer = make_full_ed2k_version(fields[0], fields[1], fields[2]);
1899 if (curVer < newVer) {
1900 AddLogLineM(true, _("You are using an outdated version of aMule!"));
1901 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]));
1902 AddLogLineM(false, _("The latest version can always be found at http://www.amule.org"));
1903 #ifdef AMULE_DAEMON
1904 AddLogLineMS(true, CFormat(_("WARNING: Your aMuled version is outdated: %i.%i.%i < %li.%li.%li"))
1905 % VERSION_MJR % VERSION_MIN % VERSION_UPDATE % fields[0] % fields[1] % fields[2]);
1906 #endif
1907 } else {
1908 AddLogLineM(false, _("Your copy of aMule is up to date."));
1912 file.Close();
1913 wxRemoveFile(filename);
1914 } else {
1915 AddLogLineM(true, _("Failed to download the version check file") );
1921 bool CamuleApp::IsConnected() const
1923 return (IsConnectedED2K() || IsConnectedKad());
1927 bool CamuleApp::IsConnectedED2K() const
1929 return serverconnect && serverconnect->IsConnected();
1933 bool CamuleApp::IsConnectedKad() const
1935 return Kademlia::CKademlia::IsConnected();
1939 bool CamuleApp::IsFirewalled() const
1941 if (theApp->IsConnectedED2K() && !theApp->serverconnect->IsLowID()) {
1942 return false; // we have an eD2K HighID -> not firewalled
1945 return IsFirewalledKad(); // If kad says ok, it's ok.
1948 bool CamuleApp::IsFirewalledKad() const
1950 return !Kademlia::CKademlia::IsConnected() // not connected counts as firewalled
1951 || Kademlia::CKademlia::IsFirewalled();
1954 bool CamuleApp::IsFirewalledKadUDP() const
1956 return !Kademlia::CKademlia::IsConnected() // not connected counts as firewalled
1957 || Kademlia::CUDPFirewallTester::IsFirewalledUDP(true);
1960 bool CamuleApp::IsKadRunning() const
1962 return Kademlia::CKademlia::IsRunning();
1965 // Kad stats
1966 uint32 CamuleApp::GetKadUsers() const
1968 return Kademlia::CKademlia::GetKademliaUsers();
1971 uint32 CamuleApp::GetKadFiles() const
1973 return Kademlia::CKademlia::GetKademliaFiles();
1976 uint32 CamuleApp::GetKadIndexedSources() const
1978 return Kademlia::CKademlia::GetIndexed()->m_totalIndexSource;
1981 uint32 CamuleApp::GetKadIndexedKeywords() const
1983 return Kademlia::CKademlia::GetIndexed()->m_totalIndexKeyword;
1986 uint32 CamuleApp::GetKadIndexedNotes() const
1988 return Kademlia::CKademlia::GetIndexed()->m_totalIndexNotes;
1991 uint32 CamuleApp::GetKadIndexedLoad() const
1993 return Kademlia::CKademlia::GetIndexed()->m_totalIndexLoad;
1997 // True IP of machine
1998 uint32 CamuleApp::GetKadIPAdress() const
2000 return wxUINT32_SWAP_ALWAYS(Kademlia::CKademlia::GetPrefs()->GetIPAddress());
2003 // Buddy status
2004 uint8 CamuleApp::GetBuddyStatus() const
2006 return clientlist->GetBuddyStatus();
2009 uint32 CamuleApp::GetBuddyIP() const
2011 return clientlist->GetBuddy()->GetIP();
2014 uint32 CamuleApp::GetBuddyPort() const
2016 return clientlist->GetBuddy()->GetUDPPort();
2019 bool CamuleApp::DoCallback( CUpDownClient *client )
2021 if(Kademlia::CKademlia::IsConnected()) {
2022 if(IsConnectedED2K()) {
2023 if(serverconnect->IsLowID()) {
2024 if(Kademlia::CKademlia::IsFirewalled()) {
2025 //Both Connected - Both Firewalled
2026 return false;
2027 } else {
2028 if(client->GetServerIP() == theApp->serverconnect->GetCurrentServer()->GetIP() &&
2029 client->GetServerPort() == theApp->serverconnect->GetCurrentServer()->GetPort()) {
2030 // Both Connected - Server lowID, Kad Open - Client on same server
2031 // We prevent a callback to the server as this breaks the protocol
2032 // and will get you banned.
2033 return false;
2034 } else {
2035 // Both Connected - Server lowID, Kad Open - Client on remote server
2036 return true;
2039 } else {
2040 //Both Connected - Server HighID, Kad don't care
2041 return true;
2043 } else {
2044 if(Kademlia::CKademlia::IsFirewalled()) {
2045 //Only Kad Connected - Kad Firewalled
2046 return false;
2047 } else {
2048 //Only Kad Conected - Kad Open
2049 return true;
2052 } else {
2053 if( IsConnectedED2K() ) {
2054 if( serverconnect->IsLowID() ) {
2055 //Only Server Connected - Server LowID
2056 return false;
2057 } else {
2058 //Only Server Connected - Server HighID
2059 return true;
2061 } else {
2062 //We are not connected at all!
2063 return false;
2068 void CamuleApp::ShowUserCount() {
2069 uint32 totaluser = 0, totalfile = 0;
2071 theApp->serverlist->GetUserFileStatus( totaluser, totalfile );
2073 wxString buffer;
2075 static const wxString s_singlenetstatusformat = _("Users: %s | Files: %s");
2076 static const wxString s_bothnetstatusformat = _("Users: E: %s K: %s | Files: E: %s K: %s");
2078 if (thePrefs::GetNetworkED2K() && thePrefs::GetNetworkKademlia()) {
2079 buffer = CFormat(s_bothnetstatusformat) % CastItoIShort(totaluser) % CastItoIShort(Kademlia::CKademlia::GetKademliaUsers()) % CastItoIShort(totalfile) % CastItoIShort(Kademlia::CKademlia::GetKademliaFiles());
2080 } else if (thePrefs::GetNetworkED2K()) {
2081 buffer = CFormat(s_singlenetstatusformat) % CastItoIShort(totaluser) % CastItoIShort(totalfile);
2082 } else if (thePrefs::GetNetworkKademlia()) {
2083 buffer = CFormat(s_singlenetstatusformat) % CastItoIShort(Kademlia::CKademlia::GetKademliaUsers()) % CastItoIShort(Kademlia::CKademlia::GetKademliaFiles());
2084 } else {
2085 buffer = _("No networks selected");
2088 Notify_ShowUserCount(buffer);
2092 void CamuleApp::ListenSocketHandler(wxSocketEvent& event)
2094 wxCHECK_RET(listensocket, wxT("Connection-event for NULL'd listen-socket"));
2095 wxCHECK_RET(event.GetSocketEvent() == wxSOCKET_CONNECTION,
2096 wxT("Invalid event received for listen-socket"));
2098 if (m_app_state == APP_STATE_RUNNING) {
2099 listensocket->OnAccept(0);
2100 } else if (m_app_state == APP_STATE_STARTING) {
2101 // When starting up, connection may be made before we are able
2102 // to handle them. However, if these are ignored, no futher
2103 // connection-events will be triggered, so we have to accept it.
2104 wxSocketBase* socket = listensocket->Accept(false);
2106 wxCHECK_RET(socket, wxT("NULL returned by Accept() during startup"));
2108 socket->Destroy();
2113 void CamuleApp::ShowConnectionState()
2115 static uint8 old_state = (1<<7); // This flag doesn't exist
2117 uint8 state = 0;
2119 if (theApp->serverconnect->IsConnected()) {
2120 state |= CONNECTED_ED2K;
2123 if (Kademlia::CKademlia::IsRunning()) {
2124 if (Kademlia::CKademlia::IsConnected()) {
2125 if (!Kademlia::CKademlia::IsFirewalled()) {
2126 state |= CONNECTED_KAD_OK;
2127 } else {
2128 state |= CONNECTED_KAD_FIREWALLED;
2130 } else {
2131 state |= CONNECTED_KAD_NOT;
2135 Notify_ShowConnState(state);
2137 if (old_state != state) {
2138 // Get the changed value
2139 int changed_flags = old_state ^ state;
2141 if (changed_flags & CONNECTED_ED2K) {
2142 // ED2K status changed
2143 wxString connected_server;
2144 CServer* ed2k_server = theApp->serverconnect->GetCurrentServer();
2145 if (ed2k_server) {
2146 connected_server = ed2k_server->GetListName();
2148 if (state & CONNECTED_ED2K) {
2149 // We connected to some server
2150 const wxString id = theApp->serverconnect->IsLowID() ? _("with LowID") : _("with HighID");
2152 AddLogLineM(true, CFormat(_("Connected to %s %s")) % connected_server % id);
2153 } else {
2154 if ( theApp->serverconnect->IsConnecting() ) {
2155 AddLogLineM(true, CFormat(_("Connecting to %s")) % connected_server);
2156 } else {
2157 AddLogLineM(true, _("Disconnected from eD2k"));
2162 if (changed_flags & CONNECTED_KAD_NOT) {
2163 if (state & CONNECTED_KAD_NOT) {
2164 AddLogLineM(true, _("Kad started."));
2165 } else {
2166 AddLogLineM(true, _("Kad stopped."));
2170 if (changed_flags & (CONNECTED_KAD_OK | CONNECTED_KAD_FIREWALLED)) {
2171 if (state & (CONNECTED_KAD_OK | CONNECTED_KAD_FIREWALLED)) {
2172 if (state & CONNECTED_KAD_OK) {
2173 AddLogLineM(true, _("Connected to Kad (ok)"));
2174 } else {
2175 AddLogLineM(true, _("Connected to Kad (firewalled)"));
2177 } else {
2178 AddLogLineM(true, _("Disconnected from Kad"));
2182 old_state = state;
2184 theApp->downloadqueue->OnConnectionState(IsConnected());
2187 ShowUserCount();
2188 Notify_ShowConnState(state);
2192 void CamuleApp::UDPSocketHandler(wxSocketEvent& event)
2194 CMuleUDPSocket* socket = (CMuleUDPSocket*)(event.GetClientData());
2195 wxCHECK_RET(socket, wxT("No socket owner specified."));
2197 if (IsOnShutDown() || thePrefs::IsUDPDisabled()) return;
2199 if (!IsRunning()) {
2200 if (event.GetSocketEvent() == wxSOCKET_INPUT) {
2201 // Back to the queue!
2202 theApp->AddPendingEvent(event);
2203 return;
2207 switch (event.GetSocketEvent()) {
2208 case wxSOCKET_INPUT:
2209 socket->OnReceive(0);
2210 break;
2212 case wxSOCKET_OUTPUT:
2213 socket->OnSend(0);
2214 break;
2216 case wxSOCKET_LOST:
2217 socket->OnDisconnected(0);
2218 break;
2220 default:
2221 wxFAIL;
2222 break;
2227 void CamuleApp::OnUnhandledException()
2229 // Call the generic exception-handler.
2230 fprintf(stderr, "\taMule Version: %s\n", (const char*)unicode2char(GetFullMuleVersion()));
2231 ::OnUnhandledException();
2234 void CamuleApp::StartKad()
2236 if (!Kademlia::CKademlia::IsRunning() && thePrefs::GetNetworkKademlia()) {
2237 // Kad makes no sense without the Client-UDP socket.
2238 if (!thePrefs::IsUDPDisabled()) {
2239 Kademlia::CKademlia::Start();
2240 } else {
2241 AddLogLineM(true,_("Kad network cannot be used if UDP port is disabled on preferences, not starting."));
2243 } else if (!thePrefs::GetNetworkKademlia()) {
2244 AddLogLineM(true,_("Kad network disabled on preferences, not connecting."));
2248 void CamuleApp::StopKad()
2250 // Stop Kad if it's running
2251 if (Kademlia::CKademlia::IsRunning()) {
2252 Kademlia::CKademlia::Stop();
2257 void CamuleApp::BootstrapKad(uint32 ip, uint16 port)
2259 if (!Kademlia::CKademlia::IsRunning()) {
2260 Kademlia::CKademlia::Start();
2261 theApp->ShowConnectionState();
2264 Kademlia::CKademlia::Bootstrap(ip, port, true);
2268 void CamuleApp::UpdateNotesDat(const wxString& url)
2270 wxString strTempFilename(theApp->ConfigDir + wxT("nodes.dat.download"));
2272 CHTTPDownloadThread *downloader = new CHTTPDownloadThread(url, strTempFilename, HTTP_NodesDat);
2273 downloader->Create();
2274 downloader->Run();
2278 void CamuleApp::DisconnectED2K()
2280 // Stop ED2K if it's running
2281 if (IsConnectedED2K()) {
2282 serverconnect->Disconnect();
2286 bool CamuleApp::CryptoAvailable() const
2288 return clientcredits && clientcredits->CryptoAvailable();
2291 uint32 CamuleApp::GetED2KID() const {
2292 return serverconnect ? serverconnect->GetClientID() : 0;
2295 uint32 CamuleApp::GetID() const {
2296 uint32 ID;
2298 if( Kademlia::CKademlia::IsConnected() && !Kademlia::CKademlia::IsFirewalled() ) {
2299 // We trust Kad above ED2K
2300 ID = ENDIAN_NTOHL(Kademlia::CKademlia::GetIPAddress());
2301 } else if( theApp->serverconnect->IsConnected() ) {
2302 ID = theApp->serverconnect->GetClientID();
2303 } else if ( Kademlia::CKademlia::IsConnected() && Kademlia::CKademlia::IsFirewalled() ) {
2304 // A firewalled Kad client get's a "1"
2305 ID = 1;
2306 } else {
2307 ID = 0;
2310 return ID;
2313 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_FINISHED_HTTP_DOWNLOAD)
2314 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_SOURCE_DNS_DONE)
2315 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_UDP_DNS_DONE)
2316 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_SERVER_DNS_DONE)
2317 // File_checked_for_headers