aboutsummaryrefslogtreecommitdiff
path: root/lib/accountregistry.cpp
blob: f25369d69435643bcc34d7a8802e4e37e2600b5d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
// SPDX-FileCopyrightText: Kitsune Ral <Kitsune-Ral@users.sf.net>
// SPDX-FileCopyrightText: Tobias Fella <fella@posteo.de>
// SPDX-License-Identifier: LGPL-2.1-or-later

#include "accountregistry.h"

#include "connection.h"
#include <QtCore/QCoreApplication>

using namespace Quotient;

void AccountRegistry::add(Connection* a)
{
    if (contains(a))
        return;
    beginInsertRows(QModelIndex(), size(), size());
    push_back(a);
    endInsertRows();
    emit accountCountChanged();
}

void AccountRegistry::drop(Connection* a)
{
    if (const auto idx = indexOf(a); idx != -1) {
        beginRemoveRows(QModelIndex(), idx, idx);
        remove(idx);
        endRemoveRows();
    }
    Q_ASSERT(!contains(a));
}

bool AccountRegistry::isLoggedIn(const QString &userId) const
{
    return std::any_of(cbegin(), cend(), [&userId](const Connection* a) {
        return a->userId() == userId;
    });
}

QVariant AccountRegistry::data(const QModelIndex& index, int role) const
{
    if (!index.isValid() || index.row() >= count())
        return {};

    if (role == AccountRole)
        return QVariant::fromValue(at(index.row()));

    return {};
}

int AccountRegistry::rowCount(const QModelIndex& parent) const
{
    return parent.isValid() ? 0 : count();
}

QHash<int, QByteArray> AccountRegistry::roleNames() const
{
    return { { AccountRole, "connection" } };
}

Connection* AccountRegistry::get(const QString& userId)
{
    for (const auto &connection : *this) {
        if (connection->userId() == userId)
            return connection;
    }
    return nullptr;
}

QKeychain::ReadPasswordJob* AccountRegistry::loadAccessTokenFromKeychain(const QString& userId)
{
    qCDebug(MAIN) << "Reading access token from keychain for" << userId;
    auto job = new QKeychain::ReadPasswordJob(qAppName(), this);
    job->setKey(userId);
    job->start();

    return job;
}

void AccountRegistry::invokeLogin()
{
    const auto accounts = SettingsGroup("Accounts").childGroups();
    for (const auto& accountId : accounts) {
        AccountSettings account { accountId };
        m_accountsLoading += accountId;
        emit accountsLoadingChanged();

        if (account.homeserver().isEmpty())
            continue;

        auto accessTokenLoadingJob =
            loadAccessTokenFromKeychain(account.userId());
        connect(accessTokenLoadingJob, &QKeychain::Job::finished, this,
                [accountId, this, accessTokenLoadingJob]() {
                    if (accessTokenLoadingJob->error()
                        != QKeychain::Error::NoError) {
                        emit keychainError(accessTokenLoadingJob->error());
                        return;
                    }

                    AccountSettings account { accountId };
                    auto connection = new Connection(account.homeserver());
                    connect(connection, &Connection::connected, this,
                            [connection] {
                                connection->loadState();
                                connection->setLazyLoading(true);

                                connection->syncLoop();
                            });
                    connect(connection, &Connection::loginError, this,
                            [this, connection](const QString& error,
                                               const QString& details) {
                                emit loginError(connection, error, details);
                            });
                    connect(connection, &Connection::resolveError, this,
                            [this, connection](const QString& error) {
                                emit resolveError(connection, error);
                            });
                    connection->assumeIdentity(
                        account.userId(), accessTokenLoadingJob->binaryData(),
                        account.deviceId());
                });
    }
}

QStringList AccountRegistry::accountsLoading() const
{
    return m_accountsLoading;
}

AccountRegistry::~AccountRegistry()
{
    for (const auto& connection : *this) {
        connection->saveState();
    }
}