RingD.cpp 70.9 KB
Newer Older
1
/**************************************************************************
atraczyk's avatar
atraczyk committed
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
* Copyright (C) 2016 by Savoir-faire Linux                                *
* Author: Jäger Nicolas <nicolas.jager@savoirfairelinux.com>              *
* Author: Traczyk Andreas <traczyk.andreas@savoirfairelinux.com>          *
*                                                                         *
* This program is free software; you can redistribute it and/or modify    *
* it under the terms of the GNU General Public License as published by    *
* the Free Software Foundation; either version 3 of the License, or       *
* (at your option) any later version.                                     *
*                                                                         *
* This program 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 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 "pch.h"

Nicolas Jager's avatar
Nicolas Jager committed
21 22
/* daemon */
#include <dring.h>
23
#include "dring/call_const.h"
atraczyk's avatar
atraczyk committed
24 25 26
#include "callmanager_interface.h"
#include "configurationmanager_interface.h"
#include "presencemanager_interface.h"
atraczyk's avatar
atraczyk committed
27
#include "videomanager_interface.h"
atraczyk's avatar
atraczyk committed
28
#include "fileutils.h"
29
#include "account_const.h"
30
#include "string_utils.h"
31
#include "gnutls\gnutls.h"
32
#include "media_const.h"
atraczyk's avatar
atraczyk committed
33 34 35 36

using namespace Windows::ApplicationModel::Core;
using namespace Windows::Storage;
using namespace Windows::UI::Core;
atraczyk's avatar
atraczyk committed
37 38 39
using namespace Windows::Media;
using namespace Windows::Media::MediaProperties;
using namespace Windows::Media::Capture;
40
using namespace Windows::System::Threading;
41 42 43
using namespace Windows::Globalization::DateTimeFormatting;
using namespace Windows::UI::ViewManagement;
using namespace Windows::System;
atraczyk's avatar
atraczyk committed
44 45 46

using namespace RingClientUWP;
using namespace RingClientUWP::Utils;
47
using namespace RingClientUWP::ViewModel;
atraczyk's avatar
atraczyk committed
48 49

void
50
RingD::InternetConnectionChanged(Platform::Object^ sender)
atraczyk's avatar
atraczyk committed
51
{
52 53 54 55 56 57 58 59 60
    hasInternet_ = Utils::hasInternet();
    networkChanged();
    connectivityChanged();
}

RingD::AccountDetailsBlob
RingD::getAllAccountDetails()
{
    RingD::AccountDetailsBlob allAccountDetails;
atraczyk's avatar
atraczyk committed
61
    std::vector<std::string> accountList = DRing::getAccountList();
62 63 64 65 66
    std::for_each(std::cbegin(accountList), std::cend(accountList), [&](const std::string& acc) {
        allAccountDetails[acc] = DRing::getAccountDetails(acc);
    });
    return allAccountDetails;
}
67

68 69 70 71 72 73 74 75 76 77 78 79 80 81
void
RingD::subscribeBuddies()
{
    for (auto account : AccountsViewModel::instance->accountsList) {
        if (Utils::hasInternet()) {
            auto contactListModel = AccountsViewModel::instance->getContactListModel(Utils::toString(account->accountID_));
            for (auto contact : contactListModel->_contactsList) {
                if (!contact->subscribed_) {
                    MSG_("account: " + account->accountID_ + " subscribing to buddy presence for ringID: " + contact->ringID_);
                    subscribeBuddy(Utils::toString(account->accountID_), Utils::toString(contact->ringID_), true);
                    contact->subscribed_ = true;
                }
            }
        }
82
    }
83
}
84

85 86 87 88 89 90 91
void
RingD::parseAccountDetails(const AccountDetailsBlob& allAccountDetails)
{
    std::for_each(std::cbegin(allAccountDetails), std::cend(allAccountDetails),
        [=](std::pair<std::string, AccountDetails> acc) {
        auto accountId = acc.first;
        auto accountDetails = acc.second;
92

93
        auto type = accountDetails.find(DRing::Account::ConfProperties::TYPE)->second;
94 95 96 97
        if (type == "RING") {
            auto  ringID = accountDetails.find(DRing::Account::ConfProperties::USERNAME)->second;
            if (!ringID.empty())
                ringID = ringID.substr(5);
98 99 100
            bool active = (accountDetails.find(DRing::Account::ConfProperties::ENABLED)->second == ring::TRUE_STR)
                ? true
                : false;
101
            bool upnpState = (accountDetails.find(DRing::Account::ConfProperties::UPNP_ENABLED)->second == ring::TRUE_STR)
102 103 104 105 106 107 108 109 110 111 112 113
                ? true
                : false;
            bool autoAnswer = (accountDetails.find(DRing::Account::ConfProperties::AUTOANSWER)->second == ring::TRUE_STR)
                ? true
                : false;
            bool dhtPublicInCalls = (accountDetails.find(DRing::Account::ConfProperties::DHT::PUBLIC_IN_CALLS)->second == ring::TRUE_STR)
                ? true
                : false;
            bool turnEnabled = (accountDetails.find(DRing::Account::ConfProperties::TURN::ENABLED)->second == ring::TRUE_STR)
                ? true
                : false;
            auto turnAddress = accountDetails.find(DRing::Account::ConfProperties::TURN::SERVER)->second;
114 115
            auto alias = accountDetails.find(DRing::Account::ConfProperties::ALIAS)->second;
            auto deviceId = accountDetails.find(DRing::Account::ConfProperties::RING_DEVICE_ID)->second;
116
            auto deviceName = accountDetails.find(DRing::Account::ConfProperties::RING_DEVICE_NAME)->second;
117 118 119 120 121

            auto account = AccountsViewModel::instance->findItem(Utils::toPlatformString(accountId));

            if (account) {
                account->name_ = Utils::toPlatformString(alias);
122
                account->_active = active;
123 124 125
                account->_upnpState = upnpState;
                account->accountType_ = Utils::toPlatformString(type);
                account->ringID_ = Utils::toPlatformString(ringID);
126 127 128 129 130 131
                account->_autoAnswer = autoAnswer;
                account->_turnEnabled = turnEnabled;
                account->_turnAddress = Utils::toPlatformString(turnAddress);
                account->_deviceId = Utils::toPlatformString(deviceId);
                account->_deviceName = Utils::toPlatformString(deviceName);

132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
                // load contact requests for the account
                auto contactRequests = DRing::getTrustRequests(accountId);
                if (auto contactListModel = AccountsViewModel::instance->getContactListModel(std::string(accountId))) {
                    for (auto& cr : contactRequests) {
                        auto ringId = cr.at("from");
                        auto timeReceived = cr.at("received");
                        auto payload = cr.at("payload");
                        auto fromP = Utils::toPlatformString(ringId);
                        auto contact = contactListModel->findContactByRingId(fromP);
                        if (contact == nullptr) {
                            contact = contactListModel->addNewContact(fromP, fromP, TrustStatus::INCOMING_CONTACT_REQUEST, false);

                            contactListModel->saveContactsToFile();
                            AccountsViewModel::instance->raiseUnreadContactRequest();

                            SmartPanelItemsViewModel::instance->refreshFilteredItemsList();
                            SmartPanelItemsViewModel::instance->update(ViewModel::NotifyStrings::notifySmartPanelItem);
                        }
                        else if (ContactRequestItemsViewModel::instance->findItem(contact) == nullptr) {
                            // The name is the ring id for now
                            contact->_name = Utils::toPlatformString(ringId);
                            // The visible ring id will potentially be replaced by a username after a lookup
                            RingD::instance->lookUpAddress(accountId, Utils::toPlatformString(ringId));

                            auto vcard = contact->getVCard();
                            auto parsedPayload = VCardUtils::parseContactRequestPayload(payload);
                            std::string vcpart;
                            try {
                                vcpart.assign(parsedPayload.at("VCARD"));
                            }
                            catch (const std::exception& e) {
                                MSG_(e.what());
                            }
                            if (!vcpart.empty()) {
                                vcard->setData(vcpart);
                                vcard->completeReception();
                                contact->_displayName = Utils::toPlatformString(vcard->getPart("FN"));
                            }

                            auto newContactRequest = ref new ContactRequestItem();
                            newContactRequest->_contact = contact;
                            ContactRequestItemsViewModel::instance->itemsList->InsertAt(0, newContactRequest);

                            ContactRequestItemsViewModel::instance->refreshFilteredItemsList();
                            ContactRequestItemsViewModel::instance->update(ViewModel::NotifyStrings::notifyContactRequestItem);
                        }
                    }
                }
180 181 182
                accountUpdated(account);
            }
            else {
183 184 185 186 187 188 189 190 191 192 193 194 195
                if (!ringID.empty()) {
                    AccountsViewModel::instance->addRingAccount(alias,
                        ringID,
                        accountId,
                        deviceId,
                        deviceName,
                        active,
                        upnpState,
                        autoAnswer,
                        dhtPublicInCalls,
                        turnEnabled,
                        turnAddress);
                }
196
            }
197
        }
198 199
        else { /* SIP */
            auto alias = accountDetails.find(DRing::Account::ConfProperties::ALIAS)->second;
200 201 202
            bool active = (accountDetails.find(DRing::Account::ConfProperties::ENABLED)->second == ring::TRUE_STR)
                ? true
                : false;
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
            auto sipHostname = accountDetails.find(DRing::Account::ConfProperties::HOSTNAME)->second;
            auto sipUsername = accountDetails.find(DRing::Account::ConfProperties::USERNAME)->second;
            auto sipPassword = accountDetails.find(DRing::Account::ConfProperties::PASSWORD)->second;

            auto account = AccountsViewModel::instance->findItem(Utils::toPlatformString(accountId));

            if (account) {
                account->name_ = Utils::toPlatformString(alias);
                account->accountType_ = Utils::toPlatformString(type);
                account->_sipHostname = Utils::toPlatformString(sipHostname);
                account->_sipUsername = Utils::toPlatformString(sipUsername);
                account->_sipPassword = Utils::toPlatformString(sipPassword);
                accountUpdated(account);
            }
            else {
218 219 220 221 222 223
                AccountsViewModel::instance->addSipAccount(alias,
                    accountId,
                    active,
                    sipHostname,
                    sipUsername,
                    sipPassword);
224 225
            }
        }
226 227
    });
}
228

