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