1b164fe8b4d6f8baad5e39e576585cad2e52bf85
[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 CAvailableApps::CAvailableApps()
205 {
206 //set all paths
207 if (GetStorageDirectory(m_szPath))
208 {
209 m_szAppsPath = m_szPath + L"\\rapps\\";
210 m_szCabPath = m_szPath + L"\\rappmgr.cab";
211 m_szSearchPath = m_szAppsPath + L"*.txt";
212 }
213 }
214
215 VOID CAvailableApps::FreeCachedEntries()
216 {
217 POSITION InfoListPosition = m_InfoList.GetHeadPosition();
218
219 /* loop and deallocate all the cached app infos in the list */
220 while (InfoListPosition)
221 {
222 CAvailableApplicationInfo* Info = m_InfoList.GetAt(InfoListPosition);
223 m_InfoList.RemoveHead();
224 delete Info;
225
226 InfoListPosition = m_InfoList.GetHeadPosition();
227 }
228 }
229
230 BOOL CAvailableApps::DeleteCurrentAppsDB()
231 {
232 HANDLE hFind = INVALID_HANDLE_VALUE;
233 WIN32_FIND_DATAW FindFileData;
234 BOOL result = TRUE;
235
236 if (m_szPath.IsEmpty())
237 return FALSE;
238
239 result = result && DeleteFileW(m_szCabPath.GetString());
240 hFind = FindFirstFileW(m_szSearchPath.GetString(), &FindFileData);
241
242 if (hFind == INVALID_HANDLE_VALUE)
243 return result;
244
245 ATL::CStringW szTmp;
246 do
247 {
248 szTmp = m_szPath + FindFileData.cFileName;
249 result = result && DeleteFileW(szTmp.GetString());
250 } while (FindNextFileW(hFind, &FindFileData) != 0);
251
252 FindClose(hFind);
253
254 return result;
255 }
256
257 BOOL CAvailableApps::UpdateAppsDB()
258 {
259 if (!DeleteCurrentAppsDB())
260 return FALSE;
261
262 CDownloadManager::DownloadApplicationsDB(APPLICATION_DATABASE_URL);
263
264 if (m_szPath.IsEmpty())
265 return FALSE;
266
267 if (!ExtractFilesFromCab(m_szCabPath, m_szAppsPath))
268 {
269 return FALSE;
270 }
271
272 return TRUE;
273 }
274
275 BOOL CAvailableApps::EnumAvailableApplications(INT EnumType, AVAILENUMPROC lpEnumProc)
276 {
277 HANDLE hFind = INVALID_HANDLE_VALUE;
278 WIN32_FIND_DATAW FindFileData;
279
280 if (!CreateDirectoryW(m_szPath.GetString(), NULL) &&
281 GetLastError() != ERROR_ALREADY_EXISTS)
282 {
283 return FALSE;
284 }
285
286 hFind = FindFirstFileW(m_szSearchPath.GetString(), &FindFileData);
287
288 if (hFind == INVALID_HANDLE_VALUE)
289 {
290 if (GetFileAttributesW(m_szCabPath) == INVALID_FILE_ATTRIBUTES)
291 {
292 CDownloadManager::DownloadApplicationsDB(APPLICATION_DATABASE_URL);
293 }
294
295 ExtractFilesFromCab(m_szCabPath, m_szAppsPath);
296 hFind = FindFirstFileW(m_szSearchPath.GetString(), &FindFileData);
297
298 if (hFind == INVALID_HANDLE_VALUE)
299 {
300 return FALSE;
301 }
302 }
303
304 do
305 {
306 // loop for all the cached entries
307 POSITION CurrentListPosition = m_InfoList.GetHeadPosition();
308 CAvailableApplicationInfo* Info = NULL;
309
310 while (CurrentListPosition != NULL)
311 {
312 POSITION LastListPosition = CurrentListPosition;
313 Info = m_InfoList.GetNext(CurrentListPosition);
314
315 // do we already have this entry in cache?
316 if (Info->sFileName == FindFileData.cFileName)
317 {
318 // is it current enough, or the file has been modified since our last time here?
319 if (CompareFileTime(&FindFileData.ftLastWriteTime, &Info->ftCacheStamp) == 1)
320 {
321 // recreate our cache, this is the slow path
322 m_InfoList.RemoveAt(LastListPosition);
323
324 delete Info;
325 Info = NULL;
326 break;
327 }
328 else
329 {
330 // speedy path, compare directly, we already have the data
331 goto skip_if_cached;
332 }
333 }
334 }
335
336 // create a new entry
337 Info = new CAvailableApplicationInfo(FindFileData.cFileName);
338
339 // set a timestamp for the next time
340 Info->SetLastWriteTime(&FindFileData.ftLastWriteTime);
341 m_InfoList.AddTail(Info);
342
343 skip_if_cached:
344 if (Info->Category == FALSE)
345 continue;
346
347 if (EnumType != Info->Category && EnumType != ENUM_ALL_AVAILABLE)
348 continue;
349
350 Info->RefreshAppInfo();
351
352 if (lpEnumProc)
353 lpEnumProc(static_cast<PAPPLICATION_INFO>(Info), m_szAppsPath.GetString());
354
355 } while (FindNextFileW(hFind, &FindFileData) != 0);
356
357 FindClose(hFind);
358 return TRUE;
359 }
360
361 const PAPPLICATION_INFO CAvailableApps::FindInfo(const ATL::CStringW& szAppName)
362 {
363 if (m_InfoList.IsEmpty())
364 {
365 return NULL;
366 }
367
368 // linear search
369 POSITION CurrentListPosition = m_InfoList.GetHeadPosition();
370 PAPPLICATION_INFO info;
371 while (CurrentListPosition != NULL)
372 {
373 info = m_InfoList.GetNext(CurrentListPosition);
374 if (info->szName == szAppName)
375 {
376 return info;
377 }
378 }
379 return NULL;
380 }
381
382 ATL::CSimpleArray<PAPPLICATION_INFO> CAvailableApps::FindInfoList(const ATL::CSimpleArray<ATL::CStringW> &arrAppsNames)
383 {
384 ATL::CSimpleArray<PAPPLICATION_INFO> result;
385 for (INT i = 0; i < arrAppsNames.GetSize(); ++i)
386 {
387 PAPPLICATION_INFO Info = FindInfo(arrAppsNames[i]);
388 if (Info)
389 {
390 result.Add(Info);
391 }
392 }
393 return result;
394 }
395
396 const ATL::CStringW& CAvailableApps::GetFolderPath()
397 {
398 return m_szPath;
399 }
400
401 const ATL::CStringW& CAvailableApps::GetAppPath()
402 {
403 return m_szAppsPath;
404 }
405
406 const ATL::CStringW& CAvailableApps::GetCabPath()
407 {
408 return m_szCabPath;
409 }
410
411 const LPCWSTR CAvailableApps::GetFolderPathString()
412 {
413 return m_szPath.GetString();
414 }
415
416 const LPCWSTR CAvailableApps::GetAppPathString()
417 {
418 return m_szPath.GetString();
419 }
420
421 const LPCWSTR CAvailableApps::GetCabPathString()
422 {
423 return m_szPath.GetString();
424 }
425 // CAvailableApps