1 /*
2  * PROJECT:     ReactOS Applications Manager
3  * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4  * PURPOSE:     Functions to load / save settings from reg.
5  * COPYRIGHT:   Copyright 2020 He Yang           (1160386205@qq.com)
6  */
7 
8 #include "rapps.h"
9 #include "settings.h"
10 
11 
12 class SettingsField
13 {
14 public:
15     virtual ~SettingsField() { ; }
16     virtual BOOL Save(CRegKey &key) = 0;
17     virtual BOOL Load(CRegKey &key) = 0;
18 };
19 
20 class SettingsFieldBool : public SettingsField
21 {
22 public:
23     SettingsFieldBool(BOOL *pValue, LPCWSTR szRegName)
24         : m_pValueStore(pValue), m_RegName(szRegName)
25     {
26     }
27 
28     virtual BOOL Save(CRegKey &key) override
29     {
30         return key.SetDWORDValue(m_RegName, (DWORD)(*m_pValueStore)) == ERROR_SUCCESS;
31     }
32     virtual BOOL Load(CRegKey &key) override
33     {
34         DWORD dwField;
35         LONG lResult = key.QueryDWORDValue(m_RegName, dwField);
36         if (lResult != ERROR_SUCCESS)
37         {
38             return FALSE;
39         }
40         *m_pValueStore = (BOOL)dwField;
41         return TRUE;
42     }
43 
44 private:
45     BOOL *m_pValueStore;     // where to read/store the value
46     LPCWSTR m_RegName;       // key name in registery
47 };
48 
49 class SettingsFieldInt : public SettingsField
50 {
51 public:
52     SettingsFieldInt(INT *pValue, LPCWSTR szRegName)
53         : m_pValueStore(pValue), m_RegName(szRegName)
54     {
55     }
56 
57     virtual BOOL Save(CRegKey &key) override
58     {
59         return key.SetDWORDValue(m_RegName, (DWORD)(*m_pValueStore)) == ERROR_SUCCESS;
60     }
61     virtual BOOL Load(CRegKey &key) override
62     {
63         DWORD dwField;
64         LONG lResult = key.QueryDWORDValue(m_RegName, dwField);
65         if (lResult != ERROR_SUCCESS)
66         {
67             return FALSE;
68         }
69         *m_pValueStore = (INT)dwField;
70         return TRUE;
71     }
72 
73 private:
74     INT *m_pValueStore;      // where to read/store the value
75     LPCWSTR m_RegName;       // key name in registery
76 };
77 
78 class SettingsFieldString : public SettingsField
79 {
80 public:
81     SettingsFieldString(WCHAR *pString, ULONG cchLen, LPCWSTR szRegName)
82         : m_pStringStore(pString), m_StringLen(cchLen), m_RegName(szRegName)
83     {
84     }
85 
86     virtual BOOL Save(CRegKey &key) override
87     {
88         return key.SetStringValue(m_RegName, m_pStringStore) == ERROR_SUCCESS;
89     }
90     virtual BOOL Load(CRegKey &key) override
91     {
92         ULONG nChar = m_StringLen - 1; // make sure the terminating L'\0'
93         LONG lResult = key.QueryStringValue(m_RegName, m_pStringStore, &nChar);
94         return lResult == ERROR_SUCCESS;
95     }
96 
97 private:
98     WCHAR *m_pStringStore;        // where to read/store the value
99     ULONG m_StringLen;            // string length, in chars
100     LPCWSTR m_RegName;            // key name in registery
101 };
102 
103 
104 void AddInfoFields(ATL::CAtlList<SettingsField *> &infoFields, SETTINGS_INFO &settings)
105 {
106     infoFields.AddTail(new SettingsFieldBool(&(settings.bSaveWndPos), L"bSaveWndPos"));
107     infoFields.AddTail(new SettingsFieldBool(&(settings.bUpdateAtStart), L"bUpdateAtStart"));
108     infoFields.AddTail(new SettingsFieldBool(&(settings.bLogEnabled), L"bLogEnabled"));
109     infoFields.AddTail(new SettingsFieldString(settings.szDownloadDir, MAX_PATH, L"szDownloadDir"));
110     infoFields.AddTail(new SettingsFieldBool(&(settings.bDelInstaller), L"bDelInstaller"));
111     infoFields.AddTail(new SettingsFieldBool(&(settings.Maximized), L"WindowPosMaximized"));
112     infoFields.AddTail(new SettingsFieldInt(&(settings.Left), L"WindowPosLeft"));
113     infoFields.AddTail(new SettingsFieldInt(&(settings.Top), L"WindowPosTop"));
114     infoFields.AddTail(new SettingsFieldInt(&(settings.Width), L"WindowPosWidth"));
115     infoFields.AddTail(new SettingsFieldInt(&(settings.Height), L"WindowPosHeight"));
116     infoFields.AddTail(new SettingsFieldInt(&(settings.Proxy), L"ProxyMode"));
117     infoFields.AddTail(new SettingsFieldString((settings.szProxyServer), MAX_PATH, L"ProxyServer"));
118     infoFields.AddTail(new SettingsFieldString((settings.szNoProxyFor), MAX_PATH, L"NoProxyFor"));
119     infoFields.AddTail(new SettingsFieldBool(&(settings.bUseSource), L"bUseSource"));
120     infoFields.AddTail(new SettingsFieldString((settings.szSourceURL), INTERNET_MAX_URL_LENGTH, L"SourceURL"));
121 
122     return;
123 }
124 
125 BOOL SaveAllSettings(CRegKey &key, SETTINGS_INFO &settings)
126 {
127     BOOL bAllSuccess = TRUE;
128     ATL::CAtlList<SettingsField *> infoFields;
129 
130     AddInfoFields(infoFields, settings);
131 
132     POSITION InfoListPosition = infoFields.GetHeadPosition();
133     while (InfoListPosition)
134     {
135         SettingsField *Info = infoFields.GetNext(InfoListPosition);
136         if (!Info->Save(key))
137         {
138             bAllSuccess = FALSE;
139             // TODO: error log
140         }
141         delete Info;
142     }
143     return bAllSuccess;
144 }
145 
146 BOOL LoadAllSettings(CRegKey &key, SETTINGS_INFO &settings)
147 {
148     BOOL bAllSuccess = TRUE;
149     ATL::CAtlList<SettingsField *> infoFields;
150 
151     AddInfoFields(infoFields, settings);
152 
153     POSITION InfoListPosition = infoFields.GetHeadPosition();
154     while (InfoListPosition)
155     {
156         SettingsField *Info = infoFields.GetNext(InfoListPosition);
157         if (!Info->Load(key))
158         {
159             bAllSuccess = FALSE;
160             // TODO: error log
161         }
162         delete Info;
163     }
164     return bAllSuccess;
165 }
166 
167 VOID FillDefaultSettings(PSETTINGS_INFO pSettingsInfo)
168 {
169     ATL::CStringW szDownloadDir;
170     ZeroMemory(pSettingsInfo, sizeof(SETTINGS_INFO));
171 
172     pSettingsInfo->bSaveWndPos = TRUE;
173     pSettingsInfo->bUpdateAtStart = FALSE;
174     pSettingsInfo->bLogEnabled = TRUE;
175     pSettingsInfo->bUseSource = FALSE;
176 
177     if (FAILED(SHGetFolderPathW(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, szDownloadDir.GetBuffer(MAX_PATH))))
178     {
179         szDownloadDir.ReleaseBuffer();
180         if (!szDownloadDir.GetEnvironmentVariableW(L"SystemDrive"))
181         {
182             szDownloadDir = L"C:";
183         }
184     }
185     else
186     {
187         szDownloadDir.ReleaseBuffer();
188     }
189 
190     PathAppendW(szDownloadDir.GetBuffer(MAX_PATH), L"\\RAPPS Downloads");
191     szDownloadDir.ReleaseBuffer();
192 
193     ATL::CStringW::CopyChars(pSettingsInfo->szDownloadDir,
194         _countof(pSettingsInfo->szDownloadDir),
195         szDownloadDir.GetString(),
196         szDownloadDir.GetLength() + 1);
197 
198     pSettingsInfo->bDelInstaller = FALSE;
199     pSettingsInfo->Maximized = FALSE;
200     pSettingsInfo->Left = CW_USEDEFAULT;
201     pSettingsInfo->Top = CW_USEDEFAULT;
202     pSettingsInfo->Width = 680;
203     pSettingsInfo->Height = 450;
204 }
205 
206 BOOL LoadSettings(PSETTINGS_INFO pSettingsInfo)
207 {
208     ATL::CRegKey RegKey;
209     if (RegKey.Open(HKEY_CURRENT_USER, L"Software\\ReactOS\\rapps", KEY_READ) != ERROR_SUCCESS)
210     {
211         return FALSE;
212     }
213 
214     return LoadAllSettings(RegKey, *pSettingsInfo);
215 }
216 
217 BOOL SaveSettings(HWND hwnd, PSETTINGS_INFO pSettingsInfo)
218 {
219     WINDOWPLACEMENT wp;
220     ATL::CRegKey RegKey;
221 
222     if (pSettingsInfo->bSaveWndPos)
223     {
224         wp.length = sizeof(wp);
225         GetWindowPlacement(hwnd, &wp);
226 
227         pSettingsInfo->Left = wp.rcNormalPosition.left;
228         pSettingsInfo->Top = wp.rcNormalPosition.top;
229         pSettingsInfo->Width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
230         pSettingsInfo->Height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
231         pSettingsInfo->Maximized = (wp.showCmd == SW_MAXIMIZE
232             || (wp.showCmd == SW_SHOWMINIMIZED
233                 && (wp.flags & WPF_RESTORETOMAXIMIZED)));
234     }
235 
236     if (RegKey.Create(HKEY_CURRENT_USER, L"Software\\ReactOS\\rapps", NULL,
237         REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, NULL) != ERROR_SUCCESS)
238     {
239         return FALSE;
240     }
241 
242     return SaveAllSettings(RegKey, *pSettingsInfo);
243 }
244