229 230 231 232
void
RingD::connectivityChanged()
{
    DRing::connectivityChanged();
atraczyk's avatar
atraczyk committed
233 234
}

235 236
void
RingD::sendAccountTextMessage(String^ message)
237
{
238 239 240 241 242
    tasks_.add_task([this, message]() {
        if (auto item = SmartPanelItemsViewModel::instance->_selectedItem) {
            auto accountId = AccountListItemsViewModel::instance->_selectedItem->_account->accountID_;
            auto contact = item->_contact;
            auto uri = contact->ringID_;
243

244 245
            auto _accountId = Utils::toString(accountId);
            auto _uri = Utils::toString(uri);
246

247 248 249 250 251
            /* payload(s) */
            IBuffer^ buffUTF8 = CryptographicBuffer::ConvertStringToBinary(message, BinaryStringEncoding::Utf8);
            auto _message = Utils::getData(buffUTF8);
            std::map<std::string, std::string> _payload;
            _payload["text/plain"] = _message;
252

253
            auto sentToken = DRing::sendAccountTextMessage(_accountId, _uri, _payload);
254

255 256 257 258 259 260 261 262 263
            Utils::runOnUIThread([this, sentToken, contact, message]() {
                if (sentToken) {
                    contact->_conversation->addMessage(MSG_FROM_ME, message, std::time(nullptr), false, sentToken.ToString());
                    contact->saveConversationToFile();
                }
            });
        }
    });
}
264

265 266 267 268 269 270 271
void
RingD::sendSIPTextMessage(String^ message)
{
    tasks_.add_task([this, message]() {
        if (auto item = SmartPanelItemsViewModel::instance->_selectedItem) {
            auto accountId = AccountListItemsViewModel::instance->_selectedItem->_account->accountID_;
            auto callId = item->_callId;
272

273 274 275 276 277
            auto _accountId = Utils::toString(accountId);
            auto _callId = Utils::toString(callId);
            auto _message = Utils::toString(message);
            std::map<std::string, std::string> _payload;
            _payload["text/plain"] = _message;
278

279
            DRing::sendTextMessage(_callId, _payload, _accountId, true /*not used*/);
280

281 282 283 284 285 286
            Utils::runOnUIThread([this, item, message]() {
                // No id generated for sip messages within a conversation, so let's generate one
                // so we can track message order.
                auto contact = item->_contact;
                auto messageId = Utils::toPlatformString(Utils::genID(0LL, 9999999999999999999LL));
                contact->_conversation->addMessage(MSG_FROM_ME, message, std::time(nullptr), false, messageId);
287

288 289 290 291
                contact->saveConversationToFile();
            });
        }
    });
292 293
}

294 295
void
RingD::sendSIPTextMessageVCF(std::string callID, std::map<std::string, std::string> message)
296
{
297 298 299 300 301 302
    tasks_.add_task([this, callID, message]() {
        auto accountId = AccountListItemsViewModel::instance->_selectedItem->_account->accountID_;
        auto _accountId = Utils::toString(accountId);
        auto _callId = callID;
        DRing::sendTextMessage(_callId, message, _accountId, true /*not used*/);
    });
303 304
}

305
void
Nicolas Jager's avatar
Nicolas Jager committed
306
RingD::createRINGAccount(String^ alias, String^ archivePassword, bool upnp, String^ registeredName)
307
{
308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326
    tasks_.add_task([this, alias, archivePassword, registeredName]() {
        auto _alias = Utils::toString(alias);
        auto _password = Utils::toString(archivePassword);
        auto _registeredName = Utils::toString(registeredName);

        std::map<std::string, std::string> accountDetails;
        accountDetails.insert(std::make_pair(DRing::Account::ConfProperties::ALIAS, _alias));
        accountDetails.insert(std::make_pair(DRing::Account::ConfProperties::ARCHIVE_PASSWORD, _password));
        accountDetails.insert(std::make_pair(DRing::Account::ConfProperties::TYPE, "RING"));
        accountDetails.insert(std::make_pair(DRing::Account::ConfProperties::UPNP_ENABLED, ring::TRUE_STR));

        Utils::runOnUIThread([this, registeredName]() {
            showLoadingOverlay(ResourceMananger::instance->getStringResource("_m_creating_account_"), SuccessColor);
            isAddingAccount = true;
            if (registeredName != "") {
                shouldRegister = true;
                nameToRegister = registeredName;
            }
        });
327

328 329
        DRing::addAccount(accountDetails);
    });
330 331 332
}

void
333
RingD::createSIPAccount(String^ alias, String^ sipPassword, String^ sipHostname, String^ sipusername)
334
{
335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355
    tasks_.add_task([this, alias, sipPassword, sipHostname, sipusername]() {
        auto _alias = Utils::toString(alias);
        auto _sipPassword = Utils::toString(sipPassword);
        auto _sipHostname = Utils::toString(sipHostname);
        auto _sipUsername = Utils::toString(sipusername);

        std::map<std::string, std::string> accountDetails;
        accountDetails.insert(std::make_pair(DRing::Account::ConfProperties::ALIAS, _alias));
        accountDetails.insert(std::make_pair(DRing::Account::ConfProperties::TYPE, "SIP"));
        accountDetails.insert(std::make_pair(DRing::Account::ConfProperties::PASSWORD, _sipPassword));
        accountDetails.insert(std::make_pair(DRing::Account::ConfProperties::HOSTNAME, _sipHostname));
        accountDetails.insert(std::make_pair(DRing::Account::ConfProperties::USERNAME, _sipUsername));

        Utils::runOnUIThread([this]() {
            showLoadingOverlay(ResourceMananger::instance->getStringResource("_m_creating_account_"), SuccessColor);
            isAddingAccount = true;
        });

        DRing::addAccount(accountDetails);
    });
}
356

357 358 359 360 361 362 363 364
void
RingD::refuseIncommingCall(String^ callId)
{
    tasks_.add_task([this, callId]() {
        auto _callId = Utils::toString(callId);
        DRing::refuse(_callId);
    });
}
365

366 367 368 369 370 371 372 373
void
RingD::acceptIncommingCall(String^ callId)
{
    tasks_.add_task([this, callId]() {
        auto _callId = Utils::toString(callId);
        DRing::accept(_callId);
    });
}
374

