Threw in some tabs for better readabillity and added the forgotten CMakeLists.txt...
[amule.git] / src / ExternalConnector.cpp
blob1e10b9ac704f79118406674eb0291f8772b9e893
1 //
2 // This file is part of the aMule Project.
3 //
4 // Copyright (c) 2004-2011 aMule Team ( admin@amule.org / http://www.amule.org )
5 //
6 // Any parts of this program derived from the xMule, lMule or eMule project,
7 // or contributed by third-party developers are copyrighted by their
8 // respective authors.
9 //
10 // This program is free software; you can redistribute it and/or modify
11 // it under the terms of the GNU General Public License as published by
12 // the Free Software Foundation; either version 2 of the License, or
13 // (at your option) any later version.
15 // This program is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU General Public License for more details.
20 // You should have received a copy of the GNU General Public License
21 // along with this program; if not, write to the Free Software
22 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "ExternalConnector.h"
26 #include "amule-config.h" // Needed for VERSION and readline detection
27 #include <common/Format.h> // Needed for CFormat
28 #include <wx/tokenzr.h> // For wxStringTokenizer
30 // For readline
31 #ifdef HAVE_LIBREADLINE
32 #if defined(HAVE_READLINE_READLINE_H)
33 #include <readline/readline.h> // Do_not_auto_remove
34 #elif defined(HAVE_READLINE_H)
35 #include <readline.h> // Do_not_auto_remove
36 #endif /* !defined(HAVE_READLINE_H) */
37 #else /* !defined(HAVE_READLINE_READLINE_H) */
38 /* no readline */
39 #endif /* HAVE_LIBREADLINE */
41 // For history
42 #ifdef HAVE_READLINE_HISTORY
43 #if defined(HAVE_READLINE_HISTORY_H)
44 #include <readline/history.h> // Do_not_auto_remove
45 #elif defined(HAVE_HISTORY_H)
46 #include <history.h> // Do_not_auto_remove
47 #endif /* defined(HAVE_READLINE_HISTORY_H) */
48 #else
49 /* no history */
50 #endif /* HAVE_READLINE_HISTORY */
53 #include <ec/cpp/ECFileConfig.h> // Needed for CECFileConfig
54 #include <common/MD5Sum.h>
55 #include "OtherFunctions.h" // Needed for GetPassword()
56 #include "MuleVersion.h" // Needed for GetMuleVersion()
58 #ifdef _MSC_VER // silly warnings about deprecated functions
59 #pragma warning(disable:4996)
60 #endif
62 //-------------------------------------------------------------------
64 CaMuleExternalConnector* CCommandTree::m_app;
66 CCommandTree::~CCommandTree()
68 DeleteContents(m_subcommands);
72 CCommandTree* CCommandTree::AddCommand(CCommandTree* command)
74 command->m_parent = this;
75 const wxString& cmd = command->m_command;
76 CmdPos_t it;
77 for (it = m_subcommands.begin(); it != m_subcommands.end(); ++it) {
78 if ((*it)->m_command > cmd) {
79 break;
82 m_subcommands.insert(it, command);
83 return command;
87 int CCommandTree::FindCommandId(const wxString& command, wxString& args, wxString& cmdstr) const
89 wxString cmd = command.BeforeFirst(wxT(' ')).Lower();
90 for (CmdPosConst_t it = m_subcommands.begin(); it != m_subcommands.end(); ++it) {
91 if ((*it)->m_command.Lower() == cmd) {
92 args = command.AfterFirst(wxT(' ')).Trim(false);
93 return (*it)->FindCommandId(args, args, cmdstr);
96 cmdstr = GetFullCommand().Lower();
97 if (m_params == CMD_PARAM_ALWAYS && args.IsEmpty()) {
98 return CMD_ERR_MUST_HAVE_PARAM;
99 } else if (m_params == CMD_PARAM_NEVER && !args.IsEmpty()) {
100 return CMD_ERR_NO_PARAM;
101 } else {
102 if ((m_cmd_id >= 0) && (m_cmd_id & CMD_DEPRECATED)) {
103 m_app->Show(wxT('\n') + m_verbose + wxT('\n'));
104 return m_cmd_id & ~CMD_DEPRECATED;
105 } else {
106 return m_cmd_id;
112 wxString CCommandTree::GetFullCommand() const
114 wxString cmd = m_command;
116 const CCommandTree *parent = m_parent;
117 while (parent && parent->m_parent) {
118 cmd = parent->m_command + wxT(" ") + cmd;
119 parent = parent->m_parent;
122 return cmd;
126 void CCommandTree::PrintHelpFor(const wxString& command) const
128 wxString cmd = command.BeforeFirst(wxT(' ')).Lower();
129 if (!cmd.IsEmpty()) {
130 for (CmdPosConst_t it = m_subcommands.begin(); it != m_subcommands.end(); ++it) {
131 if ((*it)->m_command.Lower() == cmd) {
132 (*it)->PrintHelpFor(command.AfterFirst(wxT(' ')).Trim(false));
133 return;
136 if (m_parent) {
137 m_app->Show(CFormat(_("Unknown extension '%s' for the '%s' command.\n")) % command % GetFullCommand());
138 } else {
139 m_app->Show(CFormat(_("Unknown command '%s'.\n")) % command);
141 } else {
142 wxString fullcmd = GetFullCommand();
143 if (!fullcmd.IsEmpty()) {
144 m_app->Show(fullcmd.Upper() + wxT(": ") + wxGetTranslation(m_short) + wxT("\n"));
145 if (!m_verbose.IsEmpty()) {
146 m_app->Show(wxT("\n"));
147 m_app->Show(wxGetTranslation(m_verbose));
150 if (m_params == CMD_PARAM_NEVER) {
151 m_app->Show(_("\nThis command cannot have an argument.\n"));
152 } else if (m_params == CMD_PARAM_ALWAYS) {
153 m_app->Show(_("\nThis command must have an argument.\n"));
155 if (m_cmd_id == CMD_ERR_INCOMPLETE) {
156 m_app->Show(_("\nThis command is incomplete, you must use one of the extensions below.\n"));
158 if (!m_subcommands.empty()) {
159 CmdPosConst_t it;
160 int maxlen = 0;
161 if (m_parent) {
162 m_app->Show(_("\nAvailable extensions:\n"));
163 } else {
164 m_app->Show(_("Available commands:\n"));
166 for (it = m_subcommands.begin(); it != m_subcommands.end(); ++it) {
167 if (!((*it)->m_cmd_id >= 0 && (*it)->m_cmd_id & CMD_DEPRECATED) || m_parent) {
168 int len = (*it)->m_command.Length();
169 if (len > maxlen) {
170 maxlen = len;
174 maxlen += 4;
175 for (it = m_subcommands.begin(); it != m_subcommands.end(); ++it) {
176 if (!((*it)->m_cmd_id >= 0 && (*it)->m_cmd_id & CMD_DEPRECATED) || m_parent) {
177 m_app->Show((*it)->m_command + wxString(wxT(' '), maxlen - (*it)->m_command.Length()) + wxGetTranslation((*it)->m_short) + wxT("\n"));
180 if (!m_parent) {
181 m_app->Show(CFormat(_("\nAll commands are case insensitive.\nType '%s <command>' to get detailed info on <command>.\n")) % wxT("help"));
185 m_app->Show(wxT("\n"));
188 //-------------------------------------------------------------------
190 #ifdef HAVE_LIBREADLINE
192 const CmdList_t* CCommandTree::GetSubCommandsFor(const wxString& command, bool mayRestart) const
194 if (command.IsEmpty()) {
195 return &m_subcommands;
198 wxString cmd = command.BeforeFirst(wxT(' ')).Lower();
200 if (mayRestart && cmd == wxT("help")) {
201 return GetSubCommandsFor(command.AfterFirst(wxT(' ')), false);
204 for (CmdPosConst_t it = m_subcommands.begin(); it != m_subcommands.end(); ++it) {
205 if ((*it)->m_command.Lower() == cmd) {
206 return (*it)->GetSubCommandsFor(command.AfterFirst(wxT(' ')).Trim(false), mayRestart);
210 return NULL;
214 // Forward-declare the completion function to make sure it's declaration
215 // matches the library requirements.
216 rl_compentry_func_t command_completion;
219 // File-scope pointer to the application's command set.
220 static CCommandTree * theCommands;
223 char *command_completion(const char *text, int state)
225 static const CmdList_t* curCommands;
226 static CmdPosConst_t nextCommand;
228 if (state == 0) {
229 wxString lineBuffer(rl_line_buffer, *wxConvCurrent);
230 wxString prefix(lineBuffer.Left(rl_point).BeforeLast(wxT(' ')));
232 curCommands = theCommands->GetSubCommandsFor(prefix);
233 if (curCommands) {
234 nextCommand = curCommands->begin();
235 } else {
236 return NULL;
240 wxString test(wxString(text, *wxConvCurrent).Lower());
241 while (nextCommand != curCommands->end()) {
242 wxString curTest = (*nextCommand)->GetCommand();
243 ++nextCommand;
244 if (curTest.Lower().StartsWith(test)) {
245 return strdup(static_cast<const char *>(unicode2char(curTest)));
249 return NULL;
253 #endif /* HAVE_LIBREADLINE */
255 //-------------------------------------------------------------------
257 CaMuleExternalConnector::CaMuleExternalConnector()
258 : m_configFile(NULL),
259 m_port(-1),
260 m_ZLIB(false),
261 m_KeepQuiet(false),
262 m_Verbose(false),
263 m_interactive(false),
264 m_commands(*this),
265 m_appname(NULL),
266 m_ECClient(NULL),
267 m_InputLine(NULL),
268 m_NeedsConfigSave(false),
269 m_locale(NULL),
270 m_strFullVersion(NULL),
271 m_strOSDescription(NULL)
273 SetAppName(wxT("aMule")); // Do not change!
276 CaMuleExternalConnector::~CaMuleExternalConnector()
278 delete m_configFile;
279 delete m_locale;
280 free(m_strFullVersion);
281 free(m_strOSDescription);
284 void CaMuleExternalConnector::OnInitCommandSet()
286 m_commands.AddCommand(wxT("Quit"), CMD_ID_QUIT, wxTRANSLATE("Exits from the application."), wxEmptyString);
287 m_commands.AddCommand(wxT("Exit"), CMD_ID_QUIT, wxTRANSLATE("Exits from the application."), wxEmptyString);
288 m_commands.AddCommand(wxT("Help"), CMD_ID_HELP, wxTRANSLATE("Show help."),
289 /* TRANSLATORS:
290 Do not translate the word 'help', it is a command to the program! */
291 wxTRANSLATE("To get help on a command, type 'help <command>'.\nTo get the full command list type 'help'.\n"));
294 void CaMuleExternalConnector::Show(const wxString &s)
296 if( !m_KeepQuiet ) {
297 printf("%s", (const char *)unicode2char(s));
298 #ifdef __WINDOWS__
299 fflush(stdout);
300 #endif
304 void CaMuleExternalConnector::ShowGreet()
306 wxString text = GetGreetingTitle();
307 int len = text.Length();
308 Show(wxT('\n') + wxString(wxT('-'), 22 + len) + wxT('\n'));
309 Show(wxT('|') + wxString(wxT(' '), 10) + text + wxString(wxT(' '), 10) + wxT('|') + wxT('\n'));
310 Show(wxString(wxT('-'), 22 + len) + wxT('\n'));
311 // Do not merge the line below, or translators could translate "Help"
312 Show(CFormat(_("\nUse '%s' for command list\n\n")) % wxT("Help"));
315 void CaMuleExternalConnector::Process_Answer(const wxString& answer)
317 wxStringTokenizer tokens(answer, wxT("\n"));
318 while ( tokens.HasMoreTokens() ) {
319 Show(wxT(" > ") + tokens.GetNextToken() + wxT("\n"));
323 bool CaMuleExternalConnector::Parse_Command(const wxString& buffer)
325 wxString cmd;
326 wxStringTokenizer tokens(buffer);
327 while (tokens.HasMoreTokens()) {
328 cmd += tokens.GetNextToken() + wxT(' ');
330 cmd.Trim(false);
331 cmd.Trim(true);
332 if (cmd.IsEmpty()) {
333 return false;
335 int cmd_ID = GetIDFromString(cmd);
336 if ( cmd_ID >= 0 ) {
337 cmd_ID = ProcessCommand(cmd_ID);
339 wxString error;
340 switch (cmd_ID) {
341 case CMD_ID_HELP:
342 m_commands.PrintHelpFor(GetCmdArgs());
343 break;
344 case CMD_ERR_SYNTAX:
345 error = _("Syntax error!");
346 break;
347 case CMD_ERR_PROCESS_CMD:
348 Show(_("Error processing command - should never happen! Report bug, please\n"));
349 break;
350 case CMD_ERR_NO_PARAM:
351 error = _("This command should not have any parameters.");
352 break;
353 case CMD_ERR_MUST_HAVE_PARAM:
354 error = _("This command must have a parameter.");
355 break;
356 case CMD_ERR_INVALID_ARG:
357 error = _("Invalid argument.");
358 break;
359 case CMD_ERR_INCOMPLETE:
360 error = _("This is an incomplete command.");
361 break;
363 if (!error.IsEmpty()) {
364 Show(error + wxT('\n'));
365 wxString helpStr(wxT("help"));
366 if (!GetLastCmdStr().IsEmpty()) {
367 helpStr << wxT(' ') << GetLastCmdStr();
369 Show(CFormat(_("Type '%s' to get more help.\n")) % helpStr);
371 return cmd_ID == CMD_ID_QUIT;
374 void CaMuleExternalConnector::GetCommand(const wxString &prompt, char* buffer, size_t buffer_size)
376 #ifdef HAVE_LIBREADLINE
377 char *text = readline(unicode2char(prompt + wxT("$ ")));
378 if (text && *text &&
379 (m_InputLine == 0 || strcmp(text,m_InputLine) != 0)) {
380 add_history (text);
382 if (m_InputLine)
383 free(m_InputLine);
384 m_InputLine = text;
385 #else
386 Show(prompt + wxT("$ "));
387 const char *text = fgets(buffer, buffer_size, stdin); // == buffer if ok, NULL if eof
388 #endif /* HAVE_LIBREADLINE */
389 if ( text ) {
390 size_t len = strlen(text);
391 if (len > buffer_size - 1) {
392 len = buffer_size - 1;
394 if (buffer != text) {
395 strncpy(buffer, text, len);
397 buffer[len] = 0;
398 } else {
399 strncpy(buffer, "quit", buffer_size);
403 void CaMuleExternalConnector::TextShell(const wxString &prompt)
405 char buffer[2048];
406 wxString buf;
408 bool The_End = false;
409 do {
410 GetCommand(prompt, buffer, sizeof buffer);
411 buf = char2unicode(buffer);
412 The_End = Parse_Command(buf);
413 } while ((!The_End) && (m_ECClient->IsSocketConnected()));
416 void CaMuleExternalConnector::ConnectAndRun(const wxString &ProgName, const wxString& ProgVersion)
418 if (m_NeedsConfigSave) {
419 SaveConfigFile();
420 return;
423 #ifdef SVNDATE
424 Show(CFormat(_("This is %s %s %s\n")) % wxString::FromAscii(m_appname) % wxT(VERSION) % wxT(SVNDATE));
425 #else
426 Show(CFormat(_("This is %s %s\n")) % wxString::FromAscii(m_appname) % wxT(VERSION));
427 #endif
429 // HostName, Port and Password
430 if ( m_password.IsEmpty() ) {
431 m_password = GetPassword(true);
432 // MD5 hash for an empty string, according to rfc1321.
433 if (m_password.Encode() == wxT("D41D8CD98F00B204E9800998ECF8427E")) {
434 m_password.Clear();
438 if (!m_password.IsEmpty()) {
440 // Create the socket
441 Show(_("\nCreating client...\n"));
442 m_ECClient = new CRemoteConnect(NULL);
443 m_ECClient->SetCapabilities(m_ZLIB, true, false); // ZLIB, UTF8 numbers, notification
445 // ConnectToCore is blocking since m_ECClient was initialized with NULL
446 if (!m_ECClient->ConnectToCore(m_host, m_port, wxT("foobar"), m_password.Encode(), ProgName, ProgVersion)) {
447 // no connection => close gracefully
448 if (!m_ECClient->GetServerReply().IsEmpty()) {
449 Show(CFormat(wxT("%s\n")) % m_ECClient->GetServerReply());
451 Show(CFormat(_("Connection Failed. Unable to connect to %s:%d\n")) % m_host % m_port);
452 } else {
453 // Authenticate ourselves
454 // ConnectToCore() already authenticated for us.
455 //m_ECClient->ConnectionEstablished();
456 Show(m_ECClient->GetServerReply()+wxT("\n"));
457 if (m_ECClient->IsSocketConnected()) {
458 if (m_interactive) {
459 ShowGreet();
461 Pre_Shell();
462 TextShell(ProgName);
463 Post_Shell();
464 if (m_interactive) {
465 Show(CFormat(_("\nOk, exiting %s...\n")) % ProgName);
469 m_ECClient->DestroySocket();
470 } else {
471 Show(_("Cannot connect with an empty password.\nYou must specify a password either in config file\nor on command-line, or enter one when asked.\n\nExiting...\n"));
475 void CaMuleExternalConnector::OnInitCmdLine(wxCmdLineParser& parser, const char* appname)
477 m_appname = appname;
479 parser.AddSwitch(wxEmptyString, wxT("help"),
480 _("Show this help text."),
481 wxCMD_LINE_PARAM_OPTIONAL);
482 parser.AddOption(wxT("h"), wxT("host"),
483 _("Host where aMule is running. (default: localhost)"),
484 wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL);
485 parser.AddOption(wxT("p"), wxT("port"),
486 _("aMule's port for External Connection. (default: 4712)"),
487 wxCMD_LINE_VAL_NUMBER, wxCMD_LINE_PARAM_OPTIONAL);
488 parser.AddOption(wxT("P"), wxT("password"),
489 _("External Connection password."),
490 wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL);
491 parser.AddOption(wxT("f"), wxT("config-file"),
492 _("Read configuration from file."),
493 wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL);
494 parser.AddSwitch(wxT("q"), wxT("quiet"),
495 _("Do not print any output to stdout."),
496 wxCMD_LINE_PARAM_OPTIONAL);
497 parser.AddSwitch(wxT("v"), wxT("verbose"),
498 _("Be verbose - show also debug messages."),
499 wxCMD_LINE_PARAM_OPTIONAL);
500 parser.AddOption(wxT("l"), wxT("locale"),
501 _("Sets program locale (language)."),
502 wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL);
503 parser.AddSwitch(wxT("w"), wxT("write-config"),
504 _("Write command line options to config file."),
505 wxCMD_LINE_PARAM_OPTIONAL);
506 parser.AddOption(wxEmptyString, wxT("create-config-from"),
507 _("Creates config file based on aMule's config file."),
508 wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL);
509 parser.AddSwitch(wxEmptyString, wxT("version"),
510 _("Print program version."),
511 wxCMD_LINE_PARAM_OPTIONAL);
514 bool CaMuleExternalConnector::OnCmdLineParsed(wxCmdLineParser& parser)
516 if (parser.Found(wxT("version"))) {
517 printf("%s %s\n", m_appname, (const char *)unicode2char(GetMuleVersion()));
518 return false;
521 if (!parser.Found(wxT("config-file"), &m_configFileName)) {
522 m_configFileName = wxT("remote.conf");
524 m_configDir = GetConfigDir(m_configFileName);
525 m_configFileName = m_configDir + m_configFileName;
527 wxString aMuleConfigFile;
528 if (parser.Found(wxT("create-config-from"), &aMuleConfigFile)) {
529 aMuleConfigFile = FinalizeFilename(aMuleConfigFile);
530 if (!::wxFileExists(aMuleConfigFile)) {
531 fprintf(stderr, "%s\n", (const char *)unicode2char(wxT("FATAL ERROR: File does not exist: ") + aMuleConfigFile));
532 exit(1);
534 CECFileConfig aMuleConfig(aMuleConfigFile);
535 LoadAmuleConfig(aMuleConfig);
536 SaveConfigFile();
537 m_configFile->Flush();
538 exit(0);
541 LoadConfigFile();
543 if ( !parser.Found(wxT("host"), &m_host) ) {
544 if ( m_host.IsEmpty() ) {
545 m_host = wxT("localhost");
549 long port;
550 if (parser.Found(wxT("port"), &port)) {
551 m_port = port;
554 wxString pass_plain;
555 if (parser.Found(wxT("password"), &pass_plain)) {
556 if (!pass_plain.IsEmpty()) {
557 m_password.Decode(MD5Sum(pass_plain).GetHash());
558 } else {
559 m_password.Clear();
563 if (parser.Found(wxT("write-config"))) {
564 m_NeedsConfigSave = true;
567 parser.Found(wxT("locale"), &m_language);
569 if (parser.Found(wxT("help"))) {
570 parser.Usage();
571 return false;
574 m_KeepQuiet = parser.Found(wxT("quiet"));
575 m_Verbose = parser.Found(wxT("verbose"));
577 return true;
580 void CaMuleExternalConnector::LoadAmuleConfig(CECFileConfig& cfg)
582 m_host = wxT("localhost");
583 m_port = cfg.Read(wxT("/ExternalConnect/ECPort"), 4712l);
584 cfg.ReadHash(wxT("/ExternalConnect/ECPassword"), &m_password);
585 m_language = cfg.Read(wxT("/eMule/Language"), wxEmptyString);
589 void CaMuleExternalConnector::LoadConfigFile()
591 if (!m_configFile) {
592 m_configFile = new CECFileConfig(m_configFileName);
594 if (m_configFile) {
595 m_language = m_configFile->Read(wxT("/Locale"), wxEmptyString);
596 m_host = m_configFile->Read(wxT("/EC/Host"), wxEmptyString);
597 m_port = m_configFile->Read(wxT("/EC/Port"), 4712l);
598 m_configFile->ReadHash(wxT("/EC/Password"), &m_password);
599 m_ZLIB = m_configFile->Read(wxT("/EC/ZLIB"), 1l) != 0;
603 void CaMuleExternalConnector::SaveConfigFile()
605 if (!wxFileName::DirExists(m_configDir)) {
606 wxFileName::Mkdir(m_configDir);
608 if (!m_configFile) {
609 m_configFile = new CECFileConfig(m_configFileName);
611 if (m_configFile) {
612 m_configFile->Write(wxT("/Locale"), m_language);
613 m_configFile->Write(wxT("/EC/Host"), m_host);
614 m_configFile->Write(wxT("/EC/Port"), m_port);
615 m_configFile->WriteHash(wxT("/EC/Password"), m_password);
619 bool CaMuleExternalConnector::OnInit()
621 #ifndef __WINDOWS__
622 #if wxUSE_ON_FATAL_EXCEPTION
623 // catch fatal exceptions
624 wxHandleFatalExceptions(true);
625 #endif
626 #endif
628 // If we didn't know that OnInit is called only once when creating the
629 // object, it could cause a memory leak. The two pointers below should
630 // be free()'d before assigning the new value.
631 // cppcheck-suppress publicAllocationError
632 m_strFullVersion = strdup((const char *)unicode2char(GetMuleVersion()));
633 m_strOSDescription = strdup((const char *)unicode2char(wxGetOsDescription()));
635 // Handle uncaught exceptions
636 InstallMuleExceptionHandler();
638 bool retval = wxApp::OnInit();
639 OnInitCommandSet();
640 InitCustomLanguages();
641 SetLocale(m_language);
643 #ifdef HAVE_LIBREADLINE
644 // Allow conditional parsing of the ~/.inputrc file.
646 // OnInitCmdLine() is called from wxApp::OnInit() above,
647 // thus m_appname is already set.
648 rl_readline_name = m_appname;
650 // Allow completion of our commands
651 theCommands = &m_commands;
652 rl_completion_entry_function = &command_completion;
653 #endif
655 return retval;
658 wxString CaMuleExternalConnector::SetLocale(const wxString& language)
660 if (!language.IsEmpty()) {
661 m_language = language;
662 if (m_locale) {
663 delete m_locale;
665 m_locale = new wxLocale;
666 InitLocale(*m_locale, StrLang2wx(language));
669 return m_locale == NULL ? wxString() : m_locale->GetCanonicalName();
672 #if !wxUSE_GUI && defined(__WXMAC__) && !wxCHECK_VERSION(2, 9, 0)
674 #include <wx/apptrait.h> // Do_not_auto_remove
675 #include <wx/stdpaths.h> // Do_not_auto_remove
677 class CaMuleExternalConnectorTraits : public wxConsoleAppTraits
679 public:
680 virtual wxStandardPathsBase& GetStandardPaths()
682 return s_stdPaths;
685 private:
686 static wxStandardPathsCF s_stdPaths;
689 wxStandardPathsCF CaMuleExternalConnectorTraits::s_stdPaths;
691 wxAppTraits* CaMuleExternalConnector::CreateTraits()
693 return new CaMuleExternalConnectorTraits;
696 #endif
698 #if wxUSE_ON_FATAL_EXCEPTION
699 // Gracefully handle fatal exceptions and print backtrace if possible
700 void CaMuleExternalConnector::OnFatalException()
702 /* Print the backtrace */
703 fprintf(stderr, "\n--------------------------------------------------------------------------------\n");
704 fprintf(stderr, "A fatal error has occurred and %s has crashed.\n", m_appname);
705 fprintf(stderr, "Please assist us in fixing this problem by posting the backtrace below in our\n");
706 fprintf(stderr, "'aMule Crashes' forum and include as much information as possible regarding the\n");
707 fprintf(stderr, "circumstances of this crash. The forum is located here:\n");
708 fprintf(stderr, " http://forum.amule.org/index.php?board=67.0\n");
709 fprintf(stderr, "If possible, please try to generate a real backtrace of this crash:\n");
710 fprintf(stderr, " http://wiki.amule.org/wiki/Backtraces\n\n");
711 fprintf(stderr, "----------------------------=| BACKTRACE FOLLOWS: |=----------------------------\n");
712 fprintf(stderr, "Current version is: %s %s\n", m_appname, m_strFullVersion);
713 fprintf(stderr, "Running on: %s\n\n", m_strOSDescription);
715 print_backtrace(1); // 1 == skip this function.
717 fprintf(stderr, "\n--------------------------------------------------------------------------------\n");
719 #endif
721 #ifdef __WXDEBUG__
722 void CaMuleExternalConnector::OnAssertFailure(const wxChar *file, int line, const wxChar *func, const wxChar *cond, const wxChar *msg)
724 #if !defined wxUSE_STACKWALKER || !wxUSE_STACKWALKER
725 wxString errmsg = CFormat( wxT("%s:%s:%d: Assertion '%s' failed. %s") ) % file % func % line % cond % ( msg ? msg : wxT("") );
727 fprintf(stderr, "Assertion failed: %s\n", (const char*)unicode2char(errmsg));
729 // Skip the function-calls directly related to the assert call.
730 fprintf(stderr, "\nBacktrace follows:\n");
731 print_backtrace(3);
732 fprintf(stderr, "\n");
733 #else
734 wxApp::OnAssertFailure(file, line, func, cond, msg);
735 #endif
737 #endif
738 // File_checked_for_headers