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 #include <memory>
25 
26 class QSettings;
27 
28 namespace OCC {
29 
30 class AccountState;
31 class Account;
32 
33 typedef QExplicitlySharedDataPointer<AccountState> AccountStatePtr;
34 
35 /**
36  * @brief Extra info about an ownCloud server account.
37  * @ingroup gui
38  */
39 class AccountState : public QObject, public QSharedData
40 {
41     Q_OBJECT
42     Q_PROPERTY(AccountPtr account MEMBER _account)
43 
44 public:
45     enum State {
46         /// Not even attempting to connect, most likely because the
47         /// user explicitly signed out or cancelled a credential dialog.
48         SignedOut,
49 
50         /// Account would like to be connected but hasn't heard back yet.
51         Disconnected,
52 
53         /// The account is successfully talking to the server.
54         Connected,
55 
56         /// There's a temporary problem with talking to the server,
57         /// don't bother the user too much and try again.
58         ServiceUnavailable,
59 
60         /// Similar to ServiceUnavailable, but we know the server is down
61         /// for maintenance
62         MaintenanceMode,
63 
64         /// Could not communicate with the server for some reason.
65         /// We assume this may resolve itself over time and will try
66         /// again automatically.
67         NetworkError,
68 
69         /// Server configuration error. (For example: unsupported version)
70         ConfigurationError,
71 
72         /// We are currently asking the user for credentials
73         AskingCredentials
74     };
75 
76     /// The actual current connectivity status.
77     typedef ConnectionValidator::Status ConnectionStatus;
78 
79     /// Use the account as parent
80     explicit AccountState(AccountPtr account);
81     ~AccountState() override;
82 
83     /** Creates an account state from settings and an Account object.
84      *
85      * Use from AccountManager with a prepared QSettings object only.
86      */
87     static AccountState *loadFromSettings(AccountPtr account, QSettings &settings);
88 
89     /** Writes account state information to settings.
90      *
91      * It does not write the Account data.
92      */
93     void writeToSettings(QSettings &settings);
94 
95     AccountPtr account() const;
96 
97     ConnectionStatus connectionStatus() const;
98     QStringList connectionErrors() const;
99 
100     State state() const;
101     static QString stateString(State state);
102 
103     bool isSignedOut() const;
104 
105     /** A user-triggered sign out which disconnects, stops syncs
106      * for the account and forgets the password. */
107     void signOutByUi();
108 
109     /** Tries to connect from scratch.
110      *
111      * Does nothing for signed out accounts.
112      * Connected accounts will be disconnected and try anew.
113      * Disconnected accounts will go to checkConnectivity().
114      *
115      * Useful for when network settings (proxy) change.
116      */
117     void freshConnectionAttempt();
118 
119     /// Move from SignedOut state to Disconnected (attempting to connect)
120     void signIn();
121 
122     bool isConnected() const;
123 
124     /** Returns a new settings object for this account, already in the right groups. */
125     std::unique_ptr<QSettings> settings();
126 
127     /** Mark the timestamp when the last successful ETag check happened for
128      *  this account.
129      *  The checkConnectivity() method uses the timestamp to save a call to
130      *  the server to validate the connection if the last successful etag job
131      *  was not so long ago.
132      */
133     void tagLastSuccessfullETagRequest();
134 
135 public slots:
136     /// Triggers a ping to the server to update state and
137     /// connection status and errors.
138     void checkConnectivity();
139 
140 private:
141     void setState(State state);
142 
143 signals:
144     void stateChanged(State state);
145     void isConnectedChanged();
146 
147 protected Q_SLOTS:
148     void slotConnectionValidatorResult(ConnectionValidator::Status status, const QStringList &errors);
149     void slotInvalidCredentials();
150     void slotCredentialsFetched(AbstractCredentials *creds);
151     void slotCredentialsAsked(AbstractCredentials *creds);
152 
153 private:
154     AccountPtr _account;
155     State _state;
156     ConnectionStatus _connectionStatus;
157     QStringList _connectionErrors;
158     bool _waitingForNewCredentials;
159     QElapsedTimer _timeSinceLastETagCheck;
160     QPointer<ConnectionValidator> _connectionValidator;
161 
162     /**
163      * Starts counting when the server starts being back up after 503 or
164      * maintenance mode. The account will only become connected once this
165      * timer exceeds the _maintenanceToConnectedDelay value.
166      */
167     QElapsedTimer _timeSinceMaintenanceOver;
168 
169     /**
170      * Milliseconds for which to delay reconnection after 503/maintenance.
171      */
172     int _maintenanceToConnectedDelay;
173 };
174 }
175 
176 Q_DECLARE_METATYPE(OCC::AccountState *)
177 Q_DECLARE_METATYPE(OCC::AccountStatePtr)
178 
179 #endif //ACCOUNTINFO_H
180