1 /* 2 * Copyright (C) by Daniel Molkentin <danimo@owncloud.com> 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, but 10 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 11 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * for more details. 13 */ 14 15 16 #ifndef ACCOUNTINFO_H 17 #define ACCOUNTINFO_H 18 19 #include <QByteArray> 20 #include <QElapsedTimer> 21 #include <QPointer> 22 #include "connectionvalidator.h" 23 #include "creds/abstractcredentials.h" 24 25 #include <memory> 26 27 class QSettings; 28 29 namespace OCC { 30 31 class AccountState; 32 class Account; 33 class AccountApp; 34 class RemoteWipe; 35 36 using AccountStatePtr = QExplicitlySharedDataPointer<AccountState>; 37 using AccountAppList = QList<AccountApp *>; 38 39 /** 40 * @brief Extra info about an ownCloud server account. 41 * @ingroup gui 42 */ 43 class AccountState : public QObject, public QSharedData 44 { 45 Q_OBJECT 46 Q_PROPERTY(AccountPtr account MEMBER _account) 47 48 public: 49 enum State { 50 /// Not even attempting to connect, most likely because the 51 /// user explicitly signed out or cancelled a credential dialog. 52 SignedOut, 53 54 /// Account would like to be connected but hasn't heard back yet. 55 Disconnected, 56 57 /// The account is successfully talking to the server. 58 Connected, 59 60 /// There's a temporary problem with talking to the server, 61 /// don't bother the user too much and try again. 62 ServiceUnavailable, 63 64 /// Similar to ServiceUnavailable, but we know the server is down 65 /// for maintenance 66 MaintenanceMode, 67 68 /// Could not communicate with the server for some reason. 69 /// We assume this may resolve itself over time and will try 70 /// again automatically. 71 NetworkError, 72 73 /// Server configuration error. (For example: unsupported version) 74 ConfigurationError, 75 76 /// We are currently asking the user for credentials 77 AskingCredentials 78 }; 79 80 /// The actual current connectivity status. 81 using ConnectionStatus = ConnectionValidator::Status; 82 83 /// Use the account as parent 84 explicit AccountState(AccountPtr account); 85 ~AccountState() override; 86 87 /** Creates an account state from settings and an Account object. 88 * 89 * Use from AccountManager with a prepared QSettings object only. 90 */ 91 static AccountState *loadFromSettings(AccountPtr account, QSettings &settings); 92 93 /** Writes account state information to settings. 94 * 95 * It does not write the Account data. 96 */ 97 void writeToSettings(QSettings &settings); 98 99 AccountPtr account() const; 100 101 ConnectionStatus connectionStatus() const; 102 QStringList connectionErrors() const; 103 104 State state() const; 105 static QString stateString(State state); 106 107 bool isSignedOut() const; 108 109 AccountAppList appList() const; 110 AccountApp* findApp(const QString &appId) const; 111 112 /** A user-triggered sign out which disconnects, stops syncs 113 * for the account and forgets the password. */ 114 void signOutByUi(); 115 116 /** Tries to connect from scratch. 117 * 118 * Does nothing for signed out accounts. 119 * Connected accounts will be disconnected and try anew. 120 * Disconnected accounts will go to checkConnectivity(). 121 * 122 * Useful for when network settings (proxy) change. 123 */ 124 void freshConnectionAttempt(); 125 126 /// Move from SignedOut state to Disconnected (attempting to connect) 127 void signIn(); 128 129 bool isConnected() const; 130 131 /** Returns a new settings object for this account, already in the right groups. */ 132 std::unique_ptr<QSettings> settings(); 133 134 /** Mark the timestamp when the last successful ETag check happened for 135 * this account. 136 * The checkConnectivity() method uses the timestamp to save a call to 137 * the server to validate the connection if the last successful etag job 138 * was not so long ago. 139 */ 140 void tagLastSuccessfullETagRequest(const QDateTime &tp); 141 142 /** Saves the ETag Response header from the last Notifications api 143 * request with statusCode 200. 144 */ 145 QByteArray notificationsEtagResponseHeader() const; 146 147 /** Returns the ETag Response header from the last Notifications api 148 * request with statusCode 200. 149 */ 150 void setNotificationsEtagResponseHeader(const QByteArray &value); 151 152 /** Saves the ETag Response header from the last Navigation Apps api 153 * request with statusCode 200. 154 */ 155 QByteArray navigationAppsEtagResponseHeader() const; 156 157 /** Returns the ETag Response header from the last Navigation Apps api 158 * request with statusCode 200. 159 */ 160 void setNavigationAppsEtagResponseHeader(const QByteArray &value); 161 162 ///Asks for user credentials 163 void handleInvalidCredentials(); 164 165 /** Returns the notifications status retrieved by the notificatons endpoint 166 * https://github.com/nextcloud/desktop/issues/2318#issuecomment-680698429 167 */ 168 bool isDesktopNotificationsAllowed() const; 169 170 /** Set desktop notifications status retrieved by the notificatons endpoint 171 */ 172 void setDesktopNotificationsAllowed(bool isAllowed); 173 174 public slots: 175 /// Triggers a ping to the server to update state and 176 /// connection status and errors. 177 void checkConnectivity(); 178 179 private: 180 void setState(State state); 181 void fetchNavigationApps(); 182 183 signals: 184 void stateChanged(State state); 185 void isConnectedChanged(); 186 void hasFetchedNavigationApps(); 187 void statusChanged(); 188 void desktopNotificationsAllowedChanged(); 189 190 protected Q_SLOTS: 191 void slotConnectionValidatorResult(ConnectionValidator::Status status, const QStringList &errors); 192 193 /// When client gets a 401 or 403 checks if server requested remote wipe 194 /// before asking for user credentials again 195 void slotHandleRemoteWipeCheck(); 196 197 void slotCredentialsFetched(AbstractCredentials *creds); 198 void slotCredentialsAsked(AbstractCredentials *creds); 199 200 void slotNavigationAppsFetched(const QJsonDocument &reply, int statusCode); 201 void slotEtagResponseHeaderReceived(const QByteArray &value, int statusCode); 202 void slotOcsError(int statusCode, const QString &message); 203 204 private: 205 AccountPtr _account; 206 State _state; 207 ConnectionStatus _connectionStatus; 208 QStringList _connectionErrors; 209 bool _waitingForNewCredentials; 210 QDateTime _timeOfLastETagCheck; 211 QPointer<ConnectionValidator> _connectionValidator; 212 QByteArray _notificationsEtagResponseHeader; 213 QByteArray _navigationAppsEtagResponseHeader; 214 215 /** 216 * Starts counting when the server starts being back up after 503 or 217 * maintenance mode. The account will only become connected once this 218 * timer exceeds the _maintenanceToConnectedDelay value. 219 */ 220 QElapsedTimer _timeSinceMaintenanceOver; 221 222 /** 223 * Milliseconds for which to delay reconnection after 503/maintenance. 224 */ 225 int _maintenanceToConnectedDelay; 226 227 /** 228 * Connects remote wipe check with the account 229 * the log out triggers the check (loads app password -> create request) 230 */ 231 RemoteWipe *_remoteWipe; 232 233 /** 234 * Holds the App names and URLs available on the server 235 */ 236 AccountAppList _apps; 237 238 bool _isDesktopNotificationsAllowed; 239 }; 240 241 class AccountApp : public QObject 242 { 243 Q_OBJECT 244 public: 245 AccountApp(const QString &name, const QUrl &url, 246 const QString &id, const QUrl &iconUrl, 247 QObject* parent = nullptr); 248 249 QString name() const; 250 QUrl url() const; 251 QString id() const; 252 QUrl iconUrl() const; 253 254 private: 255 QString _name; 256 QUrl _url; 257 258 QString _id; 259 QUrl _iconUrl; 260 }; 261 262 } 263 264 Q_DECLARE_METATYPE(OCC::AccountState *) 265 Q_DECLARE_METATYPE(OCC::AccountStatePtr) 266 267 #endif //ACCOUNTINFO_H 268