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