375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405
void
RingD::placeCall(Contact^ contact)
{
    tasks_.add_task([this, contact]() {
        auto _accountId = Utils::toString(contact->_accountIdAssociated);
        auto _ringId = Utils::toString(contact->ringID_);
        auto _sipUsername = Utils::toString(contact->_name);

        auto selectedAccount = AccountListItemsViewModel::instance->_selectedItem->_account;
        std::string callId;
        if (selectedAccount->accountType_ == "RING")
            callId = DRing::placeCall(_accountId, "ring:" + _ringId);
        else if (selectedAccount->accountType_ == "SIP")
            callId = DRing::placeCall(_accountId, "sip:" + _sipUsername);

        // TODO: this UI response should be called at state change?
        Utils::runOnUIThread([this, callId, _accountId, _ringId, _sipUsername, selectedAccount]() {
            if (auto contactListModel = AccountsViewModel::instance->getContactListModel(std::string(_accountId))) {
                Contact^ contact;
                if (selectedAccount->accountType_ == "RING")
                    contact = contactListModel->findContactByRingId(Utils::toPlatformString(_ringId));
                else if (selectedAccount->accountType_ == "SIP")
                    contact = contactListModel->findContactByName(Utils::toPlatformString(_sipUsername));
                if (auto item = SmartPanelItemsViewModel::instance->findItem(contact)) {
                    item->_callId = Utils::toPlatformString(callId);
                    if (!callId.empty())
                        callPlaced(Utils::toPlatformString(callId));
                }
            }
        });
    });
406 407
}

408 409
void
RingD::pauseCall(const std::string & callId)
410
{
411 412 413
    tasks_.add_task([this, callId]() {
       DRing::hold(callId);
    });
414 415
}

416 417
void
RingD::pauseCall(String ^ callId)
418
{
419 420 421 422
    tasks_.add_task([this, callId]() {
        auto _callId = Utils::toString(callId);
        DRing::hold(_callId);
    });
423 424
}

425 426
void
RingD::unPauseCall(const std::string & callId)
Nicolas Jager's avatar
Nicolas Jager committed
427
{
428 429 430
    tasks_.add_task([this, callId]() {
        DRing::unhold(callId);
    });
431
}
432

433 434
void
RingD::unPauseCall(String ^ callId)
435
{
436 437 438 439
    tasks_.add_task([this, callId]() {
        auto _callId = Utils::toString(callId);
        DRing::unhold(_callId);
    });
440
}
441

442 443
void
RingD::hangUpCall2(String ^ callId)
444
{
445 446 447 448
    tasks_.add_task([this, callId]() {
        auto _callId = Utils::toString(callId);
        DRing::hangUp(_callId);
    });
449 450
}

451 452
void
RingD::cancelOutGoingCall2(String ^ callId)
453
{
454
    hangUpCall2(callId);
455 456 457
}

void
458
RingD::getKnownDevices(String^ accountId)
459
{
460 461 462 463 464 465 466 467 468 469 470
    tasks_.add_task([this, accountId]() {
        auto _accountId = Utils::toString(accountId);

        auto devicesList = DRing::getKnownRingDevices(_accountId);
        if (devicesList.empty())
            return;

       Utils::runOnUIThread([=]() {
            devicesListRefreshed(Utils::convertMap(devicesList));
        });
    });
471 472 473
}

void
474
RingD::ExportOnRing(String ^ accountId, String ^ password)
475
{
476 477 478 479 480
    tasks_.add_task([this, accountId, password]() {
        auto _accountId = Utils::toString(accountId);
        auto _password = Utils::toString(password);
        DRing::exportOnRing(_accountId, _password);
    });
481 482
}

483 484
void
RingD::updateAccount(String^ accountId)
485
{
486 487
    tasks_.add_task([this, accountId]() {
        auto _accountId = Utils::toString(accountId);
Nicolas Jager's avatar
Nicolas Jager committed
488

489 490 491
        auto account = AccountListItemsViewModel::instance->findItem(accountId)->_account;
        std::map<std::string, std::string> accountDetails = DRing::getAccountDetails(_accountId);
        std::map<std::string, std::string> accountDetailsOld(accountDetails);
492 493
        std::vector<std::map<std::string, std::string>> credentials = DRing::getCredentials(_accountId);
        std::vector<std::map<std::string, std::string>> credentialsOld(credentials);
494

495 496
        accountDetails[DRing::Account::ConfProperties::ALIAS] = Utils::toString(account->name_);
        accountDetails[DRing::Account::ConfProperties::ENABLED] = (account->_active) ? ring::TRUE_STR : ring::FALSE_STR;
497
        accountDetails[DRing::Account::ConfProperties::AUTOANSWER] = (account->_autoAnswer) ? ring::TRUE_STR : ring::FALSE_STR;
498 499 500 501

        bool userNameAdded = false;
        auto newUsername = Utils::toString(account->_username);
        if (accountDetails[DRing::Account::ConfProperties::TYPE] == "RING") {
502 503 504
            if (account->_username != "") {
                auto oldUsername = registeredName(account);
                userNameAdded = newUsername.compare(oldUsername) != 0;
505
            }
506
            accountDetails[DRing::Account::ConfProperties::RING_DEVICE_NAME] = Utils::toString(account->_deviceName);
507 508 509 510 511 512 513
            accountDetails[DRing::Account::ConfProperties::UPNP_ENABLED] = (account->_upnpState) ? ring::TRUE_STR : ring::FALSE_STR;
            accountDetails[DRing::Account::ConfProperties::DHT::PUBLIC_IN_CALLS] = (account->_dhtPublicInCalls) ? ring::TRUE_STR : ring::FALSE_STR;
            accountDetails[DRing::Account::ConfProperties::TURN::ENABLED] = (account->_turnEnabled) ? ring::TRUE_STR : ring::FALSE_STR;
            accountDetails[DRing::Account::ConfProperties::TURN::SERVER] = Utils::toString(account->_turnAddress);
        }
        else {
            accountDetails[DRing::Account::ConfProperties::HOSTNAME] = Utils::toString(account->_sipHostname);
514 515
            credentials.at(0)[DRing::Account::ConfProperties::PASSWORD] = Utils::toString(account->_sipPassword);
            credentials.at(0)[DRing::Account::ConfProperties::USERNAME] = Utils::toString(account->_sipUsername);
516 517
        }

518 519 520 521
        bool detailsChanged = (accountDetails != accountDetailsOld || userNameAdded);
        bool credentialsChanged = (credentials != credentialsOld);

        if (!detailsChanged && !credentialsChanged) {
522 523 524 525 526 527 528 529 530 531
            OnaccountUpdated();
            return;
        }

        Utils::runOnUIThread([this]() {
            isUpdatingAccount = true;
            setOverlayStatusText(ResourceMananger::instance->getStringResource("_m_updating_account_"), SuccessColor);
            mainPage->showLoadingOverlay(true, true);
        });

532 533 534 535
        if (credentialsChanged) {
            DRing::setCredentials(_accountId, credentials);
        }

536 537 538 539 540 541 542
        DRing::setAccountDetails(_accountId, accountDetails);
        if (userNameAdded) {
            registerName(account->accountID_, "", account->_username);
        }

        Configuration::UserPreferences::instance->save();
    });
543 544
}

545 546
void
RingD::deleteAccount(String ^ accountId)
547
{
548 549 550 551 552 553 554 555 556 557 558
    Utils::runOnUIThread([this]() {
        isDeletingAccount = true;
        setOverlayStatusText(ResourceMananger::instance->getStringResource("_m_deleting_account_"), "#ffff0000");
        mainPage->showLoadingOverlay(true, true);
    });

    tasks_.add_task([this, accountId]() {
        auto _accountId = Utils::toString(accountId);

        DRing::removeAccount(_accountId);
    });
559 560
}

561 562
void
RingD::registerThisDevice(String ^ pin, String ^ archivePassword)
563
{
564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579
    Utils::runOnUIThread([this]() {
        showLoadingOverlay(ResourceMananger::instance->getStringResource("_m_creating_account_"), SuccessColor);
        isAddingAccount = true;
    });

    tasks_.add_task([this, pin, archivePassword]() {
        auto _pin = Utils::toString(pin);
        auto _password = Utils::toString(archivePassword);

        std::map<std::string, std::string> deviceDetails;
        deviceDetails.insert(std::make_pair(DRing::Account::ConfProperties::TYPE, "RING"));
        deviceDetails.insert(std::make_pair(DRing::Account::ConfProperties::ARCHIVE_PIN, _pin));
        deviceDetails.insert(std::make_pair(DRing::Account::ConfProperties::ARCHIVE_PASSWORD, _password));

        DRing::addAccount(deviceDetails);
    });
580 581
}

