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