__SAMSUNG_PATCH__ --> __TIZEN_PATCH__
[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     "org.tizen.csd.Call.Conference"
46 #define CSD_CALL_PATH   "/org/tizen/csd/call"
47 #define CSD_CALL_CONFERENCE_PATH "/org/tizen/csd/call/conference"
48 #define CSD_CALL_SENDER_PATH    "/org/tizen/csd/call/sender"
49
50 /* libcsnet D-Bus definitions */
51 #define CSD_CSNET_BUS_NAME      "org.tizen.csd.CSNet"
52 #define CSD_CSNET_PATH  "/org/tizen/csd/csnet"
53 #define CSD_CSNET_IFACE "org.tizen.csd.CSNet"
54 #define CSD_CSNET_REGISTRATION  "org.tizen.csd.CSNet.NetworkRegistration"
55 #define CSD_CSNET_OPERATOR      "org.tizen.csd.CSNet.NetworkOperator"
56 #define CSD_CSNET_SIGNAL        "org.tizen.csd.CSNet.SignalStrength"
57 #define CSD_TELEPHONE_BATTERY   "org.tizen.csd.CSNet.BatteryStrength"
58 #define CSD_CSNET_SUBSCRIBER    "org.tizen.csd.CSNet.SubscriberNumber"
59
60
61 #define CALL_FLAG_NONE  0
62 #define CALL_FLAG_PRESENTATION_ALLOWED          0x01
63 #define CALL_FLAG_PRESENTATION_RESTRICTED       0x02
64
65 /* Call status values as exported by the CSD CALL plugin */
66 #define CSD_CALL_STATUS_IDLE                    0
67 #define CSD_CALL_STATUS_CREATE                  1
68 #define CSD_CALL_STATUS_COMING                  2
69 #define CSD_CALL_STATUS_PROCEEDING              3
70 #define CSD_CALL_STATUS_MO_ALERTING             4
71 #define CSD_CALL_STATUS_MT_ALERTING             5
72 #define CSD_CALL_STATUS_WAITING                 6
73 #define CSD_CALL_STATUS_ANSWERED                7
74 #define CSD_CALL_STATUS_ACTIVE                  8
75 #define CSD_CALL_STATUS_MO_RELEASE              9
76 #define CSD_CALL_STATUS_MT_RELEASE              10
77 #define CSD_CALL_STATUS_HOLD_INITIATED          11
78 #define CSD_CALL_STATUS_HOLD                    12
79 #define CSD_CALL_STATUS_RETRIEVE_INITIATED      13
80 #define CSD_CALL_STATUS_RECONNECT_PENDING       14
81 #define CSD_CALL_STATUS_TERMINATED              15
82 #define CSD_CALL_STATUS_SWAP_INITIATED          16
83
84 #define CALL_FLAG_NONE                          0
85 #define CALL_FLAG_PRESENTATION_ALLOWED          0x01
86 #define CALL_FLAG_PRESENTATION_RESTRICTED       0x02
87
88
89 #define DBUS_STRUCT_STRING_STRING_UINT (dbus_g_type_get_struct ("GValueArray",\
90                         G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT, G_TYPE_INVALID))
91
92 #define PHONEBOOK_STORE_LIST "(\"SM\",\"ME\",\"DC\",\"MC\",\"RC\")"
93 #define PHONEBOOK_STORE_LIST_BLUENME "(\"ME\",\"DC\",\"MC\",\"RC\")"
94 #define PREFFERED_MESSAGE_STORAGE_LIST "(\"ME\",\"MT\",\"SM\",\"SR\"),(\"ME\",\"MT\",\"SM\",\"SR\"),(\"ME\",\"MT\",\"SM\",\"SR\")"
95 #define PHONEBOOK_CHARACTER_SET_LIST "(\"IRA\",\"GSM\",\"UCS2\")"
96 #define PHONEBOOK_CHARACTER_SET_SUPPORTED "\"GSM\""
97
98 #define PREFFERED_MESSAGE_STORAGE_MAX 500
99 #define CALL_LOG_COUNT_MAX 30
100 #define PHONEBOOK_COUNT_MAX 1000
101
102 #define PHONEBOOK_PATH_LENGTH 5
103 #define PHONEBOOK_NAME_MAX_LENGTH 20
104 #define PHONEBOOK_NUMBER_MAX_LENGTH 20
105 #define PHONEBOOK_MAX_CHARACTER_LENGTH  20
106
107 #define PHONEBOOK_READ_RESP_LENGTH 20
108
109 typedef struct {
110         uint8_t utf_8;
111         uint8_t gsm;
112 } GsmUnicodeTable;
113
114
115  /*0xC3 charcterset*/
116 const GsmUnicodeTable gsm_unicode_C3[] = {
117         {0xA8,0x04},{0xA9,0x05},{0xB9,0x06},{0xAC,0x07},{0xB2,0x08},
118         {0xB7,0x09},{0x98,0x0B},{0xB8,0x0C},{0x85,0x0E},{0xA5,0x0F},
119         {0x86,0x1C},{0xA6,0x1D},{0x9F,0x1E},{0x89,0x1F},{0x84,0x5B},
120         {0x96,0x5C},{0x91,0x5D},{0x9C,0x5E},{0x80,0x5F},{0xA4,0x7B},
121         {0xB6,0x7C},{0xB1,0x7D},{0xBC,0x7E},{0xA0,0x7F},
122 };
123
124 /*0xCE charcterset*/
125 const GsmUnicodeTable gsm_unicode_CE[] = {
126         {0x85,0x14},{0xA1,0x50},{0x98,0x19},{0xA0,0x16},{0x94,0x10},
127         {0xA6,0x12},{0x93,0x13},{0x9E,0x1A},{0x9B,0x14},{0xA8,0x17},
128         {0xA9,0x15},
129 };
130
131 #define GSM_UNI_MAX_C3  (sizeof(gsm_unicode_C3)/sizeof(GsmUnicodeTable))
132 #define GSM_UNI_MAX_CE  (sizeof(gsm_unicode_CE)/sizeof(GsmUnicodeTable))
133
134
135 static DBusConnection *ag_connection = NULL;
136
137 static GSList *calls = NULL;
138 static GSList *watches = NULL;
139
140 static gboolean events_enabled = FALSE;
141 static uint32_t callerid = 0;
142
143 /* Reference count for determining the call indicator status */
144 static GSList *active_calls = NULL;
145
146 static struct indicator telephony_ag_indicators[] =
147 {
148         { "battchg",    "0-5",  5,      TRUE },
149         /* signal strength in terms of bars */
150         { "signal",     "0-5",  0,      TRUE },
151         { "service",    "0,1",  0,      TRUE },
152         { "call",       "0,1",  0,      TRUE },
153         { "callsetup",  "0-3",  0,      TRUE },
154         { "callheld",   "0-2",  0,      FALSE },
155         { "roam",       "0,1",  0,      TRUE },
156         { NULL }
157 };
158
159 static char *call_status_str[] = {
160         "IDLE",
161         "CREATE",
162         "COMING",
163         "PROCEEDING",
164         "MO_ALERTING",
165         "MT_ALERTING",
166         "WAITING",
167         "ANSWERED",
168         "ACTIVE",
169         "MO_RELEASE",
170         "MT_RELEASE",
171         "HOLD_INITIATED",
172         "HOLD",
173         "RETRIEVE_INITIATED",
174         "RECONNECT_PENDING",
175         "TERMINATED",
176         "SWAP_INITIATED",
177         "???"
178 };
179
180 enum net_registration_status {
181         NETWORK_REG_STATUS_HOME,
182         NETWORK_REG_STATUS_ROAMING,
183         NETWORK_REG_STATUS_OFFLINE,
184         NETWORK_REG_STATUS_SEARCHING,
185         NETWORK_REG_STATUS_NO_SIM,
186         NETWORK_REG_STATUS_POWEROFF,
187         NETWORK_REG_STATUS_POWERSAFE,
188         NETWORK_REG_STATUS_NO_COVERAGE,
189         NETWORK_REG_STATUS_REJECTED,
190         NETWORK_REG_STATUS_UNKOWN
191 };
192
193 struct csd_call {
194         char *object_path;
195         int status;
196         gboolean originating;
197         gboolean emergency;
198         gboolean on_hold;
199         gboolean conference;
200         char *number;
201         gboolean setup;
202         uint32_t call_id;
203 };
204
205 static struct {
206         char *operator_name;
207         uint8_t status;
208         int32_t signal_bars;
209 } net = {
210         .operator_name = NULL,
211         .status = NETWORK_REG_STATUS_UNKOWN,
212         /* Init as 0 meaning inactive mode. In modem power off state
213          * can be be -1, but we treat all values as 0s regardless
214          * inactive or power off. */
215         .signal_bars = 0,
216 };
217
218 /* Supported set of call hold operations */
219 /*static const char *telephony_chld_str = "0,1,1x,2,2x,3,4";*/
220 static const char *telephony_chld_str = "0,1,2,3";
221
222
223 static char *subscriber_number = NULL;  /* Subscriber number */
224
225
226 static struct {
227         char path[PHONEBOOK_PATH_LENGTH];
228         uint32_t type;
229         uint32_t max_size;
230         uint32_t used;
231 } ag_pb_info = {
232         .path = {0,},
233         .type = 0,
234         .max_size = 0,
235         .used =0,
236 };
237
238
239 static struct csd_call *find_call(uint32_t call_id)
240
241 {
242         GSList *l;
243
244         for (l = calls; l != NULL; l = l->next) {
245                 struct csd_call *call = l->data;
246
247                 if (call->call_id == call_id)
248                         return call;
249         }
250
251         return NULL;
252 }
253
254 static struct csd_call *find_non_held_call(void)
255 {
256         GSList *l;
257
258         for (l = calls; l != NULL; l = l->next) {
259                 struct csd_call *call = l->data;
260
261                 if (call->status == CSD_CALL_STATUS_IDLE)
262                         continue;
263
264                 if (call->status != CSD_CALL_STATUS_HOLD)
265                         return call;
266         }
267
268         return NULL;
269 }
270
271 static struct csd_call *find_non_idle_call(void)
272 {
273         GSList *l;
274
275         for (l = calls; l != NULL; l = l->next) {
276                 struct csd_call *call = l->data;
277
278                 if (call->status != CSD_CALL_STATUS_IDLE)
279                         return call;
280         }
281
282         return NULL;
283 }
284
285 static struct csd_call *find_call_with_status(int status)
286 {
287         GSList *l;
288
289         if (NULL != calls) {
290                 for (l = calls; l != NULL; l = l->next) {
291                         struct csd_call *call = l->data;
292
293                         if (call->status == status)
294                                 return call;
295                 }
296         }
297         return NULL;
298 }
299
300 static void foreach_call_with_status(int status,
301                                         int (*func)(struct csd_call *call))
302 {
303         GSList *l;
304
305         for (l = calls; l != NULL; l = l->next) {
306                 struct csd_call *call = l->data;
307
308                 if (call->status == status)
309                         func(call);
310         }
311 }
312
313 static void csd_call_free(struct csd_call *call)
314 {
315         if (!call)
316                 return;
317
318         g_free(call->object_path);
319         g_free(call->number);
320
321         g_free(call);
322 }
323
324 static int release_conference(void)
325 {
326         DBusMessage *msg;
327
328         DBG("+\n");
329
330         msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
331                                                 CSD_CALL_CONFERENCE_PATH,
332                                                 CSD_CALL_INSTANCE,
333                                                 "Release");
334         if (!msg) {
335                 error("Unable to allocate new D-Bus message");
336                 return -ENOMEM;
337         }
338
339         g_dbus_send_message(ag_connection, msg);
340
341         DBG("-\n");
342
343         return 0;
344 }
345
346 static int reject_call(struct csd_call *call)
347 {
348         DBusMessage *msg;
349
350         DBG("+\n");
351
352         msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
353                                                 call->object_path,
354                                                 CSD_CALL_INSTANCE,
355                                                 "Reject");
356         if (!msg) {
357                 error("Unable to allocate new D-Bus message");
358                 return -ENOMEM;
359         }
360         DBG(" Object Path =[ %s] and Call id = [%d]\n", call->object_path, call->call_id);
361         if (!dbus_message_append_args(msg, DBUS_TYPE_UINT32, &call->call_id,
362                         DBUS_TYPE_INVALID)) {
363
364                 DBG("dbus_message_append_args -ERROR\n");
365                 dbus_message_unref(msg);
366                 return -ENOMEM;
367         }
368
369         g_dbus_send_message(ag_connection, msg);
370
371         DBG("-\n");
372
373         return 0;
374
375 }
376 static int release_call(struct csd_call *call)
377 {
378         DBusMessage *msg;
379
380         DBG("+\n");
381
382         msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
383                                                 call->object_path,
384                                                 CSD_CALL_INSTANCE,
385                                                 "Release");
386         if (!msg) {
387                 error("Unable to allocate new D-Bus message");
388                 return -ENOMEM;
389         }
390         DBG(" Object Path =[ %s] and Call id = [%d]\n", call->object_path, call->call_id);
391         if (!dbus_message_append_args(msg, DBUS_TYPE_UINT32, &call->call_id,
392                         DBUS_TYPE_INVALID)) {
393
394                 DBG("dbus_message_append_args -ERROR\n");
395                 dbus_message_unref(msg);
396                 return -ENOMEM;
397         }
398
399         g_dbus_send_message(ag_connection, msg);
400
401         DBG("-\n");
402
403         return 0;
404 }
405
406 static int dbus_method_call_send(const char *dest, const char *path,
407                                 const char *interface, const char *method,
408                                 DBusPendingCallNotifyFunction cb,
409                                 void *user_data, int type, ...)
410 {
411         DBusMessage *msg;
412         DBusPendingCall *call;
413         va_list args;
414
415         DBG("+\n");
416
417         msg = dbus_message_new_method_call(dest, path, interface, method);
418         if (!msg) {
419                 error("Unable to allocate new D-Bus %s message", method);
420                 return -ENOMEM;
421         }
422
423         va_start(args, type);
424
425         if (!dbus_message_append_args_valist(msg, type, args)) {
426                 dbus_message_unref(msg);
427                 va_end(args);
428                 return -EIO;
429         }
430
431         va_end(args);
432
433         if (!cb) {
434                 g_dbus_send_message(ag_connection, msg);
435                 return 0;
436         }
437
438         if (!dbus_connection_send_with_reply(ag_connection, msg, &call, -1)) {
439                 error("Sending %s failed", method);
440                 dbus_message_unref(msg);
441                 return -EIO;
442         }
443
444         dbus_pending_call_set_notify(call, cb, user_data, NULL);
445         dbus_message_unref(msg);
446         DBG("-\n");
447
448         return 0;
449 }
450
451 static int answer_call(struct csd_call *call)
452 {
453         DBusMessage *msg;
454         DBG("+\n");
455
456         msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
457                                                 call->object_path,
458                                                 CSD_CALL_INSTANCE,
459                                                 "Answer");
460         if (!msg) {
461                 error("Unable to allocate new D-Bus message");
462                 return -ENOMEM;
463         }
464
465         if (!dbus_message_append_args(msg, DBUS_TYPE_UINT32, &call->call_id,
466                         DBUS_TYPE_INVALID)) {
467
468                 DBG("dbus_message_append_args -ERROR\n");
469                 dbus_message_unref(msg);
470                 return -ENOMEM;
471         }
472         g_dbus_send_message(ag_connection, msg);
473         DBG("-\n");
474         return 0;
475 }
476
477 static int number_type(const char *number)
478 {
479         if (number == NULL)
480                 return NUMBER_TYPE_TELEPHONY;
481
482         if (number[0] == '+' || strncmp(number, "00", 2) == 0)
483                 return NUMBER_TYPE_INTERNATIONAL;
484
485         return NUMBER_TYPE_TELEPHONY;
486 }
487
488 static void call_set_status(struct csd_call *call, dbus_uint32_t status)
489 {
490         dbus_uint32_t prev_status;
491         int callheld = 0;
492
493         DBG("+\n");
494
495         callheld = telephony_get_indicator(telephony_ag_indicators, "callheld");
496
497         prev_status = call->status;
498         DBG("Call %s Call id %d changed from %s to %s", call->object_path, call->call_id,
499                 call_status_str[prev_status], call_status_str[status]);
500
501         if (prev_status == status) {
502                 DBG("Ignoring CSD Call state change to existing state");
503                 return;
504         }
505
506         call->status = (int) status;
507
508         switch (status) {
509         case CSD_CALL_STATUS_IDLE:
510                 if (call->setup) {
511                         telephony_update_indicator(telephony_ag_indicators,
512                                                         "callsetup",
513                                                         EV_CALLSETUP_INACTIVE);
514                         if (!call->originating)
515                                 telephony_calling_stopped_ind();
516                 }
517
518                 g_free(call->number);
519                 call->number = NULL;
520                 call->originating = FALSE;
521                 call->emergency = FALSE;
522                 call->on_hold = FALSE;
523                 call->conference = FALSE;
524                 call->setup = FALSE;
525                 break;
526         case CSD_CALL_STATUS_CREATE:
527                 call->originating = TRUE;
528                 call->setup = TRUE;
529                 break;
530         case CSD_CALL_STATUS_COMING:
531                 call->originating = FALSE;
532                 call->setup = TRUE;
533                 break;
534         case CSD_CALL_STATUS_PROCEEDING:
535                 break;
536         case CSD_CALL_STATUS_MO_ALERTING:
537                 telephony_update_indicator(telephony_ag_indicators, "callsetup",
538                                                 EV_CALLSETUP_ALERTING);
539                 break;
540         case CSD_CALL_STATUS_MT_ALERTING:
541                 /* Some headsets expect incoming call notification before they
542                  * can send ATA command. When call changed status from waiting
543                  * to alerting we need to send missing notification. Otherwise
544                  * headsets like Nokia BH-108 or BackBeat 903 are unable to
545                  * answer incoming call that was previously waiting. */
546                 if (prev_status == CSD_CALL_STATUS_WAITING)
547                         telephony_incoming_call_ind(call->number,
548                                                 number_type(call->number));
549                 break;
550         case CSD_CALL_STATUS_WAITING:
551                 break;
552         case CSD_CALL_STATUS_ANSWERED:
553                 break;
554         case CSD_CALL_STATUS_ACTIVE:
555                 if (call->on_hold) {
556                         call->on_hold = FALSE;
557                         if (find_call_with_status(CSD_CALL_STATUS_HOLD))
558                                 telephony_update_indicator(telephony_ag_indicators,
559                                                         "callheld",
560                                                         EV_CALLHELD_MULTIPLE);
561                         else
562                                 telephony_update_indicator(telephony_ag_indicators,
563                                                         "callheld",
564                                                         EV_CALLHELD_NONE);
565                 } else {
566                         if (!g_slist_find(active_calls, call))
567                                 active_calls = g_slist_prepend(active_calls, call);
568                         if (g_slist_length(active_calls) == 1)
569                                 telephony_update_indicator(telephony_ag_indicators,
570                                                                 "call",
571                                                                 EV_CALL_ACTIVE);
572                         /* Upgrade callheld status if necessary */
573                         if (callheld == EV_CALLHELD_ON_HOLD)
574                                 telephony_update_indicator(telephony_ag_indicators,
575                                                         "callheld",
576                                                         EV_CALLHELD_MULTIPLE);
577                         telephony_update_indicator(telephony_ag_indicators,
578                                                         "callsetup",
579                                                         EV_CALLSETUP_INACTIVE);
580                         if (!call->originating)
581                                 telephony_calling_stopped_ind();
582                         call->setup = FALSE;
583                 }
584                 break;
585         case CSD_CALL_STATUS_MO_RELEASE:
586         case CSD_CALL_STATUS_MT_RELEASE:
587                 active_calls = g_slist_remove(active_calls, call);
588                 if (g_slist_length(active_calls) == 0)
589                         telephony_update_indicator(telephony_ag_indicators, "call",
590                                                         EV_CALL_INACTIVE);
591
592                 if ((prev_status == CSD_CALL_STATUS_MO_ALERTING) ||
593                         (prev_status == CSD_CALL_STATUS_COMING) ||
594                         (prev_status == CSD_CALL_STATUS_CREATE) ||
595                         (prev_status == CSD_CALL_STATUS_WAITING)) {
596                                 telephony_update_indicator(telephony_ag_indicators,
597                                                         "callsetup",
598                                                         EV_CALLSETUP_INACTIVE);
599                 }
600
601                 if (prev_status == CSD_CALL_STATUS_COMING) {
602                         if (!call->originating)
603                                 telephony_calling_stopped_ind();
604                 }
605                 calls = g_slist_remove(calls, call);
606                 csd_call_free(call);
607                 break;
608         case CSD_CALL_STATUS_HOLD_INITIATED:
609                 break;
610         case CSD_CALL_STATUS_HOLD:
611                 call->on_hold = TRUE;
612                 if (find_non_held_call())
613                         telephony_update_indicator(telephony_ag_indicators,
614                                                         "callheld",
615                                                         EV_CALLHELD_MULTIPLE);
616                 else
617                         telephony_update_indicator(telephony_ag_indicators,
618                                                         "callheld",
619                                                         EV_CALLHELD_ON_HOLD);
620                 break;
621         case CSD_CALL_STATUS_RETRIEVE_INITIATED:
622                 break;
623         case CSD_CALL_STATUS_RECONNECT_PENDING:
624                 break;
625         case CSD_CALL_STATUS_TERMINATED:
626                 if (call->on_hold &&
627                                 !find_call_with_status(CSD_CALL_STATUS_HOLD)) {
628                         telephony_update_indicator(telephony_ag_indicators,
629                                                         "callheld",
630                                                         EV_CALLHELD_NONE);
631                         return;
632                 }
633
634                 if (callheld == EV_CALLHELD_MULTIPLE &&
635                                 find_call_with_status(CSD_CALL_STATUS_HOLD) &&
636                                 !find_call_with_status(CSD_CALL_STATUS_ACTIVE))
637                         telephony_update_indicator(telephony_ag_indicators,
638                                                         "callheld",
639                                                         EV_CALLHELD_ON_HOLD);
640                 break;
641         case CSD_CALL_STATUS_SWAP_INITIATED:
642                 break;
643         default:
644                 error("Unknown call status %u", status);
645                 break;
646         }
647         DBG("-\n");
648 }
649
650 /**
651  * This API shall invoke a dbus method call to bluetooth framework to split the call
652  *
653  * @return              This function returns zero on success.
654  * @param[in]           call    Pointer to the Call information structure.
655  * @param[out]          NONE.
656  */
657 static int split_call(struct csd_call *call)
658 {
659         DBusMessage *msg;
660
661         DBG("+n");
662
663         if (NULL != call) {
664                 msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
665                                                         call->object_path,
666                                                         CSD_CALL_INSTANCE,
667                                                         "Split");
668                 if (!msg) {
669                         error("Unable to allocate new D-Bus message");
670                         return -ENOMEM;
671                 }
672
673                 g_dbus_send_message(ag_connection, msg);
674         }
675         DBG("-\n");
676
677         return 0;
678 }
679 /**
680  * This API shall invoke a dbus method call to bluetooth framework to swap the calls
681  *
682  * @return              This function returns zero on success.
683  * @param[in]           NONE.
684  * @param[out]          NONE.
685  */
686 static int swap_calls(void)
687 {
688         DBusMessage *msg;
689         DBG("+\n");
690
691         msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
692                                                 CSD_CALL_INTERFACE,
693                                                 "Swap");
694         if (!msg) {
695                 error("Unable to allocate new D-Bus message");
696                 return -ENOMEM;
697         }
698
699         g_dbus_send_message(ag_connection, msg);
700         DBG("-\n");
701
702         return 0;
703 }
704
705 /**
706  * This API shall invoke a dbus method call to bluetooth framework to hold the call
707  *
708  * @return              This function returns zero on success.
709  * @param[in]           call    Pointer to the Call information structure.
710  * @param[out]          NONE.
711  */
712 static int hold_call(struct csd_call *call)
713 {
714         DBusMessage *msg;
715         DBG("+\n");
716
717         msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
718                                                 CSD_CALL_INTERFACE,
719                                                 "Hold");
720         if (!msg) {
721                 error("Unable to allocate new D-Bus message");
722                 return -ENOMEM;
723         }
724         if (NULL != call) {
725                 DBG(" Object Path =[ %s] and Call id = [%d]\n", call->object_path, call->call_id);
726
727                 if (!dbus_message_append_args(msg, DBUS_TYPE_UINT32, &call->call_id,
728                                 DBUS_TYPE_INVALID)) {
729
730                         DBG("dbus_message_append_args -ERROR\n");
731                         dbus_message_unref(msg);
732                         return -ENOMEM;
733                 }
734
735                 g_dbus_send_message(ag_connection, msg);
736         }
737         DBG("-\n");
738
739         return 0;
740 }
741
742
743 /**
744  * This API shall invoke a dbus method call to bluetooth framework to unhold the call
745  *
746  * @return              This function returns zero on success.
747  * @param[in]           call    Pointer to the Call information structure.
748  * @param[out]          NONE.
749  */
750 static int unhold_call(struct csd_call *call)
751 {
752         DBusMessage *msg;
753         DBG("+\n");
754
755         msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
756                                                 CSD_CALL_INTERFACE,
757                                                 "Unhold");
758         if (!msg) {
759                 error("Unable to allocate new D-Bus message");
760                 return -ENOMEM;
761         }
762
763         if (NULL != call) {
764                 DBG(" Object Path =[ %s] and Call id = [%d]\n", call->object_path, call->call_id);
765
766                 if (!dbus_message_append_args(msg, DBUS_TYPE_UINT32, &call->call_id,
767                                 DBUS_TYPE_INVALID)) {
768
769                         DBG("dbus_message_append_args -ERROR\n");
770                         dbus_message_unref(msg);
771                         return -ENOMEM;
772                 }
773
774                 g_dbus_send_message(ag_connection, msg);
775         }
776         DBG("-\n");
777
778         return 0;
779 }
780
781 /**
782  * This API shall invoke a dbus method call to bluetooth framework to create conmference calls
783  *
784  * @return              This function returns zero on success.
785  * @param[in]           NONE.
786  * @param[out]          NONE.
787  */
788 static int create_conference(void)
789 {
790         DBusMessage *msg;
791         DBG("+\n");
792
793         msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
794                                                 CSD_CALL_INTERFACE,
795                                                 "Conference");
796         if (!msg) {
797                 error("Unable to allocate new D-Bus message");
798                 return -ENOMEM;
799         }
800
801         g_dbus_send_message(ag_connection, msg);
802         DBG("-\n");
803
804         return 0;
805 }
806 /**
807  * This API shall invoke a dbus method call to bluetooth framework to transfer the call
808  *
809  * @return              This function returns zero on success.
810  * @param[in]           NONE.
811  * @param[out]          NONE.
812  */
813 static int call_transfer(void)
814 {
815         DBusMessage *msg;
816         DBG("+\n");
817
818         msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
819                                                 CSD_CALL_INTERFACE,
820                                                 "Transfer");
821         if (!msg) {
822                 error("Unable to allocate new D-Bus message");
823                 return -ENOMEM;
824         }
825
826         g_dbus_send_message(ag_connection, msg);
827         DBG("-\n");
828
829         return 0;
830 }
831
832 static void telephony_chld_reply(DBusPendingCall *call, void *data)
833 {
834         DBusMessage *reply = dbus_pending_call_steal_reply(call);
835         DBusError derr;
836
837         DBG("redial_reply");
838
839         dbus_error_init(&derr);
840         if (!dbus_set_error_from_message(&derr, reply)) {
841                 DBG("chld  reply: cmd is valid");
842                 telephony_dial_number_rsp(data, CME_ERROR_NONE);
843                 goto done;
844         }
845
846         DBG("chld_reply reply: %s", derr.message);
847
848         dbus_error_free(&derr);
849         telephony_dial_number_rsp(data, CME_ERROR_AG_FAILURE);
850
851 done:
852         dbus_message_unref(reply);
853 }
854
855 void telephony_call_hold_req(void *telephony_device, const char *cmd)
856 {
857         const char *idx;
858         struct csd_call *call;
859         int err = 0;
860         int chld_value = 0;
861
862         DBG("+\n");
863
864         if (strlen(cmd) > 1)
865                 idx = &cmd[1];
866         else
867                 idx = NULL;
868
869         if (idx)
870                 call = g_slist_nth_data(calls, strtol(idx, NULL, 0) - 1);
871         else
872                 call = NULL;
873 #if 0
874         switch (cmd[0]) {
875         case '0':
876                 if (find_call_with_status(CSD_CALL_STATUS_WAITING))
877                         foreach_call_with_status(CSD_CALL_STATUS_WAITING,
878                                                                 release_call);
879                 else
880                         foreach_call_with_status(CSD_CALL_STATUS_HOLD,
881                                                                 release_call);
882                 break;
883         case '1':
884                 if (idx) {
885                         if (call)
886                                 err = release_call(call);
887                         break;
888                 }
889                 foreach_call_with_status(CSD_CALL_STATUS_ACTIVE, release_call);
890                 call = find_call_with_status(CSD_CALL_STATUS_WAITING);
891                 if (call) {
892                         err = answer_call(call);
893                 }
894                 else {
895                         struct csd_call *held;
896                         held = find_call_with_status(CSD_CALL_STATUS_HOLD);
897                         if(held)
898                                 err = unhold_call(held);
899                 }
900                 break;
901         case '2':
902                 if (idx) {
903                         if (call)
904                                 err = split_call(call);
905                 } else {
906                         struct csd_call *held, *wait;
907
908                         call = find_call_with_status(CSD_CALL_STATUS_ACTIVE);
909                         held = find_call_with_status(CSD_CALL_STATUS_HOLD);
910                         wait = find_call_with_status(CSD_CALL_STATUS_WAITING);
911
912                         if (wait)
913                                 err = answer_call(wait);
914                         else if (call && held)
915                                 err = swap_calls();
916                         else {
917                                 if (call)
918                                         err = hold_call(call);
919                                 if (held)
920                                         err = unhold_call(held);
921                         }
922                 }
923                 break;
924         case '3':
925                 if (find_call_with_status(CSD_CALL_STATUS_HOLD) ||
926                                 find_call_with_status(CSD_CALL_STATUS_WAITING))
927                         err = create_conference();
928                 break;
929         case '4':
930                 err = call_transfer();
931                 break;
932         default:
933                 DBG("Unknown call hold request");
934                 break;
935         }
936
937         if (err)
938                 telephony_call_hold_rsp(telephony_device,
939                                         CME_ERROR_AG_FAILURE);
940         else
941                 telephony_call_hold_rsp(telephony_device, CME_ERROR_NONE);
942 #else
943         idx = &cmd[0];
944         chld_value = strtol(idx, NULL, 0);
945
946         err = dbus_method_call_send(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
947                                         CSD_CALL_INSTANCE, "Threeway",
948                                         telephony_chld_reply, telephony_device,
949                                         DBUS_TYPE_INT32, &chld_value,
950                                         DBUS_TYPE_INVALID);
951
952         if (err)
953                 telephony_call_hold_rsp(telephony_device,
954                                         CME_ERROR_AG_FAILURE);
955 #endif
956         DBG("-\n");
957 }
958
959 static void handle_incoming_call(DBusMessage *msg)
960 {
961
962         const char *number, *call_path;
963         struct csd_call *call;
964         uint32_t call_id;
965
966         DBG("+\n");
967         DBG("handle_incoming_call()\n");
968
969         if (!dbus_message_get_args(msg, NULL,
970                                         DBUS_TYPE_OBJECT_PATH, &call_path,
971                                         DBUS_TYPE_STRING, &number,
972                                         DBUS_TYPE_UINT32, &call_id,
973                                         DBUS_TYPE_INVALID)) {
974                 error("Unexpected parameters in Call.Coming() signal");
975                 return;
976         }
977
978         call = g_new0(struct csd_call, 1);
979         call->object_path = g_strdup(call_path);
980         call->call_id = call_id;
981         call->number = g_strdup(number);
982         calls = g_slist_append(calls, call);
983
984         DBG("Incoming call to %s from number %s call id %d", call_path, number, call_id);
985
986         if (find_call_with_status(CSD_CALL_STATUS_ACTIVE) ||
987                         find_call_with_status(CSD_CALL_STATUS_HOLD)) {
988                 telephony_call_waiting_ind(call->number,
989                                                 number_type(call->number));
990                 call_set_status(call, CSD_CALL_STATUS_WAITING);
991         } else {
992                 telephony_incoming_call_ind(call->number,
993                                                 number_type(call->number));
994
995                 call_set_status(call, CSD_CALL_STATUS_COMING);
996         }
997         telephony_update_indicator(telephony_ag_indicators, "callsetup",
998                                         EV_CALLSETUP_INCOMING);
999         DBG("-\n");
1000 }
1001
1002 static void update_registration_status(uint8_t status)
1003 {
1004         uint8_t new_status;
1005         DBG("+\n");
1006
1007         new_status = status;
1008
1009         if (net.status == new_status)
1010                 return;
1011
1012         switch (new_status) {
1013         case NETWORK_REG_STATUS_HOME:
1014                 telephony_update_indicator(telephony_ag_indicators, "roam",
1015                                                         EV_ROAM_INACTIVE);
1016                 if (net.status > NETWORK_REG_STATUS_ROAMING)
1017                         telephony_update_indicator(telephony_ag_indicators,
1018                                                         "service",
1019                                                         EV_SERVICE_PRESENT);
1020                 break;
1021         case NETWORK_REG_STATUS_ROAMING:
1022                 telephony_update_indicator(telephony_ag_indicators, "roam",
1023                                                         EV_ROAM_ACTIVE);
1024                 if (net.status > NETWORK_REG_STATUS_ROAMING)
1025                         telephony_update_indicator(telephony_ag_indicators,
1026                                                         "service",
1027                                                         EV_SERVICE_PRESENT);
1028                 break;
1029         case NETWORK_REG_STATUS_OFFLINE:
1030         case NETWORK_REG_STATUS_SEARCHING:
1031         case NETWORK_REG_STATUS_NO_SIM:
1032         case NETWORK_REG_STATUS_POWEROFF:
1033         case NETWORK_REG_STATUS_POWERSAFE:
1034         case NETWORK_REG_STATUS_NO_COVERAGE:
1035         case NETWORK_REG_STATUS_REJECTED:
1036         case NETWORK_REG_STATUS_UNKOWN:
1037                 if (net.status < NETWORK_REG_STATUS_OFFLINE)
1038                         telephony_update_indicator(telephony_ag_indicators,
1039                                                         "service",
1040                                                         EV_SERVICE_NONE);
1041                 break;
1042         }
1043
1044         net.status = new_status;
1045
1046         DBG("-\n");
1047 }
1048
1049 static void update_signal_strength(int32_t signal_bars)
1050 {
1051         DBG("+\n");
1052
1053         if (signal_bars < 0) {
1054                 DBG("signal strength smaller than expected: %d < 0",
1055                                 signal_bars);
1056                 signal_bars = 0;
1057         } else if (signal_bars > 5) {
1058                 DBG("signal strength greater than expected: %d > 5",
1059                                 signal_bars);
1060                 signal_bars = 5;
1061         }
1062
1063         if (net.signal_bars == signal_bars)
1064                 return;
1065
1066         telephony_update_indicator(telephony_ag_indicators, "signal", signal_bars);
1067
1068         net.signal_bars = signal_bars;
1069
1070         DBG("-\n");
1071 }
1072
1073 static void update_battery_strength(int32_t battery_level)
1074 {
1075         int current_battchg = 0;
1076
1077         DBG("+\n");
1078
1079         current_battchg = telephony_get_indicator(telephony_ag_indicators, "battchg");
1080
1081         if (battery_level < 0) {
1082                 DBG("Battery strength smaller than expected: %d < 0",
1083                                                                 battery_level);
1084                 battery_level = 0;
1085         } else if (battery_level > 5) {
1086                 DBG("Battery strength greater than expected: %d > 5",
1087                                                                 battery_level);
1088                 battery_level = 5;
1089         }
1090         if (current_battchg == battery_level)
1091                 return;
1092
1093         telephony_update_indicator(telephony_ag_indicators,
1094                         "battchg", battery_level);
1095
1096
1097         DBG("-\n");
1098 }
1099
1100
1101 static void handle_outgoing_call(DBusMessage *msg)
1102 {
1103         const char *number, *call_path;
1104         struct csd_call *call;
1105         uint32_t call_id;
1106
1107         DBG("+\n");
1108         DBG("handle_outgoing_call()\n");
1109
1110         if (!dbus_message_get_args(msg, NULL,
1111                                         DBUS_TYPE_OBJECT_PATH, &call_path,
1112                                         DBUS_TYPE_STRING, &number,
1113                                         DBUS_TYPE_UINT32, &call_id,
1114                                         DBUS_TYPE_INVALID)) {
1115                 error("Unexpected parameters in Call.Coming() signal");
1116                 return;
1117         }
1118
1119         call = g_new0(struct csd_call, 1);
1120         call->object_path = g_strdup(call_path);
1121         call->call_id = call_id;
1122         call->number = g_strdup(number);
1123         calls = g_slist_append(calls, call);
1124
1125         DBG("Outgoing call to %s from number %s call id %d", call_path, number, call_id);
1126
1127         call_set_status(call, CSD_CALL_STATUS_CREATE);
1128
1129         telephony_update_indicator(telephony_ag_indicators, "callsetup",
1130                                         EV_CALLSETUP_OUTGOING);
1131         DBG("-\n");
1132 }
1133
1134 static void handle_create_requested(DBusMessage *msg)
1135 {
1136         DBG("+\n");
1137         DBG("handle_create_requested()\n");
1138         DBG("-\n");
1139 }
1140
1141 static void handle_call_status(DBusMessage *msg, const char *call_path)
1142 {
1143         struct csd_call *call;
1144         dbus_uint32_t status, call_id;
1145         DBG("+\n");
1146
1147         if (!dbus_message_get_args(msg, NULL,
1148                                         DBUS_TYPE_UINT32, &status,
1149                                         DBUS_TYPE_UINT32, &call_id,
1150                                         DBUS_TYPE_INVALID)) {
1151                 error("Unexpected paramters in Instance.CallStatus() signal");
1152                 return;
1153         }
1154
1155         DBG("status = [%d] and call_id = [%d]\n", status, call_id);
1156         call = find_call(call_id);
1157         if (!call) {
1158 /*
1159         call_path is equal to CSD_CALL_PATH then we should update the call list
1160         since the call_path is sent from native AG applicaton
1161
1162         Added for updation of the call status if the call is not added inthe call list
1163 */
1164                 if (g_str_equal(CSD_CALL_PATH, call_path)) {
1165                         call = g_new0(struct csd_call, 1);
1166                         call->object_path = g_strdup(call_path);
1167                         call->call_id = call_id;
1168                         calls = g_slist_append(calls, call);
1169                 }
1170         }
1171
1172         if (status > 16) {
1173                 error("Invalid call status %u", status);
1174                 return;
1175         }
1176
1177         call_set_status(call, status);
1178         DBG("-\n");
1179 }
1180
1181 static void update_operator_name(const char *name)
1182 {
1183         DBG("+\n");
1184         if (name == NULL)
1185                 return;
1186
1187         g_free(net.operator_name);
1188         net.operator_name = g_strndup(name, 16);
1189         DBG("-\n");
1190 }
1191
1192 static void update_subscriber_number(const char *number)
1193 {
1194         DBG("+\n");
1195         if (number == NULL)
1196                 return;
1197
1198         g_free(subscriber_number);
1199         subscriber_number = g_strdup(number);
1200         DBG("-\n");
1201 }
1202
1203 static void handle_conference(DBusMessage *msg, gboolean joined)
1204 {
1205         DBG("+\n");
1206         DBG("handle_conference()\n");
1207         DBG("-\n");
1208 }
1209
1210 static void handle_registration_changed(DBusMessage *msg)
1211 {
1212         uint8_t status;
1213
1214         DBG("+\n");
1215         DBG("handle_registration_changed()\n");
1216
1217         if (!dbus_message_get_args(msg, NULL,
1218                                         DBUS_TYPE_BYTE, &status,
1219                                         DBUS_TYPE_INVALID)) {
1220                 error("Unexpected parameters in RegistrationChanged");
1221                 return;
1222         }
1223
1224         update_registration_status((uint8_t) status);
1225         DBG("-\n");
1226 }
1227
1228 static void handle_operator_name_changed(DBusMessage *msg)
1229 {
1230         const char *name;
1231
1232         DBG("+\n");
1233
1234         if (!dbus_message_get_args(msg, NULL,
1235                                         DBUS_TYPE_STRING, &name,
1236                                         DBUS_TYPE_INVALID)) {
1237                 error("Unexpected parameters in OperatorNameChanged");
1238                 return;
1239         }
1240
1241         update_operator_name(name);
1242         DBG("-\n");
1243 }
1244
1245 static void handle_signal_bars_changed(DBusMessage *msg)
1246 {
1247         int32_t signal_bars;
1248
1249         DBG("+\n");
1250
1251         if (!dbus_message_get_args(msg, NULL,
1252                                         DBUS_TYPE_INT32, &signal_bars,
1253                                         DBUS_TYPE_INVALID)) {
1254                 error("Unexpected parameters in SignalBarsChanged");
1255                 return;
1256         }
1257
1258         update_signal_strength(signal_bars);
1259         DBG("-\n");
1260 }
1261
1262 static void handle_battery_bars_changed(DBusMessage *msg)
1263 {
1264         int32_t battery_level;
1265
1266         DBG("+\n");
1267
1268         if (!dbus_message_get_args(msg, NULL,
1269                                         DBUS_TYPE_INT32, &battery_level,
1270                                         DBUS_TYPE_INVALID)) {
1271                 error("Unexpected parameters in SignalBarsChanged");
1272                 return;
1273         }
1274
1275         update_battery_strength(battery_level);
1276         DBG("-\n");
1277 }
1278
1279 static void handle_subscriber_number_changed(DBusMessage *msg)
1280 {
1281         const char *number;
1282
1283         DBG("+\n");
1284
1285         if (!dbus_message_get_args(msg, NULL,
1286                                         DBUS_TYPE_STRING, &number,
1287                                         DBUS_TYPE_INVALID)) {
1288                 error("Unexpected parameters in SubscriberNumberChanged");
1289                 return;
1290         }
1291
1292         update_subscriber_number(number);
1293         DBG("-\n");
1294 }
1295 static gboolean signal_filter(DBusConnection *conn, DBusMessage *msg,
1296                                                                 void *data)
1297 {
1298         const char *path = NULL;
1299
1300         DBG("+\n");
1301
1302         path = dbus_message_get_path(msg);
1303
1304         if (dbus_message_is_signal(msg, CSD_CALL_INTERFACE, "Coming"))
1305                 handle_incoming_call(msg);
1306         else if (dbus_message_is_signal(msg, CSD_CALL_INTERFACE, "Created"))
1307                 handle_outgoing_call(msg);
1308         else if (dbus_message_is_signal(msg, CSD_CALL_INTERFACE,
1309                                                         "CreateRequested"))
1310                 handle_create_requested(msg);
1311         else if (dbus_message_is_signal(msg, CSD_CALL_INSTANCE, "CallStatus"))
1312                 handle_call_status(msg, path);
1313         else if (dbus_message_is_signal(msg, CSD_CALL_CONFERENCE, "Joined"))
1314                 handle_conference(msg, TRUE);
1315         else if (dbus_message_is_signal(msg, CSD_CALL_CONFERENCE, "Left"))
1316                 handle_conference(msg, FALSE);
1317         else if (dbus_message_is_signal(msg, CSD_CSNET_REGISTRATION,
1318                                 "RegistrationChanged"))
1319                 handle_registration_changed(msg);
1320         else if (dbus_message_is_signal(msg, CSD_CSNET_OPERATOR,
1321                                 "OperatorNameChanged"))
1322                 handle_operator_name_changed(msg);
1323         else if (dbus_message_is_signal(msg, CSD_CSNET_SIGNAL,
1324                                 "SignalBarsChanged"))
1325                 handle_signal_bars_changed(msg);
1326         else if (dbus_message_is_signal(msg, CSD_TELEPHONE_BATTERY,
1327                                 "BatteryBarsChanged"))
1328                 handle_battery_bars_changed(msg);
1329         else if (dbus_message_is_signal(msg, CSD_CSNET_SUBSCRIBER,
1330                                 "SubscriberNumberChanged"))
1331                 handle_subscriber_number_changed(msg);
1332
1333         DBG("-\n");
1334         return TRUE;
1335 }
1336
1337 static void dbus_add_watch(const char *sender, const char *path,
1338                                 const char *interface, const char *member)
1339 {
1340         guint watch;
1341
1342         watch = g_dbus_add_signal_watch(ag_connection, sender, path, interface,
1343                                         member, signal_filter, NULL, NULL);
1344
1345         watches = g_slist_prepend(watches, GUINT_TO_POINTER(watch));
1346 }
1347
1348 static const char *telephony_memory_dial_lookup(int location)
1349 {
1350         /*memory dial not supported*/
1351         if (location == 1)
1352                 return NULL;
1353         else
1354                 return NULL;
1355 }
1356
1357 /*API's that shall be ported*/
1358
1359 int telephony_init(void)
1360 {
1361         uint32_t features = AG_FEATURE_EC_ANDOR_NR |
1362                                 AG_FEATURE_REJECT_A_CALL |
1363                                 AG_FEATURE_ENHANCED_CALL_STATUS |
1364                                 AG_FEATURE_THREE_WAY_CALLING;
1365         int i;
1366
1367         DBG("");
1368
1369         ag_connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
1370
1371         dbus_add_watch(NULL, CSD_CALL_PATH, CSD_CALL_INTERFACE, NULL);
1372         dbus_add_watch(NULL, CSD_CALL_PATH, CSD_CALL_INSTANCE, NULL);
1373         dbus_add_watch(NULL, CSD_CALL_PATH, CSD_CALL_CONFERENCE, NULL);
1374         dbus_add_watch(NULL, CSD_CSNET_PATH, CSD_CSNET_REGISTRATION,
1375                         "RegistrationChanged");
1376         dbus_add_watch(NULL, CSD_CSNET_PATH, CSD_CSNET_OPERATOR,
1377                         "OperatorNameChanged");
1378         dbus_add_watch(NULL, CSD_CSNET_PATH, CSD_CSNET_SIGNAL,
1379                         "SignalBarsChanged");
1380         dbus_add_watch(NULL, CSD_CSNET_PATH, CSD_TELEPHONE_BATTERY,
1381                         "BatteryBarsChanged");
1382         dbus_add_watch(NULL, CSD_CSNET_PATH, CSD_CSNET_SUBSCRIBER,
1383                         "SubscriberNumberChanged");
1384
1385         /* Reset indicators */
1386         for (i = 0; telephony_ag_indicators[i].desc != NULL; i++) {
1387                 if (g_str_equal(telephony_ag_indicators[i].desc, "battchg"))
1388                         telephony_ag_indicators[i].val = 5;
1389                 else
1390                         telephony_ag_indicators[i].val = 0;
1391         }
1392
1393         /*Initializatoin of the indicators*/
1394         telephony_ready_ind(features, telephony_ag_indicators, BTRH_NOT_SUPPORTED,
1395                                                                 telephony_chld_str);
1396
1397         return 0;
1398 }
1399
1400 static void remove_watch(gpointer data)
1401 {
1402         g_dbus_remove_watch(ag_connection, GPOINTER_TO_UINT(data));
1403 }
1404
1405 void telephony_exit(void)
1406 {
1407         DBG("");
1408
1409         g_free(net.operator_name);
1410         net.operator_name = NULL;
1411
1412         g_free(subscriber_number);
1413         subscriber_number = NULL;
1414
1415         net.status = NETWORK_REG_STATUS_UNKOWN;
1416         net.signal_bars = 0;
1417
1418         g_slist_free(active_calls);
1419         active_calls = NULL;
1420
1421         g_slist_foreach(calls, (GFunc) csd_call_free, NULL);
1422         g_slist_free(calls);
1423         calls = NULL;
1424
1425         g_slist_foreach(watches, (GFunc) remove_watch, NULL);
1426         g_slist_free(watches);
1427         watches = NULL;
1428
1429         dbus_connection_unref(ag_connection);
1430         ag_connection = NULL;
1431
1432         telephony_deinit();
1433 }
1434
1435 void telephony_device_connected(void *telephony_device)
1436 {
1437 }
1438
1439 void telephony_device_disconnected(void *telephony_device)
1440 {
1441         events_enabled = FALSE;
1442 }
1443
1444 void telephony_event_reporting_req(void *telephony_device, int ind)
1445 {
1446         events_enabled = ind == 1 ? TRUE : FALSE;
1447
1448         telephony_event_reporting_rsp(telephony_device, CME_ERROR_NONE);
1449 }
1450
1451 void telephony_response_and_hold_req(void *telephony_device, int rh)
1452 {
1453         telephony_response_and_hold_rsp(telephony_device,
1454                                                 CME_ERROR_NOT_SUPPORTED);
1455 }
1456
1457 static void telephony_dial_number_reply(DBusPendingCall *call, void *data)
1458 {
1459         DBusMessage *reply = dbus_pending_call_steal_reply(call);
1460         DBusError derr;
1461
1462         DBG("redial_reply");
1463
1464         dbus_error_init(&derr);
1465         if (!dbus_set_error_from_message(&derr, reply)) {
1466                 DBG("hfg  reply: dial done  successfully");
1467                 telephony_dial_number_rsp(data, CME_ERROR_NONE);
1468                 goto done;
1469         }
1470
1471         DBG("dial_reply reply: %s", derr.message);
1472
1473         dbus_error_free(&derr);
1474         telephony_dial_number_rsp(data, CME_ERROR_AG_FAILURE);
1475
1476 done:
1477         dbus_message_unref(reply);
1478 }
1479
1480 void telephony_dial_number_req(void *telephony_device, const char *number)
1481 {
1482         uint32_t flags = callerid;
1483
1484         if (strncmp(number, "*31#", 4) == 0) {
1485                 number += 4;
1486                 flags = CALL_FLAG_PRESENTATION_ALLOWED;
1487         } else if (strncmp(number, "#31#", 4) == 0) {
1488                 number += 4;
1489                 flags = CALL_FLAG_PRESENTATION_RESTRICTED;
1490         } else if (number[0] == '>') {
1491                 int location = strtol(&number[1], NULL, 0);
1492
1493                 if (0 != dbus_method_call_send(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
1494                                         CSD_CALL_INTERFACE, "DialMemory",
1495                                         telephony_dial_number_reply, telephony_device,
1496                                         DBUS_TYPE_INT32, &location,
1497                                         DBUS_TYPE_INVALID)) {
1498                         telephony_dial_number_rsp(telephony_device,
1499                                                         CME_ERROR_AG_FAILURE);
1500                 }
1501                 return;
1502         }
1503
1504         if (0 != dbus_method_call_send(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
1505                                 CSD_CALL_INTERFACE, "DialNo",
1506                                 NULL, NULL,
1507                                 DBUS_TYPE_STRING, &number,
1508                                 DBUS_TYPE_UINT32, &flags,
1509                                 DBUS_TYPE_INVALID)) {
1510                 telephony_dial_number_rsp(telephony_device,
1511                                                 CME_ERROR_AG_FAILURE);
1512                 return;
1513         }
1514
1515         telephony_dial_number_rsp(telephony_device, CME_ERROR_NONE);
1516 }
1517
1518
1519 void telephony_terminate_call_req(void *telephony_device)
1520 {
1521         struct csd_call *call;
1522         struct csd_call *alerting;
1523         int err;
1524
1525         DBG("+\n");
1526
1527         call = find_call_with_status(CSD_CALL_STATUS_ACTIVE);
1528         if (!call)
1529                 call = find_non_idle_call();
1530
1531         if (!call) {
1532                 error("No active call");
1533                 telephony_terminate_call_rsp(telephony_device,
1534                                                 CME_ERROR_NOT_ALLOWED);
1535                 return;
1536         }
1537
1538         if (NULL != (alerting = find_call_with_status(CSD_CALL_STATUS_CREATE)))
1539                 err = reject_call(alerting);
1540         else if (NULL != (alerting = find_call_with_status(CSD_CALL_STATUS_MO_ALERTING)))
1541                 err = reject_call(alerting);
1542         else if (NULL != (alerting = find_call_with_status(CSD_CALL_STATUS_COMING)))
1543                 err = reject_call(alerting);
1544         else if (call->conference)
1545                 err = release_conference();
1546         else
1547                 err = release_call(call);
1548
1549         if (err < 0)
1550                 telephony_terminate_call_rsp(telephony_device,
1551                                                 CME_ERROR_AG_FAILURE);
1552         else
1553                 telephony_terminate_call_rsp(telephony_device, CME_ERROR_NONE);
1554         DBG("-\n");
1555
1556 }
1557
1558 void telephony_answer_call_req(void *telephony_device)
1559 {
1560         struct csd_call *call;
1561
1562         call = find_call_with_status(CSD_CALL_STATUS_COMING);
1563         if (!call)
1564                 call = find_call_with_status(CSD_CALL_STATUS_MT_ALERTING);
1565
1566         if (!call)
1567                 call = find_call_with_status(CSD_CALL_STATUS_PROCEEDING);
1568
1569         if (!call)
1570                 call = find_call_with_status(CSD_CALL_STATUS_WAITING);
1571
1572         if (!call) {
1573                 telephony_answer_call_rsp(telephony_device,
1574                                                 CME_ERROR_NOT_ALLOWED);
1575                 return;
1576         }
1577
1578         if (answer_call(call) < 0)
1579                 telephony_answer_call_rsp(telephony_device,
1580                                                 CME_ERROR_AG_FAILURE);
1581         else
1582                 telephony_answer_call_rsp(telephony_device, CME_ERROR_NONE);
1583
1584 }
1585
1586 void telephony_key_press_req(void *telephony_device, const char *keys)
1587 {
1588         struct csd_call *active, *waiting;
1589         int err;
1590
1591         waiting = find_call_with_status(CSD_CALL_STATUS_COMING);
1592         if (!waiting)
1593                 waiting = find_call_with_status(CSD_CALL_STATUS_MT_ALERTING);
1594         if (!waiting)
1595                 waiting = find_call_with_status(CSD_CALL_STATUS_PROCEEDING);
1596
1597         active = find_call_with_status(CSD_CALL_STATUS_ACTIVE);
1598
1599         if (waiting)
1600                 err = answer_call(waiting);
1601         else if (active)
1602                 err = release_call(active);
1603         else
1604                 err = 0;
1605
1606         if (err < 0)
1607                 telephony_key_press_rsp(telephony_device,
1608                                                         CME_ERROR_AG_FAILURE);
1609         else
1610                 telephony_key_press_rsp(telephony_device, CME_ERROR_NONE);
1611 }
1612
1613 void telephony_last_dialed_number_req(void *telephony_device)
1614 {
1615         if (0 != dbus_method_call_send(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
1616                                 CSD_CALL_INTERFACE, "DialLastNo",
1617                                 telephony_dial_number_reply, telephony_device,
1618                                 DBUS_TYPE_INVALID)) {
1619                 telephony_dial_number_rsp(telephony_device,
1620                                                 CME_ERROR_AG_FAILURE);
1621         }
1622 }
1623
1624 void telephony_transmit_dtmf_req(void *telephony_device, char tone)
1625 {
1626         char buf[2] = { tone, '\0' }, *buf_ptr = buf;
1627
1628         if (0 != dbus_method_call_send(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
1629                                 CSD_CALL_INTERFACE, "SendDtmf",
1630                                 NULL, NULL,
1631                                 DBUS_TYPE_STRING, &buf_ptr,
1632                                 DBUS_TYPE_INVALID)) {
1633                 telephony_transmit_dtmf_rsp(telephony_device,
1634                                                 CME_ERROR_AG_FAILURE);
1635                 return;
1636         }
1637
1638         telephony_transmit_dtmf_rsp(telephony_device, CME_ERROR_NONE);
1639 }
1640
1641 static int csd_status_to_hfp(struct csd_call *call)
1642 {
1643         switch (call->status) {
1644         case CSD_CALL_STATUS_IDLE:
1645         case CSD_CALL_STATUS_MO_RELEASE:
1646         case CSD_CALL_STATUS_MT_RELEASE:
1647         case CSD_CALL_STATUS_TERMINATED:
1648                 return -1;
1649         case CSD_CALL_STATUS_CREATE:
1650                 return CALL_STATUS_DIALING;
1651         case CSD_CALL_STATUS_WAITING:
1652                 return CALL_STATUS_WAITING;
1653         case CSD_CALL_STATUS_PROCEEDING:
1654                 /* PROCEEDING can happen in outgoing/incoming */
1655                 if (call->originating)
1656                         return CALL_STATUS_DIALING;
1657                 /*
1658                  * PROCEEDING is followed by WAITING CSD status, therefore
1659                  * second incoming call status indication is set immediately
1660                  * to waiting.
1661                  */
1662                 if (g_slist_length(active_calls) > 0)
1663                         return CALL_STATUS_WAITING;
1664
1665                 return CALL_STATUS_INCOMING;
1666         case CSD_CALL_STATUS_COMING:
1667                 if (g_slist_length(active_calls) > 0)
1668                         return CALL_STATUS_WAITING;
1669
1670                 return CALL_STATUS_INCOMING;
1671         case CSD_CALL_STATUS_MO_ALERTING:
1672                 return CALL_STATUS_ALERTING;
1673         case CSD_CALL_STATUS_MT_ALERTING:
1674                 return CALL_STATUS_INCOMING;
1675         case CSD_CALL_STATUS_ANSWERED:
1676         case CSD_CALL_STATUS_ACTIVE:
1677         case CSD_CALL_STATUS_RECONNECT_PENDING:
1678         case CSD_CALL_STATUS_SWAP_INITIATED:
1679         case CSD_CALL_STATUS_HOLD_INITIATED:
1680                 return CALL_STATUS_ACTIVE;
1681         case CSD_CALL_STATUS_RETRIEVE_INITIATED:
1682         case CSD_CALL_STATUS_HOLD:
1683                 return CALL_STATUS_HELD;
1684         default:
1685                 return -1;
1686         }
1687 }
1688
1689 void telephony_list_current_calls_req(void *telephony_device)
1690 {
1691         GSList *l;
1692         int i;
1693
1694         for (l = calls, i = 1; l != NULL; l = l->next, i++) {
1695                 struct csd_call *call = l->data;
1696                 int status, direction, multiparty;
1697
1698                 status = csd_status_to_hfp(call);
1699                 if (status < 0)
1700                         continue;
1701
1702                 direction = call->originating ?
1703                                 CALL_DIR_OUTGOING : CALL_DIR_INCOMING;
1704
1705                 multiparty = call->conference ?
1706                                 CALL_MULTIPARTY_YES : CALL_MULTIPARTY_NO;
1707
1708                 telephony_list_current_call_ind(i, direction, status,
1709                                                 CALL_MODE_VOICE, multiparty,
1710                                                 call->number,
1711                                                 number_type(call->number));
1712         }
1713
1714         telephony_list_current_calls_rsp(telephony_device, CME_ERROR_NONE);
1715
1716 }
1717
1718 void telephony_operator_selection_req(void *telephony_device)
1719 {
1720         telephony_operator_selection_ind(OPERATOR_MODE_AUTO,
1721                                 net.operator_name ? net.operator_name : "");
1722         telephony_operator_selection_rsp(telephony_device, CME_ERROR_NONE);
1723 }
1724
1725 void telephony_nr_and_ec_req(void *telephony_device, gboolean enable)
1726 {
1727         telephony_nr_and_ec_rsp(telephony_device, CME_ERROR_NONE);
1728 }
1729
1730 void telephony_voice_dial_req(void *telephony_device, gboolean enable)
1731 {
1732         telephony_voice_dial_rsp(telephony_device, CME_ERROR_NOT_SUPPORTED);
1733 }
1734
1735 void telephony_subscriber_number_req(void *telephony_device)
1736 {
1737         if (subscriber_number)
1738                 telephony_subscriber_number_ind(subscriber_number,
1739                                                 number_type(subscriber_number),
1740                                                 SUBSCRIBER_SERVICE_VOICE);
1741         telephony_subscriber_number_rsp(telephony_device, CME_ERROR_NONE);
1742 }
1743
1744 void telephony_list_phonebook_store(void *telephony_device)
1745 {
1746 /*
1747         For Blue & Me car kit we may have to add  the
1748         patch here(similar to the patch done in H1 and H2 )
1749 */
1750         telephony_list_phonebook_store_rsp(telephony_device,
1751                         PHONEBOOK_STORE_LIST, CME_ERROR_NONE);
1752 }
1753
1754 static int get_phonebook_count(const char *path, uint32_t *max_size,
1755                                                                                 uint32_t *used)
1756 {
1757         DBusConnection *conn;
1758         DBusMessageIter iter;
1759         DBusMessageIter value;
1760         DBusMessage *message, *reply;
1761         DBusError error;
1762
1763         conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
1764         if (!conn) {
1765                 DBG("Can't get on system bus");
1766                 return -1;
1767         }
1768
1769         message = dbus_message_new_method_call("org.bluez.pb_agent",
1770                                                                                 "/org/bluez/pb_agent",
1771                                                                                 "org.bluez.PbAgent",
1772                                                                                 "GetCallLogSize");
1773         if (!message) {
1774                 DBG("Can't allocate new message");
1775                 dbus_connection_unref(conn);
1776                 return -1;
1777         }
1778         dbus_message_iter_init_append(message, &iter);
1779         dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &path);
1780
1781         dbus_message_iter_close_container(&iter, &value);
1782         dbus_error_init(&error);
1783
1784         reply = dbus_connection_send_with_reply_and_block(conn,
1785                         message, -1, &error);
1786
1787         if (!reply) {
1788                 if (dbus_error_is_set(&error) == TRUE) {
1789                         DBG("%s", error.message);
1790                         dbus_error_free(&error);
1791                 } else {
1792                         DBG("Failed to get contacts");
1793                 }
1794                 dbus_message_unref(message);
1795                 dbus_connection_unref(conn);
1796                 return -1;
1797         }
1798
1799         if (!dbus_message_get_args(reply, &error,
1800                                 DBUS_TYPE_UINT32, used,
1801                                 DBUS_TYPE_INVALID)) {
1802                 DBG("Can't get reply arguments\n");
1803                 if (dbus_error_is_set(&error)) {
1804                         DBG("%s\n", error.message);
1805                         dbus_error_free(&error);
1806                 }
1807                 dbus_message_unref(reply);
1808                 dbus_message_unref(message);
1809                 dbus_connection_unref(conn);
1810                 return -1;
1811         }
1812
1813         if ((g_strcmp0(path, "SM") == 0) || (g_strcmp0(path, "ME") == 0)) {
1814                 *max_size = PHONEBOOK_COUNT_MAX;
1815
1816                 if (*used > PHONEBOOK_COUNT_MAX)
1817                         *used = PHONEBOOK_COUNT_MAX;
1818         }
1819         if ((g_strcmp0(path, "DC") == 0) || (g_strcmp0(path, "MC") == 0) ||
1820                         (g_strcmp0(path, "RC") == 0)) {
1821                 *max_size = CALL_LOG_COUNT_MAX;
1822
1823                 if (*used > CALL_LOG_COUNT_MAX)
1824                         *used = CALL_LOG_COUNT_MAX;
1825         }
1826
1827         dbus_message_unref(reply);
1828         dbus_message_unref(message);
1829         dbus_connection_unref(conn);
1830
1831         return 0;
1832 }
1833
1834 void telephony_read_phonebook_store(void *telephony_device)
1835 {
1836         if ('\0' != ag_pb_info.path[0]) {
1837 /*
1838         Check the phone path ag_pb_info.path[] to which path it was set.
1839         If the path is NULL then set to "SM" and get the max_size and used
1840         counts from the phonebook type through dbus call to pbap agent
1841 */
1842                 if (!get_phonebook_count(ag_pb_info.path, &ag_pb_info.max_size,
1843                                                 &ag_pb_info.used))
1844                         telephony_read_phonebook_store_rsp(telephony_device,
1845                                         ag_pb_info.path,
1846                                         ag_pb_info.max_size,
1847                                         ag_pb_info.used,
1848                                         CME_ERROR_NONE);
1849                 else
1850                         telephony_read_phonebook_store_rsp(telephony_device,
1851                                         ag_pb_info.path,
1852                                         ag_pb_info.max_size,
1853                                         ag_pb_info.used,
1854                                         CME_ERROR_AG_FAILURE);
1855         }
1856 }
1857
1858 void telephony_set_phonebook_store(void *telephony_device, const char *path)
1859 {
1860         if (NULL != path) {
1861                 DBG("set phonebook type to [%s]\n", path);
1862                 g_strlcpy(ag_pb_info.path, path, sizeof(ag_pb_info.path));
1863         }
1864 }
1865
1866 void telephony_read_phonebook_attributes(void *telephony_device)
1867 {
1868         uint32_t total_count = 0;
1869         uint32_t used_count = 0;
1870
1871         if ('\0' != ag_pb_info.path[0]) {
1872 /*
1873         Check the phone path ag_pb_info.path[] to which path it was set.
1874         If the path is NULL then set to "SM" and get the max_size and used
1875         counts from the phonebook type through dbus call to pbap agent
1876 */
1877                 telephony_read_phonebook_attributes_rsp(telephony_device,
1878                         ag_pb_info.max_size,    PHONEBOOK_NUMBER_MAX_LENGTH,
1879                         PHONEBOOK_NAME_MAX_LENGTH, CME_ERROR_NONE);
1880         }
1881 }
1882
1883 static int convert_utf8_gsm(uint8_t ascii, uint8_t utf_8, uint8_t *gsm)
1884 {
1885         uint32_t i = 0;
1886
1887         if (ascii == 0xC3) {
1888                 for (i = 0; i < GSM_UNI_MAX_C3 ; i++) {
1889                         if (gsm_unicode_C3[i].utf_8 == utf_8) {
1890                                 *gsm = gsm_unicode_C3[i].gsm;
1891                                 return 0;
1892                         }
1893                 }
1894         } else if (ascii == 0xCE) {
1895                 for (i = 0; i < GSM_UNI_MAX_CE ; i++) {
1896                         if (gsm_unicode_CE[i].utf_8 == utf_8) {
1897                                 *gsm = gsm_unicode_CE[i].gsm;
1898                                 return 0;
1899                         }
1900                 }
1901         }
1902 }
1903
1904 static void get_unicode_string(const char *name, char *unicodename)
1905 {
1906         if (NULL != name || NULL != unicodename) {
1907                 int len = strlen(name);
1908                 if (len > 0) {
1909                         int x = 0;
1910                         int y = 0;
1911                         if (len > PHONEBOOK_MAX_CHARACTER_LENGTH)
1912                                 len = PHONEBOOK_MAX_CHARACTER_LENGTH;
1913                         for (x = 0, y = 0 ; x < len ; x++, y++) {
1914                                 if (x < (len - 1)) {
1915                                         if (convert_utf8_gsm(name[x], name[x+1] ,
1916                                                 (uint8_t *)&unicodename[y])) {
1917                                                 x++;
1918                                                 continue;
1919                                         }
1920                                 }
1921
1922                                 if (name[x] == '_') {
1923                                          unicodename[y] = ' ';
1924                                          continue;
1925                                 }
1926
1927                                 unicodename[y] = name[x];
1928                         }
1929                 }
1930         }
1931         return;
1932 }
1933
1934 static int send_read_phonebook_resp(void *telephony_device, int32_t index,
1935                                         const char *name, const char *number)
1936 {
1937         gchar *msg = NULL;
1938         int ret = -1;
1939
1940         msg =  g_new0(gchar, PHONEBOOK_NAME_MAX_LENGTH +
1941                                 PHONEBOOK_NUMBER_MAX_LENGTH + PHONEBOOK_READ_RESP_LENGTH + 3);
1942
1943         if (NULL != msg) {
1944                 char nm[PHONEBOOK_NAME_MAX_LENGTH + 1] = {0,};
1945                 char nb[PHONEBOOK_NAME_MAX_LENGTH + 1] = {0,};
1946
1947                 get_unicode_string(name, nm);
1948                 get_unicode_string(number, nb);
1949
1950                 snprintf(msg, PHONEBOOK_NAME_MAX_LENGTH +
1951                         PHONEBOOK_NUMBER_MAX_LENGTH + PHONEBOOK_READ_RESP_LENGTH + 3,
1952                         "%d,\"%s\",0,\"%s\"", index, nb, nm);
1953
1954                 ret = telephony_read_phonebook_rsp(telephony_device, msg,
1955                                 CME_ERROR_NONE);
1956
1957                 g_free(msg);
1958         }
1959         return ret;
1960 }
1961
1962 static int get_phonebook_list(void *telephony_device, const char* path,
1963                                         int32_t start_index, int32_t end_index)
1964 {
1965         DBusConnection *conn;
1966         DBusMessage *message, *reply;
1967         DBusError error;
1968         DBusMessageIter iter, iter_struct, entry;
1969         int32_t idx = 0;
1970         if ((start_index > (int) ag_pb_info.max_size) || (start_index <= 0) ||
1971                         (start_index > PHONEBOOK_COUNT_MAX)) {
1972                 return -1;
1973         }
1974
1975         if (end_index > (int) ag_pb_info.max_size)
1976                 end_index = PHONEBOOK_COUNT_MAX ;
1977
1978         conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
1979         if (!conn) {
1980                 DBG("Can't get on system bus");
1981                 return -1;
1982         }
1983
1984         message = dbus_message_new_method_call("org.bluez.pb_agent",
1985                                                 "/org/bluez/pb_agent",
1986                                                 "org.bluez.PbAgent",
1987                                                 "GetPhonebookList");
1988         if (!message) {
1989                 DBG("Can't allocate new message");
1990                 return -1;
1991         }
1992         dbus_error_init(&error);
1993
1994         reply = dbus_connection_send_with_reply_and_block(conn,
1995                         message, -1, &error);
1996
1997         if (!reply) {
1998                 if (dbus_error_is_set(&error) == TRUE) {
1999                         DBG("%s", error.message);
2000                         dbus_error_free(&error);
2001                 } else {
2002                         DBG("Failed to get contacts");
2003                 }
2004                 return -1;
2005         }
2006
2007         dbus_message_iter_init(reply, &iter);
2008         dbus_message_iter_recurse(&iter, &iter_struct);
2009
2010         idx = start_index;
2011         while (dbus_message_iter_get_arg_type(&iter_struct) == DBUS_TYPE_STRUCT) {
2012                 const char *name = NULL;
2013                 const char *tel = NULL;
2014                 uint32_t handle = 0;
2015
2016                 dbus_message_iter_recurse(&iter_struct, &entry);
2017
2018                 dbus_message_iter_get_basic(&entry, &name);
2019                 dbus_message_iter_next(&entry);
2020                 dbus_message_iter_get_basic(&entry, &tel);
2021                 dbus_message_iter_next(&entry);
2022                 dbus_message_iter_get_basic(&entry, &handle);
2023
2024                 DBG("[%d] handle:%d name:%s tel:%s]\n", handle, name, tel);
2025
2026                 /*form the packet and sent to the remote headset*/
2027                 if (-1 == end_index) {
2028                         if (send_read_phonebook_resp(telephony_device,
2029                                         start_index, name, tel))
2030                                 DBG("send_read_phonebook_resp - ERROR\n");
2031                         break;
2032                 } else {
2033                         if (idx >= start_index || idx <= end_index) {
2034                                 if (send_read_phonebook_resp(telephony_device, idx, name, tel)) {
2035                                         DBG("send_read_phonebook_resp - ERROR\n");
2036                                         telephony_read_phonebook_rsp(telephony_device, NULL,
2037                                                         CME_ERROR_AG_FAILURE);
2038
2039                                         dbus_message_unref(message);
2040                                         dbus_message_unref(reply);
2041                                         dbus_connection_unref(conn);
2042
2043                                         return -1;
2044                                 }
2045                                 idx++;
2046                         }
2047                 }
2048                 dbus_message_iter_next(&iter_struct);
2049         }
2050
2051         telephony_read_phonebook_rsp(telephony_device, NULL, CME_ERROR_NONE);
2052
2053         dbus_message_unref(message);
2054         dbus_message_unref(reply);
2055         dbus_connection_unref(conn);
2056
2057         /*Process the List and send response*/
2058         return 0;
2059 }
2060
2061 static int get_call_log_list(void *telephony_device, char* path ,
2062                         int32_t start_index, int32_t end_index)
2063 {
2064         DBusConnection *conn;
2065         DBusMessage *message = NULL, *reply;
2066         DBusError error;
2067         DBusMessageIter iter, iter_struct, entry;
2068         int32_t idx = 0;
2069
2070         if ((start_index > (int) ag_pb_info.max_size) || (start_index <= 0) ||
2071                         (start_index > CALL_LOG_COUNT_MAX)) {
2072                 return -1;
2073         }
2074
2075         if (end_index > (int) ag_pb_info.max_size)
2076                 end_index = CALL_LOG_COUNT_MAX ;
2077
2078
2079         conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
2080         if (!conn) {
2081                 DBG("Can't get on system bus");
2082                 return -1;
2083         }
2084
2085         if (g_strcmp0(ag_pb_info.path, "DC") == 0) {
2086                 message = dbus_message_new_method_call("org.bluez.pb_agent",
2087                                                         "/org/bluez/pb_agent",
2088                                                         "org.bluez.PbAgent",
2089                                                         "GetOutgoingCallsList");
2090         } else if (g_strcmp0(ag_pb_info.path, "MC") == 0) {
2091                 message = dbus_message_new_method_call("org.bluez.pb_agent",
2092                                                         "/org/bluez/pb_agent",
2093                                                         "org.bluez.PbAgent",
2094                                                         "GetMissedCallsList");
2095         } else if (g_strcmp0(ag_pb_info.path, "RC") == 0) {
2096                 message = dbus_message_new_method_call("org.bluez.pb_agent",
2097                                                         "/org/bluez/pb_agent",
2098                                                         "org.bluez.PbAgent",
2099                                                         "GetIncomingCallsList");
2100         }
2101         if (!message) {
2102                 DBG("Can't allocate new message");
2103                 dbus_connection_unref(conn);
2104                 return -1;
2105         }
2106         dbus_error_init(&error);
2107
2108         reply = dbus_connection_send_with_reply_and_block(conn,
2109                         message, -1, &error);
2110
2111         if (!reply) {
2112                 if (dbus_error_is_set(&error) == TRUE) {
2113                         DBG("%s", error.message);
2114                         dbus_error_free(&error);
2115                 } else {
2116                         DBG("Failed to get contacts");
2117                 }
2118                 dbus_message_unref(message);
2119                 dbus_connection_unref(conn);
2120                 return -1;
2121         }
2122
2123         dbus_message_iter_init(reply, &iter);
2124         dbus_message_iter_recurse(&iter, &iter_struct);
2125
2126         idx = start_index;
2127         while (dbus_message_iter_get_arg_type(&iter_struct) == DBUS_TYPE_STRUCT) {
2128                 const char *name = NULL;
2129                 const char *tel = NULL;
2130                 uint32_t handle = 0;
2131
2132                 dbus_message_iter_recurse(&iter_struct, &entry);
2133
2134                 dbus_message_iter_get_basic(&entry, &name);
2135                 dbus_message_iter_next(&entry);
2136                 dbus_message_iter_get_basic(&entry, &tel);
2137                 dbus_message_iter_next(&entry);
2138                 dbus_message_iter_get_basic(&entry, &handle);
2139
2140                 DBG("[%d] handle:%d name:%s tel:%s]\n", handle, name, tel);
2141
2142                 /*form the packet and sent to the remote headset*/
2143                 if (-1 == end_index) {
2144                         if (send_read_phonebook_resp(telephony_device,
2145                                         start_index, name, tel))
2146                                 DBG("send_read_phonebook_resp - ERROR\n");
2147                         break;
2148                 } else {
2149                         if (idx >= start_index || idx <= end_index) {
2150                                 /* Need to form the time stamp pkt  also */
2151                                 if (send_read_phonebook_resp(telephony_device, idx, name, tel)) {
2152                                         DBG("send_read_phonebook_resp - ERROR\n");
2153                                         telephony_read_phonebook_rsp(telephony_device, NULL,
2154                                                         CME_ERROR_AG_FAILURE);
2155
2156                                         dbus_message_unref(message);
2157                                         dbus_message_unref(reply);
2158                                         dbus_connection_unref(conn);
2159
2160                                         return -1;
2161                                 }
2162                                 idx++;
2163                         }
2164                 }
2165                 dbus_message_iter_next(&iter_struct);
2166         }
2167
2168         telephony_read_phonebook_rsp(telephony_device, NULL, CME_ERROR_NONE);
2169
2170         dbus_message_unref(message);
2171         dbus_message_unref(reply);
2172         dbus_connection_unref(conn);
2173
2174         /*Process the List and send response*/
2175         return 0;
2176
2177 }
2178 void telephony_read_phonebook(void *telephony_device, const char *cmd)
2179 {
2180         char *ptr = 0;
2181
2182         if (NULL != cmd) {
2183                 int32_t start_index;
2184                 int32_t end_index;
2185                 ptr = (char *) strchr(cmd, (int32_t)',');
2186                 if (NULL == ptr) {
2187                         start_index = strtol(cmd, NULL, 0);
2188                         end_index = -1;
2189                         DBG("start_index = [%d] \n", start_index);
2190                 } else {
2191                         ptr++;
2192                         start_index = strtol(cmd, NULL, 0);
2193                         end_index = strtol(ptr, NULL, 0);
2194                         DBG("start_index = [%d], end_index = [%d] \n",
2195                                         start_index, end_index);
2196                 }
2197
2198                 if ((g_strcmp0(ag_pb_info.path, "SM") == 0) ||
2199                                 (g_strcmp0(ag_pb_info.path, "ME") == 0)) {
2200                         if (get_phonebook_list(telephony_device, ag_pb_info.path,
2201                                         start_index, end_index)) {
2202                                 telephony_read_phonebook_rsp(telephony_device, NULL,
2203                                         CME_ERROR_AG_FAILURE);
2204                                 return;
2205                         }
2206                 }
2207                 if ((g_strcmp0(ag_pb_info.path, "DC") == 0) ||
2208                                 (g_strcmp0(ag_pb_info.path, "MC") == 0) ||
2209                                 (g_strcmp0(ag_pb_info.path, "RC") == 0)) {
2210                         if (get_call_log_list(telephony_device, ag_pb_info.path,
2211                                         start_index, end_index)) {
2212                                 telephony_read_phonebook_rsp(telephony_device, NULL,
2213                                                 CME_ERROR_AG_FAILURE);
2214                                 return;
2215                         }
2216                 }
2217
2218 /*
2219         Using the start and end index get the contact list from the pbap agent and
2220         send the data to remote headset.
2221 */
2222         }
2223  }
2224
2225 void telephony_find_phonebook_entry_properties(void *telephony_device)
2226 {
2227         telephony_find_phonebook_entry_properties_rsp(telephony_device,
2228                         PHONEBOOK_NUMBER_MAX_LENGTH,
2229                         PHONEBOOK_NAME_MAX_LENGTH,
2230                         CME_ERROR_NONE);
2231
2232 }
2233
2234 void telephony_find_phonebook_entry(void *telephony_device, const char *cmd)
2235 {
2236 /*
2237         Get the contact that matches with the string "cmd" and send it back to the
2238         remote headset Need a dbus API to pbap agent that does the above operation
2239 */
2240
2241 }
2242 void telephony_get_preffered_store_capacity(void *telephony_device)
2243 {
2244         telephony_get_preffered_store_capacity_rsp(telephony_device,
2245                         PREFFERED_MESSAGE_STORAGE_MAX,
2246                         CME_ERROR_NONE);
2247 }
2248
2249 void telephony_list_preffered_store(void *telephony_device)
2250 {
2251         telephony_list_preffered_store_rsp(telephony_device,
2252                         PREFFERED_MESSAGE_STORAGE_LIST,
2253                         CME_ERROR_NONE);
2254 }
2255
2256 /*
2257 void telephony_set_preffered_store_capcity(void *telephony_device, const char *cmd)
2258 {
2259 }
2260 */
2261 void telephony_get_character_set(void *telephony_device)
2262 {
2263         telephony_supported_character_generic_rsp(telephony_device,
2264                         PHONEBOOK_CHARACTER_SET_SUPPORTED,
2265                         CME_ERROR_NONE);
2266
2267 }
2268
2269 void telephony_list_supported_character(void *telephony_device)
2270 {
2271         telephony_supported_character_generic_rsp(telephony_device,
2272                         PHONEBOOK_CHARACTER_SET_LIST,
2273                         CME_ERROR_NONE);
2274 }
2275
2276 /*
2277 void telephony_set_characterset(void *telephony_device, const char *cmd)
2278 {
2279 }
2280 */