582 583
void
RingD::muteVideo(String ^ callId, bool muted)
584
{
585 586 587 588 589
    tasks_.add_task([this, callId, muted]() {
        auto _callId = Utils::toString(callId);
        DRing::muteLocalMedia(_callId, DRing::Media::Details::MEDIA_TYPE_VIDEO, muted);
    });
}
590

591 592 593 594 595 596 597
void
RingD::muteAudio(const std::string& callId, bool muted)
{
    tasks_.add_task([this, callId, muted]() {
        auto _callId = callId;
        DRing::muteLocalMedia(_callId, DRing::Media::Details::MEDIA_TYPE_AUDIO, muted);
    });
598 599
}

600 601
void
RingD::lookUpName(const std::string& accountId, String^ name)
602
{
603 604 605 606 607 608
    tasks_.add_task([this, accountId, name]() {
        auto _accountId = accountId;
        auto _name = Utils::toString(name);
        DRing::lookupName(_accountId, "", _name);
    });
}
609

610 611 612 613 614 615 616 617
void
RingD::lookUpAddress(const std::string& accountId, String^ address)
{
    tasks_.add_task([this, accountId, address]() {
        auto _accountId = accountId;
        auto _address = Utils::toString(address);
        DRing::lookupAddress(_accountId, "", _address);
    });
618 619
}

620 621
void
RingD::revokeDevice(const std::string& accountId, const std::string& password, const std::string& deviceId)
622
{
623 624 625 626
    Utils::runOnUIThread([this, deviceId]() {
        auto msg = ResourceMananger::instance->getStringResource("_m_revoking_device_");
        showLoadingOverlay(msg + Utils::toPlatformString(deviceId), SuccessColor);
    });
627

628 629 630 631 632 633
    tasks_.add_task([this, accountId, password, deviceId]() {
        auto _accountId = accountId;
        auto _password = password;
        auto _deviceId = deviceId;

        DRing::revokeDevice(_accountId, _password, _deviceId);
634 635 636
    });
}

637 638
void
RingD::registerName(String^ accountId, String^ password, String^ username)
639
{
640 641 642 643
    auto account = AccountsViewModel::instance->findItem(accountId);
    if (!account || account->accountType_ != "RING" || !account->ringID_)
        return;

644 645 646 647
    tasks_.add_task([this, accountId, password, username]() {
        auto _accountId = Utils::toString(accountId);
        auto _password = Utils::toString(password);
        auto _username = Utils::toString(username);
648

649
        bool result;
650

651 652
        result = DRing::registerName(_accountId, _password, _username);
    });
653 654
}

655 656
void
RingD::subscribeBuddy(const std::string& accountId, const std::string& uri, bool flag)
657
{
658 659 660
    tasks_.add_task([this, accountId, uri, flag]() {
        auto _accountId = accountId;
        auto _uri = uri;
661

662 663 664
        DRing::subscribeBuddy(_accountId, _uri, true);
    });
}
665

666 667 668 669 670 671 672 673
void
RingD::removeContact(const std::string& accountId, const std::string& uri)
{
    tasks_.add_task([this, accountId, uri]() {
        auto _accountId = accountId;
        auto _uri = uri;
        DRing::removeContact(_accountId, _uri, false);
    });
674 675
}

676 677
void
RingD::sendContactRequest(const std::string& accountId, const std::string& uri, const std::string& payload)
678
{
679 680 681 682 683 684 685
    tasks_.add_task([this, accountId, uri, payload]() {
        auto _accountId = accountId;
        auto _uri = uri;
        auto _payload = payload;
        std::vector<uint8_t> payload(_payload.begin(), _payload.end());
        DRing::sendTrustRequest(_accountId, _uri, payload);
    });
686 687
}

atraczyk's avatar
atraczyk committed
688
void
689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721
RingD::ShowCallToast(bool background, String^ callId, String^ name)
{
    auto item = SmartPanelItemsViewModel::instance->findItem(callId);

    if (!item)
        return;

    auto bestName = name != nullptr ? name : item->_contact->_bestName2;
    String^ avatarUri = item->_contact->_avatarImage;
    if (avatarUri == nullptr || avatarUri == L" ")
        avatarUri = ref new String(L"ms-appx:///Assets/TESTS/contactAvatar.png");

    String^ xml =
        "<toast scenario='incomingCall'>"
        "<visual> "
        "<binding template='ToastGeneric'>"
        "<image placement='appLogoOverride' hint-crop='circle' src='";

    xml += avatarUri + "'/>";

    xml += "<text>" + bestName + "</text>";

    auto acceptArgString = "a:" + callId;
    auto refuseArgString = "r:" + callId;

    xml +=
        "</binding>"
        "</visual>"
        "<actions>"
        "<action activationType='foreground' arguments= '" + acceptArgString + "' content='Accept' />"
        "<action activationType='foreground' arguments= '" + refuseArgString + "' content='Refuse' />"
        "</actions>"
        "<audio silent='true' loop='true'/></toast>";
atraczyk's avatar
atraczyk committed
722 723

    auto doc = ref new XmlDocument();
724
    doc->LoadXml(xml);
atraczyk's avatar
atraczyk committed
725

726 727 728 729 730 731 732
    toastCall = ref new ToastNotification(doc);
    toastCall->Dismissed += ref new TypedEventHandler<ToastNotification ^, ToastDismissedEventArgs ^>(
        [this](ToastNotification ^sender, ToastDismissedEventArgs ^args) {callToastPopped_ = false; });
    toastCall->Failed += ref new TypedEventHandler<ToastNotification ^, ToastFailedEventArgs ^>(
        [this](ToastNotification ^sender, ToastFailedEventArgs ^args) {callToastPopped_ = false; });
    toaster->Show(toastCall);
    callToastPopped_ = true;
atraczyk's avatar
atraczyk committed
733 734 735
}

void
736
RingD::ShowIMToast(bool background, String^ from, String^ payload, String^ name)
atraczyk's avatar
atraczyk committed
737
{
738 739 740 741 742 743 744 745 746 747 748 749 750
    auto item = SmartPanelItemsViewModel::instance->findItemByRingID(from);

    if (!item)
        return;

    IBuffer^ buffUTF8 = CryptographicBuffer::ConvertStringToBinary(payload, BinaryStringEncoding::Utf8);
    auto binMessage = Utils::toPlatformString(Utils::getData(buffUTF8));

    auto bestName = name != nullptr ? name : item->_contact->_bestName2;
    String^ avatarUri = item->_contact->_avatarImage;
    if (avatarUri == nullptr || avatarUri == L" ")
        avatarUri = ref new String(L"ms-appx:///Assets/TESTS/contactAvatar.png");

atraczyk's avatar
atraczyk committed
751
    String^ xml =
752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771
        "<toast scenario='incomingMessage' duration='short'>"
        "<visual> "
        "<binding template='ToastGeneric'>"
        "<image placement='appLogoOverride' hint-crop='circle' src='";

    xml += avatarUri + "'/>";

    xml += "<text>" + bestName + "</text>";

    xml += "<text>" + binMessage + "</text>";

    xml +=
        "</binding>"
        "</visual>";
        /*"<actions>"
        "<input id='replyTextBox' type='text' placeholderContent='Type a reply'/>"
        "<action content='Reply' arguments='action=reply&amp;convId=9318' activationType='background' hint-inputId='replyTextBox'/>"
        "</actions>";*/

    xml += "<audio src='ms-appx:///Assets/ringtone_notify.wav' loop='false'/></toast>";
atraczyk's avatar
atraczyk committed
772 773 774 775

    auto doc = ref new XmlDocument();
    doc->LoadXml(xml);

776 777
    toastText = ref new ToastNotification(doc);
    toaster->Show(toastText);
atraczyk's avatar
atraczyk committed
778 779
}

780
void
781 782 783 784 785 786 787
RingD::HideToast(ToastNotification^ toast)
{
    toaster->Hide(toast);
}

