presentation/AccountSetupSession.h
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #pragma once | ||
| 2 | #include "AccountServiceCheck.h" | ||
| 3 | #include "service/MailServerDiscovery.h" | ||
| 4 | #include <QObject> | ||
| 5 | #include <QPointer> | ||
| 6 | #include <QVariantMap> | ||
| 7 | #include <functional> | ||
| 8 | |||
| 9 | class QuickAccountSettings; | ||
| 10 | struct CalendarInfo; | ||
| 11 | struct AddressBookInfo; | ||
| 12 | |||
| 13 | // Sprint 100 S100.1.9 (D-6, §6.2.2, SJ1, SJ2): the guided setup. | ||
| 14 | // address → discovering → [review] → testing → [outgoing] → services → done | ||
| 15 | // ↘ manual (nothing or only part found) ↘ failed | ||
| 16 | // begin() takes name, address and password; the servers are found without | ||
| 17 | // the password (MailServerDiscovery), shown when they are not the | ||
| 18 | // provider's own (review), then the login is checked (AccountServiceCheck: | ||
| 19 | // IMAP login and SMTP AUTH). The account is saved through the normal async | ||
| 20 | // save with "same login" for outgoing mail (D-17). Calendars and contacts | ||
| 21 | // of the same provider are then looked for with the same login (RFC 6764 | ||
| 22 | // well-known addresses) and, at finish(), saved as a linked DAV account | ||
| 23 | // with the D-20 default selection (SB-07 cannot happen here). | ||
| 24 | // The password lives only in this object while the setup runs. | ||
| 25 | class AccountSetupSession final : public QObject { | ||
| 26 | 5 | Q_OBJECT | |
| 27 | Q_PROPERTY(QString state READ state NOTIFY changed) | ||
| 28 | Q_PROPERTY(QString address READ address NOTIFY changed) | ||
| 29 | Q_PROPERTY(QVariantMap sources READ sources NOTIFY changed) | ||
| 30 | Q_PROPERTY(QVariantMap servers READ servers NOTIFY changed) | ||
| 31 | Q_PROPERTY(QVariantMap incoming READ incoming NOTIFY changed) | ||
| 32 | Q_PROPERTY(QVariantMap outgoing READ outgoing NOTIFY changed) | ||
| 33 | Q_PROPERTY(QString message READ message NOTIFY changed) | ||
| 34 | Q_PROPERTY(QString accountId READ accountId NOTIFY changed) | ||
| 35 | // "idle", "searching", "confirm", "found", "none" | ||
| 36 | Q_PROPERTY(QString davState READ davState NOTIFY changed) | ||
| 37 | // The derived host that answered 401 and waits for the user's explicit | ||
| 38 | // credential approval (F-23); set while davState is "confirm". | ||
| 39 | Q_PROPERTY(QString davHost READ davHost NOTIFY changed) | ||
| 40 | // [{key, name, kind ("calendar", "tasks", "both", "book"), selected, reason}] | ||
| 41 | Q_PROPERTY(QVariantList collections READ collections NOTIFY changed) | ||
| 42 | Q_PROPERTY(bool busy READ busy NOTIFY changed) | ||
| 43 | public: | ||
| 44 | // authRequired: the host answered 401 — it is a DAV host that wants the | ||
| 45 | // login. The session asks before it sends credentials to a derived host | ||
| 46 | // (F-23); probes of a host the provider's autoconfig named send them | ||
| 47 | // directly. | ||
| 48 | using DavProbe = std::function<void(QObject *owner, const QString &serverUrl, const QString &username, | ||
| 49 | const QByteArray &password, | ||
| 50 | std::function<void(bool ok, QList<CalendarInfo>, QList<AddressBookInfo>, bool authRequired)>)>; | ||
| 51 | // Starts the async save of the account fields: {ok, requestId} or {ok: | ||
| 52 | // false, error}; accountSaveFinished(requestId) of the settings follows. | ||
| 53 | using AccountSaver = std::function<QVariantMap(const QVariantMap &fields)>; | ||
| 54 | explicit AccountSetupSession(QuickAccountSettings *settings, AccountSession *accounts, QObject *parent = nullptr); | ||
| 55 | ~AccountSetupSession() override; | ||
| 56 | // Test seams: replayed discovery, login check, DAV lookup. | ||
| 57 | 7 | MailServerDiscovery *discovery() { return &m_discovery; } | |
| 58 | 2 | AccountServiceCheck *serviceCheck() { return &m_check; } | |
| 59 | 3 | void setDavProbe(DavProbe probe) { m_davProbe = std::move(probe); } | |
| 60 | 5 | void setAccountSaver(AccountSaver saver) { m_saver = std::move(saver); } | |
| 61 | |||
| 62 | 54 | QString state() const { return m_state; } | |
| 63 | 2 | QString address() const { return m_address; } | |
| 64 | 8 | QVariantMap sources() const { return m_discovery.sources(); } | |
| 65 | 6 | QVariantMap servers() const { return m_servers; } | |
| 66 | 1 | QVariantMap incoming() const { return m_incoming; } | |
| 67 | 1 | QVariantMap outgoing() const { return m_outgoing; } | |
| 68 | 4 | QString message() const { return m_message; } | |
| 69 | ✗ | QString accountId() const { return m_accountId; } | |
| 70 | 40 | QString davState() const { return m_davState; } | |
| 71 | 4 | QString davHost() const { return m_davHost; } | |
| 72 | QVariantList collections() const; | ||
| 73 | bool busy() const; | ||
| 74 | |||
| 75 | // {provider, name, helpUrl} for an address being typed (Google, Microsoft, | ||
| 76 | // Apple need app passwords, T-036). | ||
| 77 | Q_INVOKABLE QVariantMap providerHint(const QString &address) const; | ||
| 78 | // Returns "" or the reason the address cannot be used (field "email"). | ||
| 79 | Q_INVOKABLE QString begin(const QString &name, const QString &address, const QString &password); | ||
| 80 | Q_INVOKABLE void lookupIspdb(); | ||
| 81 | Q_INVOKABLE void useServers(); | ||
| 82 | // The manual editor: imapHost/Port/Security, smtpHost/Port/Security, | ||
| 83 | // username, smtpLogin, smtpUsername, smtpPassword. | ||
| 84 | Q_INVOKABLE void useManual(const QVariantMap &fields); | ||
| 85 | Q_INVOKABLE void retry(const QString &password); | ||
| 86 | Q_INVOKABLE void continueWithoutSending(); | ||
| 87 | Q_INVOKABLE void setCollection(const QString &key, bool selected); | ||
| 88 | // F-23: explicit answers to the credential question of a derived host. | ||
| 89 | Q_INVOKABLE void authorizeDavHost(); | ||
| 90 | Q_INVOKABLE void skipDavHost(); | ||
| 91 | Q_INVOKABLE void finish(bool withCalendars); | ||
| 92 | Q_INVOKABLE void cancel(); | ||
| 93 | |||
| 94 | signals: | ||
| 95 | void changed(); | ||
| 96 | void done(const QString &accountId); | ||
| 97 | |||
| 98 | private: | ||
| 99 | void setState(const QString &state, const QString &message = {}); | ||
| 100 | void discoveryFinished(bool found); | ||
| 101 | void check(); | ||
| 102 | void checked(const QVariantMap &result); | ||
| 103 | void save(); | ||
| 104 | void saved(const QVariantMap &result); | ||
| 105 | void findCalendars(); | ||
| 106 | void tryDav(int index, bool withCredentials); | ||
| 107 | QVariantMap accountFields() const; | ||
| 108 | QuickAccountSettings *m_settings; | ||
| 109 | AccountSession *m_accounts; | ||
| 110 | MailServerDiscovery m_discovery; | ||
| 111 | AccountServiceCheck m_check; | ||
| 112 | DavProbe m_davProbe; | ||
| 113 | AccountSaver m_saver; | ||
| 114 | QString m_state = QStringLiteral("address"); | ||
| 115 | QString m_name, m_address, m_message, m_accountId; | ||
| 116 | QByteArray m_password; | ||
| 117 | QVariantMap m_servers, m_incoming, m_outgoing; | ||
| 118 | bool m_skipOutgoing = false; | ||
| 119 | QString m_checkId, m_saveId; | ||
| 120 | QString m_davState = QStringLiteral("idle"); | ||
| 121 | QString m_davServer; | ||
| 122 | QStringList m_davCandidates; | ||
| 123 | // F-23: candidates below m_davTrustedCount are derived from the mail | ||
| 124 | // domain (bare domain, dav.<domain>) and are probed without credentials | ||
| 125 | // first; the rest were named by the provider's autoconfig (the IMAP | ||
| 126 | // host) and already receive the mail login. | ||
| 127 | int m_davTrustedCount = 0; | ||
| 128 | int m_davIndex = 0; | ||
| 129 | QString m_davHost; | ||
| 130 | struct Collection { QString key, name, kind, reason; bool selected = true; bool calendar = true; }; | ||
| 131 | QList<Collection> m_collections; | ||
| 132 | QPointer<QObject> m_davRun; | ||
| 133 | }; | ||
| 134 |