blob: fdf734723aa53ca946bfdb39a97e584387bdca6d [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
41debugOutputWrapper(const std::string& str)
42{
43 MSG_(str);
44}
45
46void
47RingClientUWP::RingD::reloadAccountList()
48{
49 RingClientUWP::ViewModel::AccountsViewModel::instance->clearAccountList();
50 std::vector<std::string> accountList = DRing::getAccountList();
51 std::vector<std::string>::reverse_iterator rit = accountList.rbegin();
52 for (; rit != accountList.rend(); ++rit) {
53 std::map<std::string,std::string> accountDetails = DRing::getAccountDetails(*rit);
54 std::string ringID(accountDetails.find(ring::Conf::CONFIG_ACCOUNT_USERNAME)->second);
55 if(!ringID.empty())
56 ringID = ringID.substr(5);
57 RingClientUWP::ViewModel::AccountsViewModel::instance->add(
58 accountDetails.find(ring::Conf::CONFIG_ACCOUNT_ALIAS)->second, //name
59 ringID, //ringid
atraczyk797fa1a2016-08-31 09:55:53 -040060 accountDetails.find(ring::Conf::CONFIG_ACCOUNT_TYPE)->second, //type
61 *rit);
atraczykb724d332016-08-30 15:25:59 -040062 }
63 // load user preferences
64 Configuration::UserPreferences::instance->load();
65}
66
Nicolas Jager655df542016-08-31 10:24:47 -040067/* nb: send message during conversation not chat video message */
68void RingClientUWP::RingD::sendAccountTextMessage(String^ message)
69{
70 /* account id */
71 auto accountId = AccountsViewModel::instance->selectedAccount->accountID_;
72 std::wstring accountId2(accountId->Begin());
73 std::string accountId3(accountId2.begin(), accountId2.end());
74
75 /* recipient */
76 auto contact = ContactsViewModel::instance->selectedContact;
77 auto toRingId = contact->ringID_;
78 std::wstring toRingId2(toRingId->Begin());
79 std::string toRingId3(toRingId2.begin(), toRingId2.end());
80
81 /* payload(s) */
82 std::wstring message2(message->Begin());
83 std::string message3(message2.begin(), message2.end());
84 std::map<std::string, std::string> payloads;
85 payloads["text/plain"] = message3;
86
87 /* daemon */
88 auto sent = DRing::sendAccountTextMessage(accountId3, toRingId3, payloads);
89
90 /* conversation */
91 if (sent) {
92 contact->_conversation->addMessage(""/* date not yet used*/, MSG_FROM_ME, message);
atraczykf5be5462016-08-31 14:23:06 -040093
94 /* save contacts conversation to disk */
95 contact->saveConversationToFile();
96
Nicolas Jager655df542016-08-31 10:24:47 -040097 } else {
98 WNG_("message not sent, see daemon outputs");
99 }
100}
101
atraczykb724d332016-08-30 15:25:59 -0400102void
atraczyk196936e2016-09-02 15:31:53 -0400103RingD::createRINGAccount(String^ alias)
104{
Nicolas Jagerf6a10322016-09-06 08:17:49 -0400105 // refactoring : create a dedicated class constructor task and removes accountName from RingD
atraczyk196936e2016-09-02 15:31:53 -0400106 accountName = Utils::toString(alias);
107 tasksList_.push(ref new RingD::Task(Request::AddRingAccount));
108}
109
110void
111RingD::createSIPAccount(String^ alias)
112{
Nicolas Jagerf6a10322016-09-06 08:17:49 -0400113 // refactoring : create a dedicated class constructor task and removes accountName from RingD
atraczyk196936e2016-09-02 15:31:53 -0400114 accountName = Utils::toString(alias);
115 tasksList_.push(ref new RingD::Task(Request::AddSIPAccount));
116}
117
Nicolas Jagerf6a10322016-09-06 08:17:49 -0400118void RingClientUWP::RingD::refuseIncommingCall(Call^ call)
119{
120 tasksList_.push(ref new RingD::Task(Request::RefuseIncommingCall, call));
121}
122
123void RingClientUWP::RingD::acceptIncommingCall(Call^ call)
124{
125 tasksList_.push(ref new RingD::Task(Request::AcceptIncommingCall, call));
126}
127
Nicolas Jager5750df02016-09-13 11:20:33 -0400128void RingClientUWP::RingD::placeCall(Contact^ contact)
129{
130 auto to = contact->ringID_;
131 auto accountId = AccountsViewModel::instance->selectedAccount->accountID_;
132
133 auto to2 = Utils::toString(to);
134 auto accountId2 = Utils::toString(accountId);
135
136 auto callId2 = DRing::placeCall(accountId2, to2);
137
138 if (callId2 == "") {
139 WNG_("call not created, the daemon didn't return a call Id");
140 return;
141 }
142
143 auto callId = Utils::toPlatformString(callId2);
144
145 auto call = CallsViewModel::instance->addNewCall(accountId, callId, to);
146 call->isOutGoing = true;
147
148 if (call == nullptr) {
149 WNG_("call not created, nullptr reason");
150 return;
151 }
152
153 calling(call);
154
155}
156
157void
158RingClientUWP::RingD::cancelOutGoingCall(Call^ call)
159{
160 tasksList_.push(ref new RingD::Task(Request::CancelOutGoingCall, call));
161}
162
atraczyk196936e2016-09-02 15:31:53 -0400163void
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
175 std::map<std::string, SharedCallback> callHandlers = {
176 // use IncomingCall only to register the call client sided, use StateChange to determine the impact on the UI
177 DRing::exportable_callback<DRing::CallSignal::IncomingCall>([this](
178 const std::string& accountId,
179 const std::string& callId,
180 const std::string& from)
181 {
182 MSG_("<IncomingCall>");
183 MSG_("accountId = " + accountId);
184 MSG_("callId = " + callId);
185 MSG_("from = " + from);
186
187 auto accountId2 = toPlatformString(accountId);
188 auto callId2 = toPlatformString(callId);
189 auto from2 = toPlatformString(from);
190
Nicolas Jagerd76940f2016-08-31 14:44:04 -0400191 CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(
192 CoreDispatcherPriority::Normal, ref new DispatchedHandler([=]()
193 {
194 incomingCall(accountId2, callId2, from2);
195 stateChange(callId2, "incoming call", 0);
196 }));
atraczykb724d332016-08-30 15:25:59 -0400197 }),
198 DRing::exportable_callback<DRing::CallSignal::StateChange>([this](
Nicolas Jagerd76940f2016-08-31 14:44:04 -0400199 const std::string& callId,
200 const std::string& state,
201 int code)
atraczykb724d332016-08-30 15:25:59 -0400202 {
203 MSG_("<StateChange>");
204 MSG_("callId = " + callId);
205 MSG_("state = " + state);
206 MSG_("code = " + std::to_string(code));
207
208 auto callId2 = toPlatformString(callId);
209 auto state2 = toPlatformString(state);
210
atraczykb724d332016-08-30 15:25:59 -0400211
Nicolas Jagerd76940f2016-08-31 14:44:04 -0400212 CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(
213 CoreDispatcherPriority::Low, ref new DispatchedHandler([=]()
214 {
215 stateChange(callId2, state2, code);
216 }));
atraczykb724d332016-08-30 15:25:59 -0400217 }),
Nicolas Jager6e30ad82016-08-26 13:00:27 -0400218 DRing::exportable_callback<DRing::ConfigurationSignal::IncomingAccountMessage>([&](
Nicolas Jagerd76940f2016-08-31 14:44:04 -0400219 const std::string& accountId,
220 const std::string& from,
221 const std::map<std::string, std::string>& payloads)
atraczykb724d332016-08-30 15:25:59 -0400222 {
223 MSG_("<IncomingAccountMessage>");
224 MSG_("accountId = " + accountId);
225 MSG_("from = " + from);
226
Nicolas Jager6e30ad82016-08-26 13:00:27 -0400227 auto accountId2 = toPlatformString(accountId);
228 auto from2 = toPlatformString(from);
229
atraczykb724d332016-08-30 15:25:59 -0400230 for (auto i : payloads) {
231 MSG_("payload = " + i.second);
232 auto payload = Utils::toPlatformString(i.second);
Nicolas Jager6e30ad82016-08-26 13:00:27 -0400233 CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(
234 CoreDispatcherPriority::Low, ref new DispatchedHandler([=]()
235 {
236 incomingAccountMessage(accountId2, from2, payload);
237 }));
atraczykb724d332016-08-30 15:25:59 -0400238 }
239 }),
atraczyk196936e2016-09-02 15:31:53 -0400240 DRing::exportable_callback<DRing::ConfigurationSignal::RegistrationStateChanged>([this](
Nicolas Jagerf6a10322016-09-06 08:17:49 -0400241 const std::string& account_id, const std::string& state,
242 int detailsCode, const std::string& detailsStr)
atraczyk196936e2016-09-02 15:31:53 -0400243 {
244 MSG_("<RegistrationStateChanged>: ID = " + account_id + "state = " + state);
atraczyk1ddcb5a2016-09-07 16:18:30 -0400245 if (state == DRing::Account::States::REGISTERED) {
atraczyk196936e2016-09-02 15:31:53 -0400246 CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(CoreDispatcherPriority::Normal,
Nicolas Jagerf6a10322016-09-06 08:17:49 -0400247 ref new DispatchedHandler([=]() {
atraczyk1ddcb5a2016-09-07 16:18:30 -0400248 auto frame = dynamic_cast<Frame^>(Window::Current->Content);
249 dynamic_cast<RingClientUWP::MainPage^>(frame->Content)->showLoadingOverlay(false, false);
atraczyk196936e2016-09-02 15:31:53 -0400250 }));
251 }
252 }),
atraczykb724d332016-08-30 15:25:59 -0400253 DRing::exportable_callback<DRing::ConfigurationSignal::AccountsChanged>([this]()
254 {
255 CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(CoreDispatcherPriority::Normal,
Nicolas Jager655df542016-08-31 10:24:47 -0400256 ref new DispatchedHandler([=]() {
atraczykb724d332016-08-30 15:25:59 -0400257 reloadAccountList();
258 }));
Nicolas Jager5750df02016-09-13 11:20:33 -0400259 }),
260 /* to remove from daemon API, this callback is never used */
261 //DRing::exportable_callback<DRing::CallSignal::NewCallCreated>([&](
262 // const std::string& accountId,
263 // const std::string& callId,
264 // const std::string& to)
265 //{ /*...*/ })
atraczykb724d332016-08-30 15:25:59 -0400266 };
267
268 registerCallHandlers(callHandlers);
269
270 std::map<std::string, SharedCallback> dringDebugOutHandler;
271 dringDebugOutHandler.insert(DRing::exportable_callback<DRing::Debug::MessageSend>
272 (std::bind(&debugOutputWrapper, _1)));
273 registerCallHandlers(dringDebugOutHandler);
274
275 std::map<std::string, SharedCallback> getAppPathHandler =
276 {
277 DRing::exportable_callback<DRing::ConfigurationSignal::GetAppDataPath>
278 ([this](std::vector<std::string>* paths) {
279 paths->emplace_back(localFolder_);
280 })
281 };
282 registerCallHandlers(getAppPathHandler);
283
Nicolas Jageraef65722016-09-06 08:30:14 -0400284 DRing::init(static_cast<DRing::InitFlag>(DRing::DRING_FLAG_CONSOLE_LOG |
Nicolas Jagerf6a10322016-09-06 08:17:49 -0400285 DRing::DRING_FLAG_DEBUG));
atraczykb724d332016-08-30 15:25:59 -0400286
287 if (!DRing::start()) {
288 ERR_("\ndaemon didn't start.\n");
289 return;
290 }
291 else {
292 if (!hasConfig)
293 {
atraczyk4464ace2016-09-01 09:37:37 -0400294 tasksList_.push(ref new RingD::Task(Request::AddRingAccount));
295 tasksList_.push(ref new RingD::Task(Request::AddSIPAccount));
atraczykb724d332016-08-30 15:25:59 -0400296 }
297 else {
298 CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(CoreDispatcherPriority::Normal,
Nicolas Jager655df542016-08-31 10:24:47 -0400299 ref new DispatchedHandler([=]() {
atraczykb724d332016-08-30 15:25:59 -0400300 reloadAccountList();
301 }));
302 }
303 while (true) {
304 DRing::pollEvents();
305 Sleep(1000);
306 dequeueTasks();
307 }
308 DRing::fini();
309 }
310 });
311}
312
313RingD::RingD()
314{
315 localFolder_ = Utils::toString(ApplicationData::Current->LocalFolder->Path);
316}
317
318void
319RingD::dequeueTasks()
320{
321 for (int i = 0; i < tasksList_.size(); i++) {
322 auto task = tasksList_.front();
Nicolas Jagerf6a10322016-09-06 08:17:49 -0400323 auto request = dynamic_cast<Task^>(task)->request;
324 switch (request) {
atraczykb724d332016-08-30 15:25:59 -0400325 case Request::None:
atraczyk4464ace2016-09-01 09:37:37 -0400326 break;
327 case Request::AddRingAccount:
Nicolas Jagerd76940f2016-08-31 14:44:04 -0400328 {
329 std::map<std::string, std::string> ringAccountDetails;
330 ringAccountDetails.insert(std::make_pair(ring::Conf::CONFIG_ACCOUNT_ALIAS, accountName));
331 ringAccountDetails.insert(std::make_pair(ring::Conf::CONFIG_ACCOUNT_TYPE,"RING"));
332 DRing::addAccount(ringAccountDetails);
333 }
334 break;
atraczyk4464ace2016-09-01 09:37:37 -0400335 case Request::AddSIPAccount:
Nicolas Jagerd76940f2016-08-31 14:44:04 -0400336 {
337 std::map<std::string, std::string> sipAccountDetails;
338 sipAccountDetails.insert(std::make_pair(ring::Conf::CONFIG_ACCOUNT_ALIAS, accountName + " (SIP)"));
339 sipAccountDetails.insert(std::make_pair(ring::Conf::CONFIG_ACCOUNT_TYPE,"SIP"));
340 DRing::addAccount(sipAccountDetails);
341 }
342 break;
Nicolas Jagerf6a10322016-09-06 08:17:49 -0400343 case Request::RefuseIncommingCall:
344 {
345 auto callId = task->_call->callId;
346 auto callId2 = Utils::toString(callId);
347 DRing::refuse(callId2);
348 }
349 break;
350 case Request::AcceptIncommingCall:
351 {
352 auto callId = task->_call->callId;
353 auto callId2 = Utils::toString(callId);
354 DRing::accept(callId2);
355 }
356 break;
Nicolas Jager5750df02016-09-13 11:20:33 -0400357 case Request::CancelOutGoingCall:
358 {
359 auto callId = task->_call->callId;
360 auto callId2 = Utils::toString(callId);
361 DRing::hangUp(callId2);
362 }
363 break;
atraczykb724d332016-08-30 15:25:59 -0400364 default:
365 break;
366 }
367 tasksList_.pop();
368 }
369}