void
RingD::handleIncomingMessage(   const std::string& callId,
788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822
                                const std::string& accountId,
                                const std::string& from,
                                const std::map<std::string, std::string>& payloads)
{
    auto callId2 = toPlatformString(callId);
    auto accountId2 = toPlatformString(accountId);
    auto from2 = toPlatformString(from);
    from2 = Utils::TrimRingId2(from2);

    auto item = SmartPanelItemsViewModel::instance->findItemByRingID(from2);
    Contact^ contact;

    static const unsigned int profileSize = VCardUtils::PROFILE_VCF.size();
    for (auto i : payloads) {
        if (i.first.compare(0, profileSize, VCardUtils::PROFILE_VCF) == 0) {
            if (item) {
                contact = item->_contact;
                contact->getVCard()->receiveChunk(i.first, i.second);
            }
            else
                WNG_("item not found!");
            return;
        }
        auto payload = Utils::toPlatformString(i.second);
        CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(
            CoreDispatcherPriority::High, ref new DispatchedHandler([=]()
        {
            if (!accountId2->IsEmpty())
                incomingAccountMessage(accountId2, from2, payload);
            else if (!callId2->IsEmpty())
                incomingMessage(callId2, payload);
        }));
    }
}

atraczyk's avatar
atraczyk committed
823
void
824
RingD::registerCallbacks()
atraczyk's avatar
atraczyk committed
825
{
826 827 828 829
    dispatcher = CoreApplication::MainView->CoreWindow->Dispatcher;

    callHandlers = {
        DRing::exportable_callback<DRing::CallSignal::IncomingCall>([this](
830 831 832
                    const std::string& accountId,
                    const std::string& callId,
                    const std::string& from)
833 834 835 836 837
        {
            MSG_("<IncomingCall>");
            MSG_("accountId = " + accountId);
            MSG_("callId = " + callId);
            MSG_("from = " + from);
838

839 840 841
            auto accountId2 = toPlatformString(accountId);
            auto callId2 = toPlatformString(callId);
            auto from2 = toPlatformString(from);
atraczyk's avatar
atraczyk committed
842

843 844
            /* fix some issue in the daemon --> <...@...> */
            from2 = Utils::TrimRingId(from2);
Nicolas Jager's avatar
Nicolas Jager committed
845

846 847
            CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(
                CoreDispatcherPriority::High, ref new DispatchedHandler([=]()
atraczyk's avatar
atraczyk committed
848
            {
849
                auto account = AccountListItemsViewModel::instance->findItem(accountId2)->_account;
850
                if (auto contactListModel = AccountsViewModel::instance->getContactListModel(std::string(accountId))) {
851 852 853 854 855
                    Contact^ contact;
                    if (account->accountType_ == "RING")
                        contact = contactListModel->findContactByRingId(from2);
                    else if (account->accountType_ == "SIP")
                        contact = contactListModel->findContactByName(from2);
856 857 858 859 860
                    if (contact) {
                        auto item = SmartPanelItemsViewModel::instance->findItem(contact);
                        if (item)
                            item->_callId = callId2;
                    }
861
                }
862 863 864 865 866 867 868 869 870 871

                if (account->_autoAnswer) {
                    incomingCall(accountId2, callId2, from2);
                    acceptIncommingCall(callId2);
                    stateChange(callId2, CallStatus::AUTO_ANSWERING, 0);
                }
                else {
                    incomingCall(accountId2, callId2, from2);
                    stateChange(callId2, CallStatus::INCOMING_RINGING, 0);
                }
872 873
            }));
        }),
874 875 876 877 878
        DRing::exportable_callback<DRing::CallSignal::SmartInfo>([this](
            const std::map<std::string, std::string>& info)
        {
            Utils::runOnUIThread([this, info]() {updateSmartInfo(info); });
        }),
879 880 881 882
        DRing::exportable_callback<DRing::CallSignal::PeerHold>([this](
                    const std::string& callId,
                    bool state)
        {
883
            // why does this callback exist ? why are we not using stateChange ?
884 885 886 887 888 889 890 891 892 893 894 895 896
            MSG_("<PeerHold>");
            MSG_("callId = " + callId);
            MSG_("state = " + Utils::toString(state.ToString()));

            CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(
                CoreDispatcherPriority::High, ref new DispatchedHandler([=]()
            {
                if (state)
                    stateChange(Utils::toPlatformString(callId), CallStatus::PEER_PAUSED, 0);
                else
                    stateChange(Utils::toPlatformString(callId), CallStatus::IN_PROGRESS, 0);
            }));
        }),
897 898 899 900
        DRing::exportable_callback<DRing::CallSignal::AudioMuted>([this](
                    const std::string& callId,
                    bool state)
        {
901
            // why does this callback exist ? why are we not using stateChange ?
902 903 904 905 906 907 908 909 910 911
            MSG_("<AudioMuted>");
            MSG_("callId = " + callId);
            MSG_("state = " + Utils::toString(state.ToString()));

            CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(
                CoreDispatcherPriority::High, ref new DispatchedHandler([=]()
            {
                audioMuted(callId, state);
            }));
        }),
912 913 914 915 916 917 918 919 920 921 922 923 924 925 926
        DRing::exportable_callback<DRing::CallSignal::VideoMuted>([this](
                    const std::string& callId,
                    bool state)
        {
            // why this cllaback exist ? why are we not using stateChange ?
            MSG_("<VideoMuted>");
            MSG_("callId = " + callId);
            MSG_("state = " + Utils::toString(state.ToString()));

            CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(
                CoreDispatcherPriority::High, ref new DispatchedHandler([=]()
            {
                videoMuted(callId, state);
            }));
        }),
927 928 929 930 931 932 933 934 935
        DRing::exportable_callback<DRing::CallSignal::StateChange>([this](
                    const std::string& callId,
                    const std::string& state,
                    int code)
        {
            MSG_("<StateChange>");
            MSG_("callId = " + callId);
            MSG_("state = " + state);
            MSG_("code = " + std::to_string(code));
atraczyk's avatar
atraczyk committed
936

937 938 939 940
            auto item = SmartPanelItemsViewModel::instance->findItem(Utils::toPlatformString(callId));
            if (item == nullptr)
                return;

941 942
            auto callId2 = toPlatformString(callId);
            auto state2 = toPlatformString(state);
atraczyk's avatar
atraczyk committed
943

944
            auto state3 = translateCallStatus(state2);
945

946 947
            CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(
                CoreDispatcherPriority::High, ref new DispatchedHandler([=]()
atraczyk's avatar
atraczyk committed
948
            {
949 950 951
                stateChange(callId2, state3, code);
            }));
        }),
952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972
        DRing::exportable_callback<DRing::CallSignal::IncomingMessage>([&](
                    const std::string& callId,
                    const std::string& from,
                    const std::map<std::string, std::string>& payloads)
        {
            MSG_("<IncomingMessage>");
            MSG_("callId = " + callId);
            MSG_("from = " + from);

            handleIncomingMessage(callId, "", from, payloads);
        }),
        DRing::exportable_callback<DRing::DebugSignal::MessageSend>([&](const std::string& msg)
        {
            if (debugModeOn_) {
                DMSG_(msg);
            }
        })
    };
    registerCallHandlers(callHandlers);

    configurationHandlers = {
973 974 975 976 977 978 979 980
        DRing::exportable_callback<DRing::ConfigurationSignal::IncomingAccountMessage>([&](
                    const std::string& accountId,
                    const std::string& from,
                    const std::map<std::string, std::string>& payloads)
        {
            MSG_("<IncomingAccountMessage>");
            MSG_("accountId = " + accountId);
            MSG_("from = " + from);
Nicolas Jager's avatar
Nicolas Jager committed
981

982
            handleIncomingMessage("", accountId, from, payloads);
983
        }),
984 985 986 987 988
        DRing::exportable_callback<DRing::ConfigurationSignal::AccountMessageStatusChanged>([this](
                    const std::string& account_id,
                    uint64_t message_id,
                    const std::string& to,
                    int state)
989
        {
990 991 992 993 994 995 996
            MSG_("<AccountMessageStatusChanged>");
            MSG_("account_id = " + account_id);
            MSG_("message_id = " + message_id);
            MSG_("to = " + Utils::toPlatformString(to));
            MSG_("state = " + state.ToString());
            dispatcher->RunAsync(CoreDispatcherPriority::High,
                ref new DispatchedHandler([=]() {
997

998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013
                // acquittement de message
                auto contactListModel = AccountsViewModel::instance->getContactListModel(std::string(account_id));
                if (auto contact = contactListModel->findContactByRingId(Utils::toPlatformString(to))) {
                    auto conversation = contact->_conversation;
                    if (conversation) {
                        for (const auto& msg : conversation->_messages) {
                            if (msg->MessageIdInteger == message_id &&
                                state == Utils::toUnderlyingValue(DRing::Account::MessageStates::SENT)) {
                                messageStatusUpdated(msg->MessageId, state);
                                msg->IsReceived = true;
                                contact->saveConversationToFile();
                            }
                        }
                    }
                }
            }));
1014 1015 1016 1017 1018 1019 1020
        }),
        DRing::exportable_callback<DRing::ConfigurationSignal::RegistrationStateChanged>([this](
                    const std::string& account_id, const std::string& state,
                    int detailsCode, const std::string& detailsStr)
        {
            MSG_("<RegistrationStateChanged>: ID = " + account_id + " state = " + state);
            if (state == DRing::Account::States::REGISTERED) {
1021 1022 1023 1024 1025 1026 1027
                auto allAccountDetails = getAllAccountDetails();
                Utils::runOnUIThread([this, account_id, allAccountDetails]() {
                    if (auto account = AccountsViewModel::instance->findItem(Utils::toPlatformString(account_id)))
                        account->_registrationState = RegistrationState::REGISTERED;
                    parseAccountDetails(allAccountDetails);
                    subscribeBuddies();
                    if (isAddingAccount)
1028
                        OnaccountAdded(account_id);
1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040
                    else if (isUpdatingAccount)
                        OnaccountUpdated();
                });
            }
            else if (state == DRing::Account::States::UNREGISTERED) {
                auto allAccountDetails = getAllAccountDetails();
                Utils::runOnUIThread([this, account_id, allAccountDetails]() {
                    if (auto account = AccountsViewModel::instance->findItem(Utils::toPlatformString(account_id)))
                        account->_registrationState = RegistrationState::UNREGISTERED;
                    parseAccountDetails(allAccountDetails);
                    registrationStateUnregistered(account_id);
                    if (isAddingAccount)
1041
                        OnaccountAdded(account_id);
1042 1043 1044
                    else if (isUpdatingAccount)
                        OnaccountUpdated();
                });
1045 1046
            }
            else if (state == DRing::Account::States::TRYING) {
1047 1048 1049 1050 1051 1052 1053 1054 1055
                auto allAccountDetails = getAllAccountDetails();
                Utils::runOnUIThread([this, account_id, allAccountDetails]() {
                    if (auto account = AccountsViewModel::instance->findItem(Utils::toPlatformString(account_id)))
                        account->_registrationState = RegistrationState::TRYING;
                    parseAccountDetails(allAccountDetails);
                    subscribeBuddies();
                    Configuration::UserPreferences::instance->load();
                    registrationStateTrying(account_id);
                    if (isAddingAccount)
1056
                        OnaccountAdded(account_id);
1057 1058 1059
                    else if (isUpdatingAccount)
                        OnaccountUpdated();
                });
1060
            }
Nicolas Jager's avatar
Nicolas Jager committed
1061
            else if (state == DRing::Account::States::ERROR_GENERIC
1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073
                || state == DRing::Account::States::ERROR_AUTH
                || state == DRing::Account::States::ERROR_NETWORK
                || state == DRing::Account::States::ERROR_HOST
                || state == DRing::Account::States::ERROR_CONF_STUN
                || state == DRing::Account::States::ERROR_EXIST_STUN
                || state == DRing::Account::States::ERROR_SERVICE_UNAVAILABLE
                || state == DRing::Account::States::ERROR_NOT_ACCEPTABLE
                || state == DRing::Account::States::ERROR_NEED_MIGRATION
                || state == DRing::Account::States::REQUEST_TIMEOUT) {
                auto allAccountDetails = getAllAccountDetails();
                Utils::runOnUIThread([this, account_id, allAccountDetails]() {
                    parseAccountDetails(allAccountDetails);
1074
                    registrationStateErrorGeneric(account_id);
1075
                    if (isAddingAccount)
1076
                        OnaccountAdded(account_id);
1077 1078
                    else if (isUpdatingAccount)
                        OnaccountUpdated();
1079
                });
1080 1081 1082
            }
        }),
        DRing::exportable_callback<DRing::ConfigurationSignal::AccountsChanged>([this]()
1083
        {
1084
            MSG_("<AccountsChanged>");
1085 1086 1087
            if (isDeletingAccount) {
                /*if (AccountListItemsViewModel::instance->itemsList->Size != 0) {
                    accountUpdated(nullptr);
Nicolas Jager's avatar
Nicolas Jager committed
1088
                }*/
1089 1090 1091 1092 1093 1094 1095 1096 1097
                OnaccountDeleted();
            }
            else {
                auto allAccountDetails = getAllAccountDetails();
                Utils::runOnUIThread([this, allAccountDetails]() {
                    parseAccountDetails(allAccountDetails);
                });
            }
        }),
1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111
        DRing::exportable_callback<DRing::ConfigurationSignal::NameRegistrationEnded>([this](
                    const std::string& account_id, int state, const std::string& name)
        {
            MSG_("<NameRegistrationEnded>");
            bool res = state == 0;
            Utils::runOnUIThread([this, res, account_id]() {
                nameRegistered(res, Utils::toPlatformString(account_id));
            });
            if (!res)
                return;
            auto account = AccountsViewModel::instance->findItem(Utils::toPlatformString(account_id));
            account->_username = Utils::toPlatformString(name);
            AccountListItemsViewModel::instance->update({"_username"});
        }),
1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132
        DRing::exportable_callback<DRing::ConfigurationSignal::GetAppDataPath>([this](
                    const std::string& name, std::vector<std::string>* paths)
        {
            paths->emplace_back(localFolder_);
        }),
        DRing::exportable_callback<DRing::ConfigurationSignal::GetDeviceName>([this](
                    std::vector<std::string>* hostNames)
        {
            hostNames->emplace_back(Utils::getHostName());
        }),
        DRing::exportable_callback<DRing::ConfigurationSignal::KnownDevicesChanged>([&](
                    const std::string& accountId, const std::map<std::string, std::string>& devices)
        {
            dispatcher->RunAsync(CoreDispatcherPriority::High,
            ref new DispatchedHandler([=]() {
                if (isAddingDevice) {
                    isAddingDevice = false;
                    hideLoadingOverlay("This device has been successfully added", SuccessColor);
                }
                MSG_("<KnownDevicesChanged>");
                getKnownDevices(Utils::toPlatformString(accountId));
1133 1134
            }));
        }),
1135 1136
        DRing::exportable_callback<DRing::ConfigurationSignal::ExportOnRingEnded>([&](
                    const std::string& accountId, int status, const std::string& pin)
atraczyk's avatar
atraczyk committed
1137
        {
1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222
            auto accountId2 = Utils::toPlatformString(accountId);
            auto pin2 = (pin.empty()) ? "Error bad password" : "Your generated PIN : " + Utils::toPlatformString(pin);
            dispatcher->RunAsync(CoreDispatcherPriority::High,
            ref new DispatchedHandler([=]() {
                exportOnRingEnded(accountId2, pin2);
            }));
        }),
        DRing::exportable_callback<DRing::ConfigurationSignal::RegisteredNameFound>([this](
                    const std::string &accountId, int status, const std::string &address, const std::string &name)
        {
            MSG_("<RegisteredNameFound>" + name + " : " + address + " status=" +std::to_string(status));
            if (accountId.empty() && address.empty() && name.empty())
                return;
            CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(CoreDispatcherPriority::Normal,
            ref new DispatchedHandler([=]() {
                switch (status)
                {
                case 0: // everything went fine. Name/address pair was found.
                    registeredNameFound(LookupStatus::SUCCESS, accountId, address, name);
                    break;
                case 1: // provided name is not valid.
                    registeredNameFound(LookupStatus::INVALID_NAME, accountId, address, name);
                    break;
                case 2: // everything went fine. Name/address pair was not found.
                    registeredNameFound(LookupStatus::NOT_FOUND, accountId, address, name);
                    break;
                case 3: // An error happened
                    registeredNameFound(LookupStatus::ERRORR, accountId, address, name);
                    break;
                }
            }));
        }),
        DRing::exportable_callback<DRing::ConfigurationSignal::VolatileDetailsChanged>([this](
                    const std::string& accountId, const std::map<std::string, std::string>& details)
        {
            ref new DispatchedHandler([=]() {
                volatileDetailsChanged(accountId, details);
            });
        }),
        DRing::exportable_callback<DRing::ConfigurationSignal::IncomingTrustRequest>([&](
                    const std::string& account_id,
                    const std::string& from,
                    const std::vector<uint8_t>& payload,
                    time_t received)
        {
            dispatcher->RunAsync(CoreDispatcherPriority::High,
            ref new DispatchedHandler([=]() {
                auto payloadString = std::string(payload.begin(), payload.end());
                MSG_("IncomingTrustRequest");
                MSG_("account_id = " + account_id);
                MSG_("from = " + from);
                MSG_("received = " + received.ToString());
                MSG_("payload = " + payloadString);

                // First check if this TR has a corresponding contact. If not, add a contact
                // to the account's contact list with a trust status flag indicating that
                // it should be treated as a TR, and only appear in the contact request list.
                if (auto contactListModel = AccountsViewModel::instance->getContactListModel(std::string(account_id))) {
                    auto fromP = Utils::toPlatformString(from);
                    auto contact = contactListModel->findContactByRingId(fromP);

                    // If the contact exists, we should check to see if we have previously
                    // sent a TR to the peer. If, so we can accept this TR immediately.
                    // Otherwise, if it is not already been trusted, we can ignore it completely.
                    if (contact) {
                        if (contact->_trustStatus == TrustStatus::CONTACT_REQUEST_SENT) {
                            // get the vcard first
                            auto vcard = contact->getVCard();
                            auto parsedPayload = VCardUtils::parseContactRequestPayload(payloadString);
                            vcard->setData(parsedPayload.at("VCARD"));
                            vcard->completeReception();

                            DRing::acceptTrustRequest(account_id, from);
                            MSG_("Auto accepted IncomingTrustRequest");
                            return;
                        }
                        else if (contact->_trustStatus != TrustStatus::UNKNOWN) {
                            MSG_("IncomingTrustRequest ignored");
                            return;
                        }
                    }
                    else {
                        // No contact found, so add a new contact with the INCOMNG_CONTACT_REQUEST trust status flag
                        contact = contactListModel->addNewContact("", fromP, TrustStatus::INCOMING_CONTACT_REQUEST, false);
                    }
1223

1224 1225
                    // The visible ring id will potentially be replaced by a username after a lookup
                    RingD::instance->lookUpAddress(account_id, Utils::toPlatformString(from));
1226

1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324
                    auto vcard = contact->getVCard();
                    auto parsedPayload = VCardUtils::parseContactRequestPayload(payloadString);
                    vcard->setData(parsedPayload.at("VCARD"));
                    vcard->completeReception();

                    // The name is the ring id for now
                    contact->_name = Utils::toPlatformString(from);
                    contact->_displayName = Utils::toPlatformString(vcard->getPart("FN"));

                    contactListModel->saveContactsToFile();
                    AccountsViewModel::instance->raiseUnreadContactRequest();

                    SmartPanelItemsViewModel::instance->refreshFilteredItemsList();
                    SmartPanelItemsViewModel::instance->update(ViewModel::NotifyStrings::notifySmartPanelItem);

                    // Add a corresponding contact request control item to the list.
                    auto newContactRequest = ref new ContactRequestItem();
                    newContactRequest->_contact = contact;
                    ContactRequestItemsViewModel::instance->itemsList->InsertAt(0, newContactRequest);

                    ContactRequestItemsViewModel::instance->refreshFilteredItemsList();
                    ContactRequestItemsViewModel::instance->update(ViewModel::NotifyStrings::notifyContactRequestItem);
                }
            }));
        }),
        DRing::exportable_callback<DRing::ConfigurationSignal::ContactAdded>([&](
                    const std::string& account_id, const std::string& uri, bool confirmed)
        {
            dispatcher->RunAsync(CoreDispatcherPriority::High,
            ref new DispatchedHandler([=]() {
                MSG_("ContactAdded");
                MSG_("account_id = " + account_id);
                MSG_("uri = " + uri);
                MSG_("confirmed = " + confirmed.ToString());

                // If confirmed is false, we have just sent the TR and nothing need be done.
                // If confirmed is true, the sent TR has been accepted and we can change the
                // TrustStatus flag for the contact under the account_id, that matches the uri
                if (confirmed) {
                    if (auto contactListModel = AccountsViewModel::instance->getContactListModel(std::string(account_id))) {
                        auto contact = contactListModel->findContactByRingId(Utils::toPlatformString(uri));
                        if (contact == nullptr) {
                            contact = contactListModel->addNewContact(  Utils::toPlatformString(uri),
                                                                        Utils::toPlatformString(uri),
                                                                        TrustStatus::TRUSTED, false);
                            RingD::instance->lookUpAddress(account_id, Utils::toPlatformString(uri));
                        }
                        else {
                            contact->_trustStatus = TrustStatus::TRUSTED;
                        }

                        SmartPanelItemsViewModel::instance->refreshFilteredItemsList();
                        SmartPanelItemsViewModel::instance->update(ViewModel::NotifyStrings::notifySmartPanelItem);
                        ContactRequestItemsViewModel::instance->update(ViewModel::NotifyStrings::notifyContactRequestItem);

                        AccountsViewModel::instance->raiseContactDataModified(Utils::toPlatformString(uri), contact);

                        contactListModel->saveContactsToFile();
                    }
                }
            }));
        }),
        DRing::exportable_callback<DRing::ConfigurationSignal::ContactRemoved>([&](
                    const std::string& account_id, const std::string& uri, bool banned)
        {
            dispatcher->RunAsync(CoreDispatcherPriority::High,
            ref new DispatchedHandler([=]() {
                MSG_("ContactRemoved");
                MSG_("account_id = " + account_id);
                MSG_("uri = " + uri);
                MSG_("banned = " + banned.ToString());

                // It's currently not clear to me how this signal is pertinent to the UWP client
            }));
        }),
        DRing::exportable_callback<DRing::ConfigurationSignal::DeviceRevocationEnded>([&](
                    const std::string& accountId, const std::string& device, int status)
        {
            MSG_("<DeviceRevocationEnded>");
            MSG_("account_id = " + accountId);
            MSG_("device = " + device);
            MSG_("status = " + status.ToString());
            switch (Utils::toEnum<DeviceRevocationResult>(status)) {
            case DeviceRevocationResult::INVALID_CERTIFICATE:
                hideLoadingOverlay("Certificate error while revoking device ID: " + Utils::toPlatformString(device), ErrorColor);
                break;
            case DeviceRevocationResult::INVALID_PASSWORD:
                hideLoadingOverlay("Incorrect account password. Can't revoke device ID: " + Utils::toPlatformString(device), ErrorColor);
                break;
            case DeviceRevocationResult::SUCCESS:
                getKnownDevices(Utils::toPlatformString(accountId));
                hideLoadingOverlay("Device with ID: " + Utils::toPlatformString(device) + " has been successfully revoked", SuccessColor);
                break;
            }
        })/*,
        DRing::exportable_callback<DRing::ConfigurationSignal::GetAppUserName>([this](
                    std::vector<std::string>* unames)
        {
1325 1326 1327 1328
            unames->emplace_back(Utils::toString(
                UserModel::instance->firstName +
                "." +
                UserModel::instance->lastName));
1329
        })*/
1330
    };
1331
    registerConfHandlers(configurationHandlers);
1332

1333 1334 1335 1336
    using namespace Video;
    videoHandlers = {
        DRing::exportable_callback<DRing::VideoSignal::DeviceEvent>([this]()
        {
1337 1338
            MSG_("<DeviceEvent>");
        }),
1339 1340 1341
        DRing::exportable_callback<DRing::VideoSignal::DecodingStarted>([&](
                    const std::string &id, const std::string &shmPath, int width, int height, bool isMixer)
        {
1342 1343 1344 1345 1346 1347 1348 1349 1350 1351
            dispatcher->RunAsync(CoreDispatcherPriority::High,
            ref new DispatchedHandler([=]() {
                Video::VideoManager::instance->rendererManager()->startedDecoding(
                    Utils::toPlatformString(id),
                    width,
                    height);
                auto callId2 = Utils::toPlatformString(id);
                incomingVideoMuted(callId2, false);
            }));
        }),
1352 1353 1354
        DRing::exportable_callback<DRing::VideoSignal::DecodingStopped>([&](
                    const std::string &id, const std::string &shmPath, bool isMixer)
        {
1355 1356 1357 1358 1359 1360
            dispatcher->RunAsync(CoreDispatcherPriority::High,
            ref new DispatchedHandler([=]() {
                Video::VideoManager::instance->rendererManager()->removeRenderer(Utils::toPlatformString(id));
                auto callId2 = Utils::toPlatformString(id);
                incomingVideoMuted(callId2, true);
            }));
1361 1362 1363 1364
        }),
            DRing::exportable_callback<DRing::VideoSignal::DeviceAdded>([this](
                        const std::string& device)
        {
1365
            MSG_("<DeviceAdded>");
1366
        }),
1367 1368 1369
        DRing::exportable_callback<DRing::VideoSignal::ParametersChanged>([&](
                    const std::string& device)
        {
1370 1371
            dispatcher->RunAsync(CoreDispatcherPriority::High,
            ref new DispatchedHandler([=]() {
1372 1373
                MSG_("<ParametersChanged>");
                auto settings = DRing::getDeviceParams(device);
1374
                VideoManager::instance->captureManager()->activeDevice->SetDeviceProperties(
1375 1376 1377 1378
                    Utils::toPlatformString(settings["format"]),
                    stoi(settings["width"]),
                    stoi(settings["height"]),
                    stoi(settings["rate"]));
1379 1380
            }));
        }),
1381 1382 1383
        DRing::exportable_callback<DRing::VideoSignal::StartCapture>([&](
                    const std::string& device)
        {
1384 1385 1386 1387 1388 1389
            dispatcher->RunAsync(CoreDispatcherPriority::High,
            ref new DispatchedHandler([=]() {
                VideoManager::instance->captureManager()->InitializeCameraAsync(false);
                VideoManager::instance->captureManager()->videoFrameCopyInvoker->Start();
            }));
        }),
1390 1391
        DRing::exportable_callback<DRing::VideoSignal::StopCapture>([&]()
        {
1392 1393 1394 1395 1396 1397 1398 1399 1400
            dispatcher->RunAsync(CoreDispatcherPriority::High,
            ref new DispatchedHandler([=]() {
                VideoManager::instance->captureManager()->StopPreviewAsync();
                if (VideoManager::instance->captureManager()->captureTaskTokenSource)
                    VideoManager::instance->captureManager()->captureTaskTokenSource->cancel();
                VideoManager::instance->captureManager()->videoFrameCopyInvoker->Stop();
            }));
        })
    };
1401
    registerVideoHandlers(videoHandlers);
1402

1403 1404 1405
    presenceHandlers = {
        DRing::exportable_callback<DRing::PresenceSignal::NewBuddyNotification>([&](
                    const std::string& account_id, const std::string& buddy_uri, int status, const std::string& /*line_status*/)
Nicolas Jager's avatar
Nicolas Jager committed
1406 1407
        {
            dispatcher->RunAsync(CoreDispatcherPriority::High,
1408 1409 1410 1411 1412 1413 1414 1415 1416 1417
                ref new DispatchedHandler([=]() {
                MSG_("NewBuddyNotification");
                MSG_("account_id = " + account_id);
                MSG_("uri = " + buddy_uri);
                MSG_("status = " + status);
                // react to presence
                dispatcher->RunAsync(CoreDispatcherPriority::High,
                    ref new DispatchedHandler([=]() {
                    newBuddyNotification(account_id, buddy_uri, status);
                }));
Nicolas Jager's avatar
Nicolas Jager committed
1418
            }));
1419 1420
        })
    };
1421 1422 1423 1424
    registerPresHandlers(presenceHandlers);
}

