2013-10-21 23:42:52 +04: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
|
2016-10-25 12:00:07 +03:00
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
2013-10-21 23:42:52 +04:00
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef SERVERCONNECTION_H
|
|
|
|
#define SERVERCONNECTION_H
|
|
|
|
|
|
|
|
#include <QByteArray>
|
|
|
|
#include <QUrl>
|
|
|
|
#include <QNetworkCookie>
|
2013-10-23 16:48:44 +04:00
|
|
|
#include <QNetworkRequest>
|
2014-11-18 18:44:14 +03:00
|
|
|
#include <QSslSocket>
|
2013-10-23 16:48:44 +04:00
|
|
|
#include <QSslCertificate>
|
2014-01-21 04:45:02 +04:00
|
|
|
#include <QSslConfiguration>
|
2015-08-11 13:18:25 +03:00
|
|
|
#include <QSslCipher>
|
2013-10-24 02:29:08 +04:00
|
|
|
#include <QSslError>
|
2014-12-18 14:09:48 +03:00
|
|
|
#include <QSharedPointer>
|
2017-11-23 12:11:39 +03:00
|
|
|
|
|
|
|
#ifndef TOKEN_AUTH_ONLY
|
2017-01-22 15:55:08 +03:00
|
|
|
#include <QPixmap>
|
2017-11-23 12:11:39 +03:00
|
|
|
#endif
|
2017-01-22 15:55:08 +03:00
|
|
|
|
2017-08-16 09:36:52 +03:00
|
|
|
#include "common/utility.h"
|
2015-06-15 16:04:39 +03:00
|
|
|
#include <memory>
|
2015-07-16 22:49:12 +03:00
|
|
|
#include "capabilities.h"
|
2017-09-11 17:52:57 +03:00
|
|
|
#include "clientsideencryption.h"
|
2013-10-21 23:42:52 +04:00
|
|
|
|
|
|
|
class QSettings;
|
|
|
|
class QNetworkReply;
|
|
|
|
class QUrl;
|
2013-10-23 16:48:44 +04:00
|
|
|
class QNetworkAccessManager;
|
2013-10-21 23:42:52 +04:00
|
|
|
|
2019-07-24 14:56:21 +03:00
|
|
|
namespace QKeychain {
|
|
|
|
class Job;
|
|
|
|
class WritePasswordJob;
|
|
|
|
class ReadPasswordJob;
|
|
|
|
}
|
|
|
|
|
2014-11-10 00:34:07 +03:00
|
|
|
namespace OCC {
|
2013-10-21 23:42:52 +04:00
|
|
|
|
|
|
|
class AbstractCredentials;
|
|
|
|
class Account;
|
2014-12-18 14:09:48 +03:00
|
|
|
typedef QSharedPointer<Account> AccountPtr;
|
2014-11-10 00:30:29 +03:00
|
|
|
class AccessManager;
|
2017-09-08 17:43:59 +03:00
|
|
|
class SimpleNetworkJob;
|
2013-10-21 23:42:52 +04:00
|
|
|
|
2015-06-29 19:56:09 +03:00
|
|
|
/**
|
|
|
|
* @brief Reimplement this to handle SSL errors from libsync
|
|
|
|
* @ingroup libsync
|
2015-06-26 18:07:47 +03:00
|
|
|
*/
|
2013-10-24 02:29:08 +04:00
|
|
|
class AbstractSslErrorHandler
|
|
|
|
{
|
|
|
|
public:
|
2013-10-24 14:55:26 +04:00
|
|
|
virtual ~AbstractSslErrorHandler() {}
|
2015-04-06 22:46:03 +03:00
|
|
|
virtual bool handleErrors(QList<QSslError>, const QSslConfiguration &conf, QList<QSslCertificate> *, AccountPtr) = 0;
|
2013-10-24 02:29:08 +04:00
|
|
|
};
|
|
|
|
|
2015-06-29 19:56:09 +03:00
|
|
|
/**
|
|
|
|
* @brief The Account class represents an account on an ownCloud Server
|
|
|
|
* @ingroup libsync
|
2016-10-25 13:04:08 +03:00
|
|
|
*
|
|
|
|
* The Account has a name and url. It also has information about credentials,
|
|
|
|
* SSL errors and certificates.
|
2013-10-21 23:42:52 +04:00
|
|
|
*/
|
2014-04-25 01:45:20 +04:00
|
|
|
class OWNCLOUDSYNC_EXPORT Account : public QObject
|
|
|
|
{
|
2013-10-24 02:29:08 +04:00
|
|
|
Q_OBJECT
|
2013-10-21 23:42:52 +04:00
|
|
|
public:
|
2014-12-18 14:09:48 +03:00
|
|
|
static AccountPtr create();
|
2013-11-04 19:36:23 +04:00
|
|
|
~Account();
|
|
|
|
|
2014-12-18 14:09:48 +03:00
|
|
|
AccountPtr sharedFromThis();
|
|
|
|
|
2016-11-23 19:08:17 +03:00
|
|
|
/**
|
|
|
|
* The user that can be used in dav url.
|
|
|
|
*
|
|
|
|
* This can very well be different frome the login user that's
|
|
|
|
* stored in credentials()->user().
|
|
|
|
*/
|
|
|
|
QString davUser() const;
|
|
|
|
void setDavUser(const QString &newDavUser);
|
2016-08-02 14:48:56 +03:00
|
|
|
|
2017-10-05 22:08:38 +03:00
|
|
|
QString davDisplayName() const;
|
|
|
|
void setDavDisplayName(const QString &newDisplayName);
|
|
|
|
|
2017-11-23 12:11:39 +03:00
|
|
|
#ifndef TOKEN_AUTH_ONLY
|
2017-03-10 00:34:36 +03:00
|
|
|
QImage avatar() const;
|
|
|
|
void setAvatar(const QImage &img);
|
2017-11-23 12:11:39 +03:00
|
|
|
#endif
|
2017-01-22 15:55:08 +03:00
|
|
|
|
2015-04-23 15:51:06 +03:00
|
|
|
/// The name of the account as shown in the toolbar
|
|
|
|
QString displayName() const;
|
|
|
|
|
2015-04-23 15:57:36 +03:00
|
|
|
/// The internal id of the account.
|
|
|
|
QString id() const;
|
|
|
|
|
2013-10-21 23:42:52 +04:00
|
|
|
/** Server url of the account */
|
|
|
|
void setUrl(const QUrl &url);
|
2013-10-23 16:48:44 +04:00
|
|
|
QUrl url() const { return _url; }
|
|
|
|
|
2017-11-10 11:57:42 +03:00
|
|
|
/// Adjusts _userVisibleUrl once the host to use is discovered.
|
|
|
|
void setUserVisibleHost(const QString &host);
|
|
|
|
|
2016-10-25 13:04:08 +03:00
|
|
|
/**
|
|
|
|
* @brief The possibly themed dav path for the account. It has
|
|
|
|
* a trailing slash.
|
|
|
|
* @returns the (themeable) dav path for the account.
|
|
|
|
*/
|
|
|
|
QString davPath() const;
|
|
|
|
void setDavPath(const QString &s) { _davPath = s; }
|
|
|
|
void setNonShib(bool nonShib);
|
|
|
|
|
2013-10-21 23:42:52 +04:00
|
|
|
/** Returns webdav entry URL, based on url() */
|
|
|
|
QUrl davUrl() const;
|
|
|
|
|
2017-09-15 15:24:34 +03:00
|
|
|
/** Returns the legacy permalink url for a file.
|
|
|
|
*
|
|
|
|
* This uses the old way of manually building the url. New code should
|
|
|
|
* use the "privatelink" property accessible via PROPFIND.
|
|
|
|
*/
|
|
|
|
QUrl deprecatedPrivateLinkUrl(const QByteArray &numericFileId) const;
|
2017-05-10 10:37:10 +03:00
|
|
|
|
2016-10-25 13:04:08 +03:00
|
|
|
/** Holds the accounts credentials */
|
|
|
|
AbstractCredentials *credentials() const;
|
|
|
|
void setCredentials(AbstractCredentials *cred);
|
2014-06-12 18:51:47 +04:00
|
|
|
|
2017-09-08 17:43:59 +03:00
|
|
|
/** Create a network request on the account's QNAM.
|
|
|
|
*
|
|
|
|
* Network requests in AbstractNetworkJobs are created through
|
|
|
|
* this function. Other places should prefer to use jobs or
|
|
|
|
* sendRequest().
|
|
|
|
*/
|
|
|
|
QNetworkReply *sendRawRequest(const QByteArray &verb,
|
|
|
|
const QUrl &url,
|
|
|
|
QNetworkRequest req = QNetworkRequest(),
|
2018-11-12 20:46:39 +03:00
|
|
|
QIODevice *data = nullptr);
|
2013-10-21 23:42:52 +04:00
|
|
|
|
2017-09-08 17:43:59 +03:00
|
|
|
/** Create and start network job for a simple one-off request.
|
|
|
|
*
|
|
|
|
* More complicated requests typically create their own job types.
|
|
|
|
*/
|
|
|
|
SimpleNetworkJob *sendRequest(const QByteArray &verb,
|
2017-03-03 13:20:53 +03:00
|
|
|
const QUrl &url,
|
|
|
|
QNetworkRequest req = QNetworkRequest(),
|
2018-11-12 20:46:39 +03:00
|
|
|
QIODevice *data = nullptr);
|
2016-10-25 13:04:08 +03:00
|
|
|
|
2014-01-21 04:45:02 +04:00
|
|
|
/** The ssl configuration during the first connection */
|
2015-05-08 15:21:27 +03:00
|
|
|
QSslConfiguration getOrCreateSslConfig();
|
2014-01-21 04:45:02 +04:00
|
|
|
QSslConfiguration sslConfiguration() const { return _sslConfiguration; }
|
|
|
|
void setSslConfiguration(const QSslConfiguration &config);
|
2015-08-11 13:18:25 +03:00
|
|
|
// Because of bugs in Qt, we use this to store info needed for the SSL Button
|
|
|
|
QSslCipher _sessionCipher;
|
|
|
|
QByteArray _sessionTicket;
|
|
|
|
QList<QSslCertificate> _peerCertificateChain;
|
|
|
|
|
|
|
|
|
2013-10-23 16:48:44 +04:00
|
|
|
/** The certificates of the account */
|
2013-10-24 02:29:08 +04:00
|
|
|
QList<QSslCertificate> approvedCerts() const { return _approvedCerts; }
|
|
|
|
void setApprovedCerts(const QList<QSslCertificate> certs);
|
2013-11-07 15:04:45 +04:00
|
|
|
void addApprovedCerts(const QList<QSslCertificate> certs);
|
2013-10-21 23:42:52 +04:00
|
|
|
|
2015-05-08 11:17:21 +03:00
|
|
|
// Usually when a user explicitly rejects a certificate we don't
|
|
|
|
// ask again. After this call, a dialog will again be shown when
|
|
|
|
// the next unknown certificate is encountered.
|
2016-05-27 13:08:42 +03:00
|
|
|
void resetRejectedCertificates();
|
2015-05-08 11:17:21 +03:00
|
|
|
|
2013-11-04 19:36:23 +04:00
|
|
|
// pluggable handler
|
2013-10-24 02:29:08 +04:00
|
|
|
void setSslErrorHandler(AbstractSslErrorHandler *handler);
|
2013-10-23 16:48:44 +04:00
|
|
|
|
2016-10-25 13:04:08 +03:00
|
|
|
// To be called by credentials only, for storing username and the like
|
2013-11-04 19:36:23 +04:00
|
|
|
QVariant credentialSetting(const QString &key) const;
|
|
|
|
void setCredentialSetting(const QString &key, const QVariant &value);
|
|
|
|
|
2016-10-25 13:04:08 +03:00
|
|
|
/** Assign a client certificate */
|
2015-01-23 22:08:14 +03:00
|
|
|
void setCertificate(const QByteArray certficate = QByteArray(), const QString privateKey = QString());
|
2015-02-12 14:59:00 +03:00
|
|
|
|
2016-10-25 13:04:08 +03:00
|
|
|
/** Access the server capabilities */
|
2015-07-29 13:05:00 +03:00
|
|
|
const Capabilities &capabilities() const;
|
2016-10-25 13:04:08 +03:00
|
|
|
void setCapabilities(const QVariantMap &caps);
|
|
|
|
|
2017-04-19 12:02:03 +03:00
|
|
|
/** Access the server version
|
|
|
|
*
|
|
|
|
* For servers >= 10.0.0, this can be the empty string until capabilities
|
|
|
|
* have been received.
|
|
|
|
*/
|
2016-03-02 13:59:36 +03:00
|
|
|
QString serverVersion() const;
|
2017-04-19 12:02:03 +03:00
|
|
|
|
|
|
|
/** Server version for easy comparison.
|
|
|
|
*
|
|
|
|
* Example: serverVersionInt() >= makeServerVersion(11, 2, 3)
|
|
|
|
*
|
|
|
|
* Will be 0 if the version is not available yet.
|
|
|
|
*/
|
2016-03-02 13:59:36 +03:00
|
|
|
int serverVersionInt() const;
|
2017-04-19 12:02:03 +03:00
|
|
|
|
2017-03-14 17:57:57 +03:00
|
|
|
static int makeServerVersion(int majorVersion, int minorVersion, int patchVersion);
|
2016-10-25 13:04:08 +03:00
|
|
|
void setServerVersion(const QString &version);
|
2016-03-02 13:59:36 +03:00
|
|
|
|
|
|
|
/** Whether the server is too old.
|
|
|
|
*
|
|
|
|
* Not supporting server versions is a gradual process. There's a hard
|
|
|
|
* compatibility limit (see ConnectionValidator) that forbids connecting
|
|
|
|
* to extremely old servers. And there's a weak "untested, not
|
|
|
|
* recommended, potentially dangerous" limit, that users might want
|
|
|
|
* to go beyond.
|
|
|
|
*
|
|
|
|
* This function returns true if the server is beyond the weak limit.
|
|
|
|
*/
|
|
|
|
bool serverVersionUnsupported() const;
|
2015-10-16 12:52:27 +03:00
|
|
|
|
|
|
|
// Fixed from 8.1 https://github.com/owncloud/client/issues/3730
|
2016-10-25 13:04:08 +03:00
|
|
|
/** Detects a specific bug in older server versions */
|
2015-10-16 12:52:27 +03:00
|
|
|
bool rootEtagChangesNotOnlySubFolderEtags();
|
2015-02-05 17:18:38 +03:00
|
|
|
|
2018-03-26 23:49:54 +03:00
|
|
|
/** True when the server connection is using HTTP2 */
|
2017-05-22 15:41:06 +03:00
|
|
|
bool isHttp2Supported() { return _http2Supported; }
|
2017-10-05 22:08:38 +03:00
|
|
|
void setHttp2Supported(bool value) { _http2Supported = value; }
|
2017-05-22 15:41:06 +03:00
|
|
|
|
2014-03-03 19:36:30 +04:00
|
|
|
void clearCookieJar();
|
2015-06-18 21:41:00 +03:00
|
|
|
void lendCookieJarTo(QNetworkAccessManager *guest);
|
2017-01-26 12:54:03 +03:00
|
|
|
QString cookieJarPath();
|
2014-03-03 19:36:30 +04:00
|
|
|
|
2015-03-19 13:40:47 +03:00
|
|
|
void resetNetworkAccessManager();
|
2014-05-14 13:11:45 +04:00
|
|
|
QNetworkAccessManager *networkAccessManager();
|
2017-04-20 10:21:33 +03:00
|
|
|
QSharedPointer<QNetworkAccessManager> sharedNetworkAccessManager();
|
2014-05-14 13:11:45 +04:00
|
|
|
|
2016-10-25 13:04:08 +03:00
|
|
|
/// Called by network jobs on credential errors, emits invalidCredentials()
|
2014-12-11 17:43:48 +03:00
|
|
|
void handleInvalidCredentials();
|
|
|
|
|
2017-12-20 17:35:23 +03:00
|
|
|
ClientSideEncryption* e2e();
|
2017-11-13 19:22:09 +03:00
|
|
|
|
2019-07-24 14:56:21 +03:00
|
|
|
/// Used in RemoteWipe
|
|
|
|
void retrieveAppPassword();
|
2019-11-29 06:28:50 +03:00
|
|
|
void writeAppPasswordOnce(QString appPassword);
|
2019-07-24 14:56:21 +03:00
|
|
|
void deleteAppPassword();
|
|
|
|
|
2020-01-18 17:07:51 +03:00
|
|
|
/// Direct Editing
|
|
|
|
// Check for the directEditing capability
|
|
|
|
void fetchDirectEditors(const QUrl &directEditingURL, const QString &directEditingETag);
|
|
|
|
|
2017-07-06 14:43:34 +03:00
|
|
|
public slots:
|
|
|
|
/// Used when forgetting credentials
|
|
|
|
void clearQNAMCache();
|
2017-09-20 12:48:13 +03:00
|
|
|
void slotHandleSslErrors(QNetworkReply *, QList<QSslError>);
|
2017-07-06 14:43:34 +03:00
|
|
|
|
2013-11-07 15:22:17 +04:00
|
|
|
signals:
|
2016-10-25 13:04:08 +03:00
|
|
|
/// Emitted whenever there's network activity
|
2014-09-18 16:00:51 +04:00
|
|
|
void propagatorNetworkActivity();
|
2016-10-25 13:04:08 +03:00
|
|
|
|
|
|
|
/// Triggered by handleInvalidCredentials()
|
2014-12-17 16:09:57 +03:00
|
|
|
void invalidCredentials();
|
2016-10-25 13:04:08 +03:00
|
|
|
|
2014-12-17 16:09:57 +03:00
|
|
|
void credentialsFetched(AbstractCredentials *credentials);
|
2015-09-05 16:39:22 +03:00
|
|
|
void credentialsAsked(AbstractCredentials *credentials);
|
2013-11-07 15:22:17 +04:00
|
|
|
|
2015-07-16 15:21:51 +03:00
|
|
|
/// Forwards from QNetworkAccessManager::proxyAuthenticationRequired().
|
|
|
|
void proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *);
|
|
|
|
|
2015-08-14 12:31:01 +03:00
|
|
|
// e.g. when the approved SSL certificates changed
|
2016-03-01 18:08:23 +03:00
|
|
|
void wantsAccountSaved(Account *acc);
|
2015-08-14 12:31:01 +03:00
|
|
|
|
2016-03-02 13:59:36 +03:00
|
|
|
void serverVersionChanged(Account *account, const QString &newVersion, const QString &oldVersion);
|
|
|
|
|
2017-01-22 15:55:08 +03:00
|
|
|
void accountChangedAvatar();
|
2017-10-05 22:08:38 +03:00
|
|
|
void accountChangedDisplayName();
|
2017-01-22 15:55:08 +03:00
|
|
|
|
2019-07-24 14:56:21 +03:00
|
|
|
/// Used in RemoteWipe
|
|
|
|
void appPasswordRetrieved(QString);
|
|
|
|
|
2013-11-05 21:15:47 +04:00
|
|
|
protected Q_SLOTS:
|
2014-12-11 17:43:48 +03:00
|
|
|
void slotCredentialsFetched();
|
2015-09-05 16:39:22 +03:00
|
|
|
void slotCredentialsAsked();
|
2020-01-18 17:07:51 +03:00
|
|
|
void slotDirectEditingRecieved(const QJsonDocument &json);
|
2013-10-24 02:29:08 +04:00
|
|
|
|
2013-10-21 23:42:52 +04:00
|
|
|
private:
|
2018-11-12 20:46:39 +03:00
|
|
|
Account(QObject *parent = nullptr);
|
2016-10-25 13:04:08 +03:00
|
|
|
void setSharedThis(AccountPtr sharedThis);
|
2014-12-18 14:09:48 +03:00
|
|
|
|
|
|
|
QWeakPointer<Account> _sharedThis;
|
2015-04-23 15:57:36 +03:00
|
|
|
QString _id;
|
2016-11-23 19:08:17 +03:00
|
|
|
QString _davUser;
|
2017-10-05 22:08:38 +03:00
|
|
|
QString _displayName;
|
2017-11-23 12:11:39 +03:00
|
|
|
#ifndef TOKEN_AUTH_ONLY
|
2017-03-10 00:34:36 +03:00
|
|
|
QImage _avatarImg;
|
2017-11-23 12:11:39 +03:00
|
|
|
#endif
|
2013-11-04 19:36:23 +04:00
|
|
|
QMap<QString, QVariant> _settingsMap;
|
2013-10-21 23:42:52 +04:00
|
|
|
QUrl _url;
|
2017-11-10 11:57:42 +03:00
|
|
|
|
|
|
|
/** If url to use for any user-visible urls.
|
|
|
|
*
|
|
|
|
* If the server configures overwritehost this can be different from
|
|
|
|
* the connection url in _url. We retrieve the visible host through
|
|
|
|
* the ocs/v1.php/config endpoint in ConnectionValidator.
|
|
|
|
*/
|
|
|
|
QUrl _userVisibleUrl;
|
|
|
|
|
2013-10-24 02:29:08 +04:00
|
|
|
QList<QSslCertificate> _approvedCerts;
|
2014-01-21 04:45:02 +04:00
|
|
|
QSslConfiguration _sslConfiguration;
|
2015-07-16 22:49:12 +03:00
|
|
|
Capabilities _capabilities;
|
2015-02-12 14:59:00 +03:00
|
|
|
QString _serverVersion;
|
2013-10-24 14:55:26 +04:00
|
|
|
QScopedPointer<AbstractSslErrorHandler> _sslErrorHandler;
|
2016-06-15 18:57:28 +03:00
|
|
|
QSharedPointer<QNetworkAccessManager> _am;
|
2017-07-07 12:09:11 +03:00
|
|
|
QScopedPointer<AbstractCredentials> _credentials;
|
2017-05-22 15:41:06 +03:00
|
|
|
bool _http2Supported = false;
|
2016-05-27 13:08:42 +03:00
|
|
|
|
|
|
|
/// Certificates that were explicitly rejected by the user
|
|
|
|
QList<QSslCertificate> _rejectedCertificates;
|
|
|
|
|
2013-11-14 18:48:46 +04:00
|
|
|
static QString _configFileName;
|
2017-01-02 10:34:02 +03:00
|
|
|
|
2015-02-18 19:49:07 +03:00
|
|
|
QString _davPath; // defaults to value from theme, might be overwritten in brandings
|
2017-11-13 19:22:09 +03:00
|
|
|
ClientSideEncryption _e2e;
|
|
|
|
|
2019-11-29 06:28:50 +03:00
|
|
|
/// Used in RemoteWipe
|
|
|
|
bool _wroteAppPassword = false;
|
|
|
|
|
2015-04-09 17:19:17 +03:00
|
|
|
friend class AccountManager;
|
2019-12-08 02:00:02 +03:00
|
|
|
|
2020-01-18 17:07:51 +03:00
|
|
|
// Direct Editing
|
|
|
|
QString _lastDirectEditingETag;
|
|
|
|
|
2019-12-08 02:00:02 +03:00
|
|
|
/* IMPORTANT - remove later - FIXME MS@2019-12-07 -->
|
|
|
|
* TODO: For "Log out" & "Remove account": Remove client CA certs and KEY!
|
|
|
|
*
|
|
|
|
* Disabled as long as selecting another cert is not supported by the UI.
|
|
|
|
*
|
|
|
|
* Being able to specify a new certificate is important anyway: expiry etc.
|
|
|
|
*
|
|
|
|
* We introduce this dirty hack here, to allow deleting them upon Remote Wipe.
|
|
|
|
*/
|
|
|
|
public:
|
|
|
|
void setRemoteWipeRequested_HACK() { _isRemoteWipeRequested_HACK = true; }
|
|
|
|
bool isRemoteWipeRequested_HACK() { return _isRemoteWipeRequested_HACK; }
|
|
|
|
private:
|
|
|
|
bool _isRemoteWipeRequested_HACK = false;
|
|
|
|
// <-- FIXME MS@2019-12-07
|
2013-10-21 23:42:52 +04:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2014-12-18 14:09:48 +03:00
|
|
|
Q_DECLARE_METATYPE(OCC::AccountPtr)
|
2014-02-06 15:56:34 +04:00
|
|
|
|
2013-10-21 23:42:52 +04:00
|
|
|
#endif //SERVERCONNECTION_H
|