1//
2// This file is part of the aMule Project.
3//
4// Copyright (c) 2003-2011 aMule Team ( admin@amule.org / http://www.amule.org )
5// Copyright (c) 2002-2011 Merkur ( devs@emule-project.net / http://www.emule-project.net )
6//
7// Any parts of this program derived from the xMule, lMule or eMule project,
8// or contributed by third-party developers are copyrighted by their
9// respective authors.
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#include <wx/wx.h>
27#include "Preferences.h"
28
29#include <protocol/ed2k/Constants.h>
30#include <common/Constants.h>
31#include <common/DataFileVersion.h>
32
33#include <wx/config.h>
34#include <wx/dir.h>
35#include <wx/stdpaths.h>
36#include <wx/stopwatch.h>
37#include <wx/tokenzr.h>
38#include <wx/utils.h>		// Needed for wxBusyCursor
39
40#include "amule.h"
41#ifdef HAVE_CONFIG_H
42	#include "config.h"		// Needed for PACKAGE_STRING
43#endif
44
45#include "CFile.h"
46#include <common/MD5Sum.h>
47#include "Logger.h"
48#include <common/Format.h>		// Needed for CFormat
49#include <common/TextFile.h>		// Needed for CTextFile
50#include <common/ClientVersion.h>
51
52#include "UserEvents.h"
53
54#ifndef AMULE_DAEMON
55#include <wx/valgen.h>
56#include "muuli_wdr.h"
57#include "StatisticsDlg.h"
58#include "MuleColour.h"
59#endif
60
61#ifndef CLIENT_GUI
62#include "RandomFunctions.h"
63#include "PlatformSpecific.h"		// Needed for PlatformSpecific::GetMaxConnections()
64#include "SharedFileList.h"			// Needed for theApp->sharedfiles->Reload()
65#endif
66
67// Needed for IP filtering prefs
68#include "ClientList.h"
69#include "ServerList.h"
70#include "GuiEvents.h"
71
72#define DEFAULT_TCP_PORT 4662
73#define DEFAULT_UDP_PORT 4672
74
75// Static variables
76unsigned long		CPreferences::s_colors[cntStatColors];
77unsigned long		CPreferences::s_colors_ref[cntStatColors];
78
79CPreferences::CFGMap	CPreferences::s_CfgList;
80CPreferences::CFGList	CPreferences::s_MiscList;
81
82
83/* Proxy */
84CProxyData	CPreferences::s_ProxyData;
85
86/* The rest, organize it! */
87wxString	CPreferences::s_nick;
88Cfg_Lang_Base * CPreferences::s_cfgLang;
89uint16		CPreferences::s_maxupload;
90uint16		CPreferences::s_maxdownload;
91uint16		CPreferences::s_slotallocation;
92wxString	CPreferences::s_Addr;
93uint16		CPreferences::s_port;
94uint16		CPreferences::s_udpport;
95bool		CPreferences::s_UDPEnable;
96uint16		CPreferences::s_maxconnections;
97bool		CPreferences::s_reconnect;
98bool		CPreferences::s_autoconnect;
99bool		CPreferences::s_autoconnectstaticonly;
100bool		CPreferences::s_UPnPEnabled;
101bool		CPreferences::s_UPnPECEnabled;
102bool		CPreferences::s_UPnPWebServerEnabled;
103uint16		CPreferences::s_UPnPTCPPort;
104bool		CPreferences::s_autoserverlist;
105bool		CPreferences::s_deadserver;
106CPath		CPreferences::s_incomingdir;
107CPath		CPreferences::s_tempdir;
108bool		CPreferences::s_ICH;
109uint8		CPreferences::s_depth3D;
110bool		CPreferences::s_scorsystem;
111bool		CPreferences::s_hideonclose;
112bool		CPreferences::s_mintotray;
113bool		CPreferences::s_trayiconenabled;
114bool		CPreferences::s_addnewfilespaused;
115bool		CPreferences::s_addserversfromserver;
116bool		CPreferences::s_addserversfromclient;
117uint16		CPreferences::s_maxsourceperfile;
118uint16		CPreferences::s_trafficOMeterInterval;
119uint16		CPreferences::s_statsInterval;
120uint32		CPreferences::s_maxGraphDownloadRate;
121uint32		CPreferences::s_maxGraphUploadRate;
122bool		CPreferences::s_confirmExit;
123bool		CPreferences::s_filterLanIP;
124bool		CPreferences::s_paranoidfilter;
125bool		CPreferences::s_IPFilterSys;
126bool		CPreferences::s_onlineSig;
127uint16		CPreferences::s_OSUpdate;
128wxString	CPreferences::s_languageID;
129uint8		CPreferences::s_iSeeShares;
130uint8		CPreferences::s_iToolDelayTime;
131uint8		CPreferences::s_splitterbarPosition;
132uint16		CPreferences::s_deadserverretries;
133uint32		CPreferences::s_dwServerKeepAliveTimeoutMins;
134uint8		CPreferences::s_statsMax;
135uint8		CPreferences::s_statsAverageMinutes;
136bool		CPreferences::s_bpreviewprio;
137bool		CPreferences::s_smartidcheck;
138uint8		CPreferences::s_smartidstate;
139bool		CPreferences::s_safeServerConnect;
140bool		CPreferences::s_startMinimized;
141uint16		CPreferences::s_MaxConperFive;
142bool		CPreferences::s_checkDiskspace;
143uint32		CPreferences::s_uMinFreeDiskSpace;
144wxString	CPreferences::s_yourHostname;
145bool		CPreferences::s_bVerbose;
146bool		CPreferences::s_bmanualhighprio;
147bool		CPreferences::s_bstartnextfile;
148bool		CPreferences::s_bstartnextfilesame;
149bool		CPreferences::s_bstartnextfilealpha;
150bool		CPreferences::s_bshowoverhead;
151bool		CPreferences::s_bDAP;
152bool		CPreferences::s_bUAP;
153#ifndef __SVN__
154bool		CPreferences::s_showVersionOnTitle;
155#endif
156uint8_t		CPreferences::s_showRatesOnTitle;
157wxString	CPreferences::s_VideoPlayer;
158bool		CPreferences::s_showAllNotCats;
159bool		CPreferences::s_msgonlyfriends;
160bool		CPreferences::s_msgsecure;
161uint8		CPreferences::s_filterlevel;
162uint8		CPreferences::s_iFileBufferSize;
163uint8		CPreferences::s_iQueueSize;
164wxString 	CPreferences::s_datetimeformat;
165wxString	CPreferences::s_sWebPath;
166wxString	CPreferences::s_sWebPassword;
167wxString	CPreferences::s_sWebLowPassword;
168uint16		CPreferences::s_nWebPort;
169uint16		CPreferences::s_nWebUPnPTCPPort;
170bool		CPreferences::s_bWebEnabled;
171bool		CPreferences::s_bWebUseGzip;
172uint32		CPreferences::s_nWebPageRefresh;
173bool		CPreferences::s_bWebLowEnabled;
174wxString	CPreferences::s_WebTemplate;
175bool		CPreferences::s_showCatTabInfos;
176AllCategoryFilter CPreferences::s_allcatFilter;
177uint8		CPreferences::s_NoNeededSources;
178bool		CPreferences::s_DropFullQueueSources;
179bool		CPreferences::s_DropHighQueueRankingSources;
180uint32		CPreferences::s_HighQueueRanking;
181uint32		CPreferences::s_AutoDropTimer;
182bool 		CPreferences::s_AcceptExternalConnections;
183wxString	CPreferences::s_ECAddr;
184uint32		CPreferences::s_ECPort;
185wxString	CPreferences::s_ECPassword;
186bool		CPreferences::s_TransmitOnlyUploadingClients;
187bool		CPreferences::s_IPFilterClients;
188bool		CPreferences::s_IPFilterServers;
189bool		CPreferences::s_UseSrcSeeds;
190bool		CPreferences::s_ProgBar;
191bool		CPreferences::s_Percent;
192bool		CPreferences::s_SecIdent;
193bool		CPreferences::s_ExtractMetaData;
194bool		CPreferences::s_allocFullFile;
195wxString	CPreferences::s_CustomBrowser;
196bool		CPreferences::s_BrowserTab;
197CPath		CPreferences::s_OSDirectory;
198wxString	CPreferences::s_Skin;
199bool		CPreferences::s_FastED2KLinksHandler;
200bool		CPreferences::s_ToolbarOrientation;
201bool		CPreferences::s_AICHTrustEveryHash;
202wxString 	CPreferences::s_CommentFilterString;
203bool		CPreferences::s_IPFilterAutoLoad;
204wxString	CPreferences::s_IPFilterURL;
205CMD4Hash	CPreferences::s_userhash;
206bool		CPreferences::s_MustFilterMessages;
207wxString 	CPreferences::s_MessageFilterString;
208bool		CPreferences::s_FilterAllMessages;
209bool 		CPreferences::s_FilterComments;
210bool		CPreferences::s_FilterSomeMessages;
211bool		CPreferences::s_ShowMessagesInLog;
212bool		CPreferences::s_IsAdvancedSpamfilterEnabled;
213bool		CPreferences::s_IsChatCaptchaEnabled;
214bool		CPreferences::s_ShareHiddenFiles;
215bool		CPreferences::s_AutoSortDownload;
216bool		CPreferences::s_NewVersionCheck;
217bool		CPreferences::s_ConnectToKad;
218bool		CPreferences::s_ConnectToED2K;
219unsigned	CPreferences::s_maxClientVersions;
220bool		CPreferences::s_DropSlowSources;
221bool		CPreferences::s_IsClientCryptLayerSupported;
222bool		CPreferences::s_bCryptLayerRequested;
223bool		CPreferences::s_IsClientCryptLayerRequired;
224uint32		CPreferences::s_dwKadUDPKey;
225uint8		CPreferences::s_byCryptTCPPaddingLength;
226
227wxString 	CPreferences::s_Ed2kURL;
228wxString 	CPreferences::s_KadURL;
229bool	 	CPreferences::s_GeoIPEnabled;
230wxString 	CPreferences::s_GeoIPUpdateUrl;
231bool		CPreferences::s_preventSleepWhileDownloading;
232wxString 	CPreferences::s_StatsServerName;
233wxString 	CPreferences::s_StatsServerURL;
234
235/**
236 * Template Cfg class for connecting with widgets.
237 *
238 * This template provides the base functionionality needed to syncronize a
239 * variable with a widget. However, please note that wxGenericValidator only
240 * supports a few types (int, wxString, bool and wxArrayInt), so this template
241 * can't always be used directly.
242 *
243 * Cfg_Str and Cfg_Bool are able to use this template directly, whereas Cfg_Int
244 * makes use of serveral workaround to enable it to be used with integers other
245 * than int.
246 */
247template <typename TYPE>
248class Cfg_Tmpl : public Cfg_Base
249{
250public:
251	/**
252	 * Constructor.
253	 *
254	 * @param keyname
255	 * @param value
256	 * @param defaultVal
257	 */
258	Cfg_Tmpl( const wxString& keyname, TYPE& value, const TYPE& defaultVal )
259	 : Cfg_Base( keyname ),
260	   m_value( value ),
261	   m_default( defaultVal ),
262	   m_widget( NULL )
263	{}
264
265#ifndef AMULE_DAEMON
266	/**
267	 * Connects the Cfg to a widget.
268	 *
269	 * @param id The ID of the widget to be connected.
270	 * @param parent The parent of the widget. Use this to speed up searches.
271	 *
272	 * This function works by setting the wxValidator of the class. This however
273	 * poses some restrictions on which variable types can be used for this
274	 * template, as noted above. It also poses some limits on the widget types,
275	 * refer to the wx documentation for those.
276	 */
277	virtual	bool ConnectToWidget( int id, wxWindow* parent = NULL )
278	{
279		if ( id ) {
280			m_widget = wxWindow::FindWindowById( id, parent );
281
282			if ( m_widget ) {
283				wxGenericValidator validator( &m_value );
284
285				m_widget->SetValidator( validator );
286
287				return true;
288			}
289		} else {
290			m_widget = NULL;
291		}
292
293		return false;
294	}
295
296
297	/** Updates the assosiated variable, returning true on success. */
298	virtual bool TransferFromWindow()
299	{
300		if ( m_widget ) {
301			wxValidator* validator = m_widget->GetValidator();
302
303			if ( validator ) {
304				TYPE temp = m_value;
305
306				if ( validator->TransferFromWindow() ) {
307					SetChanged( temp != m_value );
308
309					return true;
310				}
311			}
312		}
313
314		return false;
315	}
316
317	/** Updates the assosiated widget, returning true on success. */
318	virtual bool TransferToWindow()
319	{
320		if ( m_widget ) {
321			wxValidator* validator = m_widget->GetValidator();
322
323			if ( validator )
324				return validator->TransferToWindow();
325		}
326
327		return false;
328	}
329
330#endif
331
332	/** Sets the default value. */
333	void	SetDefault(const TYPE& defaultVal)
334	{
335		m_default = defaultVal;
336	}
337
338protected:
339	//! Reference to the associated variable
340	TYPE&	m_value;
341
342	//! Default variable value
343	TYPE	m_default;
344
345	//! Pointer to the widget assigned to the Cfg instance
346	wxWindow*	m_widget;
347};
348
349
350/** Cfg class for wxStrings. */
351class Cfg_Str : public Cfg_Tmpl<wxString>
352{
353public:
354	/** Constructor. */
355	Cfg_Str( const wxString& keyname, wxString& value, const wxString& defaultVal = EmptyString )
356	 : Cfg_Tmpl<wxString>( keyname, value, defaultVal )
357	{}
358
359	/** Loads the string, using the specified default value. */
360	virtual void LoadFromFile(wxConfigBase* cfg)
361	{
362		cfg->Read( GetKey(), &m_value, m_default );
363	}
364
365
366	/** Saves the string to the specified wxConfig object. */
367	virtual void SaveToFile(wxConfigBase* cfg)
368	{
369		cfg->Write( GetKey(), m_value );
370	}
371};
372
373
374/**
375 * Cfg-class for encrypting strings, for example for passwords.
376 */
377class Cfg_Str_Encrypted : public Cfg_Str
378{
379public:
380	Cfg_Str_Encrypted( const wxString& keyname, wxString& value, const wxString& defaultVal = EmptyString )
381	 : Cfg_Str( keyname, value, defaultVal )
382	{}
383
384#ifndef AMULE_DAEMON
385	virtual bool TransferFromWindow()
386	{
387		// Shakraw: when storing value, store it encrypted here (only if changed in prefs)
388		if ( Cfg_Str::TransferFromWindow() ) {
389
390			// Only recalucate the hash for new, non-empty passwords
391			if ( HasChanged() && !m_value.IsEmpty() ) {
392				m_value = MD5Sum( m_value ).GetHash();
393			}
394
395			return true;
396		}
397
398
399		return false;
400	}
401#endif
402};
403
404
405/** Cfg class for CPath. */
406class Cfg_Path : public Cfg_Str
407{
408public:
409	/** Constructor. */
410	Cfg_Path(const wxString& keyname, CPath& value, const wxString& defaultVal = EmptyString )
411	 : Cfg_Str(keyname, m_temp_path, defaultVal)
412	 , m_real_path(value)
413	{}
414
415	/** @see Cfg_Str::LoadFromFile. */
416	virtual void LoadFromFile(wxConfigBase* cfg)
417	{
418		Cfg_Str::LoadFromFile(cfg);
419
420		m_real_path = CPath::FromUniv(m_temp_path);
421	}
422
423
424	/** @see Cfg_Str::SaveToFile. */
425	virtual void SaveToFile(wxConfigBase* cfg)
426	{
427		m_temp_path = CPath::ToUniv(m_real_path);
428
429		Cfg_Str::SaveToFile(cfg);
430	}
431
432
433	/** @see Cfg_Tmpl::TransferToWindow. */
434	virtual bool TransferToWindow()
435	{
436		m_temp_path = m_real_path.GetRaw();
437
438		return Cfg_Str::TransferToWindow();
439	}
440
441	/** @see Cfg_Tmpl::TransferFromWindow. */
442	virtual bool TransferFromWindow()
443	{
444		if (Cfg_Str::TransferFromWindow()) {
445			m_real_path = CPath(m_temp_path);
446			return true;
447		}
448
449		return false;
450	}
451
452private:
453	wxString m_temp_path;
454	CPath&   m_real_path;
455};
456
457
458/**
459 * Cfg class that takes care of integer types.
460 *
461 * This template is needed since wxValidator only supports normals ints, and
462 * wxConfig for the matter only supports longs, thus some worksarounds are
463 * needed.
464 *
465 * There are two work-arounds:
466 *  1) wxValidator only supports int*, so we need a immediate variable to act
467 *     as a storage. Thus we use Cfg_Tmpl<int> as base class. Thus this class
468 *     contains a integer which we use to pass the value back and forth
469 *     between the widgets.
470 *
471 *  2) wxConfig uses longs to save and read values, thus we need an immediate
472 *     stage when loading and saving the value.
473 */
474template <typename TYPE>
475class Cfg_Int : public Cfg_Tmpl<int>
476{
477public:
478	Cfg_Int( const wxString& keyname, TYPE& value, int defaultVal = 0 )
479	 : Cfg_Tmpl<int>( keyname, m_temp_value, defaultVal ),
480	   m_real_value( value ),
481	   m_temp_value( value )
482	{}
483
484
485	virtual void LoadFromFile(wxConfigBase* cfg)
486	{
487		long tmp = 0;
488		cfg->Read( GetKey(), &tmp, m_default );
489
490		// Set the temp value
491		m_temp_value = (int)tmp;
492		// Set the actual value
493		m_real_value = (TYPE)tmp;
494	}
495
496	virtual void SaveToFile(wxConfigBase* cfg)
497	{
498		cfg->Write( GetKey(), (long)m_real_value );
499	}
500
501
502#ifndef AMULE_DAEMON
503	virtual bool TransferFromWindow()
504	{
505		if ( Cfg_Tmpl<int>::TransferFromWindow() ) {
506			m_real_value = (TYPE)m_temp_value;
507
508			return true;
509		}
510
511		return false;
512	}
513
514	virtual bool TransferToWindow()
515	{
516		m_temp_value = (int)m_real_value;
517
518		if ( Cfg_Tmpl<int>::TransferToWindow() ) {
519
520			// In order to let us update labels on slider-changes, we trigger a event
521			wxSlider *slider = dynamic_cast<wxSlider *>(m_widget);
522			if (slider) {
523				int id = m_widget->GetId();
524				int pos = slider->GetValue();
525				wxScrollEvent evt( wxEVT_SCROLL_THUMBRELEASE, id, pos );
526				m_widget->GetEventHandler()->ProcessEvent( evt );
527			}
528
529			return true;
530		}
531
532		return false;
533	}
534#endif
535
536protected:
537
538	TYPE&	m_real_value;
539	int		m_temp_value;
540};
541
542
543/**
544 * Helper function for creating new Cfg_Ints.
545 *
546 * @param keyname The cfg-key under which the item should be saved.
547 * @param value The variable to syncronize. The type of this variable defines the type used to create the Cfg_Int.
548 * @param defaultVal The default value if the key isn't found when loading the value.
549 * @return A pointer to the new Cfg_Int object. The caller is responsible for deleting it.
550 *
551 * This template-function returns a Cfg_Int of the appropriate type for the
552 * variable used as argument and should be used to avoid having to specify
553 * the integer type when adding a new Cfg_Int, since that's just increases
554 * the maintainence burden.
555 */
556template <class TYPE>
557Cfg_Base* MkCfg_Int( const wxString& keyname, TYPE& value, int defaultVal )
558{
559	return new Cfg_Int<TYPE>( keyname, value, defaultVal );
560}
561
562
563/**
564 * Cfg-class for bools.
565 */
566class Cfg_Bool : public Cfg_Tmpl<bool>
567{
568public:
569	Cfg_Bool( const wxString& keyname, bool& value, bool defaultVal )
570	 : Cfg_Tmpl<bool>( keyname, value, defaultVal )
571	{}
572
573
574	virtual void LoadFromFile(wxConfigBase* cfg)
575	{
576		cfg->Read( GetKey(), &m_value, m_default );
577	}
578
579	virtual void SaveToFile(wxConfigBase* cfg)
580	{
581		cfg->Write( GetKey(), m_value );
582	}
583};
584
585
586#ifndef AMULE_DAEMON
587
588class Cfg_Colour : public Cfg_Base
589{
590      public:
591	Cfg_Colour(const wxString& key, wxColour& colour)
592		: Cfg_Base(key),
593		  m_colour(colour),
594		  m_default(CMuleColour(colour).GetULong())
595	{}
596
597	virtual void LoadFromFile(wxConfigBase* cfg)
598	{
599		long int rgb;
600		cfg->Read(GetKey(), &rgb, m_default);
601		m_colour.Set(rgb);
602	}
603
604	virtual void SaveToFile(wxConfigBase* cfg)
605	{
606		cfg->Write(GetKey(), static_cast<long int>(CMuleColour(m_colour).GetULong()));
607	}
608
609      private:
610	wxColour&	m_colour;
611	long int	m_default;
612};
613
614
615typedef struct {
616	int	 id;
617	bool	 available;
618	wxString displayname;
619	wxString name;
620} LangInfo;
621
622
623/**
624 * The languages aMule has translation for.
625 *
626 * Add new languages here.
627 * Then activate the test code in Cfg_Lang::UpdateChoice below!
628 */
629static LangInfo aMuleLanguages[] = {
630	{ wxLANGUAGE_DEFAULT,				true,	wxEmptyString,	wxTRANSLATE("System default") },
631	{ wxLANGUAGE_ALBANIAN,				false,	wxEmptyString,	wxTRANSLATE("Albanian") },
632	{ wxLANGUAGE_ARABIC,				false,	wxEmptyString,	wxTRANSLATE("Arabic") },
633	{ wxLANGUAGE_ASTURIAN,				false,	wxEmptyString,	wxTRANSLATE("Asturian") },
634	{ wxLANGUAGE_BASQUE,				false,	wxEmptyString,	wxTRANSLATE("Basque") },
635	{ wxLANGUAGE_BULGARIAN,				false,	wxEmptyString,	wxTRANSLATE("Bulgarian") },
636	{ wxLANGUAGE_CATALAN,				false,	wxEmptyString,	wxTRANSLATE("Catalan") },
637	{ wxLANGUAGE_CHINESE_SIMPLIFIED,	false,	wxEmptyString,	wxTRANSLATE("Chinese (Simplified)") },
638	{ wxLANGUAGE_CHINESE_TRADITIONAL,	false,	wxEmptyString,	wxTRANSLATE("Chinese (Traditional)") },
639	{ wxLANGUAGE_CROATIAN,				false,	wxEmptyString,	wxTRANSLATE("Croatian") },
640	{ wxLANGUAGE_CZECH,					false,	wxEmptyString,	wxTRANSLATE("Czech") },
641	{ wxLANGUAGE_DANISH,				false,	wxEmptyString,	wxTRANSLATE("Danish") },
642	{ wxLANGUAGE_DUTCH,					false,	wxEmptyString,	wxTRANSLATE("Dutch") },
643	{ wxLANGUAGE_ENGLISH,				false,	wxEmptyString,	wxTRANSLATE("English (U.K.)") },
644	{ wxLANGUAGE_ESTONIAN,				false,	wxEmptyString,	wxTRANSLATE("Estonian") },
645	{ wxLANGUAGE_FINNISH,				false,	wxEmptyString,	wxTRANSLATE("Finnish") },
646	{ wxLANGUAGE_FRENCH,				false,	wxEmptyString,	wxTRANSLATE("French") },
647	{ wxLANGUAGE_GALICIAN,				false,	wxEmptyString,	wxTRANSLATE("Galician") },
648	{ wxLANGUAGE_GERMAN,				false,	wxEmptyString,	wxTRANSLATE("German") },
649	{ wxLANGUAGE_GREEK,					false,	wxEmptyString,	wxTRANSLATE("Greek") },
650	{ wxLANGUAGE_HEBREW,				false,	wxEmptyString,	wxTRANSLATE("Hebrew") },
651	{ wxLANGUAGE_HUNGARIAN,				false,	wxEmptyString,	wxTRANSLATE("Hungarian") },
652	{ wxLANGUAGE_ITALIAN,				false,	wxEmptyString,	wxTRANSLATE("Italian") },
653	{ wxLANGUAGE_ITALIAN_SWISS,			false,	wxEmptyString,	wxTRANSLATE("Italian (Swiss)") },
654	{ wxLANGUAGE_JAPANESE,				false,	wxEmptyString,	wxTRANSLATE("Japanese") },
655	{ wxLANGUAGE_KOREAN,				false,	wxEmptyString,	wxTRANSLATE("Korean") },
656	{ wxLANGUAGE_LITHUANIAN,			false,	wxEmptyString,	wxTRANSLATE("Lithuanian") },
657	{ wxLANGUAGE_NORWEGIAN_NYNORSK,		false,	wxEmptyString,	wxTRANSLATE("Norwegian (Nynorsk)") },
658	{ wxLANGUAGE_POLISH,				false,	wxEmptyString,	wxTRANSLATE("Polish") },
659	{ wxLANGUAGE_PORTUGUESE,			false,	wxEmptyString,	wxTRANSLATE("Portuguese") },
660	{ wxLANGUAGE_PORTUGUESE_BRAZILIAN,	false,	wxEmptyString,	wxTRANSLATE("Portuguese (Brazilian)") },
661	{ wxLANGUAGE_RUSSIAN,				false,	wxEmptyString,	wxTRANSLATE("Russian") },
662	{ wxLANGUAGE_SLOVENIAN,				false,	wxEmptyString,	wxTRANSLATE("Slovenian") },
663	{ wxLANGUAGE_SPANISH,				false,	wxEmptyString,	wxTRANSLATE("Spanish") },
664	{ wxLANGUAGE_SWEDISH,				false,	wxEmptyString,	wxTRANSLATE("Swedish") },
665	{ wxLANGUAGE_TURKISH,				false,	wxEmptyString,	wxTRANSLATE("Turkish") },
666	{ wxLANGUAGE_UKRAINIAN,				false,	wxEmptyString,	wxTRANSLATE("Ukrainian") },
667};
668
669
670typedef Cfg_Int<int> Cfg_PureInt;
671
672class Cfg_Lang : public Cfg_PureInt, public Cfg_Lang_Base
673{
674public:
675	Cfg_Lang()
676		: Cfg_PureInt( wxEmptyString, m_selection, 0 )
677	{
678		m_languagesReady = false;
679		m_changePos = 0;
680	}
681
682	virtual void LoadFromFile(wxConfigBase* WXUNUSED(cfg)) {}
683	virtual void SaveToFile(wxConfigBase* WXUNUSED(cfg)) {}
684
685
686	virtual bool TransferFromWindow()
687	{
688		if (!m_languagesReady) {
689			return true;	// nothing changed, no problem
690		}
691
692		if ( Cfg_PureInt::TransferFromWindow() ) {
693			// find wx ID of selected language
694			int i = 0;
695			while (m_selection > 0) {
696				i++;
697				if (aMuleLanguages[i].available) {
698					m_selection--;
699				}
700			}
701			int id = aMuleLanguages[i].id;
702
703			// save language selection
704			thePrefs::SetLanguageID(wxLang2Str(id));
705
706			return true;
707		}
708
709		return false;
710	}
711
712
713	virtual bool TransferToWindow()
714	{
715		m_langSelector = dynamic_cast<wxChoice*>(m_widget);	// doesn't work in ctor!
716		if (m_languagesReady) {
717			FillChoice();
718		} else {
719			int wxId = StrLang2wx(thePrefs::GetLanguageID());
720			m_langSelector->Clear();
721			m_selection = 0;
722			for (uint32 i = 0; i < itemsof(aMuleLanguages); i++) {
723				if ( aMuleLanguages[i].id == wxId ) {
724					m_langSelector->Append(wxString(wxGetTranslation(aMuleLanguages[i].name)) + wxT(" [") + aMuleLanguages[i].name + wxT("]"));
725					break;
726				}
727			}
728			m_langSelector->Append(_("Change Language"));
729			m_changePos = m_langSelector->GetCount() - 1;
730		}
731
732		return Cfg_PureInt::TransferToWindow();
733	}
734
735	virtual void UpdateChoice(int pos)
736	{
737		if (!m_languagesReady && pos == m_changePos) {
738			// Find available languages and translate them.
739			// This is only done when the user selects "Change Language"
740			// Language is changed rarely, and the go-through-all locales takes a considerable
741			// time when the settings dialog is opened for the first time.
742			wxBusyCursor busyCursor;
743			aMuleLanguages[0].displayname = wxGetTranslation(aMuleLanguages[0].name);
744
745			// This supresses error-messages about invalid locales
746			for (unsigned int i = 1; i < itemsof(aMuleLanguages); ++i) {
747				if ((aMuleLanguages[i].id > wxLANGUAGE_USER_DEFINED) || wxLocale::IsAvailable(aMuleLanguages[i].id)) {
748					wxLogNull	logTarget;
749					wxLocale 	locale_to_check;
750					InitLocale(locale_to_check, aMuleLanguages[i].id);
751					if (locale_to_check.IsOk() && locale_to_check.IsLoaded(wxT(PACKAGE))) {
752						aMuleLanguages[i].displayname = wxString(wxGetTranslation(aMuleLanguages[i].name)) + wxT(" [") + aMuleLanguages[i].name + wxT("]");
753						aMuleLanguages[i].available = true;
754#if 0
755						// Check for language problems
756						// Activate this code temporarily after messing with the languages!
757						int wxid = StrLang2wx(wxLang2Str(aMuleLanguages[i].id));
758						if (wxid != aMuleLanguages[i].id) {
759							AddDebugLogLineN(logGeneral, CFormat(wxT("Language problem for %s : aMule id %d != wx id %d"))
760								% aMuleLanguages[i].name % aMuleLanguages[i].id % wxid);
761						}
762#endif
763					}
764				}
765			}
766			// Restore original locale
767			wxLocale tmpLocale;
768			InitLocale(tmpLocale, theApp->m_locale.GetLanguage());
769			FillChoice();
770			if (m_langSelector->GetCount() == 1) {
771				wxMessageBox(_("There are no translations installed for aMule"), _("No languages available"), wxICON_INFORMATION | wxOK);
772			}
773			m_langSelector->SetSelection(m_selection);
774			m_languagesReady = true;
775		}
776	}
777
778protected:
779	int	m_selection;
780
781private:
782	void FillChoice()
783	{
784		int wxId = StrLang2wx(thePrefs::GetLanguageID());
785		m_langSelector->Clear();
786		// Add all available languages and find the index of the selected language.
787		for ( unsigned int i = 0, j = 0; i < itemsof(aMuleLanguages); i++) {
788			if (aMuleLanguages[i].available) {
789				m_langSelector->Append(aMuleLanguages[i].displayname);
790				if ( aMuleLanguages[i].id == wxId ) {
791					m_selection = j;
792				}
793				j++;
794			}
795		}
796	}
797
798	bool m_languagesReady;	// true: all translations calculated
799	int	 m_changePos;
800	wxChoice * m_langSelector;
801};
802
803#endif /* ! AMULE_DAEMON */
804
805void Cfg_Lang_Base::UpdateChoice(int) {}	// dummy
806
807class Cfg_Skin : public Cfg_Str
808{
809public:
810	Cfg_Skin( const wxString& keyname, wxString& value, const wxString& defaultVal = EmptyString )
811		: Cfg_Str( keyname, value, defaultVal ),
812		  m_is_skin(false)
813	{}
814
815#ifndef AMULE_DAEMON
816	virtual bool TransferFromWindow()
817	{
818		if ( Cfg_Str::TransferFromWindow() ) {
819			if (m_is_skin) {
820				wxChoice *skinSelector = dynamic_cast<wxChoice*>(m_widget);
821				// "- default -" is always the first
822				if (skinSelector->GetSelection() == 0) {
823					m_value.Clear();
824				}
825			}
826			return true;
827		}
828
829		return false;
830	}
831
832
833	virtual bool TransferToWindow()
834	{
835
836		wxChoice *skinSelector = dynamic_cast<wxChoice*>(m_widget);
837		skinSelector->Clear();
838
839		wxString folder;
840		int flags = wxDIR_DIRS;
841		wxString filespec;
842		wxString defaultSelection = _("- default -");
843//#warning there has to be a better way...
844		if ( GetKey() == wxT("/SkinGUIOptions/Skin") ) {
845			folder = wxT("skins");
846			m_is_skin = true;
847			flags = wxDIR_FILES;
848			filespec = wxT("*.zip");
849			skinSelector->Append(defaultSelection);
850		} else {
851			folder = wxT("webserver");
852		}
853		wxString dirName(JoinPaths(GetConfigDir(theApp->m_configFile), folder));
854		wxString Filename;
855		wxDir d;
856
857		if (wxDir::Exists(dirName) &&
858			d.Open(dirName) &&
859			d.GetFirst(& Filename, filespec, flags)
860			)
861		{
862			do
863			{
864				if (m_is_skin) {
865					Filename = wxT("User:") + Filename;
866				}
867				skinSelector->Append(Filename);
868			}
869			while (d.GetNext(&Filename));
870		}
871
872		wxString dataDir;
873		if (m_is_skin) {
874			dataDir = wxStandardPaths::Get().GetDataDir();
875		} else {
876			dataDir = wxStandardPaths::Get().GetResourcesDir();
877		}
878#if !defined(__WXMSW__) && !defined(__WXMAC__)
879		dataDir = dataDir.BeforeLast(wxT('/')) + wxT("/amule");
880#endif
881		wxString systemDir(JoinPaths(dataDir,folder));
882
883		if (wxDir::Exists(systemDir) &&
884			d.Open(systemDir) &&
885			d.GetFirst(& Filename, filespec, flags)
886			)
887		{
888			do
889			{
890				if (m_is_skin) {
891					Filename = wxT("System:") +  Filename;
892				}
893				// avoid duplicates for webserver templates
894				if (skinSelector->FindString(Filename) == wxNOT_FOUND) {
895					skinSelector->Append(Filename);
896				}
897			}
898			while (d.GetNext(&Filename));
899		}
900
901		if ( skinSelector->GetCount() == 0 ) {
902			skinSelector->Append(_("no options available"));
903		}
904
905		int id = skinSelector->FindString(m_value);
906		if ( id == wxNOT_FOUND ) {
907			id = 0;
908			if (m_is_skin) {
909				m_value = defaultSelection;
910			}
911		}
912		skinSelector->SetSelection(id);
913
914		return Cfg_Str::TransferToWindow();
915	}
916#endif /* ! AMULE_DAEMON */
917
918      protected:
919	bool	m_is_skin;
920};
921
922
923/// new implementation
924CPreferences::CPreferences()
925{
926	srand( wxGetLocalTimeMillis().GetLo() ); // we need random numbers sometimes
927
928	// load preferences.dat or set standard values
929	wxString fullpath(theApp->ConfigDir + wxT("preferences.dat"));
930	CFile preffile;
931	if (wxFileExists(fullpath)) {
932		if (preffile.Open(fullpath, CFile::read)) {
933			try {
934				preffile.ReadUInt8(); // Version. Value is not used.
935				s_userhash = preffile.ReadHash();
936			} catch (const CSafeIOException& e) {
937				AddDebugLogLineC(logGeneral,
938					wxT("Error while reading userhash: ") + e.what());
939			}
940		}
941	}
942
943	if (s_userhash.IsEmpty()) {
944		for (int i = 0; i < 8; i++) {
945			RawPokeUInt16(s_userhash.GetHash() + (i * 2), rand());
946		}
947
948		Save();
949	}
950
951	// Mark hash as an eMule-type hash
952	// See also CUpDownClient::GetHashType
953	s_userhash[5] = 14;
954	s_userhash[14] = 111;
955
956#ifndef CLIENT_GUI
957	LoadPreferences();
958	ReloadSharedFolders();
959
960	// serverlist adresses
961	CTextFile slistfile;
962	if (slistfile.Open(theApp->ConfigDir + wxT("addresses.dat"), CTextFile::read)) {
963		adresses_list = slistfile.ReadLines();
964	}
965#endif
966}
967
968//
969// Gets called at init time
970//
971void CPreferences::BuildItemList( const wxString& appdir )
972{
973#ifndef AMULE_DAEMON
974	#define NewCfgItem(ID, COMMAND)	s_CfgList[ID] = COMMAND
975#else
976	int current_id = 0;
977	#define NewCfgItem(ID, COMMAND)	s_CfgList[++current_id] = COMMAND
978#endif /* AMULE_DAEMON */
979
980	/**
981	 * User settings
982	 **/
983	NewCfgItem(IDC_NICK,		(new Cfg_Str(  wxT("/eMule/Nick"), s_nick, wxT("http://www.aMule.org") )));
984#ifndef AMULE_DAEMON
985	Cfg_Lang * cfgLang = new Cfg_Lang();
986	s_cfgLang = cfgLang;
987	NewCfgItem(IDC_LANGUAGE,	cfgLang);
988#endif
989
990	/**
991	 * Browser options
992	 **/
993	#ifdef __WXMAC__
994		wxString	customBrowser = wxT("/usr/bin/open");
995	#else
996		wxString	customBrowser; // left empty
997	#endif
998
999	NewCfgItem(IDC_BROWSERTABS,	(new Cfg_Bool( wxT("/Browser/OpenPageInTab"), s_BrowserTab, true )));
1000	NewCfgItem(IDC_BROWSERSELF,	(new Cfg_Str(  wxT("/Browser/CustomBrowserString"), s_CustomBrowser, customBrowser )));
1001
1002
1003	/**
1004	 * Misc
1005	 **/
1006	NewCfgItem(IDC_QUEUESIZE,	(MkCfg_Int( wxT("/eMule/QueueSizePref"), s_iQueueSize, 50 )));
1007
1008
1009#ifdef __DEBUG__
1010	/**
1011	 * Debugging
1012	 **/
1013	NewCfgItem(ID_VERBOSEDEBUG, (new Cfg_Bool( wxT("/eMule/VerboseDebug"), s_bVerbose, false )));
1014#endif
1015
1016	/**
1017	 * Connection settings
1018	 **/
1019	NewCfgItem(IDC_MAXUP,		(MkCfg_Int( wxT("/eMule/MaxUpload"), s_maxupload, 0 )));
1020	NewCfgItem(IDC_MAXDOWN,		(MkCfg_Int( wxT("/eMule/MaxDownload"), s_maxdownload, 0 )));
1021	NewCfgItem(IDC_SLOTALLOC,	(MkCfg_Int( wxT("/eMule/SlotAllocation"), s_slotallocation, 2 )));
1022	NewCfgItem(IDC_PORT,		(MkCfg_Int( wxT("/eMule/Port"), s_port, DEFAULT_TCP_PORT )));
1023	NewCfgItem(IDC_UDPPORT,		(MkCfg_Int( wxT("/eMule/UDPPort"), s_udpport, DEFAULT_UDP_PORT )));
1024	NewCfgItem(IDC_UDPENABLE,	(new Cfg_Bool( wxT("/eMule/UDPEnable"), s_UDPEnable, true )));
1025	NewCfgItem(IDC_ADDRESS,		(new Cfg_Str( wxT("/eMule/Address"), s_Addr, wxEmptyString)));
1026	NewCfgItem(IDC_AUTOCONNECT,	(new Cfg_Bool( wxT("/eMule/Autoconnect"), s_autoconnect, true )));
1027	NewCfgItem(IDC_MAXSOURCEPERFILE,	(MkCfg_Int( wxT("/eMule/MaxSourcesPerFile"), s_maxsourceperfile, 300 )));
1028	NewCfgItem(IDC_MAXCON,		(MkCfg_Int( wxT("/eMule/MaxConnections"), s_maxconnections, GetRecommendedMaxConnections() )));
1029	NewCfgItem(IDC_MAXCON5SEC,	(MkCfg_Int( wxT("/eMule/MaxConnectionsPerFiveSeconds"), s_MaxConperFive, 20 )));
1030
1031	/**
1032	 * Proxy
1033	 **/
1034	NewCfgItem(ID_PROXY_ENABLE_PROXY,	(new Cfg_Bool( wxT("/Proxy/ProxyEnableProxy"), s_ProxyData.m_proxyEnable, false )));
1035	NewCfgItem(ID_PROXY_TYPE,		(MkCfg_Int( wxT("/Proxy/ProxyType"), s_ProxyData.m_proxyType, 0 )));
1036	NewCfgItem(ID_PROXY_NAME,		(new Cfg_Str( wxT("/Proxy/ProxyName"), s_ProxyData.m_proxyHostName, wxEmptyString )));
1037	NewCfgItem(ID_PROXY_PORT,		(MkCfg_Int( wxT("/Proxy/ProxyPort"), s_ProxyData.m_proxyPort, 1080 )));
1038	NewCfgItem(ID_PROXY_ENABLE_PASSWORD,	(new Cfg_Bool( wxT("/Proxy/ProxyEnablePassword"), s_ProxyData.m_enablePassword, false )));
1039	NewCfgItem(ID_PROXY_USER,		(new Cfg_Str( wxT("/Proxy/ProxyUser"), s_ProxyData.m_userName, wxEmptyString )));
1040	NewCfgItem(ID_PROXY_PASSWORD,		(new Cfg_Str( wxT("/Proxy/ProxyPassword"), s_ProxyData.m_password, wxEmptyString )));
1041// These were copied from eMule config file, maybe someone with windows can complete this?
1042//	NewCfgItem(ID_PROXY_AUTO_SERVER_CONNECT_WITHOUT_PROXY,	(new Cfg_Bool( wxT("/Proxy/Proxy????"), s_Proxy????, false )));
1043
1044	/**
1045	 * Servers
1046	 **/
1047	NewCfgItem(IDC_REMOVEDEAD,	(new Cfg_Bool( wxT("/eMule/RemoveDeadServer"), s_deadserver, 1 )));
1048	NewCfgItem(IDC_SERVERRETRIES,	(MkCfg_Int( wxT("/eMule/DeadServerRetry"), s_deadserverretries, 3 )));
1049	NewCfgItem(IDC_SERVERKEEPALIVE,	(MkCfg_Int( wxT("/eMule/ServerKeepAliveTimeout"), s_dwServerKeepAliveTimeoutMins, 0 )));
1050	NewCfgItem(IDC_RECONN,		(new Cfg_Bool( wxT("/eMule/Reconnect"), s_reconnect, true )));
1051	NewCfgItem(IDC_SCORE,		(new Cfg_Bool( wxT("/eMule/Scoresystem"), s_scorsystem, true )));
1052	NewCfgItem(IDC_AUTOSERVER,	(new Cfg_Bool( wxT("/eMule/Serverlist"), s_autoserverlist, false )));
1053	NewCfgItem(IDC_UPDATESERVERCONNECT,	(new Cfg_Bool( wxT("/eMule/AddServerListFromServer"), s_addserversfromserver, false)));
1054	NewCfgItem(IDC_UPDATESERVERCLIENT,	(new Cfg_Bool( wxT("/eMule/AddServerListFromClient"), s_addserversfromclient, false )));
1055	NewCfgItem(IDC_SAFESERVERCONNECT,	(new Cfg_Bool( wxT("/eMule/SafeServerConnect"), s_safeServerConnect, false )));
1056	NewCfgItem(IDC_AUTOCONNECTSTATICONLY,	(new Cfg_Bool( wxT("/eMule/AutoConnectStaticOnly"), s_autoconnectstaticonly, false )));
1057	NewCfgItem(IDC_UPNP_ENABLED,	(new Cfg_Bool( wxT("/eMule/UPnPEnabled"), s_UPnPEnabled, false )));
1058	NewCfgItem(IDC_UPNPTCPPORT,	(MkCfg_Int( wxT("/eMule/UPnPTCPPort"), s_UPnPTCPPort, 50000 )));
1059	NewCfgItem(IDC_SMARTIDCHECK,	(new Cfg_Bool( wxT("/eMule/SmartIdCheck"), s_smartidcheck, true )));
1060	// Enabled networks
1061	NewCfgItem( IDC_NETWORKKAD, (new Cfg_Bool( wxT("/eMule/ConnectToKad"),	s_ConnectToKad, true )) );
1062	NewCfgItem( IDC_NETWORKED2K, ( new Cfg_Bool( wxT("/eMule/ConnectToED2K"),	s_ConnectToED2K, true ) ));
1063
1064
1065	/**
1066	 * Files
1067	 **/
1068	NewCfgItem(IDC_TEMPFILES,	(new Cfg_Path(  wxT("/eMule/TempDir"), 	s_tempdir, appdir + wxT("Temp") )));
1069
1070	#if defined(__WXMAC__) || defined(__WXMSW__)
1071		wxString incpath = wxStandardPaths::Get().GetDocumentsDir();
1072		if (incpath.IsEmpty()) {
1073			// There is a built-in possibility for this call to fail, though I can't imagine a reason for that.
1074			incpath = appdir + wxT("Incoming");
1075		} else {
1076			incpath = JoinPaths(incpath, wxT("aMule Downloads"));
1077		}
1078	#else
1079		wxString incpath = appdir + wxT("Incoming");
1080	#endif
1081	NewCfgItem(IDC_INCFILES,	(new Cfg_Path(  wxT("/eMule/IncomingDir"), s_incomingdir, incpath )));
1082
1083	NewCfgItem(IDC_ICH,		(new Cfg_Bool( wxT("/eMule/ICH"), s_ICH, true )));
1084	NewCfgItem(IDC_AICHTRUST,	(new Cfg_Bool( wxT("/eMule/AICHTrust"), s_AICHTrustEveryHash, false )));
1085	NewCfgItem(IDC_CHECKDISKSPACE,	(new Cfg_Bool( wxT("/eMule/CheckDiskspace"), s_checkDiskspace, true )));
1086	NewCfgItem(IDC_MINDISKSPACE,	(MkCfg_Int( wxT("/eMule/MinFreeDiskSpace"), s_uMinFreeDiskSpace, 1 )));
1087	NewCfgItem(IDC_ADDNEWFILESPAUSED,	(new Cfg_Bool( wxT("/eMule/AddNewFilesPaused"), s_addnewfilespaused, false )));
1088	NewCfgItem(IDC_PREVIEWPRIO,	(new Cfg_Bool( wxT("/eMule/PreviewPrio"), s_bpreviewprio, false )));
1089	NewCfgItem(IDC_MANUALSERVERHIGHPRIO,	(new Cfg_Bool( wxT("/eMule/ManualHighPrio"), s_bmanualhighprio, false )));
1090	NewCfgItem(IDC_STARTNEXTFILE,	(new Cfg_Bool( wxT("/eMule/StartNextFile"), s_bstartnextfile, false )));
1091	NewCfgItem(IDC_STARTNEXTFILE_SAME,	(new Cfg_Bool( wxT("/eMule/StartNextFileSameCat"), s_bstartnextfilesame, false )));
1092	NewCfgItem(IDC_STARTNEXTFILE_ALPHA,	(new Cfg_Bool( wxT("/eMule/StartNextFileAlpha"), s_bstartnextfilealpha, false )));
1093	NewCfgItem(IDC_SRCSEEDS,	(new Cfg_Bool( wxT("/ExternalConnect/UseSrcSeeds"), s_UseSrcSeeds, false )));
1094	NewCfgItem(IDC_FILEBUFFERSIZE,	(MkCfg_Int( wxT("/eMule/FileBufferSizePref"), s_iFileBufferSize, 16 )));
1095	NewCfgItem(IDC_DAP,		(new Cfg_Bool( wxT("/eMule/DAPPref"), s_bDAP, true )));
1096	NewCfgItem(IDC_UAP,		(new Cfg_Bool( wxT("/eMule/UAPPref"), s_bUAP, true )));
1097	NewCfgItem(IDC_ALLOCFULLFILE,	(new Cfg_Bool( wxT("/eMule/AllocateFullFile"), s_allocFullFile, false )));
1098
1099	/**
1100	 * Web Server
1101	 */
1102	NewCfgItem(IDC_OSDIR,		(new Cfg_Path(  wxT("/eMule/OSDirectory"), s_OSDirectory,	appdir )));
1103	NewCfgItem(IDC_ONLINESIG,	(new Cfg_Bool( wxT("/eMule/OnlineSignature"), s_onlineSig, false )));
1104	NewCfgItem(IDC_OSUPDATE,	(MkCfg_Int( wxT("/eMule/OnlineSignatureUpdate"), s_OSUpdate, 5 )));
1105	NewCfgItem(IDC_ENABLE_WEB,	(new Cfg_Bool( wxT("/WebServer/Enabled"), s_bWebEnabled, false )));
1106	NewCfgItem(IDC_WEB_PASSWD,	(new Cfg_Str_Encrypted( wxT("/WebServer/Password"), s_sWebPassword )));
1107	NewCfgItem(IDC_WEB_PASSWD_LOW,	(new Cfg_Str_Encrypted( wxT("/WebServer/PasswordLow"), s_sWebLowPassword )));
1108	NewCfgItem(IDC_WEB_PORT,	(MkCfg_Int( wxT("/WebServer/Port"), s_nWebPort, 4711 )));
1109	NewCfgItem(IDC_WEBUPNPTCPPORT,	(MkCfg_Int( wxT("/WebServer/WebUPnPTCPPort"), s_nWebUPnPTCPPort, 50001 )));
1110	NewCfgItem(IDC_UPNP_WEBSERVER_ENABLED,
1111					(new Cfg_Bool( wxT("/WebServer/UPnPWebServerEnabled"), s_UPnPWebServerEnabled, false )));
1112	NewCfgItem(IDC_WEB_GZIP,	(new Cfg_Bool( wxT("/WebServer/UseGzip"), s_bWebUseGzip, true )));
1113	NewCfgItem(IDC_ENABLE_WEB_LOW,	(new Cfg_Bool( wxT("/WebServer/UseLowRightsUser"), s_bWebLowEnabled, false )));
1114	NewCfgItem(IDC_WEB_REFRESH_TIMEOUT,	(MkCfg_Int( wxT("/WebServer/PageRefreshTime"), s_nWebPageRefresh, 120 )));
1115	NewCfgItem(IDC_WEBTEMPLATE,	(new Cfg_Skin( wxT("/WebServer/Template"), s_WebTemplate, wxEmptyString )));
1116
1117	/**
1118	 * External Connections
1119	 */
1120	NewCfgItem(IDC_EXT_CONN_ACCEPT,	(new Cfg_Bool( wxT("/ExternalConnect/AcceptExternalConnections"), s_AcceptExternalConnections, false )));
1121	NewCfgItem(IDC_EXT_CONN_IP,	(new Cfg_Str( wxT("/ExternalConnect/ECAddress"), s_ECAddr, wxEmptyString )));
1122	NewCfgItem(IDC_EXT_CONN_TCP_PORT,	(MkCfg_Int( wxT("/ExternalConnect/ECPort"), s_ECPort, 4712 )));
1123	NewCfgItem(IDC_EXT_CONN_PASSWD,	(new Cfg_Str_Encrypted( wxT("/ExternalConnect/ECPassword"), s_ECPassword, wxEmptyString )));
1124	NewCfgItem(IDC_UPNP_EC_ENABLED,	(new Cfg_Bool( wxT("/ExternalConnect/UPnPECEnabled"), s_UPnPECEnabled, false )));
1125
1126	/**
1127	 * GUI behavior
1128	 **/
1129	NewCfgItem(IDC_MACHIDEONCLOSE,	(new Cfg_Bool( wxT("/GUI/HideOnClose"), s_hideonclose, false )));
1130	NewCfgItem(IDC_ENABLETRAYICON,	(new Cfg_Bool( wxT("/eMule/EnableTrayIcon"), s_trayiconenabled, false )));
1131	NewCfgItem(IDC_MINTRAY,		(new Cfg_Bool( wxT("/eMule/MinToTray"), s_mintotray, false )));
1132	NewCfgItem(IDC_EXIT,		(new Cfg_Bool( wxT("/eMule/ConfirmExit"), s_confirmExit, true )));
1133	NewCfgItem(IDC_STARTMIN,	(new Cfg_Bool( wxT("/eMule/StartupMinimized"), s_startMinimized, false )));
1134
1135	/**
1136	 * GUI appearence
1137	 **/
1138	NewCfgItem(IDC_3DDEPTH,		(MkCfg_Int( wxT("/eMule/3DDepth"), s_depth3D, 10 )));
1139	NewCfgItem(IDC_TOOLTIPDELAY,	(MkCfg_Int( wxT("/eMule/ToolTipDelay"), s_iToolDelayTime, 1 )));
1140	NewCfgItem(IDC_SHOWOVERHEAD,	(new Cfg_Bool( wxT("/eMule/ShowOverhead"), s_bshowoverhead, false )));
1141	NewCfgItem(IDC_EXTCATINFO,	(new Cfg_Bool( wxT("/eMule/ShowInfoOnCatTabs"), s_showCatTabInfos, true )));
1142	NewCfgItem(IDC_FED2KLH,		(new Cfg_Bool( wxT("/Razor_Preferences/FastED2KLinksHandler"), s_FastED2KLinksHandler, true )));
1143	NewCfgItem(IDC_PROGBAR,		(new Cfg_Bool( wxT("/ExternalConnect/ShowProgressBar"), s_ProgBar, true )));
1144	NewCfgItem(IDC_PERCENT,		(new Cfg_Bool( wxT("/ExternalConnect/ShowPercent"), s_Percent, true )));
1145	NewCfgItem(IDC_SKIN,		(new Cfg_Skin(  wxT("/SkinGUIOptions/Skin"), s_Skin, wxEmptyString )));
1146	NewCfgItem(IDC_VERTTOOLBAR,	(new Cfg_Bool( wxT("/eMule/VerticalToolbar"), s_ToolbarOrientation, false )));
1147	NewCfgItem(IDC_SHOW_COUNTRY_FLAGS,	(new Cfg_Bool( wxT("/eMule/GeoIPEnabled"), s_GeoIPEnabled, true )));
1148#ifndef __SVN__
1149	NewCfgItem(IDC_SHOWVERSIONONTITLE,	(new Cfg_Bool( wxT("/eMule/ShowVersionOnTitle"), s_showVersionOnTitle, false )));
1150#endif
1151
1152	/**
1153	 * External Apps
1154	 */
1155	NewCfgItem(IDC_VIDEOPLAYER,	(new Cfg_Str(  wxT("/eMule/VideoPlayer"), s_VideoPlayer, wxEmptyString )));
1156
1157	/**
1158	 * Statistics
1159	 **/
1160	NewCfgItem(IDC_SLIDER,		(MkCfg_Int( wxT("/eMule/StatGraphsInterval"), s_trafficOMeterInterval, 3 )));
1161	NewCfgItem(IDC_SLIDER2,		(MkCfg_Int( wxT("/eMule/statsInterval"), s_statsInterval, 30 )));
1162	NewCfgItem(IDC_DOWNLOAD_CAP,	(MkCfg_Int( wxT("/eMule/DownloadCapacity"), s_maxGraphDownloadRate, 300 )));
1163	NewCfgItem(IDC_UPLOAD_CAP,	(MkCfg_Int( wxT("/eMule/UploadCapacity"), s_maxGraphUploadRate, 100 )));
1164	NewCfgItem(IDC_SLIDER3,		(MkCfg_Int( wxT("/eMule/StatsAverageMinutes"), s_statsAverageMinutes, 5 )));
1165	NewCfgItem(IDC_SLIDER4,		(MkCfg_Int( wxT("/eMule/VariousStatisticsMaxValue"), s_statsMax, 100 )));
1166	NewCfgItem(IDC_CLIENTVERSIONS,	(MkCfg_Int( wxT("/Statistics/MaxClientVersions"), s_maxClientVersions, 0 )));
1167
1168	/**
1169	 * Security
1170	 **/
1171	NewCfgItem(IDC_SEESHARES,	(MkCfg_Int( wxT("/eMule/SeeShare"),	s_iSeeShares, 2 )));
1172	NewCfgItem(IDC_SECIDENT,        (new Cfg_Bool( wxT("/ExternalConnect/UseSecIdent"), s_SecIdent, true )));
1173	NewCfgItem(IDC_IPFCLIENTS,	(new Cfg_Bool( wxT("/ExternalConnect/IpFilterClients"), s_IPFilterClients, true )));
1174	NewCfgItem(IDC_IPFSERVERS,	(new Cfg_Bool( wxT("/ExternalConnect/IpFilterServers"), s_IPFilterServers, true )));
1175	NewCfgItem(IDC_FILTERLAN,		(new Cfg_Bool( wxT("/eMule/FilterLanIPs"), s_filterLanIP, true )));
1176	NewCfgItem(IDC_PARANOID,		(new Cfg_Bool( wxT("/eMule/ParanoidFiltering"), s_paranoidfilter, true )));
1177	NewCfgItem(IDC_AUTOIPFILTER,	(new Cfg_Bool( wxT("/eMule/IPFilterAutoLoad"), s_IPFilterAutoLoad, true )));
1178	NewCfgItem(IDC_IPFILTERURL,	(new Cfg_Str(  wxT("/eMule/IPFilterURL"), s_IPFilterURL, wxEmptyString )));
1179	NewCfgItem(ID_IPFILTERLEVEL,	(MkCfg_Int( wxT("/eMule/FilterLevel"), s_filterlevel, 127 )));
1180	NewCfgItem(IDC_IPFILTERSYS,	(new Cfg_Bool( wxT("/eMule/IPFilterSystem"), s_IPFilterSys, false )));
1181
1182	/**
1183	 * Message Filter
1184	 **/
1185	NewCfgItem(IDC_MSGFILTER,	(new Cfg_Bool( wxT("/eMule/FilterMessages"), s_MustFilterMessages, true )));
1186	NewCfgItem(IDC_MSGFILTER_ALL,	(new Cfg_Bool( wxT("/eMule/FilterAllMessages"), s_FilterAllMessages, false )));
1187	NewCfgItem(IDC_MSGFILTER_NONFRIENDS,	(new Cfg_Bool( wxT("/eMule/MessagesFromFriendsOnly"),	s_msgonlyfriends, false )));
1188	NewCfgItem(IDC_MSGFILTER_NONSECURE,	(new Cfg_Bool( wxT("/eMule/MessageFromValidSourcesOnly"),	s_msgsecure, true )));
1189	NewCfgItem(IDC_MSGFILTER_WORD,	(new Cfg_Bool( wxT("/eMule/FilterWordMessages"), s_FilterSomeMessages, false )));
1190	NewCfgItem(IDC_MSGWORD,		(new Cfg_Str(  wxT("/eMule/MessageFilter"), s_MessageFilterString, wxEmptyString )));
1191	NewCfgItem(IDC_MSGLOG,	(new Cfg_Bool( wxT("/eMule/ShowMessagesInLog"), s_ShowMessagesInLog, true )));
1192	//Todo NewCfgItem(IDC_MSGADVSPAM,	(new Cfg_Bool( wxT("/eMule/AdvancedSpamFilter"), s_IsAdvancedSpamfilterEnabled, true )));
1193	//Todo NewCfgItem(IDC_MSGCAPTCHA,	(new Cfg_Bool( wxT("/eMule/MessageUseCaptchas"), s_IsChatCaptchaEnabled, true )));
1194	s_MiscList.push_back( new Cfg_Bool( wxT("/eMule/AdvancedSpamFilter"), s_IsAdvancedSpamfilterEnabled, true ) );
1195	s_MiscList.push_back( new Cfg_Bool( wxT("/eMule/MessageUseCaptchas"), s_IsChatCaptchaEnabled, true ) );
1196
1197	NewCfgItem(IDC_FILTERCOMMENTS,	(new Cfg_Bool( wxT("/eMule/FilterComments"), s_FilterComments, false )));
1198	NewCfgItem(IDC_COMMENTWORD,		(new Cfg_Str(  wxT("/eMule/CommentFilter"), s_CommentFilterString, wxEmptyString )));
1199
1200	/**
1201	 * Hidden files sharing
1202	 **/
1203	NewCfgItem(IDC_SHAREHIDDENFILES,	(new Cfg_Bool( wxT("/eMule/ShareHiddenFiles"), s_ShareHiddenFiles, false )));
1204
1205	/**
1206	 * Auto-Sorting of downloads
1207	 **/
1208	 NewCfgItem(IDC_AUTOSORT,	 (new Cfg_Bool( wxT("/eMule/AutoSortDownloads"), s_AutoSortDownload, false )));
1209
1210	/**
1211	 * Version check
1212	 **/
1213	 NewCfgItem(IDC_NEWVERSION,	(new Cfg_Bool( wxT("/eMule/NewVersionCheck"), s_NewVersionCheck, true )));
1214
1215	 /**
1216	  * Obfuscation
1217	  **/
1218	NewCfgItem( IDC_SUPPORT_PO, ( new Cfg_Bool( wxT("/Obfuscation/IsClientCryptLayerSupported"), s_IsClientCryptLayerSupported, true )));
1219	NewCfgItem( IDC_ENABLE_PO_OUTGOING, ( new Cfg_Bool( wxT("/Obfuscation/IsCryptLayerRequested"), s_bCryptLayerRequested, true )));
1220	NewCfgItem( IDC_ENFORCE_PO_INCOMING, ( new Cfg_Bool( wxT("/Obfuscation/IsClientCryptLayerRequired"), s_IsClientCryptLayerRequired, false )));
1221#ifndef CLIENT_GUI
1222	// There is no need for GUI items for this two.
1223	s_MiscList.push_back( MkCfg_Int( wxT("/Obfuscation/CryptoPaddingLenght"), s_byCryptTCPPaddingLength, 254 ) );
1224	s_MiscList.push_back( MkCfg_Int( wxT("/Obfuscation/CryptoKadUDPKey"), s_dwKadUDPKey, GetRandomUint32() ) );
1225#endif
1226
1227	/**
1228	 * Power management
1229	 **/
1230	NewCfgItem( IDC_PREVENT_SLEEP, ( new Cfg_Bool( wxT("/PowerManagement/PreventSleepWhileDownloading"), s_preventSleepWhileDownloading, false )));
1231
1232	/**
1233	 * The following doesn't have an associated widget or section
1234	 **/
1235	s_MiscList.push_back( new Cfg_Str(  wxT("/eMule/Language"),			s_languageID ) );
1236	s_MiscList.push_back(    MkCfg_Int( wxT("/eMule/SplitterbarPosition"),		s_splitterbarPosition, 75 ) );
1237	s_MiscList.push_back( new Cfg_Str(  wxT("/eMule/YourHostname"),			s_yourHostname, wxEmptyString ) );
1238	s_MiscList.push_back( new Cfg_Str(  wxT("/eMule/DateTimeFormat"),		s_datetimeformat, wxT("%A, %x, %X") ) );
1239
1240	s_MiscList.push_back(    MkCfg_Int( wxT("/eMule/AllcatType"),			s_allcatFilter, 0 ) );
1241	s_MiscList.push_back( new Cfg_Bool( wxT("/eMule/ShowAllNotCats"),		s_showAllNotCats, false ) );
1242
1243	s_MiscList.push_back( MkCfg_Int( wxT("/eMule/SmartIdState"), s_smartidstate, 0 ) );
1244
1245	s_MiscList.push_back( new Cfg_Bool( wxT("/eMule/DropSlowSources"), 		s_DropSlowSources, false ) );
1246
1247	s_MiscList.push_back( new Cfg_Str(  wxT("/eMule/KadNodesUrl"),			s_KadURL, wxT("http://download.tuxfamily.org/technosalad/utils/nodes.dat") ) );
1248	s_MiscList.push_back( new Cfg_Str(  wxT("/eMule/Ed2kServersUrl"),		s_Ed2kURL, wxT("http://gruk.org/server.met.gz") ) );
1249	s_MiscList.push_back( MkCfg_Int( wxT("/eMule/ShowRatesOnTitle"),		s_showRatesOnTitle, 0 ));
1250
1251	s_MiscList.push_back( new Cfg_Str(  wxT("/eMule/GeoLiteCountryUpdateUrl"),		s_GeoIPUpdateUrl, wxT("http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz") ) );
1252	wxConfigBase::Get()->DeleteEntry(wxT("/eMule/GeoIPUpdateUrl")); // get rid of the old one for a while
1253
1254	s_MiscList.push_back( new Cfg_Str( wxT("/WebServer/Path"),				s_sWebPath, wxT("amuleweb") ) );
1255
1256	s_MiscList.push_back( new Cfg_Str( wxT("/eMule/StatsServerName"),		s_StatsServerName,	wxT("Shorty's ED2K stats") ) );
1257	s_MiscList.push_back( new Cfg_Str( wxT("/eMule/StatsServerURL"),		s_StatsServerURL,	wxT("http://ed2k.shortypower.dyndns.org/?hash=") ) );
1258
1259	s_MiscList.push_back( new Cfg_Bool( wxT("/ExternalConnect/TransmitOnlyUploadingClients"),	s_TransmitOnlyUploadingClients, false ) );
1260
1261#ifndef AMULE_DAEMON
1262	// Colors have been moved from global prefs to CStatisticsDlg
1263	for ( int i = 0; i < cntStatColors; i++ ) {
1264		wxString str = CFormat(wxT("/eMule/StatColor%i")) % i;
1265		s_MiscList.push_back( new Cfg_Colour( str, CStatisticsDlg::acrStat[i] ) );
1266	}
1267#endif
1268
1269	// User events
1270	for (unsigned int i = 0; i < CUserEvents::GetCount(); ++i) {
1271		// We can't use NewCfgItem here, because we need to find these items
1272		// later, which would be impossible in amuled with NewCfgItem.
1273		// The IDs we assign here are high enough to not cause any collision
1274		// even on the daemon.
1275		s_CfgList[USEREVENTS_FIRST_ID + i * USEREVENTS_IDS_PER_EVENT + 1] = new Cfg_Bool(wxT("/UserEvents/") + CUserEvents::GetKey(i) + wxT("/CoreEnabled"), CUserEvents::GetCoreEnableVar(i), false);
1276		s_CfgList[USEREVENTS_FIRST_ID + i * USEREVENTS_IDS_PER_EVENT + 2] = new Cfg_Str(wxT("/UserEvents/") + CUserEvents::GetKey(i) + wxT("/CoreCommand"), CUserEvents::GetCoreCommandVar(i), wxEmptyString);
1277		s_CfgList[USEREVENTS_FIRST_ID + i * USEREVENTS_IDS_PER_EVENT + 3] = new Cfg_Bool(wxT("/UserEvents/") + CUserEvents::GetKey(i) + wxT("/GUIEnabled"), CUserEvents::GetGUIEnableVar(i), false);
1278		s_CfgList[USEREVENTS_FIRST_ID + i * USEREVENTS_IDS_PER_EVENT + 4] = new Cfg_Str(wxT("/UserEvents/") + CUserEvents::GetKey(i) + wxT("/GUICommand"), CUserEvents::GetGUICommandVar(i), wxEmptyString);
1279	}
1280}
1281
1282
1283void CPreferences::EraseItemList()
1284{
1285	while ( s_CfgList.begin() != s_CfgList.end() ) {
1286		delete s_CfgList.begin()->second;
1287		s_CfgList.erase( s_CfgList.begin() );
1288	}
1289
1290	CFGList::iterator it = s_MiscList.begin();
1291	for ( ; it != s_MiscList.end();  ) {
1292		delete *it;
1293		it = s_MiscList.erase( it );
1294	}
1295}
1296
1297
1298void CPreferences::LoadAllItems(wxConfigBase* cfg)
1299{
1300#ifndef CLIENT_GUI
1301	// Preserve values from old config. The global config object may not be set yet
1302	// when BuildItemList() is called, so we need to provide defaults later - here.
1303	if (cfg->HasEntry(wxT("/eMule/ExecOnCompletion"))) {
1304		bool ExecOnCompletion;
1305		cfg->Read(wxT("/eMule/ExecOnCompletion"), &ExecOnCompletion, false);
1306		// Assign to core command, that's the most likely it was.
1307		static_cast<Cfg_Bool*>(s_CfgList[USEREVENTS_FIRST_ID + CUserEvents::DownloadCompleted * USEREVENTS_IDS_PER_EVENT + 1])->SetDefault(ExecOnCompletion);
1308		cfg->DeleteEntry(wxT("/eMule/ExecOnCompletion"));
1309	}
1310	if (cfg->HasEntry(wxT("/eMule/ExecOnCompletionCommand"))) {
1311		wxString ExecOnCompletionCommand;
1312		cfg->Read(wxT("/eMule/ExecOnCompletionCommand"), &ExecOnCompletionCommand, wxEmptyString);
1313		static_cast<Cfg_Str*>(s_CfgList[USEREVENTS_FIRST_ID + CUserEvents::DownloadCompleted * USEREVENTS_IDS_PER_EVENT + 2])->SetDefault(ExecOnCompletionCommand);
1314		cfg->DeleteEntry(wxT("/eMule/ExecOnCompletionCommand"));
1315	}
1316#endif
1317	CFGMap::iterator it_a = s_CfgList.begin();
1318	for ( ; it_a != s_CfgList.end(); ++it_a ) {
1319		it_a->second->LoadFromFile( cfg );
1320	}
1321
1322	CFGList::iterator it_b = s_MiscList.begin();
1323	for ( ; it_b != s_MiscList.end(); ++it_b ) {
1324		(*it_b)->LoadFromFile( cfg );
1325	}
1326
1327	// Preserve old value of UDPDisable
1328	if (cfg->HasEntry(wxT("/eMule/UDPDisable"))) {
1329		bool UDPDisable;
1330		cfg->Read(wxT("/eMule/UDPDisable"), &UDPDisable, false);
1331		SetUDPDisable(UDPDisable);
1332		cfg->DeleteEntry(wxT("/eMule/UDPDisable"));
1333	}
1334
1335	// Preserve old value of UseSkinFiles
1336	if (cfg->HasEntry(wxT("/SkinGUIOptions/UseSkinFiles"))) {
1337		bool UseSkinFiles;
1338		cfg->Read(wxT("/SkinGUIOptions/UseSkinFiles"), &UseSkinFiles, false);
1339		if (!UseSkinFiles) {
1340			s_Skin.Clear();
1341		}
1342		cfg->DeleteEntry(wxT("/SkinGUIOptions/UseSkinFiles"));
1343	}
1344
1345#ifdef __DEBUG__
1346	// Load debug-categories
1347	int count = theLogger.GetDebugCategoryCount();
1348
1349	for ( int i = 0; i < count; i++ ) {
1350		const CDebugCategory& cat = theLogger.GetDebugCategory( i );
1351
1352		bool enabled = false;
1353		cfg->Read( wxT("/Debug/Cat_") + cat.GetName(), &enabled );
1354
1355		theLogger.SetEnabled( cat.GetType(), enabled );
1356	}
1357#endif
1358
1359	// Now do some post-processing / sanity checking on the values we just loaded
1360#ifndef CLIENT_GUI
1361	CheckUlDlRatio();
1362	SetPort(s_port);
1363	if (s_byCryptTCPPaddingLength > 254) {
1364		s_byCryptTCPPaddingLength = GetRandomUint8() % 254;
1365	}
1366	SetSlotAllocation(s_slotallocation);
1367#endif
1368}
1369
1370
1371void CPreferences::SaveAllItems(wxConfigBase* cfg)
1372{
1373	// Save the Cfg values
1374	CFGMap::iterator it_a = s_CfgList.begin();
1375	for ( ; it_a != s_CfgList.end(); ++it_a )
1376		it_a->second->SaveToFile( cfg );
1377
1378	CFGList::iterator it_b = s_MiscList.begin();
1379	for ( ; it_b != s_MiscList.end(); ++it_b )
1380		(*it_b)->SaveToFile( cfg );
1381
1382
1383// Save debug-categories
1384#ifdef __DEBUG__
1385	int count = theLogger.GetDebugCategoryCount();
1386
1387	for ( int i = 0; i < count; i++ ) {
1388		const CDebugCategory& cat = theLogger.GetDebugCategory( i );
1389
1390		cfg->Write( wxT("/Debug/Cat_") + cat.GetName(), cat.IsEnabled() );
1391	}
1392#endif
1393}
1394
1395void CPreferences::SetMaxUpload(uint16 in)
1396{
1397	if ( s_maxupload != in ) {
1398		s_maxupload = in;
1399
1400		// Ensure that the ratio is upheld
1401		CheckUlDlRatio();
1402	}
1403}
1404
1405
1406void CPreferences::SetMaxDownload(uint16 in)
1407{
1408	if ( s_maxdownload != in ) {
1409		s_maxdownload = in;
1410
1411		// Ensure that the ratio is upheld
1412		CheckUlDlRatio();
1413	}
1414}
1415
1416
1417void CPreferences::UnsetAutoServerStart()
1418{
1419	s_autoserverlist = false;
1420}
1421
1422
1423// Here we slightly limit the users' ability to be a bad citizen: for very low upload rates
1424// we force a low download rate, so as to discourage this type of leeching.
1425// We're Open Source, and whoever wants it can do his own mod to get around this, but the
1426// packaged product will try to enforce good behavior.
1427//
1428// Kry note: of course, any leecher mod will be banned asap.
1429void CPreferences::CheckUlDlRatio()
1430{
1431	// Backwards compatibility
1432	if ( s_maxupload == 0xFFFF )
1433		s_maxupload = UNLIMITED;
1434
1435	// Backwards compatibility
1436	if ( s_maxdownload == 0xFFFF )
1437		s_maxdownload = UNLIMITED;
1438
1439	if ( s_maxupload == UNLIMITED )
1440		return;
1441
1442	// Enforce the limits
1443	if ( s_maxupload < 4  ) {
1444		if ( ( s_maxupload * 3 < s_maxdownload ) || ( s_maxdownload == 0 ) )
1445			s_maxdownload = s_maxupload * 3 ;
1446	} else if ( s_maxupload < 10  ) {
1447		if ( ( s_maxupload * 4 < s_maxdownload ) || ( s_maxdownload == 0 ) )
1448			s_maxdownload = s_maxupload * 4;
1449	}
1450}
1451
1452
1453void CPreferences::Save()
1454{
1455	wxString fullpath(theApp->ConfigDir + wxT("preferences.dat"));
1456
1457	CFile preffile;
1458	if (!wxFileExists(fullpath)) {
1459		preffile.Create(fullpath);
1460	}
1461
1462	if (preffile.Open(fullpath, CFile::read_write)) {
1463		try {
1464			preffile.WriteUInt8(PREFFILE_VERSION);
1465			preffile.WriteHash(s_userhash);
1466		} catch (const CIOFailureException& e) {
1467			AddDebugLogLineC(logGeneral, wxT("IO failure while saving user-hash: ") + e.what());
1468		}
1469	}
1470
1471	SavePreferences();
1472
1473	#ifndef CLIENT_GUI
1474	CTextFile sdirfile;
1475	if (sdirfile.Open(theApp->ConfigDir + wxT("shareddir.dat"), CTextFile::write)) {
1476		for (size_t i = 0; i < shareddir_list.size(); ++i) {
1477			sdirfile.WriteLine(CPath::ToUniv(shareddir_list[i]), wxConvUTF8);
1478		}
1479
1480	}
1481	#endif
1482}
1483
1484
1485CPreferences::~CPreferences()
1486{
1487	DeleteContents(m_CatList);
1488}
1489
1490
1491int32 CPreferences::GetRecommendedMaxConnections()
1492{
1493#ifndef CLIENT_GUI
1494	int iRealMax = PlatformSpecific::GetMaxConnections();
1495	if(iRealMax == -1 || iRealMax > 520) {
1496		return 500;
1497	}
1498	if(iRealMax < 20) {
1499		return iRealMax;
1500	}
1501	if(iRealMax <= 256) {
1502		return iRealMax - 10;
1503	}
1504	return iRealMax - 20;
1505#else
1506	return 500;
1507#endif
1508}
1509
1510
1511void CPreferences::SavePreferences()
1512{
1513	wxConfigBase* cfg = wxConfigBase::Get();
1514
1515	cfg->Write( wxT("/eMule/AppVersion"), wxT(VERSION) );
1516
1517	// Save the options
1518	SaveAllItems( cfg );
1519
1520	// Ensure that the changes are saved to disk.
1521	cfg->Flush();
1522}
1523
1524
1525void CPreferences::SaveCats()
1526{
1527	if ( GetCatCount() ) {
1528		wxConfigBase* cfg = wxConfigBase::Get();
1529
1530		// Save the main cat.
1531		cfg->Write( wxT("/eMule/AllcatType"), (int)s_allcatFilter);
1532
1533		// The first category is the default one and should not be counted
1534
1535		cfg->Write( wxT("/General/Count"), (long)(m_CatList.size() - 1) );
1536
1537		uint32 maxcat = m_CatList.size();
1538		for (uint32 i = 1; i < maxcat; i++) {
1539			cfg->SetPath(CFormat(wxT("/Cat#%i")) % i);
1540
1541			cfg->Write( wxT("Title"),	m_CatList[i]->title );
1542			cfg->Write( wxT("Incoming"),	CPath::ToUniv(m_CatList[i]->path) );
1543			cfg->Write( wxT("Comment"),	m_CatList[i]->comment );
1544			cfg->Write( wxT("Color"),	wxString(CFormat(wxT("%u")) % m_CatList[i]->color));
1545			cfg->Write( wxT("Priority"),	(int)m_CatList[i]->prio );
1546		}
1547		// remove deleted cats from config
1548		while (cfg->DeleteGroup(CFormat(wxT("/Cat#%i")) % maxcat++)) {}
1549
1550		cfg->Flush();
1551	}
1552}
1553
1554
1555void CPreferences::LoadPreferences()
1556{
1557	LoadCats();
1558}
1559
1560
1561void CPreferences::LoadCats()
1562{
1563	// default cat ... Meow! =(^.^)=
1564	Category_Struct* defaultcat = new Category_Struct;
1565	defaultcat->prio = 0;
1566	defaultcat->color = 0;
1567
1568	AddCat( defaultcat );
1569
1570	wxConfigBase* cfg = wxConfigBase::Get();
1571
1572	long max = cfg->Read( wxT("/General/Count"), 0l );
1573
1574	for ( int i = 1; i <= max ; i++ ) {
1575		cfg->SetPath(CFormat(wxT("/Cat#%i")) % i);
1576
1577		Category_Struct* newcat = new Category_Struct;
1578
1579		newcat->title = cfg->Read( wxT("Title"), wxEmptyString );
1580		newcat->path  = CPath::FromUniv(cfg->Read(wxT("Incoming"), wxEmptyString));
1581
1582		// Some sanity checking
1583		if ( newcat->title.IsEmpty() || !newcat->path.IsOk() ) {
1584			AddLogLineN(_("Invalid category found, skipping"));
1585
1586			delete newcat;
1587			continue;
1588		}
1589
1590		newcat->comment = cfg->Read( wxT("Comment"), wxEmptyString );
1591		newcat->prio = cfg->Read( wxT("Priority"), 0l );
1592		newcat->color = StrToULong(cfg->Read(wxT("Color"), wxT("0")));
1593
1594		AddCat(newcat);
1595
1596		if (!newcat->path.DirExists()) {
1597			CPath::MakeDir(newcat->path);
1598		}
1599	}
1600}
1601
1602
1603uint16 CPreferences::GetDefaultMaxConperFive()
1604{
1605	return MAXCONPER5SEC;
1606}
1607
1608
1609uint32 CPreferences::AddCat(Category_Struct* cat)
1610{
1611	m_CatList.push_back( cat );
1612
1613	return m_CatList.size() - 1;
1614}
1615
1616
1617void CPreferences::RemoveCat(size_t index)
1618{
1619	if ( index < m_CatList.size() ) {
1620		CatList::iterator it = m_CatList.begin() + index;
1621
1622		delete *it;
1623
1624		m_CatList.erase( it );
1625
1626		// remove cat directory from shares
1627		theApp->sharedfiles->Reload();
1628	}
1629}
1630
1631
1632uint32 CPreferences::GetCatCount()
1633{
1634	return m_CatList.size();
1635}
1636
1637
1638Category_Struct* CPreferences::GetCategory(size_t index)
1639{
1640	wxASSERT( index < m_CatList.size() );
1641
1642	return m_CatList[index];
1643}
1644
1645
1646const CPath& CPreferences::GetCatPath(uint8 index)
1647{
1648	wxASSERT( index < m_CatList.size() );
1649
1650	return m_CatList[index]->path;
1651}
1652
1653
1654uint32 CPreferences::GetCatColor(size_t index)
1655{
1656	wxASSERT( index < m_CatList.size() );
1657
1658	return m_CatList[index]->color;
1659}
1660
1661bool CPreferences::CreateCategory(
1662	Category_Struct *& category,
1663	const wxString& name,
1664	const CPath& path,
1665	const wxString& comment,
1666	uint32 color,
1667	uint8 prio)
1668{
1669	category = new Category_Struct();
1670	category->path = thePrefs::GetIncomingDir();	// set a default in case path is invalid
1671	uint32 cat = AddCat(category);
1672	return UpdateCategory(cat, name, path, comment, color, prio);
1673}
1674
1675bool CPreferences::UpdateCategory(
1676	uint8 cat,
1677	const wxString& name,
1678	const CPath& path,
1679	const wxString& comment,
1680	uint32 color,
1681	uint8 prio)
1682{
1683	Category_Struct *category = m_CatList[cat];
1684
1685	// return true if path is ok, false if not
1686	bool ret = true;
1687	if (!path.IsOk() || (!path.DirExists() && !CPath::MakeDir(path))) {
1688		ret = false;
1689		// keep path as it was
1690	} else if (category->path != path) {
1691		// path changed: reload shared files, adding files in the new path and removing those from the old path
1692		category->path		= path;
1693		theApp->sharedfiles->Reload();
1694	}
1695	category->title			= name;
1696	category->comment		= comment;
1697	category->color			= color;
1698	category->prio			= prio;
1699
1700	SaveCats();
1701	return ret;
1702}
1703
1704
1705wxString CPreferences::GetBrowser()
1706{
1707	wxString cmd(s_CustomBrowser);
1708#ifndef __WXMSW__
1709	if( s_BrowserTab ) {
1710		// This is certainly not the best way to do it, but I'm lazy
1711		if ((wxT("mozilla") == cmd.Right(7)) || (wxT("firefox") == cmd.Right(7))
1712			|| (wxT("MozillaFirebird") == cmd.Right(15))) {
1713			cmd += wxT(" -remote 'openURL(%s, new-tab)'");
1714		}
1715		if ((wxT("galeon") == cmd.Right(6)) || (wxT("epiphany") == cmd.Right(8))) {
1716			cmd += wxT(" -n '%s'");
1717		}
1718		if (wxT("opera") == cmd.Right(5)) {
1719			cmd += wxT(" --newpage '%s'");
1720		}
1721		if (wxT("netscape") == cmd.Right(8)) {
1722			cmd += wxT(" -remote 'openURLs(%s,new-tab)'");
1723		}
1724	}
1725#endif /* !__WXMSW__ */
1726	return cmd;
1727}
1728
1729void CPreferences::SetFilteringClients(bool val)
1730{
1731	if (val != s_IPFilterClients) {
1732		s_IPFilterClients = val;
1733		if (val) {
1734			theApp->clientlist->FilterQueues();
1735		}
1736	}
1737}
1738
1739void CPreferences::SetFilteringServers(bool val)
1740{
1741	if (val != s_IPFilterServers) {
1742		s_IPFilterServers = val;
1743		if (val) {
1744			theApp->serverlist->FilterServers();
1745		}
1746	}
1747}
1748
1749void CPreferences::SetIPFilterLevel(uint8 level)
1750{
1751	if (level != s_filterlevel) {
1752		// Set the new access-level
1753		s_filterlevel = level;
1754#ifndef CLIENT_GUI
1755		// and reload the filter
1756		NotifyAlways_IPFilter_Reload();
1757#endif
1758	}
1759}
1760
1761void CPreferences::SetPort(uint16 val)
1762{
1763	// Warning: Check for +3, because server UDP is TCP+3
1764
1765	if (val +3 > 65535) {
1766		AddLogLineC(_("TCP port can't be higher than 65532 due to server UDP socket being TCP+3"));
1767		AddLogLineN(CFormat(_("Default port will be used (%d)")) % DEFAULT_TCP_PORT);
1768		s_port = DEFAULT_TCP_PORT;
1769	} else {
1770		s_port = val;
1771	}
1772}
1773
1774
1775void CPreferences::ReloadSharedFolders()
1776{
1777#ifndef CLIENT_GUI
1778	shareddir_list.clear();
1779
1780	CTextFile file;
1781	if (file.Open(theApp->ConfigDir + wxT("shareddir.dat"), CTextFile::read)) {
1782		wxArrayString lines = file.ReadLines(txtReadDefault, wxConvUTF8);
1783
1784		for (size_t i = 0; i < lines.size(); ++i) {
1785			CPath path = CPath::FromUniv(lines[i]);
1786
1787			if (path.DirExists()) {
1788				shareddir_list.push_back(path);
1789			} else {
1790				AddLogLineN(CFormat(_("Dropping non-existing shared directory: %s")) % path.GetRaw());
1791			}
1792		}
1793	}
1794#endif
1795}
1796
1797
1798bool CPreferences::IsMessageFiltered(const wxString& message)
1799{
1800	if (s_FilterAllMessages) {
1801		return true;
1802	} else {
1803		if (s_FilterSomeMessages) {
1804			if (s_MessageFilterString.IsSameAs(wxT("*"))){
1805				// Filter anything
1806				return true;
1807			} else {
1808				wxStringTokenizer tokenizer( s_MessageFilterString, wxT(",") );
1809				while (tokenizer.HasMoreTokens()) {
1810					if ( message.Lower().Trim(false).Trim(true).Contains(
1811							tokenizer.GetNextToken().Lower().Trim(false).Trim(true))) {
1812						return true;
1813					}
1814				}
1815				return false;
1816			}
1817		} else {
1818			return false;
1819		}
1820	}
1821}
1822
1823
1824bool CPreferences::IsCommentFiltered(const wxString& comment)
1825{
1826	if (s_FilterComments) {
1827		wxStringTokenizer tokenizer( s_CommentFilterString, wxT(",") );
1828		while (tokenizer.HasMoreTokens()) {
1829			if ( comment.Lower().Trim(false).Trim(true).Contains(
1830					tokenizer.GetNextToken().Lower().Trim(false).Trim(true))) {
1831				return true;
1832			}
1833		}
1834	}
1835	return false;
1836}
1837
1838wxString CPreferences::GetLastHTTPDownloadURL(uint8 t)
1839{
1840	wxConfigBase* cfg = wxConfigBase::Get();
1841	wxString key = CFormat(wxT("/HTTPDownload/URL_%d")) % t;
1842	return cfg->Read(key, wxEmptyString);
1843}
1844
1845void CPreferences::SetLastHTTPDownloadURL(uint8 t, const wxString& val)
1846{
1847	wxConfigBase* cfg = wxConfigBase::Get();
1848	wxString key = CFormat(wxT("/HTTPDownload/URL_%d")) % t;
1849	cfg->Write(key, val);
1850}
1851
1852// File_checked_for_headers
1853