2014-12-17 16:09:57 +03:00
|
|
|
/*
|
|
|
|
* Copyright (C) by Daniel Molkentin <danimo@owncloud.com>
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; version 2 of the License.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful, but
|
|
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
|
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
|
|
* for more details.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "accountstate.h"
|
2015-04-09 17:19:17 +03:00
|
|
|
#include "accountmanager.h"
|
2014-12-17 16:09:57 +03:00
|
|
|
#include "account.h"
|
|
|
|
#include "creds/abstractcredentials.h"
|
2015-09-05 16:39:22 +03:00
|
|
|
#include "logger.h"
|
2015-10-20 10:25:42 +03:00
|
|
|
#include "configfile.h"
|
2014-12-17 16:09:57 +03:00
|
|
|
|
|
|
|
#include <QDebug>
|
2015-06-15 16:04:39 +03:00
|
|
|
#include <QSettings>
|
2015-08-30 16:20:35 +03:00
|
|
|
#include <qfontmetrics.h>
|
2014-12-17 16:09:57 +03:00
|
|
|
|
|
|
|
namespace OCC {
|
|
|
|
|
2014-12-18 14:09:48 +03:00
|
|
|
AccountState::AccountState(AccountPtr account)
|
2015-04-23 16:59:32 +03:00
|
|
|
: QObject()
|
2014-12-17 16:09:57 +03:00
|
|
|
, _account(account)
|
|
|
|
, _state(AccountState::Disconnected)
|
|
|
|
, _connectionStatus(ConnectionValidator::Undefined)
|
|
|
|
, _waitingForNewCredentials(false)
|
|
|
|
{
|
|
|
|
qRegisterMetaType<AccountState*>("AccountState*");
|
|
|
|
|
2014-12-18 14:09:48 +03:00
|
|
|
connect(account.data(), SIGNAL(invalidCredentials()),
|
2014-12-17 16:09:57 +03:00
|
|
|
SLOT(slotInvalidCredentials()));
|
2014-12-18 14:09:48 +03:00
|
|
|
connect(account.data(), SIGNAL(credentialsFetched(AbstractCredentials*)),
|
2014-12-17 16:09:57 +03:00
|
|
|
SLOT(slotCredentialsFetched(AbstractCredentials*)));
|
2015-09-05 16:39:22 +03:00
|
|
|
connect(account.data(), SIGNAL(credentialsAsked(AbstractCredentials*)),
|
|
|
|
SLOT(slotCredentialsAsked(AbstractCredentials*)));
|
2015-10-19 12:50:26 +03:00
|
|
|
_timeSinceLastETagCheck.invalidate();
|
2014-12-17 16:09:57 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
AccountState::~AccountState()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2016-03-01 18:08:23 +03:00
|
|
|
AccountState *AccountState::loadFromSettings(AccountPtr account, QSettings& /*settings*/)
|
|
|
|
{
|
|
|
|
auto accountState = new AccountState(account);
|
|
|
|
return accountState;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AccountState::writeToSettings(QSettings& /*settings*/)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2014-12-18 14:09:48 +03:00
|
|
|
AccountPtr AccountState::account() const
|
2014-12-17 16:09:57 +03:00
|
|
|
{
|
2015-04-17 18:56:17 +03:00
|
|
|
return _account;
|
2014-12-17 16:09:57 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
AccountState::ConnectionStatus AccountState::connectionStatus() const
|
|
|
|
{
|
|
|
|
return _connectionStatus;
|
|
|
|
}
|
|
|
|
|
|
|
|
QStringList AccountState::connectionErrors() const
|
|
|
|
{
|
|
|
|
return _connectionErrors;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString AccountState::connectionStatusString(ConnectionStatus status)
|
|
|
|
{
|
|
|
|
return ConnectionValidator::statusString(status);
|
|
|
|
}
|
|
|
|
|
|
|
|
AccountState::State AccountState::state() const
|
|
|
|
{
|
|
|
|
return _state;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AccountState::setState(State state)
|
|
|
|
{
|
|
|
|
if (_state != state) {
|
|
|
|
qDebug() << "AccountState state change: "
|
|
|
|
<< stateString(_state) << "->" << stateString(state);
|
|
|
|
State oldState = _state;
|
|
|
|
_state = state;
|
|
|
|
|
|
|
|
if (_state == SignedOut) {
|
|
|
|
_connectionStatus = ConnectionValidator::Undefined;
|
|
|
|
_connectionErrors.clear();
|
|
|
|
} else if (oldState == SignedOut && _state == Disconnected) {
|
2016-01-21 15:33:03 +03:00
|
|
|
checkConnectivity();
|
2014-12-17 16:09:57 +03:00
|
|
|
}
|
2016-04-28 23:43:53 +03:00
|
|
|
if (oldState == Connected || _state == Connected) {
|
|
|
|
emit isConnectedChanged();
|
|
|
|
}
|
2014-12-17 16:09:57 +03:00
|
|
|
}
|
2015-05-15 13:26:23 +03:00
|
|
|
|
|
|
|
// might not have changed but the underlying _connectionErrors might have
|
|
|
|
emit stateChanged(_state);
|
2014-12-17 16:09:57 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
QString AccountState::stateString(State state)
|
|
|
|
{
|
|
|
|
switch (state)
|
|
|
|
{
|
|
|
|
case SignedOut:
|
2015-07-01 13:30:18 +03:00
|
|
|
return tr("Signed out");
|
2014-12-17 16:09:57 +03:00
|
|
|
case Disconnected:
|
2015-07-01 13:30:18 +03:00
|
|
|
return tr("Disconnected");
|
2014-12-17 16:09:57 +03:00
|
|
|
case Connected:
|
2015-07-01 13:30:18 +03:00
|
|
|
return tr("Connected");
|
2015-04-24 12:32:47 +03:00
|
|
|
case ServiceUnavailable:
|
2015-07-01 13:30:18 +03:00
|
|
|
return tr("Service unavailable");
|
2014-12-17 16:09:57 +03:00
|
|
|
case NetworkError:
|
2015-07-01 13:30:18 +03:00
|
|
|
return tr("Network error");
|
2014-12-17 16:09:57 +03:00
|
|
|
case ConfigurationError:
|
2015-07-01 13:30:18 +03:00
|
|
|
return tr("Configuration error");
|
2014-12-17 16:09:57 +03:00
|
|
|
}
|
2015-07-01 13:30:18 +03:00
|
|
|
return tr("Unknown account state");
|
2014-12-17 16:09:57 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
bool AccountState::isSignedOut() const
|
|
|
|
{
|
|
|
|
return _state == SignedOut;
|
|
|
|
}
|
|
|
|
|
2015-12-09 13:06:28 +03:00
|
|
|
void AccountState::signOutByUi()
|
2014-12-17 16:09:57 +03:00
|
|
|
{
|
2015-12-09 13:06:28 +03:00
|
|
|
account()->credentials()->forgetSensitiveData();
|
|
|
|
setState(SignedOut);
|
|
|
|
}
|
|
|
|
|
|
|
|
void AccountState::signIn()
|
|
|
|
{
|
|
|
|
if (_state == SignedOut) {
|
2014-12-17 16:09:57 +03:00
|
|
|
setState(Disconnected);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AccountState::isConnected() const
|
|
|
|
{
|
|
|
|
return _state == Connected;
|
|
|
|
}
|
|
|
|
|
2015-04-24 12:32:47 +03:00
|
|
|
bool AccountState::isConnectedOrTemporarilyUnavailable() const
|
2015-02-25 11:49:39 +03:00
|
|
|
{
|
2015-04-24 12:32:47 +03:00
|
|
|
return isConnected() || _state == ServiceUnavailable;
|
2015-02-25 11:49:39 +03:00
|
|
|
}
|
|
|
|
|
2015-10-19 12:50:26 +03:00
|
|
|
void AccountState::tagLastSuccessfullETagRequest()
|
|
|
|
{
|
|
|
|
_timeSinceLastETagCheck.restart();
|
|
|
|
}
|
|
|
|
|
2016-01-21 15:33:03 +03:00
|
|
|
void AccountState::checkConnectivity()
|
2014-12-17 16:09:57 +03:00
|
|
|
{
|
|
|
|
if (isSignedOut() || _waitingForNewCredentials) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-05-15 13:26:23 +03:00
|
|
|
if (_connectionValidator) {
|
2015-11-17 13:02:15 +03:00
|
|
|
qDebug() << "ConnectionValidator already running, ignoring" << account()->displayName();
|
2015-05-15 13:26:23 +03:00
|
|
|
return;
|
|
|
|
}
|
2015-10-19 12:50:26 +03:00
|
|
|
|
|
|
|
// IF the account is connected the connection check can be skipped
|
|
|
|
// if the last successful etag check job is not so long ago.
|
2015-10-20 10:25:42 +03:00
|
|
|
ConfigFile cfg;
|
|
|
|
int polltime = cfg.remotePollInterval();
|
|
|
|
|
2015-10-19 12:50:26 +03:00
|
|
|
if (isConnected() && _timeSinceLastETagCheck.isValid()
|
2015-10-20 10:25:42 +03:00
|
|
|
&& _timeSinceLastETagCheck.elapsed() < polltime) {
|
2015-11-18 14:13:03 +03:00
|
|
|
//qDebug() << account()->displayName() << "The last ETag check succeeded within the last " << polltime/1000 << " secs. No connection check needed!";
|
2015-10-19 12:50:26 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-09-05 16:39:22 +03:00
|
|
|
ConnectionValidator * conValidator = new ConnectionValidator(account());
|
2015-05-15 13:26:23 +03:00
|
|
|
_connectionValidator = conValidator;
|
2014-12-17 16:09:57 +03:00
|
|
|
connect(conValidator, SIGNAL(connectionResult(ConnectionValidator::Status,QStringList)),
|
|
|
|
SLOT(slotConnectionValidatorResult(ConnectionValidator::Status,QStringList)));
|
|
|
|
if (isConnected()) {
|
|
|
|
// Use a small authed propfind as a minimal ping when we're
|
|
|
|
// already connected.
|
|
|
|
conValidator->checkAuthentication();
|
|
|
|
} else {
|
|
|
|
// Check the server and then the auth.
|
2015-03-19 13:40:47 +03:00
|
|
|
|
2016-05-31 11:20:29 +03:00
|
|
|
// Let's try this for all OS and see if it fixes the Qt issues we have on Linux #4720 #3888 #4051
|
|
|
|
//#ifdef Q_OS_WIN
|
2015-03-19 13:40:47 +03:00
|
|
|
// There seems to be a bug in Qt on Windows where QNAM sometimes stops
|
|
|
|
// working correctly after the computer woke up from sleep. See #2895 #2899
|
|
|
|
// and #2973.
|
|
|
|
// As an attempted workaround, reset the QNAM regularly if the account is
|
|
|
|
// disconnected.
|
|
|
|
account()->resetNetworkAccessManager();
|
2015-07-02 12:28:40 +03:00
|
|
|
|
|
|
|
// If we don't reset the ssl config a second CheckServerJob can produce a
|
|
|
|
// ssl config that does not have a sensible certificate chain.
|
|
|
|
account()->setSslConfiguration(QSslConfiguration());
|
2016-05-31 11:20:29 +03:00
|
|
|
//#endif
|
2014-12-17 16:09:57 +03:00
|
|
|
conValidator->checkServerAndAuth();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void AccountState::slotConnectionValidatorResult(ConnectionValidator::Status status, const QStringList& errors)
|
|
|
|
{
|
|
|
|
if (isSignedOut()) {
|
2016-05-30 19:15:41 +03:00
|
|
|
qDebug() << "Signed out, ignoring" << connectionStatusString(status) << _account->url().toString();
|
2014-12-17 16:09:57 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_connectionStatus != status) {
|
|
|
|
qDebug() << "AccountState connection status change: "
|
|
|
|
<< connectionStatusString(_connectionStatus) << "->"
|
|
|
|
<< connectionStatusString(status);
|
|
|
|
_connectionStatus = status;
|
|
|
|
}
|
|
|
|
_connectionErrors = errors;
|
|
|
|
|
|
|
|
switch (status)
|
|
|
|
{
|
|
|
|
case ConnectionValidator::Connected:
|
2015-07-07 15:44:16 +03:00
|
|
|
if (_state != Connected) {
|
2015-06-08 13:14:37 +03:00
|
|
|
setState(Connected);
|
|
|
|
}
|
2014-12-17 16:09:57 +03:00
|
|
|
break;
|
|
|
|
case ConnectionValidator::Undefined:
|
|
|
|
case ConnectionValidator::NotConfigured:
|
|
|
|
setState(Disconnected);
|
|
|
|
break;
|
|
|
|
case ConnectionValidator::ServerVersionMismatch:
|
|
|
|
setState(ConfigurationError);
|
|
|
|
break;
|
2015-02-11 11:23:04 +03:00
|
|
|
case ConnectionValidator::StatusNotFound:
|
|
|
|
// This can happen either because the server does not exist
|
|
|
|
// or because we are having network issues. The latter one is
|
|
|
|
// much more likely, so keep trying to connect.
|
|
|
|
setState(NetworkError);
|
|
|
|
break;
|
2015-09-05 16:37:20 +03:00
|
|
|
case ConnectionValidator::CredentialsMissingOrWrong:
|
|
|
|
slotInvalidCredentials();
|
2014-12-17 16:09:57 +03:00
|
|
|
break;
|
2015-01-21 17:30:25 +03:00
|
|
|
case ConnectionValidator::UserCanceledCredentials:
|
|
|
|
setState(SignedOut);
|
|
|
|
break;
|
2015-04-24 12:32:47 +03:00
|
|
|
case ConnectionValidator::ServiceUnavailable:
|
|
|
|
setState(ServiceUnavailable);
|
2015-02-25 11:49:39 +03:00
|
|
|
break;
|
2014-12-17 16:09:57 +03:00
|
|
|
case ConnectionValidator::Timeout:
|
|
|
|
setState(NetworkError);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void AccountState::slotInvalidCredentials()
|
|
|
|
{
|
2015-09-05 16:37:20 +03:00
|
|
|
if (isSignedOut() || _waitingForNewCredentials)
|
2014-12-17 16:09:57 +03:00
|
|
|
return;
|
2015-09-05 16:37:20 +03:00
|
|
|
|
|
|
|
if (account()->credentials()->ready())
|
|
|
|
account()->credentials()->invalidateToken();
|
|
|
|
account()->credentials()->fetchFromKeychain();
|
2014-12-17 16:09:57 +03:00
|
|
|
|
|
|
|
setState(ConfigurationError);
|
|
|
|
_waitingForNewCredentials = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AccountState::slotCredentialsFetched(AbstractCredentials* credentials)
|
2015-09-05 16:39:22 +03:00
|
|
|
{
|
|
|
|
if (!credentials->ready()) {
|
|
|
|
// No exiting credentials found in the keychain
|
2016-01-21 15:33:03 +03:00
|
|
|
credentials->askFromUser();
|
2015-09-05 16:39:22 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
_waitingForNewCredentials = false;
|
|
|
|
|
|
|
|
// When new credentials become available we always want to restart the
|
|
|
|
// connection validation, even if it's currently running.
|
|
|
|
delete _connectionValidator;
|
|
|
|
|
2016-01-21 15:33:03 +03:00
|
|
|
checkConnectivity();
|
2015-09-05 16:39:22 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void AccountState::slotCredentialsAsked(AbstractCredentials* credentials)
|
2014-12-17 16:09:57 +03:00
|
|
|
{
|
|
|
|
_waitingForNewCredentials = false;
|
|
|
|
|
|
|
|
if (!credentials->ready()) {
|
|
|
|
// User canceled the connection or did not give a password
|
|
|
|
setState(SignedOut);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-05-22 10:38:44 +03:00
|
|
|
// When new credentials become available we always want to restart the
|
|
|
|
// connection validation, even if it's currently running.
|
2015-09-05 16:39:22 +03:00
|
|
|
delete _connectionValidator;
|
2015-05-22 10:38:44 +03:00
|
|
|
|
2016-01-21 15:33:03 +03:00
|
|
|
checkConnectivity();
|
2014-12-17 16:09:57 +03:00
|
|
|
}
|
|
|
|
|
2015-07-02 14:31:42 +03:00
|
|
|
std::unique_ptr<QSettings> AccountState::settings()
|
2015-06-15 16:04:39 +03:00
|
|
|
{
|
|
|
|
auto s = _account->settingsWithGroup(QLatin1String("Accounts"));
|
|
|
|
s->beginGroup(_account->id());
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
2015-08-30 16:20:35 +03:00
|
|
|
QString AccountState::shortDisplayNameForSettings(int width) const
|
2015-08-05 15:49:16 +03:00
|
|
|
{
|
2015-08-30 16:20:35 +03:00
|
|
|
QString user = account()->credentials()->user();
|
|
|
|
QString host = account()->url().host();
|
2015-09-10 11:17:16 +03:00
|
|
|
int port = account()->url().port();
|
|
|
|
if (port > 0 && port != 80 && port != 443) {
|
|
|
|
host.append(QLatin1Char(':'));
|
|
|
|
host.append(QString::number(port));
|
|
|
|
}
|
2015-08-30 16:20:35 +03:00
|
|
|
if (width > 0) {
|
|
|
|
QFont f;
|
|
|
|
QFontMetrics fm(f);
|
2015-09-10 11:17:16 +03:00
|
|
|
host = fm.elidedText(host, Qt::ElideMiddle, width);
|
2015-08-30 16:20:35 +03:00
|
|
|
user = fm.elidedText(user, Qt::ElideRight, width);
|
2015-08-05 15:49:16 +03:00
|
|
|
}
|
2015-08-30 16:20:35 +03:00
|
|
|
return user + QLatin1String("\n") + host;
|
2015-08-05 15:49:16 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-04-17 18:56:17 +03:00
|
|
|
|
2014-12-17 16:09:57 +03:00
|
|
|
} // namespace OCC
|