[RAPPS]
[reactos.git] / reactos / base / applications / rapps / available.cpp
index 5c9ca6d..fd1ba2b 100644 (file)
@@ -1,53 +1,61 @@
 /*
- * PROJECT:         ReactOS Applications Manager
- * LICENSE:         GPL - See COPYING in the top level directory
- * FILE:            base/applications/rapps/available.cpp
- * PURPOSE:         Classes for working with available applications
- * PROGRAMMERS:     Dmitry Chapyshev           (dmitry@reactos.org)
- *                  Ismael Ferreras Morezuelas (swyterzone+ros@gmail.com)
- *                  Alexander Shaposhnikov     (chaez.san@gmail.com)
+ * PROJECT:     ReactOS Applications Manager
+ * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
+ * FILE:        base/applications/rapps/available.cpp
+ * PURPOSE:     Classes for working with available applications
+ * COPYRIGHT:   Copyright 2009 Dmitry Chapyshev           (dmitry@reactos.org)
+ *              Copyright 2015 Ismael Ferreras Morezuelas (swyterzone+ros@gmail.com)
+ *              Copyright 2017 Alexander Shaposhnikov     (sanchaez@reactos.org)
  */
-
 #include "rapps.h"
 
- // CAvailableApplicationInfo
+#include "available.h"
+#include "misc.h"
+#include "dialogs.h"
 
+#include <atlcoll.h>
+#include <atlsimpcoll.h>
+#include <atlstr.h>
+
+ // CAvailableApplicationInfo
 CAvailableApplicationInfo::CAvailableApplicationInfo(const ATL::CStringW& sFileNameParam)
-    : m_Parser(sFileNameParam)
+    : m_IsInstalled(FALSE), m_HasLanguageInfo(FALSE), m_HasInstalledVersion(FALSE), m_Parser(sFileNameParam)
 {
-    LicenseType = LICENSE_TYPE::None;
-    sFileName = sFileNameParam;
+    m_LicenseType = LICENSE_NONE;
+
+    m_sFileName = sFileNameParam;
 
     RetrieveGeneralInfo();
 }
 
 VOID CAvailableApplicationInfo::RefreshAppInfo()
 {
-    if (szUrlDownload.IsEmpty())
+    if (m_szUrlDownload.IsEmpty())
     {
         RetrieveGeneralInfo();
     }
 }
 
