From 54312619ab0d6bdebdb2426f6cfe275e2afa0fd6 Mon Sep 17 00:00:00 2001 From: Andrew Lindesay Date: Thu, 15 Feb 2018 22:19:21 +0100 Subject: [PATCH] HaikuDepot : 'Old Client' Handling The server side has the ability to reject client requests where the client is no longer supported because it is presumably too old. This change will inform the user when this happens and will prevent the client from attempting further server communications within this execution of the application. --- src/apps/haikudepot/HaikuDepotConstants.h | 22 +++++ src/apps/haikudepot/Jamfile | 1 + .../server/AbstractServerProcess.cpp | 15 +-- .../haikudepot/server/AbstractServerProcess.h | 12 +-- .../AbstractSingleFileServerProcess.cpp | 10 +- .../server/BulkLoadStateMachine.cpp | 35 +++---- .../haikudepot/server/BulkLoadStateMachine.h | 3 +- src/apps/haikudepot/server/ServerHelper.cpp | 92 +++++++++++++++++++ src/apps/haikudepot/server/ServerHelper.h | 24 +++++ .../server/ServerIconExportUpdateProcess.cpp | 19 ++-- src/apps/haikudepot/server/ServerSettings.cpp | 23 ++++- src/apps/haikudepot/server/ServerSettings.h | 7 +- .../haikudepot/server/WebAppInterface.cpp | 24 ++++- src/apps/haikudepot/ui/App.cpp | 9 +- src/apps/haikudepot/ui/MainWindow.h | 13 +-- 15 files changed, 237 insertions(+), 72 deletions(-) create mode 100644 src/apps/haikudepot/HaikuDepotConstants.h create mode 100644 src/apps/haikudepot/server/ServerHelper.cpp create mode 100644 src/apps/haikudepot/server/ServerHelper.h diff --git a/src/apps/haikudepot/HaikuDepotConstants.h b/src/apps/haikudepot/HaikuDepotConstants.h new file mode 100644 index 0000000000..7ca466b908 --- /dev/null +++ b/src/apps/haikudepot/HaikuDepotConstants.h @@ -0,0 +1,22 @@ +/* + * Copyright 2018, Andrew Lindesay . + * All rights reserved. Distributed under the terms of the MIT License. + */ + + +enum { + MSG_MAIN_WINDOW_CLOSED = 'mwcl', + MSG_PACKAGE_SELECTED = 'pkgs', + MSG_PACKAGE_WORKER_BUSY = 'pkwb', + MSG_PACKAGE_WORKER_IDLE = 'pkwi', + MSG_ADD_VISIBLE_PACKAGES = 'avpk', + MSG_UPDATE_SELECTED_PACKAGE = 'uspk', + MSG_CLIENT_TOO_OLD = 'oldc', +}; + + +#define HD_ERROR_BASE (B_ERRORS_END + 1) +#define HD_NETWORK_INACCESSIBLE (HD_ERROR_BASE + 1) +#define HD_CLIENT_TOO_OLD (HD_ERROR_BASE + 2) +#define HD_ERR_NOT_MODIFIED (HD_ERROR_BASE + 3) +#define HD_ERR_NO_DATA (HD_ERROR_BASE + 4) \ No newline at end of file diff --git a/src/apps/haikudepot/Jamfile b/src/apps/haikudepot/Jamfile index 02a988d599..72c968b781 100644 --- a/src/apps/haikudepot/Jamfile +++ b/src/apps/haikudepot/Jamfile @@ -101,6 +101,7 @@ Application HaikuDepot : # network + server AbstractServerProcess.cpp AbstractSingleFileServerProcess.cpp + ServerHelper.cpp ServerSettings.cpp WebAppInterface.cpp PkgDataUpdateProcess.cpp diff --git a/src/apps/haikudepot/server/AbstractServerProcess.cpp b/src/apps/haikudepot/server/AbstractServerProcess.cpp index c78614f035..3187476515 100644 --- a/src/apps/haikudepot/server/AbstractServerProcess.cpp +++ b/src/apps/haikudepot/server/AbstractServerProcess.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2017, Andrew Lindesay . + * Copyright 2017-2018, Andrew Lindesay . * All rights reserved. Distributed under the terms of the MIT License. */ #include "AbstractServerProcess.h" @@ -17,7 +17,9 @@ #include +#include "HaikuDepotConstants.h" #include "Logger.h" +#include "ServerHelper.h" #include "ServerSettings.h" #include "StandardMetaDataJsonEventListener.h" #include "StorageUtils.h" @@ -27,8 +29,6 @@ #define MAX_REDIRECTS 3 #define MAX_FAILURES 2 -#define HTTP_STATUS_FOUND 302 -#define HTTP_STATUS_NOT_MODIFIED 304 // 30 seconds #define TIMEOUT_MICROSECONDS 3e+7 @@ -405,10 +405,13 @@ AbstractServerProcess::DownloadToLocalFile(const BPath& targetFilePath, fprintf(stdout, "[%s] did complete streaming data [%" B_PRIdSSIZE " bytes]\n", Name(), listener.ContentLength()); return B_OK; - } else if (statusCode == HTTP_STATUS_NOT_MODIFIED) { + } else if (statusCode == B_HTTP_STATUS_NOT_MODIFIED) { fprintf(stdout, "[%s] remote data has not changed since [%s]\n", Name(), ifModifiedSinceHeader.String()); - return APP_ERR_NOT_MODIFIED; + return HD_ERR_NOT_MODIFIED; + } else if (statusCode == B_HTTP_STATUS_PRECONDITION_FAILED) { + ServerHelper::NotifyClientTooOld(responseHeaders); + return HD_CLIENT_TOO_OLD; } else if (BHttpRequest::IsRedirectionStatusCode(statusCode)) { if (location.Length() != 0) { BUrl redirectUrl(result.Url(), location); @@ -477,5 +480,5 @@ AbstractServerProcess::MoveDamagedFileAside(const BPath& currentFilePath) bool AbstractServerProcess::IsSuccess(status_t e) { - return e == B_OK || e == APP_ERR_NOT_MODIFIED; + return e == B_OK || e == HD_ERR_NOT_MODIFIED; } diff --git a/src/apps/haikudepot/server/AbstractServerProcess.h b/src/apps/haikudepot/server/AbstractServerProcess.h index f8288b13e3..11e7cf5602 100644 --- a/src/apps/haikudepot/server/AbstractServerProcess.h +++ b/src/apps/haikudepot/server/AbstractServerProcess.h @@ -1,5 +1,5 @@ /* - * Copyright 2017, Andrew Lindesay . + * Copyright 2017-2018, Andrew Lindesay . * All rights reserved. Distributed under the terms of the MIT License. */ @@ -15,10 +15,6 @@ #include "Stoppable.h" -#define APP_ERR_NOT_MODIFIED (B_APP_ERROR_BASE + 452) -#define APP_ERR_NO_DATA (B_APP_ERROR_BASE + 453) - - typedef enum process_options { SERVER_PROCESS_NO_NETWORKING = 1 << 0, SERVER_PROCESS_PREFER_CACHE = 1 << 1, @@ -87,10 +83,8 @@ protected: const BPath& targetFilePath, const BUrl& url); - status_t DeleteLocalFile(const BPath& currentFilePath); - - status_t MoveDamagedFileAside( - const BPath& currentFilePath); + status_t DeleteLocalFile(const BPath& filePath); + status_t MoveDamagedFileAside(const BPath& filePath); bool HasOption(uint32 flag); bool ShouldAttemptNetworkDownload( diff --git a/src/apps/haikudepot/server/AbstractSingleFileServerProcess.cpp b/src/apps/haikudepot/server/AbstractSingleFileServerProcess.cpp index 39df0eba90..2a852fa58f 100644 --- a/src/apps/haikudepot/server/AbstractSingleFileServerProcess.cpp +++ b/src/apps/haikudepot/server/AbstractSingleFileServerProcess.cpp @@ -1,9 +1,10 @@ /* - * Copyright 2017, Andrew Lindesay . + * Copyright 2017-2018, Andrew Lindesay . * All rights reserved. Distributed under the terms of the MIT License. */ #include "AbstractSingleFileServerProcess.h" +#include "HaikuDepotConstants.h" #include "Logger.h" #include "ServerSettings.h" #include "StorageUtils.h" @@ -49,18 +50,17 @@ AbstractSingleFileServerProcess::RunInternal() ServerSettings::CreateFullUrl(urlPathComponent)); } - if (IsSuccess(result) || result == APP_ERR_NOT_MODIFIED) { + if (IsSuccess(result)) { status_t hasDataResult = StorageUtils::ExistsObject( localPath, &hasData, NULL, &size); hasData = hasData && size > 0; if (hasDataResult == B_OK && !hasData) - result = APP_ERR_NO_DATA; + result = HD_ERR_NO_DATA; } - if (IsSuccess(result) || result == APP_ERR_NOT_MODIFIED) { - + if (IsSuccess(result)) { if (Logger::IsInfoEnabled()) printf("[%s] did fetch data\n", Name()); diff --git a/src/apps/haikudepot/server/BulkLoadStateMachine.cpp b/src/apps/haikudepot/server/BulkLoadStateMachine.cpp index e7a5a5b1e0..c88964816b 100644 --- a/src/apps/haikudepot/server/BulkLoadStateMachine.cpp +++ b/src/apps/haikudepot/server/BulkLoadStateMachine.cpp @@ -1,18 +1,17 @@ /* - * Copyright 2017, Andrew Lindesay . + * Copyright 2017-2018, Andrew Lindesay . * All rights reserved. Distributed under the terms of the MIT License. */ #include "BulkLoadStateMachine.h" #include -#include -#include #include "Logger.h" #include "PkgDataUpdateProcess.h" #include "RepositoryDataUpdateProcess.h" #include "ServerIconExportUpdateProcess.h" #include "ServerSettings.h" +#include "ServerHelper.h" BulkLoadStateMachine::BulkLoadStateMachine(Model* model) @@ -186,9 +185,17 @@ BulkLoadStateMachine::Start() if (!IsRunning()) { fBulkLoadContext = new BulkLoadContext(); - if (ServerSettings::ForceNoNetwork() || !HasNetwork()) + if (ServerSettings::IsClientTooOld()) { + printf("bulk load proceeding without network communications " + "because the client is too old\n"); fBulkLoadContext->AddProcessOption( SERVER_PROCESS_NO_NETWORKING); + } + + if (!ServerHelper::IsNetworkAvailable()) { + fBulkLoadContext->AddProcessOption( + SERVER_PROCESS_NO_NETWORKING); + } if (ServerSettings::PreferCache()) fBulkLoadContext->AddProcessOption(SERVER_PROCESS_PREFER_CACHE); @@ -348,22 +355,4 @@ BulkLoadStateMachine::InitiateBulkPopulatePackagesForAllDepots() if (0 == fBulkLoadContext->CountPkgProcesses()) ContextPoll(); -} - - -bool -BulkLoadStateMachine::HasNetwork() -{ - BNetworkRoster& roster = BNetworkRoster::Default(); - BNetworkInterface interface; - uint32 cookie = 0; - while (roster.GetNextInterface(&cookie, interface) == B_OK) { - uint32 flags = interface.Flags(); - if ((flags & IFF_LOOPBACK) == 0 - && (flags & (IFF_UP | IFF_LINK)) == (IFF_UP | IFF_LINK)) { - return true; - } - } - - return false; -} +} \ No newline at end of file diff --git a/src/apps/haikudepot/server/BulkLoadStateMachine.h b/src/apps/haikudepot/server/BulkLoadStateMachine.h index 0fb8f15085..b1063e5d6d 100644 --- a/src/apps/haikudepot/server/BulkLoadStateMachine.h +++ b/src/apps/haikudepot/server/BulkLoadStateMachine.h @@ -1,5 +1,5 @@ /* - * Copyright 2017, Andrew Lindesay . + * Copyright 2017-2018, Andrew Lindesay . * All rights reserved. Distributed under the terms of the MIT License. */ #ifndef BULK_LOAD_STATE_MACHINE_H @@ -31,7 +31,6 @@ private: void ContextPoll(); void SetContextState(bulk_load_state state); void StopAllProcesses(); - bool HasNetwork(); bool CanTransitionTo( bulk_load_state targetState); diff --git a/src/apps/haikudepot/server/ServerHelper.cpp b/src/apps/haikudepot/server/ServerHelper.cpp new file mode 100644 index 0000000000..d9033292b7 --- /dev/null +++ b/src/apps/haikudepot/server/ServerHelper.cpp @@ -0,0 +1,92 @@ +/* + * Copyright 2017-2018, Andrew Lindesay . + * All rights reserved. Distributed under the terms of the MIT License. + */ + +#include "ServerHelper.h" + +#include +#include + +#include +#include +#include +#include +#include + +#include "HaikuDepotConstants.h" +#include "ServerSettings.h" + + +#undef B_TRANSLATION_CONTEXT +#define B_TRANSLATION_CONTEXT "ServerHelper" +#define KEY_MSG_MINIMUM_VERSION "minimumVersion" +#define KEY_HEADER_MINIMUM_VERSION "X-Desktop-Application-Minimum-Version" + + +void +ServerHelper::NotifyClientTooOld(const BHttpHeaders& responseHeaders) +{ + if (!ServerSettings::IsClientTooOld()) { + ServerSettings::SetClientTooOld(); + + const char* minimumVersionC = responseHeaders[KEY_HEADER_MINIMUM_VERSION]; + BMessage message(MSG_CLIENT_TOO_OLD); + + if (minimumVersionC != NULL && strlen(minimumVersionC) != 0) { + message.AddString(KEY_MSG_MINIMUM_VERSION, minimumVersionC); + } + + be_app->PostMessage(&message); + } +} + + +void +ServerHelper::AlertClientTooOld(BMessage* message) +{ + BString minimumVersion; + BString alertText; + + if (message->FindString(KEY_MSG_MINIMUM_VERSION, &minimumVersion) != B_OK) + minimumVersion = "???"; + + alertText.SetToFormat( + B_TRANSLATE("This application is too old to communicate with the " + " HaikuDepot server system. Obtain a newer version of HaikuDepot " + " by updating your Haiku system. The minimum version of " + " HaikuDepot required is \"%s\"."), minimumVersion.String()); + + BAlert* alert = new BAlert( + B_TRANSLATE("client_version_too_old"), + alertText, + B_TRANSLATE("OK")); + + alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); + alert->Go(); +} + + +bool +ServerHelper::IsNetworkAvailable() +{ + return !ServerSettings::ForceNoNetwork() && IsPlatformNetworkAvailable(); +} + + +bool +ServerHelper::IsPlatformNetworkAvailable() +{ + BNetworkRoster& roster = BNetworkRoster::Default(); + BNetworkInterface interface; + uint32 cookie = 0; + while (roster.GetNextInterface(&cookie, interface) == B_OK) { + uint32 flags = interface.Flags(); + if ((flags & IFF_LOOPBACK) == 0 + && (flags & (IFF_UP | IFF_LINK)) == (IFF_UP | IFF_LINK)) { + return true; + } + } + + return false; +} diff --git a/src/apps/haikudepot/server/ServerHelper.h b/src/apps/haikudepot/server/ServerHelper.h new file mode 100644 index 0000000000..b526cf8845 --- /dev/null +++ b/src/apps/haikudepot/server/ServerHelper.h @@ -0,0 +1,24 @@ +/* + * Copyright 2017-2018, Andrew Lindesay . + * All rights reserved. Distributed under the terms of the MIT License. + */ + +#ifndef SERVER_HELPER_H +#define SERVER_HELPER_H + +#include +#include + + +class ServerHelper { +public: + static bool IsNetworkAvailable(); + static bool IsPlatformNetworkAvailable(); + + static void NotifyClientTooOld( + const BHttpHeaders& responseHeaders + ); + static void AlertClientTooOld(BMessage* message); +}; + +#endif // SERVER_HELPER_H diff --git a/src/apps/haikudepot/server/ServerIconExportUpdateProcess.cpp b/src/apps/haikudepot/server/ServerIconExportUpdateProcess.cpp index 5d434c9a35..521e355d20 100644 --- a/src/apps/haikudepot/server/ServerIconExportUpdateProcess.cpp +++ b/src/apps/haikudepot/server/ServerIconExportUpdateProcess.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2017, Andrew Lindesay . + * Copyright 2017-2018, Andrew Lindesay . * All rights reserved. Distributed under the terms of the MIT License. */ @@ -14,6 +14,7 @@ #include #include +#include "HaikuDepotConstants.h" #include "Logger.h" #include "ServerSettings.h" #include "StorageUtils.h" @@ -71,7 +72,7 @@ ServerIconExportUpdateProcess::RunInternal() status_t hasDataResult = HasLocalData(&hasData); if (IsSuccess(hasDataResult) && !hasData) - result = APP_ERR_NO_DATA; + result = HD_ERR_NO_DATA; } } @@ -150,10 +151,7 @@ ServerIconExportUpdateProcess::DownloadAndUnpack() result = Download(tarGzFilePath); - if (result != APP_ERR_NOT_MODIFIED) { - if (result != B_OK) - return result; - + if (result == B_OK) { printf("delete any existing stored data\n"); StorageUtils::RemoveDirectoryContents(fLocalStorageDirectoryPath); @@ -185,9 +183,9 @@ ServerIconExportUpdateProcess::DownloadAndUnpack() } delete tarGzFile; - } - printf("did complete fetching icons\n"); + printf("did complete fetching icons\n"); + } return result; } @@ -226,4 +224,7 @@ ServerIconExportUpdateProcess::Download(BPath& tarGzFilePath) { return DownloadToLocalFileAtomically(tarGzFilePath, ServerSettings::CreateFullUrl("/__pkgicon/all.tar.gz")); -} \ No newline at end of file +} + + + diff --git a/src/apps/haikudepot/server/ServerSettings.cpp b/src/apps/haikudepot/server/ServerSettings.cpp index 043fee4b48..7a24a887d2 100644 --- a/src/apps/haikudepot/server/ServerSettings.cpp +++ b/src/apps/haikudepot/server/ServerSettings.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2017, Andrew Lindesay . + * Copyright 2017-2018, Andrew Lindesay . * All rights reserved. Distributed under the terms of the MIT License. */ @@ -10,6 +10,9 @@ #include #include +#include +#include +#include #include #include @@ -24,6 +27,8 @@ pthread_once_t ServerSettings::sUserAgentInitOnce = PTHREAD_ONCE_INIT; bool ServerSettings::sPreferCache = false; bool ServerSettings::sDropCache = false; bool ServerSettings::sForceNoNetwork = false; +bool ServerSettings::sClientTooOld = false; +BLocker ServerSettings::sLock; status_t @@ -152,4 +157,20 @@ void ServerSettings::SetForceNoNetwork(bool value) { sForceNoNetwork = value; +} + + +bool +ServerSettings::IsClientTooOld() +{ + BAutolock locker(&sLock); + return sClientTooOld; +} + + +void +ServerSettings::SetClientTooOld() +{ + BAutolock locker(&sLock); + sClientTooOld = true; } \ No newline at end of file diff --git a/src/apps/haikudepot/server/ServerSettings.h b/src/apps/haikudepot/server/ServerSettings.h index 63fe40ec57..51f6073d4b 100644 --- a/src/apps/haikudepot/server/ServerSettings.h +++ b/src/apps/haikudepot/server/ServerSettings.h @@ -1,5 +1,5 @@ /* - * Copyright 2017, Andrew Lindesay . + * Copyright 2017-2018, Andrew Lindesay . * All rights reserved. Distributed under the terms of the MIT License. */ @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -26,17 +27,21 @@ public: static void SetDropCache(bool value); static bool ForceNoNetwork(); static void SetForceNoNetwork(bool value); + static bool IsClientTooOld(); + static void SetClientTooOld(); private: static void _InitUserAgent(); static const BString _GetUserAgentVersionString(); + static BLocker sLock; static BUrl sBaseUrl; static BString sUserAgent; static pthread_once_t sUserAgentInitOnce; static bool sPreferCache; static bool sDropCache; static bool sForceNoNetwork; + static bool sClientTooOld; }; #endif // SERVER_SETTINGS_H diff --git a/src/apps/haikudepot/server/WebAppInterface.cpp b/src/apps/haikudepot/server/WebAppInterface.cpp index c3e02ede50..b4e7c0ec09 100644 --- a/src/apps/haikudepot/server/WebAppInterface.cpp +++ b/src/apps/haikudepot/server/WebAppInterface.cpp @@ -23,10 +23,12 @@ #include #include "AutoLocker.h" +#include "HaikuDepotConstants.h" #include "List.h" #include "Logger.h" #include "PackageInfo.h" #include "ServerSettings.h" +#include "ServerHelper.h" #define BASEURL_DEFAULT "https://depot.haiku-os.org" @@ -560,6 +562,12 @@ status_t WebAppInterface::_SendJsonRequest(const char* domain, BString jsonString, uint32 flags, BMessage& reply) const { + if (!ServerHelper::IsNetworkAvailable()) + return HD_NETWORK_INACCESSIBLE; + + if (!ServerSettings::IsClientTooOld()) + return HD_CLIENT_TOO_OLD; + if (Logger::IsTraceEnabled()) printf("_SendJsonRequest(%s)\n", jsonString.String()); @@ -602,9 +610,19 @@ WebAppInterface::_SendJsonRequest(const char* domain, BString jsonString, request.Result()); int32 statusCode = result.StatusCode(); - if (statusCode != 200) { - printf("Response code: %" B_PRId32 "\n", statusCode); - return B_ERROR; + + switch (statusCode) { + case B_HTTP_STATUS_OK: + break; + + case B_HTTP_STATUS_PRECONDITION_FAILED: + ServerHelper::NotifyClientTooOld(result.Headers()); + return HD_CLIENT_TOO_OLD; + + default: + printf("json-rpc request to endpoint [.../%s] failed with http " + "status [%" B_PRId32 "]\n", domain, statusCode); + return B_ERROR; } jsonString.SetTo(static_cast(replyData.Buffer()), diff --git a/src/apps/haikudepot/ui/App.cpp b/src/apps/haikudepot/ui/App.cpp index e7ede8a8f4..af3543d509 100644 --- a/src/apps/haikudepot/ui/App.cpp +++ b/src/apps/haikudepot/ui/App.cpp @@ -1,6 +1,6 @@ /* * Copyright 2013, Stephan Aßmus . - * Copyright 2017, Andrew Lindesay . + * Copyright 2017-2018, Andrew Lindesay . * All rights reserved. Distributed under the terms of the MIT License. */ @@ -24,6 +24,7 @@ #include "FeaturedPackagesView.h" #include "Logger.h" #include "MainWindow.h" +#include "ServerHelper.h" #include "ServerSettings.h" #include "ScreenshotWindow.h" @@ -103,6 +104,10 @@ App::MessageReceived(BMessage* message) break; } + case MSG_CLIENT_TOO_OLD: + ServerHelper::AlertClientTooOld(message); + break; + default: BApplication::MessageReceived(message); break; @@ -149,7 +154,7 @@ app_print_help() fprintf(stdout, "'-v' : allows for the verbosity level to be set.\n"); fprintf(stdout, "'-u' : allows for the haiku depot server url to be\n"); fprintf(stdout, " configured.\n"); - fprintf(stdout, "'--nonetworking' : prevents network access.**\n"); + fprintf(stdout, "'--nonetworking' : prevents network access.\n"); fprintf(stdout, "'--prefercache' : prefer to get data from cache rather\n"); fprintf(stdout, " then obtain data from the network.**\n"); fprintf(stdout, "'--dropcache' : drop cached data before performing\n"); diff --git a/src/apps/haikudepot/ui/MainWindow.h b/src/apps/haikudepot/ui/MainWindow.h index 152b46c1c3..2fda08e70b 100644 --- a/src/apps/haikudepot/ui/MainWindow.h +++ b/src/apps/haikudepot/ui/MainWindow.h @@ -2,7 +2,7 @@ * Copyright 2013-2014, Stephan Aßmus . * Copyright 2013, Rene Gollent . * Copyright 2017, Julian Harnath . - * Copyright 2017, Andrew Lindesay . + * Copyright 2017-2018, Andrew Lindesay . * All rights reserved. Distributed under the terms of the MIT License. */ #ifndef MAIN_WINDOW_H @@ -15,6 +15,7 @@ #include "PackageAction.h" #include "PackageActionHandler.h" #include "PackageInfoListener.h" +#include "HaikuDepotConstants.h" class BCardLayout; @@ -30,16 +31,6 @@ class ScreenshotWindow; class WorkStatusView; -enum { - MSG_MAIN_WINDOW_CLOSED = 'mwcl', - MSG_PACKAGE_SELECTED = 'pkgs', - MSG_PACKAGE_WORKER_BUSY = 'pkwb', - MSG_PACKAGE_WORKER_IDLE = 'pkwi', - MSG_ADD_VISIBLE_PACKAGES = 'avpk', - MSG_UPDATE_SELECTED_PACKAGE = 'uspk', -}; - - class MainWindow : public BWindow, private PackageInfoListener, private PackageActionHandler { public: