blob: 31876393ccbf921ee9d41ff9f0ef29bc0a19bb21 [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 */
70 auto contact = ContactsViewModel::instance->selectedContact;
71 auto toRingId = contact->ringID_;
72 std::wstring toRingId2(toRingId->Begin());
73 std::string toRingId3(toRingId2.begin(), toRingId2.end());
74
75 /* payload(s) */
76 std::wstring message2(message->Begin());
77 std::string message3(message2.begin(), message2.end());
78 std::map<std::string, std::string> payloads;
79 payloads["text/plain"] = message3;
80
81 /* daemon */
82 auto sent = DRing::sendAccountTextMessage(accountId3, toRingId3, payloads);
83
84 /* conversation */
85 if (sent) {
86 contact->_conversation->addMessage(""/* date not yet used*/, MSG_FROM_ME, message);
atraczykf5be5462016-08-31 14:23:06 -040087
88 /* save contacts conversation to disk */
89 contact->saveConversationToFile();
90
Nicolas Jager655df542016-08-31 10:24:47 -040091 } else {
92 WNG_("message not sent, see daemon outputs");
93 }
94}
95
atraczykb724d332016-08-30 15:25:59 -040096void
atraczyk196936e2016-09-02 15:31:53 -040097RingD::createRINGAccount(String^ alias)
98{
Nicolas Jagerf6a10322016-09-06 08:17:49 -040099 // refactoring : create a dedicated class constructor task and removes accountName from RingD
atraczyk196936e2016-09-02 15:31:53 -0400100 accountName = Utils::toString(alias);
101 tasksList_.push(ref new RingD::Task(Request::AddRingAccount));
102}
103
104void
105RingD::createSIPAccount(String^ alias)
106{
Nicolas Jagerf6a10322016-09-06 08:17:49 -0400107 // refactoring : create a dedicated class constructor task and removes accountName from RingD
atraczyk196936e2016-09-02 15:31:53 -0400108 accountName = Utils::toString(alias);
109 tasksList_.push(ref new RingD::Task(Request::AddSIPAccount));
110}
111
Nicolas Jagerf6a10322016-09-06 08:17:49 -0400112void RingClientUWP::RingD::refuseIncommingCall(Call^ call)
113{
114 tasksList_.push(ref new RingD::Task(Request::RefuseIncommingCall, call));
115}
116
117void RingClientUWP::RingD::acceptIncommingCall(Call^ call)
118{
119 tasksList_.push(ref new RingD::Task(Request::AcceptIncommingCall, call));
120}
121
Nicolas Jager5750df02016-09-13 11:20:33 -0400122void RingClientUWP::RingD::placeCall(Contact^ contact)
123{
124 auto to = contact->ringID_;
125 auto accountId = AccountsViewModel::instance->selectedAccount->accountID_;
126
127 auto to2 = Utils::toString(to);
128 auto accountId2 = Utils::toString(accountId);
129
130 auto callId2 = DRing::placeCall(accountId2, to2);
131
132 if (callId2 == "") {
133 WNG_("call not created, the daemon didn't return a call Id");
134 return;
135 }
136
137 auto callId = Utils::toPlatformString(callId2);
138
139 auto call = CallsViewModel::instance->addNewCall(accountId, callId, to);
140 call->isOutGoing = true;
141
142 if (call == nullptr) {
143 WNG_("call not created, nullptr reason");
144 return;
145 }
146
147 calling(call);
148
149}
150
151void
152RingClientUWP::RingD::cancelOutGoingCall(Call^ call)
153{
154 tasksList_.push(ref new RingD::Task(Request::CancelOutGoingCall, call));
155}
156
atraczyk196936e2016-09-02 15:31:53 -0400157void
Nicolas Jager121bdf32016-09-13 12:12:15 -0400158RingClientUWP::RingD::hangUpCall(Call^ call)
159{
160 tasksList_.push(ref new RingD::Task(Request::HangUpCall, call));
161}
162
163void
atraczykb724d332016-08-30 15:25:59 -0400164RingClientUWP::RingD::startDaemon()
165{
Nicolas Jagerd76940f2016-08-31 14:44:04 -0400166 // TODO (during refactoring) : use namespace
167 /* clear the calls list and instantiate the singleton (required) */
168 RingClientUWP::ViewModel::CallsViewModel::instance->clearCallsList();
169
atraczykb724d332016-08-30 15:25:59 -0400170 create_task([&]()
171 {
172 using SharedCallback = std::shared_ptr<DRing::CallbackWrapperBase>;
173 using namespace std::placeholders;
174
Nicolas Jagerd83bc542016-09-16 12:07:31 -0400175 auto dispatcher = CoreApplication::MainView->CoreWindow->Dispatcher;
176
atraczykb724d332016-08-30 15:25:59 -0400177 std::map<std::string, SharedCallback> callHandlers = {
178 // use IncomingCall only to register the call client sided, use StateChange to determine the impact on the UI
179 DRing::exportable_callback<DRing::CallSignal::IncomingCall>([this](
180 const std::string& accountId,
181 const std::string& callId,
182 const std::string& from)
183 {
184 MSG_("<IncomingCall>");
185 MSG_("accountId = " + accountId);
186 MSG_("callId = " + callId);
187 MSG_("from = " + from);
188
189 auto accountId2 = toPlatformString(accountId);
190 auto callId2 = toPlatformString(callId);
191 auto from2 = toPlatformString(from);
192
Nicolas Jagerf494bda2016-09-16 08:43:43 -0400193 /* fix some issue in the daemon --> <...@...> */
194 from2 = Utils::TrimRingId(from2);
195
Nicolas Jagerd76940f2016-08-31 14:44:04 -0400196 CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(
197 CoreDispatcherPriority::Normal, ref new DispatchedHandler([=]()
198 {
199 incomingCall(accountId2, callId2, from2);
200 stateChange(callId2, "incoming call", 0);
201 }));
atraczykb724d332016-08-30 15:25:59 -0400202 }),
203 DRing::exportable_callback<DRing::CallSignal::StateChange>([this](
Nicolas Jagerd76940f2016-08-31 14:44:04 -0400204 const std::string& callId,
205 const std::string& state,
206 int code)
atraczykb724d332016-08-30 15:25:59 -0400207 {
208 MSG_("<StateChange>");
209 MSG_("callId = " + callId);
210 MSG_("state = " + state);
211 MSG_("code = " + std::to_string(code));
212
213 auto callId2 = toPlatformString(callId);
214 auto state2 = toPlatformString(state);
215
atraczykb724d332016-08-30 15:25:59 -0400216
Nicolas Jagerd76940f2016-08-31 14:44:04 -0400217 CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(
218 CoreDispatcherPriority::Low, ref new DispatchedHandler([=]()
219 {
220 stateChange(callId2, state2, code);
221 }));
atraczykb724d332016-08-30 15:25:59 -0400222 }),
Nicolas Jager6e30ad82016-08-26 13:00:27 -0400223 DRing::exportable_callback<DRing::ConfigurationSignal::IncomingAccountMessage>([&](
Nicolas Jagerd76940f2016-08-31 14:44:04 -0400224 const std::string& accountId,
225 const std::string& from,
226 const std::map<std::string, std::string>& payloads)
atraczykb724d332016-08-30 15:25:59 -0400227 {
228 MSG_("<IncomingAccountMessage>");
229 MSG_("accountId = " + accountId);
230 MSG_("from = " + from);
231
Nicolas Jager6e30ad82016-08-26 13:00:27 -0400232 auto accountId2 = toPlatformString(accountId);
233 auto from2 = toPlatformString(from);
234
atraczykb724d332016-08-30 15:25:59 -0400235 for (auto i : payloads) {
236 MSG_("payload = " + i.second);
237 auto payload = Utils::toPlatformString(i.second);
Nicolas Jager6e30ad82016-08-26 13:00:27 -0400238 CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(
239 CoreDispatcherPriority::Low, ref new DispatchedHandler([=]()
240 {
241 incomingAccountMessage(accountId2, from2, payload);
242 }));
atraczykb724d332016-08-30 15:25:59 -0400243 }
244 }),
atraczyk5c395ea2016-09-20 17:28:09 -0400245 DRing::exportable_callback<DRing::CallSignal::IncomingMessage>([&](
246 const std::string& callId,
247 const std::string& from,
248 const std::map<std::string, std::string>& payloads)
249 {
250 MSG_("<IncomingMessage>");
251 MSG_("callId = " + callId);
252 MSG_("from = " + from);
253
254 auto callId2 = toPlatformString(callId);
255 auto from2 = toPlatformString(from);
256
257 from2 = Utils::TrimRingId2(from2);
258
259 Call^ call = CallsViewModel::instance->findCall(callId2);
260
261 if (!call)
262 return;
263
264 String^ accountId2 = call->accountId;
265 const std::string PROFILE_VCF = "x-ring/ring.profile.vcard";
266 static const unsigned int profileSize = PROFILE_VCF.size();
267
268 for (auto i : payloads) {
269 if (i.first.compare(0, profileSize, PROFILE_VCF) == 0) {
270 MSG_("VCARD");
271 return;
272 }
273 MSG_("payload.first = " + i.first);
274 MSG_("payload.second = " + i.second);
275
276 auto payload = Utils::toPlatformString(i.second);
277 CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(
278 CoreDispatcherPriority::Low, ref new DispatchedHandler([=]()
279 {
280 incomingAccountMessage(accountId2, from2, payload);
281 }));
282 }
283 }),
atraczyk196936e2016-09-02 15:31:53 -0400284 DRing::exportable_callback<DRing::ConfigurationSignal::RegistrationStateChanged>([this](
Nicolas Jagerf6a10322016-09-06 08:17:49 -0400285 const std::string& account_id, const std::string& state,
286 int detailsCode, const std::string& detailsStr)
atraczyk196936e2016-09-02 15:31:53 -0400287 {
288 MSG_("<RegistrationStateChanged>: ID = " + account_id + "state = " + state);
atraczyk1ddcb5a2016-09-07 16:18:30 -0400289 if (state == DRing::Account::States::REGISTERED) {
atraczyk196936e2016-09-02 15:31:53 -0400290 CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(CoreDispatcherPriority::Normal,
Nicolas Jagerf6a10322016-09-06 08:17:49 -0400291 ref new DispatchedHandler([=]() {
atraczyk1ddcb5a2016-09-07 16:18:30 -0400292 auto frame = dynamic_cast<Frame^>(Window::Current->Content);
293 dynamic_cast<RingClientUWP::MainPage^>(frame->Content)->showLoadingOverlay(false, false);
atraczyk196936e2016-09-02 15:31:53 -0400294 }));
295 }
296 }),
atraczykb724d332016-08-30 15:25:59 -0400297 DRing::exportable_callback<DRing::ConfigurationSignal::AccountsChanged>([this]()
298 {
299 CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(CoreDispatcherPriority::Normal,
Nicolas Jager655df542016-08-31 10:24:47 -0400300 ref new DispatchedHandler([=]() {
atraczykb724d332016-08-30 15:25:59 -0400301 reloadAccountList();
302 }));
Nicolas Jager5750df02016-09-13 11:20:33 -0400303 }),
Nicolas Jagerd83bc542016-09-16 12:07:31 -0400304 DRing::exportable_callback<DRing::Debug::MessageSend>([&](const std::string& toto)
305 {
306 dispatcher->RunAsync(CoreDispatcherPriority::Normal,
307 ref new DispatchedHandler([=]() {
308 RingDebug::instance->print(toto);
309 }));
310 })
Nicolas Jager5750df02016-09-13 11:20:33 -0400311 /* to remove from daemon API, this callback is never used */
312 //DRing::exportable_callback<DRing::CallSignal::NewCallCreated>([&](
313 // const std::string& accountId,
314 // const std::string& callId,
315 // const std::string& to)
316 //{ /*...*/ })
atraczykb724d332016-08-30 15:25:59 -0400317 };
318
319 registerCallHandlers(callHandlers);
320
atraczykb724d332016-08-30 15:25:59 -0400321 std::map<std::string, SharedCallback> getAppPathHandler =
322 {
323 DRing::exportable_callback<DRing::ConfigurationSignal::GetAppDataPath>
324 ([this](std::vector<std::string>* paths) {
325 paths->emplace_back(localFolder_);
326 })
327 };
328 registerCallHandlers(getAppPathHandler);
329
Nicolas Jageraef65722016-09-06 08:30:14 -0400330 DRing::init(static_cast<DRing::InitFlag>(DRing::DRING_FLAG_CONSOLE_LOG |
Nicolas Jagerf6a10322016-09-06 08:17:49 -0400331 DRing::DRING_FLAG_DEBUG));
atraczykb724d332016-08-30 15:25:59 -0400332
333 if (!DRing::start()) {
334 ERR_("\ndaemon didn't start.\n");
335 return;
336 }
337 else {
338 if (!hasConfig)
339 {
atraczyk4464ace2016-09-01 09:37:37 -0400340 tasksList_.push(ref new RingD::Task(Request::AddRingAccount));
341 tasksList_.push(ref new RingD::Task(Request::AddSIPAccount));
atraczykb724d332016-08-30 15:25:59 -0400342 }
343 else {
344 CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(CoreDispatcherPriority::Normal,
Nicolas Jager655df542016-08-31 10:24:47 -0400345 ref new DispatchedHandler([=]() {
atraczykb724d332016-08-30 15:25:59 -0400346 reloadAccountList();
347 }));
348 }
349 while (true) {
350 DRing::pollEvents();
351 Sleep(1000);
352 dequeueTasks();
353 }
354 DRing::fini();
355 }
356 });
357}
358
359RingD::RingD()
360{
361 localFolder_ = Utils::toString(ApplicationData::Current->LocalFolder->Path);
362}
363
364void
365RingD::dequeueTasks()
366{
367 for (int i = 0; i < tasksList_.size(); i++) {
368 auto task = tasksList_.front();
Nicolas Jagerf6a10322016-09-06 08:17:49 -0400369 auto request = dynamic_cast<Task^>(task)->request;
370 switch (request) {
atraczykb724d332016-08-30 15:25:59 -0400371 case Request::None:
atraczyk4464ace2016-09-01 09:37:37 -0400372 break;
373 case Request::AddRingAccount:
Nicolas Jagerd76940f2016-08-31 14:44:04 -0400374 {
375 std::map<std::string, std::string> ringAccountDetails;
376 ringAccountDetails.insert(std::make_pair(ring::Conf::CONFIG_ACCOUNT_ALIAS, accountName));
377 ringAccountDetails.insert(std::make_pair(ring::Conf::CONFIG_ACCOUNT_TYPE,"RING"));
378 DRing::addAccount(ringAccountDetails);
379 }
380 break;
atraczyk4464ace2016-09-01 09:37:37 -0400381 case Request::AddSIPAccount:
Nicolas Jagerd76940f2016-08-31 14:44:04 -0400382 {
383 std::map<std::string, std::string> sipAccountDetails;
384 sipAccountDetails.insert(std::make_pair(ring::Conf::CONFIG_ACCOUNT_ALIAS, accountName + " (SIP)"));
385 sipAccountDetails.insert(std::make_pair(ring::Conf::CONFIG_ACCOUNT_TYPE,"SIP"));
386 DRing::addAccount(sipAccountDetails);
387 }
388 break;
Nicolas Jagerf6a10322016-09-06 08:17:49 -0400389 case Request::RefuseIncommingCall:
390 {
391 auto callId = task->_call->callId;
392 auto callId2 = Utils::toString(callId);
393 DRing::refuse(callId2);
394 }
395 break;
396 case Request::AcceptIncommingCall:
397 {
398 auto callId = task->_call->callId;
399 auto callId2 = Utils::toString(callId);
400 DRing::accept(callId2);
401 }
402 break;
Nicolas Jager5750df02016-09-13 11:20:33 -0400403 case Request::CancelOutGoingCall:
Nicolas Jager121bdf32016-09-13 12:12:15 -0400404 case Request::HangUpCall:
Nicolas Jager5750df02016-09-13 11:20:33 -0400405 {
406 auto callId = task->_call->callId;
407 auto callId2 = Utils::toString(callId);
408 DRing::hangUp(callId2);
409 }
410 break;
atraczykb724d332016-08-30 15:25:59 -0400411 default:
412 break;
413 }
414 tasksList_.pop();
415 }
416}