void
1425
RingD::OnaccountAdded(const std::string& accountId)
1426
{
1427 1428 1429 1430
    if (shouldRegister) {
        shouldRegister = false;
        registerName(Utils::toPlatformString(accountId), "", nameToRegister);
    }
1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455
    isAddingAccount = false;
    hideLoadingOverlay("Account created successfully", SuccessColor, 2000);
    Configuration::UserPreferences::instance->raiseSelectIndex(0);
    Configuration::UserPreferences::instance->save();
}

void
RingD::OnaccountUpdated()
{
    isUpdatingAccount = false;
    hideLoadingOverlay("Account updated successfully", SuccessColor, 500);
}

void
RingD::OnaccountDeleted()
{
    isDeletingAccount = false;
    if (AccountListItemsViewModel::instance->itemsList->Size == 0) {
        auto configFile = RingD::instance->getLocalFolder() + ".config\\dring.yml";
        Utils::fileDelete(configFile);
        Utils::runOnUIThreadDelayed(100,[this]() {summonWizard(); });
    }
    else {
        hideLoadingOverlay("Account deleted successfully", SuccessColor, 500);
    }
1456
}
atraczyk's avatar
atraczyk committed
1457

1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468
void
RingD::init()
{
    if (daemonInitialized_) {
        CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(CoreDispatcherPriority::Normal,
        ref new DispatchedHandler([=]() {
            finishCaptureDeviceEnumeration();
        }));
        return;
    }

1469 1470
    setOverlayStatusText("Starting Ring...", "#ff000000");

1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485
    gnutls_global_init();
    RingD::instance->registerCallbacks();
    RingD::instance->initDaemon( DRing::DRING_FLAG_CONSOLE_LOG | DRing::DRING_FLAG_DEBUG );
    Video::VideoManager::instance->captureManager()->EnumerateWebcamsAsync();

    daemonInitialized_ = true;
}

