newaccountmodel.cpp 45.4 KB
Newer Older
Nicolas Jager's avatar
Nicolas Jager committed
1
/****************************************************************************
2
 *    Copyright (C) 2017-2019 Savoir-faire Linux Inc.                       *
3
4
 *   Author: Nicolas Jäger <nicolas.jager@savoirfairelinux.com>             *
 *   Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>           *
5
 *   Author: Kateryna Kostiuk <kateryna.kostiuk@savoirfairelinux.com>       *
6
 *   Author: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com>         *
Nicolas Jager's avatar
Nicolas Jager committed
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 *                                                                          *
 *   This library is free software; you can redistribute it and/or          *
 *   modify it under the terms of the GNU Lesser General Public             *
 *   License as published by the Free Software Foundation; either           *
 *   version 2.1 of the License, or (at your option) any later version.     *
 *                                                                          *
 *   This library 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      *
 *   Lesser General Public License for more details.                        *
 *                                                                          *
 *   You should have received a copy of the GNU General Public License      *
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.  *
 ***************************************************************************/
#include "api/newaccountmodel.h"

23
24
// daemon
#include <account_const.h>
Nicolas Jager's avatar
Nicolas Jager committed
25

26
27
28
29
30
//qt
#include <QtGui/QPixmap>
#include <QtGui/QImage>
#include <QtCore/QBuffer>

31
// new LRC
32
#include "api/lrc.h"
33
34
#include "api/contactmodel.h"
#include "api/conversationmodel.h"
35
#include "api/peerdiscoverymodel.h"
Sébastien Blin's avatar
Sébastien Blin committed
36
#include "api/newcallmodel.h"
37
#include "api/newcodecmodel.h"
38
#include "api/newdevicemodel.h"
39
#include "api/behaviorcontroller.h"
40
#include "authority/storagehelper.h"
41
#include "callbackshandler.h"
Nicolas Jager's avatar
Nicolas Jager committed
42
#include "database.h"
43
#include "vcard.h"
Nicolas Jager's avatar
Nicolas Jager committed
44

45
// old LRC
46
#include "api/profile.h"
47
#include "qtwrapper/conversions_wrap.hpp"
48
49
50
51

// Dbus
#include "dbus/configurationmanager.h"

52
#include <atomic>
53

