1//
2// This file is part of the aMule Project.
3//
4// Copyright (c) 2003-2011 Angel Vidal ( kry@amule.org )
5// Copyright (c) 2003-2011 aMule Team ( admin@amule.org / http://www.amule.org )
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.
10//
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.
15//
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
24//
25
26
27#ifdef HAVE_CONFIG_H
28	#include "config.h"		// Needed for VERSION
29#endif
30
31#include <common/ClientVersion.h>
32
33#include "TextClient.h"
34
35#ifndef __WXMSW__
36	#include <unistd.h> // Do_not_auto_remove
37#endif
38
39
40//-------------------------------------------------------------------
41
42
43//-------------------------------------------------------------------
44
45#include <ec/cpp/ECSpecialTags.h>
46
47#include <wx/tokenzr.h>
48
49#include <common/Format.h>		// Needed for CFormat
50#include "OtherFunctions.h"
51#include "KnownFile.h"			// Needed for Priority Levels
52#include "DataToText.cpp"		// Needed for PriorityToStr
53
54#define APP_INIT_SIZE_X 640
55#define APP_INIT_SIZE_Y 480
56
57#define theApp (*((CamulecmdApp*)wxTheApp))
58
59//-------------------------------------------------------------------
60
61enum {
62	CMD_ID_STATUS,
63	CMD_ID_RESUME,
64	CMD_ID_PAUSE,
65	CMD_ID_PRIORITY_LOW,
66	CMD_ID_PRIORITY_NORMAL,
67	CMD_ID_PRIORITY_HIGH,
68	CMD_ID_PRIORITY_AUTO,
69	CMD_ID_CANCEL,
70	CMD_ID_CONNECT,
71	CMD_ID_CONNECT_ED2K,
72	CMD_ID_CONNECT_KAD,
73	CMD_ID_DISCONNECT,
74	CMD_ID_DISCONNECT_ED2K,
75	CMD_ID_DISCONNECT_KAD,
76	CMD_ID_RELOAD_SHARED,
77	CMD_ID_RELOAD_IPFILTER_LOCAL,
78	CMD_ID_RELOAD_IPFILTER_NET,
79	CMD_ID_SET_IPFILTER_ON,
80	CMD_ID_SET_IPFILTER_OFF,
81 	CMD_ID_SET_IPFILTER_CLIENTS_ON,
82	CMD_ID_SET_IPFILTER_CLIENTS_OFF,
83 	CMD_ID_SET_IPFILTER_SERVERS_ON,
84	CMD_ID_SET_IPFILTER_SERVERS_OFF,
85	CMD_ID_SET_IPFILTER_LEVEL,
86 	CMD_ID_GET_IPFILTER,
87 	CMD_ID_GET_IPFILTER_STATE,
88	CMD_ID_GET_IPFILTER_STATE_CLIENTS,
89	CMD_ID_GET_IPFILTER_STATE_SERVERS,
90 	CMD_ID_GET_IPFILTER_LEVEL,
91	CMD_ID_SHOW_UL,
92	CMD_ID_SHOW_DL,
93	CMD_ID_SHOW_LOG,
94	CMD_ID_SHOW_SERVERS,
95	CMD_ID_SHOW_SHARED,
96	CMD_ID_RESET_LOG,
97	CMD_ID_SHUTDOWN,
98 	CMD_ID_ADDLINK,
99 	CMD_ID_SET_BWLIMIT_UP,
100 	CMD_ID_SET_BWLIMIT_DOWN,
101 	CMD_ID_GET_BWLIMITS,
102	CMD_ID_STATTREE,
103	CMD_ID_SEARCH,
104	CMD_ID_SEARCH_GLOBAL,
105	CMD_ID_SEARCH_LOCAL,
106	CMD_ID_SEARCH_KAD,
107	CMD_ID_SEARCH_RESULTS,
108	CMD_ID_SEARCH_PROGRESS,
109	CMD_ID_DOWNLOAD,
110	// IDs for deprecated commands
111	CMD_ID_SET_IPFILTER
112
113};
114
115// method to create a SearchFile
116SearchFile::SearchFile(CEC_SearchFile_Tag *tag)
117{
118	nHash = tag->FileHash();
119	sHash = nHash.Encode();
120	sFileName = tag->FileName();
121	lFileSize = tag->SizeFull();
122	lSourceCount = tag->SourceCount();
123	bPresent = tag->AlreadyHave();
124}
125
126//-------------------------------------------------------------------
127IMPLEMENT_APP (CamulecmdApp)
128//-------------------------------------------------------------------
129
130void CamulecmdApp::OnInitCmdLine(wxCmdLineParser& parser)
131{
132	CaMuleExternalConnector::OnInitCmdLine(parser, "amulecmd");
133	parser.AddOption(wxT("c"), wxT("command"),
134		_("Execute <str> and exit."),
135		wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL);
136}
137
138bool CamulecmdApp::OnCmdLineParsed(wxCmdLineParser& parser)
139{
140	m_HasCmdOnCmdLine = parser.Found(wxT("command"), &m_CmdString);
141	if (m_CmdString.Lower().StartsWith(wxT("help")))
142	{
143		OnInitCommandSet();
144		printf("%s %s\n", m_appname, (const char *)unicode2char(GetMuleVersion()));
145		Parse_Command(m_CmdString);
146		exit(0);
147	}
148	m_interactive = !m_HasCmdOnCmdLine;
149	return CaMuleExternalConnector::OnCmdLineParsed(parser);
150}
151
152void CamulecmdApp::TextShell(const wxString& prompt)
153{
154	if (m_HasCmdOnCmdLine)
155		Parse_Command(m_CmdString);
156	else
157		CaMuleExternalConnector::TextShell(prompt);
158}
159
160int CamulecmdApp::ProcessCommand(int CmdId)
161{
162	wxString args = GetCmdArgs();
163	CECPacket *request = 0;
164	std::list<CECPacket *> request_list;
165	int tmp_int = 0;
166	EC_SEARCH_TYPE search_type = EC_SEARCH_KAD;
167
168	// Implementation of the deprecated command 'SetIPFilter'.
169	if (CmdId == CMD_ID_SET_IPFILTER) {
170		if ( ! args.IsEmpty() ) {
171			if (args.IsSameAs(wxT("ON"), false)) {
172				CmdId = CMD_ID_SET_IPFILTER_ON;
173			} else if (args.IsSameAs(wxT("OFF"), false)) {
174				CmdId = CMD_ID_SET_IPFILTER_OFF;
175			} else {
176				return CMD_ERR_INVALID_ARG;
177			}
178		} else {
179			CmdId = CMD_ID_GET_IPFILTER_STATE;
180		}
181	}
182
183	switch (CmdId) {
184		case CMD_ID_STATUS:
185			request_list.push_back(new CECPacket(EC_OP_STAT_REQ, EC_DETAIL_CMD));
186			break;
187
188		case CMD_ID_SHUTDOWN:
189			request_list.push_back(new CECPacket(EC_OP_SHUTDOWN));
190			break;
191
192 		case CMD_ID_CONNECT:
193			if ( !args.IsEmpty() ) {
194				unsigned int ip[4];
195				unsigned int port;
196				// Not much we can do against this unicode2char.
197				int result = sscanf(unicode2char(args), "%d.%d.%d.%d:%d", &ip[0], &ip[1], &ip[2], &ip[3], &port);
198				if (result != 5) {
199					// Try to resolve DNS -- good for dynamic IP servers
200					wxString serverName(args.BeforeFirst(wxT(':')));
201					long lPort;
202					bool ok = args.AfterFirst(wxT(':')).ToLong(&lPort);
203					port = (unsigned int)lPort;
204					wxIPV4address a;
205					a.Hostname(serverName);
206					a.Service(port);
207					result = sscanf(unicode2char(a.IPAddress()), "%d.%d.%d.%d", &ip[0], &ip[1], &ip[2], &ip[3]);
208					if (serverName.IsEmpty() || !ok || (result != 4)) {
209						Show(_("Invalid IP format. Use xxx.xxx.xxx.xxx:xxxx\n"));
210						return 0;
211					}
212				}
213				EC_IPv4_t addr;
214				addr.m_ip[0] = ip[0];
215				addr.m_ip[1] = ip[1];
216				addr.m_ip[2] = ip[2];
217				addr.m_ip[3] = ip[3];
218				addr.m_port = port;
219				request = new CECPacket(EC_OP_SERVER_CONNECT);
220				request->AddTag(CECTag(EC_TAG_SERVER, addr));
221				request_list.push_back(request);
222			} else {
223				request_list.push_back(new CECPacket(EC_OP_CONNECT));
224			}
225			break;
226
227		case CMD_ID_CONNECT_ED2K:
228			request_list.push_back(new CECPacket(EC_OP_SERVER_CONNECT));
229			break;
230
231 		case CMD_ID_CONNECT_KAD:
232			request_list.push_back(new CECPacket(EC_OP_KAD_START));
233			break;
234
235 		case CMD_ID_DISCONNECT:
236			request_list.push_back(new CECPacket(EC_OP_DISCONNECT));
237			break;
238
239		case CMD_ID_DISCONNECT_ED2K:
240			request_list.push_back(new CECPacket(EC_OP_SERVER_DISCONNECT));
241			break;
242
243 		case CMD_ID_DISCONNECT_KAD:
244			request_list.push_back(new CECPacket(EC_OP_KAD_STOP));
245			break;
246
247		case CMD_ID_RELOAD_SHARED:
248			request_list.push_back(new CECPacket(EC_OP_SHAREDFILES_RELOAD));
249			break;
250
251		case CMD_ID_RELOAD_IPFILTER_LOCAL:
252			request_list.push_back(new CECPacket(EC_OP_IPFILTER_RELOAD));
253			break;
254
255		case CMD_ID_RELOAD_IPFILTER_NET:
256			request = new CECPacket(EC_OP_IPFILTER_UPDATE);
257			request->AddTag(EC_TAG_STRING, args);
258			request_list.push_back(request);
259			break;
260
261		case CMD_ID_SET_IPFILTER_ON:
262		case CMD_ID_SET_IPFILTER_CLIENTS_ON:
263		case CMD_ID_SET_IPFILTER_SERVERS_ON:
264			tmp_int = 1;
265		case CMD_ID_SET_IPFILTER_OFF:
266		case CMD_ID_SET_IPFILTER_CLIENTS_OFF:
267		case CMD_ID_SET_IPFILTER_SERVERS_OFF:
268			{
269				if (CmdId == CMD_ID_SET_IPFILTER_CLIENTS_ON || CmdId == CMD_ID_SET_IPFILTER_CLIENTS_OFF) {
270					CmdId = CMD_ID_GET_IPFILTER_STATE_CLIENTS;
271				} else if (CmdId == CMD_ID_SET_IPFILTER_SERVERS_ON || CmdId == CMD_ID_SET_IPFILTER_SERVERS_OFF) {
272					CmdId = CMD_ID_GET_IPFILTER_STATE_SERVERS;
273				} else {
274					CmdId = CMD_ID_GET_IPFILTER_STATE;
275				}
276
277				request = new CECPacket(EC_OP_SET_PREFERENCES);
278				CECEmptyTag prefs(EC_TAG_PREFS_SECURITY);
279				if (CmdId != CMD_ID_GET_IPFILTER_STATE_SERVERS) {
280					prefs.AddTag(CECTag(EC_TAG_IPFILTER_CLIENTS, (uint8)tmp_int));
281				}
282				if (CmdId != CMD_ID_GET_IPFILTER_STATE_CLIENTS) {
283					prefs.AddTag(CECTag(EC_TAG_IPFILTER_SERVERS, (uint8)tmp_int));
284				}
285				request->AddTag(prefs);
286				request_list.push_back(request);
287			}
288		case CMD_ID_GET_IPFILTER:
289		case CMD_ID_GET_IPFILTER_STATE:
290		case CMD_ID_GET_IPFILTER_STATE_CLIENTS:
291		case CMD_ID_GET_IPFILTER_STATE_SERVERS:
292			request = new CECPacket(EC_OP_GET_PREFERENCES);
293			request->AddTag(CECTag(EC_TAG_SELECT_PREFS, (uint32)EC_PREFS_SECURITY));
294			request_list.push_back(request);
295			break;
296
297		case CMD_ID_SET_IPFILTER_LEVEL:
298			if (!args.IsEmpty()) // This 'if' must stay as long as we support the deprecated 'IPLevel' command.
299			{
300				unsigned long int level = 0;
301				if (args.ToULong(&level) == true && level < 256) {
302					request = new CECPacket(EC_OP_SET_PREFERENCES);
303					CECEmptyTag prefs(EC_TAG_PREFS_SECURITY);
304					prefs.AddTag(CECTag(EC_TAG_IPFILTER_LEVEL, (uint8)level));
305					request->AddTag(prefs);
306					request_list.push_back(request);
307				} else {
308					return CMD_ERR_INVALID_ARG;
309				}
310			}
311			CmdId = CMD_ID_GET_IPFILTER_LEVEL;
312		case CMD_ID_GET_IPFILTER_LEVEL:
313			request = new CECPacket(EC_OP_GET_PREFERENCES);
314			request->AddTag(CECTag(EC_TAG_SELECT_PREFS, (uint32)EC_PREFS_SECURITY));
315			request_list.push_back(request);
316			break;
317
318		case CMD_ID_PAUSE:
319		case CMD_ID_CANCEL:
320		case CMD_ID_RESUME:
321		{
322			if ( args.IsEmpty() ) {
323				Show(_("This command requires an argument. Valid arguments: 'all', filename, or a number.\n"));
324				return 0;
325			} else {
326				wxStringTokenizer argsTokenizer(args);
327				wxString token;
328				CMD4Hash hash;
329
330				// Grab the entire dl queue right away
331				CECPacket request_all(EC_OP_GET_DLOAD_QUEUE, EC_DETAIL_CMD);
332				const CECPacket *reply_all = SendRecvMsg_v2(&request_all);
333
334				if (reply_all) {
335					switch(CmdId) {
336						case CMD_ID_PAUSE:
337								request = new CECPacket(EC_OP_PARTFILE_PAUSE); break;
338						case CMD_ID_CANCEL:
339								request = new CECPacket(EC_OP_PARTFILE_DELETE); break;
340						case CMD_ID_RESUME:
341								request = new CECPacket(EC_OP_PARTFILE_RESUME); break;
342						default: wxFAIL;
343					}
344
345					// We loop through all the arguments
346					while(argsTokenizer.HasMoreTokens()) {
347						token=argsTokenizer.GetNextToken();
348
349						// If the user requested all, then we select all files and exit the loop
350						// since there is little point to add anything more to "everything"
351						if( token == wxT("all") ) {
352							for (CECPacket::const_iterator it = reply_all->begin(); it != reply_all->end(); it++) {
353								CEC_PartFile_Tag *tag = (CEC_PartFile_Tag *) & *it;
354								request->AddTag(CECTag(EC_TAG_PARTFILE, tag->FileHash()));
355							}
356							break;
357						} else if ( hash.Decode(token.Trim(false).Trim(true)) ) {
358							if ( !hash.IsEmpty() ) {
359								Show(_("Processing by hash: "+token+wxT("\n")));
360								request->AddTag(CECTag(EC_TAG_PARTFILE, hash));
361							}
362						} else {
363							 // Go through the dl queue and look at each filename
364							for (CECPacket::const_iterator it = reply_all->begin(); it != reply_all->end(); it++) {
365								CEC_PartFile_Tag *tag = (CEC_PartFile_Tag *) & *it;
366								wxString partmetname = tag->PartMetName();
367
368								// We check for filename, XXX.pat.met, XXX.part, XXX
369								if( tag->FileName() == token ||
370									partmetname == token ||
371									partmetname.Truncate(partmetname.Len()-4) == token ||
372									partmetname.Truncate(partmetname.Len()-5) == token) {
373									Show(_("Processing by filename: "+token+wxT("\n")));
374									request->AddTag(CECTag(EC_TAG_PARTFILE, tag->FileHash()));
375								}
376							}
377						} // End of filename check else
378					} // End of argument token loop
379
380				request_list.push_back(request);
381
382				delete reply_all;
383
384				} // End of dl queue processing
385
386			} // end of command processing
387			break;
388		}
389
390		case CMD_ID_PRIORITY_LOW:
391		case CMD_ID_PRIORITY_NORMAL:
392		case CMD_ID_PRIORITY_HIGH:
393		case CMD_ID_PRIORITY_AUTO:
394			if ( args.IsEmpty() ) {
395				Show(_("This command requires an argument. Valid arguments: a file hash.\n"));
396				return 0;
397			} else {
398				CMD4Hash hash;
399				if (hash.Decode(args.Trim(false).Trim(true))) {
400					if (!hash.IsEmpty()) {
401						request = new CECPacket(EC_OP_PARTFILE_PRIO_SET);
402						CECTag hashtag(EC_TAG_PARTFILE, hash);
403						switch(CmdId) {
404							case CMD_ID_PRIORITY_LOW:
405								hashtag.AddTag(CECTag(EC_TAG_PARTFILE_PRIO, (uint8)PR_LOW));
406								break;
407							case CMD_ID_PRIORITY_NORMAL:
408								hashtag.AddTag(CECTag(EC_TAG_PARTFILE_PRIO, (uint8)PR_NORMAL));
409								break;
410							case CMD_ID_PRIORITY_HIGH:
411								hashtag.AddTag(CECTag(EC_TAG_PARTFILE_PRIO, (uint8)PR_HIGH));
412								break;
413							case CMD_ID_PRIORITY_AUTO:
414								hashtag.AddTag(CECTag(EC_TAG_PARTFILE_PRIO, (uint8)PR_AUTO));
415								break;
416							default: wxFAIL;
417						}
418						request->AddTag(hashtag);
419						request_list.push_back(request);
420					} else {
421						Show(_("Not a valid number\n"));
422						return 0;
423					}
424				} else {
425						Show(_("Not a valid hash (length should be exactly 32 chars)\n"));
426						return 0;
427				}
428			}
429			break;
430
431		case CMD_ID_SHOW_UL:
432			request_list.push_back(new CECPacket(EC_OP_GET_ULOAD_QUEUE));
433			break;
434
435		case CMD_ID_SHOW_DL:
436			request_list.push_back(new CECPacket(EC_OP_GET_DLOAD_QUEUE));
437			break;
438
439		case CMD_ID_SHOW_LOG:
440			request_list.push_back(new CECPacket(EC_OP_GET_LOG));
441			break;
442
443		case CMD_ID_SHOW_SERVERS:
444			request_list.push_back(new CECPacket(EC_OP_GET_SERVER_LIST, EC_DETAIL_CMD));
445			break;
446
447		case CMD_ID_RESET_LOG:
448			request_list.push_back(new CECPacket(EC_OP_RESET_LOG));
449			break;
450
451		case CMD_ID_ADDLINK:
452			if (args.StartsWith(wxT("ed2k://"))) {
453				//aMule doesn't like AICH links without |/| in front of h=
454				if (args.Find(wxT("|h=")) > -1 && args.Find(wxT("|/|h=")) == -1) {
455					args.Replace(wxT("|h="),wxT("|/|h="));
456				}
457				// repair links where | is replaced with %7C (Firefox)
458				if (args.StartsWith(wxT("ed2k://%7C"))) {
459					args.Replace(wxT("%7C"),wxT("|"));
460				}
461			}
462			request = new CECPacket(EC_OP_ADD_LINK);
463			request->AddTag(CECTag(EC_TAG_STRING, args));
464			request_list.push_back(request);
465			break;
466
467		case CMD_ID_SET_BWLIMIT_UP:
468			tmp_int = EC_TAG_CONN_MAX_UL - EC_TAG_CONN_MAX_DL;
469		case CMD_ID_SET_BWLIMIT_DOWN:
470			tmp_int += EC_TAG_CONN_MAX_DL;
471			{
472				unsigned long int limit;
473				if (args.ToULong(&limit)) {
474					request = new CECPacket(EC_OP_SET_PREFERENCES);
475					CECEmptyTag prefs(EC_TAG_PREFS_CONNECTIONS);
476					prefs.AddTag(CECTag(tmp_int, (uint16)limit));
477					request->AddTag(prefs);
478					request_list.push_back(request);
479				} else {
480					return CMD_ERR_INVALID_ARG;
481				}
482			}
483		case CMD_ID_GET_BWLIMITS:
484			request = new CECPacket(EC_OP_GET_PREFERENCES);
485			request->AddTag(CECTag(EC_TAG_SELECT_PREFS, (uint32)EC_PREFS_CONNECTIONS));
486			request_list.push_back(request);
487			break;
488
489		case CMD_ID_STATTREE:
490			request = new CECPacket(EC_OP_GET_STATSTREE);
491			if (!args.IsEmpty()) {
492				unsigned long int max_versions;
493				if (args.ToULong(&max_versions)) {
494					if (max_versions < 256) {
495						request->AddTag(CECTag(EC_TAG_STATTREE_CAPPING, (uint8)max_versions));
496					} else {
497						delete request;
498						return CMD_ERR_INVALID_ARG;
499					}
500				} else {
501					delete request;
502					return CMD_ERR_INVALID_ARG;
503				}
504			}
505			request_list.push_back(request);
506			break;
507		case CMD_ID_SEARCH_GLOBAL:
508			search_type = EC_SEARCH_GLOBAL;
509		case CMD_ID_SEARCH_LOCAL:
510			if (search_type != EC_SEARCH_GLOBAL){
511				search_type = EC_SEARCH_LOCAL;
512			}
513		case CMD_ID_SEARCH_KAD:
514			if (search_type != EC_SEARCH_GLOBAL && search_type != EC_SEARCH_LOCAL){
515				search_type = EC_SEARCH_KAD;
516			}
517			if (!args.IsEmpty())
518			{
519				wxString search = args;
520				wxString type;
521				wxString extention;
522				uint32 avail = 0;
523				uint32 min_size = 0;
524				uint32 max_size = 0;
525
526				request = new CECPacket(EC_OP_SEARCH_START);
527				request->AddTag(CEC_Search_Tag (search, search_type, type, extention, avail, min_size, max_size));
528				request_list.push_back(request);
529			}
530			break;
531		case CMD_ID_SEARCH:
532			printf("No search type defined.\nType 'help search' to get more help.\n");
533			break;
534
535
536		case CMD_ID_SEARCH_RESULTS:
537			request_list.push_back(new CECPacket(EC_OP_SEARCH_RESULTS, EC_DETAIL_FULL));
538			break;
539
540		case CMD_ID_SEARCH_PROGRESS:
541			request_list.push_back(new CECPacket(EC_OP_SEARCH_PROGRESS));
542			break;
543
544		case CMD_ID_DOWNLOAD:
545			if (!args.IsEmpty())
546			{
547				unsigned long int id = 0;
548				if (args.ToULong(&id) == true && id < m_Results_map.size()) {
549
550					SearchFile* file = m_Results_map[id];
551					printf("Download File: %lu %s\n", id, (const char*)unicode2char(file->sFileName));
552					request = new CECPacket(EC_OP_DOWNLOAD_SEARCH_RESULT);
553					// get with id the hash and category=0
554					uint32 category = 0;
555					CECTag hashtag(EC_TAG_PARTFILE, file->nHash);
556					hashtag.AddTag(CECTag(EC_TAG_PARTFILE_CAT, category));
557					request->AddTag(hashtag);
558					request_list.push_back(request);
559				} else {
560					return CMD_ERR_INVALID_ARG;
561				}
562			}
563			break;
564
565		default:
566			return CMD_ERR_PROCESS_CMD;
567	}
568
569	m_last_cmd_id = CmdId;
570
571	if ( ! request_list.empty() ) {
572		std::list<CECPacket *>::iterator it = request_list.begin();
573		while ( it != request_list.end() ) {
574			CECPacket *curr = *it++;
575			if (curr->GetOpCode() == EC_OP_SHUTDOWN) {
576				SendPacket(curr);
577				delete curr;
578				return CMD_ID_QUIT;
579			}
580			const CECPacket *reply = SendRecvMsg_v2(curr);
581			delete curr;
582			if ( reply ) {
583				Process_Answer_v2(reply);
584				delete reply;
585			}
586		}
587		request_list.resize(0);
588	}
589
590	return CMD_OK;
591}
592
593 /*
594 * Method to show the results in the console
595 */
596void CamulecmdApp::ShowResults(CResultMap results_map)
597{
598	unsigned int name_max = 80;
599	unsigned int mb_max = 5;
600	unsigned int nr_max = 5;
601	unsigned long int id = 0;
602	wxString output, name, sources, mb , kb;
603
604	printf("Nr.    Filename:                                                                        Size(MB):  Sources: \n");
605	printf("-----------------------------------------------------------------------------------------------------------\n");
606
607	for( std::map<unsigned long int,SearchFile*>::iterator iter = results_map.begin(); iter != results_map.end(); iter++ ) {
608    		id = (*iter).first;
609		SearchFile* file = (*iter).second;
610
611		output.Printf(wxT("%i.      "), id);
612		output = output.SubString(0, nr_max).Append(file->sFileName).Append(' ', name_max);
613		mb.Printf(wxT("     %d"), file->lFileSize/1024/1024);
614		kb.Printf(wxT(".%d"), file->lFileSize/1024%1024);
615		output = output.SubString(0, nr_max + name_max + mb_max - mb.Length() ).Append(mb).Append(kb);
616		printf("%s     %ld\n",(const char*)unicode2char(output), file->lSourceCount );
617 	}
618}
619
620
621// Formats a statistics (sub)tree to text
622wxString StatTree2Text(CEC_StatTree_Node_Tag *tree, int depth)
623{
624	if (!tree) {
625		return wxEmptyString;
626	}
627	wxString result = wxString(wxChar(' '), depth) + tree->GetDisplayString() + wxT("\n");
628	for (CECTag::const_iterator it = tree->begin(); it != tree->end(); it++) {
629		CEC_StatTree_Node_Tag *tmp = (CEC_StatTree_Node_Tag*) & *it;
630		if (tmp->GetTagName() == EC_TAG_STATTREE_NODE) {
631			result += StatTree2Text(tmp, depth + 1);
632		}
633	}
634	return result;
635}
636
637/*
638 * Format EC packet into text form for output to console
639 */
640void CamulecmdApp::Process_Answer_v2(const CECPacket *response)
641{
642	wxString s;
643	wxString msgFailedUnknown(_("Request failed with an unknown error."));
644	wxASSERT(response);
645	switch (response->GetOpCode()) {
646		case EC_OP_NOOP:
647			s << _("Operation was successful.");
648			break;
649		case EC_OP_FAILED:
650			{
651				const CECTag *tag = response->GetFirstTagSafe();
652				if (tag->IsString()) {
653					s <<	CFormat(_("Request failed with the following error: %s")) % wxGetTranslation(tag->GetStringData());
654				} else {
655					s << msgFailedUnknown;
656				}
657			}
658			break;
659		case EC_OP_SET_PREFERENCES:
660			{
661				const CECTag *tab = response->GetTagByNameSafe(EC_TAG_PREFS_SECURITY);
662				const CECTag *ipfilterLevel = tab->GetTagByName(EC_TAG_IPFILTER_LEVEL);
663				if (ipfilterLevel) {
664					if (m_last_cmd_id == CMD_ID_GET_IPFILTER ||
665					    m_last_cmd_id == CMD_ID_GET_IPFILTER_STATE ||
666					    m_last_cmd_id == CMD_ID_GET_IPFILTER_STATE_CLIENTS) {
667						s += CFormat(_("IP filtering for clients is %s.\n"))
668								% ((tab->GetTagByName(EC_TAG_IPFILTER_CLIENTS) == NULL) ? _("OFF") : _("ON"));
669					}
670					if (m_last_cmd_id == CMD_ID_GET_IPFILTER ||
671					    m_last_cmd_id == CMD_ID_GET_IPFILTER_STATE ||
672					    m_last_cmd_id == CMD_ID_GET_IPFILTER_STATE_SERVERS) {
673						s += CFormat(_("IP filtering for servers is %s.\n"))
674								% ((tab->GetTagByName(EC_TAG_IPFILTER_SERVERS) == NULL) ? _("OFF") : _("ON"));
675					}
676					if (m_last_cmd_id == CMD_ID_GET_IPFILTER ||
677					    m_last_cmd_id == CMD_ID_GET_IPFILTER_LEVEL) {
678						s << CFormat(_("Current IPFilter Level is %d.\n")) % ipfilterLevel->GetInt();
679					}
680				}
681				tab = response->GetTagByNameSafe(EC_TAG_PREFS_CONNECTIONS);
682				const CECTag *connMaxUL = tab->GetTagByName(EC_TAG_CONN_MAX_UL);
683				const CECTag *connMaxDL = tab->GetTagByName(EC_TAG_CONN_MAX_DL);
684				if (connMaxUL && connMaxDL) {
685					s << CFormat(_("Bandwidth limits: Up: %u kB/s, Down: %u kB/s.\n"))
686						% connMaxUL->GetInt() % connMaxDL->GetInt();
687				}
688			}
689			break;
690		case EC_OP_STRINGS:
691			for (CECPacket::const_iterator it = response->begin(); it != response->end(); it++) {
692				const CECTag &tag = *it;
693				s << tag.GetStringData() << wxT("\n");
694			}
695			break;
696		case EC_OP_STATS: {
697			CEC_ConnState_Tag *connState = (CEC_ConnState_Tag*)response->GetTagByName(EC_TAG_CONNSTATE);
698			if (connState) {
699				s << _("eD2k") << wxT(": ");
700				if (connState->IsConnectedED2K()) {
701					CECTag *server = connState->GetTagByName(EC_TAG_SERVER);
702					CECTag *serverName = server ? server->GetTagByName(EC_TAG_SERVER_NAME) : NULL;
703					if (server && serverName) {
704						s << CFormat(_("Connected to %s %s %s")) %
705						 serverName->GetStringData() %
706						 server->GetIPv4Data().StringIP() %
707						 (connState->HasLowID() ? _("with LowID") : _("with HighID"));
708					}
709				} else if (connState->IsConnectingED2K()) {
710					s << _("Now connecting");
711				} else {
712					s << _("Not connected");
713				}
714				s << wxT('\n') << _("Kad") << wxT(": ");
715				if (connState->IsKadRunning()) {
716					if (connState->IsConnectedKademlia()) {
717						s << _("Connected") << wxT(" (");
718						if (connState->IsKadFirewalled()) {
719							s << _("firewalled");
720						} else {
721							s << _("ok");
722						}
723						s << wxT(')');
724					} else {
725						s << _("Not connected");
726					}
727				} else {
728					s << _("Not running");
729				}
730				s << wxT('\n');
731			}
732			const CECTag *tmpTag;
733			if ((tmpTag = response->GetTagByName(EC_TAG_STATS_DL_SPEED)) != 0) {
734				s <<	CFormat(_("\nDownload:\t%s")) % CastItoSpeed(tmpTag->GetInt());
735			}
736			if ((tmpTag = response->GetTagByName(EC_TAG_STATS_UL_SPEED)) != 0) {
737				s <<	CFormat(_("\nUpload:\t%s")) % CastItoSpeed(tmpTag->GetInt());
738			}
739			if ((tmpTag = response->GetTagByName(EC_TAG_STATS_UL_QUEUE_LEN)) != 0) {
740				s << 	CFormat(_("\nClients in queue:\t%d\n")) % tmpTag->GetInt();
741			}
742			if ((tmpTag = response->GetTagByName(EC_TAG_STATS_TOTAL_SRC_COUNT)) != 0) {
743				s << 	CFormat(_("\nTotal sources:\t%d\n")) % tmpTag->GetInt();
744			}
745			break;
746		}
747		case EC_OP_DLOAD_QUEUE:
748			for (CECPacket::const_iterator it = response->begin(); it != response->end(); it++) {
749				CEC_PartFile_Tag *tag =	(CEC_PartFile_Tag *) & *it;
750					uint64 filesize, donesize;
751					filesize = tag->SizeFull();
752					donesize = tag->SizeDone();
753					s <<	tag->FileHashString() << wxT(" ") <<
754						tag->FileName() <<
755						(CFormat(wxT("\n\t [%.1f%%] %4i/%4i "))
756							% ((float)donesize / ((float)filesize)*100.0)
757							% ((int)tag->SourceCount() - (int)tag->SourceNotCurrCount())
758							% (int)tag->SourceCount()) <<
759						((int)tag->SourceCountA4AF() ? wxString(CFormat(wxT("+%2.2i ")) % (int)tag->SourceCountA4AF()) : wxString(wxT("    "))) <<
760						((int)tag->SourceXferCount() ? wxString(CFormat(wxT("(%2.2i) - ")) % (int)tag->SourceXferCount()) : wxString(wxT("     - "))) <<
761						tag->GetFileStatusString();
762					s << wxT(" - ") << tag->PartMetName();
763                    if (tag->DownPrio() < 10) {
764                            s << wxT(" - ") << PriorityToStr((int)tag->DownPrio(), 0);
765                    } else {
766                            s << wxT(" - ") << PriorityToStr((tag->DownPrio() - 10), 1);
767                    }
768					if ( tag->SourceXferCount() > 0) {
769						s << wxT(" - ") + CastItoSpeed(tag->Speed());
770					}
771					s << wxT("\n");
772			}
773			break;
774		case EC_OP_ULOAD_QUEUE:
775			for (CECPacket::const_iterator it = response->begin(); it != response->end(); it++) {
776				const CECTag *tag = & *it;
777				const CECTag *clientName = tag->GetTagByName(EC_TAG_CLIENT_NAME);
778				const CECTag *partfileName = tag->GetTagByName(EC_TAG_PARTFILE_NAME);
779				const CECTag *partfileSizeXfer = tag->GetTagByName(EC_TAG_PARTFILE_SIZE_XFER);
780				const CECTag *partfileSpeed = tag->GetTagByName(EC_TAG_CLIENT_UP_SPEED);
781				if (clientName && partfileName && partfileSizeXfer && partfileSpeed) {
782					s <<	wxT("\n") <<
783						CFormat(wxT("%10u ")) % tag->GetInt() <<
784						clientName->GetStringData() << wxT(" ") <<
785						partfileName->GetStringData() << wxT(" ") <<
786						CastItoXBytes(partfileSizeXfer->GetInt()) << wxT(" ") <<
787						CastItoSpeed(partfileSpeed->GetInt());
788				}
789			}
790			break;
791		case EC_OP_LOG:
792			for (CECPacket::const_iterator it = response->begin(); it != response->end(); it++) {
793				const CECTag &tag = *it;
794				s << tag.GetStringData() << wxT("\n");
795			}
796			break;
797		case EC_OP_SERVER_LIST:
798			for (CECPacket::const_iterator it = response->begin(); it != response->end(); it++) {
799				const CECTag &tag = *it;
800				const CECTag *serverName = tag.GetTagByName(EC_TAG_SERVER_NAME);
801				if (serverName) {
802					wxString ip = tag.GetIPv4Data().StringIP();
803					ip.Append(' ', 24 - ip.Length());
804					s << ip << serverName->GetStringData() << wxT("\n");
805				}
806			}
807			break;
808		case EC_OP_STATSTREE:
809			s << StatTree2Text((CEC_StatTree_Node_Tag*)response->GetTagByName(EC_TAG_STATTREE_NODE), 0);
810			break;
811
812		case EC_OP_SEARCH_RESULTS:
813		{
814			int i = 0;
815			m_Results_map.clear();
816			s += CFormat(_("Number of search results: %i\n")) % response->GetTagCount();
817			for (CECPacket::const_iterator it = response->begin(); it != response->end(); it++) {
818				CEC_SearchFile_Tag *tag = (CEC_SearchFile_Tag *) & *it;
819				//printf("Tag FileName: %s \n",(const char*)unicode2char(tag->FileName()));
820				m_Results_map[i++] = new SearchFile(tag);
821			}
822			ShowResults(m_Results_map);
823			break;
824		}
825		case EC_OP_SEARCH_PROGRESS:
826		{
827			const CECTag *tab = response->GetTagByNameSafe(EC_TAG_SEARCH_STATUS);
828			uint32 progress = tab->GetInt();
829			if (progress <= 100) {
830				s += CFormat(_("Search progress: %u %% \n")) % progress;
831			} else {
832				s += _("Search progress not available");
833			}
834			break;
835		}
836		default:
837			s += CFormat(_("Received an unknown reply from the server, OpCode = %#x.")) % response->GetOpCode();
838	}
839	Process_Answer(s);
840}
841
842void CamulecmdApp::OnInitCommandSet()
843{
844	CCommandTree *tmp;
845	CCommandTree *tmp2;
846	CCommandTree *tmp3;
847
848	CaMuleExternalConnector::OnInitCommandSet();
849
850	m_commands.AddCommand(wxT("Status"), CMD_ID_STATUS, wxTRANSLATE("Show short status information."),
851			      wxTRANSLATE("Show connection status, current up/download speeds, etc.\n"), CMD_PARAM_NEVER);
852
853	m_commands.AddCommand(wxT("Statistics"), CMD_ID_STATTREE, wxTRANSLATE("Show full statistics tree."),
854			      wxTRANSLATE("Optionally, a number in the range 0-255 can be passed as an argument to this\ncommand, which tells how many entries of the client version subtrees should be\nshown. Passing 0 or omitting it means 'unlimited'.\n\nExample: 'statistics 5' will show only the top 5 versions for each client type.\n"));
855
856	m_commands.AddCommand(wxT("Shutdown"), CMD_ID_SHUTDOWN, wxTRANSLATE("Shut down aMule."),
857			      wxTRANSLATE("Shut down the remote running core (amule/amuled).\nThis will also shut down the text client, since it is unusable without a\nrunning core.\n"), CMD_PARAM_NEVER);
858
859	tmp = m_commands.AddCommand(wxT("Reload"), CMD_ERR_INCOMPLETE, wxTRANSLATE("Reload the given object."), wxEmptyString, CMD_PARAM_NEVER);
860	tmp->AddCommand(wxT("Shared"), CMD_ID_RELOAD_SHARED, wxTRANSLATE("Reload shared files list."), wxEmptyString, CMD_PARAM_NEVER);
861
862	tmp2 = tmp->AddCommand(wxT("IPFilter"), CMD_ID_RELOAD_IPFILTER_LOCAL, wxTRANSLATE("Reload IP filtering table."), wxEmptyString, CMD_PARAM_OPTIONAL);
863	tmp2->AddCommand(wxT("File"), CMD_ID_RELOAD_IPFILTER_LOCAL, wxTRANSLATE("Reload current IP filtering table."), wxEmptyString, CMD_PARAM_NEVER);
864	tmp2->AddCommand(wxT("Net"), CMD_ID_RELOAD_IPFILTER_NET, wxTRANSLATE("Update IP filtering table from URL."),
865					wxTRANSLATE("If URL is omitted the URL from the preferences is used."), CMD_PARAM_OPTIONAL);
866
867	tmp = m_commands.AddCommand(wxT("Connect"), CMD_ID_CONNECT, wxTRANSLATE("Connect to the network."),
868				    wxTRANSLATE("This will connect to all networks that are enabled in Preferences.\nYou may also optionally specify a server address in IP:Port form, to connect to\nthat server only. The IP must be a dotted decimal IPv4 address,\nor a resolvable DNS name."), CMD_PARAM_OPTIONAL);
869	tmp->AddCommand(wxT("ED2K"), CMD_ID_CONNECT_ED2K, wxTRANSLATE("Connect to eD2k only."), wxEmptyString, CMD_PARAM_NEVER);
870	tmp->AddCommand(wxT("Kad"), CMD_ID_CONNECT_KAD, wxTRANSLATE("Connect to Kad only."), wxEmptyString, CMD_PARAM_NEVER);
871
872	tmp = m_commands.AddCommand(wxT("Disconnect"), CMD_ID_DISCONNECT, wxTRANSLATE("Disconnect from the network."),
873				    wxTRANSLATE("This will disconnect from all networks that are currently connected.\n"), CMD_PARAM_NEVER);
874	tmp->AddCommand(wxT("ED2K"), CMD_ID_DISCONNECT_ED2K, wxTRANSLATE("Disconnect from eD2k only."), wxEmptyString, CMD_PARAM_NEVER);
875	tmp->AddCommand(wxT("Kad"), CMD_ID_DISCONNECT_KAD, wxTRANSLATE("Disconnect from Kad only."), wxEmptyString, CMD_PARAM_NEVER);
876
877 	m_commands.AddCommand(wxT("Add"), CMD_ID_ADDLINK, wxTRANSLATE("Add an eD2k or magnet link to core."),
878			      wxTRANSLATE("The eD2k link to be added can be:\n*) a file link (ed2k://|file|...), it will be added to the download queue,\n*) a server link (ed2k://|server|...), it will be added to the server list,\n*) or a serverlist link, in which case all servers in the list will be added to the\n   server list.\n\nThe magnet link must contain the eD2k hash and file length.\n"), CMD_PARAM_ALWAYS);
879
880	tmp = m_commands.AddCommand(wxT("Set"), CMD_ERR_INCOMPLETE, wxTRANSLATE("Set a preference value."),
881				    wxEmptyString, CMD_PARAM_NEVER);
882
883	tmp2 = tmp->AddCommand(wxT("IPFilter"), CMD_ERR_INCOMPLETE, wxTRANSLATE("Set IP filtering preferences."), wxEmptyString, CMD_PARAM_NEVER);
884	tmp2->AddCommand(wxT("On"), CMD_ID_SET_IPFILTER_ON, wxTRANSLATE("Turn IP filtering on for both clients and servers."), wxEmptyString, CMD_PARAM_NEVER);
885	tmp2->AddCommand(wxT("Off"), CMD_ID_SET_IPFILTER_OFF, wxTRANSLATE("Turn IP filtering off for both clients and servers."), wxEmptyString, CMD_PARAM_NEVER);
886	tmp3 = tmp2->AddCommand(wxT("Clients"), CMD_ERR_INCOMPLETE, wxTRANSLATE("Enable/Disable IP filtering for clients."), wxEmptyString, CMD_PARAM_NEVER);
887	tmp3->AddCommand(wxT("On"), CMD_ID_SET_IPFILTER_CLIENTS_ON, wxTRANSLATE("Turn IP filtering on for clients."), wxEmptyString, CMD_PARAM_NEVER);
888	tmp3->AddCommand(wxT("Off"), CMD_ID_SET_IPFILTER_CLIENTS_OFF, wxTRANSLATE("Turn IP filtering off for clients."), wxEmptyString, CMD_PARAM_NEVER);
889	tmp3 = tmp2->AddCommand(wxT("Servers"), CMD_ERR_INCOMPLETE, wxTRANSLATE("Enable/Disable IP filtering for servers."), wxEmptyString, CMD_PARAM_NEVER);
890	tmp3->AddCommand(wxT("On"), CMD_ID_SET_IPFILTER_SERVERS_ON, wxTRANSLATE("Turn IP filtering on for servers."), wxEmptyString, CMD_PARAM_NEVER);
891	tmp3->AddCommand(wxT("Off"), CMD_ID_SET_IPFILTER_SERVERS_OFF, wxTRANSLATE("Turn IP filtering off for servers."), wxEmptyString, CMD_PARAM_NEVER);
892	tmp2->AddCommand(wxT("Level"), CMD_ID_SET_IPFILTER_LEVEL, wxTRANSLATE("Select IP filtering level."),
893			 wxTRANSLATE("Valid filtering levels are in the range 0-255, and it's default (initial)\nvalue is 127.\n"), CMD_PARAM_ALWAYS);
894
895	tmp2 = tmp->AddCommand(wxT("BwLimit"), CMD_ERR_INCOMPLETE, wxTRANSLATE("Set bandwidth limits."),
896			       wxTRANSLATE("The value given to these commands has to be in kilobytes/sec.\n"), CMD_PARAM_NEVER);
897	tmp2->AddCommand(wxT("Up"), CMD_ID_SET_BWLIMIT_UP, wxTRANSLATE("Set upload bandwidth limit."),
898			 wxT("The given value must be in kilobytes/sec.\n"), CMD_PARAM_ALWAYS);
899	tmp2->AddCommand(wxT("Down"), CMD_ID_SET_BWLIMIT_DOWN, wxTRANSLATE("Set download bandwidth limit."),
900			 wxT("The given value must be in kilobytes/sec.\n"), CMD_PARAM_ALWAYS);
901
902	tmp = m_commands.AddCommand(wxT("Get"), CMD_ERR_INCOMPLETE, wxTRANSLATE("Get and display a preference value."),
903				    wxEmptyString, CMD_PARAM_NEVER);
904
905	tmp2 = tmp->AddCommand(wxT("IPFilter"), CMD_ID_GET_IPFILTER, wxTRANSLATE("Get IP filtering preferences."), wxEmptyString, CMD_PARAM_NEVER);
906	tmp3 = tmp2->AddCommand(wxT("State"), CMD_ID_GET_IPFILTER_STATE, wxTRANSLATE("Get IP filtering state for both clients and servers."), wxEmptyString, CMD_PARAM_NEVER);
907	tmp3->AddCommand(wxT("Clients"), CMD_ID_GET_IPFILTER_STATE_CLIENTS, wxTRANSLATE("Get IP filtering state for clients only."), wxEmptyString, CMD_PARAM_NEVER);
908	tmp3->AddCommand(wxT("Servers"), CMD_ID_GET_IPFILTER_STATE_SERVERS, wxTRANSLATE("Get IP filtering state for servers only."), wxEmptyString, CMD_PARAM_NEVER);
909	tmp2->AddCommand(wxT("Level"), CMD_ID_GET_IPFILTER_LEVEL, wxTRANSLATE("Get IP filtering level."), wxEmptyString, CMD_PARAM_NEVER);
910
911	tmp->AddCommand(wxT("BwLimits"), CMD_ID_GET_BWLIMITS, wxTRANSLATE("Get bandwidth limits."), wxEmptyString, CMD_PARAM_NEVER);
912
913	tmp = m_commands.AddCommand(wxT("Search"), CMD_ID_SEARCH, wxTRANSLATE("Execute a search."),
914			      wxTRANSLATE("A search type has to be specified by giving the type:\n    GLOBAL\n    LOCAL\n    KAD\nExample: 'search kad file' will execute a kad search for \"file\".\n"), CMD_PARAM_ALWAYS);
915	tmp->AddCommand(wxT("global"), CMD_ID_SEARCH_GLOBAL, wxTRANSLATE("Execute a global search."), wxEmptyString, CMD_PARAM_ALWAYS);
916	tmp->AddCommand(wxT("local"), CMD_ID_SEARCH_LOCAL, wxTRANSLATE("Execute a local search"), wxEmptyString, CMD_PARAM_ALWAYS);
917	tmp->AddCommand(wxT("kad"), CMD_ID_SEARCH_KAD, wxTRANSLATE("Execute a kad search"), wxEmptyString, CMD_PARAM_ALWAYS);
918
919	m_commands.AddCommand(wxT("Results"), CMD_ID_SEARCH_RESULTS, wxTRANSLATE("Show the results of the last search."),
920			      wxTRANSLATE("Return the results of the previous search.\n"), CMD_PARAM_NEVER);
921
922	m_commands.AddCommand(wxT("Progress"), CMD_ID_SEARCH_PROGRESS, wxTRANSLATE("Show the progress of a search."),
923			      wxTRANSLATE("Show the progress of a search.\n"), CMD_PARAM_NEVER);
924
925	m_commands.AddCommand(wxT("Download"), CMD_ID_DOWNLOAD, wxTRANSLATE("Start downloading a file"),
926			      wxTRANSLATE("The number of a file from the last search has to be given.\nExample: 'download 12' will start to download the file with the number 12 of the previous search.\n"), CMD_PARAM_ALWAYS);
927
928
929	//
930	// TODO: These commands below need implementation and/or rewrite!
931	//
932
933  	m_commands.AddCommand(wxT("Pause"), CMD_ID_PAUSE, wxTRANSLATE("Pause download."),
934 			      wxEmptyString, CMD_PARAM_ALWAYS);
935
936  	m_commands.AddCommand(wxT("Resume"), CMD_ID_RESUME, wxTRANSLATE("Resume download."),
937 			      wxEmptyString, CMD_PARAM_ALWAYS);
938
939   	m_commands.AddCommand(wxT("Cancel"), CMD_ID_CANCEL, wxTRANSLATE("Cancel download."),
940  			      wxEmptyString, CMD_PARAM_ALWAYS);
941
942	tmp = m_commands.AddCommand(wxT("Priority"), CMD_ERR_INCOMPLETE, wxTRANSLATE("Set download priority."),
943				    wxTRANSLATE("Set priority of a download to Low, Normal, High or Auto.\n"), CMD_PARAM_ALWAYS);
944	tmp->AddCommand(wxT("Low"), CMD_ID_PRIORITY_LOW, wxTRANSLATE("Set priority to low."), wxEmptyString, CMD_PARAM_ALWAYS);
945	tmp->AddCommand(wxT("Normal"), CMD_ID_PRIORITY_NORMAL, wxTRANSLATE("Set priority to normal."), wxEmptyString, CMD_PARAM_ALWAYS);
946	tmp->AddCommand(wxT("High"), CMD_ID_PRIORITY_HIGH, wxTRANSLATE("Set priority to high."), wxEmptyString, CMD_PARAM_ALWAYS);
947	tmp->AddCommand(wxT("Auto"), CMD_ID_PRIORITY_AUTO, wxTRANSLATE("Set priority to auto."), wxEmptyString, CMD_PARAM_ALWAYS);
948
949	tmp = m_commands.AddCommand(wxT("Show"), CMD_ERR_INCOMPLETE, wxTRANSLATE("Show queues/lists."),
950				    wxTRANSLATE("Show upload/download queue, server list or shared files list.\n"), CMD_PARAM_ALWAYS);
951	tmp->AddCommand(wxT("UL"), CMD_ID_SHOW_UL, wxTRANSLATE("Show upload queue."), wxEmptyString, CMD_PARAM_NEVER);
952	tmp->AddCommand(wxT("DL"), CMD_ID_SHOW_DL, wxTRANSLATE("Show download queue."), wxEmptyString, CMD_PARAM_NEVER);
953	tmp->AddCommand(wxT("Log"), CMD_ID_SHOW_LOG, wxTRANSLATE("Show log."), wxEmptyString, CMD_PARAM_NEVER);
954	tmp->AddCommand(wxT("Servers"), CMD_ID_SHOW_SERVERS, wxTRANSLATE("Show servers list."), wxEmptyString, CMD_PARAM_NEVER);
955// 	tmp->AddCommand(wxT("Shared"), CMD_ID_SHOW_SHARED, wxTRANSLATE("Show shared files list."), wxEmptyString, CMD_PARAM_NEVER);
956
957	m_commands.AddCommand(wxT("Reset"), CMD_ID_RESET_LOG, wxTRANSLATE("Reset log."), wxEmptyString, CMD_PARAM_NEVER);
958
959	//
960	// Deprecated commands, kept for backwards compatibility only.
961	//
962
963#define DEPRECATED(OLDCMD, ID, NEWCMD, PARAM) \
964	m_commands.AddCommand(wxT(OLDCMD), CMD_ID_##ID | CMD_DEPRECATED, CFormat(wxTRANSLATE("Deprecated command, use '%s' instead.")) % wxT(NEWCMD), \
965			      CFormat(wxTRANSLATE("This is a deprecated command, and may be removed in the future.\nUse '%s' instead.\n")) % wxT(NEWCMD), CMD_PARAM_##PARAM)
966
967	DEPRECATED("Stats", STATUS, "Status", NEVER);
968	DEPRECATED("SetIPFilter", SET_IPFILTER, "Set IPFilter", OPTIONAL);
969	DEPRECATED("GetIPLevel", GET_IPFILTER_LEVEL, "Get IPFilter Level", NEVER);
970	DEPRECATED("SetIPLevel", SET_IPFILTER_LEVEL, "Set IPFilter Level", ALWAYS);
971	DEPRECATED("IPLevel", SET_IPFILTER_LEVEL, "Get/Set IPFilter Level", OPTIONAL);
972	DEPRECATED("Servers", SHOW_SERVERS, "Show Servers", NEVER);
973	DEPRECATED("GetBWLimits", GET_BWLIMITS, "Get BwLimits", NEVER);
974	DEPRECATED("SetUpBWLimit", SET_BWLIMIT_UP, "Set BwLimit Up", ALWAYS);
975	DEPRECATED("SetDownBWLimit", SET_BWLIMIT_DOWN, "Set BwLimit Down", ALWAYS);
976}
977
978int CamulecmdApp::OnRun()
979{
980	ConnectAndRun(wxT("aMulecmd"), wxT(VERSION));
981	return 0;
982}
983
984// Dummy functions for EC logging
985bool ECLogIsEnabled()
986{
987	return false;
988}
989
990void DoECLogLine(const wxString &)
991{
992}
993// File_checked_for_headers
994