#include "ServerHelper.h"
#include <stdio.h>
#include <stdlib.h>
#include <Alert.h>
#include <Application.h>
#include <Catalog.h>
#include <NetworkInterface.h>
#include <NetworkRoster.h>
#include "Logger.h"
#include "HaikuDepotConstants.h"
#include "ServerSettings.h"
#include "WebAppInterface.h"
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "ServerHelper"
static const char* const kKeyMinimumVersion = "minimum_version";
static const char* const kKeyHeaderMinimumVersion = "X-Desktop-Application-Minimum-Version";
void
ServerHelper::NotifyServerJsonRpcError(BMessage& responsePayload)
{
BMessage message(MSG_SERVER_ERROR);
message.AddMessage("error", &responsePayload);
be_app->PostMessage(&message);
}
void
ServerHelper::AlertServerJsonRpcError(BMessage* responseEnvelopeMessage)
{
BMessage errorMessage;
int32 errorCode = 0;
if (responseEnvelopeMessage->FindMessage("error", &errorMessage) == B_OK)
errorCode = WebAppInterface::ErrorCodeFromResponse(errorMessage);
BString alertText;
switch (errorCode) {
case ERROR_CODE_VALIDATION:
alertText = B_TRANSLATE("A validation error has occurred");
break;
case ERROR_CODE_OBJECTNOTFOUND:
alertText = B_TRANSLATE("A requested object or an object involved"
" in the request was not found on the server.");
break;
case ERROR_CODE_CAPTCHABADRESPONSE:
alertText = B_TRANSLATE("The response to the captcha was"
" incorrect.");
break;
case ERROR_CODE_AUTHORIZATIONFAILURE:
case ERROR_CODE_AUTHORIZATIONRULECONFLICT:
alertText = B_TRANSLATE("Authorization or security issue. Logout"
" and log back in again to check that your password is correct"
" and also check that you have agreed to the latest usage"
" conditions.");
break;
default:
alertText.SetToFormat(
B_TRANSLATE("An unexpected error has been sent from the"
" server [%" B_PRIi32 "]"), errorCode);
break;
}
BAlert* alert = new BAlert(
B_TRANSLATE("Server error"),
alertText,
B_TRANSLATE("OK"));
alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
alert->Go();
}
void
ServerHelper::NotifyTransportError(status_t error)
{
switch (error) {
case HD_CLIENT_TOO_OLD:
break;
default:
{
BMessage message(MSG_NETWORK_TRANSPORT_ERROR);
message.AddInt64("errno", (int64) error);
be_app->PostMessage(&message);
break;
}
}
}
void
ServerHelper::AlertTransportError(BMessage* message)
{
if (ServerSettings::ForceNoNetwork()) {
HDERROR("Even though the user has opted to force no networking, a network transport error"
" is being alerted.");
return;
}
status_t error = B_OK;
int64 errnoInt64;
message->FindInt64("errno", &errnoInt64);
error = (status_t) errnoInt64;
BString errorDescription("?");
BString alertText;
switch (error) {
case HD_NETWORK_INACCESSIBLE:
errorDescription = B_TRANSLATE("Network error");
break;
default:
errorDescription.SetTo(strerror(error));
break;
}
alertText.SetToFormat(B_TRANSLATE("A network transport error has arisen communicating with the"
" server system: %s"),
errorDescription.String());
BAlert* alert = new BAlert(B_TRANSLATE("Network transport error"), alertText,
B_TRANSLATE("Stop network use"), B_TRANSLATE("OK"));
alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
switch (alert->Go()) {
case 0:
HDINFO("user has opted to disable use of networking");
ServerSettings::SetForceNoNetwork(true);
break;
default:
break;
}
}
void
ServerHelper::NotifyClientTooOld(const BHttpHeaders& responseHeaders)
{
if (!ServerSettings::IsClientTooOld()) {
ServerSettings::SetClientTooOld();
const char* minimumVersionC = responseHeaders[kKeyHeaderMinimumVersion];
BMessage message(MSG_CLIENT_TOO_OLD);
if (minimumVersionC != NULL && strlen(minimumVersionC) != 0) {
message.AddString(kKeyMinimumVersion, minimumVersionC);
}
be_app->PostMessage(&message);
}
}
void
ServerHelper::AlertClientTooOld(BMessage* message)
{
BString minimumVersion;
BString alertText;
if (message->FindString(kKeyMinimumVersion, &minimumVersion) != B_OK)
minimumVersion = "???";
alertText.SetToFormat(
B_TRANSLATE("This application is too old to communicate with the"
" server system. Obtain a newer version of this application"
" by updating your system. The minimum required version of this"
" application 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;
}
void
ServerHelper::GetFailuresFromJsonRpcError(
ValidationFailures& failures, BMessage& responseEnvelopeMessage)
{
BMessage errorMessage;
if (responseEnvelopeMessage.FindMessage("error", &errorMessage) == B_OK) {
BMessage dataMessage;
if (errorMessage.FindMessage("data", &dataMessage) == B_OK) {
int32 i = 0;
BMessage dataItemMessage;
while (dataMessage.FindMessage(BString() << i, &dataItemMessage)
== B_OK) {
BString key;
BString value;
if (dataItemMessage.FindString("key", &key) == B_OK
&& dataItemMessage.FindString("value", &value) == B_OK) {
failures.AddFailure(key, value);
} else {
HDERROR("possibly corrupt validation message missing key "
"or value");
}
i++;
}
}
}
}