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