[RAPPS] Refactoring & bugfixes
[reactos.git] / reactos / base / applications / rapps / available.cpp
1 /*
2 * PROJECT: ReactOS Applications Manager
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: base/applications/rapps/available.cpp
5 * PURPOSE: Classes for working with available applications
6 * PROGRAMMERS: Dmitry Chapyshev (dmitry@reactos.org)
7 * Ismael Ferreras Morezuelas (swyterzone+ros@gmail.com)
8 * Alexander Shaposhnikov (chaez.san@gmail.com)
9 */
10
11 #include "rapps.h"
12
13 // CAvailableApplicationInfo
14
15 CAvailableApplicationInfo::CAvailableApplicationInfo(const ATL::CStringW& sFileNameParam)
16 {
17 LicenseType = LICENSE_TYPE::None;
18 sFileName = sFileNameParam;
19 RetrieveCategory();
20 }
21
22 VOID CAvailableApplicationInfo::RefreshAppInfo()
23 {
24 if (RetrieveGeneralInfo())
25 {
26 RetrieveLicenseType();
27 RetrieveLanguages();
28 RetrieveInstalledStatus();
29 if (m_IsInstalled)
30 {
31 RetrieveInstalledVersion();
32 }
33 }
34 }
35
36 BOOL CAvailableApplicationInfo::RetrieveGeneralInfo()
37 {
38 if (szUrlDownload.IsEmpty())
39 {
40 if (!GetString(L"Name", szName)
41 || !GetString(L"URLDownload", szUrlDownload))
42 {
43 return FALSE;
44 }
45
46 GetString(L"RegName", szRegName);
47 GetString(L"Version", szVersion);
48 GetString(L"License", szLicense);
49 GetString(L"Description", szDesc);
50 GetString(L"Size", szSize);
51 GetString(L"URLSite", szUrlSite);
52 GetString(L"CDPath", szCDPath);
53 GetString(L"Language", szRegName);
54 GetString(L"SHA1", szSHA1);
55 return TRUE;
56 }
57 return FALSE;
58 }
59
60 VOID CAvailableApplicationInfo::RetrieveInstalledStatus()
61 {
62 m_IsInstalled = ::GetInstalledVersion(NULL, szRegName)
63 || ::GetInstalledVersion(NULL, szName);
64 }
65
66 VOID CAvailableApplicationInfo::RetrieveInstalledVersion()
67 {
68 m_HasInstalledVersion = ::GetInstalledVersion(&szInstalledVersion, szRegName)
69 || ::GetInstalledVersion(&szInstalledVersion, szName);
70 }
71
72 BOOL CAvailableApplicationInfo::RetrieveLanguages()
73 {
74 const WCHAR cDelimiter = L'|';
75 ATL::CStringW szBuffer;
76
77 // TODO: Get multiline parameter
78 if (!ParserGetString(L"Languages", sFileName, szBuffer))
79 return FALSE;
80
81 // Parse parameter string
82 ATL::CStringW szLocale;
83 for (INT i = 0; szBuffer[i] != UNICODE_NULL; ++i)
84 {
85 if (szBuffer[i] != cDelimiter)
86 {
87 szLocale += szBuffer[i];
88 }
89 else
90 {
91 Languages.Add(szLocale);
92 szLocale.Empty();
93 }
94 }
95
96 // For the text after delimiter
97 if (!szLocale.IsEmpty())
98 {
99 Languages.Add(szLocale);
100 }
101
102 return TRUE;
103 }
104
105 VOID CAvailableApplicationInfo::RetrieveLicenseType()
106 {
107 INT IntBuffer = ParserGetInt(L"LicenseType", sFileName);
108
109 if (IntBuffer < 0 || IntBuffer > LICENSE_TYPE::Max)
110 {
111 LicenseType = LICENSE_TYPE::None;
112 }
113 else
114 {
115 LicenseType = (LICENSE_TYPE) IntBuffer;
116 }
117 }
118
119 VOID CAvailableApplicationInfo::RetrieveCategory()
120 {
121 Category = ParserGetInt(L"Category", sFileName);
122 }
123
124 BOOL CAvailableApplicationInfo::HasLanguageInfo() const
125 {
126 return m_HasLanguageInfo;
127 }
128
129 BOOL CAvailableApplicationInfo::HasNativeLanguage() const
130 {
131 if (!m_HasLanguageInfo)
132 {
133 return FALSE;
134 }
135
136 //TODO: make the actual check
137 return TRUE;
138 }
139
140 BOOL CAvailableApplicationInfo::HasEnglishLanguage() const
141 {
142 if (!m_HasLanguageInfo)
143 {
144 return FALSE;
145 }
146
147 //TODO: make the actual check
148 return TRUE;
149 }
150
151 BOOL CAvailableApplicationInfo::IsInstalled() const
152 {
153 return m_IsInstalled;
154 }
155
156 BOOL CAvailableApplicationInfo::HasInstalledVersion() const
157 {
158 return m_HasInstalledVersion;
159 }
160
161 BOOL CAvailableApplicationInfo::HasUpdate() const
162 {
163 return (szInstalledVersion.Compare(szVersion) < 0) ? TRUE : FALSE;
164 }
165
166 VOID CAvailableApplicationInfo::SetLastWriteTime(FILETIME* ftTime)
167 {
168 RtlCopyMemory(&ftCacheStamp, ftTime, sizeof(FILETIME));
169 }
170
171 inline BOOL CAvailableApplicationInfo::GetString(LPCWSTR lpKeyName, ATL::CStringW& ReturnedString)
172 {
173 if (!ParserGetString(lpKeyName, sFileName, ReturnedString))
174 {
175 ReturnedString.Empty();
176 return FALSE;
177 }
178 return TRUE;
179 }
180
181 // CAvailableApps
182 CAvailableApps::CAvailableApps()
183 {
184 //set all paths
185 if (GetStorageDirectory(m_szPath))
186 {
187 m_szAppsPath = m_szPath + L"\\rapps\\";
188 m_szCabPath = m_szPath + L"\\rappmgr.cab";
189 m_szSearchPath = m_szAppsPath + L"*.txt";
190 }
191 }
192
193 VOID CAvailableApps::FreeCachedEntries()
194 {
195 POSITION InfoListPosition = m_InfoList.GetHeadPosition();
196
197 /* loop and deallocate all the cached app infos in the list */
198 while (InfoListPosition)
199 {
200 CAvailableApplicationInfo* Info = m_InfoList.GetAt(InfoListPosition);
201 m_InfoList.RemoveHead();
202 delete Info;
203
204 InfoListPosition = m_InfoList.GetHeadPosition();
205 }
206 }
207
208 BOOL CAvailableApps::DeleteCurrentAppsDB()
209 {
210 HANDLE hFind = INVALID_HANDLE_VALUE;
211 WIN32_FIND_DATAW FindFileData;
212 BOOL result = TRUE;
213
214 if (m_szPath.IsEmpty())
215 return FALSE;
216
217 result = result && DeleteFileW(m_szCabPath.GetString());
218 hFind = FindFirstFileW(m_szSearchPath.GetString(), &FindFileData);
219
220 if (hFind == INVALID_HANDLE_VALUE)
221 return result;
222
223 ATL::CStringW szTmp;
224 do
225 {
226 szTmp = m_szPath + FindFileData.cFileName;
227 result = result && DeleteFileW(szTmp.GetString());
228 } while (FindNextFileW(hFind, &FindFileData) != 0);
229
230 FindClose(hFind);
231
232 return result;
233 }
234
235 BOOL CAvailableApps::UpdateAppsDB()
236 {
237 if (!DeleteCurrentAppsDB())
238 return FALSE;
239
240 DownloadApplicationsDB(APPLICATION_DATABASE_URL);
241
242 if (m_szPath.IsEmpty())
243 return FALSE;
244
245 if (!ExtractFilesFromCab(m_szCabPath, m_szAppsPath))
246 {
247 return FALSE;
248 }
249
250 return TRUE;
251 }
252
253 BOOL CAvailableApps::EnumAvailableApplications(INT EnumType, AVAILENUMPROC lpEnumProc)
254 {
255 HANDLE hFind = INVALID_HANDLE_VALUE;
256 WIN32_FIND_DATAW FindFileData;
257
258 if (!CreateDirectoryW(m_szPath.GetString(), NULL) &&
259 GetLastError() != ERROR_ALREADY_EXISTS)
260 {
261 return FALSE;
262 }
263
264 hFind = FindFirstFileW(m_szSearchPath.GetString(), &FindFileData);
265
266 if (hFind == INVALID_HANDLE_VALUE)
267 {
268 if (GetFileAttributesW(m_szCabPath) == INVALID_FILE_ATTRIBUTES)
269 DownloadApplicationsDB(APPLICATION_DATABASE_URL);
270
271 ExtractFilesFromCab(m_szCabPath, m_szAppsPath);
272 hFind = FindFirstFileW(m_szSearchPath.GetString(), &FindFileData);
273
274 if (hFind == INVALID_HANDLE_VALUE)
275 return FALSE;
276 }
277
278 do
279 {
280 /* loop for all the cached entries */
281 POSITION CurrentListPosition = m_InfoList.GetHeadPosition();
282 CAvailableApplicationInfo* Info = NULL;
283
284 while (CurrentListPosition != NULL)
285 {
286 POSITION LastListPosition = CurrentListPosition;
287 Info = m_InfoList.GetNext(CurrentListPosition);
288
289 /* do we already have this entry in cache? */
290 if (Info->sFileName == FindFileData.cFileName)
291 {
292 /* is it current enough, or the file has been modified since our last time here? */
293 if (CompareFileTime(&FindFileData.ftLastWriteTime, &Info->ftCacheStamp) == 1)
294 {
295 /* recreate our cache, this is the slow path */
296 m_InfoList.RemoveAt(LastListPosition);
297
298 delete Info;
299 Info = nullptr;
300 break;
301 }
302 else
303 {
304 /* speedy path, compare directly, we already have the data */
305 goto skip_if_cached;
306 }
307 }
308 }
309
310 /* create a new entry */
311 Info = new CAvailableApplicationInfo(FindFileData.cFileName);
312
313 /* set a timestamp for the next time */
314 Info->SetLastWriteTime(&FindFileData.ftLastWriteTime);
315 m_InfoList.AddTail(Info);
316
317 skip_if_cached:
318 if (Info->Category == FALSE)
319 continue;
320
321 if (EnumType != Info->Category && EnumType != ENUM_ALL_AVAILABLE)
322 continue;
323
324 Info->RefreshAppInfo();
325
326 if (!lpEnumProc(static_cast<PAPPLICATION_INFO>(Info), m_szAppsPath.GetString()))
327 break;
328
329 } while (FindNextFileW(hFind, &FindFileData) != 0);
330
331 FindClose(hFind);
332 return TRUE;
333 }
334
335 const ATL::CStringW & CAvailableApps::GetFolderPath()
336 {
337 return m_szPath;
338 }
339
340 const ATL::CStringW & CAvailableApps::GetAppPath()
341 {
342 return m_szAppsPath;
343 }
344
345 const ATL::CStringW & CAvailableApps::GetCabPath()
346 {
347 return m_szCabPath;
348 }
349
350 const LPCWSTR CAvailableApps::GetFolderPathString()
351 {
352 return m_szPath.GetString();
353 }
354
355 const LPCWSTR CAvailableApps::GetAppPathString()
356 {
357 return m_szPath.GetString();
358 }
359
360 const LPCWSTR CAvailableApps::GetCabPathString()
361 {
362 return m_szPath.GetString();
363 }