/*- * Copyright (c) 2017-2021 Carsten Sonne Larsen * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include "setting.h" #include "global.h" #include "conv.h" #include "text.h" #include "mem.h" #include "logmod.h" #define MODULENAME "Settings" struct AppSettings *Settings; struct AppSettingKeys *SettingKeys; static const struct AppSettingKeys SettingKeyStruct = { .DestinationAddress = KEYWORD_SERVER, .DestinationPort = KEYWORD_PORT, .Threshold = KEYWORD_THRESHOLD, .Interval = KEYWORD_INTERVAL, .Priority = KEYWORD_PRIORITY, .PopKey = KEYWORD_POPKEY, .Popup = KEYWORD_POPUP, .Readonly = KEYWORD_READONLY, .Expert = KEYWORD_EXPERT, .Timeout = KEYWORD_TIMEOUT, .Active = KEYWORD_ACTIVE, .NoLog = KEYWORD_NOLOG, .TZ = KEYWORD_TZ, .TimeZoneDisplay = KEYWORD_TZD, .TimeZoneName = KEYWORD_TZNAME, .TimeZoneValue = KEYWORD_TZVALUE, .TimeZoneDst = KEYWORD_TZDST, .PopupOnStart = KEYWORD_POPUP2}; const struct AppSettings DefaultSettings = { .Type = DefaultSettingType, .DestinationAddress = (char *)SERVER_DEF, .DestinationPort = (char *)PORT_DEF, .Timeout = TIMEOUT_DEF, .Interval = INTERVAL_DEF, .PopKey = POPKEY_DEF, .Popup = POPUP_DEF, .Readonly = READONLY_DEF, .Expert = EXPERT_DEF, .Priority = PRIORITY_DEF, .Threshold = THRESHOLD_DEF, .Active = ACTIVE_DEF, .NoLog = NOLOG_DEF, .TZ = TZ_DEF, .TimeZoneDisplay = TZD_DEF, .TimeZoneName = TZNAME_DEF, .TimeZoneValue = TZVALUE_DEF, .TimeZoneDst = TZDST_DEF, .Values = 0xFFFFF, .PopupOnStart = false}; static void SetPrioritySetting(struct AppSettings *, void *); static void SetIntervalSetting(struct AppSettings *, void *); static void SetTimeoutSetting(struct AppSettings *, void *); static void SetThresholdSetting(struct AppSettings *, void *); static void SetDestinationAddressSetting(struct AppSettings *, void *); static void SetDestinationPortSetting(struct AppSettings *, void *); static void SetReadOnlySetting(struct AppSettings *, void *); static void SetExpertSetting(struct AppSettings *, void *); static void SetPopupSetting(struct AppSettings *, void *); static void SetPopKeySetting(struct AppSettings *, void *); static void SetActiveSetting(struct AppSettings *, void *); static void SetNoLogSetting(struct AppSettings *, void *); static void SetTZSetting(struct AppSettings *, void *); static void SetTimeZoneDisplaySetting(struct AppSettings *, void *); static void SetTimeZoneNameSetting(struct AppSettings *, void *); static void SetTimeZoneValueSetting(struct AppSettings *, void *); static void SetTimeZoneDstSetting(struct AppSettings *, void *); static void ExecutePopupFunction(struct AppSettings *, void *); const struct SettingFunc settingFunctions[] = { {KEYWORD_READONLY, SetReadOnlySetting}, {KEYWORD_EXPERT, SetExpertSetting}, {KEYWORD_ACTIVE, SetActiveSetting}, {KEYWORD_NOLOG, SetNoLogSetting}, {KEYWORD_SERVER, SetDestinationAddressSetting}, {KEYWORD_PORT, SetDestinationPortSetting}, {KEYWORD_TIMEOUT, SetTimeoutSetting}, {KEYWORD_THRESHOLD, SetThresholdSetting}, {KEYWORD_INTERVAL, SetIntervalSetting}, {KEYWORD_PRIORITY, SetPrioritySetting}, {KEYWORD_POPKEY, SetPopKeySetting}, {KEYWORD_POPUP, SetPopupSetting}, {KEYWORD_TZ, SetTZSetting}, {KEYWORD_TZD, SetTimeZoneDisplaySetting}, {KEYWORD_TZNAME, SetTimeZoneNameSetting}, {KEYWORD_TZVALUE, SetTimeZoneValueSetting}, {KEYWORD_TZDST, SetTimeZoneDstSetting}, {KEYWORD_POPUP2, ExecutePopupFunction}}; #define MAXSETTINGLINELEN 256 static struct AppSettings *fileSettings; static struct AppSettings *cachedSettings; static char *BooleanAsText(bool value) { return (char *)(value ? yesValueString : noValueString); } void InitSettings(void) { Settings = CreateSettings(GlobalSettingType); SettingKeys = (struct AppSettingKeys *)&SettingKeyStruct; } void CleanupSettings(void) { FreeSettings(Settings); } void ShowAppSettings(struct AppSettings *settings) { char low[MAXLONGLONGCHARSIZE]; LongLongToStr(settings->Threshold, low); LogDebug(settingValueString, SettingKeys->Popup, BooleanAsText(settings->Popup)); LogDebug(settingValueString, SettingKeys->PopKey, settings->PopKey); LogDebug(settingValueLong, SettingKeys->Priority, settings->Priority); LogDebug(settingValueString, SettingKeys->Threshold, low); LogDebug(settingValueString, SettingKeys->DestinationAddress, settings->DestinationAddress); LogDebug(settingValueString, SettingKeys->DestinationPort, settings->DestinationPort); LogDebug(settingValueLong, SettingKeys->Timeout, settings->Timeout); LogDebug(settingValueLong, SettingKeys->Interval, settings->Interval); LogDebug(settingValueString, SettingKeys->Readonly, BooleanAsText(settings->Readonly)); LogDebug(settingValueString, SettingKeys->Expert, BooleanAsText(settings->Expert)); LogDebug(settingValueString, SettingKeys->Active, BooleanAsText(settings->Active)); LogDebug(settingValueString, SettingKeys->NoLog, BooleanAsText(settings->NoLog)); LogDebug(settingValueString, SettingKeys->TZ, settings->TZ); LogDebug(settingValueString, SettingKeys->TimeZoneName, settings->TimeZoneName); LogDebug(settingValueLong, SettingKeys->TimeZoneValue, settings->TimeZoneValue); LogDebug(settingValueLong, SettingKeys->TimeZoneDisplay, settings->TimeZoneDisplay); LogDebug(settingValueLong, SettingKeys->TimeZoneDst, settings->TimeZoneDst); } void ShowSettings(void) { LogDebug(effectiveSettings); ShowAppSettings(Settings); } void LogFoundSetting(long type, const char *name) { switch (type) { case PrefsSettingType: LogDebug(foundSetting, name); break; case CliSettingType: LogDebug(foundCliSetting, name); break; case WbSettingType: LogDebug(foundWbSetting, name); break; default: break; } } static void ParseLongSetting( struct AppSettings *settings, long flag, const char *keyword, long *valueField, void *value) { LogFoundSetting(settings->Type, keyword); if (settings->Type == CliSettingType) { *valueField = *(long *)value; settings->Values |= flag; return; } if (TryParseLong((char *)value, valueField)) { settings->Values |= flag; return; } LogWarn(integerError, value); } static void ParseBooleanSetting( struct AppSettings *settings, long flag, const char *keyword, long *valueField, void *value, bool switchOption) { LogFoundSetting(settings->Type, keyword); // CLI switch is always a long value if (settings->Type == CliSettingType && switchOption) { *valueField = (value != NULL ? true : false); settings->Values |= flag; return; } if (value == NULL || *((const char *)value) == '\0') { LogWarn(yesNoError, '\0'); return; } if (Stricmp((CONST_STRPTR)noValueString, (CONST_STRPTR)value) == 0 || Stricmp((CONST_STRPTR) "0", (CONST_STRPTR)value) == 0) { *valueField = false; settings->Values |= flag; return; } if (Stricmp((CONST_STRPTR)yesValueString, (CONST_STRPTR)value) == 0 || Stricmp((CONST_STRPTR) "1", (CONST_STRPTR)value) == 0) { *valueField = true; settings->Values |= flag; return; } LogWarn(yesNoError, value); } static void SetPrioritySetting(struct AppSettings *settings, void *value) { ParseLongSetting(settings, PrioritySet, SettingKeys->Priority, &settings->Priority, value); } static void SetIntervalSetting(struct AppSettings *settings, void *value) { ParseLongSetting(settings, IntervalSet, SettingKeys->Interval, &settings->Interval, value); } static void SetTimeoutSetting(struct AppSettings *settings, void *value) { ParseLongSetting(settings, TimeoutSet, SettingKeys->Timeout, &settings->Timeout, value); } static void SetThresholdSetting(struct AppSettings *settings, void *value) { LogFoundSetting(settings->Type, SettingKeys->Threshold); if (TryParseLongLong((char *)value, &settings->Threshold)) { settings->Values |= ThresholdSet; return; } LogWarn(integerError, value); } static void SetDestinationAddressSetting(struct AppSettings *settings, void *value) { LogFoundSetting(settings->Type, SettingKeys->DestinationAddress); settings->DestinationAddress = StrDupSafe((const char *)value); settings->Values |= DestinationAddressSet; } static void SetPopKeySetting(struct AppSettings *settings, void *value) { LogFoundSetting(settings->Type, SettingKeys->PopKey); settings->PopKey = StrDupSafe((const char *)value); settings->Values |= PopKeySet; } static void SetDestinationPortSetting(struct AppSettings *settings, void *value) { LogFoundSetting(settings->Type, SettingKeys->DestinationPort); settings->DestinationPort = StrDupSafe((const char *)value); settings->Values |= DestinationPortSet; } static void SetReadOnlySetting(struct AppSettings *settings, void *value) { ParseBooleanSetting(settings, ReadonlySet, SettingKeys->Readonly, &settings->Readonly, value, true); } static void SetExpertSetting(struct AppSettings *settings, void *value) { ParseBooleanSetting(settings, ExpertSet, SettingKeys->Expert, &settings->Expert, value, true); } static void SetActiveSetting(struct AppSettings *settings, void *value) { ParseBooleanSetting(settings, ActiveSet, SettingKeys->Active, &settings->Active, value, true); } static void SetNoLogSetting(struct AppSettings *settings, void *value) { ParseBooleanSetting(settings, NoLogSet, SettingKeys->NoLog, &settings->NoLog, value, true); } static void SetPopupSetting(struct AppSettings *settings, void *value) { ParseBooleanSetting(settings, PopUpSet, SettingKeys->Popup, &settings->Popup, value, false); } static void SetTZSetting(struct AppSettings *settings, void *value) { LogFoundSetting(settings->Type, SettingKeys->TZ); settings->TZ = StrDupSafe((const char *)value); settings->Values |= TzSet; } static void SetTimeZoneDisplaySetting(struct AppSettings *settings, void *value) { ParseLongSetting(settings, TimeZoneDisplaySet, SettingKeys->TimeZoneDisplay, &settings->TimeZoneDisplay, value); } static void SetTimeZoneNameSetting(struct AppSettings *settings, void *value) { LogFoundSetting(settings->Type, SettingKeys->TimeZoneName); settings->TimeZoneName = StrDupSafe((const char *)value); settings->Values |= TimeZoneNameSet; } static void SetTimeZoneValueSetting(struct AppSettings *settings, void *value) { ParseLongSetting(settings, TimeZoneValueSet, SettingKeys->TimeZoneValue, &settings->TimeZoneValue, value); } static void SetTimeZoneDstSetting(struct AppSettings *settings, void *value) { ParseLongSetting(settings, TimeZoneDstSet, SettingKeys->TimeZoneDst, &settings->TimeZoneDst, value); } static void ExecutePopupFunction(struct AppSettings *settings, void *value) { // Run-time switch. Show settings window when starting LogFoundSetting(settings->Type, SettingKeys->PopupOnStart); settings->PopupOnStart = true; } static void ParseSetting(struct AppSettings *settings, char *line) { char *value; char *end; int i; value = StrChr(line, '=', MAXSETTINGLINELEN); if (value == NULL) { LogWarn(unknownSetting, "No assignment"); return; } end = StrChr(value, '\n', MAXSETTINGLINELEN); if (end == NULL) { LogWarn(unknownSetting, "No end of line"); return; } *value++ = '\0'; *end = '\0'; for (i = 0; i < KEYWORD_COUNT; i++) { if (Stricmp((STRPTR)settingFunctions[i].Name, (STRPTR)line) == 0) { settingFunctions[i].Function(settings, (void *)value); return; } } LogWarn(unknownSetting, line); } void LoadSettings(void) { struct AppSettings *settings; const int maxLines = 25; char line[MAXSETTINGLINELEN]; char message[MAXDOSERRORLEN]; bool eof = false; int count = 0; long error; BPTR file; LogDebug(prefsFileSearch, prefsFile); file = Open((STRPTR)prefsFile, MODE_OLDFILE); if (!file) { error = IoErr(); if (error == ERROR_OBJECT_NOT_FOUND) { LogNotice(prefsFileNotFound); } else { Fault(error, (STRPTR)fileOpenError, (STRPTR)message, MAXDOSERRORLEN); LogWarn(message); } return; } LogInfo(prefsFileFound); settings = CreateSettings(PrefsSettingType); do { char *c = (char *)FGets(file, (STRPTR)line, MAXSETTINGLINELEN); eof = (c == NULL); if (!eof) { ParseSetting(settings, line); count++; } } while (!eof && count < maxLines); // If NULL is returned for an EOF, IoErr() will return 0. error = IoErr(); if (error != 0) { Fault(error, (STRPTR)fileReadError, (STRPTR)message, MAXDOSERRORLEN); LogError(message); } Close(file); fileSettings = settings; } static void WriteSetting(BPTR file, const char *format, ...) { long count; va_list args; va_start(args, format); count = VFPrintf(file, (void *)format, (void *)args); va_end(args); if (count <= 0) { long error = IoErr(); if (error != 0) { char message[MAXDOSERRORLEN]; Fault(error, (STRPTR)fileWriteError, (STRPTR)message, MAXDOSERRORLEN); LogError(message); } } } void SaveSettings(bool persist) { char low[MAXLONGLONGCHARSIZE]; const char *dirName = persist ? persistentPrefsDir : prefsDir; const char *fileName = persist ? persistentPrefsFile : prefsFile; BPTR lock = CreateDir((STRPTR)dirName); if (lock != NULL) UnLock(lock); BPTR file = Open((STRPTR)fileName, MODE_NEWFILE); if (!file) { char message[MAXDOSERRORLEN]; long error = IoErr(); Fault(error, (STRPTR)fileSaveError, (STRPTR)message, MAXDOSERRORLEN); LogWarn(message); return; } LogInfo(prefsFileSave, fileName); LongLongToStr(Settings->Threshold, low); WriteSetting(file, saveValueString, SettingKeys->Popup, BooleanAsText(Settings->Popup)); WriteSetting(file, saveValueString, SettingKeys->PopKey, Settings->PopKey); WriteSetting(file, saveValueLong, SettingKeys->Priority, Settings->Priority); WriteSetting(file, saveValueString, SettingKeys->Threshold, low); WriteSetting(file, saveValueString, SettingKeys->DestinationAddress, Settings->DestinationAddress); WriteSetting(file, saveValueString, SettingKeys->DestinationPort, Settings->DestinationPort); WriteSetting(file, saveValueLong, SettingKeys->Timeout, Settings->Timeout); WriteSetting(file, saveValueLong, SettingKeys->Interval, Settings->Interval); WriteSetting(file, saveValueString, SettingKeys->Readonly, BooleanAsText(Settings->Readonly)); WriteSetting(file, saveValueString, SettingKeys->Expert, BooleanAsText(Settings->Expert)); WriteSetting(file, saveValueString, SettingKeys->Active, BooleanAsText(Settings->Active)); WriteSetting(file, saveValueString, SettingKeys->NoLog, BooleanAsText(Settings->NoLog)); WriteSetting(file, saveValueLong, SettingKeys->TimeZoneDisplay, Settings->TimeZoneDisplay); if (Settings->TZ != NULL && *Settings->TZ != '\0') WriteSetting(file, saveValueString, SettingKeys->TZ, Settings->TZ); if (Settings->TimeZoneName != NULL && *Settings->TimeZoneName != '\0') WriteSetting(file, saveValueString, SettingKeys->TimeZoneName, Settings->TimeZoneName); if (Settings->TimeZoneValue != TZVALUE_DEF) WriteSetting(file, saveValueLong, SettingKeys->TimeZoneValue, Settings->TimeZoneValue); if (Settings->TimeZoneDst != TZDST_DEF) WriteSetting(file, saveValueLong, SettingKeys->TimeZoneDst, Settings->TimeZoneDst); Close(file); } struct AppSettings *CreateSettings(long type) { struct AppSettings *settings; settings = AllocStructSafe(struct AppSettings); settings->Type = type; return settings; } struct AppSettings *CopySettings(const struct AppSettings *settings) { struct AppSettings *s = CreateSettings(settings->Type); CopyMem((void *)settings, s, sizeof(struct AppSettings)); s->DestinationAddress = StrDupSafe(settings->DestinationAddress); s->DestinationPort = StrDupSafe(settings->DestinationPort); s->PopKey = StrDupSafe(settings->PopKey); s->TZ = StrDupSafe(settings->TZ); s->TimeZoneName = StrDupSafe(settings->TimeZoneName); s->Values = 0xFFFFF; return s; } void FreeSettings(struct AppSettings *settings) { if (settings->DestinationAddress != NULL) FreeMemSafe(settings->DestinationAddress); if (settings->DestinationPort != NULL) FreeMemSafe(settings->DestinationPort); if (settings->PopKey != NULL) FreeMemSafe(settings->PopKey); if (settings->TZ != NULL) FreeMemSafe(settings->TZ); if (settings->TimeZoneName != NULL) FreeMemSafe(settings->TimeZoneName); FreeMemSafe(settings); } static void ApplyLongSetting( struct AppSettings *settings, long flag, const char *keyword, long *curValue, long *newValue, bool quiet) { if ((settings->Values & flag) == flag) { if (settings->Type == DefaultSettingType) { LogDebug(settingValueLong, keyword, *newValue); } else if (*curValue != *newValue) { LogInfo(settingChangedLong, keyword, *curValue, *newValue); } else if (!quiet) { LogDebug(settingSetLong, keyword, *newValue); } *curValue = *newValue; } } static void ApplyBooleanSetting( struct AppSettings *settings, long flag, const char *keyword, long *curValue, long *newValue, bool quiet) { if ((settings->Values & flag) == flag) { if (settings->Type == DefaultSettingType) { LogDebug(settingValueString, keyword, BooleanAsText(*newValue)); } else if (*curValue != *newValue) { LogInfo(settingChangedString, keyword, BooleanAsText(*curValue), BooleanAsText(*newValue)); } else if (!quiet) { LogDebug(settingSetString, keyword, BooleanAsText(*newValue)); } *curValue = *newValue; } } static void ApplyStringSetting( struct AppSettings *settings, long flag, const char *keyword, char **curValue, char *newValue, bool quiet) { if ((settings->Values & flag) == flag) { if (settings->Type == DefaultSettingType) { LogDebug(settingValueString, keyword, newValue); } else if (Stricmp((STRPTR)*curValue, (STRPTR)newValue) != 0) { LogInfo(settingChangedString, keyword, *curValue, newValue); } else if (!quiet) { LogDebug(settingSetString, keyword, newValue); } if (*curValue != NULL) { FreeMemSafe(*curValue); } *curValue = StrDupSafe(newValue); } } void ApplyAppSettings(struct AppSettings *settings, bool quiet) { switch (settings->Type) { case DefaultSettingType: LogInfo(applyDefaultSettings); break; case PrefsSettingType: LogInfo(applyFileSettings); break; case CliSettingType: LogInfo(applyCliSettings); break; case WbSettingType: LogInfo(applyWbSettings); break; default: break; } if (settings->Type == CliSettingType || settings->Type == WbSettingType) Settings->PopupOnStart = settings->PopupOnStart; ApplyStringSetting(settings, TzSet, SettingKeys->TZ, &Settings->TZ, settings->TZ, quiet); ApplyLongSetting(settings, TimeZoneDisplaySet, SettingKeys->TimeZoneDisplay, &Settings->TimeZoneDisplay, &settings->TimeZoneDisplay, quiet); ApplyStringSetting(settings, TimeZoneNameSet, SettingKeys->TimeZoneName, &Settings->TimeZoneName, settings->TimeZoneName, quiet); ApplyLongSetting(settings, TimeZoneValueSet, SettingKeys->TimeZoneValue, &Settings->TimeZoneValue, &settings->TimeZoneValue, quiet); ApplyBooleanSetting(settings, PopUpSet, SettingKeys->Popup, &Settings->Popup, &settings->Popup, quiet); ApplyStringSetting(settings, PopKeySet, SettingKeys->PopKey, &Settings->PopKey, settings->PopKey, quiet); ApplyLongSetting(settings, PrioritySet, SettingKeys->Priority, &Settings->Priority, &settings->Priority, quiet); ApplyLongSetting(settings, TimeoutSet, SettingKeys->Timeout, &Settings->Timeout, &settings->Timeout, quiet); ApplyLongSetting(settings, IntervalSet, SettingKeys->Interval, &Settings->Interval, &settings->Interval, quiet); ApplyLongSetting(settings, TimeZoneDstSet, SettingKeys->TimeZoneDst, &Settings->TimeZoneDst, &settings->TimeZoneDst, quiet); ApplyBooleanSetting(settings, ReadonlySet, SettingKeys->Readonly, &Settings->Readonly, &settings->Readonly, quiet); ApplyBooleanSetting(settings, ExpertSet, SettingKeys->Expert, &Settings->Expert, &settings->Expert, quiet); ApplyBooleanSetting(settings, ActiveSet, SettingKeys->Active, &Settings->Active, &settings->Active, quiet); ApplyBooleanSetting(settings, NoLogSet, SettingKeys->NoLog, &Settings->NoLog, &settings->NoLog, quiet); ApplyStringSetting(settings, DestinationAddressSet, SettingKeys->DestinationAddress, &Settings->DestinationAddress, settings->DestinationAddress, quiet); ApplyStringSetting(settings, DestinationPortSet, SettingKeys->DestinationPort, &Settings->DestinationPort, settings->DestinationPort, quiet); if ((settings->Values & ThresholdSet) == ThresholdSet) { char before[MAXLONGLONGCHARSIZE]; char after[MAXLONGLONGCHARSIZE]; if (settings->Type == DefaultSettingType) { LongLongToStr(settings->Threshold, after); LogDebug(settingValueString, SettingKeys->Threshold, after); } else if (Settings->Threshold != settings->Threshold) { LongLongToStr(Settings->Threshold, before); LongLongToStr(settings->Threshold, after); LogInfo(settingChangedString, SettingKeys->Threshold, before, after); } else if (!quiet) { LongLongToStr(Settings->Threshold, before); LogDebug(settingSetString, SettingKeys->Threshold, before); } Settings->Threshold = settings->Threshold; } } void CacheSettings(struct AppSettings *settings) { if (cachedSettings != NULL) { FreeSettings(cachedSettings); } cachedSettings = settings; } void ApplySettings() { ApplyAppSettings((struct AppSettings *)&DefaultSettings, false); if (fileSettings != NULL) { ApplyAppSettings(fileSettings, false); FreeSettings(fileSettings); } if (cachedSettings != NULL) { ApplyAppSettings(cachedSettings, false); FreeSettings(cachedSettings); } }