Nicolas Jager's avatar
Nicolas Jager committed
54
55
56
57
58
namespace lrc
{

using namespace api;

59
class NewAccountModelPimpl: public QObject
Nicolas Jager's avatar
Nicolas Jager committed
60
{
61
    Q_OBJECT
Nicolas Jager's avatar
Nicolas Jager committed
62
public:
63
    NewAccountModelPimpl(NewAccountModel& linked,
Anthony Léonard's avatar
Anthony Léonard committed
64
                         Lrc& lrc,
65
                         const CallbacksHandler& callbackHandler,
66
67
68
                         const BehaviorController& behaviorController,
                         MigrationCb& willMigrateCb,
                         MigrationCb& didMigrateCb);
Nicolas Jager's avatar
Nicolas Jager committed
69
70
    ~NewAccountModelPimpl();

71
72
73
    using AccountInfoDbMap = std::map<std::string,
                                      std::pair<account::Info, std::shared_ptr<Database>>>;

74
    NewAccountModel& linked;
Anthony Léonard's avatar
Anthony Léonard committed
75
    Lrc& lrc;
76
    const CallbacksHandler& callbacksHandler;
77
    const BehaviorController& behaviorController;
78
    AccountInfoDbMap accounts;
79

80
81
    // Synchronization tools
    std::mutex m_mutex_account;
82
83
    std::mutex m_mutex_account_removal;
    std::condition_variable m_condVar_account_removal;
84
85
    std::atomic_bool username_changed;
    std::string new_username;
86

87
88
89
    /**
     * Add the profile information from an account to the db then add it to accounts.
     * @param accountId
90
     * @param db an optional migrated database object
91
92
     * @note this method get details for an account from the daemon.
     */
93
    void addToAccounts(const std::string& accountId, std::shared_ptr<Database> db = nullptr);
94

95
96
97
98
99
100
101
102
103
104
105
    /**
     * Remove account from accounts list. Emit accountRemoved.
     * @param accountId
     */
    void removeFromAccounts(const std::string& accountId);

    /**
     * Sync changes to the accounts list with the lrc.
     */
    void updateAccounts();

106
public Q_SLOTS:
107

108
109
110
111
112
113
    /**
     * Emit accountStatusChanged.
     * @param accountId
     * @param status
     */
    void slotAccountStatusChanged(const std::string& accountID, const api::account::Status status);
114

115
116
117
118
119
120
121
    /**
     * Emit exportOnRingEnded.
     * @param accountId
     * @param status
     * @param pin
     */
    void slotExportOnRingEnded(const std::string& accountID, int status, const std::string& pin);
122

123
124
125
126
127
    /**
     * @param accountId
     * @param details
     */
    void slotAccountDetailsChanged(const std::string& accountID, const std::map<std::string, std::string>& details);
128

129
130
131
132
133
134
    /**
     * @param accountId
     * @param details
     */
    void slotVolatileAccountDetailsChanged(const std::string& accountID, const std::map<std::string, std::string>& details);

135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
    /**
     * Emit nameRegistrationEnded
     * @param accountId
     * @param status
     * @param name
     */
    void slotNameRegistrationEnded(const std::string& accountId, int status, const std::string& name);

    /**
     * Emit registeredNameFound
     * @param accountId
     * @param status
     * @param address
     * @param name
     */
    void slotRegisteredNameFound(const std::string& accountId, int status, const std::string& address, const std::string& name);
151
152
153
154
155
156
157

    /**
     * Emit migrationEnded
     * @param accountId
     * @param ok
     */
    void slotMigrationEnded(const std::string& accountId, bool ok);
Nicolas Jager's avatar
Nicolas Jager committed
158
159
};

Anthony Léonard's avatar
Anthony Léonard committed
160
NewAccountModel::NewAccountModel(Lrc& lrc,
161
                                 const CallbacksHandler& callbacksHandler,
162
163
164
                                 const BehaviorController& behaviorController,
                                 MigrationCb& willMigrateCb,
                                 MigrationCb& didMigrateCb)
Nicolas Jager's avatar
Nicolas Jager committed
165
: QObject()
166
167
, pimpl_(std::make_unique<NewAccountModelPimpl>(*this, lrc, callbacksHandler, behaviorController,
                                                willMigrateCb, didMigrateCb))
Nicolas Jager's avatar
Nicolas Jager committed
168
169
170
171
172
173
174
{
}

NewAccountModel::~NewAccountModel()
{
}

175
std::vector<std::string>
Nicolas Jager's avatar
Nicolas Jager committed
176
177
NewAccountModel::getAccountList() const
{
178
    std::vector<std::string> accountsId;
179
    const QStringList accountIds = ConfigurationManager::instance().getAccountList();
180

181
    for (auto const& id : accountIds) {
182
        auto account = pimpl_->accounts.find(id.toStdString());
183
        // Do not include accounts flagged for removal
184
        if (account != pimpl_->accounts.end() && account->second.first.valid)
185
            accountsId.emplace_back(id.toStdString());
186
    }
187
188

    return accountsId;
Nicolas Jager's avatar
Nicolas Jager committed
189
190
}

191
192
193
void
NewAccountModel::setAccountEnabled(const std::string& accountId, bool enabled) const
{
194
195
    auto account = pimpl_->accounts.find(accountId);
    if (account == pimpl_->accounts.end()) {
196
197
        throw std::out_of_range("NewAccountModel::getAccountConfig, can't find " + accountId);
    }
198
199
    auto& accountInfo = account->second.first;
    accountInfo.enabled = enabled;
200
    ConfigurationManager::instance().sendRegister(QString::fromStdString(accountId), enabled);
201
202
}

203
void
204
205
206
NewAccountModel::setAccountConfig(const std::string& accountId,
                                  const account::ConfProperties_t& confProperties) const
{
207
208
    auto account = pimpl_->accounts.find(accountId);
    if (account == pimpl_->accounts.end()) {
209
210
        throw std::out_of_range("NewAccountModel::save, can't find " + accountId);
    }
211
    auto& accountInfo = account->second.first;
212
213
214
215
216
217
218
219
    auto& configurationManager = ConfigurationManager::instance();
    MapStringString details = confProperties.toDetails();
    // Set values from Info. No need to include ID and TYPE. SIP accounts may modify the USERNAME
    // TODO: move these into the ConfProperties_t struct ?
    using namespace DRing::Account;
    qDebug("UPNP_ENABLED: %s\n", details[ConfProperties::UPNP_ENABLED].toStdString().c_str());
    details[ConfProperties::ENABLED]                    = toQString(accountInfo.enabled);
    details[ConfProperties::ALIAS]                      = toQString(accountInfo.profileInfo.alias);
220
    details[ConfProperties::DISPLAYNAME]                = toQString(accountInfo.profileInfo.alias);
221
    details[ConfProperties::TYPE]                       = (accountInfo.profileInfo.type == profile::Type::RING) ? QString(ProtocolNames::RING) : QString(ProtocolNames::SIP);
222
223
    if (accountInfo.profileInfo.type == profile::Type::RING) {
        details[ConfProperties::USERNAME] = toQString(accountInfo.profileInfo.uri).prepend((accountInfo.profileInfo.type == profile::Type::RING) ? "ring:" : "");
224
225
226
227
228
229
230
231
    } else if (accountInfo.profileInfo.type == profile::Type::SIP) {
        MapStringString credentials;
        credentials[ConfProperties::USERNAME] = toQString(confProperties.username);
        credentials[ConfProperties::PASSWORD] = toQString(confProperties.password);
        credentials[ConfProperties::REALM] = confProperties.realm.empty()? QString("*") : toQString(confProperties.realm);
        QVector<MapStringString> credentialsVec;
        credentialsVec.append(credentials);
        ConfigurationManager::instance().setCredentials(accountId.c_str(), credentialsVec);
232
233
        details[ConfProperties::USERNAME] = toQString(confProperties.username);
    }
234
235
236
237
238
    configurationManager.setAccountDetails(QString::fromStdString(accountId), details);
}

account::ConfProperties_t
NewAccountModel::getAccountConfig(const std::string& accountId) const
239
{
240
241
    auto account = pimpl_->accounts.find(accountId);
    if (account == pimpl_->accounts.end()) {
242
243
        throw std::out_of_range("NewAccountModel::getAccountConfig, can't find " + accountId);
    }
244
245
    auto& accountInfo = account->second.first;
    return accountInfo.confProperties;
246
247
}

248
249
250
void
NewAccountModel::setAlias(const std::string& accountId, const std::string& alias)
{
251
252
    auto account = pimpl_->accounts.find(accountId);
    if (account == pimpl_->accounts.end()) {
253
254
        throw std::out_of_range("NewAccountModel::setAlias, can't find " + accountId);
    }
255
256
257
258
259
    auto& accountInfo = account->second.first;
    accountInfo.profileInfo.alias = alias;

    authority::storage::createOrUpdateProfile(accountInfo.id, accountInfo.profileInfo);

260
    emit profileUpdated(accountId);
261
262
}

263
264
265
void
NewAccountModel::setAvatar(const std::string& accountId, const std::string& avatar)
{
266
267
    auto account = pimpl_->accounts.find(accountId);
    if (account == pimpl_->accounts.end()) {
268
269
        throw std::out_of_range("NewAccountModel::setAvatar, can't find " + accountId);
    }
270
271
272
273
274
    auto& accountInfo = account->second.first;
    accountInfo.profileInfo.avatar = avatar;

    authority::storage::createOrUpdateProfile(accountInfo.id, accountInfo.profileInfo);

275
    emit profileUpdated(accountId);
276
277
}

278
279
280
281
282
283
bool
NewAccountModel::registerName(const std::string& accountId, const std::string& password, const std::string& username)
{
    return ConfigurationManager::instance().registerName(accountId.c_str(), password.c_str(), username.c_str());
}

284
bool
285
NewAccountModel::exportToFile(const std::string& accountId, const std::string& path, const std::string& password) const
286
{
287
    return ConfigurationManager::instance().exportToFile(accountId.c_str(), path.c_str(), password.c_str());
288
289
}

290
291
292
293
294
295
bool
NewAccountModel::exportOnRing(const std::string& accountId, const std::string& password) const
{
    return ConfigurationManager::instance().exportOnRing(accountId.c_str(), password.c_str());
}

296
297
298
299
300
301
302
303
304
305
306
307
void
NewAccountModel::removeAccount(const std::string& accountId) const
{
    ConfigurationManager::instance().removeAccount(accountId.c_str());
}

bool
NewAccountModel::changeAccountPassword(const std::string& accountId,
                                       const std::string& currentPassword,
                                       const std::string& newPassword) const
{
    return ConfigurationManager::instance()
308
309
310
311
312
313
    .changeAccountPassword(accountId.c_str(), currentPassword.c_str(), newPassword.c_str());
}

void
NewAccountModel::flagFreeable(const std::string& accountId) const
{
314
315
    auto account = pimpl_->accounts.find(accountId);
    if (account == pimpl_->accounts.end())
316
317
318
319
        throw std::out_of_range("NewAccountModel::flagFreeable, can't find " + accountId);

    {
        std::lock_guard<std::mutex> lock(pimpl_->m_mutex_account_removal);
320
        account->second.first.freeable = true;
321
322
    }
    pimpl_->m_condVar_account_removal.notify_all();
323
324
}

Nicolas Jager's avatar
Nicolas Jager committed
325
const account::Info&
326
NewAccountModel::getAccountInfo(const std::string& accountId) const
Nicolas Jager's avatar
Nicolas Jager committed
327
{
328
329
330
331
    auto accountInfo = pimpl_->accounts.find(accountId);
    if (accountInfo == pimpl_->accounts.end())
        throw std::out_of_range("NewAccountModel::getAccountInfo, can't find " + accountId);

332
    return accountInfo->second.first;
Nicolas Jager's avatar
Nicolas Jager committed
333
334
}

335
NewAccountModelPimpl::NewAccountModelPimpl(NewAccountModel& linked,
Anthony Léonard's avatar
Anthony Léonard committed
336
                                           Lrc& lrc,
337
                                           const CallbacksHandler& callbacksHandler,
338
339
340
                                           const BehaviorController& behaviorController,
                                           MigrationCb& willMigrateCb,
                                           MigrationCb& didMigrateCb)
341
: linked(linked)
Anthony Léonard's avatar
Anthony Léonard committed
342
, lrc {lrc}
343
, behaviorController(behaviorController)
344
, callbacksHandler(callbacksHandler)
345
, username_changed(false)
Nicolas Jager's avatar
Nicolas Jager committed
346
{
347
    const QStringList accountIds = ConfigurationManager::instance().getAccountList();
348
349
350
351
352
353
354
355
356
357

    // NOTE: If the daemon is down, but dbus answered, id can contains
    // "Remote peer disconnected", "The name is not activable", etc.
    // So avoid to migrate useless directories.
    for (auto& id : accountIds)
        if (id.indexOf(" ") != -1) {
            qWarning() << "Invalid dbus answer. Daemon not running";
            return;
        }

358
359
360
361
    auto accountDbs = authority::storage::migrateIfNeeded(accountIds, willMigrateCb, didMigrateCb);
    for (const auto& id : accountIds) {
        addToAccounts(id.toStdString(), accountDbs.at(accountIds.indexOf(id)));
    }
362

363
    connect(&callbacksHandler, &CallbacksHandler::accountsChanged, this, &NewAccountModelPimpl::updateAccounts);
364
    connect(&callbacksHandler, &CallbacksHandler::accountStatusChanged, this, &NewAccountModelPimpl::slotAccountStatusChanged);
365
    connect(&callbacksHandler, &CallbacksHandler::accountDetailsChanged, this, &NewAccountModelPimpl::slotAccountDetailsChanged);
366
    connect(&callbacksHandler, &CallbacksHandler::volatileAccountDetailsChanged, this, &NewAccountModelPimpl::slotVolatileAccountDetailsChanged);
367
    connect(&callbacksHandler, &CallbacksHandler::exportOnRingEnded, this, &NewAccountModelPimpl::slotExportOnRingEnded);
368
369
    connect(&callbacksHandler, &CallbacksHandler::nameRegistrationEnded, this, &NewAccountModelPimpl::slotNameRegistrationEnded);
    connect(&callbacksHandler, &CallbacksHandler::registeredNameFound, this, &NewAccountModelPimpl::slotRegisteredNameFound);
370
    connect(&callbacksHandler, &CallbacksHandler::migrationEnded, this, &NewAccountModelPimpl::slotMigrationEnded);
Nicolas Jager's avatar
Nicolas Jager committed
371
372
373
374
}

NewAccountModelPimpl::~NewAccountModelPimpl()
{
375
}
Nicolas Jager's avatar
Nicolas Jager committed
376

377
378
379
380
381
382
383
384
385
386
void
NewAccountModelPimpl::updateAccounts()
{
    qDebug() << "Syncing lrc accounts list with the daemon";
    ConfigurationManagerInterface& configurationManager = ConfigurationManager::instance();
    QStringList accountIds = configurationManager.getAccountList();

    // Detect removed accounts
    std::list<std::string> toBeRemoved;
    for (auto& it : accounts) {
387
        auto& accountInfo = it.second.first;
388
389
390
391
392
393
394
395
396
397
398
399
        if (!accountIds.contains(QString::fromStdString(accountInfo.id))) {
            qDebug("detected account removal %s", accountInfo.id.c_str());
            toBeRemoved.push_back(accountInfo.id);
        }
    }

    for (auto it = toBeRemoved.begin(); it != toBeRemoved.end(); ++it) {
        removeFromAccounts(*it);
    }

    // Detect new accounts
    for (auto& id : accountIds) {
400
        auto account = accounts.find(id.toStdString());
401
402
403
404
        // NOTE: If the daemon is down, but dbus answered, id can contains
        // "Remote peer disconnected", "The name is not activable", etc.
        // So avoid to create useless directories.
        if (account == accounts.end() && id.indexOf(" ") == -1) {
405
406
            qDebug("detected new account %s", id.toStdString().c_str());
            addToAccounts(id.toStdString());
407
408
            auto updatedAccount = accounts.find(id.toStdString());
            if (updatedAccount == accounts.end()) {
409
410
                return;
            }
411
            if (updatedAccount->second.first.profileInfo.type == profile::Type::SIP) {
412
413
414
415
416
                // NOTE: At this point, a SIP account is ready, but not a Ring
                // account. Indeed, the keys are not generated at this point.
                // See slotAccountStatusChanged for more details.
                emit linked.accountAdded(id.toStdString());
            }
417
418
        }
    }
Nicolas Jager's avatar
Nicolas Jager committed
419
420
}

421
422
423
void
NewAccountModelPimpl::slotAccountStatusChanged(const std::string& accountID, const api::account::Status status)
{
424
425
426
427
    if (status == api::account::Status::INVALID) {
        emit linked.invalidAccountDetected(accountID);
        return;
    }
428
429
430
431
432
433
434
    auto it = accounts.find(accountID);

    // If account is not in the map yet, don't add it, it is updateAccounts's job
    if (it == accounts.end()) {
        return;
    }

435
    auto& accountInfo = it->second.first;
436

437
438
439
440
441
442
443
444
445
446
447
448
449
    if (accountInfo.profileInfo.type != profile::Type::SIP) {
        if (status != api::account::Status::INITIALIZING
            && accountInfo.status == api::account::Status::INITIALIZING) {
            // Detect when a new account is generated (keys are ready). During
            // the generation, a Ring account got the "INITIALIZING" status.
            // When keys are generated, the status will change.
            accounts.erase(accountID);
            addToAccounts(accountID);
            emit linked.accountAdded(accountID);
        } else if (!accountInfo.profileInfo.uri.empty()) {
            accountInfo.status = status;
            emit linked.accountStatusChanged(accountID);
        }
450
451
    } else {
        accountInfo.status = status;
452
        emit linked.accountStatusChanged(accountID);
453
454
455
456
    }
}

void
457
NewAccountModelPimpl::slotAccountDetailsChanged(const std::string& accountId, const std::map<std::string, std::string>& details)
458
{
459
460
    auto account = accounts.find(accountId);
    if (account == accounts.end()) {
461
462
        throw std::out_of_range("NewAccountModelPimpl::slotAccountDetailsChanged, can't find " + accountId);
    }
463
464
    auto& accountInfo = account->second.first;
    accountInfo.fromDetails(convertMap(details));
465
466
    if (username_changed) {
        username_changed = false;
467
        accountInfo.registeredName = new_username;
468
469
        emit linked.profileUpdated(accountId);
    }
470
471
    emit linked.accountStatusChanged(accountId);
}
472

473
474
475
476
477
void
NewAccountModelPimpl::slotVolatileAccountDetailsChanged(const std::string& accountId, const std::map<std::string, std::string>& details)
{
    auto account = accounts.find(accountId);
    if (account == accounts.end()) {
478
479
        qWarning() << "NewAccountModelPimpl::slotVolatileAccountDetailsChanged, can't find " << accountId.c_str();
        return;
480
481
482
483
484
485
486
487
488
489
    }
    auto& accountInfo = account->second.first;

    auto new_usernameIt = details.find(DRing::Account::VolatileProperties::REGISTERED_NAME);
    if (new_usernameIt == details.end())
        return;
    accountInfo.registeredName = new_usernameIt->second;
    emit linked.profileUpdated(accountId);
}

490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
void
NewAccountModelPimpl::slotExportOnRingEnded(const std::string& accountID, int status, const std::string& pin)
{
    account::ExportOnRingStatus convertedStatus = account::ExportOnRingStatus::INVALID;
    switch (status) {
    case 0:
        convertedStatus = account::ExportOnRingStatus::SUCCESS;
        break;
    case 1:
        convertedStatus = account::ExportOnRingStatus::WRONG_PASSWORD;
        break;
    case 2:
        convertedStatus = account::ExportOnRingStatus::NETWORK_ERROR;
        break;
    default:
        break;
    }
    emit linked.exportOnRingEnded(accountID, convertedStatus, pin);
}

510
511
512
513
514
515
void
NewAccountModelPimpl::slotNameRegistrationEnded(const std::string& accountId, int status, const std::string& name)
{
    account::RegisterNameStatus convertedStatus = account::RegisterNameStatus::INVALID;
    switch (status)
    {
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
516
    case 0: {
517
        convertedStatus = account::RegisterNameStatus::SUCCESS;
518
519
        auto account = accounts.find(accountId);
        if (account != accounts.end() && account->second.first.registeredName.empty()) {
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
520
            auto conf = linked.getAccountConfig(accountId);
521
522
            username_changed = true;
            new_username = name;
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
523
524
            linked.setAccountConfig(accountId, conf);
        }
525
        break;
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
526
      }
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
    case 1:
        convertedStatus = account::RegisterNameStatus::WRONG_PASSWORD;
        break;
    case 2:
        convertedStatus = account::RegisterNameStatus::INVALID_NAME;
        break;
    case 3:
        convertedStatus = account::RegisterNameStatus::ALREADY_TAKEN;
        break;
    case 4:
        convertedStatus = account::RegisterNameStatus::NETWORK_ERROR;
        break;
    default:
        break;
    }
    emit linked.nameRegistrationEnded(accountId, convertedStatus, name);
}

void
NewAccountModelPimpl::slotRegisteredNameFound(const std::string& accountId, int status, const std::string& address, const std::string& name)
{
    account::LookupStatus convertedStatus = account::LookupStatus::INVALID;
    switch (status)
    {
    case 0:
        convertedStatus = account::LookupStatus::SUCCESS;
        break;
    case 1:
        convertedStatus = account::LookupStatus::INVALID_NAME;
        break;
    case 2:
        convertedStatus = account::LookupStatus::NOT_FOUND;
        break;
    case 3:
        convertedStatus = account::LookupStatus::ERROR;
        break;
    default:
        break;
    }
    emit linked.registeredNameFound(accountId, convertedStatus, address, name);
}

569
570
571
572
void
NewAccountModelPimpl::slotMigrationEnded(const std::string& accountId, bool ok)
{
    if (ok) {
573
574
575
576
577
578
579
580
581
582
583
        auto it = accounts.find(accountId);
        if (it == accounts.end()) {
            addToAccounts(accountId);
            return;
        }
        auto& accountInfo = it->second.first;
        MapStringString details = ConfigurationManager::instance().getAccountDetails(accountId.c_str());
        accountInfo.fromDetails(details);
        MapStringString volatileDetails = ConfigurationManager::instance().getVolatileAccountDetails(accountId.c_str());
        std::string daemonStatus = volatileDetails[DRing::Account::ConfProperties::Registration::STATUS].toStdString();
        accountInfo.status = lrc::api::account::to_status(daemonStatus);
584
585
586
587
    }
    emit linked.migrationEnded(accountId, ok);
}

588
void
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
NewAccountModelPimpl::addToAccounts(const std::string& accountId,
                                    std::shared_ptr<Database> db)
{
    if (db == nullptr) {
        try {
            auto appPath = authority::storage::getPath();
            auto dbName = QString::fromStdString(accountId + "/history");
            db = DatabaseFactory::create<Database>(dbName, appPath);
            // create the profiles path if necessary
            QDir profilesDir(appPath + QString::fromStdString(accountId) + "/profiles");
            if (!profilesDir.exists()) {
                profilesDir.mkpath(".");
            }
        } catch (const std::runtime_error& e) {
            qWarning() << e.what();
            return;
        }
    }

    auto it = accounts.emplace(accountId, std::make_pair(account::Info(), db));
609
610

    if (!it.second) {
611
        qWarning("failed to add new account: id already present in map");
612
613
614
        return;
    }

615
    // Init profile
616
617
618
    account::Info& newAccInfo = (it.first)->second.first;
    newAccInfo.id = accountId;
    newAccInfo.profileInfo.avatar = authority::storage::getAccountAvatar(accountId);
619

620
621
    // Fill account::Info struct with details from daemon
    MapStringString details = ConfigurationManager::instance().getAccountDetails(accountId.c_str());
622
    newAccInfo.fromDetails(details);
623

624
    // Init models for this account
625
626
627
628
629
630
631
    newAccInfo.accountModel = &linked;
    newAccInfo.callModel = std::make_unique<NewCallModel>(newAccInfo, callbacksHandler);
    newAccInfo.contactModel = std::make_unique<ContactModel>(newAccInfo, *db, callbacksHandler, behaviorController);
    newAccInfo.conversationModel = std::make_unique<ConversationModel>(newAccInfo, lrc, *db, callbacksHandler, behaviorController);
    newAccInfo.peerDiscoveryModel = std::make_unique<PeerDiscoveryModel>(callbacksHandler, accountId);
    newAccInfo.deviceModel = std::make_unique<NewDeviceModel>(newAccInfo, callbacksHandler);
    newAccInfo.codecModel = std::make_unique<NewCodecModel>(newAccInfo, callbacksHandler);
632

633
    MapStringString volatileDetails = ConfigurationManager::instance().getVolatileAccountDetails(accountId.c_str());
634
    std::string daemonStatus = volatileDetails[DRing::Account::ConfProperties::Registration::STATUS].toStdString();
635
    newAccInfo.status = lrc::api::account::to_status(daemonStatus);
636
637
638
}

void
639
NewAccountModelPimpl::removeFromAccounts(const std::string& accountId)
640
{
641
642
    /* Update db before waiting for the client to stop using the structs is fine
       as long as we don't free anything */
643
644
    auto account = accounts.find(accountId);
    if (account == accounts.end()) {
645
646
        return;
    }
647
    auto& accountInfo = account->second.first;
648
649
650
    /* Inform client about account removal. Do *not* free account structures
       before we are sure that the client stopped using it, otherwise we might
       get into use-after-free troubles. */
651
    accountInfo.valid = false;
652
    emit linked.accountRemoved(accountId);
653
654
655
656
657
658
659
660
661
662

#ifdef CHK_FREEABLE_BEFORE_ERASE_ACCOUNT
    std::unique_lock<std::mutex> lock(m_mutex_account_removal);
    // Wait for client to stop using old account structs
    m_condVar_account_removal.wait(lock, [&](){return accounts[accountId].freeable;});
    lock.unlock();
#endif

    // Now we can free them
    accounts.erase(accountId);
663
664
}

665
666
667
668
669
670
671
672
void
account::Info::fromDetails(const MapStringString& details)
{
    using namespace DRing::Account;
    const MapStringString volatileDetails = ConfigurationManager::instance().getVolatileAccountDetails(id.c_str());

    // General
    if (details[ConfProperties::TYPE] != "")
673
        profileInfo.type                                = details[ConfProperties::TYPE] == QString(ProtocolNames::RING) ? profile::Type::RING : profile::Type::SIP;
674
    registeredName                                      = profileInfo.type == profile::Type::RING ? volatileDetails[VolatileProperties::REGISTERED_NAME].toStdString() : "";
675
    profileInfo.alias                                   = toStdString(details[ConfProperties::DISPLAYNAME]);
676
677
678
679
680
681
    enabled                                             = toBool(details[ConfProperties::ENABLED]);
    confProperties.mailbox                              = toStdString(details[ConfProperties::MAILBOX]);
    confProperties.dtmfType                             = toStdString(details[ConfProperties::DTMF_TYPE]);
    confProperties.autoAnswer                           = toBool(details[ConfProperties::AUTOANSWER]);
    confProperties.activeCallLimit                      = toInt(details[ConfProperties::ACTIVE_CALL_LIMIT]);
    confProperties.hostname                             = toStdString(details[ConfProperties::HOSTNAME]);
682
683
684
    profileInfo.uri                                     = (profileInfo.type == profile::Type::RING and details[ConfProperties::USERNAME].contains("ring:"))
                                                          ? details[ConfProperties::USERNAME].toStdString().substr(std::string("ring:").size())
                                                          : details[ConfProperties::USERNAME].toStdString();
685
    confProperties.username                             = toStdString(details[ConfProperties::USERNAME]);
686
687
688
689
    confProperties.routeset                             = toStdString(details[ConfProperties::ROUTE]);
    confProperties.password                             = toStdString(details[ConfProperties::PASSWORD]);
    confProperties.realm                                = toStdString(details[ConfProperties::REALM]);
    confProperties.localInterface                       = toStdString(details[ConfProperties::LOCAL_INTERFACE]);
690
691
    confProperties.deviceId                             = toStdString(details[ConfProperties::RING_DEVICE_ID]);
    confProperties.deviceName                           = toStdString(details[ConfProperties::RING_DEVICE_NAME]);
692
693
694
695
696
697
698
    confProperties.publishedSameAsLocal                 = toBool(details[ConfProperties::PUBLISHED_SAMEAS_LOCAL]);
    confProperties.localPort                            = toInt(details[ConfProperties::LOCAL_PORT]);
    confProperties.publishedPort                        = toInt(details[ConfProperties::PUBLISHED_PORT]);
    confProperties.publishedAddress                     = toStdString(details[ConfProperties::PUBLISHED_ADDRESS]);
    confProperties.userAgent                            = toStdString(details[ConfProperties::USER_AGENT]);
    confProperties.upnpEnabled                          = toBool(details[ConfProperties::UPNP_ENABLED]);
    confProperties.hasCustomUserAgent                   = toBool(details[ConfProperties::HAS_CUSTOM_USER_AGENT]);
699
700
701
    confProperties.allowIncoming                        = toBool(details[ConfProperties::ALLOW_CERT_FROM_HISTORY])
                                                        | toBool(details[ConfProperties::ALLOW_CERT_FROM_CONTACT])
                                                        | toBool(details[ConfProperties::ALLOW_CERT_FROM_TRUSTED]);
702
703
704
705
706
707
708
    confProperties.archivePassword                      = toStdString(details[ConfProperties::ARCHIVE_PASSWORD]);
    confProperties.archiveHasPassword                   = toBool(details[ConfProperties::ARCHIVE_HAS_PASSWORD]);
    confProperties.archivePath                          = toStdString(details[ConfProperties::ARCHIVE_PATH]);
    confProperties.archivePin                           = toStdString(details[ConfProperties::ARCHIVE_PIN]);
    confProperties.proxyEnabled                         = toBool(details[ConfProperties::PROXY_ENABLED]);
    confProperties.proxyServer                          = toStdString(details[ConfProperties::PROXY_SERVER]);
    confProperties.proxyPushToken                       = toStdString(details[ConfProperties::PROXY_PUSH_TOKEN]);
709
    confProperties.peerDiscovery                        = toBool(details[ConfProperties::DHT_PEER_DISCOVERY]);
710
711
    confProperties.accountDiscovery                     = toBool(details[ConfProperties::ACCOUNT_PEER_DISCOVERY]);
    confProperties.accountPublish                       = toBool(details[ConfProperties::ACCOUNT_PUBLISH]);
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
    // Audio
    confProperties.Audio.audioPortMax                   = toInt(details[ConfProperties::Audio::PORT_MAX]);
    confProperties.Audio.audioPortMin                   = toInt(details[ConfProperties::Audio::PORT_MIN]);
    // Video
    confProperties.Video.videoEnabled                   = toBool(details[ConfProperties::Video::ENABLED]);
    confProperties.Video.videoPortMax                   = toInt(details[ConfProperties::Video::PORT_MAX]);
    confProperties.Video.videoPortMin                   = toInt(details[ConfProperties::Video::PORT_MIN]);
    // STUN
    confProperties.STUN.server                          = toStdString(details[ConfProperties::STUN::SERVER]);
    confProperties.STUN.enable                          = toBool(details[ConfProperties::STUN::ENABLED]);
    // TURN
    confProperties.TURN.server                          = toStdString(details[ConfProperties::TURN::SERVER]);
    confProperties.TURN.enable                          = toBool(details[ConfProperties::TURN::ENABLED]);
    confProperties.TURN.username                        = toStdString(details[ConfProperties::TURN::SERVER_UNAME]);
    confProperties.TURN.password                        = toStdString(details[ConfProperties::TURN::SERVER_PWD]);
    confProperties.TURN.realm                           = toStdString(details[ConfProperties::TURN::SERVER_REALM]);
    // Presence
    confProperties.Presence.presencePublishSupported    = toBool(details[ConfProperties::Presence::SUPPORT_PUBLISH]);
    confProperties.Presence.presenceSubscribeSupported  = toBool(details[ConfProperties::Presence::SUPPORT_SUBSCRIBE]);
    confProperties.Presence.presenceEnabled             = toBool(details[ConfProperties::Presence::ENABLED]);
    // Ringtone
    confProperties.Ringtone.ringtonePath                = toStdString(details[ConfProperties::Ringtone::PATH]);
    confProperties.Ringtone.ringtoneEnabled             = toBool(details[ConfProperties::Ringtone::ENABLED]);
    // SRTP
736
    confProperties.SRTP.keyExchange                     = toStdString(details[ConfProperties::SRTP::KEY_EXCHANGE]).empty()? account::KeyExchangeProtocol::NONE : account::KeyExchangeProtocol::SDES;
737
738
739
740
    confProperties.SRTP.enable                          = toBool(details[ConfProperties::SRTP::ENABLED]);
    confProperties.SRTP.rtpFallback                     = toBool(details[ConfProperties::SRTP::RTP_FALLBACK]);
    // TLS
    confProperties.TLS.listenerPort                     = toInt(details[ConfProperties::TLS::LISTENER_PORT]);
741
    confProperties.TLS.enable                           = details[ConfProperties::TYPE] == QString(ProtocolNames::RING)? true : toBool(details[ConfProperties::TLS::ENABLED]);
742
743
744
745
746
    confProperties.TLS.port                             = toInt(details[ConfProperties::TLS::PORT]);
    confProperties.TLS.certificateListFile              = toStdString(details[ConfProperties::TLS::CA_LIST_FILE]);
    confProperties.TLS.certificateFile                  = toStdString(details[ConfProperties::TLS::CERTIFICATE_FILE]);
    confProperties.TLS.privateKeyFile                   = toStdString(details[ConfProperties::TLS::PRIVATE_KEY_FILE]);
    confProperties.TLS.password                         = toStdString(details[ConfProperties::TLS::PASSWORD]);
747
748
749
750
751
752
753
754
755
756
    auto method = toStdString(details[ConfProperties::TLS::METHOD]);
    if (method == "TLSv1") {
        confProperties.TLS.method                       = account::TlsMethod::TLSv1;
    } else if (method == "TLSv1.1") {
        confProperties.TLS.method                       = account::TlsMethod::TLSv1_1;
    } else if (method == "TLSv1.2") {
        confProperties.TLS.method                       = account::TlsMethod::TLSv1_2;
    } else {
        confProperties.TLS.method                       = account::TlsMethod::DEFAULT;
    }
757
758
759
760
761
762
763
764
765
766
767
768
769
    confProperties.TLS.ciphers                          = toStdString(details[ConfProperties::TLS::CIPHERS]);
    confProperties.TLS.serverName                       = toStdString(details[ConfProperties::TLS::SERVER_NAME]);
    confProperties.TLS.verifyServer                     = toBool(details[ConfProperties::TLS::VERIFY_SERVER]);
    confProperties.TLS.verifyClient                     = toBool(details[ConfProperties::TLS::VERIFY_CLIENT]);
    confProperties.TLS.requireClientCertificate         = toBool(details[ConfProperties::TLS::REQUIRE_CLIENT_CERTIFICATE]);
    confProperties.TLS.negotiationTimeoutSec            = toInt(details[ConfProperties::TLS::NEGOTIATION_TIMEOUT_SEC]);
    // DHT
    confProperties.DHT.port                             = toInt(details[ConfProperties::DHT::PORT]);
    confProperties.DHT.PublicInCalls                    = toBool(details[ConfProperties::DHT::PUBLIC_IN_CALLS]);
    confProperties.DHT.AllowFromTrusted                 = toBool(details[ConfProperties::DHT::ALLOW_FROM_TRUSTED]);
    // RingNS
    confProperties.RingNS.uri                           = toStdString(details[ConfProperties::RingNS::URI]);
    confProperties.RingNS.account                       = toStdString(details[ConfProperties::RingNS::ACCOUNT]);
770
771
    // Registration
    confProperties.Registration.expire                  = toInt(details[ConfProperties::Registration::EXPIRE]);
772
773
    // Jams
    confProperties.managerUri                           = toStdString(details[ConfProperties::MANAGER_URI]);
774
    confProperties.managerUsername                      = toStdString(details[ConfProperties::MANAGER_USERNAME]);
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
}

MapStringString
account::ConfProperties_t::toDetails() const
{
    using namespace DRing::Account;
    MapStringString details;
    // General
    details[ConfProperties::MAILBOX]                    = toQString(this->mailbox);
    details[ConfProperties::DTMF_TYPE]                  = toQString(this->dtmfType);
    details[ConfProperties::AUTOANSWER]                 = toQString(this->autoAnswer);
    details[ConfProperties::ACTIVE_CALL_LIMIT]          = toQString(this->activeCallLimit);
    details[ConfProperties::HOSTNAME]                   = toQString(this->hostname);
    details[ConfProperties::ROUTE]                      = toQString(this->routeset);
    details[ConfProperties::PASSWORD]                   = toQString(this->password);
    details[ConfProperties::REALM]                      = toQString(this->realm);
791
792
    details[ConfProperties::RING_DEVICE_ID]             = toQString(this->deviceId);
    details[ConfProperties::RING_DEVICE_NAME]           = toQString(this->deviceName);
793
794
795
796
797
798
799
800
    details[ConfProperties::LOCAL_INTERFACE]            = toQString(this->localInterface);
    details[ConfProperties::PUBLISHED_SAMEAS_LOCAL]     = toQString(this->publishedSameAsLocal);
    details[ConfProperties::LOCAL_PORT]                 = toQString(this->localPort);
    details[ConfProperties::PUBLISHED_PORT]             = toQString(this->publishedPort);
    details[ConfProperties::PUBLISHED_ADDRESS]          = toQString(this->publishedAddress);
    details[ConfProperties::USER_AGENT]                 = toQString(this->userAgent);
    details[ConfProperties::UPNP_ENABLED]               = toQString(this->upnpEnabled);
    details[ConfProperties::HAS_CUSTOM_USER_AGENT]      = toQString(this->hasCustomUserAgent);
801
802
803
    details[ConfProperties::ALLOW_CERT_FROM_HISTORY]    = toQString(this->allowIncoming);
    details[ConfProperties::ALLOW_CERT_FROM_CONTACT]    = toQString(this->allowIncoming);
    details[ConfProperties::ALLOW_CERT_FROM_TRUSTED]    = toQString(this->allowIncoming);
804
805
806
807
808
809
810
811
    details[ConfProperties::ARCHIVE_PASSWORD]           = toQString(this->archivePassword);
    details[ConfProperties::ARCHIVE_HAS_PASSWORD]       = toQString(this->archiveHasPassword);
    details[ConfProperties::ARCHIVE_PATH]               = toQString(this->archivePath);
    details[ConfProperties::ARCHIVE_PIN]                = toQString(this->archivePin);
    // ConfProperties::DEVICE_NAME name is set with NewDeviceModel interface
    details[ConfProperties::PROXY_ENABLED]              = toQString(this->proxyEnabled);
    details[ConfProperties::PROXY_SERVER]               = toQString(this->proxyServer);
    details[ConfProperties::PROXY_PUSH_TOKEN]           = toQString(this->proxyPushToken);
812
    details[ConfProperties::DHT_PEER_DISCOVERY]         = toQString(this->peerDiscovery);
813
814
    details[ConfProperties::ACCOUNT_PEER_DISCOVERY]     = toQString(this->accountDiscovery);
    details[ConfProperties::ACCOUNT_PUBLISH]            = toQString(this->accountPublish);
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
    // Audio
    details[ConfProperties::Audio::PORT_MAX]            = toQString(this->Audio.audioPortMax);
    details[ConfProperties::Audio::PORT_MIN]            = toQString(this->Audio.audioPortMin);
    // Video
    details[ConfProperties::Video::ENABLED]             = toQString(this->Video.videoEnabled);
    details[ConfProperties::Video::PORT_MAX]            = toQString(this->Video.videoPortMax);
    details[ConfProperties::Video::PORT_MIN]            = toQString(this->Video.videoPortMin);
    // STUN
    details[ConfProperties::STUN::SERVER]               = toQString(this->STUN.server);
    details[ConfProperties::STUN::ENABLED]              = toQString(this->STUN.enable);
    // TURN
    details[ConfProperties::TURN::SERVER]               = toQString(this->TURN.server);
    details[ConfProperties::TURN::ENABLED]              = toQString(this->TURN.enable);
    details[ConfProperties::TURN::SERVER_UNAME]         = toQString(this->TURN.username);
    details[ConfProperties::TURN::SERVER_PWD]           = toQString(this->TURN.password);
    details[ConfProperties::TURN::SERVER_REALM]         = toQString(this->TURN.realm);
    // Presence
    details[ConfProperties::Presence::SUPPORT_PUBLISH]  = toQString(this->Presence.presencePublishSupported);
    details[ConfProperties::Presence::SUPPORT_SUBSCRIBE] = toQString(this->Presence.presenceSubscribeSupported);
    details[ConfProperties::Presence::ENABLED]          = toQString(this->Presence.presenceEnabled);
    // Ringtone
    details[ConfProperties::Ringtone::PATH]             = toQString(this->Ringtone.ringtonePath);
    details[ConfProperties::Ringtone::ENABLED]          = toQString(this->Ringtone.ringtoneEnabled);
    // SRTP
839
    details[ConfProperties::SRTP::KEY_EXCHANGE]         = this->SRTP.keyExchange == account::KeyExchangeProtocol::NONE? "" : "sdes";
840
841
842
843
844
845
846
847
848
849
    details[ConfProperties::SRTP::ENABLED]              = toQString(this->SRTP.enable);
    details[ConfProperties::SRTP::RTP_FALLBACK]         = toQString(this->SRTP.rtpFallback);
    // TLS
    details[ConfProperties::TLS::LISTENER_PORT]         = toQString(this->TLS.listenerPort);
    details[ConfProperties::TLS::ENABLED]               = toQString(this->TLS.enable);
    details[ConfProperties::TLS::PORT]                  = toQString(this->TLS.port);
    details[ConfProperties::TLS::CA_LIST_FILE]          = toQString(this->TLS.certificateListFile);
    details[ConfProperties::TLS::CERTIFICATE_FILE]      = toQString(this->TLS.certificateFile);
    details[ConfProperties::TLS::PRIVATE_KEY_FILE]      = toQString(this->TLS.privateKeyFile);
    details[ConfProperties::TLS::PASSWORD]              = toQString(this->TLS.password);
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
    switch (this->TLS.method) {
    case account::TlsMethod::TLSv1:
        details[ConfProperties::TLS::METHOD]            = "TLSv1";
        break;
    case account::TlsMethod::TLSv1_1:
        details[ConfProperties::TLS::METHOD]            = "TLSv1.1";
        break;
    case account::TlsMethod::TLSv1_2:
        details[ConfProperties::TLS::METHOD]            = "TLSv1.2";
        break;
    case account::TlsMethod::DEFAULT:
    default:
        details[ConfProperties::TLS::METHOD]            = "Default";
        break;
    }
865
866
867
868
869
870
871
872
873
874
875
876
877
    details[ConfProperties::TLS::CIPHERS]               = toQString(this->TLS.ciphers);
    details[ConfProperties::TLS::SERVER_NAME]           = toQString(this->TLS.serverName);
    details[ConfProperties::TLS::VERIFY_SERVER]         = toQString(this->TLS.verifyServer);
    details[ConfProperties::TLS::VERIFY_CLIENT]         = toQString(this->TLS.verifyClient);
    details[ConfProperties::TLS::REQUIRE_CLIENT_CERTIFICATE] = toQString(this->TLS.requireClientCertificate);
    details[ConfProperties::TLS::NEGOTIATION_TIMEOUT_SEC] = toQString(this->TLS.negotiationTimeoutSec);
    // DHT
    details[ConfProperties::DHT::PORT]                  = toQString(this->DHT.port);
    details[ConfProperties::DHT::PUBLIC_IN_CALLS]       = toQString(this->DHT.PublicInCalls);
    details[ConfProperties::DHT::ALLOW_FROM_TRUSTED]    = toQString(this->DHT.AllowFromTrusted);
    // RingNS
    details[ConfProperties::RingNS::URI]                = toQString(this->RingNS.uri);
    details[ConfProperties::RingNS::ACCOUNT]            = toQString(this->RingNS.account);
878
879
    // Registration
    details[ConfProperties::Registration::EXPIRE]       = toQString(this->Registration.expire);
880
881
    // Manager
    details[ConfProperties::MANAGER_URI]                = toQString(this->managerUri);
882
    details[ConfProperties::MANAGER_USERNAME]           = toQString(this->managerUsername);
883
884
885
886

    return details;
}

887
888
889
890
891
std::string
NewAccountModel::createNewAccount(profile::Type type,
                                  const std::string& displayName,
                                  const std::string& archivePath,
                                  const std::string& password,
892
893
                                  const std::string& pin,
                                  const std::string& uri)
894
895
896
897
898
899
900
901
902
903
904
905
906
{

    MapStringString details = type == profile::Type::SIP?
                              ConfigurationManager::instance().getAccountTemplate("SIP") :
                              ConfigurationManager::instance().getAccountTemplate("RING");
    using namespace DRing::Account;
    details[ConfProperties::TYPE] = type == profile::Type::SIP? "SIP" : "RING";
    details[ConfProperties::DISPLAYNAME] = displayName.c_str();
    details[ConfProperties::ALIAS] = displayName.c_str();
    details[ConfProperties::UPNP_ENABLED] = "true";
    details[ConfProperties::ARCHIVE_PASSWORD] = password.c_str();
    details[ConfProperties::ARCHIVE_PIN] = pin.c_str();
    details[ConfProperties::ARCHIVE_PATH] = archivePath.c_str();
907
908
909
    if (type == profile::Type::SIP) {
        details[ConfProperties::USERNAME] = uri.c_str();
    }
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925

    QString accountId = ConfigurationManager::instance().addAccount(details);
    return accountId.toStdString();
}



std::string
NewAccountModel::connectToAccountManager(const std::string& username,
                                         const std::string& password,
                                         const std::string& serverUri)
{
    MapStringString details = ConfigurationManager::instance().getAccountTemplate("RING");
    using namespace DRing::Account;
    details[ConfProperties::TYPE] = "RING";
    details[ConfProperties::MANAGER_URI] = serverUri.c_str();
926
927
    details[ConfProperties::MANAGER_USERNAME] = username.c_str();
    details[ConfProperties::ARCHIVE_PASSWORD] = password.c_str();
928

929
930
931
932
    QString accountId = ConfigurationManager::instance().addAccount(details);
    return accountId.toStdString();
}

933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
void
NewAccountModel::setTopAccount(const std::string& accountId)
{
    bool found = false;
    std::string order = {};

    const QStringList accountIds = ConfigurationManager::instance().getAccountList();
    for (auto& id : accountIds)
    {
        if (id.toStdString() == accountId) {
            found = true;
        } else {
            order += id.toStdString() + "/";
        }
    }
    if (found) {
        order = accountId + "/" + order;
    }
    ConfigurationManager::instance().setAccountsOrder(order.c_str());
}

954
std::string
955
NewAccountModel::accountVCard(const std::string& accountId, bool compressImage) const
956
{
957
958
    auto account = pimpl_->accounts.find(accountId);
    if (account == pimpl_->accounts.end()) {
959
960
        return {};
    }
961
962
    auto& accountInfo = account->second.first;
    return authority::storage::vcard::profileToVcard(accountInfo.profileInfo, compressImage);
963
}
964

Nicolas Jager's avatar
Nicolas Jager committed
965
966
967
} // namespace lrc

#include "api/moc_newaccountmodel.cpp"
968
#include "newaccountmodel.moc"