2 * PROJECT: ReactOS Applications Manager
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * FILE: base/applications/rapps/available.cpp
5 * PURPOSE: Classes for working with available applications
6 * COPYRIGHT: Copyright 2009 Dmitry Chapyshev (dmitry@reactos.org)
7 * Copyright 2015 Ismael Ferreras Morezuelas (swyterzone+ros@gmail.com)
8 * Copyright 2017 Alexander Shaposhnikov (sanchaez@reactos.org)
12 #include "available.h"
17 #include <atlsimpcoll.h>
20 // CAvailableApplicationInfo
21 CAvailableApplicationInfo::CAvailableApplicationInfo(const ATL::CStringW
& sFileNameParam
)
22 : m_IsSelected(FALSE
), m_LicenseType(LICENSE_NONE
), m_sFileName(sFileNameParam
),
23 m_IsInstalled(FALSE
), m_HasLanguageInfo(FALSE
), m_HasInstalledVersion(FALSE
)
25 RetrieveGeneralInfo();
28 VOID
CAvailableApplicationInfo::RefreshAppInfo()
30 if (m_szUrlDownload
.IsEmpty())
32 RetrieveGeneralInfo();
36 // Lazily load general info from the file
37 VOID
CAvailableApplicationInfo::RetrieveGeneralInfo()
39 m_Parser
= new CConfigParser(m_sFileName
);
41 m_Parser
->GetInt(L
"Category", m_Category
);
43 if (!GetString(L
"Name", m_szName
)
44 || !GetString(L
"URLDownload", m_szUrlDownload
))
50 GetString(L
"RegName", m_szRegName
);
51 GetString(L
"Version", m_szVersion
);
52 GetString(L
"License", m_szLicense
);
53 GetString(L
"Description", m_szDesc
);
54 GetString(L
"URLSite", m_szUrlSite
);
55 GetString(L
"CDPath", m_szCDPath
);
56 GetString(L
"Language", m_szRegName
);
57 GetString(L
"SHA1", m_szSHA1
);
60 RetrieveLicenseType();
62 RetrieveInstalledStatus();
66 RetrieveInstalledVersion();
72 VOID
CAvailableApplicationInfo::RetrieveInstalledStatus()
74 m_IsInstalled
= ::GetInstalledVersion(NULL
, m_szRegName
)
75 || ::GetInstalledVersion(NULL
, m_szName
);
78 VOID
CAvailableApplicationInfo::RetrieveInstalledVersion()
80 ATL::CStringW szNameVersion
;
81 szNameVersion
= m_szName
+ L
" " + m_szVersion
;
82 m_HasInstalledVersion
= ::GetInstalledVersion(&m_szInstalledVersion
, m_szRegName
)
83 || ::GetInstalledVersion(&m_szInstalledVersion
, m_szName
)
84 || ::GetInstalledVersion(&m_szInstalledVersion
, szNameVersion
);
87 VOID
CAvailableApplicationInfo::RetrieveLanguages()
89 const WCHAR cDelimiter
= L
'|';
90 ATL::CStringW szBuffer
;
92 // TODO: Get multiline parameter
93 if (!m_Parser
->GetString(L
"Languages", szBuffer
))
95 m_HasLanguageInfo
= FALSE
;
99 // Parse parameter string
100 ATL::CStringW m_szLocale
;
102 for (INT i
= 0; szBuffer
[i
] != UNICODE_NULL
; ++i
)
104 if (szBuffer
[i
] != cDelimiter
&& szBuffer
[i
] != L
'\n')
106 m_szLocale
+= szBuffer
[i
];
110 if (StrToIntExW(m_szLocale
.GetString(), STIF_DEFAULT
, &iLCID
))
112 m_LanguageLCIDs
.Add(static_cast<LCID
>(iLCID
));
118 // For the text after delimiter
119 if (!m_szLocale
.IsEmpty())
121 if (StrToIntExW(m_szLocale
.GetString(), STIF_DEFAULT
, &iLCID
))
123 m_LanguageLCIDs
.Add(static_cast<LCID
>(iLCID
));
127 m_HasLanguageInfo
= TRUE
;
130 VOID
CAvailableApplicationInfo::RetrieveLicenseType()
134 m_Parser
->GetInt(L
"LicenseType", IntBuffer
);
136 if (IsLicenseType(IntBuffer
))
138 m_LicenseType
= static_cast<LicenseType
>(IntBuffer
);
142 m_LicenseType
= LICENSE_NONE
;
146 VOID
CAvailableApplicationInfo::RetrieveSize()
150 if (!m_Parser
->GetInt(L
"SizeBytes", iSizeBytes
))
152 // fall back to "Size" string
153 GetString(L
"Size", m_szSize
);
157 StrFormatByteSizeW(iSizeBytes
, m_szSize
.GetBuffer(MAX_PATH
), MAX_PATH
);
158 m_szSize
.ReleaseBuffer();
161 BOOL
CAvailableApplicationInfo::FindInLanguages(LCID what
) const
163 if (!m_HasLanguageInfo
)
168 //Find locale code in the list
169 const INT nLanguagesSize
= m_LanguageLCIDs
.GetSize();
170 for (INT i
= 0; i
< nLanguagesSize
; ++i
)
172 if (m_LanguageLCIDs
[i
] == what
)
181 BOOL
CAvailableApplicationInfo::HasLanguageInfo() const
183 return m_HasLanguageInfo
;
186 BOOL
CAvailableApplicationInfo::HasNativeLanguage() const
188 return FindInLanguages(GetUserDefaultLCID());
191 BOOL
CAvailableApplicationInfo::HasEnglishLanguage() const
193 return FindInLanguages(MAKELCID(MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
), SORT_DEFAULT
));
196 BOOL
CAvailableApplicationInfo::IsInstalled() const
198 return m_IsInstalled
;
201 BOOL
CAvailableApplicationInfo::HasInstalledVersion() const
203 return m_HasInstalledVersion
;
206 BOOL
CAvailableApplicationInfo::HasUpdate() const
208 return (m_szInstalledVersion
.Compare(m_szVersion
) < 0) ? TRUE
: FALSE
;
211 VOID
CAvailableApplicationInfo::SetLastWriteTime(FILETIME
* ftTime
)
213 RtlCopyMemory(&m_ftCacheStamp
, ftTime
, sizeof(FILETIME
));
216 inline BOOL
CAvailableApplicationInfo::GetString(LPCWSTR lpKeyName
, ATL::CStringW
& ReturnedString
)
218 if (!m_Parser
->GetString(lpKeyName
, ReturnedString
))
220 ReturnedString
.Empty();
225 // CAvailableApplicationInfo
228 AvailableStrings::AvailableStrings()
230 //FIXME: maybe provide a fallback?
231 if (GetStorageDirectory(szPath
))
233 szAppsPath
= szPath
+ L
"\\rapps\\";
234 szCabName
= L
"rappmgr.cab";
236 szCabPath
= (szCabDir
+ L
"\\") + szCabName
;
237 szSearchPath
= szAppsPath
+ L
"*.txt";
243 AvailableStrings
CAvailableApps::m_Strings
;
245 CAvailableApps::CAvailableApps()
249 VOID
CAvailableApps::FreeCachedEntries()
251 POSITION InfoListPosition
= m_InfoList
.GetHeadPosition();
253 /* loop and deallocate all the cached app infos in the list */
254 while (InfoListPosition
)
256 CAvailableApplicationInfo
* Info
= m_InfoList
.GetNext(InfoListPosition
);
260 m_InfoList
.RemoveAll();
263 VOID
CAvailableApps::DeleteCurrentAppsDB()
265 HANDLE hFind
= INVALID_HANDLE_VALUE
;
266 WIN32_FIND_DATAW FindFileData
;
268 hFind
= FindFirstFileW(m_Strings
.szSearchPath
.GetString(), &FindFileData
);
270 if (hFind
!= INVALID_HANDLE_VALUE
)
275 szTmp
= m_Strings
.szAppsPath
+ FindFileData
.cFileName
;
276 DeleteFileW(szTmp
.GetString());
277 } while (FindNextFileW(hFind
, &FindFileData
) != 0);
281 RemoveDirectoryW(m_Strings
.szAppsPath
);
282 RemoveDirectoryW(m_Strings
.szPath
);
285 BOOL
CAvailableApps::UpdateAppsDB()
287 HANDLE hFind
= INVALID_HANDLE_VALUE
;
288 WIN32_FIND_DATAW FindFileData
;
290 if (!CreateDirectoryW(m_Strings
.szPath
, NULL
) && GetLastError() != ERROR_ALREADY_EXISTS
)
295 //if there are some files in the db folder - we're good
296 hFind
= FindFirstFileW(m_Strings
.szSearchPath
, &FindFileData
);
297 if (hFind
!= INVALID_HANDLE_VALUE
)
303 CDownloadManager::DownloadApplicationsDB(APPLICATION_DATABASE_URL
);
305 if (!ExtractFilesFromCab(m_Strings
.szCabName
,
307 m_Strings
.szAppsPath
))
312 DeleteFileW(m_Strings
.szCabPath
);
317 BOOL
CAvailableApps::ForceUpdateAppsDB()
319 DeleteCurrentAppsDB();
320 return UpdateAppsDB();
323 BOOL
CAvailableApps::Enum(INT EnumType
, AVAILENUMPROC lpEnumProc
)
326 HANDLE hFind
= INVALID_HANDLE_VALUE
;
327 WIN32_FIND_DATAW FindFileData
;
329 hFind
= FindFirstFileW(m_Strings
.szSearchPath
.GetString(), &FindFileData
);
331 if (hFind
== INVALID_HANDLE_VALUE
)
339 // loop for all the cached entries
340 POSITION CurrentListPosition
= m_InfoList
.GetHeadPosition();
341 CAvailableApplicationInfo
* Info
= NULL
;
343 while (CurrentListPosition
!= NULL
)
345 POSITION LastListPosition
= CurrentListPosition
;
346 Info
= m_InfoList
.GetNext(CurrentListPosition
);
348 // do we already have this entry in cache?
349 if (Info
->m_sFileName
== FindFileData
.cFileName
)
351 // is it current enough, or the file has been modified since our last time here?
352 if (CompareFileTime(&FindFileData
.ftLastWriteTime
, &Info
->m_ftCacheStamp
) == 1)
354 // recreate our cache, this is the slow path
355 m_InfoList
.RemoveAt(LastListPosition
);
363 // speedy path, compare directly, we already have the data
369 // create a new entry
370 Info
= new CAvailableApplicationInfo(FindFileData
.cFileName
);
372 // set a timestamp for the next time
373 Info
->SetLastWriteTime(&FindFileData
.ftLastWriteTime
);
374 m_InfoList
.AddTail(Info
);
377 if (EnumType
== Info
->m_Category
378 || EnumType
== ENUM_ALL_AVAILABLE
379 || (EnumType
== ENUM_CAT_SELECTED
&& Info
->m_IsSelected
))
381 Info
->RefreshAppInfo();
384 lpEnumProc(Info
, m_Strings
.szAppsPath
.GetString());
386 } while (FindNextFileW(hFind
, &FindFileData
) != 0);
392 CAvailableApplicationInfo
* CAvailableApps::FindInfo(const ATL::CStringW
& szAppName
) const
394 if (m_InfoList
.IsEmpty())
400 POSITION CurrentListPosition
= m_InfoList
.GetHeadPosition();
401 CAvailableApplicationInfo
* info
;
402 while (CurrentListPosition
!= NULL
)
404 info
= m_InfoList
.GetNext(CurrentListPosition
);
405 if (info
->m_szName
.CompareNoCase(szAppName
) == 0)
413 ATL::CSimpleArray
<CAvailableApplicationInfo
> CAvailableApps::FindInfoList(const ATL::CSimpleArray
<ATL::CStringW
> &arrAppsNames
) const
415 ATL::CSimpleArray
<CAvailableApplicationInfo
> result
;
416 for (INT i
= 0; i
< arrAppsNames
.GetSize(); ++i
)
418 CAvailableApplicationInfo
* Info
= FindInfo(arrAppsNames
[i
]);
427 ATL::CSimpleArray
<CAvailableApplicationInfo
> CAvailableApps::GetSelected() const
429 ATL::CSimpleArray
<CAvailableApplicationInfo
> result
;
430 POSITION CurrentListPosition
= m_InfoList
.GetHeadPosition();
431 CAvailableApplicationInfo
* Info
;
433 while (CurrentListPosition
!= NULL
)
435 Info
= m_InfoList
.GetNext(CurrentListPosition
);
436 if (Info
->m_IsSelected
)
444 const ATL::CStringW
& CAvailableApps::GetFolderPath() const
446 return m_Strings
.szPath
;
449 const ATL::CStringW
& CAvailableApps::GetAppPath() const
451 return m_Strings
.szAppsPath
;
454 const ATL::CStringW
& CAvailableApps::GetCabPath() const
456 return m_Strings
.szCabPath
;