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