Files
pilotclient/src/blackgui/components/loginadvcomponent.cpp
Klaus Basan dd70a67cf0 Ref T703, get partner callsign and validate it
* added functions in network details
* validation and login with partner callsign
2019-09-16 22:41:21 +01:00

395 lines
16 KiB
C++

/* Copyright (C) 2019
* swift project Community / Contributors
*
* This file is part of swift Project. It is subject to the license terms in the LICENSE file found in the top-level
* directory of this distribution. No part of swift project, including this file, may be copied, modified, propagated,
* or distributed except according to the terms contained in the LICENSE file.
*/
#include "ui_loginadvcomponent.h"
#include "loginadvcomponent.h"
#include "serverlistselector.h"
#include "dbquickmappingwizard.h"
#include "blackgui/editors/serverform.h"
#include "blackgui/editors/pilotform.h"
#include "blackgui/guiapplication.h"
#include "blackgui/loginmodebuttons.h"
#include "blackgui/ticklabel.h"
#include "blackgui/uppercasevalidator.h"
#include "blackcore/context/contextaudio.h"
#include "blackcore/context/contextownaircraft.h"
#include "blackcore/context/contextsimulator.h"
#include "blackcore/context/contextnetwork.h"
#include "blackcore/data/globalsetup.h"
#include "blackcore/webdataservices.h"
#include "blackcore/network.h"
#include "blackcore/simulator.h"
#include "blackmisc/simulation/simulatorinternals.h"
#include "blackmisc/simulation/aircraftmodel.h"
#include "blackmisc/simulation/simulatedaircraft.h"
#include "blackmisc/aviation/aircrafticaocode.h"
#include "blackmisc/aviation/airlineicaocode.h"
#include "blackmisc/aviation/airporticaocode.h"
#include "blackmisc/network/entityflags.h"
#include "blackmisc/network/serverlist.h"
#include "blackmisc/icons.h"
#include "blackmisc/logmessage.h"
#include "blackmisc/statusmessage.h"
#include "blackmisc/crashhandler.h"
#include "blackconfig/buildconfig.h"
#include <QDialogButtonBox>
#include <QMessageBox>
#include <QGroupBox>
#include <QIntValidator>
#include <QLineEdit>
#include <QProgressBar>
#include <QPushButton>
#include <QTabWidget>
#include <QTimer>
#include <QToolButton>
#include <QStringBuilder>
#include <QtGlobal>
#include <QPointer>
#include <QPair>
using namespace BlackConfig;
using namespace BlackMisc;
using namespace BlackMisc::Aviation;
using namespace BlackMisc::Audio;
using namespace BlackMisc::Network;
using namespace BlackMisc::Simulation;
using namespace BlackCore;
using namespace BlackCore::Data;
using namespace BlackCore::Context;
using namespace BlackGui;
namespace BlackGui
{
namespace Components
{
const CLogCategoryList &CLoginAdvComponent::getLogCategories()
{
static const BlackMisc::CLogCategoryList cats { CLogCategory::guiComponent() };
return cats;
}
CLoginAdvComponent::CLoginAdvComponent(QWidget *parent) :
COverlayMessagesFrame(parent),
ui(new Ui::CLoginAdvComponent)
{
ui->setupUi(this);
connect(ui->pb_Cancel, &QPushButton::clicked, this, &CLoginAdvComponent::loginCancelled, Qt::QueuedConnection);
connect(ui->pb_Connect, &QPushButton::clicked, this, &CLoginAdvComponent::toggleNetworkConnection, Qt::QueuedConnection);
connect(ui->comp_NetworkDetails, &CNetworkDetailsComponent::overridePilot, this, &CLoginAdvComponent::overrideCredentialsToPilot, Qt::QueuedConnection);
connect(ui->comp_NetworkDetails, &CNetworkDetailsComponent::requestNetworkSettings, this, &CLoginAdvComponent::requestNetworkSettings, Qt::QueuedConnection);
// overlay
this->setOverlaySizeFactors(0.8, 0.5);
this->setReducedInfo(true);
this->setForceSmall(true);
this->showKillButton(false);
// override details/voice
ui->comp_NetworkDetails->setAlwaysAllowOverride(true);
// auto logoff
// we decided to make it difficult for users to disable it
if (!CBuildConfig::isLocalDeveloperDebugBuild())
{
ui->cb_AutoLogoff->setChecked(true);
}
// Stored data
this->loadRememberedUserData();
// signals
if (sGui && sGui->getIContextSimulator())
{
connect(sGui->getIContextSimulator(), &IContextSimulator::vitalityLost, this, &CLoginAdvComponent::autoLogoffDetection, Qt::QueuedConnection);
connect(sGui->getIContextSimulator(), &IContextSimulator::simulatorStatusChanged, this, &CLoginAdvComponent::onSimulatorStatusChanged, Qt::QueuedConnection);
}
// inital setup, if data already available
ui->form_Pilot->validate();
ui->cb_AutoLogoff->setChecked(m_networkSetup.useAutoLogoff());
}
CLoginAdvComponent::~CLoginAdvComponent()
{ }
void CLoginAdvComponent::setAutoLogoff(bool autoLogoff)
{
ui->cb_AutoLogoff->setChecked(autoLogoff);
}
void CLoginAdvComponent::loginCancelled()
{
this->closeOverlay();
emit this->loginOrLogoffCancelled();
}
void CLoginAdvComponent::toggleNetworkConnection()
{
if (!sGui || sGui->isShuttingDown()) { return; }
if (!sGui->getIContextNetwork() || !sGui->getIContextAudio()) { return; }
const bool isConnected = sGui && sGui->getIContextNetwork()->isConnected();
const bool vatsimLogin = ui->comp_NetworkDetails->isVatsimServerSelected();
m_networkSetup.setAutoLogoff(ui->cb_AutoLogoff->isChecked());
ui->form_Pilot->setVatsimValidation(vatsimLogin);
CServer currentServer; // used for login
CSimulatedAircraft ownAircraft; // used own aircraft
CStatusMessage msg;
if (!isConnected)
{
const CStatusMessageList aircraftMsgs = ui->comp_OwnAircraft->validate();
if (aircraftMsgs.isFailure())
{
this->showOverlayHTMLMessage(CStatusMessage(this).validationWarning(u"Invalid aircraft data, login not possible"), OverlayMessageMs);
return;
}
const CStatusMessageList pilotMsgs = ui->form_Pilot->validate();
if (pilotMsgs.isFailure())
{
// this->showOverlayHTMLMessage(CStatusMessage(this).validationWarning(u"Invalid pilot data, login not possible"), OverlayMessageMs);
this->showOverlayMessagesOrHTMLMessage(pilotMsgs, false, OverlayMessageMs);
return;
}
// sync values with GUI values
const COwnAircraftComponent::CGuiAircraftValues values = ui->comp_OwnAircraft->getAircraftValuesFromGui();
this->updateOwnAircraftCallsignAndPilotFromGuiValues();
ui->comp_OwnAircraft->updateOwnAircaftIcaoValuesFromGuiValues();
// Login mode
const INetwork::LoginMode mode = ui->comp_NetworkDetails->getLoginMode();
switch (mode)
{
case INetwork::LoginStealth: CLogMessage(this).info(u"login in stealth mode"); break;
case INetwork::LoginAsObserver: CLogMessage(this).info(u"login in observer mode"); break;
default: break; // INetwork::LoginNormal
}
// Server
currentServer = this->getCurrentServer();
const CUser user = this->getUserFromPilotGuiValues();
currentServer.setUser(user);
// FSD setup, then override
if (ui->comp_NetworkDetails->isFsdSetupOverrideEnabled())
{
const CFsdSetup fsd = ui->comp_NetworkDetails->getFsdSetup();
currentServer.setFsdSetup(fsd);
}
if (ui->comp_NetworkDetails->isVoiceSetupOverrideEnabled())
{
const CVoiceSetup voice = ui->comp_NetworkDetails->getVoiceSetup();
currentServer.setVoiceSetup(voice);
}
// update for own aircraft context
sGui->getIContextOwnAircraft()->updateOwnAircraftPilot(currentServer.getUser());
// set own aircraft from all values
ownAircraft = sGui->getIContextOwnAircraft()->getOwnAircraft();
// check the copilot stuff
CCallsign partnerCs;
if (ui->comp_NetworkDetails->hasPartnerCallsign())
{
partnerCs = ui->comp_NetworkDetails->getPartnerCallsign();
if (partnerCs == ownAircraft.getCallsign())
{
this->showOverlayHTMLMessage("Your callsign and the pilot/copilot callsign must be NOT the same", OverlayMessageMs);
return;
}
const bool ok = (partnerCs.asString().startsWith(ownAircraft.getCallsignAsString(), Qt::CaseInsensitive) || ownAircraft.getCallsignAsString().startsWith(partnerCs.asString(), Qt::CaseInsensitive));
if (!ok)
{
this->showOverlayHTMLMessage("Callsign and the pilot/copilot callsign appear not to be synchronized", OverlayMessageMs);
return;
}
}
// Login
if (sGui && sGui->getIContextAudio())
{
sGui->getIContextAudio()->setVoiceSetup(currentServer.getVoiceSetup());
}
msg = sGui->getIContextNetwork()->connectToNetwork(currentServer, values.ownLiverySend, values.useLivery, values.ownAircraftModelStringSend, values.useModelString, partnerCs, mode);
if (msg.isSuccess())
{
Q_ASSERT_X(currentServer.isValidForLogin(), Q_FUNC_INFO, "invalid server");
sGui->setExtraWindowTitle(QStringLiteral("[%1]").arg(ownAircraft.getCallsignAsString()));
CCrashHandler::instance()->crashAndLogInfoUserName(currentServer.getUser().getRealNameAndId());
CCrashHandler::instance()->crashAndLogInfoFlightNetwork(currentServer.getEcosystem().toQString(true));
CCrashHandler::instance()->crashAndLogAppendInfo(currentServer.getServerSessionId(false));
m_networkSetup.setLastServer(currentServer);
if (vatsimLogin) { m_networkSetup.setLastVatsimServer(currentServer); }
}
else
{
sGui->setExtraWindowTitle("");
}
}
else
{
// disconnect from network
sGui->getIContextAudio()->leaveAllVoiceRooms();
sGui->setExtraWindowTitle("");
msg = sGui->getIContextNetwork()->disconnectFromNetwork();
}
// log message and trigger events
msg.addCategories(this);
CLogMessage::preformatted(msg);
if (msg.isSuccess())
{
this->setGuiLoginAsValues(ownAircraft);
emit this->loginOrLogoffSuccessful();
}
else
{
emit this->loginOrLogoffCancelled();
}
}
void CLoginAdvComponent::resetState()
{
ui->comp_NetworkDetails->resetState();
}
void CLoginAdvComponent::loadRememberedUserData()
{
const CServer lastServer = m_networkSetup.getLastServer();
const CUser lastUser = lastServer.getUser();
ui->form_Pilot->setUser(lastUser);
ui->comp_OwnAircraft->setUser(lastUser);
}
void CLoginAdvComponent::overrideCredentialsToPilot(const CUser &user)
{
ui->form_Pilot->setUser(user, true);
}
void CLoginAdvComponent::onSimulatorStatusChanged(int status)
{
ISimulator::SimulatorStatus s = static_cast<ISimulator::SimulatorStatus>(status);
if (!this->hasValidContexts()) { return; }
if (sGui->getIContextNetwork()->isConnected())
{
if (!s.testFlag(ISimulator::Connected))
{
// sim NOT connected but network connected
this->autoLogoffDetection();
}
}
}
bool CLoginAdvComponent::hasValidContexts() const
{
if (!sGui || !sGui->supportsContexts()) { return false; }
if (sGui->isShuttingDown()) { return false; }
if (!sGui->getIContextSimulator()) { return false; }
if (!sGui->getIContextNetwork()) { return false; }
if (!sGui->getIContextOwnAircraft()) { return false; }
return true;
}
CUser CLoginAdvComponent::getUserFromPilotGuiValues() const
{
CUser user = ui->form_Pilot->getUser();
user.setCallsign(ui->comp_OwnAircraft->getCallsignFromGui());
return user;
}
void CLoginAdvComponent::setGuiLoginAsValues(const CSimulatedAircraft &ownAircraft)
{
const QString ac(
ownAircraft.getAircraftIcaoCodeDesignator() %
(ownAircraft.hasAirlineDesignator() ? (u' ' % ownAircraft.getAirlineIcaoCodeDesignator()) : QString()) %
(ownAircraft.hasModelString() ? (u' ' % ownAircraft.getModelString()) : QString())
);
}
CServer CLoginAdvComponent::getCurrentVatsimServer() const
{
return ui->comp_NetworkDetails->getCurrentVatsimServer();
}
CServer CLoginAdvComponent::getCurrentOtherServer() const
{
return ui->comp_NetworkDetails->getCurrentOtherServer();
}
CServer CLoginAdvComponent::getCurrentServer() const
{
return ui->comp_NetworkDetails->getCurrentServer();
}
void CLoginAdvComponent::autoLogoffDetection()
{
if (!ui->cb_AutoLogoff->isChecked()) { return; }
if (!this->hasValidContexts()) { return; }
if (!sGui->getIContextNetwork()->isConnected()) { return; } // nothing to logoff
const CStatusMessage m = CStatusMessage(this, CStatusMessage::SeverityInfo, u"Auto logoff in progress (could be simulator shutdown, crash, closing simulator)");
const int delaySecs = 30;
this->showOverlayHTMLMessage(m, qRound(1000 * delaySecs * 0.8));
emit this->requestLoginPage();
}
bool CLoginAdvComponent::updateOwnAircraftCallsignAndPilotFromGuiValues()
{
if (!this->hasValidContexts()) { return false; }
CSimulatedAircraft ownAircraft(sGui->getIContextOwnAircraft()->getOwnAircraft());
const CCallsign cs = ui->comp_OwnAircraft->getCallsignFromGui();
bool changedCallsign = false;
if (!cs.isEmpty() && ownAircraft.getCallsign() != cs)
{
sGui->getIContextOwnAircraft()->updateOwnCallsign(cs);
ownAircraft.setCallsign(cs); // also update
changedCallsign = true;
}
CUser pilot = ownAircraft.getPilot();
const CUser uiUser = ui->form_Pilot->getUser();
pilot.setRealName(uiUser.getRealName());
pilot.setHomeBase(uiUser.getHomeBase());
pilot.setId(uiUser.getId());
pilot.setCallsign(cs);
bool changedPilot = false;
if (ownAircraft.getPilot() != pilot)
{
// it can be that the callsign was changed and this results in unchanged here
changedPilot = sGui->getIContextOwnAircraft()->updateOwnAircraftPilot(pilot);
}
return changedCallsign || changedPilot;
}
void CLoginAdvComponent::updateGui()
{
if (!this->hasValidContexts()) { return; }
if (!sGui->getIContextNetwork()) { return; }
const IContextNetwork *nwc = sGui->getIContextNetwork();
const bool connected = nwc->isConnected();
if (!connected) { return; }
// in any case override if connected
ui->comp_OwnAircraft->setOwnModelAndIcaoValues();
const CServer server = nwc->getConnectedServer();
ui->comp_NetworkDetails->setLoginMode(nwc->getLoginMode());
const CSimulatedAircraft ownAircraft = sGui->getIContextOwnAircraft()->getOwnAircraft();
this->setGuiLoginAsValues(ownAircraft);
}
} // namespace
} // namespace