f30d8f04e9f2212dea15a5ef91c49f530462e691
[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 #include "defines.h"
11
12 #include "available.h"
13 #include "misc.h"
14 #include "dialogs.h"
15
16 #include <atlcoll.h>
17 #include <atlsimpcoll.h>
18 #include <atlstr.h>
19
20 // CAvailableApplicationInfo
21 CAvailableApplicationInfo::CAvailableApplicationInfo(const ATL::CStringW& sFileNameParam)
22 : m_Parser(sFileNameParam)
23 {
24 LicenseType = LICENSE_TYPE::None;
25 sFileName = sFileNameParam;
26
27 RetrieveGeneralInfo();
28 }
29
30 VOID CAvailableApplicationInfo::RefreshAppInfo()
31 {
32 if (szUrlDownload.IsEmpty())
33 {
34 RetrieveGeneralInfo();
35 }
36 }
37
38 // Lazily load general info from the file
39 VOID CAvailableApplicationInfo::RetrieveGeneralInfo()
40 {
41 Category = m_Parser.GetInt(L"Category");
42
43 if (!GetString(L"Name", szName)
44 || !GetString(L"URLDownload", szUrlDownload))
45 {
46 return;
47 }
48
49 GetString(L"RegName", szRegName);
50 GetString(L"Version", szVersion);
51 GetString(L"License", szLicense);
52 GetString(L"Description", szDesc);
53 GetString(L"Size", szSize);
54 GetString(L"URLSite", szUrlSite);
55 GetString(L"CDPath", szCDPath);
56 GetString(L"Language", szRegName);
57 GetString(L"SHA1", szSHA1);
58
59 RetrieveLicenseType();
60 RetrieveLanguages();
61 RetrieveInstalledStatus();
62 if (m_IsInstalled)
63 {
64 RetrieveInstalledVersion();
65 }
66 }
67
68 VOID CAvailableApplicationInfo::RetrieveInstalledStatus()
69 {
70 m_IsInstalled = ::GetInstalledVersion(NULL, szRegName)
71 || ::GetInstalledVersion(NULL, szName);
72 }
73
74 VOID CAvailableApplicationInfo::RetrieveInstalledVersion()
75 {
76 m_HasInstalledVersion = ::GetInstalledVersion(&szInstalledVersion, szRegName)
77 || ::GetInstalledVersion(&szInstalledVersion, szName);
78 }
79
80 VOID CAvailableApplicationInfo::RetrieveLanguages()
81 {
82 const WCHAR cDelimiter = L'|';
83 ATL::CStringW szBuffer;
84
85 // TODO: Get multiline parameter
86 if (!m_Parser.GetString(L"Languages", szBuffer))
87 {
88 m_HasLanguageInfo = FALSE;
89 return;
90 }
91
92 // Parse parameter string
93 ATL::CStringW m_szLocale;
94 INT iLCID;
95 for (INT i = 0; szBuffer[i] != UNICODE_NULL; ++i)
96 {
97 if (szBuffer[i] != cDelimiter && szBuffer[i] != L'\n')
98 {
99 m_szLocale += szBuffer[i];
100 }
101 else
102 {
103 if (StrToIntExW(m_szLocale.GetString(), STIF_DEFAULT, &iLCID))
104 {
105 Languages.Add(static_cast<LCID>(iLCID));
106 m_szLocale.Empty();
107 }
108 }
109 }
110
111 // For the text after delimiter
112 if (!m_szLocale.IsEmpty())
113 {
114 if (StrToIntExW(m_szLocale.GetString(), STIF_DEFAULT, &iLCID))
115 {
116 Languages.Add(static_cast<LCID>(iLCID));
117 }
118 }
119
120 m_HasLanguageInfo = TRUE;
121 }
122
123 VOID CAvailableApplicationInfo::RetrieveLicenseType()
124 {
125 INT IntBuffer = m_Parser.GetInt(L"LicenseType");
126
127 if (IntBuffer < 0 || IntBuffer > LICENSE_TYPE::Max)
128 {
129 LicenseType = LICENSE_TYPE::None;
130 }
131 else
132 {
133 LicenseType = (LICENSE_TYPE) IntBuffer;
134 }
135 }
136
137 BOOL CAvailableApplicationInfo::FindInLanguages(LCID what) const
138 {
139 if (!m_HasLanguageInfo)
140 {
141 return FALSE;
142 }
143
144 //Find locale code in the list
145 const INT nLanguagesSize = Languages.GetSize();
146 for (INT i = 0; i < nLanguagesSize; ++i)
147 {
148 if (Languages[i] == what)
149 {
150 return TRUE;
151 }
152 }
153
154 return FALSE;
155 }
156
157 BOOL CAvailableApplicationInfo::HasLanguageInfo() const
158 {
159 return m_HasLanguageInfo;
160 }
161
162 BOOL CAvailableApplicationInfo::HasNativeLanguage() const
163 {
164 return FindInLanguages(GetUserDefaultLCID());
165 }
166
167 BOOL CAvailableApplicationInfo::HasEnglishLanguage() const
168 {
169 return FindInLanguages(MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), SORT_DEFAULT));
170 }
171
172 BOOL CAvailableApplicationInfo::IsInstalled() const
173 {
174 return m_IsInstalled;
175 }
176
177 BOOL CAvailableApplicationInfo::HasInstalledVersion() const
178 {
179 return m_HasInstalledVersion;
180 }
181
182 BOOL CAvailableApplicationInfo::HasUpdate() const
183 {
184 return (szInstalledVersion.Compare(szVersion) < 0) ? TRUE : FALSE;
185 }
186
187 VOID CAvailableApplicationInfo::SetLastWriteTime(FILETIME* ftTime)
188 {
189 RtlCopyMemory(&ftCacheStamp, ftTime, sizeof(FILETIME));
190 }
191
192 inline BOOL CAvailableApplicationInfo::GetString(LPCWSTR lpKeyName, ATL::CStringW& ReturnedString)
193 {
194 if (!m_Parser.GetString(lpKeyName, ReturnedString))
195 {
196 ReturnedString.Empty();
197 return FALSE;
198 }
199 return TRUE;
200 }
201 // CAvailableApplicationInfo
202
203 // CAvailableApps
204 ATL::CStringW CAvailableApps::m_szPath;
205 ATL::CStringW CAvailableApps::m_szCabPath;
206 ATL::CStringW CAvailableApps::m_szAppsPath;
207 ATL::CStringW CAvailableApps::m_szSearchPath;
208
209 BOOL CAvailableApps::InitializeStaticStrings()
210 {
211
212 if (!m_szPath.IsEmpty())
213 {
214 // strings are filled
215 return TRUE;
216 }
217
218 //FIXME: maybe provide a fallback?
219 if (GetStorageDirectory(m_szPath))
220 {
221 m_szAppsPath = m_szPath + L"\\rapps\\";
222 m_szCabPath = m_szPath + L"\\rappmgr.cab";
223 m_szSearchPath = m_szAppsPath + L"*.txt";
224 return TRUE;
225 }
226
227 return FALSE;
228 }
229
230 CAvailableApps::CAvailableApps()
231 {
232 //set all paths
233 InitializeStaticStrings();
234 }
235
236 VOID CAvailableApps::FreeCachedEntries()
237 {
238 POSITION InfoListPosition = m_InfoList.GetHeadPosition();
239
240 /* loop and deallocate all the cached app infos in the list */
241 while (InfoListPosition)
242 {
243 CAvailableApplicationInfo* Info = m_InfoList.GetNext(InfoListPosition);
244 delete Info;
245 }
246
247 m_InfoList.RemoveAll();
248 }
249
250 VOID CAvailableApps::DeleteCurrentAppsDB()
251 {
252 HANDLE hFind = INVALID_HANDLE_VALUE;
253 WIN32_FIND_DATAW FindFileData;
254
255 if (!InitializeStaticStrings())
256 {
257 return;
258 }
259
260 hFind = FindFirstFileW(m_szSearchPath.GetString(), &FindFileData);
261
262 if (hFind != INVALID_HANDLE_VALUE)
263 {
264 ATL::CStringW szTmp;
265 do
266 {
267 szTmp = m_szAppsPath + FindFileData.cFileName;
268 DeleteFileW(szTmp.GetString());
269 } while (FindNextFileW(hFind, &FindFileData) != 0);
270 FindClose(hFind);
271 }
272
273 RemoveDirectoryW(m_szAppsPath);
274 RemoveDirectoryW(m_szPath);
275 }
276
277 BOOL CAvailableApps::UpdateAppsDB()
278 {
279 HANDLE hFind = INVALID_HANDLE_VALUE;
280 WIN32_FIND_DATAW FindFileData;
281
282 if (!InitializeStaticStrings())
283 {
284 return FALSE;
285 }
286
287 if (!CreateDirectoryW(m_szPath.GetString(), NULL) && GetLastError() != ERROR_ALREADY_EXISTS)
288 {
289 return FALSE;
290 }
291
292 //if there are some files in the db folder - we're good
293 hFind = FindFirstFileW(m_szSearchPath.GetString(), &FindFileData);
294 if (hFind != INVALID_HANDLE_VALUE)
295 {
296 return TRUE;
297 }
298
299 CDownloadManager::DownloadApplicationsDB(APPLICATION_DATABASE_URL);
300
301 if (!ExtractFilesFromCab(m_szCabPath, m_szAppsPath))
302 {
303 return FALSE;
304 }
305
306 DeleteFileW(m_szCabPath.GetString());
307
308 return TRUE;
309 }
310
311 BOOL CAvailableApps::ForceUpdateAppsDB()
312 {
313 DeleteCurrentAppsDB();
314 return UpdateAppsDB();
315 }
316
317 BOOL CAvailableApps::EnumAvailableApplications(INT EnumType, AVAILENUMPROC lpEnumProc)
318 {
319
320 HANDLE hFind = INVALID_HANDLE_VALUE;
321 WIN32_FIND_DATAW FindFileData;
322
323 hFind = FindFirstFileW(m_szSearchPath.GetString(), &FindFileData);
324
325 if (hFind == INVALID_HANDLE_VALUE)
326 {
327 //no db yet
328 return FALSE;
329 }
330
331 do
332 {
333 // loop for all the cached entries
334 POSITION CurrentListPosition = m_InfoList.GetHeadPosition();
335 CAvailableApplicationInfo* Info = NULL;
336
337 while (CurrentListPosition != NULL)
338 {
339 POSITION LastListPosition = CurrentListPosition;
340 Info = m_InfoList.GetNext(CurrentListPosition);
341
342 // do we already have this entry in cache?
343 if (Info->sFileName == FindFileData.cFileName)
344 {
345 // is it current enough, or the file has been modified since our last time here?
346 if (CompareFileTime(&FindFileData.ftLastWriteTime, &Info->ftCacheStamp) == 1)
347 {
348 // recreate our cache, this is the slow path
349 m_InfoList.RemoveAt(LastListPosition);
350
351 delete Info;
352 Info = NULL;
353 break;
354 }
355 else
356 {
357 // speedy path, compare directly, we already have the data
358 goto skip_if_cached;
359 }
360 }
361 }
362
363 // create a new entry
364 Info = new CAvailableApplicationInfo(FindFileData.cFileName);
365
366 // set a timestamp for the next time
367 Info->SetLastWriteTime(&FindFileData.ftLastWriteTime);
368 m_InfoList.AddTail(Info);
369
370 skip_if_cached:
371 if (Info->Category == FALSE)
372 continue;
373
374 if (EnumType != Info->Category && EnumType != ENUM_ALL_AVAILABLE)
375 continue;
376
377 Info->RefreshAppInfo();
378
379 if (lpEnumProc)
380 lpEnumProc(static_cast<PAPPLICATION_INFO>(Info), m_szAppsPath.GetString());
381
382 } while (FindNextFileW(hFind, &FindFileData) != 0);
383
384 FindClose(hFind);
385 return TRUE;
386 }
387
388 const PAPPLICATION_INFO CAvailableApps::FindInfo(const ATL::CStringW& szAppName)
389 {
390 if (m_InfoList.IsEmpty())
391 {
392 return NULL;
393 }
394
395 // linear search
396 POSITION CurrentListPosition = m_InfoList.GetHeadPosition();
397 PAPPLICATION_INFO info;
398 while (CurrentListPosition != NULL)
399 {
400 info = m_InfoList.GetNext(CurrentListPosition);
401 if (info->szName == szAppName)
402 {
403 return info;
404 }
405 }
406 return NULL;
407 }
408
409 ATL::CSimpleArray<PAPPLICATION_INFO> CAvailableApps::FindInfoList(const ATL::CSimpleArray<ATL::CStringW> &arrAppsNames)
410 {
411 ATL::CSimpleArray<PAPPLICATION_INFO> result;
412 for (INT i = 0; i < arrAppsNames.GetSize(); ++i)
413 {
414 PAPPLICATION_INFO Info = FindInfo(arrAppsNames[i]);
415 if (Info)
416 {
417 result.Add(Info);
418 }
419 }
420 return result;
421 }
422
423 const ATL::CStringW& CAvailableApps::GetFolderPath()
424 {
425 return m_szPath;
426 }
427
428 const ATL::CStringW& CAvailableApps::GetAppPath()
429 {
430 return m_szAppsPath;
431 }
432
433 const ATL::CStringW& CAvailableApps::GetCabPath()
434 {
435 return m_szCabPath;
436 }
437
438 const LPCWSTR CAvailableApps::GetFolderPathString()
439 {
440 return m_szPath.GetString();
441 }
442
443 const LPCWSTR CAvailableApps::GetAppPathString()
444 {
445 return m_szPath.GetString();
446 }
447
448 const LPCWSTR CAvailableApps::GetCabPathString()
449 {
450 return m_szPath.GetString();
451 }
452 // CAvailableApps