+// Lazily load general info from the file
 VOID CAvailableApplicationInfo::RetrieveGeneralInfo()
 {
-    Category = m_Parser.GetInt(L"Category");
+    m_Category = m_Parser.GetInt(L"Category");
 
-    if (!GetString(L"Name", szName)
-        || !GetString(L"URLDownload", szUrlDownload))
+    if (!GetString(L"Name", m_szName)
+        || !GetString(L"URLDownload", m_szUrlDownload))
     {
         return;
     }
 
-    GetString(L"RegName", szRegName);
-    GetString(L"Version", szVersion);
-    GetString(L"License", szLicense);
-    GetString(L"Description", szDesc);
-    GetString(L"Size", szSize);
-    GetString(L"URLSite", szUrlSite);
-    GetString(L"CDPath", szCDPath);
-    GetString(L"Language", szRegName);
-    GetString(L"SHA1", szSHA1);
+    GetString(L"RegName", m_szRegName);
+    GetString(L"Version", m_szVersion);
+    GetString(L"License", m_szLicense);
+    GetString(L"Description", m_szDesc);
+    GetString(L"Size", m_szSize);
+    GetString(L"URLSite", m_szUrlSite);
+    GetString(L"CDPath", m_szCDPath);
+    GetString(L"Language", m_szRegName);
+    GetString(L"SHA1", m_szSHA1);
 
     RetrieveLicenseType();
     RetrieveLanguages();
@@ -60,14 +68,17 @@ VOID CAvailableApplicationInfo::RetrieveGeneralInfo()
 
 VOID CAvailableApplicationInfo::RetrieveInstalledStatus()
 {
-    m_IsInstalled = ::GetInstalledVersion(NULL, szRegName)
-        || ::GetInstalledVersion(NULL, szName);
+    m_IsInstalled = ::GetInstalledVersion(NULL, m_szRegName)
+        || ::GetInstalledVersion(NULL, m_szName);
 }
 
 VOID CAvailableApplicationInfo::RetrieveInstalledVersion()
 {
-    m_HasInstalledVersion = ::GetInstalledVersion(&szInstalledVersion, szRegName)
-        || ::GetInstalledVersion(&szInstalledVersion, szName);
+    ATL::CStringW szNameVersion;
+    szNameVersion = m_szName + L" " + m_szVersion;
+    m_HasInstalledVersion = ::GetInstalledVersion(&m_szInstalledVersion, m_szRegName)
+        || ::GetInstalledVersion(&m_szInstalledVersion, m_szName)
+        || ::GetInstalledVersion(&m_szInstalledVersion, szNameVersion);
 }
 
 VOID CAvailableApplicationInfo::RetrieveLanguages()
@@ -84,7 +95,7 @@ VOID CAvailableApplicationInfo::RetrieveLanguages()
 
     // Parse parameter string
     ATL::CStringW m_szLocale;
-    int iLCID;
+    INT iLCID;
     for (INT i = 0; szBuffer[i] != UNICODE_NULL; ++i)
     {
         if (szBuffer[i] != cDelimiter && szBuffer[i] != L'\n')
@@ -95,7 +106,7 @@ VOID CAvailableApplicationInfo::RetrieveLanguages()
         {
             if (StrToIntExW(m_szLocale.GetString(), STIF_DEFAULT, &iLCID))
             {
-                Languages.Add(static_cast<LCID>(iLCID));
+                m_LanguageLCIDs.Add(static_cast<LCID>(iLCID));
                 m_szLocale.Empty();
             }
         }
@@ -106,7 +117,7 @@ VOID CAvailableApplicationInfo::RetrieveLanguages()
     {
         if (StrToIntExW(m_szLocale.GetString(), STIF_DEFAULT, &iLCID))
         {
-            Languages.Add(static_cast<LCID>(iLCID));
+            m_LanguageLCIDs.Add(static_cast<LCID>(iLCID));
         }
     }
 
@@ -117,13 +128,13 @@ VOID CAvailableApplicationInfo::RetrieveLicenseType()
 {
     INT IntBuffer = m_Parser.GetInt(L"LicenseType");
 
-    if (IntBuffer < 0 || IntBuffer > LICENSE_TYPE::Max)
+    if (IsLicenseType(IntBuffer))
     {
-        LicenseType = LICENSE_TYPE::None;
+        m_LicenseType = static_cast<LicenseType>(IntBuffer);
     }
     else
     {
-        LicenseType = (LICENSE_TYPE) IntBuffer;
+        m_LicenseType = LICENSE_NONE;
     }
 }
 
@@ -135,10 +146,10 @@ BOOL CAvailableApplicationInfo::FindInLanguages(LCID what) const
     }
 
     //Find locale code in the list
-    const INT nLanguagesSize = Languages.GetSize();
+    const INT nLanguagesSize = m_LanguageLCIDs.GetSize();
     for (INT i = 0; i < nLanguagesSize; ++i)
     {
-        if (Languages[i] == what)
+        if (m_LanguageLCIDs[i] == what)
         {
             return TRUE;
         }
@@ -174,12 +185,12 @@ BOOL CAvailableApplicationInfo::HasInstalledVersion() const
 
 BOOL CAvailableApplicationInfo::HasUpdate() const
 {
-    return (szInstalledVersion.Compare(szVersion) < 0) ? TRUE : FALSE;
+    return (m_szInstalledVersion.Compare(m_szVersion) < 0) ? TRUE : FALSE;
 }
 
 VOID CAvailableApplicationInfo::SetLastWriteTime(FILETIME* ftTime)
 {
-    RtlCopyMemory(&ftCacheStamp, ftTime, sizeof(FILETIME));
+    RtlCopyMemory(&m_ftCacheStamp, ftTime, sizeof(FILETIME));
 }
 
 inline BOOL CAvailableApplicationInfo::GetString(LPCWSTR lpKeyName, ATL::CStringW& ReturnedString)
@@ -194,15 +205,36 @@ inline BOOL CAvailableApplicationInfo::GetString(LPCWSTR lpKeyName, ATL::CString
 // CAvailableApplicationInfo 
 
 // CAvailableApps
-CAvailableApps::CAvailableApps()
+ATL::CStringW CAvailableApps::m_szPath;
+ATL::CStringW CAvailableApps::m_szCabPath;
+ATL::CStringW CAvailableApps::m_szAppsPath;
+ATL::CStringW CAvailableApps::m_szSearchPath;
+
+BOOL CAvailableApps::InitializeStaticStrings()
 {
-    //set all paths
+
+    if (!m_szPath.IsEmpty())
+    {
+        // strings are filled
+        return TRUE;
+    }
+
+    //FIXME: maybe provide a fallback?
     if (GetStorageDirectory(m_szPath))
     {
         m_szAppsPath = m_szPath + L"\\rapps\\";
         m_szCabPath = m_szPath + L"\\rappmgr.cab";
         m_szSearchPath = m_szAppsPath + L"*.txt";
+        return TRUE;
     }
+
+    return FALSE;
+}
+
+CAvailableApps::CAvailableApps()
+{
+    //set all paths
+    InitializeStaticStrings();
 }
 
 VOID CAvailableApps::FreeCachedEntries()
@@ -212,82 +244,92 @@ VOID CAvailableApps::FreeCachedEntries()
     /* loop and deallocate all the cached app infos in the list */
     while (InfoListPosition)
     {
-        CAvailableApplicationInfo* Info = m_InfoList.GetAt(InfoListPosition);
-        m_InfoList.RemoveHead();
+        CAvailableApplicationInfo* Info = m_InfoList.GetNext(InfoListPosition);
         delete Info;
-
-        InfoListPosition = m_InfoList.GetHeadPosition();
     }
+
+    m_InfoList.RemoveAll();
 }
 
-BOOL CAvailableApps::DeleteCurrentAppsDB()
+VOID CAvailableApps::DeleteCurrentAppsDB()
 {
     HANDLE hFind = INVALID_HANDLE_VALUE;
     WIN32_FIND_DATAW FindFileData;
-    BOOL result = TRUE;
 
-    if (m_szPath.IsEmpty())
-        return FALSE;
+    if (!InitializeStaticStrings())
+    {
+        return;
+    }
 
-    result = result && DeleteFileW(m_szCabPath.GetString());
     hFind = FindFirstFileW(m_szSearchPath.GetString(), &FindFileData);
 
-    if (hFind == INVALID_HANDLE_VALUE)
-        return result;
-
-    ATL::CStringW szTmp;
-    do
+    if (hFind != INVALID_HANDLE_VALUE)
     {
-        szTmp = m_szPath + FindFileData.cFileName;
-        result = result && DeleteFileW(szTmp.GetString());
-    } while (FindNextFileW(hFind, &FindFileData) != 0);
-
-    FindClose(hFind);
+        ATL::CStringW szTmp;
+        do
+        {
+            szTmp = m_szAppsPath + FindFileData.cFileName;
+            DeleteFileW(szTmp.GetString());
+        } while (FindNextFileW(hFind, &FindFileData) != 0);
+        FindClose(hFind);
+    }
 
-    return result;
+    RemoveDirectoryW(m_szAppsPath);
+    RemoveDirectoryW(m_szPath);
 }
 
 BOOL CAvailableApps::UpdateAppsDB()
 {
-    if (!DeleteCurrentAppsDB())
-        return FALSE;
+    HANDLE hFind = INVALID_HANDLE_VALUE;
+    WIN32_FIND_DATAW FindFileData;
 
-    DownloadApplicationsDB(APPLICATION_DATABASE_URL);
+    if (!InitializeStaticStrings())
+    {
+        return FALSE;
+    }
 
-    if (m_szPath.IsEmpty())
+    if (!CreateDirectoryW(m_szPath.GetString(), NULL) && GetLastError() != ERROR_ALREADY_EXISTS)
+    {
         return FALSE;
+    }
+
+    //if there are some files in the db folder - we're good
+    hFind = FindFirstFileW(m_szSearchPath.GetString(), &FindFileData);
+    if (hFind != INVALID_HANDLE_VALUE)
+    {
+        return TRUE;
+    }
+
+    CDownloadManager::DownloadApplicationsDB(APPLICATION_DATABASE_URL);
 
     if (!ExtractFilesFromCab(m_szCabPath, m_szAppsPath))
     {
         return FALSE;
     }
 
+    DeleteFileW(m_szCabPath.GetString());
+
     return TRUE;
 }
 
-BOOL CAvailableApps::EnumAvailableApplications(INT EnumType, AVAILENUMPROC lpEnumProc)
+BOOL CAvailableApps::ForceUpdateAppsDB()
 {
+    DeleteCurrentAppsDB();
+    return UpdateAppsDB();
+}
+
+BOOL CAvailableApps::Enum(INT EnumType, AVAILENUMPROC lpEnumProc)
+{
+
     HANDLE hFind = INVALID_HANDLE_VALUE;
     WIN32_FIND_DATAW FindFileData;
 
-    if (!CreateDirectoryW(m_szPath.GetString(), NULL) &&
-        GetLastError() != ERROR_ALREADY_EXISTS)
-    {
-        return FALSE;
-    }
-
     hFind = FindFirstFileW(m_szSearchPath.GetString(), &FindFileData);
 
     if (hFind == INVALID_HANDLE_VALUE)
     {
-        if (GetFileAttributesW(m_szCabPath) == INVALID_FILE_ATTRIBUTES)
-            DownloadApplicationsDB(APPLICATION_DATABASE_URL);
-
-        ExtractFilesFromCab(m_szCabPath, m_szAppsPath);
-        hFind = FindFirstFileW(m_szSearchPath.GetString(), &FindFileData);
-
-        if (hFind == INVALID_HANDLE_VALUE)
-            return FALSE;
+        //no db yet
+        return FALSE;
     }
 
     do
@@ -302,16 +344,16 @@ BOOL CAvailableApps::EnumAvailableApplications(INT EnumType, AVAILENUMPROC lpEnu
             Info = m_InfoList.GetNext(CurrentListPosition);
 
             // do we already have this entry in cache?
-            if (Info->sFileName == FindFileData.cFileName)
+            if (Info->m_sFileName == FindFileData.cFileName)
             {
                 // is it current enough, or the file has been modified since our last time here?
-                if (CompareFileTime(&FindFileData.ftLastWriteTime, &Info->ftCacheStamp) == 1)
+                if (CompareFileTime(&FindFileData.ftLastWriteTime, &Info->m_ftCacheStamp) == 1)
                 {
                     // recreate our cache, this is the slow path
                     m_InfoList.RemoveAt(LastListPosition);
 
                     delete Info;
-                    Info = nullptr;
+                    Info = NULL;
                     break;
                 }
                 else
@@ -330,16 +372,16 @@ BOOL CAvailableApps::EnumAvailableApplications(INT EnumType, AVAILENUMPROC lpEnu
         m_InfoList.AddTail(Info);
 
 skip_if_cached:
-        if (Info->Category == FALSE)
+        if (Info->m_Category == FALSE)
             continue;
 
-        if (EnumType != Info->Category && EnumType != ENUM_ALL_AVAILABLE)
+        if (EnumType != Info->m_Category && EnumType != ENUM_ALL_AVAILABLE)
             continue;
 
         Info->RefreshAppInfo();
 
-        if (!lpEnumProc(static_cast<PAPPLICATION_INFO>(Info), m_szAppsPath.GetString()))
-            break;
+        if (lpEnumProc)
+            lpEnumProc(static_cast<CAvailableApplicationInfo*>(Info), m_szAppsPath.GetString());
 
     } while (FindNextFileW(hFind, &FindFileData) != 0);
 
@@ -347,139 +389,68 @@ skip_if_cached:
     return TRUE;
 }
 
-const ATL::CStringW & CAvailableApps::GetFolderPath()
+CAvailableApplicationInfo* CAvailableApps::FindInfo(const ATL::CStringW& szAppName) const
 {
-    return m_szPath;
-}
-
-const ATL::CStringW & CAvailableApps::GetAppPath()
-{
-    return m_szAppsPath;
-}
-
-const ATL::CStringW & CAvailableApps::GetCabPath()
-{
-    return m_szCabPath;
-}
-
-const LPCWSTR CAvailableApps::GetFolderPathString()
-{
-    return m_szPath.GetString();
-}
-
-const LPCWSTR CAvailableApps::GetAppPathString()
-{
-    return m_szPath.GetString();
-}
+    if (m_InfoList.IsEmpty())
+    {
+        return NULL;
+    }
 
-const LPCWSTR CAvailableApps::GetCabPathString()
-{
-    return m_szPath.GetString();
+    // linear search
+    POSITION CurrentListPosition = m_InfoList.GetHeadPosition();
+    CAvailableApplicationInfo* info;
+    while (CurrentListPosition != NULL)
+    {
+        info = m_InfoList.GetNext(CurrentListPosition);
+        if (info->m_szName == szAppName)
+        {
+            return info;
+        }
+    }
+    return NULL;
 }
-// CAvailableApps
-
-// CConfigParser
-ATL::CStringW CConfigParser::m_szLocaleID;
-ATL::CStringW CConfigParser::m_szCachedINISectionLocale;
-ATL::CStringW CConfigParser::m_szCachedINISectionLocaleNeutral;
 
-CConfigParser::CConfigParser(const ATL::CStringW& FileName) : szConfigPath(GetINIFullPath(FileName))
+ATL::CSimpleArray<CAvailableApplicationInfo*> CAvailableApps::FindInfoList(const ATL::CSimpleArray<ATL::CStringW> &arrAppsNames) const
 {
-    // we don't have cached section strings for the current system language, create them, lazy
-    CacheINILocaleLazy();
+    ATL::CSimpleArray<CAvailableApplicationInfo*> result;
+    for (INT i = 0; i < arrAppsNames.GetSize(); ++i)
+    {
+        CAvailableApplicationInfo* Info = FindInfo(arrAppsNames[i]);
+        if (Info)
+        {
+            result.Add(Info);
+        }
+    }
+    return result;
 }
 
-ATL::CStringW CConfigParser::GetINIFullPath(const ATL::CStringW& FileName)
+const ATL::CStringW& CAvailableApps::GetFolderPath() const
 {
-    ATL::CStringW szDir;
-    ATL::CStringW szBuffer;
-
-    GetStorageDirectory(szDir);
-    szBuffer.Format(L"%ls\\rapps\\%ls", szDir, FileName);
-
-    return szBuffer;
+    return m_szPath;
 }
 
-VOID CConfigParser::CacheINILocaleLazy()
+const ATL::CStringW& CAvailableApps::GetAppPath() const
 {
-    if (m_szLocaleID.IsEmpty())
-    {
-        // TODO: Set default locale if call fails
-        // find out what is the current system lang code (e.g. "0a") and append it to SectionLocale
-        GetLocaleInfoW(GetUserDefaultLCID(), LOCALE_ILANGUAGE,
-                       m_szLocaleID.GetBuffer(m_cchLocaleSize), m_cchLocaleSize);
-
-        m_szLocaleID.ReleaseBuffer();
-        m_szCachedINISectionLocale = L"Section." + m_szLocaleID;
-
-        // turn "Section.0c0a" into "Section.0a", keeping just the neutral lang part
-        m_szCachedINISectionLocaleNeutral = m_szCachedINISectionLocale + m_szLocaleID.Right(2);
-    }
+    return m_szAppsPath;
 }
 
-const ATL::CStringW& CConfigParser::GetLocale()
+const ATL::CStringW& CAvailableApps::GetCabPath() const
 {
-    CacheINILocaleLazy();
-    return m_szLocaleID;
+    return m_szCabPath;
 }
 
-INT CConfigParser::GetLocaleSize()
+LPCWSTR CAvailableApps::GetFolderPathString() const
 {
-    return m_cchLocaleSize;
+    return m_szPath.GetString();
 }
 
-UINT CConfigParser::GetString(const ATL::CStringW& KeyName, ATL::CStringW& ResultString)
+LPCWSTR CAvailableApps::GetAppPathString() const
 {
-    DWORD dwResult;
-
-    LPWSTR ResultStringBuffer = ResultString.GetBuffer(MAX_PATH);
-    // 1st - find localized strings (e.g. "Section.0c0a")
-    dwResult = GetPrivateProfileStringW(m_szCachedINISectionLocale.GetString(),
-                                        KeyName.GetString(),
-                                        NULL,
-                                        ResultStringBuffer,
-                                        MAX_PATH,
-                                        szConfigPath.GetString());
-
-    if (!dwResult)
-    {
-        // 2nd - if they weren't present check for neutral sub-langs/ generic translations (e.g. "Section.0a")
-        dwResult = GetPrivateProfileStringW(m_szCachedINISectionLocaleNeutral.GetString(),
-                                            KeyName.GetString(),
-                                            NULL,
-                                            ResultStringBuffer,
-                                            MAX_PATH,
-                                            szConfigPath.GetString());
-        if (!dwResult)
-        {
-            // 3rd - if they weren't present fallback to standard english strings (just "Section")
-            dwResult = GetPrivateProfileStringW(L"Section",
-                                                KeyName.GetString(),
-                                                NULL,
-                                                ResultStringBuffer,
-                                                MAX_PATH,
-                                                szConfigPath.GetString());
-        }
-    }
-
-    ResultString.ReleaseBuffer();
-    return (dwResult != 0 ? TRUE : FALSE);
+    return m_szPath.GetString();
 }
 
-UINT CConfigParser::GetInt(const ATL::CStringW& KeyName)
+LPCWSTR CAvailableApps::GetCabPathString() const
 {
-    ATL::CStringW Buffer;
-
-    // grab the text version of our entry
-    if (!GetString(KeyName, Buffer))
-        return FALSE;
-
-    if (Buffer.IsEmpty())
-        return FALSE;
-
-    // convert it to an actual integer
-    int result = StrToIntW(Buffer.GetString());
-
-    return (UINT) (result <= 0) ? 0 : result;
+    return m_szPath.GetString();
 }
-// CConfigParser
\ No newline at end of file
+// CAvailableApps