Tizen 2.0 Release
[framework/connectivity/bluez.git] / audio / telephony-tizen.c
1 /*
2  *  Bluetooth protocol stack for Linux
3  *
4  * Copyright (c) 2000 - 2010 Samsung Electronics Co., Ltd.
5  *
6  * Contact: Chethan  T N <chethan.tn@samsung.com>
7  *
8  * This library is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU Lesser General Public License as published by the
10  * Free Software Foundation; either version 2.1 of the License, or (at your option)
11  * any later version.
12  *
13  * This library is distributed in the hope that it will be useful, but WITHOUT ANY
14  * WARRANTY; without even the implied warranty of MERCHANTABILITY or
15  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
16  * License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this library; if not, write to the Free Software Foundation, Inc., 51
20  * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  *
22  *//*:Associate with "Bluetooth" */
23
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <unistd.h>
27 #include <fcntl.h>
28 #include <stdint.h>
29 #include <string.h>
30 #include <glib.h>
31 #include <glib-object.h>
32
33 #include <dbus/dbus.h>
34 #include <gdbus.h>
35
36 #include "log.h"
37 #include "telephony.h"
38 #include "error.h"
39
40
41 /* CSD CALL plugin D-Bus definitions */
42 #define CSD_CALL_BUS_NAME       "org.tizen.csd"
43 #define CSD_CALL_INTERFACE      "org.tizen.csd.Call"
44 #define CSD_CALL_INSTANCE       "org.tizen.csd.Call.Instance"
45 #define CSD_CALL_CONFERENCE_PATH "/org/tizen/csd/call/conference"
46 #define CSD_DEVICE_INTERFACE    "org.tizen.device"
47
48 /* Phonebook definitions */
49 #define PHONEBOOK_BUS_NAME      "org.bluez.pb_agent"
50 #define PHONEBOOK_PATH          "/org/bluez/pb_agent"
51 #define PHONEBOOK_INTERFACE     "org.bluez.PbAgent.At"
52
53 #define CALL_FLAG_NONE  0
54 #define CALL_FLAG_PRESENTATION_ALLOWED          0x01
55 #define CALL_FLAG_PRESENTATION_RESTRICTED       0x02
56
57 #define TELEPHONY_CSD_INTERFACE "org.tizen.telephony.csd"
58 #define TELEPHONY_CSD_OBJECT_PATH       "/org/tizen/csd"
59
60 #define HFP_AGENT_SERVICE "org.bluez.hfp_agent"
61 #define HFP_AGENT_PATH "/org/bluez/hfp_agent"
62 #define HFP_AGENT_INTERFACE "Org.Hfp.Bluez.Interface"
63
64 /* Call status values as exported by the CSD CALL plugin */
65 #define CSD_CALL_STATUS_IDLE                    0
66 #define CSD_CALL_STATUS_CREATE                  1
67 #define CSD_CALL_STATUS_COMING                  2
68 #define CSD_CALL_STATUS_PROCEEDING              3
69 #define CSD_CALL_STATUS_MO_ALERTING             4
70 #define CSD_CALL_STATUS_MT_ALERTING             5
71 #define CSD_CALL_STATUS_WAITING                 6
72 #define CSD_CALL_STATUS_ANSWERED                7
73 #define CSD_CALL_STATUS_ACTIVE                  8
74 #define CSD_CALL_STATUS_MO_RELEASE              9
75 #define CSD_CALL_STATUS_MT_RELEASE              10
76 #define CSD_CALL_STATUS_HOLD_INITIATED          11
77 #define CSD_CALL_STATUS_HOLD                    12
78 #define CSD_CALL_STATUS_RETRIEVE_INITIATED      13
79 #define CSD_CALL_STATUS_RECONNECT_PENDING       14
80 #define CSD_CALL_STATUS_TERMINATED              15
81 #define CSD_CALL_STATUS_SWAP_INITIATED          16
82
83
84 #define PREFFERED_MESSAGE_STORAGE_LIST "(\"ME\",\"MT\",\"SM\",\"SR\"),(\"ME\",\"MT\",\"SM\",\"SR\"),(\"ME\",\"MT\",\"SM\",\"SR\")"
85
86 #define PREFFERED_MESSAGE_STORAGE_MAX 500
87 #define CALL_LOG_COUNT_MAX 30
88 #define PHONEBOOK_COUNT_MAX 1000
89
90 #define PHONEBOOK_NAME_MAX_LENGTH 20
91 #define PHONEBOOK_NUMBER_MAX_LENGTH 20
92 #define PHONEBOOK_MAX_CHARACTER_LENGTH  20
93
94 #define PHONEBOOK_READ_RESP_LENGTH 20
95
96 enum {
97         CHARSET_UTF_8 = 0,
98         CHARSET_IRA
99 };
100
101 static const char *character_set_list[] = {
102         "\"UTF-8\"", "\"IRA\""
103 };
104
105 static const char *phonebook_store_list[] =  {
106         "\"ME\"", "\"DC\"", "\"MC\"", "\"RC\""
107 };
108
109 #define CHARACTER_SET_LIST_SIZE (sizeof(character_set_list)/sizeof(const char *))
110 #define PHONEBOOK_STORE_LIST_SIZE (sizeof(phonebook_store_list)/sizeof(const char *))
111
112 typedef struct {
113         uint8_t utf_8;
114         uint8_t gsm;
115 } GsmUnicodeTable;
116
117
118  /*0xC3 charcterset*/
119 const GsmUnicodeTable gsm_unicode_C3[] = {
120         {0xA8,0x04}, {0xA9,0x05}, {0xB9,0x06}, {0xAC,0x07}, {0xB2,0x08},
121         {0xB7,0x09}, {0x98,0x0B}, {0xB8,0x0C}, {0x85,0x0E}, {0xA5,0x0F},
122         {0x86,0x1C}, {0xA6,0x1D}, {0x9F,0x1E}, {0x89,0x1F}, {0x84,0x5B},
123         {0x96,0x5C}, {0x91,0x5D}, {0x9C,0x5E}, {0x80,0x5F}, {0xA4,0x7B},
124         {0xB6,0x7C}, {0xB1,0x7D}, {0xBC,0x7E}, {0xA0,0x7F},
125 };
126
127 /*0xCE charcterset*/
128 const GsmUnicodeTable gsm_unicode_CE[] = {
129         {0x85,0x14}, {0xA1,0x50}, {0x98,0x19}, {0xA0,0x16}, {0x94,0x10},
130         {0xA6,0x12}, {0x93,0x13}, {0x9E,0x1A}, {0x9B,0x14}, {0xA8,0x17},
131         {0xA9,0x15},
132 };
133
134 #define GSM_UNI_MAX_C3  (sizeof(gsm_unicode_C3)/sizeof(GsmUnicodeTable))
135 #define GSM_UNI_MAX_CE  (sizeof(gsm_unicode_CE)/sizeof(GsmUnicodeTable))
136
137
138 static DBusConnection *ag_connection = NULL;
139
140 static GSList *calls = NULL;
141
142 static gboolean events_enabled = FALSE;
143 static uint32_t callerid = 0;
144
145 /* Reference count for determining the call indicator status */
146 static GSList *active_calls = NULL;
147 static GSList *sender_paths = NULL;
148
149 typedef struct {
150         gchar *sender;
151         gchar *path;
152         unsigned int watch_id;
153 } sender_path_t;
154
155 static struct indicator telephony_ag_indicators[] =
156 {
157         { "battchg",    "0-5",  5,      TRUE },
158         /* signal strength in terms of bars */
159         { "signal",     "0-5",  0,      TRUE },
160         { "service",    "0,1",  0,      TRUE },
161         { "call",       "0,1",  0,      TRUE },
162         { "callsetup",  "0-3",  0,      TRUE },
163         { "callheld",   "0-2",  0,      FALSE },
164         { "roam",       "0,1",  0,      TRUE },
165         { NULL }
166 };
167
168 static char *call_status_str[] = {
169         "IDLE",
170         "CREATE",
171         "COMING",
172         "PROCEEDING",
173         "MO_ALERTING",
174         "MT_ALERTING",
175         "WAITING",
176         "ANSWERED",
177         "ACTIVE",
178         "MO_RELEASE",
179         "MT_RELEASE",
180         "HOLD_INITIATED",
181         "HOLD",
182         "RETRIEVE_INITIATED",
183         "RECONNECT_PENDING",
184         "TERMINATED",
185         "SWAP_INITIATED",
186         "???"
187 };
188
189 enum net_registration_status {
190         NETWORK_REG_STATUS_HOME,
191         NETWORK_REG_STATUS_ROAMING,
192         NETWORK_REG_STATUS_OFFLINE,
193         NETWORK_REG_STATUS_SEARCHING,
194         NETWORK_REG_STATUS_NO_SIM,
195         NETWORK_REG_STATUS_POWEROFF,
196         NETWORK_REG_STATUS_POWERSAFE,
197         NETWORK_REG_STATUS_NO_COVERAGE,
198         NETWORK_REG_STATUS_REJECTED,
199         NETWORK_REG_STATUS_UNKOWN
200 };
201
202 struct csd_call {
203         char *path;
204         int status;
205         gboolean originating;
206         gboolean emergency;
207         gboolean on_hold;
208         gboolean conference;
209         char *number;
210         gboolean setup;
211         uint32_t call_id;
212         char *sender;
213 };
214
215 static struct {
216         char *operator_name;
217         uint8_t status;
218         int32_t signal_bars;
219 } net = {
220         .operator_name = NULL,
221         .status = NETWORK_REG_STATUS_UNKOWN,
222         /* Init as 0 meaning inactive mode. In modem power off state
223          * can be be -1, but we treat all values as 0s regardless
224          * inactive or power off. */
225         .signal_bars = 0,
226 };
227
228 /* Supported set of call hold operations */
229 /*static const char *telephony_chld_str = "0,1,1x,2,2x,3,4";*/
230 static const char *telephony_chld_str = "0,1,2,3";
231
232
233 static char *subscriber_number = NULL;  /* Subscriber number */
234
235
236 static struct {
237         int32_t path_id;
238         int32_t charset_id;
239 } ag_pb_info = {
240         .path_id = 0,
241         .charset_id = 0,
242 };
243
244 static void call_set_status(struct csd_call *call, dbus_uint32_t status);
245
246 static void free_sender_path(sender_path_t *s_path)
247 {
248         if (s_path == NULL)
249                 return;
250
251         g_free(s_path->path);
252         g_free(s_path->sender);
253         g_free(s_path);
254 }
255
256 static void free_sender_list()
257 {
258         GSList *l;
259
260         for (l = sender_paths; l != NULL; l = l->next) {
261                 free_sender_path(l->data);
262         }
263         g_slist_free(sender_paths);
264         sender_paths = NULL;
265         return;
266 }
267
268 static int telephony_remove_from_sender_list(const char *sender, const char *path)
269 {
270         GSList *l;
271         sender_path_t *s_path;
272
273         if (sender == NULL || path == NULL)
274                 return  -EINVAL;
275
276         for (l = sender_paths; l != NULL; l = l->next) {
277                 s_path = l->data;
278                 if (s_path == NULL)
279                         return -ENOENT;
280                 if (g_strcmp0(s_path->path, path) == 0) {
281                         g_dbus_remove_watch(ag_connection, s_path->watch_id);
282                         sender_paths = g_slist_remove(sender_paths, s_path);
283                         free_sender_path(s_path);
284
285                         /*Free sender_paths if no application is registered*/
286                         if (0 == g_slist_length(sender_paths)) {
287                                 g_slist_free(sender_paths);
288                                 sender_paths = NULL;
289                         }
290                         return 0;
291                 }
292         }
293         return -ENOENT;
294 }
295
296 static void remove_call_with_sender(gchar *sender)
297 {
298         GSList *l;
299
300         DBG("+\n");
301
302         if (sender == NULL)
303                 return;
304
305         for (l = calls; l != NULL; l = l->next) {
306                 struct csd_call *call = l->data;
307
308                 if (g_strcmp0(call->sender, sender) == 0)
309                         /* Release the Call and inform headset */
310                         call_set_status(call, CSD_CALL_STATUS_MT_RELEASE);
311         }
312
313         DBG("-\n");
314 }
315
316 static void telephony_app_exit_cb(DBusConnection *conn, void *user_data)
317 {
318         sender_path_t *s_path = (sender_path_t *)user_data;
319
320         DBG("+\n");
321
322         if (s_path == NULL)
323                 return;
324
325         /* check any active call from application */
326         remove_call_with_sender(s_path->sender);
327
328         if (!telephony_remove_from_sender_list(s_path->sender, s_path->path))
329                 DBG("Application removed \n");
330         else
331                 DBG("Application not removed \n");
332         DBG("-\n");
333 }
334
335 static gboolean telephony_is_registered(const char *path)
336 {
337         GSList *l;
338         sender_path_t *s_path;
339
340         if (path == NULL || sender_paths == NULL)
341                 return FALSE;
342
343         for (l = sender_paths; l != NULL; l = l->next) {
344                 s_path = l->data;
345                 if (s_path == NULL)
346                         break;
347
348                 if (g_strcmp0(s_path->path, path) == 0) {
349                         return TRUE;
350                 }
351         }
352         return FALSE;
353 }
354
355 static gboolean telephony_is_call_allowed(const char *path)
356 {
357         GSList *l;
358
359         if (path == NULL)
360                 return FALSE;
361
362         /*if call list doesn't exist the call should be allowed, since its a new call*/
363         if (!calls)
364                 return TRUE;
365
366         for (l = calls; l != NULL; l = l->next) {
367                 struct csd_call *call = l->data;
368
369                 if (g_strcmp0(call->path, path) == 0)
370                         return TRUE;
371
372         }
373         return FALSE;
374 }
375
376 static int telephony_add_to_sender_list(const char *sender, const char *path)
377 {
378         sender_path_t *s_path;
379
380         if (sender == NULL || path == NULL)
381                 return -EINVAL;
382
383         /*check if already registered*/
384         if (telephony_is_registered(path)) {
385                 return -EEXIST;
386         }
387
388         s_path = g_new0(sender_path_t, 1);
389         s_path->path = g_strdup(path);
390         s_path->sender = g_strdup(sender);
391         s_path->watch_id = g_dbus_add_disconnect_watch(ag_connection, sender,
392                                         telephony_app_exit_cb, s_path, NULL);
393         sender_paths = g_slist_append(sender_paths, s_path);
394         return 0;
395 }
396
397 static struct csd_call *find_call_with_id(uint32_t call_id)
398
399 {
400         GSList *l;
401
402         for (l = calls; l != NULL; l = l->next) {
403                 struct csd_call *call = l->data;
404
405                 if (call->call_id == call_id)
406                         return call;
407         }
408
409         return NULL;
410 }
411
412 static struct csd_call *find_non_held_call(void)
413 {
414         GSList *l;
415
416         for (l = calls; l != NULL; l = l->next) {
417                 struct csd_call *call = l->data;
418
419                 if (call->status == CSD_CALL_STATUS_IDLE)
420                         continue;
421
422                 if (call->status != CSD_CALL_STATUS_HOLD)
423                         return call;
424         }
425
426         return NULL;
427 }
428
429 static struct csd_call *find_non_idle_call(void)
430 {
431         GSList *l;
432
433         for (l = calls; l != NULL; l = l->next) {
434                 struct csd_call *call = l->data;
435
436                 if (call->status != CSD_CALL_STATUS_IDLE)
437                         return call;
438         }
439
440         return NULL;
441 }
442
443 static struct csd_call *find_call_with_status(int status)
444 {
445         GSList *l;
446
447         if (NULL != calls) {
448                 for (l = calls; l != NULL; l = l->next) {
449                         struct csd_call *call = l->data;
450
451                         if (call->status == status)
452                                 return call;
453                 }
454         }
455         return NULL;
456 }
457
458 static void csd_call_free(struct csd_call *call)
459 {
460         if (!call)
461                 return;
462
463         g_free(call->path);
464         g_free(call->number);
465         g_free(call->sender);
466
467         g_free(call);
468 }
469
470 static int reject_call(struct csd_call *call)
471 {
472         DBusMessage *msg;
473
474         DBG("+\n");
475
476         DBG("telephony-tizen: reject_call ");
477
478         msg = dbus_message_new_method_call(HFP_AGENT_SERVICE, HFP_AGENT_PATH,
479                                         HFP_AGENT_INTERFACE, "RejectCall");
480         if (!msg) {
481                 error("Unable to allocate new D-Bus message");
482                 return -ENOMEM;
483         }
484         DBG(" Path =[ %s] and Call id = [%d]\n", call->path, call->call_id);
485         if (!dbus_message_append_args(msg, DBUS_TYPE_UINT32, &call->call_id,
486                         DBUS_TYPE_STRING, &call->path,
487                         DBUS_TYPE_STRING, &call->sender,
488                         DBUS_TYPE_INVALID)) {
489
490                 DBG("dbus_message_append_args -ENOMEM\n");
491                 dbus_message_unref(msg);
492                 return -ENOMEM;
493         }
494
495         g_dbus_send_message(ag_connection, msg);
496
497         DBG("-\n");
498
499         return 0;
500
501 }
502
503 static int release_call(struct csd_call *call)
504 {
505         DBusMessage *msg;
506
507         DBG("+\n");
508
509         DBG("telephony-tizen: release_call ");
510
511         msg = dbus_message_new_method_call(HFP_AGENT_SERVICE, HFP_AGENT_PATH,
512                                         HFP_AGENT_INTERFACE, "ReleaseCall");
513         if (!msg) {
514                 error("Unable to allocate new D-Bus message");
515                 return -ENOMEM;
516         }
517         DBG("Path =[ %s] and Call id = [%d]\n", call->path, call->call_id);
518         if (!dbus_message_append_args(msg, DBUS_TYPE_UINT32, &call->call_id,
519                         DBUS_TYPE_STRING, &call->path,
520                         DBUS_TYPE_STRING, &call->sender,
521                         DBUS_TYPE_INVALID)) {
522
523                 DBG("dbus_message_append_args -ENOMEM\n");
524                 dbus_message_unref(msg);
525                 return -ENOMEM;
526         }
527
528         g_dbus_send_message(ag_connection, msg);
529
530         DBG("-\n");
531
532         return 0;
533 }
534
535 static int release_conference(void)
536 {
537         GSList *l;
538
539         DBG("+\n");
540
541         for (l = calls; l != NULL; l = l->next) {
542                 struct csd_call *call = l->data;
543
544                 if (call->conference)
545                         release_call(call);
546         }
547
548         DBG("-\n");
549
550         return 0;
551 }
552
553 static int dbus_method_call_send(const char *dest, const char *path,
554                                 const char *interface, const char *method,
555                                 DBusPendingCallNotifyFunction cb,
556                                 void *user_data, int type, ...)
557 {
558         DBusMessage *msg;
559         DBusPendingCall *call;
560         va_list args;
561
562         DBG("+\n");
563
564         msg = dbus_message_new_method_call(dest, path, interface, method);
565         if (!msg) {
566                 error("Unable to allocate new D-Bus %s message", method);
567                 return -ENOMEM;
568         }
569
570         va_start(args, type);
571
572         if (!dbus_message_append_args_valist(msg, type, args)) {
573                 dbus_message_unref(msg);
574                 va_end(args);
575                 return -EIO;
576         }
577
578         va_end(args);
579
580         if (!cb) {
581                 g_dbus_send_message(ag_connection, msg);
582                 return 0;
583         }
584
585         if (!dbus_connection_send_with_reply(ag_connection, msg, &call, -1)) {
586                 error("Sending %s failed", method);
587                 dbus_message_unref(msg);
588                 return -EIO;
589         }
590
591         dbus_pending_call_set_notify(call, cb, user_data, NULL);
592         dbus_message_unref(msg);
593         DBG("-\n");
594
595         return 0;
596 }
597
598 static int answer_call(struct csd_call *call)
599 {
600         DBusMessage *msg;
601         DBG("+\n");
602
603         msg = dbus_message_new_method_call(HFP_AGENT_SERVICE, HFP_AGENT_PATH,
604                                         HFP_AGENT_INTERFACE, "AnswerCall");
605         if (!msg) {
606                 error("Unable to allocate new D-Bus message");
607                 return -ENOMEM;
608         }
609
610         if (!dbus_message_append_args(msg, DBUS_TYPE_UINT32, &call->call_id,
611                         DBUS_TYPE_STRING, &call->path,
612                         DBUS_TYPE_STRING, &call->sender,
613                         DBUS_TYPE_INVALID)) {
614
615                 DBG("dbus_message_append_args -ENOMEM\n");
616                 dbus_message_unref(msg);
617                 return -ENOMEM;
618         }
619         g_dbus_send_message(ag_connection, msg);
620         DBG("-\n");
621         return 0;
622 }
623
624 static int reject_accept_call(struct csd_call *call, void *telephony_device)
625 {
626         uint32_t chld_value = 1;
627
628         return dbus_method_call_send(HFP_AGENT_SERVICE, HFP_AGENT_PATH,
629                         HFP_AGENT_INTERFACE, "ThreewayCall",
630                         NULL, telephony_device,
631                         DBUS_TYPE_UINT32, &chld_value,
632                         DBUS_TYPE_STRING, &call->path,
633                         DBUS_TYPE_STRING, &call->sender,
634                         DBUS_TYPE_INVALID);
635 }
636
637 static int number_type(const char *number)
638 {
639         if (number == NULL)
640                 return NUMBER_TYPE_TELEPHONY;
641
642         if (number[0] == '+' || strncmp(number, "00", 2) == 0)
643                 return NUMBER_TYPE_INTERNATIONAL;
644
645         return NUMBER_TYPE_TELEPHONY;
646 }
647
648 /* Since we dont have support from voice call regarding call conference this */
649 /* function will handle both join and split scenarios */
650
651 /* This function checks the status of each call in the list and set/unset */
652 /* conference status based on below algorithm */
653 /* If more that one active/held calls are there, conf flag of those calls will be set */
654 /* If only one active/held call is there, conf flag of those calls will be unset */
655 static void handle_conference(void)
656 {
657         GSList *l;
658         struct csd_call *first_active_call = NULL;
659         struct csd_call *first_held_call = NULL;
660         int active_call_count = 0;
661         int held_call_count = 0;
662
663         for (l = calls; l != NULL; l = l->next) {
664                 struct csd_call *call = l->data;
665
666                 if (call->status == CSD_CALL_STATUS_ACTIVE) {
667                         if (first_active_call == NULL)
668                                 first_active_call = call;
669
670                         active_call_count++;
671
672                         if (active_call_count >= 2) {
673                                 if (!first_active_call->conference)
674                                         first_active_call->conference = TRUE;
675                                 call->conference = TRUE;
676                         }
677
678                 } else if (call->status == CSD_CALL_STATUS_HOLD) {
679                         if (first_held_call == NULL)
680                                 first_held_call = call;
681
682                         held_call_count++;
683
684                         if (held_call_count >= 2) {
685                                 if (!first_held_call->conference)
686                                         first_held_call->conference = TRUE;
687                                 call->conference = TRUE;
688                         }
689                 }
690         }
691
692         if (active_call_count == 1) {
693                 if (first_active_call->conference)
694                         first_active_call->conference = FALSE;
695         }
696
697         if (held_call_count == 1) {
698                 if (first_held_call->conference)
699                         first_held_call->conference = FALSE;
700         }
701 }
702
703 static void call_set_status(struct csd_call *call, dbus_uint32_t status)
704 {
705         dbus_uint32_t prev_status;
706         int callheld = 0;
707
708         DBG("+\n");
709
710         callheld = telephony_get_indicator(telephony_ag_indicators, "callheld");
711
712         prev_status = call->status;
713         DBG("Call %s Call id %d changed from %s to %s", call->path, call->call_id,
714                 call_status_str[prev_status], call_status_str[status]);
715
716         if (prev_status == status) {
717                 DBG("Ignoring CSD Call state change to existing state");
718                 return;
719         }
720
721         call->status = (int) status;
722
723         switch (status) {
724         case CSD_CALL_STATUS_IDLE:
725                 if (call->setup) {
726                         telephony_update_indicator(telephony_ag_indicators,
727                                                         "callsetup",
728                                                         EV_CALLSETUP_INACTIVE);
729                         if (!call->originating)
730                                 telephony_calling_stopped_ind();
731                 }
732
733                 g_free(call->number);
734                 call->number = NULL;
735                 call->originating = FALSE;
736                 call->emergency = FALSE;
737                 call->on_hold = FALSE;
738                 call->conference = FALSE;
739                 call->setup = FALSE;
740                 break;
741         case CSD_CALL_STATUS_CREATE:
742                 call->originating = TRUE;
743                 call->setup = TRUE;
744                 break;
745         case CSD_CALL_STATUS_COMING:
746                 call->originating = FALSE;
747                 call->setup = TRUE;
748                 break;
749         case CSD_CALL_STATUS_PROCEEDING:
750                 break;
751         case CSD_CALL_STATUS_MO_ALERTING:
752                 telephony_update_indicator(telephony_ag_indicators, "callsetup",
753                                                 EV_CALLSETUP_ALERTING);
754                 break;
755         case CSD_CALL_STATUS_MT_ALERTING:
756                 /* Some headsets expect incoming call notification before they
757                  * can send ATA command. When call changed status from waiting
758                  * to alerting we need to send missing notification. Otherwise
759                  * headsets like Nokia BH-108 or BackBeat 903 are unable to
760                  * answer incoming call that was previously waiting. */
761                 if (prev_status == CSD_CALL_STATUS_WAITING)
762                         telephony_incoming_call_ind(call->number,
763                                                 number_type(call->number));
764                 break;
765         case CSD_CALL_STATUS_WAITING:
766                 break;
767         case CSD_CALL_STATUS_ANSWERED:
768                 break;
769         case CSD_CALL_STATUS_ACTIVE:
770                 if (call->on_hold) {
771                         call->on_hold = FALSE;
772                         if (find_call_with_status(CSD_CALL_STATUS_HOLD))
773                                 telephony_update_indicator(telephony_ag_indicators,
774                                                         "callheld",
775                                                         EV_CALLHELD_MULTIPLE);
776                         else
777                                 telephony_update_indicator(telephony_ag_indicators,
778                                                         "callheld",
779                                                         EV_CALLHELD_NONE);
780                 } else {
781                         if (!g_slist_find(active_calls, call))
782                                 active_calls = g_slist_prepend(active_calls, call);
783                         if (g_slist_length(active_calls) == 1)
784                                 telephony_update_indicator(telephony_ag_indicators,
785                                                                 "call",
786                                                                 EV_CALL_ACTIVE);
787                         /* Upgrade callheld status if necessary */
788                         if (callheld == EV_CALLHELD_ON_HOLD)
789                                 telephony_update_indicator(telephony_ag_indicators,
790                                                         "callheld",
791                                                         EV_CALLHELD_MULTIPLE);
792                         telephony_update_indicator(telephony_ag_indicators,
793                                                         "callsetup",
794                                                         EV_CALLSETUP_INACTIVE);
795                         if (!call->originating)
796                                 telephony_calling_stopped_ind();
797                         call->setup = FALSE;
798                 }
799                 break;
800         case CSD_CALL_STATUS_MO_RELEASE:
801         case CSD_CALL_STATUS_MT_RELEASE:
802                 active_calls = g_slist_remove(active_calls, call);
803                 if (g_slist_length(active_calls) == 0)
804                         telephony_update_indicator(telephony_ag_indicators, "call",
805                                                         EV_CALL_INACTIVE);
806
807                 if ((prev_status == CSD_CALL_STATUS_MO_ALERTING) ||
808                         (prev_status == CSD_CALL_STATUS_COMING) ||
809                         (prev_status == CSD_CALL_STATUS_CREATE) ||
810                         (prev_status == CSD_CALL_STATUS_WAITING)) {
811                                 telephony_update_indicator(telephony_ag_indicators,
812                                                         "callsetup",
813                                                         EV_CALLSETUP_INACTIVE);
814                 }
815
816                 if (prev_status == CSD_CALL_STATUS_COMING) {
817                         if (!call->originating)
818                                 telephony_calling_stopped_ind();
819                 }
820                 calls = g_slist_remove(calls, call);
821                 csd_call_free(call);
822
823                 break;
824         case CSD_CALL_STATUS_HOLD_INITIATED:
825                 break;
826         case CSD_CALL_STATUS_HOLD:
827                 call->on_hold = TRUE;
828                 if (find_non_held_call())
829                         telephony_update_indicator(telephony_ag_indicators,
830                                                         "callheld",
831                                                         EV_CALLHELD_MULTIPLE);
832                 else
833                         telephony_update_indicator(telephony_ag_indicators,
834                                                         "callheld",
835                                                         EV_CALLHELD_ON_HOLD);
836                 break;
837         case CSD_CALL_STATUS_RETRIEVE_INITIATED:
838                 break;
839         case CSD_CALL_STATUS_RECONNECT_PENDING:
840                 break;
841         case CSD_CALL_STATUS_TERMINATED:
842                 if (call->on_hold &&
843                                 !find_call_with_status(CSD_CALL_STATUS_HOLD)) {
844                         telephony_update_indicator(telephony_ag_indicators,
845                                                         "callheld",
846                                                         EV_CALLHELD_NONE);
847                         return;
848                 }
849
850                 if (callheld == EV_CALLHELD_MULTIPLE &&
851                                 find_call_with_status(CSD_CALL_STATUS_HOLD) &&
852                                 !find_call_with_status(CSD_CALL_STATUS_ACTIVE))
853                         telephony_update_indicator(telephony_ag_indicators,
854                                                         "callheld",
855                                                         EV_CALLHELD_ON_HOLD);
856                 break;
857         case CSD_CALL_STATUS_SWAP_INITIATED:
858                 break;
859         default:
860                 error("Unknown call status %u", status);
861                 break;
862         }
863
864         /* Update the conference status of each call */
865         handle_conference();
866
867         DBG("-\n");
868 }
869
870 static void telephony_chld_reply(DBusPendingCall *call, void *data)
871 {
872         DBusMessage *reply = dbus_pending_call_steal_reply(call);
873         DBusError derr;
874
875         DBG("redial_reply");
876
877         dbus_error_init(&derr);
878         if (!dbus_set_error_from_message(&derr, reply)) {
879                 DBG("chld  reply: cmd is valid");
880                 telephony_dial_number_rsp(data, CME_ERROR_NONE);
881                 goto done;
882         }
883
884         DBG("chld_reply reply: %s", derr.message);
885
886         dbus_error_free(&derr);
887         telephony_dial_number_rsp(data, CME_ERROR_AG_FAILURE);
888
889 done:
890         dbus_message_unref(reply);
891 }
892
893 void telephony_call_hold_req(void *telephony_device, const char *cmd)
894 {
895         const char *idx;
896         struct csd_call *call;
897         int err = 0;
898         uint32_t chld_value;
899         GSList *l = NULL;
900         sender_path_t *s_path = NULL;
901
902         DBG("+\n");
903
904         DBG("telephony-tizen: got call hold request %s", cmd);
905
906         /* Find any Ongoing call, in active/held/waiting */
907         if (NULL == (call = find_call_with_status(CSD_CALL_STATUS_ACTIVE)))
908                 if (NULL == (call = find_call_with_status(
909                                                 CSD_CALL_STATUS_HOLD)))
910                         if (NULL == (call = find_call_with_status(
911                                                 CSD_CALL_STATUS_WAITING))) {
912                                 DBG("No Onging Call \n");
913                                 telephony_call_hold_rsp(telephony_device,
914                                                         CME_ERROR_AG_FAILURE);
915                                 return;
916                         }
917
918         /*Get sender path using call path*/
919         for (l = sender_paths; l != NULL; l = l->next) {
920                 s_path = l->data;
921                 if (s_path == NULL) {
922                         telephony_call_hold_rsp(telephony_device,
923                                                         CME_ERROR_AG_FAILURE);
924                         return;
925                 }
926                 if (g_strcmp0(s_path->path, call->path) == 0)
927                         break;
928         }
929
930         if (s_path == NULL) {
931                 telephony_call_hold_rsp(telephony_device,
932                                                 CME_ERROR_AG_FAILURE);
933                 return;
934         }
935
936         idx = &cmd[0];
937         chld_value = strtoul(idx, NULL, 0);
938
939         DBG("Sender = %s path = %s \n", s_path->sender, s_path->path);
940
941         err = dbus_method_call_send(HFP_AGENT_SERVICE, HFP_AGENT_PATH,
942                                 HFP_AGENT_INTERFACE, "ThreewayCall",
943                                 telephony_chld_reply, telephony_device,
944                                 DBUS_TYPE_UINT32, &chld_value,
945                                 DBUS_TYPE_STRING, &call->path,
946                                 DBUS_TYPE_STRING, &call->sender,
947                                 DBUS_TYPE_INVALID);
948
949         if (err)
950                 telephony_call_hold_rsp(telephony_device,
951                                         CME_ERROR_AG_FAILURE);
952         DBG("-\n");
953 }
954
955 static int update_registration_status(uint8_t status)
956 {
957         uint8_t new_status;
958         int ret = 0;
959         DBG("+\n");
960
961         new_status = status;
962
963         if (net.status == new_status)
964                 return ret;
965
966         switch (new_status) {
967         case NETWORK_REG_STATUS_HOME:
968                 ret = telephony_update_indicator(telephony_ag_indicators, "roam",
969                                                         EV_ROAM_INACTIVE);
970
971                 if (net.status > NETWORK_REG_STATUS_ROAMING) {
972                         ret = telephony_update_indicator(telephony_ag_indicators,
973                                                         "service",
974                                                         EV_SERVICE_PRESENT);
975                 }
976                 break;
977         case NETWORK_REG_STATUS_ROAMING:
978                 ret = telephony_update_indicator(telephony_ag_indicators, "roam",
979                                                         EV_ROAM_ACTIVE);
980
981                 if (net.status > NETWORK_REG_STATUS_ROAMING) {
982                         ret = telephony_update_indicator(telephony_ag_indicators,
983                                                         "service",
984                                                         EV_SERVICE_PRESENT);
985                 }
986                 break;
987         case NETWORK_REG_STATUS_OFFLINE:
988         case NETWORK_REG_STATUS_SEARCHING:
989         case NETWORK_REG_STATUS_NO_SIM:
990         case NETWORK_REG_STATUS_POWEROFF:
991         case NETWORK_REG_STATUS_POWERSAFE:
992         case NETWORK_REG_STATUS_NO_COVERAGE:
993         case NETWORK_REG_STATUS_REJECTED:
994         case NETWORK_REG_STATUS_UNKOWN:
995                 if (net.status < NETWORK_REG_STATUS_OFFLINE) {
996                         ret = telephony_update_indicator(telephony_ag_indicators,
997                                                         "service",
998                                                         EV_SERVICE_NONE);
999                 }
1000                 break;
1001         }
1002
1003         net.status = new_status;
1004
1005         DBG("telephony-tizen: registration status changed: %d", status);
1006         DBG("-\n");
1007
1008         return ret;
1009 }
1010
1011 static int update_signal_strength(int32_t signal_bars)
1012 {
1013         DBG("+\n");
1014
1015         if (signal_bars < 0) {
1016                 DBG("signal strength smaller than expected: %d < 0",
1017                                 signal_bars);
1018                 signal_bars = 0;
1019         } else if (signal_bars > 5) {
1020                 DBG("signal strength greater than expected: %d > 5",
1021                                 signal_bars);
1022                 signal_bars = 5;
1023         }
1024
1025         if (net.signal_bars == signal_bars)
1026                 return 0;
1027
1028         net.signal_bars = signal_bars;
1029         DBG("telephony-tizen: signal strength updated: %d/5", signal_bars);
1030
1031         return telephony_update_indicator(telephony_ag_indicators, "signal", signal_bars);
1032 }
1033
1034 static int update_battery_strength(int32_t battery_level)
1035 {
1036         int current_battchg = 0;
1037
1038         DBG("+\n");
1039
1040         current_battchg = telephony_get_indicator(telephony_ag_indicators, "battchg");
1041
1042         if (battery_level < 0) {
1043                 DBG("Battery strength smaller than expected: %d < 0",
1044                                                                 battery_level);
1045                 battery_level = 0;
1046         } else if (battery_level > 5) {
1047                 DBG("Battery strength greater than expected: %d > 5",
1048                                                                 battery_level);
1049                 battery_level = 5;
1050         }
1051         if (current_battchg == battery_level)
1052                 return 0;
1053
1054         DBG("telephony-tizen: battery strength updated: %d/5", battery_level);
1055         DBG("-\n");
1056
1057         return telephony_update_indicator(telephony_ag_indicators,
1058                         "battchg", battery_level);
1059 }
1060
1061
1062 static int update_operator_name(const char *name)
1063 {
1064         DBG("+\n");
1065         if (name == NULL)
1066                 return -EINVAL;
1067
1068         g_free(net.operator_name);
1069         net.operator_name = g_strndup(name, 16);
1070         DBG("telephony-tizen: operator name updated: %s", name);
1071         DBG("-\n");
1072         return 0;
1073 }
1074
1075 static int update_subscriber_number(const char *number)
1076 {
1077         DBG("+\n");
1078         if (number == NULL)
1079                 return -EINVAL;
1080
1081         g_free(subscriber_number);
1082         subscriber_number = g_strdup(number);
1083         DBG("telephony-tizen: subscriber_number updated: %s", subscriber_number);
1084         DBG("-\n");
1085         return 0;
1086 }
1087
1088 static DBusMessage *telephony_error_reply(DBusMessage *msg, int error)
1089 {
1090         switch (error) {
1091         case -ENOENT:
1092                 return btd_error_not_available(msg);
1093         case -ENODEV:
1094                 return btd_error_not_connected(msg);
1095         case -EBUSY:
1096                 return btd_error_busy(msg);
1097         case -EINVAL:
1098                 return btd_error_invalid_args(msg);
1099         case -EEXIST:
1100                 return btd_error_already_exists(msg);
1101         case -ENOMEM:
1102                 return btd_error_failed(msg, "No memory");
1103         case -EIO:
1104                 return btd_error_failed(msg, "I/O error");
1105         default:
1106                 return dbus_message_new_method_return(msg);
1107         }
1108 }
1109
1110 static struct csd_call *create_call(DBusMessage *msg, const char *path,
1111                                         const char *number, uint32_t call_id,
1112                                         const char *sender)
1113
1114 {
1115         struct csd_call *call;
1116
1117         call = find_call_with_id(call_id);
1118         if (!call) {
1119                 call = g_new0(struct csd_call, 1);
1120                 call->path = g_strdup(path);
1121                 call->call_id = call_id;
1122                 call->number = g_strdup(number);
1123                 call->sender = g_strdup(sender);
1124                 calls = g_slist_append(calls, call);
1125         }
1126         return call;
1127 }
1128
1129 static DBusMessage *incoming(DBusConnection *conn, DBusMessage *msg,
1130                                         void *data)
1131 {
1132         const char *number, *call_path;
1133         const char *sender;
1134         struct csd_call *call;
1135         uint32_t call_id;
1136         int ret;
1137         DBG("+\n");
1138         DBG("telephony_incoming()\n");
1139
1140         if (!dbus_message_get_args(msg, NULL,
1141                                         DBUS_TYPE_STRING, &call_path,
1142                                         DBUS_TYPE_STRING, &number,
1143                                         DBUS_TYPE_UINT32, &call_id,
1144                                         DBUS_TYPE_STRING, &sender,
1145                                         DBUS_TYPE_INVALID)) {
1146
1147                 return btd_error_invalid_args(msg);
1148         }
1149
1150         ret = telephony_is_registered(call_path);
1151         if (!ret)
1152                 return telephony_error_reply(msg,  -ENOENT);
1153
1154         /*Check in the active call list, if any of the call_path exists if not don't allow
1155         the call since it is initated by other applicatoin*/
1156
1157         ret = telephony_is_call_allowed(call_path);
1158         if (!ret)
1159                 return telephony_error_reply(msg,  -ENOENT);
1160
1161
1162         call = create_call(msg, call_path, number, call_id, sender);
1163
1164         DBG("Incoming call to %s from number %s call id %d", call_path, number, call_id);
1165         ret = telephony_update_indicator(telephony_ag_indicators, "callsetup",
1166                                         EV_CALLSETUP_INCOMING);
1167         if (ret)
1168                 return telephony_error_reply(msg, ret);
1169
1170         if (find_call_with_status(CSD_CALL_STATUS_ACTIVE) ||
1171                         find_call_with_status(CSD_CALL_STATUS_HOLD)) {
1172                 ret = telephony_call_waiting_ind(call->number,
1173                                                 number_type(call->number));
1174                 if (ret)
1175                         return telephony_error_reply(msg, ret);
1176
1177                 call_set_status(call, CSD_CALL_STATUS_WAITING);
1178         } else {
1179                 ret = telephony_incoming_call_ind(call->number,
1180                                                 number_type(call->number));
1181                 if (ret)
1182                         return telephony_error_reply(msg, ret);
1183
1184                 call_set_status(call, CSD_CALL_STATUS_COMING);
1185         }
1186         DBG("-\n");
1187         return dbus_message_new_method_return(msg);
1188 }
1189
1190 static DBusMessage *outgoing(DBusConnection *conn, DBusMessage *msg,
1191                                         void *data)
1192 {
1193         const char *number, *call_path;
1194         const char *sender;
1195         struct csd_call *call;
1196         uint32_t call_id;
1197         int ret;
1198
1199         DBG("+\n");
1200         DBG("telephony_outgoing_call()\n");
1201
1202         if (!dbus_message_get_args(msg, NULL,
1203                                         DBUS_TYPE_STRING, &call_path,
1204                                         DBUS_TYPE_STRING, &number,
1205                                         DBUS_TYPE_UINT32, &call_id,
1206                                         DBUS_TYPE_STRING, &sender,
1207                                         DBUS_TYPE_INVALID)) {
1208                 return btd_error_invalid_args(msg);
1209         }
1210
1211         ret = telephony_is_registered(call_path);
1212         if (!ret)
1213                 return telephony_error_reply(msg, -ENOENT);
1214
1215         /*Check in the active call list, if any of the call_path exists if not don't allow
1216         the call since it is initated by other applicatoin*/
1217
1218         ret = telephony_is_call_allowed(call_path);
1219         if (!ret)
1220                 return telephony_error_reply(msg, -ENOENT);
1221
1222         call = create_call(msg, call_path, number, call_id, sender);
1223
1224         DBG("Outgoing call to %s from number %s call id %d", call_path, number, call_id);
1225
1226         call_set_status(call, CSD_CALL_STATUS_CREATE);
1227
1228         ret = telephony_update_indicator(telephony_ag_indicators, "callsetup",
1229                                         EV_CALLSETUP_OUTGOING);
1230         if (ret)
1231                 return telephony_error_reply(msg, ret);
1232
1233         DBG("-\n");
1234         return dbus_message_new_method_return(msg);
1235 }
1236
1237 static DBusMessage *set_call_status(DBusConnection *conn, DBusMessage *msg,
1238                                         void *data)
1239 {
1240         struct csd_call *call;
1241         dbus_uint32_t status, call_id;
1242         const char *call_path;
1243         const char *sender;
1244         int ret;
1245
1246         DBG("+\n");
1247
1248         if (!dbus_message_get_args(msg, NULL,
1249                                         DBUS_TYPE_STRING, &call_path,
1250                                         DBUS_TYPE_UINT32, &status,
1251                                         DBUS_TYPE_UINT32, &call_id,
1252                                         DBUS_TYPE_STRING, &sender,
1253                                         DBUS_TYPE_INVALID)) {
1254                 error("Unexpected paramters in Instance.CallStatus() signal");
1255                 return btd_error_invalid_args(msg);
1256         }
1257
1258         if (status > 16) {
1259                 return btd_error_invalid_args(msg);
1260         }
1261
1262         ret = telephony_is_registered(call_path);
1263         if (!ret)
1264                 return telephony_error_reply(msg, -ENOENT);
1265
1266         ret = telephony_is_call_allowed(call_path);
1267         if (!ret)
1268                 return telephony_error_reply(msg, -ENOENT);
1269
1270         DBG("status = [%d] and call_id = [%d] \n", status, call_id);
1271
1272         call = find_call_with_id(call_id);
1273         if (!call) {
1274 /*
1275         call_path is equal to CSD_CALL_PATH then we should update the call list
1276         since the call_path is sent from native AG applicaton
1277
1278         Added for updation of the call status if the call is not added in the call list
1279 */
1280                 call = create_call(msg, call_path, NULL, call_id, sender);
1281         }
1282         call_set_status(call, status);
1283         DBG("-\n");
1284         return dbus_message_new_method_return(msg);
1285 }
1286
1287 static DBusMessage *register_telephony_agent(DBusConnection *conn, DBusMessage *msg,
1288                                         void *data)
1289 {
1290         gboolean flag;
1291         const char *sender;
1292         const char *path;
1293         int ret;
1294
1295         DBG("+\n");
1296
1297         if (!dbus_message_get_args(msg, NULL,
1298                                         DBUS_TYPE_BOOLEAN, &flag,
1299                                         DBUS_TYPE_STRING, &path,
1300                                         DBUS_TYPE_STRING, &sender,
1301                                         DBUS_TYPE_INVALID)) {
1302                 error("Unexpected parameters in RegisterSenderPath");
1303                 return btd_error_invalid_args(msg);
1304         }
1305
1306         DBG("flag = %d \n", flag);
1307         DBG("Sender = %s \n", sender);
1308         DBG("path = %s \n", path);
1309
1310         if (flag)
1311                 ret = telephony_add_to_sender_list(sender, path);
1312         else
1313                 ret = telephony_remove_from_sender_list(sender, path);
1314
1315         if (ret)
1316                 return telephony_error_reply(msg, ret);
1317
1318         DBG("-\n");
1319
1320         return dbus_message_new_method_return(msg);
1321 }
1322
1323 static DBusMessage *set_property(DBusConnection *conn, DBusMessage *msg,
1324                                         void *data)
1325 {
1326         const char *property;
1327         DBusMessageIter iter;
1328         DBusMessageIter sub;
1329         int ret;
1330
1331         if (!dbus_message_iter_init(msg, &iter))
1332                 return btd_error_invalid_args(msg);
1333
1334         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
1335                 return btd_error_invalid_args(msg);
1336
1337         dbus_message_iter_get_basic(&iter, &property);
1338         dbus_message_iter_next(&iter);
1339
1340         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
1341                 return btd_error_invalid_args(msg);
1342         dbus_message_iter_recurse(&iter, &sub);
1343
1344         if (g_str_equal("RegistrationChanged", property)) {
1345                 uint8_t value;
1346                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BYTE)
1347                         return btd_error_invalid_args(msg);
1348
1349                 dbus_message_iter_get_basic(&sub, &value);
1350
1351                 ret = update_registration_status(value);
1352                 if (ret)
1353                         return telephony_error_reply(msg, ret);
1354         } else if (g_str_equal("OperatorNameChanged", property)) {
1355                 const char *name;
1356                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)
1357                         return btd_error_invalid_args(msg);
1358
1359                 dbus_message_iter_get_basic(&sub, &name);
1360
1361                 ret = update_operator_name(name);
1362                 if (ret)
1363                         return telephony_error_reply(msg, ret);
1364         } else if (g_str_equal("SignalBarsChanged", property)) {
1365                 int32_t value;
1366                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INT32)
1367                         return btd_error_invalid_args(msg);
1368
1369                 dbus_message_iter_get_basic(&sub, &value);
1370                 ret = update_signal_strength(value);
1371                 if (ret)
1372                         return telephony_error_reply(msg, ret);
1373
1374         } else if (g_str_equal("BatteryBarsChanged", property)) {
1375                 int32_t value;
1376                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INT32)
1377                         return btd_error_invalid_args(msg);
1378
1379                 dbus_message_iter_get_basic(&sub, &value);
1380                 ret = update_battery_strength(value);
1381                 if (ret)
1382                         return telephony_error_reply(msg, ret);
1383
1384         } else if (g_str_equal("SubscriberNumberChanged", property)) {
1385                 const char *number;
1386                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)
1387                         return btd_error_invalid_args(msg);
1388
1389                 dbus_message_iter_get_basic(&sub, &number);
1390                 ret = update_subscriber_number(number);
1391                 if (ret)
1392                         return telephony_error_reply(msg, ret);
1393         }
1394
1395         return dbus_message_new_method_return(msg);
1396 }
1397
1398 static GDBusMethodTable telephony_methods[] = {
1399         { GDBUS_METHOD("Incoming",
1400                         GDBUS_ARGS({ "path", "s" }, { "number", "s" },
1401                                         { "id", "u" }, { "sender", "s" }),
1402                         NULL,
1403                         incoming) },
1404         { GDBUS_METHOD("Outgoing",
1405                         GDBUS_ARGS({ "path", "s" }, { "number", "s" },
1406                                         { "id", "u" }, { "sender", "s" }),
1407                         NULL,
1408                         outgoing) },
1409         { GDBUS_METHOD("SetCallStatus",
1410                         GDBUS_ARGS({ "path", "s" }, { "status", "u" },
1411                                         { "id", "u" }, { "sender", "s" }),
1412                         NULL,
1413                         set_call_status) },
1414         { GDBUS_METHOD("RegisterTelephonyAgent",
1415                         GDBUS_ARGS({ "flag", "b" }, { "path", "s" },
1416                                         { "sender", "s" }),
1417                         NULL,
1418                         register_telephony_agent) },
1419         { GDBUS_METHOD("SetProperty",
1420                         GDBUS_ARGS({ "name", "s" }, { "property", "v" }),
1421                         NULL,
1422                         set_property) },
1423         { }
1424 };
1425
1426 static void path_unregister(void *data)
1427 {
1428         DBG("+\n");
1429         g_dbus_unregister_interface(ag_connection, TELEPHONY_CSD_OBJECT_PATH,
1430                                         TELEPHONY_CSD_INTERFACE);
1431         DBG("-\n");
1432 }
1433
1434 /*API's that shall be ported*/
1435 int telephony_init(void)
1436 {
1437         uint32_t features = AG_FEATURE_EC_ANDOR_NR |
1438                                 AG_FEATURE_REJECT_A_CALL |
1439                                 AG_FEATURE_ENHANCED_CALL_STATUS |
1440                                 AG_FEATURE_THREE_WAY_CALLING |
1441                                 AG_FEATURE_VOICE_RECOGNITION;
1442         int i;
1443
1444         DBG("");
1445
1446         ag_connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
1447
1448         if (!g_dbus_register_interface(ag_connection, TELEPHONY_CSD_OBJECT_PATH,
1449                                         TELEPHONY_CSD_INTERFACE,
1450                                         telephony_methods, NULL, NULL,
1451                                         NULL, path_unregister)) {
1452                 error("D-Bus failed to register %s interface", TELEPHONY_CSD_INTERFACE);
1453                 return -1;
1454         }
1455
1456         /* Reset indicators */
1457         for (i = 0; telephony_ag_indicators[i].desc != NULL; i++) {
1458                 if (g_str_equal(telephony_ag_indicators[i].desc, "battchg"))
1459                         telephony_ag_indicators[i].val = 5;
1460                 else
1461                         telephony_ag_indicators[i].val = 0;
1462         }
1463
1464         /*Initializatoin of the indicators*/
1465         telephony_ready_ind(features, telephony_ag_indicators,
1466                                         BTRH_NOT_SUPPORTED,
1467                                         telephony_chld_str);
1468
1469         return 0;
1470 }
1471
1472 void telephony_exit(void)
1473 {
1474         DBG("");
1475
1476         g_free(net.operator_name);
1477         net.operator_name = NULL;
1478
1479         g_free(subscriber_number);
1480         subscriber_number = NULL;
1481
1482         net.status = NETWORK_REG_STATUS_UNKOWN;
1483         net.signal_bars = 0;
1484
1485         g_slist_free(active_calls);
1486         active_calls = NULL;
1487
1488         g_slist_foreach(calls, (GFunc) csd_call_free, NULL);
1489         g_slist_free(calls);
1490         calls = NULL;
1491
1492         free_sender_list();
1493
1494         g_dbus_unregister_interface(ag_connection, TELEPHONY_CSD_OBJECT_PATH,
1495                                                 TELEPHONY_CSD_INTERFACE);
1496
1497         dbus_connection_unref(ag_connection);
1498         ag_connection = NULL;
1499
1500         telephony_deinit();
1501 }
1502
1503 void telephony_device_connected(void *telephony_device)
1504 {
1505         DBG("telephony-tizen: device %p connected", telephony_device);
1506 }
1507
1508 void telephony_device_disconnected(void *telephony_device)
1509 {
1510         DBG("telephony-tizen: device %p disconnected", telephony_device);
1511         events_enabled = FALSE;
1512 }
1513
1514 void telephony_event_reporting_req(void *telephony_device, int ind)
1515 {
1516         events_enabled = ind == 1 ? TRUE : FALSE;
1517
1518         telephony_event_reporting_rsp(telephony_device, CME_ERROR_NONE);
1519 }
1520
1521 void telephony_response_and_hold_req(void *telephony_device, int rh)
1522 {
1523         DBG("telephony-tizen: response_and_hold_req - device %p disconnected",
1524                 telephony_device);
1525
1526         telephony_response_and_hold_rsp(telephony_device,
1527                                                 CME_ERROR_NOT_SUPPORTED);
1528 }
1529
1530 static void telephony_dial_number_reply(DBusPendingCall *call, void *data)
1531 {
1532         DBusMessage *reply = dbus_pending_call_steal_reply(call);
1533         DBusError derr;
1534
1535         DBG("redial_reply");
1536
1537         dbus_error_init(&derr);
1538         if (!dbus_set_error_from_message(&derr, reply)) {
1539                 DBG("hfg  reply: dial done  successfully");
1540                 telephony_dial_number_rsp(data, CME_ERROR_NONE);
1541                 goto done;
1542         }
1543
1544         DBG("dial_reply reply: %s", derr.message);
1545
1546         dbus_error_free(&derr);
1547         telephony_dial_number_rsp(data, CME_ERROR_AG_FAILURE);
1548
1549 done:
1550         dbus_message_unref(reply);
1551 }
1552
1553 void telephony_dial_number_req(void *telephony_device, const char *number)
1554 {
1555         uint32_t flags = callerid;
1556
1557         DBG("telephony-tizen: dial request to %s", number);
1558
1559         if (strncmp(number, "*31#", 4) == 0) {
1560                 number += 4;
1561                 flags = CALL_FLAG_PRESENTATION_ALLOWED;
1562         } else if (strncmp(number, "#31#", 4) == 0) {
1563                 number += 4;
1564                 flags = CALL_FLAG_PRESENTATION_RESTRICTED;
1565         } else if (number[0] == '>') {
1566                 int location = strtol(&number[1], NULL, 0);
1567
1568                 if (0 != dbus_method_call_send(HFP_AGENT_SERVICE,
1569                                 HFP_AGENT_PATH, HFP_AGENT_INTERFACE,
1570                                 "DialMemory",
1571                                 telephony_dial_number_reply, telephony_device,
1572                                 DBUS_TYPE_INT32, &location,
1573                                 DBUS_TYPE_INVALID)) {
1574                         telephony_dial_number_rsp(telephony_device,
1575                                                         CME_ERROR_AG_FAILURE);
1576                 }
1577                 return;
1578         }
1579
1580         if (0 != dbus_method_call_send(HFP_AGENT_SERVICE, HFP_AGENT_PATH,
1581                                 HFP_AGENT_INTERFACE, "DialNum",
1582                                 NULL, NULL,
1583                                 DBUS_TYPE_STRING, &number,
1584                                 DBUS_TYPE_UINT32, &flags,
1585                                 DBUS_TYPE_INVALID)) {
1586                 telephony_dial_number_rsp(telephony_device,
1587                                                 CME_ERROR_AG_FAILURE);
1588                 return;
1589         }
1590
1591         telephony_dial_number_rsp(telephony_device, CME_ERROR_NONE);
1592 }
1593
1594
1595 void telephony_terminate_call_req(void *telephony_device)
1596 {
1597         struct csd_call *call;
1598         struct csd_call *alerting;
1599         int err;
1600
1601         DBG("+\n");
1602
1603         call = find_call_with_status(CSD_CALL_STATUS_ACTIVE);
1604         if (!call)
1605                 call = find_non_idle_call();
1606
1607         if (!call) {
1608                 error("No active call");
1609                 telephony_terminate_call_rsp(telephony_device,
1610                                                 CME_ERROR_NOT_ALLOWED);
1611                 return;
1612         }
1613
1614         if (NULL != find_call_with_status(CSD_CALL_STATUS_WAITING))
1615                 err = reject_accept_call(call, telephony_device);
1616         else if (NULL != (alerting = find_call_with_status(CSD_CALL_STATUS_CREATE)))
1617                 err = reject_call(alerting);
1618         else if (NULL != (alerting = find_call_with_status(CSD_CALL_STATUS_MO_ALERTING)))
1619                 err = reject_call(alerting);
1620         else if (NULL != (alerting = find_call_with_status(CSD_CALL_STATUS_COMING)))
1621                 err = reject_call(alerting);
1622         else if (call->conference)
1623                 err = release_conference();
1624         else
1625                 err = release_call(call);
1626
1627         if (err < 0)
1628                 telephony_terminate_call_rsp(telephony_device,
1629                                                 CME_ERROR_AG_FAILURE);
1630         else
1631                 telephony_terminate_call_rsp(telephony_device, CME_ERROR_NONE);
1632         DBG("-\n");
1633
1634 }
1635
1636 void telephony_answer_call_req(void *telephony_device)
1637 {
1638         struct csd_call *call;
1639
1640         call = find_call_with_status(CSD_CALL_STATUS_COMING);
1641         if (!call)
1642                 call = find_call_with_status(CSD_CALL_STATUS_MT_ALERTING);
1643
1644         if (!call)
1645                 call = find_call_with_status(CSD_CALL_STATUS_PROCEEDING);
1646
1647         if (!call)
1648                 call = find_call_with_status(CSD_CALL_STATUS_WAITING);
1649
1650         if (!call) {
1651                 telephony_answer_call_rsp(telephony_device,
1652                                                 CME_ERROR_NOT_ALLOWED);
1653                 return;
1654         }
1655
1656         if (answer_call(call) < 0)
1657                 telephony_answer_call_rsp(telephony_device,
1658                                                 CME_ERROR_AG_FAILURE);
1659         else
1660                 telephony_answer_call_rsp(telephony_device, CME_ERROR_NONE);
1661
1662 }
1663
1664 void telephony_key_press_req(void *telephony_device, const char *keys)
1665 {
1666         struct csd_call *active, *waiting;
1667         int err;
1668
1669         DBG("telephony-tizen: got key press request for %s", keys);
1670
1671         waiting = find_call_with_status(CSD_CALL_STATUS_COMING);
1672         if (!waiting)
1673                 waiting = find_call_with_status(CSD_CALL_STATUS_MT_ALERTING);
1674         if (!waiting)
1675                 waiting = find_call_with_status(CSD_CALL_STATUS_PROCEEDING);
1676
1677         active = find_call_with_status(CSD_CALL_STATUS_ACTIVE);
1678
1679         if (waiting)
1680                 err = answer_call(waiting);
1681         else if (active)
1682                 err = release_call(active);
1683         else {
1684                 /*As per the HSP1.2 specification, for user action - Cellular phone can perform
1685                 predefined user action. In our case we shall support Last no. dial*/
1686                 dbus_method_call_send(HFP_AGENT_SERVICE, HFP_AGENT_PATH,
1687                                 HFP_AGENT_INTERFACE, "DialLastNum",
1688                                 telephony_dial_number_reply, telephony_device,
1689                                 DBUS_TYPE_INVALID);
1690                 return;
1691         }
1692
1693         if (err < 0)
1694                 telephony_key_press_rsp(telephony_device,
1695                                                         CME_ERROR_AG_FAILURE);
1696         else
1697                 telephony_key_press_rsp(telephony_device, CME_ERROR_NONE);
1698 }
1699
1700 void telephony_last_dialed_number_req(void *telephony_device)
1701 {
1702         DBG("telephony-tizen: last dialed number request");
1703
1704         if (0 != dbus_method_call_send(HFP_AGENT_SERVICE, HFP_AGENT_PATH,
1705                                 HFP_AGENT_INTERFACE, "DialLastNum",
1706                                 telephony_dial_number_reply, telephony_device,
1707                                 DBUS_TYPE_INVALID)) {
1708                 telephony_dial_number_rsp(telephony_device,
1709                                                 CME_ERROR_AG_FAILURE);
1710         }
1711 }
1712
1713 void telephony_transmit_dtmf_req(void *telephony_device, char tone)
1714 {
1715         char buf[2] = { tone, '\0' }, *buf_ptr = buf;
1716         struct csd_call *call;
1717
1718         DBG("telephony-tizen: transmit dtmf: %s", buf);
1719
1720         /* Find any Ongoing call, in active/held/waiting */
1721         if (NULL == (call = find_call_with_status(CSD_CALL_STATUS_ACTIVE)))
1722                 if (NULL == (call = find_call_with_status(
1723                                                 CSD_CALL_STATUS_HOLD)))
1724                         if (NULL == (call = find_call_with_status(
1725                                                 CSD_CALL_STATUS_WAITING))) {
1726                                 DBG("No Onging Call \n");
1727                                 telephony_transmit_dtmf_rsp(telephony_device,
1728                                                 CME_ERROR_AG_FAILURE);
1729                                 return;
1730                         }
1731
1732         if (0 != dbus_method_call_send(HFP_AGENT_SERVICE, HFP_AGENT_PATH,
1733                                 HFP_AGENT_INTERFACE, "SendDtmf",
1734                                 NULL, NULL,
1735                                 DBUS_TYPE_STRING, &buf_ptr,
1736                                 DBUS_TYPE_STRING, &call->path,
1737                                 DBUS_TYPE_STRING, &call->sender,
1738                                 DBUS_TYPE_INVALID)) {
1739                 telephony_transmit_dtmf_rsp(telephony_device,
1740                                                 CME_ERROR_AG_FAILURE);
1741                 return;
1742         }
1743
1744         telephony_transmit_dtmf_rsp(telephony_device, CME_ERROR_NONE);
1745 }
1746
1747 static int csd_status_to_hfp(struct csd_call *call)
1748 {
1749         switch (call->status) {
1750         case CSD_CALL_STATUS_IDLE:
1751         case CSD_CALL_STATUS_MO_RELEASE:
1752         case CSD_CALL_STATUS_MT_RELEASE:
1753         case CSD_CALL_STATUS_TERMINATED:
1754                 return -1;
1755         case CSD_CALL_STATUS_CREATE:
1756                 return CALL_STATUS_DIALING;
1757         case CSD_CALL_STATUS_WAITING:
1758                 return CALL_STATUS_WAITING;
1759         case CSD_CALL_STATUS_PROCEEDING:
1760                 /* PROCEEDING can happen in outgoing/incoming */
1761                 if (call->originating)
1762                         return CALL_STATUS_DIALING;
1763                 /*
1764                  * PROCEEDING is followed by WAITING CSD status, therefore
1765                  * second incoming call status indication is set immediately
1766                  * to waiting.
1767                  */
1768                 if (g_slist_length(active_calls) > 0)
1769                         return CALL_STATUS_WAITING;
1770
1771                 return CALL_STATUS_INCOMING;
1772         case CSD_CALL_STATUS_COMING:
1773                 if (g_slist_length(active_calls) > 0)
1774                         return CALL_STATUS_WAITING;
1775
1776                 return CALL_STATUS_INCOMING;
1777         case CSD_CALL_STATUS_MO_ALERTING:
1778                 return CALL_STATUS_ALERTING;
1779         case CSD_CALL_STATUS_MT_ALERTING:
1780                 return CALL_STATUS_INCOMING;
1781         case CSD_CALL_STATUS_ANSWERED:
1782         case CSD_CALL_STATUS_ACTIVE:
1783         case CSD_CALL_STATUS_RECONNECT_PENDING:
1784         case CSD_CALL_STATUS_SWAP_INITIATED:
1785         case CSD_CALL_STATUS_HOLD_INITIATED:
1786                 return CALL_STATUS_ACTIVE;
1787         case CSD_CALL_STATUS_RETRIEVE_INITIATED:
1788         case CSD_CALL_STATUS_HOLD:
1789                 return CALL_STATUS_HELD;
1790         default:
1791                 return -1;
1792         }
1793 }
1794
1795 void telephony_list_current_calls_req(void *telephony_device)
1796 {
1797         GSList *l;
1798         int i;
1799
1800         DBG("telephony-tizen: list current calls request");
1801
1802         for (l = calls, i = 1; l != NULL; l = l->next, i++) {
1803                 struct csd_call *call = l->data;
1804                 int status, direction, multiparty;
1805
1806                 status = csd_status_to_hfp(call);
1807                 if (status < 0)
1808                         continue;
1809
1810                 direction = call->originating ?
1811                                 CALL_DIR_OUTGOING : CALL_DIR_INCOMING;
1812
1813                 multiparty = call->conference ?
1814                                 CALL_MULTIPARTY_YES : CALL_MULTIPARTY_NO;
1815
1816                 telephony_list_current_call_ind(i, direction, status,
1817                                                 CALL_MODE_VOICE, multiparty,
1818                                                 call->number,
1819                                                 number_type(call->number));
1820         }
1821
1822         telephony_list_current_calls_rsp(telephony_device, CME_ERROR_NONE);
1823
1824 }
1825
1826 static void telephony_operator_reply(DBusPendingCall *call, void *telephony_device)
1827 {
1828         DBusMessage *reply = dbus_pending_call_steal_reply(call);
1829         DBusError derr;
1830         const gchar *operator_name;
1831
1832         DBG("telephony_operator_reply\n");
1833
1834         dbus_error_init(&derr);
1835
1836         if (dbus_set_error_from_message(&derr, reply)) {
1837                 DBG("telephony_operator_reply error:%s", derr.message);
1838                 goto failed;
1839         }
1840
1841         if (!dbus_message_get_args(reply, NULL,
1842                                 DBUS_TYPE_STRING, &operator_name,
1843                                 DBUS_TYPE_INVALID))
1844                 goto failed;
1845
1846         DBG("telephony_operator_reply -operator_name:%s", operator_name);
1847         net.operator_name = g_strndup(operator_name, 16);
1848
1849         telephony_operator_selection_ind(OPERATOR_MODE_AUTO,
1850                                 operator_name);
1851         telephony_operator_selection_rsp(telephony_device, CME_ERROR_NONE);
1852         return;
1853
1854 failed:
1855         dbus_error_free(&derr);
1856         telephony_operator_selection_ind(OPERATOR_MODE_AUTO, "UNKOWN");
1857         telephony_operator_selection_rsp(telephony_device, CME_ERROR_NONE);
1858 }
1859
1860 void telephony_operator_selection_req(void *telephony_device)
1861 {
1862         int err = 0;
1863
1864         err = dbus_method_call_send(HFP_AGENT_SERVICE, HFP_AGENT_PATH,
1865                                 HFP_AGENT_INTERFACE, "GetOperatorName",
1866                                 telephony_operator_reply, telephony_device,
1867                                 DBUS_TYPE_INVALID);
1868         if (err)
1869                 telephony_operator_selection_rsp(telephony_device,
1870                                 CME_ERROR_AG_FAILURE);
1871 }
1872
1873 void telephony_nr_and_ec_req(void *telephony_device, gboolean enable)
1874 {
1875         DBG("telephony-tizen: got %s NR and EC request",
1876                         enable ? "enable" : "disable");
1877
1878         if (0 != dbus_method_call_send(HFP_AGENT_SERVICE, HFP_AGENT_PATH,
1879                                 HFP_AGENT_INTERFACE, "NrecStatus",
1880                                 NULL, NULL, DBUS_TYPE_BOOLEAN, &enable,
1881                                 DBUS_TYPE_INVALID)) {
1882                 telephony_nr_and_ec_rsp(telephony_device,
1883                                                 CME_ERROR_AG_FAILURE);
1884                 return;
1885         }
1886
1887         telephony_nr_and_ec_rsp(telephony_device, CME_ERROR_NONE);
1888 }
1889
1890 void telephony_voice_dial_req(void *telephony_device, gboolean enable)
1891 {
1892
1893         DBG("telephony-tizen: got %s voice dial request",
1894                                 enable ? "enable" : "disable");
1895
1896         if (0 != dbus_method_call_send(HFP_AGENT_SERVICE, HFP_AGENT_PATH,
1897                                 HFP_AGENT_INTERFACE, "VoiceDial",
1898                                 NULL, NULL, DBUS_TYPE_BOOLEAN, &enable,
1899                                 DBUS_TYPE_INVALID)) {
1900                 telephony_voice_dial_rsp(telephony_device,
1901                                                 CME_ERROR_AG_FAILURE);
1902                 return;
1903         }
1904
1905         telephony_voice_dial_rsp(telephony_device, CME_ERROR_NONE);
1906 }
1907
1908 void telephony_subscriber_number_req(void *telephony_device)
1909 {
1910         DBG("telephony-tizen: subscriber number request");
1911         if (subscriber_number)
1912                 telephony_subscriber_number_ind(subscriber_number,
1913                                                 number_type(subscriber_number),
1914                                                 SUBSCRIBER_SERVICE_VOICE);
1915         telephony_subscriber_number_rsp(telephony_device, CME_ERROR_NONE);
1916 }
1917
1918 static char *get_supported_list(const char *list[], unsigned int size)
1919 {
1920         GString *str;
1921         int i = 0;
1922
1923         if (list == NULL || size == 0)
1924                 return NULL;
1925
1926         str = g_string_new("(");
1927         while (i < size) {
1928                 if (i > 0)
1929                         g_string_append(str, ",");
1930
1931                 g_string_append(str, list[i]);
1932                 i++;
1933         }
1934
1935         g_string_append(str, ")");
1936
1937         return g_string_free(str, FALSE);
1938 }
1939
1940 static int convert_utf8_gsm(uint8_t ascii, uint8_t utf_8, uint8_t *gsm)
1941 {
1942         uint32_t i;
1943
1944         if (ascii == 0xC3) {
1945                 for (i = 0; i < GSM_UNI_MAX_C3 ; i++) {
1946                         if (gsm_unicode_C3[i].utf_8 == utf_8) {
1947                                 *gsm = gsm_unicode_C3[i].gsm;
1948                                 return 0;
1949                         }
1950                 }
1951         } else if (ascii == 0xCE) {
1952                 for (i = 0; i < GSM_UNI_MAX_CE ; i++) {
1953                         if (gsm_unicode_CE[i].utf_8 == utf_8) {
1954                                 *gsm = gsm_unicode_CE[i].gsm;
1955                                 return 0;
1956                         }
1957                 }
1958         }
1959
1960         return 1;
1961 }
1962
1963 static void get_unicode_string(const char *name, char *unicodename)
1964 {
1965         if (NULL != name && NULL != unicodename) {
1966                 int len = strlen(name);
1967                 int x, y;
1968
1969                 if (len == 0)
1970                         return;
1971
1972                 if (len > PHONEBOOK_MAX_CHARACTER_LENGTH)
1973                         len = PHONEBOOK_MAX_CHARACTER_LENGTH;
1974
1975                 for (x = 0, y = 0 ; x < len ; x++, y++) {
1976                         if (x < (len - 1)) {
1977                                 if (convert_utf8_gsm(name[x], name[x+1],
1978                                                 (uint8_t *)&unicodename[y])) {
1979                                         x++;
1980                                         continue;
1981                                 }
1982                         }
1983
1984                         if (name[x] == '_') {
1985                                  unicodename[y] = ' ';
1986                                  continue;
1987                         }
1988
1989                         unicodename[y] = name[x];
1990                 }
1991         }
1992         return;
1993 }
1994
1995 static int get_phonebook_count(const char *path, uint32_t *max_size,
1996                                 uint32_t *used)
1997 {
1998         DBusConnection *conn;
1999         DBusMessage *message, *reply;
2000         DBusError error;
2001
2002         uint32_t max = 0;
2003         uint32_t size = 0;
2004
2005         conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
2006         if (!conn) {
2007                 DBG("Can't get on system bus");
2008                 return -1;
2009         }
2010
2011         message = dbus_message_new_method_call(PHONEBOOK_BUS_NAME,
2012                                         PHONEBOOK_PATH,
2013                                         PHONEBOOK_INTERFACE,
2014                                         "GetPhonebookSizeAt");
2015         if (!message) {
2016                 DBG("Can't allocate new message");
2017                 dbus_connection_unref(conn);
2018                 return -1;
2019         }
2020
2021         dbus_message_append_args(message, DBUS_TYPE_STRING, &path,
2022                                 DBUS_TYPE_INVALID);
2023
2024         dbus_error_init(&error);
2025
2026         reply = dbus_connection_send_with_reply_and_block(conn,
2027                         message, -1, &error);
2028
2029         if (!reply) {
2030                 if (dbus_error_is_set(&error) == TRUE) {
2031                         DBG("%s", error.message);
2032                         dbus_error_free(&error);
2033                 } else {
2034                         DBG("Failed to get contacts");
2035                 }
2036                 dbus_message_unref(message);
2037                 dbus_connection_unref(conn);
2038                 return -1;
2039         }
2040
2041         if (!dbus_message_get_args(reply, &error,
2042                                 DBUS_TYPE_UINT32, &size,
2043                                 DBUS_TYPE_INVALID)) {
2044                 DBG("Can't get reply arguments\n");
2045                 if (dbus_error_is_set(&error)) {
2046                         DBG("%s\n", error.message);
2047                         dbus_error_free(&error);
2048                 }
2049                 dbus_message_unref(reply);
2050                 dbus_message_unref(message);
2051                 dbus_connection_unref(conn);
2052                 return -1;
2053         }
2054
2055         if ((g_strcmp0(path, "\"SM\"") == 0) ||
2056                         (g_strcmp0(path, "\"ME\"") == 0)) {
2057                 max = PHONEBOOK_COUNT_MAX;
2058         }
2059         if ((g_strcmp0(path, "\"DC\"") == 0) ||
2060                         (g_strcmp0(path, "\"MC\"") == 0) ||
2061                         (g_strcmp0(path, "\"RC\"") == 0)) {
2062                 max = CALL_LOG_COUNT_MAX;
2063         }
2064
2065         if (max_size)
2066                 *max_size = max;
2067
2068         if (used) {
2069                 if (size > max)
2070                         *used = max;
2071                 else
2072                         *used = size;
2073         }
2074
2075         dbus_message_unref(reply);
2076         dbus_message_unref(message);
2077         dbus_connection_unref(conn);
2078
2079         return 0;
2080 }
2081
2082 static int read_phonebook_entries(int start_index, int end_index)
2083 {
2084         DBusConnection *conn;
2085         DBusMessage *message, *reply;
2086         DBusMessageIter iter, iter_struct;
2087         DBusError error;
2088
2089         int count = 0;
2090
2091         conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
2092         if (!conn) {
2093                 DBG("Can't get on system bus");
2094                 return -1;
2095         }
2096
2097         message = dbus_message_new_method_call(PHONEBOOK_BUS_NAME,
2098                                         PHONEBOOK_PATH,
2099                                         PHONEBOOK_INTERFACE,
2100                                         "GetPhonebookEntriesAt");
2101         if (!message) {
2102                 DBG("Can't allocate new message");
2103                 dbus_connection_unref(conn);
2104                 return -1;
2105         }
2106
2107         dbus_message_append_args(message,
2108                                 DBUS_TYPE_STRING,
2109                                 &phonebook_store_list[ag_pb_info.path_id],
2110                                 DBUS_TYPE_INT32, &start_index,
2111                                 DBUS_TYPE_INT32, &end_index,
2112                                 DBUS_TYPE_INVALID);
2113
2114         dbus_error_init(&error);
2115
2116         reply = dbus_connection_send_with_reply_and_block(conn,
2117                         message, -1, &error);
2118
2119         if (!reply) {
2120                 if (dbus_error_is_set(&error) == TRUE) {
2121                         DBG("%s", error.message);
2122                         dbus_error_free(&error);
2123                 } else {
2124                         DBG("Failed to get contacts");
2125                 }
2126
2127                 dbus_message_unref(message);
2128                 dbus_connection_unref(conn);
2129
2130                 return -1;
2131         }
2132
2133         dbus_message_iter_init(reply, &iter);
2134         dbus_message_iter_recurse(&iter, &iter_struct);
2135
2136         while(dbus_message_iter_get_arg_type(&iter_struct) ==
2137                         DBUS_TYPE_STRUCT) {
2138                 const char *name = NULL;
2139                 const char *number = NULL;
2140
2141                 char *uni_name;
2142                 char *uni_number;
2143
2144                 uint32_t handle = 0;
2145
2146                 DBusMessageIter entry_iter;
2147
2148                 dbus_message_iter_recurse(&iter_struct,&entry_iter);
2149
2150                 dbus_message_iter_get_basic(&entry_iter, &name);
2151                 dbus_message_iter_next(&entry_iter);
2152                 dbus_message_iter_get_basic(&entry_iter, &number);
2153                 dbus_message_iter_next(&entry_iter);
2154                 dbus_message_iter_get_basic(&entry_iter, &handle);
2155                 dbus_message_iter_next(&entry_iter);
2156
2157                 dbus_message_iter_next(&iter_struct);
2158
2159                 uni_name = g_strndup(name, PHONEBOOK_NAME_MAX_LENGTH);
2160                 uni_number = g_strndup(number, PHONEBOOK_NAME_MAX_LENGTH);
2161
2162                 telephony_read_phonebook_entries_ind(uni_name,
2163                                 uni_number, handle);
2164
2165                 count++;
2166
2167                 g_free(uni_name);
2168                 g_free(uni_number);
2169         }
2170
2171         dbus_message_unref(message);
2172         dbus_message_unref(reply);
2173         dbus_connection_unref(conn);
2174
2175         return count;
2176 }
2177
2178 static int find_phonebook_entries(const char *str)
2179 {
2180         DBusConnection *conn;
2181         DBusMessage *message, *reply;
2182         DBusMessageIter iter, iter_struct;
2183         DBusError error;
2184
2185         conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
2186         if (!conn) {
2187                 DBG("Can't get on system bus");
2188                 return -1;
2189         }
2190
2191         message = dbus_message_new_method_call(PHONEBOOK_BUS_NAME,
2192                                         PHONEBOOK_PATH,
2193                                         PHONEBOOK_INTERFACE,
2194                                         "GetPhonebookEntriesFindAt");
2195         if (!message) {
2196                 DBG("Can't allocate new message");
2197                 dbus_connection_unref(conn);
2198                 return -1;
2199         }
2200
2201         dbus_message_append_args(message,
2202                                 DBUS_TYPE_STRING,
2203                                 &phonebook_store_list[ag_pb_info.path_id],
2204                                 DBUS_TYPE_STRING, &str,
2205                                 DBUS_TYPE_INVALID);
2206
2207         dbus_error_init(&error);
2208
2209         reply = dbus_connection_send_with_reply_and_block(conn,
2210                         message, -1, &error);
2211
2212         if (!reply) {
2213                 if (dbus_error_is_set(&error) == TRUE) {
2214                         DBG("%s", error.message);
2215                         dbus_error_free(&error);
2216                 } else {
2217                         DBG("Failed to get contacts");
2218                 }
2219
2220                 dbus_message_unref(message);
2221                 dbus_connection_unref(conn);
2222
2223                 return -1;
2224         }
2225
2226         dbus_message_iter_init(reply, &iter);
2227         dbus_message_iter_recurse(&iter, &iter_struct);
2228
2229         while(dbus_message_iter_get_arg_type(&iter_struct) ==
2230                         DBUS_TYPE_STRUCT) {
2231                 const char *name = NULL;
2232                 const char *number = NULL;
2233
2234                 char *uni_name;
2235                 char *uni_number;
2236
2237                 uint32_t handle = 0;
2238
2239                 DBusMessageIter entry_iter;
2240
2241                 dbus_message_iter_recurse(&iter_struct,&entry_iter);
2242
2243                 dbus_message_iter_get_basic(&entry_iter, &name);
2244                 dbus_message_iter_next(&entry_iter);
2245                 dbus_message_iter_get_basic(&entry_iter, &number);
2246                 dbus_message_iter_next(&entry_iter);
2247                 dbus_message_iter_get_basic(&entry_iter, &handle);
2248                 dbus_message_iter_next(&entry_iter);
2249
2250                 dbus_message_iter_next(&iter_struct);
2251
2252                 uni_name = g_strndup(name, PHONEBOOK_NAME_MAX_LENGTH);
2253                 uni_number = g_strndup(number, PHONEBOOK_NAME_MAX_LENGTH);
2254
2255                 telephony_find_phonebook_entries_ind(uni_name, uni_number, handle);
2256
2257                 g_free(uni_name);
2258                 g_free(uni_number);
2259         }
2260
2261         dbus_message_unref(message);
2262         dbus_message_unref(reply);
2263         dbus_connection_unref(conn);
2264
2265         return 0;
2266 }
2267
2268 void telephony_select_phonebook_memory_status(void *telephony_device)
2269 {
2270         int32_t path_id = ag_pb_info.path_id;
2271         uint32_t used;
2272         uint32_t max_size;
2273
2274         cme_error_t err = CME_ERROR_NONE;
2275
2276
2277         DBG("telephony-tizen: telephony_read_phonebook_store\n");
2278
2279         if (path_id < 0 || path_id >= PHONEBOOK_STORE_LIST_SIZE)
2280                 path_id = 0;
2281
2282         if (get_phonebook_count(phonebook_store_list[path_id],
2283                                 &max_size, &used))
2284                 err = CME_ERROR_AG_FAILURE;
2285
2286         telephony_select_phonebook_memory_status_rsp(telephony_device,
2287                         phonebook_store_list[path_id],
2288                         max_size, used,
2289                         err);
2290 }
2291
2292 void telephony_select_phonebook_memory_list(void *telephony_device)
2293 {
2294 /*
2295         For Blue & Me car kit we may have to add  the
2296         patch here(similar to the patch done in H1 and H2 )
2297 */
2298         char *str;
2299
2300         str = get_supported_list(phonebook_store_list,
2301                         PHONEBOOK_STORE_LIST_SIZE);
2302
2303         DBG("telephony-tizen: telephony_select_phonebook_memory_list %d :%s\n",
2304                         PHONEBOOK_STORE_LIST_SIZE, str);
2305
2306         telephony_select_phonebook_memory_list_rsp(telephony_device,
2307                         str, CME_ERROR_NONE);
2308
2309         g_free(str);
2310 }
2311
2312 void telephony_select_phonebook_memory(void *telephony_device, const gchar *path)
2313 {
2314
2315         int i = 0;
2316         cme_error_t err;
2317
2318         DBG("telephony-tizen: telephony_select_phonebook_memory\n");
2319         DBG("set phonebook type to [%s]\n", path);
2320
2321         while (i < PHONEBOOK_STORE_LIST_SIZE) {
2322                 if (strcmp(phonebook_store_list[i], path) == 0)
2323                         break;
2324
2325                 i++;
2326         }
2327
2328         if  (i >= 0 && i < PHONEBOOK_STORE_LIST_SIZE) {
2329                 err = CME_ERROR_NONE;
2330                 ag_pb_info.path_id = i;
2331         } else {
2332                 err = CME_ERROR_INVALID_TEXT_STRING;
2333         }
2334         telephony_select_phonebook_memory_rsp(telephony_device, err);
2335 }
2336
2337 void telephony_read_phonebook_entries_list(void *telephony_device)
2338 {
2339         cme_error_t err = CME_ERROR_NONE;
2340
2341         int32_t path_id = ag_pb_info.path_id;
2342         uint32_t used;
2343
2344         DBG("telephony-tizen: telephony_read_phonebook_entries_list\n");
2345
2346         if (path_id < 0 || path_id >= PHONEBOOK_STORE_LIST_SIZE)
2347                 err = CME_ERROR_INVALID_INDEX;
2348         else {
2349                 if (get_phonebook_count(phonebook_store_list[path_id],
2350                                         NULL, &used) != 0) {
2351                         err = CME_ERROR_NOT_ALLOWED;
2352                 }
2353         }
2354
2355         telephony_read_phonebook_entries_list_rsp(telephony_device, used,
2356                         PHONEBOOK_NUMBER_MAX_LENGTH, PHONEBOOK_NAME_MAX_LENGTH,
2357                         err);
2358 }
2359
2360 void telephony_read_phonebook_entries(void *telephony_device, const char *cmd)
2361 {
2362         int start_index = 0;
2363         int end_index = 0;
2364
2365         int count;
2366
2367         char *str = NULL;
2368         char *next = NULL;
2369
2370         cme_error_t err;
2371
2372         DBG("telephony-tizen: telephony_read_phonebook_entries\n");
2373
2374         if (cmd == NULL)
2375                 return;
2376
2377         str = g_strdup(cmd);
2378         next = strchr(str, ',');
2379
2380         if (next) {
2381                 *next = '\0';
2382                 next++;
2383
2384                 end_index = strtol(next, NULL, 10);
2385         }
2386
2387         start_index = strtol(str, NULL, 10);
2388
2389         g_free(str);
2390
2391         count = read_phonebook_entries(start_index, end_index);
2392
2393         if (count < 0)
2394                 err = CME_ERROR_AG_FAILURE;
2395         else if (count == 0)
2396                 err = CME_ERROR_INVALID_INDEX;
2397         else
2398                 err = CME_ERROR_NONE;
2399
2400         telephony_read_phonebook_entries_rsp(telephony_device, err);
2401 }
2402
2403 void telephony_find_phonebook_entries_status(void *telephony_device)
2404 {
2405         telephony_find_phonebook_entries_status_ind(
2406                         PHONEBOOK_NUMBER_MAX_LENGTH,
2407                         PHONEBOOK_NAME_MAX_LENGTH);
2408
2409         telephony_find_phonebook_entries_status_rsp(telephony_device,
2410                                                 CME_ERROR_NONE);
2411 }
2412
2413 void telephony_find_phonebook_entries(void *telephony_device, const char *cmd)
2414 {
2415         gchar *st = NULL;
2416         gchar *unquoted = NULL;
2417
2418         cme_error_t err = CME_ERROR_NONE;
2419
2420         DBG("telephony-tizen: telephony_find_phonebook_entry\n");
2421
2422         /* remove quote and compress */
2423         st = strchr(cmd, '"');
2424         if (st == NULL)
2425                 unquoted = g_strdup(cmd);
2426         else {
2427                 gchar *end = NULL;
2428
2429                 end = strrchr(cmd, '"');
2430                 if(end == NULL)
2431                         unquoted = g_strdup(cmd);
2432                 else
2433                         unquoted = g_strndup(st + 1, end - st - 1);
2434         }
2435
2436         if (find_phonebook_entries(unquoted))
2437                 err = CME_ERROR_AG_FAILURE;
2438
2439         telephony_find_phonebook_entries_rsp(telephony_device, err);
2440
2441         g_free(unquoted);
2442 }
2443
2444 void telephony_get_preffered_store_capacity(void *telephony_device)
2445 {
2446         DBG("telephony-tizen: telephony_list_preffered_store_capcity\n");
2447
2448         telephony_get_preffered_store_capacity_rsp(telephony_device,
2449                         PREFFERED_MESSAGE_STORAGE_MAX,
2450                         CME_ERROR_NONE);
2451 }
2452
2453 void telephony_list_preffered_store(void *telephony_device)
2454 {
2455         DBG("telephony-tizen: telephony_list_preffered_store_capcity\n");
2456
2457         telephony_list_preffered_store_rsp(telephony_device,
2458                         PREFFERED_MESSAGE_STORAGE_LIST,
2459                         CME_ERROR_NONE);
2460 }
2461
2462 /*
2463 void telephony_set_preffered_store_capcity(void *telephony_device, const char *cmd)
2464 {
2465 }
2466 */
2467
2468 void telephony_get_character_set(void *telephony_device)
2469 {
2470         DBG("telephony-tizen: telephony_get_character_set\n");
2471
2472         telephony_supported_character_generic_rsp(telephony_device,
2473                         (char *)character_set_list[ag_pb_info.charset_id],
2474                         CME_ERROR_NONE);
2475
2476 }
2477
2478 void telephony_list_supported_character(void *telephony_device)
2479 {
2480         char *str;
2481
2482         str = get_supported_list(character_set_list,
2483                         CHARACTER_SET_LIST_SIZE);
2484
2485         DBG("telephony-tizen: telephony_list_supported_character_set %d :%s\n",
2486                         CHARACTER_SET_LIST_SIZE, str);
2487
2488         telephony_supported_character_generic_rsp(telephony_device,
2489                         str, CME_ERROR_NONE);
2490
2491         g_free(str);
2492 }
2493
2494 void telephony_set_characterset(void *telephony_device, const char *cmd)
2495 {
2496         DBG("telephony-tizen: telephony_set_characterset [%s]\n", cmd);
2497
2498         int i = 0;
2499
2500         while (i < CHARACTER_SET_LIST_SIZE) {
2501                 if (strcmp(character_set_list[i], cmd) == 0) {
2502                         telephony_set_characterset_generic_rsp(telephony_device,
2503                                         CME_ERROR_NONE);
2504                         ag_pb_info.charset_id = i;
2505                         return;
2506                 }
2507
2508                 i++;
2509         }
2510
2511         telephony_set_characterset_generic_rsp(telephony_device,
2512                         CME_ERROR_NOT_SUPPORTED);
2513         return;
2514
2515 }
2516
2517 static void telephony_get_battery_property_reply(
2518                         DBusPendingCall *call, void *data)
2519 {
2520         DBusMessage *reply = dbus_pending_call_steal_reply(call);
2521         DBusError derr;
2522         int32_t bcs = 0;
2523         int32_t bcl = 0;
2524
2525         DBG("battery_property_reply");
2526
2527         dbus_error_init(&derr);
2528         if (dbus_set_error_from_message(&derr, reply)) {
2529                 DBG("battery_property_reply: %s", derr.message);
2530                 dbus_error_free(&derr);
2531                 telephony_battery_charge_status_rsp(data, bcs,
2532                         bcl, CME_ERROR_AG_FAILURE);
2533                 goto done;
2534         }
2535
2536         if (dbus_message_get_args(reply, NULL,
2537                         DBUS_TYPE_INT32, &bcs,
2538                         DBUS_TYPE_INT32, &bcl,
2539                         DBUS_TYPE_INVALID) == FALSE) {
2540                 DBG("get_signal_quality_reply: Invalid arguments");
2541                 telephony_battery_charge_status_rsp(data, bcs,
2542                         bcl, CME_ERROR_AG_FAILURE);
2543                 goto done;
2544
2545         }
2546
2547         telephony_battery_charge_status_rsp(data, bcs,
2548                 bcl, CME_ERROR_NONE);
2549
2550 done:
2551         dbus_message_unref(reply);
2552 }
2553
2554 void telephony_get_battery_property(void *telephony_device)
2555 {
2556         DBG("telephony-tizen: telephony_get_battery_property\n");
2557
2558         if (0 != dbus_method_call_send(HFP_AGENT_SERVICE, HFP_AGENT_PATH,
2559                                 HFP_AGENT_INTERFACE, "GetBatteryStatus",
2560                                 telephony_get_battery_property_reply,
2561                                 telephony_device, DBUS_TYPE_INVALID)) {
2562                 telephony_battery_charge_status_rsp(telephony_device, 0, 0,
2563                                                 CME_ERROR_AG_FAILURE);
2564         }
2565 }
2566
2567 static void telephony_get_signal_quality_reply(DBusPendingCall *call,
2568                         void *data)
2569 {
2570         DBusMessage *reply = dbus_pending_call_steal_reply(call);
2571         DBusError derr;
2572         int32_t rssi = 0;
2573         int32_t ber = 0;
2574
2575         DBG("get_signal_quality_reply");
2576
2577         dbus_error_init(&derr);
2578         if (dbus_set_error_from_message(&derr, reply)) {
2579                 DBG("get_signal_quality_reply: %s", derr.message);
2580                 dbus_error_free(&derr);
2581                 telephony_signal_quality_rsp(data, rssi,
2582                         ber, CME_ERROR_AG_FAILURE);
2583                 goto done;
2584         }
2585
2586         if (dbus_message_get_args(reply, NULL,
2587                         DBUS_TYPE_INT32, &rssi,
2588                         DBUS_TYPE_INT32, &ber,
2589                         DBUS_TYPE_INVALID) == FALSE) {
2590                 DBG("get_signal_quality_reply: Invalid arguments");
2591                 telephony_signal_quality_rsp(data, rssi,
2592                         ber, CME_ERROR_AG_FAILURE);
2593                 goto done;
2594
2595         }
2596
2597         telephony_signal_quality_rsp(data, rssi,
2598                 ber, CME_ERROR_NONE);
2599
2600 done:
2601         dbus_message_unref(reply);
2602 }
2603
2604 void telephony_get_signal_quality(void *telephony_device)
2605 {
2606         DBG("telephony-tizen: telephony_get_signal_quality\n");
2607
2608         if (0 != dbus_method_call_send(HFP_AGENT_SERVICE, HFP_AGENT_PATH,
2609                                 HFP_AGENT_INTERFACE, "GetSignalQuality",
2610                                 telephony_get_signal_quality_reply,
2611                                 telephony_device, DBUS_TYPE_INVALID)) {
2612                 telephony_signal_quality_rsp(telephony_device, 0, 0,
2613                                                 CME_ERROR_AG_FAILURE);
2614         }
2615
2616 }