Upstream tarball 9584
[amule.git] / src / amule.cpp
blob6566fcb8ee305b262e9311dcd1efc04878c88390
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 // Handle sigint and sigterm
412 signal(SIGINT, OnShutdownSignal);
413 signal(SIGTERM, OnShutdownSignal);
414 #endif
416 #ifdef __WXMAC__
417 // For listctrl's to behave on Mac
418 wxSystemOptions::SetOption(wxT("mac.listctrl.always_use_generic"), 1);
419 #endif
421 // This can't be on constructor or wx2.4.2 doesn't set it.
422 #if !wxCHECK_VERSION(2, 9, 0)
423 SetVendorName(wxT("TikuWarez"));
424 #endif
425 SetAppName(wxT("aMule"));
427 wxString FullMuleVersion = GetFullMuleVersion();
428 wxString OSDescription = wxGetOsDescription();
429 strFullMuleVersion = strdup((const char *)unicode2char(FullMuleVersion));
430 strOSDescription = strdup((const char *)unicode2char(OSDescription));
431 OSType = OSDescription.BeforeFirst( wxT(' ') );
432 if ( OSType.IsEmpty() ) {
433 OSType = wxT("Unknown");
436 // Handle uncaught exceptions
437 InstallMuleExceptionHandler();
439 // Parse cmdline arguments.
440 wxCmdLineParser cmdline(AMULE_APP_BASE::argc, AMULE_APP_BASE::argv);
442 // Handle these arguments.
443 cmdline.AddSwitch(wxT("v"), wxT("version"), wxT("Displays the current version number."));
444 cmdline.AddSwitch(wxT("h"), wxT("help"), wxT("Displays this information."));
445 cmdline.AddSwitch(wxT("i"), wxT("enable-stdin"), wxT("Does not disable stdin."));
446 #ifdef AMULE_DAEMON
447 cmdline.AddSwitch(wxT("f"), wxT("full-daemon"), wxT("Fork to background."));
448 cmdline.AddOption(wxT("p"), wxT("pid-file"), wxT("After fork, create a pid-file in the given fullname file."));
449 cmdline.AddOption(wxT("c"), wxT("config-dir"), wxT("read config from <dir> instead of home"));
450 cmdline.AddSwitch(wxT("e"), wxT("ec-config"), wxT("Configure EC (External Connections)."));
451 #else
452 cmdline.AddOption(wxT("geometry"), wxEmptyString,
453 wxT("Sets the geometry of the app.\n")
454 wxT("\t\t\t<str> uses the same format as standard X11 apps:\n")
455 wxT("\t\t\t[=][<width>{xX}<height>][{+-}<xoffset>{+-}<yoffset>]"));
456 #endif
457 cmdline.AddSwitch(wxT("d"), wxT("disable-fatal"), wxT("Does not handle fatal exception."));
458 cmdline.AddSwitch(wxT("o"), wxT("log-stdout"), wxT("Print log messages to stdout."));
459 cmdline.AddSwitch(wxT("r"), wxT("reset-config"), wxT("Resets config to default values."));
460 #ifndef __WXMSW__
461 // Change webserver path, not available on Windows
462 cmdline.AddOption(wxT("w"), wxT("use-amuleweb"), wxT("Specify location of amuleweb binary."));
463 #endif
465 // Show help on --help or invalid commands
466 if ( cmdline.Parse() ) {
467 return false;
468 } else if ( cmdline.Found(wxT("help")) ) {
469 cmdline.Usage();
470 return false;
473 bool ec_config = false;
475 #ifdef AMULE_DAEMON
476 ec_config = cmdline.Found(wxT("ec-config"));
477 if ( cmdline.Found(wxT("config-dir"), &ConfigDir) ) {
478 if (ConfigDir.Last() != wxFileName::GetPathSeparator()) {
479 ConfigDir += wxFileName::GetPathSeparator();
481 } else {
482 ConfigDir = GetConfigDir();
484 #else
485 ConfigDir = GetConfigDir();
486 #endif
488 if ( !cmdline.Found(wxT("disable-fatal")) ) {
489 #ifndef __WXMSW__
490 // catch fatal exceptions
491 wxHandleFatalExceptions(true);
492 #endif
495 bool reset_config = cmdline.Found(wxT("reset-config"));
497 theLogger.SetEnabledStdoutLog(cmdline.Found(wxT("log-stdout")));
498 #ifdef AMULE_DAEMON
499 enable_daemon_fork = cmdline.Found(wxT("full-daemon"));
500 if ( cmdline.Found(wxT("pid-file"), &PidFile) ) {
501 // Remove any existing PidFile
502 if ( wxFileExists (PidFile) ) wxRemoveFile (PidFile);
504 #else
505 enable_daemon_fork = false;
506 PidFile.Clear();
507 #endif
509 if (theLogger.IsEnabledStdoutLog()) {
510 if ( enable_daemon_fork ) {
511 AddLogLineMS(false, wxT("Daemon will fork to background - log to stdout disabled"));
512 theLogger.SetEnabledStdoutLog(false);
513 } else {
514 AddLogLineMS(false, wxT("Logging to stdout enabled"));
518 if ( cmdline.Found(wxT("version")) ) {
519 AddLogLineMS(false, CFormat(wxT("%s (OS: %s)")) % FullMuleVersion % OSType);
521 return false;
524 // Default geometry of the GUI. Can be changed with a cmdline argument...
525 bool geometry_enabled = false;
526 wxString geom_string;
527 #ifndef AMULE_DAEMON
528 if ( cmdline.Found(wxT("geometry"), &geom_string) ) {
529 geometry_enabled = true;
531 #endif
533 AddLogLineMS(false, wxT("Initialising ") + FullMuleVersion);
535 // Ensure that "~/.aMule/" is accessible.
536 if (!CheckMuleDirectory(wxT("configuration"), CPath(ConfigDir), wxEmptyString).first) {
537 return false;
540 if (reset_config) {
541 // Make a backup first.
542 wxRemoveFile(ConfigDir + wxT("amule.conf.backup"));
543 wxRenameFile(ConfigDir + wxT("amule.conf"), ConfigDir + wxT("amule.conf.backup"));
544 AddLogLineMS(false, wxT("Your settings have ben resetted to default values.\nOld config file has been saved as amule.conf.backup\n"));
547 #if defined(__WXMAC__) && defined(AMULE_DAEMON)
548 //#warning TODO: fix wxSingleInstanceChecker for amuled on Mac (wx link problems)
549 AddLogLineMS(true, wxT("WARNING: The check for other instances is currently disabled in amuled.\n"
550 "Please make sure that no other instance of aMule is running or your files might be corrupted.\n"));
551 #else
552 AddLogLineMS(false, wxT("Checking if there is an instance already running..."));
554 m_singleInstance = new wxSingleInstanceChecker();
555 if (m_singleInstance->Create(wxT("muleLock"), ConfigDir)
556 && m_singleInstance->IsAnotherRunning()) {
557 AddLogLineMS(true, wxT("There is an instance of aMule already running"));
558 AddLogLineNS(CFormat(wxT("(lock file: %s%s)")) % ConfigDir % wxT("muleLock"));
560 // This is very tricky. The most secure way to communicate is via ED2K links file
561 wxTextFile ed2kFile(ConfigDir + wxT("ED2KLinks"));
562 if (!ed2kFile.Exists()) {
563 ed2kFile.Create();
566 if (ed2kFile.Open()) {
567 ed2kFile.AddLine(wxT("RAISE_DIALOG"));
568 ed2kFile.Write();
570 AddLogLineMS(false, wxT("Raising current running instance."));
571 } else {
572 AddLogLineMS(true, wxT("Failed to open 'ED2KFile', cannot signal running instance."));
575 return false;
576 } else {
577 AddLogLineMS(false, wxT("No other instances are running."));
579 #endif
581 // Close standard-input
582 if ( !cmdline.Found(wxT("enable-stdin")) ) {
583 // The full daemon will close all std file-descriptors by itself,
584 // so closing it here would lead to the closing on the first open
585 // file, which is the logfile opened below
586 if (!enable_daemon_fork) {
587 close(0);
591 // This creates the CFG file we shall use
592 wxConfigBase* cfg = new wxFileConfig( wxEmptyString, wxEmptyString, ConfigDir + wxT("amule.conf") );
594 // Set the config object as the global cfg file
595 wxConfig::Set( cfg );
597 // Make a backup of the log file
598 CPath logfileName = CPath(ConfigDir + wxT("logfile"));
599 if (logfileName.FileExists()) {
600 CPath::BackupFile(logfileName, wxT(".bak"));
603 // Open the log file
604 if (!theLogger.OpenLogfile(logfileName.GetRaw())) {
605 // use std err as last resolt to indicate problem
606 fputs("ERROR: unable to open log file\n", stderr);
607 // failure to open log is serious problem
608 return false;
611 // Load Preferences
612 CPreferences::BuildItemList(ConfigDir);
613 CPreferences::LoadAllItems( wxConfigBase::Get() );
615 glob_prefs = new CPreferences();
617 std::pair<bool, CPath> checkResult;
618 checkResult = CheckMuleDirectory(wxT("temp"), thePrefs::GetTempDir(), ConfigDir + wxT("Temp"));
619 if (checkResult.first) {
620 thePrefs::SetTempDir(checkResult.second);
621 } else {
622 return false;
625 checkResult = CheckMuleDirectory(wxT("incoming"), thePrefs::GetIncomingDir(), ConfigDir + wxT("Incoming"));
626 if (checkResult.first) {
627 thePrefs::SetIncomingDir(checkResult.second);
628 } else {
629 return false;
632 // Some sanity check
633 if (!thePrefs::UseTrayIcon()) {
634 thePrefs::SetMinToTray(false);
637 // Build the filenames for the two OS files
638 SetOSFiles(thePrefs::GetOSDir().GetRaw());
640 #ifdef ENABLE_NLS
641 // Load localization settings
642 Localize_mule();
643 #endif
645 // Configure EC for amuled when invoked with ec-config
646 if (ec_config) {
647 AddLogLineMS(false, _("\nEC configuration"));
648 thePrefs::SetECPass(GetPassword());
649 thePrefs::EnableExternalConnections(true);
650 AddLogLineMS(false, _("Password set and external connections enabled."));
653 #ifndef __WXMSW__
654 if (getuid() == 0) {
655 wxString msg =
656 wxT("Warning! You are running aMule as root.\n")
657 wxT("Doing so is not recommended for security reasons,\n")
658 wxT("and you are advised to run aMule as an normal\n")
659 wxT("user instead.");
661 ShowAlert(msg, _("WARNING"), wxCENTRE | wxOK | wxICON_ERROR);
663 fprintf(stderr, "\n--------------------------------------------------\n");
664 fprintf(stderr, "%s", (const char*)unicode2UTF8(msg));
665 fprintf(stderr, "\n--------------------------------------------------\n\n");
667 #endif
669 // Display notification on new version or first run
670 wxTextFile vfile( ConfigDir + wxT("lastversion") );
671 wxString newMule(wxT( VERSION ));
673 if ( !wxFileExists( vfile.GetName() ) ) {
674 vfile.Create();
677 if ( vfile.Open() ) {
678 // Check if this version has been run before
679 bool found = false;
680 for ( size_t i = 0; i < vfile.GetLineCount(); i++ ) {
681 // Check if this version has been run before
682 if ( vfile.GetLine(i) == newMule ) {
683 found = true;
684 break;
688 // We havent run this version before?
689 if ( !found ) {
690 // Insert new at top to provide faster searches
691 vfile.InsertLine( newMule, 0 );
693 Trigger_New_version( newMule );
696 // Keep at most 10 entires
697 while ( vfile.GetLineCount() > 10 )
698 vfile.RemoveLine( vfile.GetLineCount() - 1 );
700 vfile.Write();
701 vfile.Close();
704 // Check if we have the old style locale config
705 wxString langId = thePrefs::GetLanguageID();
706 if (!langId.IsEmpty() && (langId.GetChar(0) >= '0' && langId.GetChar(0) <= '9')) {
707 wxString info(_("Your locale has been changed to System Default due to a configuration change. Sorry."));
708 thePrefs::SetLanguageID(wxLang2Str(wxLANGUAGE_DEFAULT));
709 ShowAlert(info, _("Info"), wxCENTRE | wxOK | wxICON_ERROR);
712 m_statistics = new CStatistics();
714 clientlist = new CClientList();
715 friendlist = new CFriendList();
716 searchlist = new CSearchList();
717 knownfiles = new CKnownFileList();
718 serverlist = new CServerList();
720 sharedfiles = new CSharedFileList(knownfiles);
721 clientcredits = new CClientCreditsList();
723 // bugfix - do this before creating the uploadqueue
724 downloadqueue = new CDownloadQueue();
725 uploadqueue = new CUploadQueue();
726 ipfilter = new CIPFilter();
728 // Creates all needed listening sockets
729 wxString msg;
730 if (!ReinitializeNetwork(&msg)) {
731 AddLogLineMS(false, wxT("\n"));
732 AddLogLineMS(false, msg);
735 // Test if there's any new version
736 if (thePrefs::CheckNewVersion()) {
737 // We use the thread base because I don't want a dialog to pop up.
738 CHTTPDownloadThread* version_check =
739 new CHTTPDownloadThread(wxT("http://amule.sourceforge.net/lastversion"),
740 theApp->ConfigDir + wxT("last_version_check"), HTTP_VersionCheck, false);
741 version_check->Create();
742 version_check->Run();
745 // Create main dialog, or fork to background (daemon).
746 InitGui(geometry_enabled, geom_string);
748 #if !defined(__WXMAC__) && defined(AMULE_DAEMON)
749 // Need to refresh wxSingleInstanceChecker after the daemon fork() !
750 if (enable_daemon_fork) {
751 //#warning TODO: fix wxSingleInstanceChecker for amuled on Mac (wx link problems)
752 delete m_singleInstance;
753 m_singleInstance = new wxSingleInstanceChecker(wxT("muleLock"), ConfigDir);
754 // No need to check IsAnotherRunning() - we've done it before.
756 #endif
758 // Has to be created after the call to InitGui, as fork
759 // (when using posix threads) only replicates the mainthread,
760 // and the UBT constructor creates a thread.
761 uploadBandwidthThrottler = new UploadBandwidthThrottler();
763 // These must be initialized after the gui is loaded.
764 serverlist->Init();
765 downloadqueue->LoadMetFiles(thePrefs::GetTempDir());
766 sharedfiles->Reload();
768 if (thePrefs::IPFilterAutoLoad()) {
769 ipfilter->Update(thePrefs::IPFilterURL());
773 // Ensure that the up/down ratio is used
774 CPreferences::CheckUlDlRatio();
776 // The user can start pressing buttons like mad if he feels like it.
777 m_app_state = APP_STATE_RUNNING;
779 // Kry - Load the sources seeds on app init
780 if (thePrefs::GetSrcSeedsOn()) {
781 downloadqueue->LoadSourceSeeds();
784 if (!serverlist->GetServerCount() && thePrefs::GetNetworkED2K()) {
785 // There are no servers and ED2K active -> ask for download.
786 // As we cannot ask in amuled, we just update there
787 // Kry TODO: Store server.met URL on preferences and use it here and in GUI.
788 #ifndef AMULE_DAEMON
789 if (wxYES == wxMessageBox(
790 wxString(
791 _("You don't have any server in the server list.\nDo you want aMule to download a new list now?")),
792 wxString(_("Server list download")),
793 wxYES_NO,
794 static_cast<wxWindow*>(theApp->amuledlg)))
795 #endif
797 // workaround amuled crash
798 #ifndef AMULE_DAEMON
799 serverlist->UpdateServerMetFromURL(
800 wxT("http://gruk.org/server.met.gz"));
801 #endif
806 // Autoconnect if that option is enabled
807 if (thePrefs::DoAutoConnect() && (thePrefs::GetNetworkED2K() || thePrefs::GetNetworkKademlia())) {
808 AddLogLineM(true, _("Connecting"));
809 if (thePrefs::GetNetworkED2K()) {
810 theApp->serverconnect->ConnectToAnyServer();
813 StartKad();
817 // Enable GeoIP
818 #ifdef ENABLE_IP2COUNTRY
819 theApp->amuledlg->EnableIP2Country();
820 #endif
822 // No webserver on Win at all (yet)
823 #ifndef __WXMSW__
824 // Run webserver?
825 if (thePrefs::GetWSIsEnabled()) {
826 wxString aMuleConfigFile = ConfigDir + wxT("amule.conf");
827 wxString amulewebPath = wxT("amuleweb");
828 if(true == cmdline.Found(wxT("use-amuleweb"), &amulewebPath)) {
829 AddLogLineNS(CFormat(_("Using amuleweb in '%s'.")) % amulewebPath);
832 #if defined(__WXMAC__) && !defined(AMULE_DAEMON)
833 // For the Mac GUI application, look for amuleweb in the bundle
834 CFURLRef amulewebUrl = CFBundleCopyAuxiliaryExecutableURL(
835 CFBundleGetMainBundle(), CFSTR("amuleweb"));
837 if (amulewebUrl) {
838 CFURLRef absoluteUrl = CFURLCopyAbsoluteURL(amulewebUrl);
839 CFRelease(amulewebUrl);
841 if (absoluteUrl) {
842 CFStringRef amulewebCfstr = CFURLCopyFileSystemPath(absoluteUrl, kCFURLPOSIXPathStyle);
843 CFRelease(absoluteUrl);
844 amulewebPath = wxMacCFStringHolder(amulewebCfstr).AsString(wxLocale::GetSystemEncoding());
847 #endif
849 wxString cmd =
850 wxT("'") +
851 amulewebPath +
852 wxT("' '--amule-config-file=") +
853 aMuleConfigFile +
854 wxT("'");
855 CTerminationProcessAmuleweb *p = new CTerminationProcessAmuleweb(cmd, &webserver_pid);
856 webserver_pid = wxExecute(cmd, wxEXEC_ASYNC, p);
857 bool webserver_ok = webserver_pid > 0;
858 if (webserver_ok) {
859 AddLogLineM(true, CFormat(_("web server running on pid %d")) % webserver_pid);
860 } else {
861 delete p;
862 ShowAlert(_(
863 "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"),
864 _("ERROR"), wxOK | wxICON_ERROR);
867 #endif /* ! __WXMSW__ */
869 // Start performing background tasks
870 CThreadScheduler::Start();
872 return true;
875 bool CamuleApp::ReinitializeNetwork(wxString* msg)
877 bool ok = true;
878 static bool firstTime = true;
880 if (!firstTime) {
881 // TODO: Destroy previously created sockets
883 firstTime = false;
885 // Some sanity checks first
886 if (thePrefs::ECPort() == thePrefs::GetPort()) {
887 // Select a random usable port in the range 1025 ... 2^16 - 1
888 uint16 port = thePrefs::ECPort();
889 while ( port < 1024 || port == thePrefs::GetPort() ) {
890 port = (uint16)rand();
892 thePrefs::SetECPort( port );
894 wxString err =
895 wxT("Network configuration failed! You cannot use the same port\n")
896 wxT("for the main TCP port and the External Connections port.\n")
897 wxT("The EC port has been changed to avoid conflict, see the\n")
898 wxT("preferences for the new value.\n");
899 *msg << err;
901 AddLogLineM( false, wxEmptyString );
902 AddLogLineM( true, err );
903 AddLogLineM( false, wxEmptyString );
905 ok = false;
908 if (thePrefs::GetUDPPort() == thePrefs::GetPort() + 3) {
909 // Select a random usable value in the range 1025 ... 2^16 - 1
910 uint16 port = thePrefs::GetUDPPort();
911 while ( port < 1024 || port == thePrefs::GetPort() + 3 ) {
912 port = (uint16)rand();
914 thePrefs::SetUDPPort( port );
916 wxString err =
917 wxT("Network configuration failed! You set your UDP port to\n")
918 wxT("the value of the main TCP port plus 3.\n")
919 wxT("This port has been reserved for the Server-UDP port. The\n")
920 wxT("port value has been changed to avoid conflict, see the\n")
921 wxT("preferences for the new value\n");
922 *msg << err;
924 AddLogLineM( false, wxEmptyString );
925 AddLogLineM( true, err );
926 AddLogLineM( false, wxEmptyString );
928 ok = false;
931 // Create the address where we are going to listen
932 // TODO: read this from configuration file
933 amuleIPV4Address myaddr[4];
935 // Create the External Connections Socket.
936 // Default is 4712.
937 // Get ready to handle connections from apps like amulecmd
938 if (thePrefs::GetECAddress().IsEmpty() || !myaddr[0].Hostname(thePrefs::GetECAddress())) {
939 myaddr[0].AnyAddress();
941 myaddr[0].Service(thePrefs::ECPort());
942 ECServerHandler = new ExternalConn(myaddr[0], msg);
944 // Create the UDP socket TCP+3.
945 // Used for source asking on servers.
946 if (thePrefs::GetAddress().IsEmpty()) {
947 myaddr[1].AnyAddress();
948 } else if (!myaddr[1].Hostname(thePrefs::GetAddress())) {
949 myaddr[1].AnyAddress();
950 AddLogLineM(true, CFormat(_("Could not bind ports to the specified address: %s"))
951 % thePrefs::GetAddress());
954 wxString ip = myaddr[1].IPAddress();
955 myaddr[1].Service(thePrefs::GetPort()+3);
956 serverconnect = new CServerConnect(serverlist, myaddr[1]);
957 *msg << CFormat( wxT("*** Server UDP socket (TCP+3) at %s:%u\n") )
958 % ip % ((unsigned int)thePrefs::GetPort() + 3u);
960 // Create the ListenSocket (aMule TCP socket).
961 // Used for Client Port / Connections from other clients,
962 // Client to Client Source Exchange.
963 // Default is 4662.
964 myaddr[2] = myaddr[1];
965 myaddr[2].Service(thePrefs::GetPort());
966 listensocket = new CListenSocket(myaddr[2]);
967 *msg << CFormat( wxT("*** TCP socket (TCP) listening on %s:%u\n") )
968 % ip % (unsigned int)(thePrefs::GetPort());
969 // This command just sets a flag to control maximum number of connections.
970 // Notify(true) has already been called to the ListenSocket, so events may
971 // be already comming in.
972 if (listensocket->Ok()) {
973 listensocket->StartListening();
974 } else {
975 // If we wern't able to start listening, we need to warn the user
976 wxString err;
977 err = CFormat(_("Port %u is not available. You will be LOWID\n")) %
978 (unsigned int)(thePrefs::GetPort());
979 *msg << err;
980 AddLogLineM(true, err);
981 err.Clear();
982 err = CFormat(
983 _("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.")) %
984 (unsigned int)(thePrefs::GetPort());
985 ShowAlert(err, _("ERROR"), wxOK | wxICON_ERROR);
988 // Create the UDP socket.
989 // Used for extended eMule protocol, Queue Rating, File Reask Ping.
990 // Also used for Kademlia.
991 // Default is port 4672.
992 myaddr[3] = myaddr[1];
993 myaddr[3].Service(thePrefs::GetUDPPort());
994 clientudp = new CClientUDPSocket(myaddr[3], thePrefs::GetProxyData());
995 if (!thePrefs::IsUDPDisabled()) {
996 *msg << CFormat( wxT("*** Client UDP socket (extended eMule) at %s:%u") )
997 % ip % thePrefs::GetUDPPort();
998 } else {
999 *msg << wxT("*** Client UDP socket (extended eMule) disabled on preferences");
1002 #ifdef ENABLE_UPNP
1003 if (thePrefs::GetUPnPEnabled()) {
1004 try {
1005 m_upnpMappings[0] = CUPnPPortMapping(
1006 myaddr[0].Service(),
1007 "TCP",
1008 thePrefs::GetUPnPECEnabled(),
1009 "aMule TCP External Connections Socket");
1010 m_upnpMappings[1] = CUPnPPortMapping(
1011 myaddr[1].Service(),
1012 "UDP",
1013 thePrefs::GetUPnPEnabled(),
1014 "aMule UDP socket (TCP+3)");
1015 m_upnpMappings[2] = CUPnPPortMapping(
1016 myaddr[2].Service(),
1017 "TCP",
1018 thePrefs::GetUPnPEnabled(),
1019 "aMule TCP Listen Socket");
1020 m_upnpMappings[3] = CUPnPPortMapping(
1021 myaddr[3].Service(),
1022 "UDP",
1023 thePrefs::GetUPnPEnabled(),
1024 "aMule UDP Extended eMule Socket");
1025 m_upnp = new CUPnPControlPoint(thePrefs::GetUPnPTCPPort());
1026 m_upnp->AddPortMappings(m_upnpMappings);
1027 } catch(CUPnPException &e) {
1028 wxString error_msg;
1029 error_msg << e.what();
1030 AddLogLineM(true, error_msg);
1031 fprintf(stderr, "%s\n", (const char *)unicode2char(error_msg));
1034 #endif
1036 return ok;
1039 // Returns a magnet ed2k URI
1040 wxString CamuleApp::CreateMagnetLink(const CAbstractFile *f)
1042 CMagnetURI uri;
1044 uri.AddField(wxT("dn"), f->GetFileName().Cleanup(false).GetPrintable());
1045 uri.AddField(wxT("xt"), wxString(wxT("urn:ed2k:")) + f->GetFileHash().Encode().Lower());
1046 uri.AddField(wxT("xt"), wxString(wxT("urn:ed2khash:")) + f->GetFileHash().Encode().Lower());
1047 uri.AddField(wxT("xl"), wxString::Format(wxT("%") wxLongLongFmtSpec wxT("u"), f->GetFileSize()));
1049 return uri.GetLink();
1052 // Returns a ed2k file URL
1053 wxString CamuleApp::CreateED2kLink(const CAbstractFile *f, bool add_source, bool use_hostname, bool addcryptoptions)
1055 wxASSERT(!(!add_source && (use_hostname || addcryptoptions)));
1056 // Construct URL like this: ed2k://|file|<filename>|<size>|<hash>|/
1057 wxString strURL = CFormat(wxT("ed2k://|file|%s|%i|%s|/"))
1058 % f->GetFileName().Cleanup(false)
1059 % f->GetFileSize() % f->GetFileHash().Encode();
1061 if (add_source && IsConnected() && !IsFirewalled()) {
1062 // Create the first part of the URL
1063 strURL << wxT("|sources,");
1064 if (use_hostname) {
1065 strURL << thePrefs::GetYourHostname();
1066 } else {
1067 uint32 clientID = GetID();
1068 strURL << (uint8) clientID << wxT(".") <<
1069 (uint8)(clientID >> 8) << wxT(".") <<
1070 (uint8)(clientID >> 16) << wxT(".") <<
1071 (uint8)(clientID >> 24);
1074 strURL << wxT(":") <<
1075 thePrefs::GetPort();
1077 if (addcryptoptions) {
1078 const uint8 uSupportsCryptLayer = thePrefs::IsClientCryptLayerSupported() ? 1 : 0;
1079 const uint8 uRequestsCryptLayer = thePrefs::IsClientCryptLayerRequested() ? 1 : 0;
1080 const uint8 uRequiresCryptLayer = thePrefs::IsClientCryptLayerRequired() ? 1 : 0;
1081 const uint8 byCryptOptions = (uRequiresCryptLayer << 2) | (uRequestsCryptLayer << 1) | (uSupportsCryptLayer << 0) | (uSupportsCryptLayer ? 0x80 : 0x00);
1083 strURL << wxT(":") << byCryptOptions;
1085 if (byCryptOptions & 0x80) {
1086 strURL << wxT(":") << thePrefs::GetUserHash().Encode();
1089 strURL << wxT("|/");
1090 } else if (add_source) {
1091 AddLogLineM(true, _("WARNING: You can't add yourself as a source for an eD2k link while having a lowid."));
1094 // Result is "ed2k://|file|<filename>|<size>|<hash>|/|sources,[(<ip>|<hostname>):<port>[:cryptoptions[:hash]]]|/"
1095 return strURL;
1098 // Returns a ed2k link with AICH info if available
1099 wxString CamuleApp::CreateED2kAICHLink(const CKnownFile* f)
1101 // Create the first part of the URL
1102 wxString strURL = CreateED2kLink(f);
1103 // Append the AICH info
1104 if (f->HasProperAICHHashSet()) {
1105 strURL.RemoveLast(); // remove trailing '/'
1106 strURL << wxT("h=") << f->GetAICHMasterHash() << wxT("|/");
1109 // Result is "ed2k://|file|<filename>|<size>|<hash>|h=<AICH master hash>|/"
1110 return strURL;
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://www.amule.org/wiki/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();
1433 if (!IsRunning()) {
1434 return;
1437 #ifndef AMULE_DAEMON
1438 // Check if we should terminate the app
1439 if ( g_shutdownSignal ) {
1440 wxWindow* top = GetTopWindow();
1442 if ( top ) {
1443 top->Close(true);
1444 } else {
1445 // No top-window, have to force termination.
1446 wxExit();
1449 #endif
1451 uploadqueue->Process();
1452 downloadqueue->Process();
1453 //theApp->clientcredits->Process();
1454 theStats::CalculateRates();
1456 if (msCur-msPrevHist > 1000) {
1457 // unlike the other loop counters in this function this one will sometimes
1458 // produce two calls in quick succession (if there was a gap of more than one
1459 // second between calls to TimerProc) - this is intentional! This way the
1460 // history list keeps an average of one node per second and gets thinned out
1461 // correctly as time progresses.
1462 msPrevHist += 1000;
1464 m_statistics->RecordHistory();
1469 if (msCur-msPrev1 > 1000) { // approximately every second
1470 msPrev1 = msCur;
1471 clientcredits->Process();
1472 clientlist->Process();
1474 // Publish files to server if needed.
1475 sharedfiles->Process();
1477 if( Kademlia::CKademlia::IsRunning() ) {
1478 Kademlia::CKademlia::Process();
1479 if(Kademlia::CKademlia::GetPrefs()->HasLostConnection()) {
1480 StopKad();
1481 clientudp->Close();
1482 clientudp->Open();
1483 if (thePrefs::Reconnect()) {
1484 StartKad();
1489 if( serverconnect->IsConnecting() && !serverconnect->IsSingleConnect() ) {
1490 serverconnect->TryAnotherConnectionrequest();
1492 if (serverconnect->IsConnecting()) {
1493 serverconnect->CheckForTimeout();
1495 listensocket->UpdateConnectionsStatus();
1500 if (msCur-msPrev5 > 5000) { // every 5 seconds
1501 msPrev5 = msCur;
1502 listensocket->Process();
1505 if (msCur-msPrevSave >= 60000) {
1506 msPrevSave = msCur;
1507 wxString buffer;
1509 // Save total upload/download to preferences
1510 wxConfigBase* cfg = wxConfigBase::Get();
1511 buffer = CFormat(wxT("%llu")) % (theStats::GetSessionReceivedBytes() + thePrefs::GetTotalDownloaded());
1512 cfg->Write(wxT("/Statistics/TotalDownloadedBytes"), buffer);
1514 buffer = CFormat(wxT("%llu")) % (theStats::GetSessionSentBytes() + thePrefs::GetTotalUploaded());
1515 cfg->Write(wxT("/Statistics/TotalUploadedBytes"), buffer);
1517 // Write changes to file
1518 cfg->Flush();
1522 // Special
1523 if (msCur - msPrevOS >= thePrefs::GetOSUpdate() * 1000ull) {
1524 OnlineSig(); // Added By Bouc7
1525 msPrevOS = msCur;
1528 if (msCur - msPrevKnownMet >= 30*60*1000/*There must be a prefs option for this*/) {
1529 // Save Shared Files data
1530 knownfiles->Save();
1531 msPrevKnownMet = msCur;
1535 // Recomended by lugdunummaster himself - from emule 0.30c
1536 serverconnect->KeepConnectionAlive();
1541 void CamuleApp::OnFinishedHashing(CHashingEvent& evt)
1543 wxCHECK_RET(evt.GetResult(), wxT("No result of hashing"));
1545 CKnownFile* owner = const_cast<CKnownFile*>(evt.GetOwner());
1546 CKnownFile* result = evt.GetResult();
1548 if (owner) {
1549 // Check if the partfile still exists, as it might have
1550 // been deleted in the mean time.
1551 if (downloadqueue->IsPartFile(owner)) {
1552 // This cast must not be done before the IsPartFile
1553 // call, as dynamic_cast will barf on dangling pointers.
1554 dynamic_cast<CPartFile*>(owner)->PartFileHashFinished(result);
1556 } else {
1557 static int filecount;
1558 static uint64 bytecount;
1560 if (knownfiles->SafeAddKFile(result)) {
1561 AddDebugLogLineM(false, logKnownFiles,
1562 CFormat(wxT("Safe adding file to sharedlist: %s")) % result->GetFileName());
1563 sharedfiles->SafeAddKFile(result);
1565 filecount++;
1566 bytecount += result->GetFileSize();
1567 // If we have added 30 files or files with a total size of ~300mb
1568 if ( ( filecount == 30 ) || ( bytecount >= 314572800 ) ) {
1569 AddDebugLogLineM(false, logKnownFiles, wxT("Failsafe for crash on file hashing creation"));
1570 if ( m_app_state != APP_STATE_SHUTTINGDOWN ) {
1571 knownfiles->Save();
1572 filecount = 0;
1573 bytecount = 0;
1576 } else {
1577 AddDebugLogLineM(false, logKnownFiles,
1578 CFormat(wxT("File not added to sharedlist: %s")) % result->GetFileName());
1579 delete result;
1585 void CamuleApp::OnFinishedAICHHashing(CHashingEvent& evt)
1587 wxCHECK_RET(evt.GetResult(), wxT("No result of AICH-hashing"));
1589 CKnownFile* owner = const_cast<CKnownFile*>(evt.GetOwner());
1590 CScopedPtr<CKnownFile> result(evt.GetResult());
1592 // Check that the owner is still valid
1593 if (knownfiles->IsKnownFile(owner)) {
1594 if (result->GetAICHHashset()->GetStatus() == AICH_HASHSETCOMPLETE) {
1595 CAICHHashSet* oldSet = owner->GetAICHHashset();
1596 CAICHHashSet* newSet = result->GetAICHHashset();
1598 owner->SetAICHHashset(newSet);
1599 newSet->SetOwner(owner);
1601 result->SetAICHHashset(oldSet);
1602 oldSet->SetOwner(result.get());
1608 void CamuleApp::OnFinishedCompletion(CCompletionEvent& evt)
1610 CPartFile* completed = const_cast<CPartFile*>(evt.GetOwner());
1611 wxCHECK_RET(completed, wxT("Completion event sent for unspecified file"));
1612 wxASSERT_MSG(downloadqueue->IsPartFile(completed), wxT("CCompletionEvent for unknown partfile."));
1614 completed->CompleteFileEnded(evt.ErrorOccured(), evt.GetFullPath());
1615 if (evt.ErrorOccured()) {
1616 CUserEvents::ProcessEvent(CUserEvents::ErrorOnCompletion, completed);
1619 // Check if we should execute an script/app/whatever.
1620 CUserEvents::ProcessEvent(CUserEvents::DownloadCompleted, completed);
1623 void CamuleApp::OnFinishedAllocation(CAllocFinishedEvent& evt)
1625 CPartFile *file = evt.GetFile();
1626 wxCHECK_RET(file, wxT("Allocation finished event sent for unspecified file"));
1627 wxASSERT_MSG(downloadqueue->IsPartFile(file), wxT("CAllocFinishedEvent for unknown partfile"));
1629 file->SetPartFileStatus(PS_EMPTY);
1631 if (evt.Succeeded()) {
1632 if (evt.IsPaused()) {
1633 file->StopFile();
1634 } else {
1635 file->ResumeFile();
1637 } else {
1638 AddLogLineM(false, CFormat(_("Disk space preallocation for file '%s' failed: %s")) % file->GetFileName() % wxString(UTF82unicode(std::strerror(evt.GetResult()))));
1639 file->StopFile();
1642 file->AllocationFinished();
1645 void CamuleApp::OnNotifyEvent(CMuleGUIEvent& evt)
1647 #if defined(AMULE_DAEMON)
1648 evt.Notify();
1649 #else
1650 if (theApp->amuledlg) {
1651 evt.Notify();
1653 #endif
1657 void CamuleApp::ShutDown()
1659 // Log
1660 AddDebugLogLineM(false, logGeneral, wxT("CamuleApp::ShutDown() has started."));
1662 // Signal the hashing thread to terminate
1663 m_app_state = APP_STATE_SHUTTINGDOWN;
1665 StopKad();
1667 // Kry - Save the sources seeds on app exit
1668 if (thePrefs::GetSrcSeedsOn()) {
1669 downloadqueue->SaveSourceSeeds();
1672 OnlineSig(true); // Added By Bouc7
1674 // Close sockets to avoid new clients coming in
1675 if (listensocket) {
1676 listensocket->Close();
1677 listensocket->KillAllSockets();
1680 if (serverconnect) {
1681 serverconnect->Disconnect();
1684 ECServerHandler->KillAllSockets();
1686 #ifdef ENABLE_UPNP
1687 if (thePrefs::GetUPnPEnabled()) {
1688 if (m_upnp) {
1689 m_upnp->DeletePortMappings(m_upnpMappings);
1692 #endif
1694 // saving data & stuff
1695 if (knownfiles) {
1696 knownfiles->Save();
1699 thePrefs::Add2TotalDownloaded(theStats::GetSessionReceivedBytes());
1700 thePrefs::Add2TotalUploaded(theStats::GetSessionSentBytes());
1702 if (glob_prefs) {
1703 glob_prefs->Save();
1706 if (clientlist) {
1707 clientlist->DeleteAll();
1710 CThreadScheduler::Terminate();
1712 theApp->uploadBandwidthThrottler->EndThread();
1714 // Log
1715 AddDebugLogLineM(false, logGeneral, wxT("CamuleApp::ShutDown() has ended."));
1719 bool CamuleApp::AddServer(CServer *srv, bool fromUser)
1721 if ( serverlist->AddServer(srv, fromUser) ) {
1722 Notify_ServerAdd(srv);
1723 return true;
1725 return false;
1729 uint32 CamuleApp::GetPublicIP(bool ignorelocal) const
1731 if (m_dwPublicIP == 0) {
1732 if (Kademlia::CKademlia::IsConnected() && Kademlia::CKademlia::GetIPAddress() ) {
1733 return wxUINT32_SWAP_ALWAYS(Kademlia::CKademlia::GetIPAddress());
1734 } else {
1735 return ignorelocal ? 0 : m_localip;
1739 return m_dwPublicIP;
1743 void CamuleApp::SetPublicIP(const uint32 dwIP)
1745 wxASSERT((dwIP == 0) || !IsLowID(dwIP));
1747 if (dwIP != 0 && dwIP != m_dwPublicIP && serverlist != NULL) {
1748 m_dwPublicIP = dwIP;
1749 serverlist->CheckForExpiredUDPKeys();
1750 } else {
1751 m_dwPublicIP = dwIP;
1756 wxString CamuleApp::GetLog(bool reset)
1758 ConfigDir = GetConfigDir();
1759 wxFile logfile;
1760 logfile.Open(ConfigDir + wxT("logfile"));
1761 if ( !logfile.IsOpened() ) {
1762 return _("ERROR: can't open logfile");
1764 int len = logfile.Length();
1765 if ( len == 0 ) {
1766 return _("WARNING: logfile is empty. Something is wrong.");
1768 char *tmp_buffer = new char[len + sizeof(wxChar)];
1769 logfile.Read(tmp_buffer, len);
1770 memset(tmp_buffer + len, 0, sizeof(wxChar));
1772 // try to guess file format
1773 wxString str;
1774 if (tmp_buffer[0] && tmp_buffer[1]) {
1775 str = wxString(UTF82unicode(tmp_buffer));
1776 } else {
1777 str = wxString((wxWCharBuffer&)tmp_buffer);
1780 delete [] tmp_buffer;
1781 if ( reset ) {
1782 theLogger.CloseLogfile();
1783 if (theLogger.OpenLogfile(ConfigDir + wxT("logfile"))) {
1784 AddLogLineM(false, _("Log has been reset"));
1787 return str;
1791 wxString CamuleApp::GetServerLog(bool reset)
1793 wxString ret = server_msg;
1794 if ( reset ) {
1795 server_msg.Clear();
1797 return ret;
1800 wxString CamuleApp::GetDebugLog(bool reset)
1802 return GetLog(reset);
1806 void CamuleApp::AddServerMessageLine(wxString &msg)
1808 server_msg += msg + wxT("\n");
1809 AddLogLineM(false, CFormat(_("ServerMessage: %s")) % msg);
1814 void CamuleApp::OnFinishedHTTPDownload(CMuleInternalEvent& event)
1816 switch (event.GetInt()) {
1817 case HTTP_IPFilter:
1818 ipfilter->DownloadFinished(event.GetExtraLong());
1819 break;
1820 case HTTP_ServerMet:
1821 serverlist->DownloadFinished(event.GetExtraLong());
1822 break;
1823 case HTTP_ServerMetAuto:
1824 serverlist->AutoDownloadFinished(event.GetExtraLong());
1825 break;
1826 case HTTP_VersionCheck:
1827 CheckNewVersion(event.GetExtraLong());
1828 break;
1829 case HTTP_NodesDat:
1830 if (event.GetExtraLong() != -1) {
1832 wxString file = ConfigDir + wxT("nodes.dat");
1833 if (wxFileExists(file)) {
1834 wxRemoveFile(file);
1837 if ( Kademlia::CKademlia::IsRunning() ) {
1838 Kademlia::CKademlia::Stop();
1841 wxRenameFile(file + wxT(".download"),file);
1843 Kademlia::CKademlia::Start();
1844 theApp->ShowConnectionState();
1846 } else {
1847 AddLogLineM(true, _("Failed to download the nodes list."));
1849 break;
1850 #ifdef ENABLE_IP2COUNTRY
1851 case HTTP_GeoIP:
1852 theApp->amuledlg->IP2CountryDownloadFinished(event.GetExtraLong());
1853 // If we updated, the dialog is already up. Redraw it to show the flags.
1854 theApp->amuledlg->Refresh();
1855 break;
1856 #endif
1860 void CamuleApp::CheckNewVersion(uint32 result)
1862 if (result == 1) {
1863 wxString filename = ConfigDir + wxT("last_version_check");
1864 wxTextFile file;
1866 if (!file.Open(filename)) {
1867 AddLogLineM(true, _("Failed to open the downloaded version check file") );
1868 return;
1869 } else if (!file.GetLineCount()) {
1870 AddLogLineM(true, _("Corrupted version check file"));
1871 } else {
1872 wxString versionLine = file.GetFirstLine();
1873 wxStringTokenizer tkz(versionLine, wxT("."));
1875 AddDebugLogLineM(false, logGeneral, wxString(wxT("Running: ")) + wxT(VERSION) + wxT(", Version check: ") + versionLine);
1877 long fields[] = {0, 0, 0};
1878 for (int i = 0; i < 3; ++i) {
1879 if (!tkz.HasMoreTokens()) {
1880 AddLogLineM(true, _("Corrupted version check file"));
1881 return;
1882 } else {
1883 wxString token = tkz.GetNextToken();
1885 if (!token.ToLong(&fields[i])) {
1886 AddLogLineM(true, _("Corrupted version check file"));
1887 return;
1892 long curVer = make_full_ed2k_version(VERSION_MJR, VERSION_MIN, VERSION_UPDATE);
1893 long newVer = make_full_ed2k_version(fields[0], fields[1], fields[2]);
1895 if (curVer < newVer) {
1896 AddLogLineM(true, _("You are using an outdated version of aMule!"));
1897 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]));
1898 AddLogLineM(false, _("The latest version can always be found at http://www.amule.org"));
1899 #ifdef AMULE_DAEMON
1900 AddLogLineMS(true, CFormat(_("WARNING: Your aMuled version is outdated: %i.%i.%i < %li.%li.%li"))
1901 % VERSION_MJR % VERSION_MIN % VERSION_UPDATE % fields[0] % fields[1] % fields[2]);
1902 #endif
1903 } else {
1904 AddLogLineM(false, _("Your copy of aMule is up to date."));
1908 file.Close();
1909 wxRemoveFile(filename);
1910 } else {
1911 AddLogLineM(true, _("Failed to download the version check file") );
1917 bool CamuleApp::IsConnected() const
1919 return (IsConnectedED2K() || IsConnectedKad());
1923 bool CamuleApp::IsConnectedED2K() const
1925 return serverconnect && serverconnect->IsConnected();
1929 bool CamuleApp::IsConnectedKad() const
1931 return Kademlia::CKademlia::IsConnected();
1935 bool CamuleApp::IsFirewalled() const
1937 if (theApp->IsConnectedED2K() && !theApp->serverconnect->IsLowID()) {
1938 return false; // we have an eD2K HighID -> not firewalled
1941 return IsFirewalledKad(); // If kad says ok, it's ok.
1944 bool CamuleApp::IsFirewalledKad() const
1946 return !Kademlia::CKademlia::IsConnected() // not connected counts as firewalled
1947 || Kademlia::CKademlia::IsFirewalled();
1950 bool CamuleApp::IsFirewalledKadUDP() const
1952 return !Kademlia::CKademlia::IsConnected() // not connected counts as firewalled
1953 || Kademlia::CUDPFirewallTester::IsFirewalledUDP(true);
1956 bool CamuleApp::IsKadRunning() const
1958 return Kademlia::CKademlia::IsRunning();
1961 // Kad stats
1962 uint32 CamuleApp::GetKadUsers() const
1964 return Kademlia::CKademlia::GetKademliaUsers();
1967 uint32 CamuleApp::GetKadFiles() const
1969 return Kademlia::CKademlia::GetKademliaFiles();
1972 uint32 CamuleApp::GetKadIndexedSources() const
1974 return Kademlia::CKademlia::GetIndexed()->m_totalIndexSource;
1977 uint32 CamuleApp::GetKadIndexedKeywords() const
1979 return Kademlia::CKademlia::GetIndexed()->m_totalIndexKeyword;
1982 uint32 CamuleApp::GetKadIndexedNotes() const
1984 return Kademlia::CKademlia::GetIndexed()->m_totalIndexNotes;
1987 uint32 CamuleApp::GetKadIndexedLoad() const
1989 return Kademlia::CKademlia::GetIndexed()->m_totalIndexLoad;
1993 // True IP of machine
1994 uint32 CamuleApp::GetKadIPAdress() const
1996 return wxUINT32_SWAP_ALWAYS(Kademlia::CKademlia::GetPrefs()->GetIPAddress());
1999 // Buddy status
2000 uint8 CamuleApp::GetBuddyStatus() const
2002 return clientlist->GetBuddyStatus();
2005 uint32 CamuleApp::GetBuddyIP() const
2007 return clientlist->GetBuddy()->GetIP();
2010 uint32 CamuleApp::GetBuddyPort() const
2012 return clientlist->GetBuddy()->GetUDPPort();
2015 bool CamuleApp::DoCallback( CUpDownClient *client )
2017 if(Kademlia::CKademlia::IsConnected()) {
2018 if(IsConnectedED2K()) {
2019 if(serverconnect->IsLowID()) {
2020 if(Kademlia::CKademlia::IsFirewalled()) {
2021 //Both Connected - Both Firewalled
2022 return false;
2023 } else {
2024 if(client->GetServerIP() == theApp->serverconnect->GetCurrentServer()->GetIP() &&
2025 client->GetServerPort() == theApp->serverconnect->GetCurrentServer()->GetPort()) {
2026 // Both Connected - Server lowID, Kad Open - Client on same server
2027 // We prevent a callback to the server as this breaks the protocol
2028 // and will get you banned.
2029 return false;
2030 } else {
2031 // Both Connected - Server lowID, Kad Open - Client on remote server
2032 return true;
2035 } else {
2036 //Both Connected - Server HighID, Kad don't care
2037 return true;
2039 } else {
2040 if(Kademlia::CKademlia::IsFirewalled()) {
2041 //Only Kad Connected - Kad Firewalled
2042 return false;
2043 } else {
2044 //Only Kad Conected - Kad Open
2045 return true;
2048 } else {
2049 if( IsConnectedED2K() ) {
2050 if( serverconnect->IsLowID() ) {
2051 //Only Server Connected - Server LowID
2052 return false;
2053 } else {
2054 //Only Server Connected - Server HighID
2055 return true;
2057 } else {
2058 //We are not connected at all!
2059 return false;
2064 void CamuleApp::ShowUserCount() {
2065 uint32 totaluser = 0, totalfile = 0;
2067 theApp->serverlist->GetUserFileStatus( totaluser, totalfile );
2069 wxString buffer;
2071 static const wxString s_singlenetstatusformat = _("Users: %s | Files: %s");
2072 static const wxString s_bothnetstatusformat = _("Users: E: %s K: %s | Files: E: %s K: %s");
2074 if (thePrefs::GetNetworkED2K() && thePrefs::GetNetworkKademlia()) {
2075 buffer = CFormat(s_bothnetstatusformat) % CastItoIShort(totaluser) % CastItoIShort(Kademlia::CKademlia::GetKademliaUsers()) % CastItoIShort(totalfile) % CastItoIShort(Kademlia::CKademlia::GetKademliaFiles());
2076 } else if (thePrefs::GetNetworkED2K()) {
2077 buffer = CFormat(s_singlenetstatusformat) % CastItoIShort(totaluser) % CastItoIShort(totalfile);
2078 } else if (thePrefs::GetNetworkKademlia()) {
2079 buffer = CFormat(s_singlenetstatusformat) % CastItoIShort(Kademlia::CKademlia::GetKademliaUsers()) % CastItoIShort(Kademlia::CKademlia::GetKademliaFiles());
2080 } else {
2081 buffer = _("No networks selected");
2084 Notify_ShowUserCount(buffer);
2088 void CamuleApp::ListenSocketHandler(wxSocketEvent& event)
2090 wxCHECK_RET(listensocket, wxT("Connection-event for NULL'd listen-socket"));
2091 wxCHECK_RET(event.GetSocketEvent() == wxSOCKET_CONNECTION,
2092 wxT("Invalid event received for listen-socket"));
2094 if (m_app_state == APP_STATE_RUNNING) {
2095 listensocket->OnAccept(0);
2096 } else if (m_app_state == APP_STATE_STARTING) {
2097 // When starting up, connection may be made before we are able
2098 // to handle them. However, if these are ignored, no futher
2099 // connection-events will be triggered, so we have to accept it.
2100 wxSocketBase* socket = listensocket->Accept(false);
2102 wxCHECK_RET(socket, wxT("NULL returned by Accept() during startup"));
2104 socket->Destroy();
2109 void CamuleApp::ShowConnectionState()
2111 static uint8 old_state = (1<<7); // This flag doesn't exist
2113 uint8 state = 0;
2115 if (theApp->serverconnect->IsConnected()) {
2116 state |= CONNECTED_ED2K;
2119 if (Kademlia::CKademlia::IsRunning()) {
2120 if (Kademlia::CKademlia::IsConnected()) {
2121 if (!Kademlia::CKademlia::IsFirewalled()) {
2122 state |= CONNECTED_KAD_OK;
2123 } else {
2124 state |= CONNECTED_KAD_FIREWALLED;
2126 } else {
2127 state |= CONNECTED_KAD_NOT;
2131 Notify_ShowConnState(state);
2133 if (old_state != state) {
2134 // Get the changed value
2135 int changed_flags = old_state ^ state;
2137 if (changed_flags & CONNECTED_ED2K) {
2138 // ED2K status changed
2139 wxString connected_server;
2140 CServer* ed2k_server = theApp->serverconnect->GetCurrentServer();
2141 if (ed2k_server) {
2142 connected_server = ed2k_server->GetListName();
2144 if (state & CONNECTED_ED2K) {
2145 // We connected to some server
2146 const wxString id = theApp->serverconnect->IsLowID() ? _("with LowID") : _("with HighID");
2148 AddLogLineM(true, CFormat(_("Connected to %s %s")) % connected_server % id);
2149 } else {
2150 if ( theApp->serverconnect->IsConnecting() ) {
2151 AddLogLineM(true, CFormat(_("Connecting to %s")) % connected_server);
2152 } else {
2153 AddLogLineM(true, _("Disconnected from eD2k"));
2158 if (changed_flags & CONNECTED_KAD_NOT) {
2159 if (state & CONNECTED_KAD_NOT) {
2160 AddLogLineM(true, _("Kad started."));
2161 } else {
2162 AddLogLineM(true, _("Kad stopped."));
2166 if (changed_flags & (CONNECTED_KAD_OK | CONNECTED_KAD_FIREWALLED)) {
2167 if (state & (CONNECTED_KAD_OK | CONNECTED_KAD_FIREWALLED)) {
2168 if (state & CONNECTED_KAD_OK) {
2169 AddLogLineM(true, _("Connected to Kad (ok)"));
2170 } else {
2171 AddLogLineM(true, _("Connected to Kad (firewalled)"));
2173 } else {
2174 AddLogLineM(true, _("Disconnected from Kad"));
2178 old_state = state;
2180 theApp->downloadqueue->OnConnectionState(IsConnected());
2183 ShowUserCount();
2184 Notify_ShowConnState(state);
2188 void CamuleApp::UDPSocketHandler(wxSocketEvent& event)
2190 CMuleUDPSocket* socket = (CMuleUDPSocket*)(event.GetClientData());
2191 wxCHECK_RET(socket, wxT("No socket owner specified."));
2193 if (IsOnShutDown() || thePrefs::IsUDPDisabled()) return;
2195 if (!IsRunning()) {
2196 if (event.GetSocketEvent() == wxSOCKET_INPUT) {
2197 // Back to the queue!
2198 theApp->AddPendingEvent(event);
2199 return;
2203 switch (event.GetSocketEvent()) {
2204 case wxSOCKET_INPUT:
2205 socket->OnReceive(0);
2206 break;
2208 case wxSOCKET_OUTPUT:
2209 socket->OnSend(0);
2210 break;
2212 case wxSOCKET_LOST:
2213 socket->OnDisconnected(0);
2214 break;
2216 default:
2217 wxFAIL;
2218 break;
2223 void CamuleApp::OnUnhandledException()
2225 // Call the generic exception-handler.
2226 fprintf(stderr, "\taMule Version: %s\n", (const char*)unicode2char(GetFullMuleVersion()));
2227 ::OnUnhandledException();
2230 void CamuleApp::StartKad()
2232 if (!Kademlia::CKademlia::IsRunning() && thePrefs::GetNetworkKademlia()) {
2233 // Kad makes no sense without the Client-UDP socket.
2234 if (!thePrefs::IsUDPDisabled()) {
2235 Kademlia::CKademlia::Start();
2236 } else {
2237 AddLogLineM(true,_("Kad network cannot be used if UDP port is disabled on preferences, not starting."));
2239 } else if (!thePrefs::GetNetworkKademlia()) {
2240 AddLogLineM(true,_("Kad network disabled on preferences, not connecting."));
2244 void CamuleApp::StopKad()
2246 // Stop Kad if it's running
2247 if (Kademlia::CKademlia::IsRunning()) {
2248 Kademlia::CKademlia::Stop();
2253 void CamuleApp::BootstrapKad(uint32 ip, uint16 port)
2255 if (!Kademlia::CKademlia::IsRunning()) {
2256 Kademlia::CKademlia::Start();
2257 theApp->ShowConnectionState();
2260 Kademlia::CKademlia::Bootstrap(ip, port, true);
2264 void CamuleApp::UpdateNotesDat(const wxString& url)
2266 wxString strTempFilename(theApp->ConfigDir + wxT("nodes.dat.download"));
2268 CHTTPDownloadThread *downloader = new CHTTPDownloadThread(url, strTempFilename, HTTP_NodesDat);
2269 downloader->Create();
2270 downloader->Run();
2274 void CamuleApp::DisconnectED2K()
2276 // Stop ED2K if it's running
2277 if (IsConnectedED2K()) {
2278 serverconnect->Disconnect();
2282 bool CamuleApp::CryptoAvailable() const
2284 return clientcredits && clientcredits->CryptoAvailable();
2287 uint32 CamuleApp::GetED2KID() const {
2288 return serverconnect ? serverconnect->GetClientID() : 0;
2291 uint32 CamuleApp::GetID() const {
2292 uint32 ID;
2294 if( Kademlia::CKademlia::IsConnected() && !Kademlia::CKademlia::IsFirewalled() ) {
2295 // We trust Kad above ED2K
2296 ID = ENDIAN_NTOHL(Kademlia::CKademlia::GetIPAddress());
2297 } else if( theApp->serverconnect->IsConnected() ) {
2298 ID = theApp->serverconnect->GetClientID();
2299 } else if ( Kademlia::CKademlia::IsConnected() && Kademlia::CKademlia::IsFirewalled() ) {
2300 // A firewalled Kad client get's a "1"
2301 ID = 1;
2302 } else {
2303 ID = 0;
2306 return ID;
2309 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_FINISHED_HTTP_DOWNLOAD)
2310 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_SOURCE_DNS_DONE)
2311 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_UDP_DNS_DONE)
2312 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_SERVER_DNS_DONE)
2313 // File_checked_for_headers