void
RingD::deinit()
{
    DRing::fini();
    gnutls_global_deinit();
}

1486 1487 1488 1489 1490
void
RingD::initDaemon(int flags)
{
    DRing::init(static_cast<DRing::InitFlag>(flags));
}
1491

1492 1493 1494 1495 1496 1497 1498
void
RingD::startDaemon()
{
    if (daemonRunning_) {
        ERR_("daemon already runnging");
        return;
    }
atraczyk's avatar
atraczyk committed
1499

1500 1501
    IAsyncAction^ action = ThreadPool::RunAsync(ref new WorkItemHandler([=](IAsyncAction^ spAction)
    {
1502 1503 1504 1505 1506 1507 1508
        CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(CoreDispatcherPriority::Normal,
            ref new DispatchedHandler([=]() {
            if (!isInWizard) {
                setOverlayStatusText("Loading from config...", "#ff000000");
            }
        }));

1509
        daemonRunning_ = DRing::start();
1510

1511
        auto vcm = Video::VideoManager::instance->captureManager();
1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528
        if (vcm->deviceList->Size > 0) {
            std::string deviceName = DRing::getDefaultDevice();
            std::map<std::string, std::string> settings = DRing::getSettings(deviceName);
            int rate = stoi(settings["rate"]);
            std::string size = settings["size"];
            std::string::size_type pos = size.find('x');
            int width = std::stoi(size.substr(0, pos));
            int height = std::stoi(size.substr(pos + 1, size.length()));
            for (auto dev : vcm->deviceList) {
                if (!Utils::toString(dev->name()).compare(deviceName))
                    vcm->activeDevice = dev;
            }
            vcm->activeDevice->SetDeviceProperties("", width, height, rate);
            CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(CoreDispatcherPriority::Normal,
            ref new DispatchedHandler([=]() {
                finishCaptureDeviceEnumeration();
            }));
1529 1530
        }

1531
        if (!daemonRunning_) {
atraczyk's avatar
atraczyk committed
1532 1533 1534 1535
            ERR_("\ndaemon didn't start.\n");
            return;
        }
        else {
1536 1537 1538 1539 1540 1541 1542 1543 1544 1545
            switch (_startingStatus) {
            case StartingStatus::REGISTERING_ON_THIS_PC:
            case StartingStatus::REGISTERING_THIS_DEVICE:
            {
                break;
            }
            case StartingStatus::NORMAL:
            default:
            {
                break;
atraczyk's avatar
atraczyk committed
1546
            }
1547 1548
            }

1549
            /* at this point the config.yml is safe. */
1550 1551 1552 1553
            std::string tokenFile = localFolder_ + "\\creation.token";
            if (fileExists(tokenFile)) {
                fileDelete(tokenFile);
            }
1554

1555 1556 1557 1558
            if (!isInWizard) {
                hideLoadingOverlay("Ring started successfully", SuccessColor, 1000);
            }

Nicolas Jager's avatar
Nicolas Jager committed
1559
            while (daemonRunning) {
atraczyk's avatar
atraczyk committed
1560
                DRing::pollEvents();