blob: 2508fb8d2d5f1ce461a82e78c4398f2a7b681d88 [file] [log] [blame]
Nicolas Jager6e30ad82016-08-26 13:00:27 -04001/**************************************************************************
atraczykb724d332016-08-30 15:25:59 -04002* Copyright (C) 2016 by Savoir-faire Linux *
3* Author: Jäger Nicolas <nicolas.jager@savoirfairelinux.com> *
4* Author: Traczyk Andreas <traczyk.andreas@savoirfairelinux.com> *
5* *
6* This program is free software; you can redistribute it and/or modify *
7* it under the terms of the GNU General Public License as published by *
8* the Free Software Foundation; either version 3 of the License, or *
9* (at your option) any later version. *
10* *
11* This program is distributed in the hope that it will be useful, *
12* but WITHOUT ANY WARRANTY; without even the implied warranty of *
13* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14* GNU General Public License for more details. *
15* *
16* You should have received a copy of the GNU General Public License *
17* along with this program. If not, see <http://www.gnu.org/licenses/>. *
18**************************************************************************/
19#include "pch.h"
20
21/* daemon */
22#include <dring.h>
23#include "callmanager_interface.h"
24#include "configurationmanager_interface.h"
25#include "presencemanager_interface.h"
26#include "fileutils.h"
atraczykb724d332016-08-30 15:25:59 -040027#include "account_schema.h"
atraczyk196936e2016-09-02 15:31:53 -040028#include "account_const.h"
atraczykb724d332016-08-30 15:25:59 -040029
30#include "SmartPanel.xaml.h"
31
32using namespace Windows::ApplicationModel::Core;
33using namespace Windows::Storage;
34using namespace Windows::UI::Core;
35
36using namespace RingClientUWP;
37using namespace RingClientUWP::Utils;
Nicolas Jager655df542016-08-31 10:24:47 -040038using namespace RingClientUWP::ViewModel;
atraczykb724d332016-08-30 15:25:59 -040039
40void
atraczykb724d332016-08-30 15:25:59 -040041RingClientUWP::RingD::reloadAccountList()
42{
43 RingClientUWP::ViewModel::AccountsViewModel::instance->clearAccountList();
44 std::vector<std::string> accountList = DRing::getAccountList();
45 std::vector<std::string>::reverse_iterator rit = accountList.rbegin();
46 for (; rit != accountList.rend(); ++rit) {
47 std::map<std::string,std::string> accountDetails = DRing::getAccountDetails(*rit);
48 std::string ringID(accountDetails.find(ring::Conf::CONFIG_ACCOUNT_USERNAME)->second);
49 if(!ringID.empty())
50 ringID = ringID.substr(5);
51 RingClientUWP::ViewModel::AccountsViewModel::instance->add(
52 accountDetails.find(ring::Conf::CONFIG_ACCOUNT_ALIAS)->second, //name
53 ringID, //ringid
atraczyk797fa1a2016-08-31 09:55:53 -040054 accountDetails.find(ring::Conf::CONFIG_ACCOUNT_TYPE)->second, //type
55 *rit);
atraczykb724d332016-08-30 15:25:59 -040056 }
57 // load user preferences
58 Configuration::UserPreferences::instance->load();
59}
60
Nicolas Jager655df542016-08-31 10:24:47 -040061/* nb: send message during conversation not chat video message */
62void RingClientUWP::RingD::sendAccountTextMessage(String^ message)
63{
64 /* account id */
65 auto accountId = AccountsViewModel::instance->selectedAccount->accountID_;
66 std::wstring accountId2(accountId->Begin());
67 std::string accountId3(accountId2.begin(), accountId2.end());
68
69 /* recipient */
Nicolas Jagerc551c362016-10-01 19:24:50 -040070 auto item = SmartPanelItemsViewModel::instance->_selectedItem;
71 auto contact = item->_contact;
Nicolas Jager655df542016-08-31 10:24:47 -040072 auto toRingId = contact->ringID_;
73 std::wstring toRingId2(toRingId->Begin());
74 std::string toRingId3(toRingId2.begin(), toRingId2.end());
75
76 /* payload(s) */
77 std::wstring message2(message->Begin());
78 std::string message3(message2.begin(), message2.end());
79 std::map<std::string, std::string> payloads;
80 payloads["text/plain"] = message3;
81
82 /* daemon */
83 auto sent = DRing::sendAccountTextMessage(accountId3, toRingId3, payloads);
84
85 /* conversation */
86 if (sent) {
87 contact->_conversation->addMessage(""/* date not yet used*/, MSG_FROM_ME, message);
atraczykf5be5462016-08-31 14:23:06 -040088
89 /* save contacts conversation to disk */
90 contact->saveConversationToFile();
91
Nicolas Jager655df542016-08-31 10:24:47 -040092 } else {
93 WNG_("message not sent, see daemon outputs");
94 }
95}
96
atraczykb724d332016-08-30 15:25:59 -040097void
atraczyk196936e2016-09-02 15:31:53 -040098RingD::createRINGAccount(String^ alias)
99{
Nicolas Jagerf6a10322016-09-06 08:17:49 -0400100 // refactoring : create a dedicated class constructor task and removes accountName from RingD
atraczyk196936e2016-09-02 15:31:53 -0400101 accountName = Utils::toString(alias);
102 tasksList_.push(ref new RingD::Task(Request::AddRingAccount));
103}
104
105void
106RingD::createSIPAccount(String^ alias)
107{
Nicolas Jagerf6a10322016-09-06 08:17:49 -0400108 // refactoring : create a dedicated class constructor task and removes accountName from RingD
atraczyk196936e2016-09-02 15:31:53 -0400109 accountName = Utils::toString(alias);
110 tasksList_.push(ref new RingD::Task(Request::AddSIPAccount));
111}
112
Nicolas Jagerf6a10322016-09-06 08:17:49 -0400113void RingClientUWP::RingD::refuseIncommingCall(Call^ call)
114{
115 tasksList_.push(ref new RingD::Task(Request::RefuseIncommingCall, call));
116}
117
118void RingClientUWP::RingD::acceptIncommingCall(Call^ call)
119{
120 tasksList_.push(ref new RingD::Task(Request::AcceptIncommingCall, call));
121}
122
Nicolas Jager5750df02016-09-13 11:20:33 -0400123void RingClientUWP::RingD::placeCall(Contact^ contact)
124{
125 auto to = contact->ringID_;
126 auto accountId = AccountsViewModel::instance->selectedAccount->accountID_;
127
128 auto to2 = Utils::toString(to);
129 auto accountId2 = Utils::toString(accountId);
130
131 auto callId2 = DRing::placeCall(accountId2, to2);
132
133 if (callId2 == "") {
134 WNG_("call not created, the daemon didn't return a call Id");
135 return;
136 }
137
138 auto callId = Utils::toPlatformString(callId2);
139
140 auto call = CallsViewModel::instance->addNewCall(accountId, callId, to);
141 call->isOutGoing = true;
142
143 if (call == nullptr) {
144 WNG_("call not created, nullptr reason");
145 return;
146 }
147
148 calling(call);
149
150}
151
152void
153RingClientUWP::RingD::cancelOutGoingCall(Call^ call)
154{
155 tasksList_.push(ref new RingD::Task(Request::CancelOutGoingCall, call));
156}
157
atraczyk196936e2016-09-02 15:31:53 -0400158void
Nicolas Jager121bdf32016-09-13 12:12:15 -0400159RingClientUWP::RingD::hangUpCall(Call^ call)
160{
161 tasksList_.push(ref new RingD::Task(Request::HangUpCall, call));
162}
163
164void
atraczykb724d332016-08-30 15:25:59 -0400165RingClientUWP::RingD::startDaemon()
166{
Nicolas Jagerd76940f2016-08-31 14:44:04 -0400167 // TODO (during refactoring) : use namespace
168 /* clear the calls list and instantiate the singleton (required) */
169 RingClientUWP::ViewModel::CallsViewModel::instance->clearCallsList();
170
atraczykb724d332016-08-30 15:25:59 -0400171 create_task([&]()
172 {
173 using SharedCallback = std::shared_ptr<DRing::CallbackWrapperBase>;
174 using namespace std::placeholders;
175
Nicolas Jagerd83bc542016-09-16 12:07:31 -0400176 auto dispatcher = CoreApplication::MainView->CoreWindow->Dispatcher;
177
atraczykb724d332016-08-30 15:25:59 -0400178 std::map<std::string, SharedCallback> callHandlers = {
179 // use IncomingCall only to register the call client sided, use StateChange to determine the impact on the UI
180 DRing::exportable_callback<DRing::CallSignal::IncomingCall>([this](
181 const std::string& accountId,
182 const std::string& callId,
183 const std::string& from)
184 {
185 MSG_("<IncomingCall>");
186 MSG_("accountId = " + accountId);
187 MSG_("callId = " + callId);
188 MSG_("from = " + from);
189
190 auto accountId2 = toPlatformString(accountId);
191 auto callId2 = toPlatformString(callId);
192 auto from2 = toPlatformString(from);
193
Nicolas Jagerf494bda2016-09-16 08:43:43 -0400194 /* fix some issue in the daemon --> <...@...> */
195 from2 = Utils::TrimRingId(from2);
196
Nicolas Jagerd76940f2016-08-31 14:44:04 -0400197 CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(
198 CoreDispatcherPriority::Normal, ref new DispatchedHandler([=]()
199 {
200 incomingCall(accountId2, callId2, from2);
Nicolas Jagerc551c362016-10-01 19:24:50 -0400201 stateChange(callId2, CallStatus::INCOMING_RINGING, 0);
Nicolas Jagerd76940f2016-08-31 14:44:04 -0400202 }));
atraczykb724d332016-08-30 15:25:59 -0400203 }),
204 DRing::exportable_callback<DRing::CallSignal::StateChange>([this](
Nicolas Jagerd76940f2016-08-31 14:44:04 -0400205 const std::string& callId,
206 const std::string& state,
207 int code)
atraczykb724d332016-08-30 15:25:59 -0400208 {
209 MSG_("<StateChange>");
210 MSG_("callId = " + callId);
211 MSG_("state = " + state);
212 MSG_("code = " + std::to_string(code));
213
214 auto callId2 = toPlatformString(callId);
215 auto state2 = toPlatformString(state);
216
Nicolas Jagerc551c362016-10-01 19:24:50 -0400217 auto state3 = getCallStatus(state2);
218
atraczykb724d332016-08-30 15:25:59 -0400219
Nicolas Jagerd76940f2016-08-31 14:44:04 -0400220 CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(
221 CoreDispatcherPriority::Low, ref new DispatchedHandler([=]()
222 {
Nicolas Jagerc551c362016-10-01 19:24:50 -0400223 stateChange(callId2, state3, code);
Nicolas Jagerd76940f2016-08-31 14:44:04 -0400224 }));
atraczykb724d332016-08-30 15:25:59 -0400225 }),
Nicolas Jager6e30ad82016-08-26 13:00:27 -0400226 DRing::exportable_callback<DRing::ConfigurationSignal::IncomingAccountMessage>([&](
Nicolas Jagerd76940f2016-08-31 14:44:04 -0400227 const std::string& accountId,
228 const std::string& from,
229 const std::map<std::string, std::string>& payloads)
atraczykb724d332016-08-30 15:25:59 -0400230 {
231 MSG_("<IncomingAccountMessage>");
232 MSG_("accountId = " + accountId);
233 MSG_("from = " + from);
234
Nicolas Jager6e30ad82016-08-26 13:00:27 -0400235 auto accountId2 = toPlatformString(accountId);
236 auto from2 = toPlatformString(from);
237
atraczykb724d332016-08-30 15:25:59 -0400238 for (auto i : payloads) {
239 MSG_("payload = " + i.second);
240 auto payload = Utils::toPlatformString(i.second);
Nicolas Jager6e30ad82016-08-26 13:00:27 -0400241 CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(
242 CoreDispatcherPriority::Low, ref new DispatchedHandler([=]()
243 {
244 incomingAccountMessage(accountId2, from2, payload);
245 }));
atraczykb724d332016-08-30 15:25:59 -0400246 }
247 }),
atraczyk5c395ea2016-09-20 17:28:09 -0400248 DRing::exportable_callback<DRing::CallSignal::IncomingMessage>([&](
249 const std::string& callId,
250 const std::string& from,
251 const std::map<std::string, std::string>& payloads)
252 {
253 MSG_("<IncomingMessage>");
254 MSG_("callId = " + callId);
255 MSG_("from = " + from);
256
257 auto callId2 = toPlatformString(callId);
258 auto from2 = toPlatformString(from);
259
260 from2 = Utils::TrimRingId2(from2);
261
262 Call^ call = CallsViewModel::instance->findCall(callId2);
263
264 if (!call)
265 return;
266
267 String^ accountId2 = call->accountId;
268 const std::string PROFILE_VCF = "x-ring/ring.profile.vcard";
269 static const unsigned int profileSize = PROFILE_VCF.size();
270
271 for (auto i : payloads) {
272 if (i.first.compare(0, profileSize, PROFILE_VCF) == 0) {
273 MSG_("VCARD");
274 return;
275 }
276 MSG_("payload.first = " + i.first);
277 MSG_("payload.second = " + i.second);
278
279 auto payload = Utils::toPlatformString(i.second);
280 CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(
281 CoreDispatcherPriority::Low, ref new DispatchedHandler([=]()
282 {
283 incomingAccountMessage(accountId2, from2, payload);
284 }));
285 }
286 }),
atraczyk196936e2016-09-02 15:31:53 -0400287 DRing::exportable_callback<DRing::ConfigurationSignal::RegistrationStateChanged>([this](
Nicolas Jagerf6a10322016-09-06 08:17:49 -0400288 const std::string& account_id, const std::string& state,
289 int detailsCode, const std::string& detailsStr)
atraczyk196936e2016-09-02 15:31:53 -0400290 {
291 MSG_("<RegistrationStateChanged>: ID = " + account_id + "state = " + state);
atraczyk1ddcb5a2016-09-07 16:18:30 -0400292 if (state == DRing::Account::States::REGISTERED) {
atraczyk196936e2016-09-02 15:31:53 -0400293 CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(CoreDispatcherPriority::Normal,
Nicolas Jagerf6a10322016-09-06 08:17:49 -0400294 ref new DispatchedHandler([=]() {
atraczyk1ddcb5a2016-09-07 16:18:30 -0400295 auto frame = dynamic_cast<Frame^>(Window::Current->Content);
296 dynamic_cast<RingClientUWP::MainPage^>(frame->Content)->showLoadingOverlay(false, false);
atraczyk196936e2016-09-02 15:31:53 -0400297 }));
298 }
299 }),
atraczykb724d332016-08-30 15:25:59 -0400300 DRing::exportable_callback<DRing::ConfigurationSignal::AccountsChanged>([this]()
301 {
302 CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(CoreDispatcherPriority::Normal,
Nicolas Jager655df542016-08-31 10:24:47 -0400303 ref new DispatchedHandler([=]() {
atraczykb724d332016-08-30 15:25:59 -0400304 reloadAccountList();
305 }));
Nicolas Jager5750df02016-09-13 11:20:33 -0400306 }),
Nicolas Jagerd83bc542016-09-16 12:07:31 -0400307 DRing::exportable_callback<DRing::Debug::MessageSend>([&](const std::string& toto)
308 {
309 dispatcher->RunAsync(CoreDispatcherPriority::Normal,
310 ref new DispatchedHandler([=]() {
311 RingDebug::instance->print(toto);
312 }));
313 })
Nicolas Jager5750df02016-09-13 11:20:33 -0400314 /* to remove from daemon API, this callback is never used */
315 //DRing::exportable_callback<DRing::CallSignal::NewCallCreated>([&](
316 // const std::string& accountId,
317 // const std::string& callId,
318 // const std::string& to)
319 //{ /*...*/ })
atraczykb724d332016-08-30 15:25:59 -0400320 };
321
322 registerCallHandlers(callHandlers);
323
atraczykb724d332016-08-30 15:25:59 -0400324 std::map<std::string, SharedCallback> getAppPathHandler =
325 {
326 DRing::exportable_callback<DRing::ConfigurationSignal::GetAppDataPath>
327 ([this](std::vector<std::string>* paths) {
328 paths->emplace_back(localFolder_);
329 })
330 };
331 registerCallHandlers(getAppPathHandler);
332
Nicolas Jageraef65722016-09-06 08:30:14 -0400333 DRing::init(static_cast<DRing::InitFlag>(DRing::DRING_FLAG_CONSOLE_LOG |
Nicolas Jagerf6a10322016-09-06 08:17:49 -0400334 DRing::DRING_FLAG_DEBUG));
atraczykb724d332016-08-30 15:25:59 -0400335
336 if (!DRing::start()) {
337 ERR_("\ndaemon didn't start.\n");
338 return;
339 }
340 else {
341 if (!hasConfig)
342 {
atraczyk4464ace2016-09-01 09:37:37 -0400343 tasksList_.push(ref new RingD::Task(Request::AddRingAccount));
344 tasksList_.push(ref new RingD::Task(Request::AddSIPAccount));
atraczykb724d332016-08-30 15:25:59 -0400345 }
346 else {
347 CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(CoreDispatcherPriority::Normal,
Nicolas Jager655df542016-08-31 10:24:47 -0400348 ref new DispatchedHandler([=]() {
atraczykb724d332016-08-30 15:25:59 -0400349 reloadAccountList();
350 }));
351 }
352 while (true) {
353 DRing::pollEvents();
354 Sleep(1000);
355 dequeueTasks();
356 }
357 DRing::fini();
358 }
359 });
360}
361
362RingD::RingD()
363{
364 localFolder_ = Utils::toString(ApplicationData::Current->LocalFolder->Path);
365}
366
367void
368RingD::dequeueTasks()
369{
370 for (int i = 0; i < tasksList_.size(); i++) {
371 auto task = tasksList_.front();
Nicolas Jagerf6a10322016-09-06 08:17:49 -0400372 auto request = dynamic_cast<Task^>(task)->request;
373 switch (request) {
atraczykb724d332016-08-30 15:25:59 -0400374 case Request::None:
atraczyk4464ace2016-09-01 09:37:37 -0400375 break;
376 case Request::AddRingAccount:
Nicolas Jagerd76940f2016-08-31 14:44:04 -0400377 {
378 std::map<std::string, std::string> ringAccountDetails;
379 ringAccountDetails.insert(std::make_pair(ring::Conf::CONFIG_ACCOUNT_ALIAS, accountName));
380 ringAccountDetails.insert(std::make_pair(ring::Conf::CONFIG_ACCOUNT_TYPE,"RING"));
381 DRing::addAccount(ringAccountDetails);
382 }
383 break;
atraczyk4464ace2016-09-01 09:37:37 -0400384 case Request::AddSIPAccount:
Nicolas Jagerd76940f2016-08-31 14:44:04 -0400385 {
386 std::map<std::string, std::string> sipAccountDetails;
387 sipAccountDetails.insert(std::make_pair(ring::Conf::CONFIG_ACCOUNT_ALIAS, accountName + " (SIP)"));
388 sipAccountDetails.insert(std::make_pair(ring::Conf::CONFIG_ACCOUNT_TYPE,"SIP"));
389 DRing::addAccount(sipAccountDetails);
390 }
391 break;
Nicolas Jagerf6a10322016-09-06 08:17:49 -0400392 case Request::RefuseIncommingCall:
393 {
394 auto callId = task->_call->callId;
395 auto callId2 = Utils::toString(callId);
396 DRing::refuse(callId2);
397 }
398 break;
399 case Request::AcceptIncommingCall:
400 {
401 auto callId = task->_call->callId;
402 auto callId2 = Utils::toString(callId);
403 DRing::accept(callId2);
404 }
405 break;
Nicolas Jager5750df02016-09-13 11:20:33 -0400406 case Request::CancelOutGoingCall:
Nicolas Jager121bdf32016-09-13 12:12:15 -0400407 case Request::HangUpCall:
Nicolas Jager5750df02016-09-13 11:20:33 -0400408 {
409 auto callId = task->_call->callId;
410 auto callId2 = Utils::toString(callId);
411 DRing::hangUp(callId2);
412 }
413 break;
atraczykb724d332016-08-30 15:25:59 -0400414 default:
415 break;
416 }
417 tasksList_.pop();
418 }
419}
Nicolas Jagerc551c362016-10-01 19:24:50 -0400420
421CallStatus RingClientUWP::RingD::getCallStatus(String^ state)
422{
423 if (state == "INCOMING")
424 return CallStatus::INCOMING_RINGING;
425
426 if (state == "CURRENT")
427 return CallStatus::IN_PROGRESS;
428
429 if (state == "OVER")
430 return CallStatus::ENDED;
431
432 if (state == "RINGING")
433 return CallStatus::OUTGOING_RINGING;
434
435 if (state == "CONNECTING")
436 return CallStatus::SEARCHING;
437
438 return CallStatus::NONE;
439}