aba31d92a683497f841c6eee5fd03286c72d6320
[profile/ivi/phoned.git] / src / ofono.cpp
1 #include "ofono.h"
2 #include "utils.h"
3
4 #include <gio/gio.h>
5 #include <stdio.h>
6 #include <string.h>
7 #include <algorithm>
8
9 #include <stdlib.h>
10
11 #include "Logger.h"
12
13 namespace PhoneD {
14
15 #define OFONO_PREFIX                     "org.ofono"
16
17 #define OFONO_SERVICE                    OFONO_PREFIX
18 #define OFONO_MANAGER_IFACE              OFONO_PREFIX ".Manager"
19 #define OFONO_MODEM_IFACE                OFONO_PREFIX ".Modem"
20 #define OFONO_VOICECALLMANAGER_IFACE     OFONO_PREFIX ".VoiceCallManager"
21 #define OFONO_VOICECALL_IFACE            OFONO_PREFIX ".VoiceCall"
22 #define OFONO_CALLVOLUME_IFACE           OFONO_PREFIX ".CallVolume"
23
24 #define CHECK_FOR_MODEM_POWERED_INTERVAL 60 // interval for check whether 'Selected' remote device is Powered, and power it on, if it is not (in seconds)
25
26 OFono::OFono() :
27     mModemPath( NULL ),
28     mActiveCall( NULL )
29 {
30     LoggerD("entered");
31
32     /*
33     if(getModems()) {
34         LoggerD("Failed to call 'GetModems'");
35     }
36     */
37     Utils::setSignalListener(G_BUS_TYPE_SYSTEM, OFONO_SERVICE,
38                              OFONO_MANAGER_IFACE, "/",
39                              "ModemAdded", OFono::handleSignal,
40                              this);
41     Utils::setSignalListener(G_BUS_TYPE_SYSTEM, OFONO_SERVICE,
42                              OFONO_MANAGER_IFACE, "/",
43                              "ModemRemoved", OFono::handleSignal,
44                              this);
45
46     // won't request calls here, since the service OFONO_VOICECALLMANAGER_IFACE may not be available yet
47     //get active calls
48     //if(mModemPath) {
49     //    getCalls();
50     //}
51
52     // periodic check whether modem for 'Selected' remote device is powered
53     // among other things, it handles also the case when the phone gets out of the range of HMI BT
54     g_timeout_add(CHECK_FOR_MODEM_POWERED_INTERVAL*1000, OFono::checkForModemPowered, this);
55 }
56
57 OFono::~OFono() {
58     LoggerD("entered");
59     removeModem(mModemPath);
60 }
61
62 gboolean OFono::checkForModemPowered(gpointer user_data) {
63     OFono *ctx = static_cast<OFono*>(user_data);
64     if(!ctx || !ctx->mModemPath)
65         return G_SOURCE_CONTINUE; // continuous timeout
66
67     if(!ctx->isModemPowered(ctx->mModemPath)) {
68         ctx->setModemPowered(ctx->mModemPath, true);
69     }
70
71     return G_SOURCE_CONTINUE; // continuous timeout
72 }
73
74 bool OFono::isModemPowered(const char *modem) {
75     if(modem)
76         return false;
77
78     GError *err = NULL;
79     GVariant *reply = NULL;
80     reply = g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
81                                          OFONO_SERVICE,
82                                          modem,
83                                          OFONO_MODEM_IFACE,
84                                          "GetProperties",
85                                          NULL,
86                                          NULL,
87                                          G_DBUS_CALL_FLAGS_NONE,
88                                          -1,
89                                          NULL,
90                                          &err);
91
92
93     if(err || !reply) {
94         if(err)
95             g_error_free(err);
96         return false;
97     }
98
99     GVariant *prop = NULL;
100     GVariantIter *iter = NULL;
101     g_variant_get(reply, "(a{sv})", &iter);
102     bool powered = false;
103     while((prop = g_variant_iter_next_value(iter))) {
104         const char *name = NULL;
105         GVariant *value = NULL;
106         g_variant_get(prop, "{sv}", &name, &value);
107         if(name && !strcmp(name, "Powered")) {
108             powered = g_variant_get_boolean(value);
109         }
110     }
111
112     g_variant_unref(reply);
113
114     return powered;
115 }
116
117 // synchronous version of method for setting property
118 bool OFono::setProperty(const char* iface, const char* path, const char *property, int type, void *value) {
119     LoggerD("OFono::setProperty(): name= " << property << " on " << path);
120
121     char signature[2];
122     sprintf(signature, "%c", type); // eg. "b" for boolean
123
124     GError *err = NULL;
125     g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL,NULL),
126                                  OFONO_SERVICE,
127                                  path,
128                                  iface,
129                                  "SetProperty",
130                                  g_variant_new ("(sv)", // floating parameters are consumed, no cleanup/unref needed
131                                      property,
132                                      g_variant_new(signature, value) // floating parameters are consumed, no cleanup/unref needed
133                                  ),
134                                  NULL,
135                                  G_DBUS_CALL_FLAGS_NONE,
136                                  -1,
137                                  NULL,
138                                  &err);
139
140     if(err) {
141         LoggerE("Failed to call \"SetProperty\" DBUS method: " << err->message);
142         g_error_free(err);
143         return false;
144     }
145
146     return true;
147 }
148
149 // asynchronous version of method for setting property
150 void OFono::setPropertyAsync(const char* iface, const char* path, const char *property, int type, void *value, GAsyncReadyCallback callback) {
151     LoggerD("Setting OFono property via asynchronous call: name= " << property << " on " << path);
152
153     char signature[2];
154     sprintf(signature, "%c", type); // eg. "b" for boolean
155
156     g_dbus_connection_call( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL,NULL),
157                             OFONO_SERVICE,
158                             path,
159                             iface,
160                             "SetProperty",
161                             g_variant_new ("(sv)", // floating parameters are consumed, no cleanup/unref needed
162                                 property,
163                                 g_variant_new(signature, value) // floating parameters are consumed, no cleanup/unref needed
164                             ),
165                             NULL,
166                             G_DBUS_CALL_FLAGS_NONE,
167                             -1,
168                             NULL,
169                             callback,
170                             this);
171 }
172
173 // callback for async calls on 'g_dbus'
174 void OFono::GDbusAsyncReadyCallback(GObject *source, GAsyncResult *result, gpointer user_data) {
175     //process result here if needed
176     //LoggerD("Async method call finished, ie. callback received");
177 }
178
179 void OFono::setModemPowered(const char *modem, bool powered) {
180     LoggerD("Setting modem 'Powered': " << modem << " to " << powered);
181     setPropertyAsync(OFONO_MODEM_IFACE, modem, "Powered", DBUS_TYPE_BOOLEAN, &powered, OFono::asyncSetModemPoweredCallback);
182 }
183
184 void OFono::asyncSetModemPoweredCallback(GObject *source, GAsyncResult *result, gpointer user_data) {
185     GError *err = NULL;
186     g_dbus_connection_call_finish(g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL), result, &err);
187     if(err) {
188         LoggerE("Failed to set 'Powered' property on modem: " << err->message);
189         OFono *ctx = static_cast<OFono*>(user_data);
190         if(!ctx) {
191             LoggerE("Invalid ctx");
192             return;
193         }
194         // notify about the failure
195         if(!ctx->isModemPowered(ctx->mModemPath)) // Modem is not 'Powered', ie. the remote BT device is not 'Selected' for BT operations
196             ctx->setModemPoweredFailed(err?err->message:"Failed to set 'Powered' property on Modem.");
197         g_error_free(err);
198     }
199     else
200         LoggerE("Property 'Powered' successfuly set on modem");
201 }
202
203 void OFono::asyncSelectModemCallback(GObject *source, GAsyncResult *result, gpointer user_data) {
204     CtxCbData *data = static_cast<CtxCbData*>(user_data);
205     if(!data || !data->ctx || !data->data1) {
206         LoggerE("Invalid callback data");
207         return;
208     }
209     OFono *ctx = static_cast<OFono*>(data->ctx);
210     char *addr = static_cast<char*>(data->data1);
211
212     std::string btAddress = addr;
213
214     free(addr);
215     delete data;
216
217     GError *err = NULL;
218     GVariant *reply;
219     reply = g_dbus_connection_call_finish(g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL), result, &err);
220     if(err || !reply) {
221         if(err) {
222             LoggerE("Failed to 'GetModems': " << err->message);
223             g_error_free(err);
224         }
225         else if(!reply)
226             LoggerE("Reply from calling 'GetModems' method is NULL");
227
228         return;
229     }
230
231     // path of retrieved modems is in form: /hfp/AABBCCDDEEFF_FFEEDDCCBBAA
232     // where: AABBCCDDEEFF is MAC address of default local BT device
233     //   and: FFEEDDCCBBAA is MAC address of selected remote BT device
234     // we expect given MAC address to be in the form: AA:BB:CC:DD:EE:FF
235     // remove all non-digit characters, eg. ":","-"
236     btAddress.erase(std::remove_if(btAddress.begin(), btAddress.end(), isnxdigit), btAddress.end());
237
238     GVariantIter *modems;
239     GVariantIter *props;
240     const char *path;
241     g_variant_get(reply, "(a(oa{sv}))", &modems);
242     while(g_variant_iter_next(modems, "(oa{sv})", &path, &props)) {
243         // check if the modem is from selected remote device
244         std::string pathString(path);
245         size_t idx = pathString.find( "_" ) + 1; // index of address of remote device
246         std::string modemRemoteBtAddress = pathString.substr (idx, pathString.length()-idx);
247
248         // remove additional underscores
249         modemRemoteBtAddress.erase(std::remove_if(modemRemoteBtAddress.begin(),modemRemoteBtAddress.end(),isnxdigit),modemRemoteBtAddress.end());
250         LoggerD("modem paths to be compared: %s, %s", modemRemoteBtAddress.c_str(),btAddress.c_str());
251
252         if(!modemRemoteBtAddress.compare(btAddress))
253         {
254             ctx->addModem(path, props);
255             // currently only one modem is supported - that's why the break is here
256             // take the first one from the list and make it 'default'
257             break;
258         }
259     }
260
261     g_variant_unref(reply);
262 }
263
264 void OFono::selectModem(std::string &btAddress) {
265     LoggerD("Selecting modem: " << btAddress);
266     // Retrieving list of available modems to get the one that is for 'wanted' device
267     g_dbus_connection_call( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
268                             OFONO_SERVICE,
269                             "/",
270                             OFONO_MANAGER_IFACE,
271                             "GetModems",
272                             NULL,
273                             NULL,
274                             G_DBUS_CALL_FLAGS_NONE,
275                             -1,
276                             NULL,
277                             OFono::asyncSelectModemCallback,
278                             new CtxCbData(this, NULL, strdup(btAddress.c_str()), NULL));
279 }
280
281 void OFono::addModem(const char *path, GVariantIter *props) {
282     LoggerD("entered");
283
284     if(!path || !props)
285         return;
286
287     // shouldn't happen, but just in case free the memory here
288     if(mModemPath)
289         free(mModemPath);
290
291     mModemPath = strdup(path); // make a copy of path, 'cause it will be unref-ed
292
293     const char *key = NULL;
294     GVariant *value = NULL;
295     bool online = FALSE;
296     while(g_variant_iter_next(props, "{sv}", &key, &value)) {
297         if(!strcmp(key, "Powered")) {
298             //bool powered = g_variant_get_boolean(value);
299         }
300         else if(!strcmp(key, "Online")) {
301             online = g_variant_get_boolean(value);
302         }
303     }
304
305     Utils::setSignalListener(G_BUS_TYPE_SYSTEM, OFONO_SERVICE,
306                              OFONO_VOICECALLMANAGER_IFACE, mModemPath,
307                              "CallAdded", OFono::handleSignal,
308                              this);
309
310     Utils::setSignalListener(G_BUS_TYPE_SYSTEM, OFONO_SERVICE,
311                              OFONO_VOICECALLMANAGER_IFACE, mModemPath,
312                              "PropertyChanged", OFono::handleSignal,
313                              this);
314
315     Utils::setSignalListener(G_BUS_TYPE_SYSTEM, OFONO_SERVICE,
316                              OFONO_VOICECALLMANAGER_IFACE, mModemPath,
317                              "CallRemoved", OFono::handleSignal,
318                              this);
319
320     Utils::setSignalListener(G_BUS_TYPE_SYSTEM, OFONO_SERVICE,
321                              OFONO_MODEM_IFACE, mModemPath,
322                              "PropertyChanged", OFono::handleSignal,
323                              this);
324
325     if(!online) {
326         // power on modem
327         setModemPowered(mModemPath, true);
328     }
329     else
330     {
331         // we can query calls from here, since the modem is already powered
332         getCalls();
333         // when the modem is already online, "PropertyChanged" for "Paired" is not emited
334         // to handle all functionality to modem being powered, call modemPowered from here as well
335         modemPowered(true);
336     }
337 }
338
339 void OFono::unselectModem() {
340     removeModem(mModemPath);
341 }
342
343 void OFono::removeModem(const char *modemPath) {
344     LoggerD("Removing modem: " << (modemPath?modemPath:"INVALID DATA"));
345
346     // remove all subscriptions to DBUS signals from the modem
347     if(modemPath) {
348         Utils::removeSignalListener(G_BUS_TYPE_SYSTEM, OFONO_SERVICE,
349                                     OFONO_VOICECALLMANAGER_IFACE, modemPath,
350                                     "CallAdded");
351         Utils::removeSignalListener(G_BUS_TYPE_SYSTEM, OFONO_SERVICE,
352                                     OFONO_VOICECALLMANAGER_IFACE, modemPath,
353                                     "PropertyChanged");
354         Utils::removeSignalListener(G_BUS_TYPE_SYSTEM, OFONO_SERVICE,
355                                     OFONO_VOICECALLMANAGER_IFACE, modemPath,
356                                     "CallRemoved");
357         Utils::removeSignalListener(G_BUS_TYPE_SYSTEM, OFONO_SERVICE,
358                                     OFONO_MODEM_IFACE, modemPath,
359                                     "PropertyChanged");
360
361         // power off modem
362         setModemPowered(modemPath, false);
363         // at this point we will not get notification "PropertyChanged" on 'Powered' property,
364         // call 'modemPowered()' method directly from here
365         modemPowered(false);
366
367         // free the memory
368         if(modemPath && mModemPath && !strcmp(modemPath, mModemPath)) {
369             free(mModemPath);
370             mModemPath = NULL;
371         }
372     }
373 }
374
375 void OFono::getCalls()
376 {
377     LoggerD("entered");
378
379     GError *err = NULL;
380     GVariant *reply = NULL;
381     reply = g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL),
382                                          OFONO_SERVICE,
383                                          mModemPath,
384                                          OFONO_VOICECALLMANAGER_IFACE,
385                                          "GetCalls",
386                                          NULL,
387                                          NULL,
388                                          G_DBUS_CALL_FLAGS_NONE,
389                                          -1,
390                                          NULL,
391                                          &err);
392
393
394     if(err || !reply) {
395         if(err) {
396             LoggerE("error calling GetCalls method");
397             g_error_free(err);
398         }
399         else if(!reply)
400             LoggerE("reply is NULL");
401
402         return;
403     }
404
405     GVariantIter *calls;
406     GVariantIter *props;
407     const char *path;
408     g_variant_get(reply, "(a(oa{sv}))", &calls);
409     while(g_variant_iter_next(calls, "(oa{sv})", &path, &props)) {
410         addCall(path, props);
411     }
412
413     g_variant_unref(reply);
414
415     return;
416 }
417
418 void OFono::handleSignal(GDBusConnection       *connection,
419                          const gchar           *sender,
420                          const gchar           *object_path,
421                          const gchar           *interface_name,
422                          const gchar           *signal_name,
423                          GVariant              *parameters,
424                          gpointer               user_data)
425 {
426     LoggerD("signal received: \"" << interface_name << "\" -> \"" << signal_name << "\"");
427
428     OFono* ctx = static_cast<OFono*>(user_data);
429     if(!ctx) {
430         LoggerE("Failed to cast object");
431         return;
432     }
433
434     if(!interface_name || !signal_name) {
435         LoggerE("Invalid callback data");
436         return;
437     }
438     if(!strcmp(interface_name, OFONO_MANAGER_IFACE)) {
439         if(!strcmp(signal_name, "ModemAdded")) {
440             const char *modem = NULL;
441             GVariantIter *props = NULL;
442             g_variant_get(parameters, "(oa{sv})", &modem, &props);
443             if(modem) {
444                 std::string modemString(modem);
445                 size_t idx = modemString.find( "_" ) + 1; // index of address of remote device
446                 std::string modemRemoteBtAddress = modemString.substr (idx, modemString.length()-idx);
447                 if(makeMACFromRawMAC(modemRemoteBtAddress)) {
448                     ctx->modemAdded(modemRemoteBtAddress);
449                 }
450             }
451         }
452     }
453     else if(!strcmp(interface_name, OFONO_MANAGER_IFACE)) {
454         if(!strcmp(signal_name, "ModemRemoved")) {
455             const char *modem = NULL;
456             g_variant_get(parameters, "(o)", &modem);
457             if(modem) {
458                 LoggerD("Modem removed: " << modem);
459                 if(ctx->mModemPath && !strcmp(modem, ctx->mModemPath)) {
460                     ctx->removeModem(ctx->mModemPath);
461                 }
462             }
463         }
464     }
465     else if(!strcmp(interface_name, OFONO_MODEM_IFACE)) {
466         if(!strcmp(signal_name, "PropertyChanged")) {
467             const char *name = NULL;
468             GVariant *value = NULL;
469             g_variant_get(parameters, "(sv)", &name, &value);
470             if(!strcmp(name, "Powered")) {
471                 bool powered = g_variant_get_boolean(value);
472                 LoggerD("\t" << name << " = " << (powered?"TRUE":"FALSE"));
473                 ctx->modemPowered(powered);
474                 // !!! won't request calls here, since the service may not be available yet
475                 // see "Interfaces" "PropertyChanged" on OFONO_MODEM_IFACE
476                 //if(powered)
477                 //    ctx->getCalls();
478             }
479             else if(!strcmp(name, "Online")) {
480                 bool online = g_variant_get_boolean(value);
481                 LoggerD("\t" << name << " = " << (online?"TRUE":"FALSE"));
482             }
483             else if(!strcmp(name, "Interfaces")) {
484                 GVariantIter iter;
485                 GVariant *interface;
486                 GVariant *variant = g_variant_get_child_value(parameters,1); // signature: "v"
487                 GVariant *interfaces = g_variant_get_child_value(variant,0); // signature: "as"
488                 g_variant_iter_init(&iter, interfaces);
489                 while((interface = g_variant_iter_next_value(&iter))) {
490                     const char *iface = g_variant_get_string(interface, NULL);
491                     if(!strcmp(iface, OFONO_VOICECALLMANAGER_IFACE)) {
492                         //TODO: ??? check if the service is newly added ??? - not to request calls multiple times
493                         // service is up, request active calls now
494                         ctx->getCalls();
495                     }
496                 };
497             }
498         }
499     }
500     else if(!strcmp(interface_name, OFONO_VOICECALLMANAGER_IFACE)) {
501         if(!strcmp(signal_name, "CallAdded")) {
502             if(!parameters) {
503                 LoggerE("Invalid parameters");
504                 return;
505             }
506
507             const char *path = NULL;
508             GVariantIter *props = NULL;
509             g_variant_get(parameters, "(oa{sv})", &path, &props);
510             ctx->addCall(path, props);
511         }
512         else if(!strcmp(signal_name, "CallRemoved")) {
513             if(!parameters) {
514                 LoggerD("Invalid parameters");
515                 return;
516             }
517             // TODO: do the check for the call
518             // for now, remove just the active one
519             ctx->removeCall(&ctx->mActiveCall);
520         }
521         else {
522             LoggerD("un-handled signal \"" << signal_name << "\" on " << interface_name);
523         }
524     }
525     else if(!strcmp(interface_name, OFONO_VOICECALL_IFACE)) {
526         if(!strcmp(signal_name, "PropertyChanged")) {
527             const char *key = NULL;
528             GVariant *value = NULL;
529             g_variant_get(parameters, "(sv)", &key, &value);
530             if(!strcmp(key, "State")) {
531                 const char *state = NULL;
532                 g_variant_get(value, "s", &state);
533                 if(ctx->mActiveCall->state)
534                     g_free(ctx->mActiveCall->state);
535                 ctx->mActiveCall->state = strdup(state);
536                 LoggerD("PROPERTY CHANGED: " << key << " = " << state);
537             }
538             else {
539                 LoggerD("PROPERTY CHANGED: " << key);
540             }
541             // TODO: check for the remaining properties
542             ctx->callChanged(ctx->mActiveCall->state, ctx->mActiveCall->line_id);
543         }
544     }
545     else {
546         LoggerD("signal received for un-handled IFACE: " << interface_name);
547     }
548 }
549
550 void OFono::addCall(const char *path, GVariantIter *props) {
551     LoggerD("entered");
552
553     // only one call at a time is curently supported
554     if(mActiveCall) {
555         LoggerD("Unable to add a call when another is on-going");
556         return;
557     }
558
559     if(!path)
560         return;
561
562     mActiveCall = new OFono::Call();
563     mActiveCall->path = strdup(path);
564
565     Utils::setSignalListener(G_BUS_TYPE_SYSTEM, OFONO_SERVICE,
566                              OFONO_VOICECALL_IFACE, path,
567                              "PropertyChanged", OFono::handleSignal,
568                              this);
569
570     const char *key = NULL;
571     GVariant *value = NULL;
572     while(g_variant_iter_next(props, "{sv}", &key, &value)) {
573         if(!strcmp(key, "State")) {
574             const char *state = NULL;
575             g_variant_get(value, "s", &state);
576             mActiveCall->state = state ? strdup(state) : NULL;
577         }
578         else if(!strcmp(key, "LineIdentification")) {
579             const char *line_id = NULL;
580             g_variant_get(value, "s", &line_id);
581             mActiveCall->line_id = line_id ? strdup(line_id) : NULL;
582         }
583     }
584
585     // notify listener about call state changed
586     if(!!mActiveCall->state && !!mActiveCall->line_id) {
587         callChanged(mActiveCall->state, mActiveCall->line_id);
588     }
589 }
590
591 void OFono::removeCall(OFono::Call **call) {
592     LoggerD("entered");
593
594     // unsubscribe and remove signal listeners for the call
595     Utils::removeSignalListener(G_BUS_TYPE_SYSTEM, OFONO_SERVICE,
596                                 OFONO_VOICECALL_IFACE, (*call)->path,
597                                 "PropertyChanged");
598
599     if(*call) {
600         delete *call;
601         *call = NULL;
602     }
603 }
604
605 bool OFono::invokeCall(const char* phoneNumber, char **error) {
606     if(!mModemPath) { // no selected modem to perform operation on
607         *error = strdup("No active modem set");
608         return false;
609     }
610
611     if(mActiveCall) { // active call
612         *error = strdup("Already active call");
613         return false;
614     }
615
616     GError *err = NULL;
617     GVariant *reply;
618     reply = g_dbus_connection_call_sync( g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL,NULL),
619                                          OFONO_SERVICE,
620                                          mModemPath,
621                                          OFONO_VOICECALLMANAGER_IFACE,
622                                          "Dial",
623                                          g_variant_new ("(ss)", // floating parameters are consumed, no cleanup/unref needed
624                                              phoneNumber,
625                                              ""
626                                          ),
627                                          NULL,
628                                          G_DBUS_CALL_FLAGS_NONE,
629                                          -1,
630                                          NULL,
631                                          &err);
632
633     if(err) {
634         LoggerE("Failed to call 'Dial' DBUS method: " << err->message);
635         *error = strdup(err->message);
636         g_error_free(err);
637         return false;
638     }
639
640     if(!reply) {
641         LoggerE("Reply from calling 'Dial' is NULL");
642         *error = strdup("Failed to get 'call' object from OFONO's 'Dial' reply");
643         return false;
644     }
645
646     // TODO: process reply here - ??? is it really needed 'cause we are handling CallAdded signal anyway ???
647     g_variant_unref(reply);
648
649     return true;
650 }
651
652 bool OFono::answerCall(char **error) {
653     if(!mActiveCall) { // no active call to hangup
654         *error = strdup("No active call");
655         return false;
656     }
657
658     GError *err = NULL;
659     g_dbus_connection_call_sync (g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL,NULL),
660                     OFONO_SERVICE,
661                     mActiveCall->path,
662                     OFONO_VOICECALL_IFACE,
663                     "Answer",
664                     NULL,
665                     NULL,
666                     G_DBUS_CALL_FLAGS_NONE,
667                     -1,
668                     NULL,
669                     &err);
670
671     if(err) {
672         LoggerD("Failed to call 'Answer' DBUS method: " << err->message);
673         *error = strdup(err->message);
674         g_error_free(err);
675         return false;
676     }
677
678     return true;
679 }
680
681 bool OFono::hangupCall(char **error) {
682     if(!mActiveCall) { // no active call to hangup
683         *error = strdup("No active call");
684         return false;
685     }
686
687     GError *err = NULL;
688     g_dbus_connection_call_sync (g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL,NULL),
689                     OFONO_SERVICE,
690                     mActiveCall->path,
691                     OFONO_VOICECALL_IFACE,
692                     "Hangup",
693                     NULL,
694                     NULL,
695                     G_DBUS_CALL_FLAGS_NONE,
696                     -1,
697                     NULL,
698                     &err);
699
700     if(err) {
701         LoggerD("Failed to call 'Hangup' DBUS method: " << err->message);
702         *error = strdup(err->message);
703         g_error_free(err);
704         return false;
705     }
706
707     return true;
708 }
709
710 OFono::Call *OFono::activeCall() {
711     LoggerD("OFono::activeCall()");
712     // make a copy of object, since it may be destroyed meanwhile
713     return mActiveCall ? new OFono::Call(mActiveCall) : NULL;
714 }
715
716 bool OFono::muteCall(bool mute, char **error) {
717     if(!mActiveCall) { // no active call to hangup
718         *error = strdup("No active call");
719         return false;
720     }
721
722     bool success = setProperty(OFONO_CALLVOLUME_IFACE, mModemPath, "Muted", DBUS_TYPE_BOOLEAN, &mute);
723     if(!success) {
724         *error = strdup("Failed to set 'Muted' property on the call");
725         return false;
726     }
727
728     return true;
729 }
730
731 } // PhoneD
732