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. 14// 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. 19// 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 23// 24 25#include "ExternalConnector.h" 26 27#ifdef HAVE_CONFIG_H 28 #include "config.h" // Needed for VERSION and readline detection 29#endif 30 31#include <common/ClientVersion.h> 32#include <common/Format.h> // Needed for CFormat 33#include <wx/tokenzr.h> // For wxStringTokenizer 34 35// For readline 36#ifdef HAVE_LIBREADLINE 37 #if defined(HAVE_READLINE_READLINE_H) 38 #include <readline/readline.h> // Do_not_auto_remove 39 #elif defined(HAVE_READLINE_H) 40 #include <readline.h> // Do_not_auto_remove 41 #else /* !defined(HAVE_READLINE_H) */ 42 extern "C" char *readline (const char*); 43 #endif /* !defined(HAVE_READLINE_H) */ 44#else /* !defined(HAVE_READLINE_READLINE_H) */ 45 /* no readline */ 46#endif /* HAVE_LIBREADLINE */ 47 48// For history 49#ifdef HAVE_READLINE_HISTORY 50 #if defined(HAVE_READLINE_HISTORY_H) 51 #include <readline/history.h> // Do_not_auto_remove 52 #elif defined(HAVE_HISTORY_H) 53 #include <history.h> // Do_not_auto_remove 54 #else /* !defined(HAVE_HISTORY_H) */ 55 extern "C" void add_history (const char*); 56 #endif /* defined(HAVE_READLINE_HISTORY_H) */ 57#else 58 /* no history */ 59#endif /* HAVE_READLINE_HISTORY */ 60 61 62#include <ec/cpp/ECFileConfig.h> // Needed for CECFileConfig 63#include <common/MD5Sum.h> 64 65#ifdef _MSC_VER // silly warnings about deprecated functions 66#pragma warning(disable:4996) 67#endif 68 69//------------------------------------------------------------------- 70 71CCommandTree::~CCommandTree() 72{ 73 DeleteContents(m_subcommands); 74} 75 76 77CCommandTree* CCommandTree::AddCommand(CCommandTree* command) 78{ 79 command->m_parent = this; 80 const wxString& cmd = command->m_command; 81 CmdPos_t it; 82 for (it = m_subcommands.begin(); it != m_subcommands.end(); ++it) { 83 if ((*it)->m_command > cmd) { 84 break; 85 } 86 } 87 m_subcommands.insert(it, command); 88 return command; 89} 90 91 92int CCommandTree::FindCommandId(const wxString& command, wxString& args, wxString& cmdstr) const 93{ 94 wxString cmd = command.BeforeFirst(wxT(' ')).Lower(); 95 for (CmdPosConst_t it = m_subcommands.begin(); it != m_subcommands.end(); ++it) { 96 if ((*it)->m_command.Lower() == cmd) { 97 args = command.AfterFirst(wxT(' ')).Trim(false); 98 return (*it)->FindCommandId(args, args, cmdstr); 99 } 100 } 101 cmdstr = GetFullCommand().Lower(); 102 if (m_params == CMD_PARAM_ALWAYS && args.IsEmpty()) { 103 return CMD_ERR_MUST_HAVE_PARAM; 104 } else if (m_params == CMD_PARAM_NEVER && !args.IsEmpty()) { 105 return CMD_ERR_NO_PARAM; 106 } else { 107 if ((m_cmd_id >= 0) && (m_cmd_id & CMD_DEPRECATED)) { 108 m_app.Show(wxT('\n') + m_verbose + wxT('\n')); 109 return m_cmd_id & ~CMD_DEPRECATED; 110 } else { 111 return m_cmd_id; 112 } 113 } 114} 115 116 117wxString CCommandTree::GetFullCommand() const 118{ 119 wxString cmd = m_command; 120 121 const CCommandTree *parent = m_parent; 122 while (parent && parent->m_parent) { 123 cmd = parent->m_command + wxT(" ") + cmd; 124 parent = parent->m_parent; 125 } 126 127 return cmd; 128} 129 130 131void CCommandTree::PrintHelpFor(const wxString& command) const 132{ 133 wxString cmd = command.BeforeFirst(wxT(' ')).Lower(); 134 if (!cmd.IsEmpty()) { 135 for (CmdPosConst_t it = m_subcommands.begin(); it != m_subcommands.end(); ++it) { 136 if ((*it)->m_command.Lower() == cmd) { 137 (*it)->PrintHelpFor(command.AfterFirst(wxT(' ')).Trim(false)); 138 return; 139 } 140 } 141 if (m_parent) { 142 m_app.Show(CFormat(_("Unknown extension '%s' for the '%s' command.\n")) % command % GetFullCommand()); 143 } else { 144 m_app.Show(CFormat(_("Unknown command '%s'.\n")) % command); 145 } 146 } else { 147 wxString fullcmd = GetFullCommand(); 148 if (!fullcmd.IsEmpty()) { 149 m_app.Show(fullcmd.Upper() + wxT(": ") + wxGetTranslation(m_short) + wxT("\n")); 150 if (!m_verbose.IsEmpty()) { 151 m_app.Show(wxT("\n")); 152 m_app.Show(wxGetTranslation(m_verbose)); 153 } 154 } 155 if (m_params == CMD_PARAM_NEVER) { 156 m_app.Show(_("\nThis command cannot have an argument.\n")); 157 } else if (m_params == CMD_PARAM_ALWAYS) { 158 m_app.Show(_("\nThis command must have an argument.\n")); 159 } 160 if (m_cmd_id == CMD_ERR_INCOMPLETE) { 161 m_app.Show(_("\nThis command is incomplete, you must use one of the extensions below.\n")); 162 } 163 if (!m_subcommands.empty()) { 164 CmdPosConst_t it; 165 int maxlen = 0; 166 if (m_parent) { 167 m_app.Show(_("\nAvailable extensions:\n")); 168 } else { 169 m_app.Show(_("Available commands:\n")); 170 } 171 for (it = m_subcommands.begin(); it != m_subcommands.end(); ++it) { 172 if (!((*it)->m_cmd_id >= 0 && (*it)->m_cmd_id & CMD_DEPRECATED) || m_parent) { 173 int len = (*it)->m_command.Length(); 174 if (len > maxlen) { 175 maxlen = len; 176 } 177 } 178 } 179 maxlen += 4; 180 for (it = m_subcommands.begin(); it != m_subcommands.end(); ++it) { 181 if (!((*it)->m_cmd_id >= 0 && (*it)->m_cmd_id & CMD_DEPRECATED) || m_parent) { 182 m_app.Show((*it)->m_command + wxString(wxT(' '), maxlen - (*it)->m_command.Length()) + wxGetTranslation((*it)->m_short) + wxT("\n")); 183 } 184 } 185 if (!m_parent) { 186 m_app.Show(CFormat(_("\nAll commands are case insensitive.\nType '%s <command>' to get detailed info on <command>.\n")) % wxT("help")); 187 } 188 } 189 } 190 m_app.Show(wxT("\n")); 191} 192 193//------------------------------------------------------------------- 194 195CaMuleExternalConnector::CaMuleExternalConnector() 196 : m_configFile(NULL), 197 m_port(-1), 198 m_KeepQuiet(false), 199 m_Verbose(false), 200 m_interactive(false), 201 m_commands(*this), 202 m_ECClient(NULL), 203 m_InputLine(NULL), 204 m_NeedsConfigSave(false), 205 m_locale(NULL), 206 m_strFullVersion(NULL), 207 m_strOSDescription(NULL) 208{ 209 SetAppName(wxT("aMule")); // Do not change! 210} 211 212CaMuleExternalConnector::~CaMuleExternalConnector() 213{ 214 delete m_configFile; 215 delete m_locale; 216 free(m_strFullVersion); 217 free(m_strOSDescription); 218} 219 220void CaMuleExternalConnector::OnInitCommandSet() 221{ 222 m_commands.AddCommand(wxT("Quit"), CMD_ID_QUIT, wxTRANSLATE("Exits from the application."), wxEmptyString); 223 m_commands.AddCommand(wxT("Exit"), CMD_ID_QUIT, wxTRANSLATE("Exits from the application."), wxEmptyString); 224 m_commands.AddCommand(wxT("Help"), CMD_ID_HELP, wxTRANSLATE("Show help."), 225 /* TRANSLATORS: 226 Do not translate the word 'help', it is a command to the program! */ 227 wxTRANSLATE("To get help on a command, type 'help <command>'.\nTo get the full command list type 'help'.\n")); 228} 229 230void CaMuleExternalConnector::Show(const wxString &s) 231{ 232 if( !m_KeepQuiet ) { 233 printf("%s", (const char *)unicode2char(s)); 234#ifdef __WXMSW__ 235 fflush(stdout); 236#endif 237 } 238} 239 240void CaMuleExternalConnector::ShowGreet() 241{ 242 wxString text = GetGreetingTitle(); 243 int len = text.Length(); 244 Show(wxT('\n') + wxString(wxT('-'), 22 + len) + wxT('\n')); 245 Show(wxT('|') + wxString(wxT(' '), 10) + text + wxString(wxT(' '), 10) + wxT('|') + wxT('\n')); 246 Show(wxString(wxT('-'), 22 + len) + wxT('\n')); 247 // Do not merge the line below, or translators could translate "Help" 248 Show(CFormat(_("\nUse '%s' for command list\n\n")) % wxT("Help")); 249} 250 251void CaMuleExternalConnector::Process_Answer(const wxString& answer) 252{ 253 wxStringTokenizer tokens(answer, wxT("\n")); 254 while ( tokens.HasMoreTokens() ) { 255 Show(wxT(" > ") + tokens.GetNextToken() + wxT("\n")); 256 } 257} 258 259bool CaMuleExternalConnector::Parse_Command(const wxString& buffer) 260{ 261 wxString cmd; 262 wxStringTokenizer tokens(buffer); 263 while (tokens.HasMoreTokens()) { 264 cmd += tokens.GetNextToken() + wxT(' '); 265 } 266 cmd.Trim(false); 267 cmd.Trim(true); 268 int cmd_ID = GetIDFromString(cmd); 269 if ( cmd_ID >= 0 ) { 270 cmd_ID = ProcessCommand(cmd_ID); 271 } 272 wxString error; 273 switch (cmd_ID) { 274 case CMD_ID_HELP: 275 m_commands.PrintHelpFor(GetCmdArgs()); 276 break; 277 case CMD_ERR_SYNTAX: 278 error = _("Syntax error!"); 279 break; 280 case CMD_ERR_PROCESS_CMD: 281 Show(_("Error processing command - should never happen! Report bug, please\n")); 282 break; 283 case CMD_ERR_NO_PARAM: 284 error = _("This command should not have any parameters."); 285 break; 286 case CMD_ERR_MUST_HAVE_PARAM: 287 error = _("This command must have a parameter."); 288 break; 289 case CMD_ERR_INVALID_ARG: 290 error = _("Invalid argument."); 291 break; 292 case CMD_ERR_INCOMPLETE: 293 error = _("This is an incomplete command."); 294 break; 295 } 296 if (!error.IsEmpty()) { 297 Show(error + wxT('\n')); 298 wxString helpStr(wxT("help")); 299 if (!GetLastCmdStr().IsEmpty()) { 300 helpStr << wxT(' ') << GetLastCmdStr(); 301 } 302 Show(CFormat(_("Type '%s' to get more help.\n")) % helpStr); 303 } 304 return cmd_ID == CMD_ID_QUIT; 305} 306 307void CaMuleExternalConnector::GetCommand(const wxString &prompt, char* buffer, size_t buffer_size) 308{ 309#ifdef HAVE_LIBREADLINE 310 char *text = readline(unicode2char(prompt + wxT("$ "))); 311 if (text && *text && 312 (m_InputLine == 0 || strcmp(text,m_InputLine) != 0)) { 313 add_history (text); 314 } 315 if (m_InputLine) 316 free(m_InputLine); 317 m_InputLine = text; 318#else 319 Show(prompt + wxT("$ ")); 320 const char *text = fgets(buffer, buffer_size, stdin); // == buffer if ok, NULL if eof 321#endif /* HAVE_LIBREADLINE */ 322 if ( text ) { 323 size_t len = strlen(text); 324 if (len > buffer_size - 1) { 325 len = buffer_size - 1; 326 } 327 if (buffer != text) { 328 strncpy(buffer, text, len); 329 } 330 buffer[len] = 0; 331 } else { 332 strncpy(buffer, "quit", buffer_size); 333 } 334} 335 336void CaMuleExternalConnector::TextShell(const wxString &prompt) 337{ 338 char buffer[2048]; 339 wxString buf; 340 341 bool The_End = false; 342 do { 343 GetCommand(prompt, buffer, sizeof buffer); 344 buf = char2unicode(buffer); 345 The_End = Parse_Command(buf); 346 } while ((!The_End) && (m_ECClient->IsSocketConnected())); 347} 348 349void CaMuleExternalConnector::ConnectAndRun(const wxString &ProgName, const wxString& ProgVersion) 350{ 351 if (m_NeedsConfigSave) { 352 SaveConfigFile(); 353 return; 354 } 355 356 #ifdef SVNDATE 357 Show(CFormat(_("This is %s %s %s\n")) % wxString::FromAscii(m_appname) % wxT(VERSION) % wxT(SVNDATE)); 358 #else 359 Show(CFormat(_("This is %s %s\n")) % wxString::FromAscii(m_appname) % wxT(VERSION)); 360 #endif 361 362 // HostName, Port and Password 363 if ( m_password.IsEmpty() ) { 364 wxString pass_plain; 365 #ifndef __WXMSW__ 366 pass_plain = char2unicode(getpass("Enter password for mule connection: ")); 367 #else 368 //#warning This way, pass enter is not hidden on windows. Bad thing. 369 char temp_str[512]; 370 fflush(stdin); 371 printf("Enter password for mule connection: \n"); 372 fflush(stdout); 373 fgets(temp_str, 512, stdin); 374 temp_str[strlen(temp_str)-1] = '\0'; 375 pass_plain = char2unicode(temp_str); 376 #endif 377 wxCHECK2(m_password.Decode(MD5Sum(pass_plain).GetHash()), /* Do nothing. */ ); 378 // MD5 hash for an empty string, according to rfc1321. 379 if (m_password.Encode() == wxT("D41D8CD98F00B204E9800998ECF8427E")) { 380 m_password.Clear(); 381 } 382 383 // Clear plain-text password 384 pass_plain = wxT("01234567890123456789"); 385 } 386 387 if (!m_password.IsEmpty()) { 388 389 // Create the socket 390 Show(_("\nCreating client...\n")); 391 m_ECClient = new CRemoteConnect(NULL); 392 m_ECClient->SetCapabilities(m_ZLIB, true, false); // ZLIB, UTF8 numbers, notification 393 394 // ConnectToCore is blocking since m_ECClient was initialized with NULL 395 if (!m_ECClient->ConnectToCore(m_host, m_port, wxT("foobar"), m_password.Encode(), ProgName, ProgVersion)) { 396 // no connection => close gracefully 397 if (!m_ECClient->GetServerReply().IsEmpty()) { 398 Show(CFormat(wxT("%s\n")) % m_ECClient->GetServerReply()); 399 } 400 Show(CFormat(_("Connection Failed. Unable to connect to %s:%d\n")) % m_host % m_port); 401 } else { 402 // Authenticate ourselves 403 // ConnectToCore() already authenticated for us. 404 //m_ECClient->ConnectionEstablished(); 405 Show(m_ECClient->GetServerReply()+wxT("\n")); 406 if (m_ECClient->IsSocketConnected()) { 407 if (m_interactive) { 408 ShowGreet(); 409 } 410 Pre_Shell(); 411 TextShell(ProgName); 412 Post_Shell(); 413 if (m_interactive) { 414 Show(CFormat(_("\nOk, exiting %s...\n")) % ProgName); 415 } 416 } 417 } 418 m_ECClient->DestroySocket(); 419 } else { 420 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")); 421 } 422} 423 424void CaMuleExternalConnector::OnInitCmdLine(wxCmdLineParser& parser, const char* appname) 425{ 426 m_appname = appname; 427 428 parser.AddSwitch(wxEmptyString, wxT("help"), 429 _("Show this help text."), 430 wxCMD_LINE_PARAM_OPTIONAL); 431 parser.AddOption(wxT("h"), wxT("host"), 432 _("Host where aMule is running. (default: localhost)"), 433 wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL); 434 parser.AddOption(wxT("p"), wxT("port"), 435 _("aMule's port for External Connection. (default: 4712)"), 436 wxCMD_LINE_VAL_NUMBER, wxCMD_LINE_PARAM_OPTIONAL); 437 parser.AddOption(wxT("P"), wxT("password"), 438 _("External Connection password."), 439 wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL); 440 parser.AddOption(wxT("f"), wxT("config-file"), 441 _("Read configuration from file."), 442 wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL); 443 parser.AddSwitch(wxT("q"), wxT("quiet"), 444 _("Do not print any output to stdout."), 445 wxCMD_LINE_PARAM_OPTIONAL); 446 parser.AddSwitch(wxT("v"), wxT("verbose"), 447 _("Be verbose - show also debug messages."), 448 wxCMD_LINE_PARAM_OPTIONAL); 449 parser.AddOption(wxT("l"), wxT("locale"), 450 _("Sets program locale (language)."), 451 wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL); 452 parser.AddSwitch(wxT("w"), wxT("write-config"), 453 _("Write command line options to config file."), 454 wxCMD_LINE_PARAM_OPTIONAL); 455 parser.AddOption(wxEmptyString, wxT("create-config-from"), 456 _("Creates config file based on aMule's config file."), 457 wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL); 458 parser.AddSwitch(wxEmptyString, wxT("version"), 459 _("Print program version."), 460 wxCMD_LINE_PARAM_OPTIONAL); 461} 462 463bool CaMuleExternalConnector::OnCmdLineParsed(wxCmdLineParser& parser) 464{ 465 if (parser.Found(wxT("version"))) { 466 printf("%s %s\n", m_appname, (const char *)unicode2char(GetMuleVersion())); 467 return false; 468 } 469 470 if (!parser.Found(wxT("config-file"), &m_configFileName)) { 471 m_configFileName = GetConfigDir() + wxT("remote.conf"); 472 } 473 474 wxString aMuleConfigFile; 475 if (parser.Found(wxT("create-config-from"), &aMuleConfigFile)) { 476 aMuleConfigFile = FinalizeFilename(aMuleConfigFile); 477 if (!::wxFileExists(aMuleConfigFile)) { 478 fprintf(stderr, "%s\n", (const char *)unicode2char(wxT("FATAL ERROR: File does not exist: ") + aMuleConfigFile)); 479 exit(1); 480 } 481 CECFileConfig aMuleConfig(aMuleConfigFile); 482 LoadAmuleConfig(aMuleConfig); 483 SaveConfigFile(); 484 m_configFile->Flush(); 485 exit(0); 486 } 487 488 LoadConfigFile(); 489 490 if ( !parser.Found(wxT("host"), &m_host) ) { 491 if ( m_host.IsEmpty() ) { 492 m_host = wxT("localhost"); 493 } 494 } 495 496 long port; 497 if (parser.Found(wxT("port"), &port)) { 498 m_port = port; 499 } 500 501 wxString pass_plain; 502 if (parser.Found(wxT("password"), &pass_plain)) { 503 if (!pass_plain.IsEmpty()) { 504 m_password.Decode(MD5Sum(pass_plain).GetHash()); 505 } else { 506 m_password.Clear(); 507 } 508 } 509 510 if (parser.Found(wxT("write-config"))) { 511 m_NeedsConfigSave = true; 512 } 513 514 parser.Found(wxT("locale"), &m_language); 515 516 if (parser.Found(wxT("help"))) { 517 parser.Usage(); 518 return false; 519 } 520 521 m_KeepQuiet = parser.Found(wxT("quiet")); 522 m_Verbose = parser.Found(wxT("verbose")); 523 524 return true; 525} 526 527void CaMuleExternalConnector::LoadAmuleConfig(CECFileConfig& cfg) 528{ 529 m_host = wxT("localhost"); 530 m_port = cfg.Read(wxT("/ExternalConnect/ECPort"), 4712l); 531 cfg.ReadHash(wxT("/ExternalConnect/ECPassword"), &m_password); 532 m_language = cfg.Read(wxT("/eMule/Language"), wxEmptyString); 533} 534 535 536void CaMuleExternalConnector::LoadConfigFile() 537{ 538 if (!m_configFile) { 539 m_configFile = new CECFileConfig(m_configFileName); 540 } 541 if (m_configFile) { 542 m_language = m_configFile->Read(wxT("/Locale"), wxEmptyString); 543 m_host = m_configFile->Read(wxT("/EC/Host"), wxEmptyString); 544 m_port = m_configFile->Read(wxT("/EC/Port"), 4712l); 545 m_configFile->ReadHash(wxT("/EC/Password"), &m_password); 546 m_ZLIB = m_configFile->Read(wxT("/EC/ZLIB"), 1l) != 0; 547 } 548} 549 550void CaMuleExternalConnector::SaveConfigFile() 551{ 552 if (!wxFileName::DirExists(GetConfigDir())) { 553 wxFileName::Mkdir(GetConfigDir()); 554 } 555 if (!m_configFile) { 556 m_configFile = new CECFileConfig(m_configFileName); 557 } 558 if (m_configFile) { 559 m_configFile->Write(wxT("/Locale"), m_language); 560 m_configFile->Write(wxT("/EC/Host"), m_host); 561 m_configFile->Write(wxT("/EC/Port"), m_port); 562 m_configFile->WriteHash(wxT("/EC/Password"), m_password); 563 } 564} 565 566bool CaMuleExternalConnector::OnInit() 567{ 568#ifndef __WXMSW__ 569 #if wxUSE_ON_FATAL_EXCEPTION 570 // catch fatal exceptions 571 wxHandleFatalExceptions(true); 572 #endif 573#endif 574 575 m_strFullVersion = strdup((const char *)unicode2char(GetMuleVersion())); 576 m_strOSDescription = strdup((const char *)unicode2char(wxGetOsDescription())); 577 578 // Handle uncaught exceptions 579 InstallMuleExceptionHandler(); 580 581 bool retval = wxApp::OnInit(); 582 OnInitCommandSet(); 583 InitCustomLanguages(); 584 SetLocale(m_language); 585 return retval; 586} 587 588wxString CaMuleExternalConnector::SetLocale(const wxString& language) 589{ 590 if (!language.IsEmpty()) { 591 m_language = language; 592 if (m_locale) { 593 delete m_locale; 594 } 595 m_locale = new wxLocale; 596 InitLocale(*m_locale, StrLang2wx(language)); 597 } 598 599 return m_locale == NULL ? wxString() : m_locale->GetCanonicalName(); 600} 601 602#if !wxUSE_GUI && defined(__WXMAC__) && !wxCHECK_VERSION(2, 9, 0) 603 604#include <wx/apptrait.h> // Do_not_auto_remove 605#include <wx/stdpaths.h> // Do_not_auto_remove 606 607class CaMuleExternalConnectorTraits : public wxConsoleAppTraits 608{ 609public: 610 virtual wxStandardPathsBase& GetStandardPaths() 611 { 612 return s_stdPaths; 613 } 614 615private: 616 static wxStandardPathsCF s_stdPaths; 617}; 618 619wxStandardPathsCF CaMuleExternalConnectorTraits::s_stdPaths; 620 621wxAppTraits* CaMuleExternalConnector::CreateTraits() 622{ 623 return new CaMuleExternalConnectorTraits; 624} 625 626#endif 627 628#if wxUSE_ON_FATAL_EXCEPTION 629// Gracefully handle fatal exceptions and print backtrace if possible 630void CaMuleExternalConnector::OnFatalException() 631{ 632 /* Print the backtrace */ 633 fprintf(stderr, "\n--------------------------------------------------------------------------------\n"); 634 fprintf(stderr, "A fatal error has occurred and %s has crashed.\n", m_appname); 635 fprintf(stderr, "Please assist us in fixing this problem by posting the backtrace below in our\n"); 636 fprintf(stderr, "'aMule Crashes' forum and include as much information as possible regarding the\n"); 637 fprintf(stderr, "circumstances of this crash. The forum is located here:\n"); 638 fprintf(stderr, " http://forum.amule.org/index.php?board=67.0\n"); 639 fprintf(stderr, "If possible, please try to generate a real backtrace of this crash:\n"); 640 fprintf(stderr, " http://wiki.amule.org/index.php/Backtraces\n\n"); 641 fprintf(stderr, "----------------------------=| BACKTRACE FOLLOWS: |=----------------------------\n"); 642 fprintf(stderr, "Current version is: %s %s\n", m_appname, m_strFullVersion); 643 fprintf(stderr, "Running on: %s\n\n", m_strOSDescription); 644 645 print_backtrace(1); // 1 == skip this function. 646 647 fprintf(stderr, "\n--------------------------------------------------------------------------------\n"); 648} 649#endif 650 651#ifdef __WXDEBUG__ 652void CaMuleExternalConnector::OnAssertFailure(const wxChar *file, int line, const wxChar *func, const wxChar *cond, const wxChar *msg) 653{ 654#if !defined wxUSE_STACKWALKER || !wxUSE_STACKWALKER 655 wxString errmsg = CFormat( wxT("%s:%s:%d: Assertion '%s' failed. %s") ) % file % func % line % cond % ( msg ? msg : wxT("") ); 656 657 fprintf(stderr, "Assertion failed: %s\n", (const char*)unicode2char(errmsg)); 658 659 // Skip the function-calls directly related to the assert call. 660 fprintf(stderr, "\nBacktrace follows:\n"); 661 print_backtrace(3); 662 fprintf(stderr, "\n"); 663#else 664 wxApp::OnAssertFailure(file, line, func, cond, msg); 665#endif 666} 667#endif 668// File_checked_for_headers 669