1 /*
2 * Copyright (C) 2001-2012 Jacek Sieka, arnetheduck on gmail point com
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
19 #include "stdinc.h"
20
21 #include "SettingsManager.h"
22
23 #include "SimpleXML.h"
24 #include "Util.h"
25 #include "File.h"
26 #include "version.h"
27 #include "AdcHub.h"
28 #include "CID.h"
29 #ifdef WITH_DHT
30 #include "dht/DHT.h"
31 #endif
32 #include "SearchManager.h"
33 #include "StringTokenizer.h"
34
35 namespace dcpp {
36
37 StringList SettingsManager::connectionSpeeds;
38
39 const string SettingsManager::settingTags[] =
40 {
41 // Strings
42 "Nick", "UploadSpeed", "Description", "DownloadDirectory", "EMail",
43 "ExternalIp", "HublistServers", "HttpProxy",
44 "LogDirectory", "LogFormatPostDownload","LogFormatPostFinishedDownload",
45 "LogFormatPostUpload", "LogFormatMainChat", "LogFormatPrivateChat",
46 "TempDownloadDirectory", "BindAddress", "SocksServer",
47 "SocksUser", "SocksPassword", "ConfigVersion", "DefaultAwayMessage",
48 "TimeStampsFormat", "CID", "LogFileMainChat", "LogFilePrivateChat",
49 "LogFileStatus", "LogFileUpload", "LogFileDownload", "LogFileFinishedDownload",
50 "LogFileSystem",
51 "LogFormatSystem", "LogFormatStatus", "LogFileSpy", "LogFormatSpy", "TLSPrivateKeyFile",
52 "TLSCertificateFile", "TLSTrustedCertificatesPath",
53 "Language", "SkipListShare", "InternetIp", "BindIfaceName",
54 "DHTKey", "DynDNSServer", "MimeHandler",
55 "SENTRY",
56 // Ints
57 "IncomingConnections", "InPort", "Slots", "AutoFollow",
58 "ShareHidden", "FilterMessages", "AutoSearch",
59 "AutoSearchTime", "ReportFoundAlternates", "TimeStamps",
60 "IgnoreHubPms", "IgnoreBotPms",
61 "ListDuplicates", "BufferSize", "DownloadSlots", "MaxDownloadSpeed",
62 "LogMainChat", "LogPrivateChat", "LogDownloads","LogFileFinishedDownload",
63 "LogUploads", "MinUploadSpeed", "AutoAway",
64 "SocksPort", "SocksResolve", "KeepLists", "AutoKick",
65 "CompressTransfers", "SFVCheck",
66 "MaxCompression", "NoAwayMsgToBots", "SkipZeroByte", "AdlsBreakOnFirst",
67 "HubUserCommands", "AutoSearchAutoMatch","LogSystem",
68 "LogFilelistTransfers",
69 "SendUnknownCommands", "MaxHashSpeed",
70 "GetUserCountry", "LogStatusMessages", "SearchPassiveAlways",
71 "AddFinishedInstantly", "DontDLAlreadyShared",
72 "UDPPort", "ShowLastLinesLog", "AdcDebug",
73 "SearchHistory", "SetMinislotSize",
74 "MaxFilelistSize", "HighestPrioSize", "HighPrioSize", "NormalPrioSize",
75 "LowPrioSize", "LowestPrio", "AutoDropSpeed", "AutoDropInterval",
76 "AutoDropElapsed", "AutoDropInactivity", "AutoDropMinSources",
77 "AutoDropFilesize", "AutoDropAll", "AutoDropFilelists",
78 "AutoDropDisconnect", "OutgoingConnections", "NoIpOverride", "NoUseTempDir",
79 "ShareTempFiles", "SearchOnlyFreeSlots", "LastSearchType",
80 "SocketInBuffer", "SocketOutBuffer",
81 "AutoRefreshTime", "HashingStartDelay", "UseTLS", "AutoSearchLimit",
82 "AutoKickNoFavs", "PromptPassword",
83 "DontDlAlreadyQueued", "MaxCommandLength", "AllowUntrustedHubs",
84 "AllowUntrustedClients", "TLSPort", "FastHash",
85 "SegmentedDL", "FollowLinks", "SendBloom",
86 "Coral", "SearchFilterShared", "FinishedDLOnlyFull",
87 "SearchMerge", "HashBufferSize", "HashBufferPopulate",
88 "HashBufferNoReserve", "HashBufferPrivate",
89 "UseDHT", "DHTPort",
90 "ReconnectDelay", "AutoDetectIncomingConnection",
91 "BandwidthLimitStart", "BandwidthLimitEnd", "EnableThrottle","TimeDependentThrottle",
92 "MaxDownloadSpeedAlternate", "MaxUploadSpeedAlternate",
93 "MaxDownloadSpeedMain", "MaxUploadSpeedMain",
94 "SlotsAlternateLimiting", "SlotsPrimaryLimiting", "KeepFinishedFiles",
95 "ShowFreeSlotsDesc", "UseIP", "OverLapChunks", "CaseSensitiveFilelist",
96 "IpFilter", "TextColor", "UseLua", "AllowNatt", "IpTOSValue", "SegmentSize",
97 "BindIface", "MinimumSearchInterval", "EnableDynDNS", "AllowUploadOverMultiHubs",
98 "UseADLOnlyOnOwnList", "AllowSimUploads", "CheckTargetsPathsOnStart", "NmdcDebug",
99 "ShareSkipZeroByte", "RequireTLS", "LogSpy", "AppUnitBase",
100 "SENTRY",
101 // Int64
102 "TotalUpload", "TotalDownload",
103 "SENTRY",
104 // Floats
105 "SENTRY"
106 };
107
SettingsManager()108 SettingsManager::SettingsManager()
109 {
110
111 connectionSpeeds.push_back("0.005");
112 connectionSpeeds.push_back("0.01");
113 connectionSpeeds.push_back("0.02");
114 connectionSpeeds.push_back("0.05");
115 connectionSpeeds.push_back("0.1");
116 connectionSpeeds.push_back("0.2");
117 connectionSpeeds.push_back("0.5");
118 connectionSpeeds.push_back("1");
119 connectionSpeeds.push_back("2");
120 connectionSpeeds.push_back("5");
121 connectionSpeeds.push_back("10");
122 connectionSpeeds.push_back("20");
123 connectionSpeeds.push_back("50");
124 connectionSpeeds.push_back("100");
125 connectionSpeeds.push_back("1000");
126
127 for(int i=0; i<SETTINGS_LAST; i++)
128 isSet[i] = false;
129
130 for(int i=0; i<INT_LAST-INT_FIRST; i++) {
131 intDefaults[i] = 0;
132 intSettings[i] = 0;
133 }
134 for(int i=0; i<INT64_LAST-INT64_FIRST; i++) {
135 int64Defaults[i] = 0;
136 int64Settings[i] = 0;
137 }
138 for(int i=0; i<FLOAT_LAST-FLOAT_FIRST; i++) {
139 floatDefaults[i] = 0;
140 floatSettings[i] = 0;
141 }
142
143 setDefault(DOWNLOAD_DIRECTORY, Util::getPath(Util::PATH_DOWNLOADS));
144 setDefault(TEMP_DOWNLOAD_DIRECTORY, Util::getPath(Util::PATH_DOWNLOADS) + "Incomplete" PATH_SEPARATOR_STR);
145 setDefault(SLOTS, 5);
146 setDefault(TCP_PORT, 3000);
147 setDefault(UDP_PORT, 3000);
148 setDefault(TLS_PORT, 3001);
149 setDefault(INCOMING_CONNECTIONS, INCOMING_DIRECT);
150 setDefault(OUTGOING_CONNECTIONS, OUTGOING_DIRECT);
151 setDefault(AUTO_FOLLOW, true);
152 setDefault(SHARE_HIDDEN, false);
153 setDefault(FILTER_MESSAGES, true);
154 setDefault(AUTO_SEARCH, true);
155 setDefault(AUTO_SEARCH_TIME, 2);
156 setDefault(REPORT_ALTERNATES, true);
157 setDefault(TIME_STAMPS, true);
158 setDefault(IGNORE_HUB_PMS, false);
159 setDefault(IGNORE_BOT_PMS, false);
160 setDefault(LIST_DUPES, true);
161 setDefault(BUFFER_SIZE, 64);
162 setDefault(HUBLIST_SERVERS,
163 "http://dchublist.com/hublist.xml.bz2;"
164 "http://dchublist.ru/hublist.xml.bz2"
165 );
166 setDefault(DOWNLOAD_SLOTS, 3);
167 setDefault(SKIPLIST_SHARE, "*.~*|*.*~");
168 setDefault(MAX_DOWNLOAD_SPEED, 0);
169 setDefault(LOG_DIRECTORY, Util::getPath(Util::PATH_USER_LOCAL) + "Logs" PATH_SEPARATOR_STR);
170 setDefault(LOG_UPLOADS, false);
171 setDefault(LOG_DOWNLOADS, false);
172 setDefault(LOG_FINISHED_DOWNLOADS, false);
173 setDefault(LOG_PRIVATE_CHAT, false);
174 setDefault(LOG_MAIN_CHAT, false);
175 setDefault(LOG_SPY, false);
176 setDefault(UPLOAD_SPEED, connectionSpeeds[11]);
177 setDefault(MIN_UPLOAD_SPEED, 0);
178 setDefault(LOG_FORMAT_POST_DOWNLOAD, "[%Y-%m-%d %H:%M:%S] %[target] downloaded from %[userNI] (%[userCID]), %[fileSI] (%[fileSIchunk]), %[speed], %[time], %[fileTR]");
179 setDefault(LOG_FORMAT_POST_FINISHED_DOWNLOAD, "%Y-%m-%d %H:%M: %[target] " + string(_("downloaded from")) + " %[userNI] (%[userCID]), %[fileSI] (%[fileSIsession]), %[speed], %[time], %[fileTR]");
180 setDefault(LOG_FORMAT_POST_UPLOAD, "[%Y-%m-%d %H:%M:%S] %[source] uploaded to %[userNI] (%[userCID]), %[fileSI] (%[fileSIchunk]), %[speed], %[time], %[fileTR]");
181 setDefault(LOG_FORMAT_MAIN_CHAT, "[%Y-%m-%d %H:%M:%S] %[message]");
182 setDefault(LOG_FORMAT_PRIVATE_CHAT, "[%Y-%m-%d %H:%M:%S] %[message]");
183 setDefault(LOG_FORMAT_STATUS, "[%Y-%m-%d %H:%M:%S] %[message]");
184 setDefault(LOG_FORMAT_SYSTEM, "[%Y-%m-%d %H:%M:%S] %[message]");
185 setDefault(LOG_FORMAT_SPY, "[%Y-%m-%d %H:%M:%S] %[message] (%[count])");
186 setDefault(LOG_FILE_MAIN_CHAT, "CHAT/%B - %Y/%[hubNI] (%[hubURL]).log");
187 setDefault(LOG_FILE_STATUS, "STATUS/%B - %Y/%[hubNI] (%[hubURL]).log");
188 setDefault(LOG_FILE_PRIVATE_CHAT, "PM/%B - %Y/%[userNI] (%[userCID]).log");
189 setDefault(LOG_FILE_UPLOAD, "Uploads.log");
190 setDefault(LOG_FILE_DOWNLOAD, "Downloads.log");
191 setDefault(LOG_FILE_FINISHED_DOWNLOAD, "Finished_downloads.log");
192 setDefault(LOG_FILE_SYSTEM, "System.log");
193 setDefault(LOG_FILE_SPY, "Spy.log");
194 setDefault(AUTO_AWAY, false);
195 setDefault(BIND_ADDRESS, "0.0.0.0");
196 setDefault(SOCKS_PORT, 1080);
197 setDefault(SOCKS_RESOLVE, 1);
198 setDefault(CONFIG_VERSION, "0.181"); // 0.181 is the last version missing configversion
199 setDefault(KEEP_LISTS, false);
200 setDefault(AUTO_KICK, false);
201 setDefault(COMPRESS_TRANSFERS, true);
202 setDefault(SFV_CHECK, true);
203 setDefault(DEFAULT_AWAY_MESSAGE, "I'm away. State your business and I might answer later if you're lucky.");
204 setDefault(TIME_STAMPS_FORMAT, "%H:%M");
205 setDefault(MAX_COMPRESSION, 6);
206 setDefault(NO_AWAYMSG_TO_BOTS, true);
207 setDefault(SKIP_ZERO_BYTE, false);
208 setDefault(ADLS_BREAK_ON_FIRST, false);
209 setDefault(HUB_USER_COMMANDS, true);
210 setDefault(AUTO_SEARCH_AUTO_MATCH, false);
211 setDefault(LOG_FILELIST_TRANSFERS, false);
212 setDefault(LOG_SYSTEM, false);
213 setDefault(SEND_UNKNOWN_COMMANDS, true);
214 setDefault(MAX_HASH_SPEED, 0);
215 setDefault(GET_USER_COUNTRY, true);
216 setDefault(LOG_STATUS_MESSAGES, false);
217 setDefault(ADD_FINISHED_INSTANTLY, false);
218 setDefault(DONT_DL_ALREADY_SHARED, false);
219 setDefault(SHOW_LAST_LINES_LOG, 0);
220 setDefault(ADC_DEBUG, false);
221 setDefault(SEARCH_HISTORY, 10);
222 setDefault(SET_MINISLOT_SIZE, 64);
223 setDefault(MAX_FILELIST_SIZE, 4*1024);
224 setDefault(PRIO_HIGHEST_SIZE, 64);
225 setDefault(PRIO_HIGH_SIZE, 0);
226 setDefault(PRIO_NORMAL_SIZE, 0);
227 setDefault(PRIO_LOW_SIZE, 0);
228 setDefault(PRIO_LOWEST, false);
229 setDefault(AUTODROP_SPEED, 1024);
230 setDefault(AUTODROP_INTERVAL, 10);
231 setDefault(AUTODROP_ELAPSED, 15);
232 setDefault(AUTODROP_INACTIVITY, 10);
233 setDefault(AUTODROP_MINSOURCES, 2);
234 setDefault(AUTODROP_FILESIZE, 0);
235 setDefault(AUTODROP_ALL, true);
236 setDefault(AUTODROP_FILELISTS, true);
237 setDefault(AUTODROP_DISCONNECT, true);
238 setDefault(NO_IP_OVERRIDE, false);
239 setDefault(NO_USE_TEMP_DIR, false);
240 setDefault(SHARE_TEMP_FILES, false);
241 setDefault(SEARCH_ONLY_FREE_SLOTS, false);
242 setDefault(SEARCH_FILTER_SHARED, true);
243 setDefault(LAST_SEARCH_TYPE, 0);
244 setDefault(SOCKET_IN_BUFFER, 64*1024);
245 setDefault(SOCKET_OUT_BUFFER, 64*1024);
246 setDefault(TLS_TRUSTED_CERTIFICATES_PATH, Util::getPath(Util::PATH_USER_CONFIG) + "Certificates" PATH_SEPARATOR_STR);
247 setDefault(TLS_PRIVATE_KEY_FILE, Util::getPath(Util::PATH_USER_CONFIG) + "Certificates" PATH_SEPARATOR_STR "client.key");
248 setDefault(TLS_CERTIFICATE_FILE, Util::getPath(Util::PATH_USER_CONFIG) + "Certificates" PATH_SEPARATOR_STR "client.crt");
249 setDefault(AUTO_REFRESH_TIME, 60); // minutes
250 setDefault(HASHING_START_DELAY, 60); // seconds
251 setDefault(USE_TLS, true);
252 setDefault(AUTO_SEARCH_LIMIT, 5);
253 setDefault(AUTO_KICK_NO_FAVS, false);
254 setDefault(PROMPT_PASSWORD, false);
255 setDefault(DONT_DL_ALREADY_QUEUED, false);
256 setDefault(MAX_COMMAND_LENGTH, 16*1024*1024);
257 setDefault(ALLOW_UNTRUSTED_HUBS, true);
258 setDefault(ALLOW_UNTRUSTED_CLIENTS, true);
259 setDefault(FAST_HASH, true);
260 setDefault(SEGMENTED_DL, true);
261 setDefault(FOLLOW_LINKS, false);
262 setDefault(SEND_BLOOM, true);
263 setDefault(CORAL, true);
264 setDefault(FINISHED_DL_ONLY_FULL, true);
265 setDefault(SEARCH_MERGE, true);
266 setDefault(HASH_BUFFER_SIZE_MB, 8);
267 setDefault(HASH_BUFFER_POPULATE, true);
268 setDefault(HASH_BUFFER_NORESERVE, true);
269 setDefault(HASH_BUFFER_PRIVATE, true);
270 setDefault(RECONNECT_DELAY, 15);
271 setDefault(DHT_PORT, 6250);
272 setDefault(USE_DHT, false);
273 setDefault(SEARCH_PASSIVE, false);
274 setDefault(AUTO_DETECT_CONNECTION, false);
275 setDefault(MAX_UPLOAD_SPEED_MAIN, 0);
276 setDefault(MAX_DOWNLOAD_SPEED_MAIN, 0);
277 setDefault(TIME_DEPENDENT_THROTTLE, false);
278 setDefault(THROTTLE_ENABLE, false);
279 setDefault(MAX_DOWNLOAD_SPEED_ALTERNATE, 0);
280 setDefault(MAX_UPLOAD_SPEED_ALTERNATE, 0);
281 setDefault(BANDWIDTH_LIMIT_START, 1);
282 setDefault(BANDWIDTH_LIMIT_END, 1);
283 setDefault(SLOTS_ALTERNATE_LIMITING, 1);
284 setDefault(SLOTS_PRIMARY, 3);
285 setDefault(KEEP_FINISHED_FILES, false);
286 setDefault(USE_IP, true);
287 setDefault(SHOW_FREE_SLOTS_DESC, false);
288 setDefault(OVERLAP_CHUNKS, true);
289 setDefault(CASESENSITIVE_FILELIST, false);
290 setDefault(IPFILTER,false);
291 setDefault(USE_LUA,false);
292 setDefault(ALLOW_NATT, true);
293 setDefault(IP_TOS_VALUE, -1);
294 setDefault(SEGMENT_SIZE, 0);
295 setDefault(BIND_IFACE, false);
296 setDefault(BIND_IFACE_NAME, "");
297 setDefault(MINIMUM_SEARCH_INTERVAL, 60);
298 setDefault(DYNDNS_SERVER, "http://checkip.dyndns.org/index.html");
299 setDefault(DYNDNS_ENABLE, false);
300 setDefault(ALLOW_UPLOAD_MULTI_HUB, true);
301 setDefault(USE_ADL_ONLY_OWN_LIST, false);
302 setDefault(ALLOW_SIM_UPLOADS, true);
303 setDefault(CHECK_TARGETS_PATHS_ON_START, false);
304 setDefault(SHARE_SKIP_ZERO_BYTE, false);
305 setDefault(APP_UNIT_BASE, 0);
306 setSearchTypeDefaults();
307 }
308
load(string const & aFileName)309 void SettingsManager::load(string const& aFileName)
310 {
311 try {
312 SimpleXML xml;
313
314 xml.fromXML(File(aFileName, File::READ, File::OPEN).read());
315
316 xml.resetCurrentChild();
317
318 xml.stepIn();
319
320 if(xml.findChild("Settings"))
321 {
322 xml.stepIn();
323
324 int i;
325
326 for(i=STR_FIRST; i<STR_LAST; i++)
327 {
328 const string& attr = settingTags[i];
329 dcassert(attr.find("SENTRY") == string::npos);
330
331 if(xml.findChild(attr))
332 set(StrSetting(i), xml.getChildData());
333 xml.resetCurrentChild();
334 }
335 for(i=INT_FIRST; i<INT_LAST; i++)
336 {
337 const string& attr = settingTags[i];
338 dcassert(attr.find("SENTRY") == string::npos);
339
340 if(xml.findChild(attr))
341 set(IntSetting(i), Util::toInt(xml.getChildData()));
342 xml.resetCurrentChild();
343 }
344 for(i=FLOAT_FIRST; i<FLOAT_LAST; i++)
345 {
346 const string& attr = settingTags[i];
347 dcassert(attr.find("SENTRY") == string::npos);
348
349 if(xml.findChild(attr))
350 set(FloatSetting(i), Util::toInt(xml.getChildData()) / 1000.);
351 xml.resetCurrentChild();
352 }
353 for(i=INT64_FIRST; i<INT64_LAST; i++)
354 {
355 const string& attr = settingTags[i];
356 dcassert(attr.find("SENTRY") == string::npos);
357
358 if(xml.findChild(attr))
359 set(Int64Setting(i), Util::toInt64(xml.getChildData()));
360 xml.resetCurrentChild();
361 }
362
363 xml.stepOut();
364 }
365
366 xml.resetCurrentChild();
367 if(xml.findChild("SearchTypes")) {
368 try {
369 searchTypes.clear();
370 xml.stepIn();
371 while(xml.findChild("SearchType")) {
372 const string& extensions = xml.getChildData();
373 if(extensions.empty()) {
374 continue;
375 }
376 const string& name = xml.getChildAttrib("Id");
377 if(name.empty()) {
378 continue;
379 }
380 searchTypes[name] = StringTokenizer<string>(extensions, ';').getTokens();
381 }
382 xml.stepOut();
383 } catch(const SimpleXMLException&) {
384 setSearchTypeDefaults();
385 }
386 }
387
388 if(SETTING(PRIVATE_ID).length() != 39 || CID(SETTING(PRIVATE_ID)).isZero()) {
389 set(PRIVATE_ID, CID::generate().toBase32());
390 }
391
392 double v = Util::toDouble(SETTING(CONFIG_VERSION));
393 // if(v < 0.x) { // Fix old settings here }
394
395 if(v <= 0.674) {
396
397 // Formats changed, might as well remove these...
398 unset(LOG_FORMAT_POST_DOWNLOAD);
399 unset(LOG_FORMAT_POST_UPLOAD);
400 unset(LOG_FORMAT_MAIN_CHAT);
401 unset(LOG_FORMAT_PRIVATE_CHAT);
402 unset(LOG_FORMAT_STATUS);
403 unset(LOG_FORMAT_SYSTEM);
404 unset(LOG_FILE_MAIN_CHAT);
405 unset(LOG_FILE_STATUS);
406 unset(LOG_FILE_PRIVATE_CHAT);
407 unset(LOG_FILE_UPLOAD);
408 unset(LOG_FILE_DOWNLOAD);
409 unset(LOG_FILE_SYSTEM);
410 }
411
412 if(SETTING(SET_MINISLOT_SIZE) < 64)
413 set(SET_MINISLOT_SIZE, 64);
414 if(SETTING(AUTODROP_INTERVAL) < 1)
415 set(AUTODROP_INTERVAL, 1);
416 if(SETTING(AUTODROP_ELAPSED) < 1)
417 set(AUTODROP_ELAPSED, 1);
418 if(SETTING(AUTO_SEARCH_LIMIT) > 5)
419 set(AUTO_SEARCH_LIMIT, 5);
420 else if(SETTING(AUTO_SEARCH_LIMIT) < 1)
421 set(AUTO_SEARCH_LIMIT, 1);
422
423 #ifdef _DEBUG
424 set(PRIVATE_ID, CID::generate().toBase32());
425 #endif
426 setDefault(UDP_PORT, SETTING(TCP_PORT));
427
428 File::ensureDirectory(SETTING(TLS_TRUSTED_CERTIFICATES_PATH));
429
430 fire(SettingsManagerListener::Load(), xml);
431
432 xml.stepOut();
433
434 } catch(const Exception&) {
435 if(CID(SETTING(PRIVATE_ID)).isZero())
436 set(PRIVATE_ID, CID::generate().toBase32());
437 }
438 if (SETTING(DHT_KEY).length() != 39 || CID(SETTING(DHT_KEY)).isZero())
439 set(DHT_KEY, CID::generate().toBase32());
440 }
441
save(string const & aFileName)442 void SettingsManager::save(string const& aFileName) {
443
444 SimpleXML xml;
445 xml.addTag("DCPlusPlus");
446 xml.stepIn();
447 xml.addTag("Settings");
448 xml.stepIn();
449
450 int i;
451 string type("type"), curType("string");
452
453 for(i=STR_FIRST; i<STR_LAST; i++)
454 {
455 if(i == CONFIG_VERSION) {
456 xml.addTag(settingTags[i], VERSIONSTRING);
457 xml.addChildAttrib(type, curType);
458 } else if(isSet[i]) {
459 xml.addTag(settingTags[i], get(StrSetting(i), false));
460 xml.addChildAttrib(type, curType);
461 }
462 }
463
464 curType = "int";
465 for(i=INT_FIRST; i<INT_LAST; i++)
466 {
467 if(isSet[i]) {
468 xml.addTag(settingTags[i], get(IntSetting(i), false));
469 xml.addChildAttrib(type, curType);
470 }
471 }
472 for(i=FLOAT_FIRST; i<FLOAT_LAST; i++)
473 {
474 if(isSet[i]) {
475 xml.addTag(settingTags[i], static_cast<int>(get(FloatSetting(i), false) * 1000.));
476 xml.addChildAttrib(type, curType);
477 }
478 }
479 curType = "int64";
480 for(i=INT64_FIRST; i<INT64_LAST; i++)
481 {
482 if(isSet[i])
483 {
484 xml.addTag(settingTags[i], get(Int64Setting(i), false));
485 xml.addChildAttrib(type, curType);
486 }
487 }
488 xml.stepOut();
489
490 xml.addTag("SearchTypes");
491 xml.stepIn();
492 for(SearchTypesIterC i = searchTypes.begin(); i != searchTypes.end(); ++i) {
493 xml.addTag("SearchType", Util::toString(";", i->second));
494 xml.addChildAttrib("Id", i->first);
495 }
496 xml.stepOut();
497
498 fire(SettingsManagerListener::Save(), xml);
499
500 try {
501 File out(aFileName + ".tmp", File::WRITE, File::CREATE | File::TRUNCATE);
502 BufferedOutputStream<false> f(&out);
503 f.write(SimpleXML::utf8Header);
504 xml.toXML(&f);
505 f.flush();
506 out.close();
507 File::deleteFile(aFileName);
508 File::renameFile(aFileName + ".tmp", aFileName);
509 } catch(const FileException&) {
510 // ...
511 }
512 }
513
validateSearchTypeName(const string & name) const514 void SettingsManager::validateSearchTypeName(const string& name) const {
515 if(name.empty() || (name.size() == 1 && name[0] >= '1' && name[0] <= '6')) {
516 throw SearchTypeException(_("Invalid search type name"));
517 }
518 for(int type = SearchManager::TYPE_ANY; type != SearchManager::TYPE_LAST; ++type) {
519 if(SearchManager::getTypeStr(type) == name) {
520 throw SearchTypeException(_("This search type already exists"));
521 }
522 }
523 }
524
setSearchTypeDefaults()525 void SettingsManager::setSearchTypeDefaults() {
526 searchTypes.clear();
527
528 // for conveniency, the default search exts will be the same as the ones defined by SEGA.
529 const vector<StringList>& searchExts = AdcHub::getSearchExts();
530 for(size_t i = 0, n = searchExts.size(); i < n; ++i)
531 searchTypes[string(1, '1' + i)] = searchExts[i];
532
533 fire(SettingsManagerListener::SearchTypesChanged());
534 }
535
addSearchType(const string & name,const StringList & extensions,bool validated)536 void SettingsManager::addSearchType(const string& name, const StringList& extensions, bool validated) {
537 if(!validated) {
538 validateSearchTypeName(name);
539 }
540
541 if(searchTypes.find(name) != searchTypes.end()) {
542 throw SearchTypeException(_("This search type already exists"));
543 }
544
545 searchTypes[name] = extensions;
546 fire(SettingsManagerListener::SearchTypesChanged());
547 }
548
delSearchType(const string & name)549 void SettingsManager::delSearchType(const string& name) {
550 validateSearchTypeName(name);
551 searchTypes.erase(name);
552 fire(SettingsManagerListener::SearchTypesChanged());
553 }
554
renameSearchType(const string & oldName,const string & newName)555 void SettingsManager::renameSearchType(const string& oldName, const string& newName) {
556 validateSearchTypeName(newName);
557 StringList exts = getSearchType(oldName)->second;
558 addSearchType(newName, exts, true);
559 searchTypes.erase(oldName);
560 }
561
modSearchType(const string & name,const StringList & extensions)562 void SettingsManager::modSearchType(const string& name, const StringList& extensions) {
563 getSearchType(name)->second = extensions;
564 fire(SettingsManagerListener::SearchTypesChanged());
565 }
566
getExtensions(const string & name)567 const StringList& SettingsManager::getExtensions(const string& name) {
568 return getSearchType(name)->second;
569 }
570
getSearchType(const string & name)571 SettingsManager::SearchTypesIter SettingsManager::getSearchType(const string& name) {
572 SearchTypesIter ret = searchTypes.find(name);
573 if(ret == searchTypes.end()) {
574 throw SearchTypeException(_("No such search type"));
575 }
576 return ret;
577 }
578
getType(const char * name,int & n,int & type) const579 bool SettingsManager::getType(const char* name, int& n, int& type) const {
580 for(n = 0; n < INT64_LAST; n++) {
581 if (strcmp(settingTags[n].c_str(), name) == 0) {
582 if (n < STR_LAST) {
583 type = TYPE_STRING;
584 return true;
585 } else if (n < INT_LAST) {
586 type= TYPE_INT;
587 return true;
588 } else {
589 type = TYPE_INT64;
590 return true;
591 }
592 }
593 }
594 return false;
595 }
596
parseCoreCmd(const std::string & cmd)597 const std::string SettingsManager::parseCoreCmd(const std::string& cmd) {
598 StringTokenizer<string> sl(cmd, ' ');
599 if (sl.getTokens().size() == 1) {
600 string ret;
601 bool b = parseCoreCmd(ret, sl.getTokens().at(0), Util::emptyString);
602 return (!b ? _("Error: setting not found!") : _("Core setting ") + sl.getTokens().at(0) + ": " + ret);
603 } else if (sl.getTokens().size() >= 2) {
604 string tmp = cmd.substr(sl.getTokens().at(0).size()+1);
605 string ret;
606 bool b = parseCoreCmd(ret, sl.getTokens().at(0), tmp);
607 return (!b ? _("Error: setting not found!") : _("Change core setting ") + sl.getTokens().at(0) + _(" to ") + tmp);
608 }
609 return Util::emptyString;
610 }
611
parseCoreCmd(string & ret,const std::string & key,const string & value)612 bool SettingsManager::parseCoreCmd(string& ret, const std::string& key, const string& value) {
613 if (key.empty()) {
614 return false;
615 }
616
617 int n,type;
618 getType(key.c_str(),n,type);
619 if (type == SettingsManager::TYPE_INT) {
620 if (!value.empty()) {
621 int i = atoi(value.c_str());
622 set((SettingsManager::IntSetting)n,i);
623 } else if (value.empty())
624 ret = Util::toString(get((SettingsManager::IntSetting)n,false));
625 }
626 else if (type == SettingsManager::TYPE_STRING) {
627 if (!value.empty())
628 set((SettingsManager::StrSetting)n, value);
629 else if (value.empty())
630 ret = get((SettingsManager::StrSetting)n,false);
631 } else
632 return false;
633 return true;
634 }
635
636 } // namespace dcpp
637