Get sms parameter fix
[platform/core/telephony/tel-plugin-imc.git] / src / imc_call.c
1 /*
2  * tel-plugin-imc
3  *
4  * Copyright (c) 2013 Samsung Electronics Co. Ltd. All rights reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22
23 #include <glib.h>
24
25 #include <tcore.h>
26 #include <server.h>
27 #include <plugin.h>
28 #include <core_object.h>
29 #include <hal.h>
30 #include <queue.h>
31 #include <storage.h>
32 #include <at.h>
33 #include <vconf.h>
34 #include <co_call.h>
35
36 #include "imc_call.h"
37 #include "imc_common.h"
38
39 #define COMMA   0X2c
40 #define STATUS_INCOMING    4
41 #define STATUS_WAITING     5
42 #define STATUS_CONNECTED   7
43
44 #define find_call_object(co, call_id, call_obj) \
45         do { \
46                 call_obj = tcore_call_object_find_by_id(co, call_id); \
47                 if (!call_obj) { \
48                         err("unable to find call object"); \
49                         return; \
50                 } \
51         } while (0)
52
53 struct imc_set_volume_info {
54         guint next_index;
55         guint volume;
56 };
57
58 static gchar *xdrv_set_volume[] = {
59         "AT+XDRV=40,7,3,88",
60         "AT+XDRV=40,7,0,88",
61         "AT+XDRV=40,8,0,88",
62         "AT+XDRV=40,8,2,",
63         NULL
64 };
65
66 /*Forward Declarations*/
67 static void on_response_imc_call_default(TcorePending *p,
68         guint data_len, const void *data, void *user_data);
69
70 static TelReturn __call_list_get(CoreObject *co, gboolean flag);
71
72 static TelCallType __call_type(int type)
73 {
74         dbg("Entry");
75
76         switch (type) {
77         case 0:
78                 return TEL_CALL_TYPE_VOICE;
79
80         case 1:
81                 return TEL_CALL_TYPE_VIDEO;
82
83         default:
84                 err("invalid call type, returning default call type as voice");
85                 return TEL_CALL_TYPE_VOICE;
86         }
87 }
88
89 static TelCallState __call_state(int state)
90 {
91         dbg("Entry");
92
93         switch (state) {
94         case 0:
95                 return TEL_CALL_STATE_ACTIVE;
96
97         case 1:
98                 return TEL_CALL_STATE_HELD;
99
100         case 2:
101                 return TEL_CALL_STATE_DIALING;
102
103         case 3:
104                 return TEL_CALL_STATE_ALERT;
105
106         case 4:
107         case 5:
108                 return TEL_CALL_STATE_INCOMING;
109
110         default:
111                 return TEL_CALL_STATE_IDLE;
112         }
113 }
114
115 static void __call_branch_by_status(CoreObject *co, CallObject *call_obj,
116         TelCallState call_state)
117 {
118         unsigned int call_id;
119         TelCallType call_type;
120         TelCallState state;
121         TcoreNotification command = TCORE_NOTIFICATION_UNKNOWN;
122         dbg("Call State[%d]", call_state);
123
124         if (tcore_call_object_get_state(call_obj, &state) == FALSE) {
125                 err("unable to get call status");
126                 return;
127         }
128
129         if (call_state == state) {
130                 dbg("current call state and existing call state are same");
131                 return;
132         }
133
134         if (tcore_call_object_get_call_type(call_obj, &call_type) == FALSE) {
135                 err("unable to get call type");
136                 return;
137         }
138
139         if (tcore_call_object_get_id(call_obj, &call_id) == FALSE) {
140                 err("unable to get call id");
141                 return;
142         }
143
144         /* Set Status */
145         tcore_call_object_set_state(call_obj, call_state);
146
147         if (call_type == TEL_CALL_TYPE_VOICE) {
148                 /* voice call notification */
149                 switch (call_state) {
150                 case TEL_CALL_STATE_ACTIVE:
151                         command = TCORE_NOTIFICATION_CALL_STATUS_ACTIVE;
152                 break;
153
154                 case TEL_CALL_STATE_HELD:
155                         command = TCORE_NOTIFICATION_CALL_STATUS_HELD;
156                 break;
157
158                 case TEL_CALL_STATE_DIALING:
159                         command = TCORE_NOTIFICATION_CALL_STATUS_DIALING;
160                 break;
161
162                 case TEL_CALL_STATE_ALERT:
163                         command = TCORE_NOTIFICATION_CALL_STATUS_ALERT;
164                 break;
165
166                 case TEL_CALL_STATE_INCOMING:
167                 case TEL_CALL_STATE_WAITING: {
168                         TelCallIncomingInfo incoming = {0,};
169                         command = TCORE_NOTIFICATION_CALL_STATUS_INCOMING;
170                         incoming.call_id = call_id;
171                         tcore_call_object_get_cli_validity(call_obj, &incoming.cli_validity);
172                         tcore_call_object_get_number(call_obj, incoming.number);
173                         tcore_call_object_get_cni_validity(call_obj, &incoming.cni_validity);
174                         tcore_call_object_get_name(call_obj, incoming.name);
175                         tcore_call_object_get_mt_forward(call_obj, &incoming.forward);
176                         tcore_call_object_get_active_line(call_obj, &incoming.active_line);
177
178                         /* Send notification */
179                         tcore_object_send_notification(co, command,
180                                 sizeof(TelCallIncomingInfo), &incoming);
181                         return;
182                 }
183
184                 case TEL_CALL_STATE_IDLE: {
185                         TelCallStatusIdleNoti idle;
186                         command = TCORE_NOTIFICATION_CALL_STATUS_IDLE;
187                         idle.call_id = call_id;
188
189                         /* TODO - get proper call end cause. */
190                         idle.cause = TEL_CALL_END_CAUSE_NONE;
191
192                         /* Send notification */
193                         tcore_object_send_notification(co, command,
194                                 sizeof(TelCallStatusIdleNoti), &idle);
195
196                         /* Free Call object */
197                         tcore_call_object_free(co, call_obj);
198                         return;
199                 }
200                 }
201
202         }
203         else if (call_type == TEL_CALL_TYPE_VIDEO) {
204                 /* video call notification */
205                 switch (call_state) {
206                 case TEL_CALL_STATE_ACTIVE:
207                         command = TCORE_NOTIFICATION_VIDEO_CALL_STATUS_ACTIVE;
208                 break;
209
210                 case TEL_CALL_STATE_HELD:
211                         err("invalid state");
212                 break;
213
214                 case TEL_CALL_STATE_DIALING:
215                         command = TCORE_NOTIFICATION_VIDEO_CALL_STATUS_DIALING;
216                 break;
217
218                 case TEL_CALL_STATE_ALERT:
219                         command = TCORE_NOTIFICATION_VIDEO_CALL_STATUS_ALERT;
220                 break;
221
222                 case TEL_CALL_STATE_INCOMING:
223                 case TEL_CALL_STATE_WAITING:
224                         command = TCORE_NOTIFICATION_VIDEO_CALL_STATUS_INCOMING;
225                 break;
226
227                 case TEL_CALL_STATE_IDLE: {
228                         TelCallStatusIdleNoti idle;
229                         command = TCORE_NOTIFICATION_VIDEO_CALL_STATUS_IDLE;
230                         idle.call_id = call_id;
231
232                         /* TODO - get proper call end cause. */
233                         idle.cause = TEL_CALL_END_CAUSE_NONE;
234
235                         /* Send notification */
236                         tcore_object_send_notification(co, command,
237                                 sizeof(TelCallStatusIdleNoti), &idle);
238
239                         /* Free Call object */
240                         tcore_call_object_free(co, call_obj);
241                         return;
242                 }
243                 }
244         }
245         else {
246                 err("Unknown Call type: [%d]", call_type);
247         }
248
249         if (command != TCORE_NOTIFICATION_UNKNOWN)
250                 tcore_object_send_notification(co, command, sizeof(call_id), &call_id);
251 }
252
253 static void __handle_call_list_get(CoreObject *co, gboolean flag, void *data)
254 {
255         int call_id;
256         int direction;
257         int call_type;
258         int state;
259         int mpty;
260         int ton;
261         GSList *tokens = NULL;
262         char *resp = NULL;
263         char *line;
264         char *num = NULL;
265         int num_type;
266         char number[TEL_CALL_CALLING_NUMBER_LEN_MAX +1] = {0,};
267         GSList *lines = data;
268         CallObject *call_obj = NULL;
269
270          while (lines != NULL) {
271                 line = (char *)lines->data;
272                 /* point to next node */
273                 lines = lines->next;
274                 /* free previous tokens*/
275                 tcore_at_tok_free(tokens);
276
277                 tokens = tcore_at_tok_new(line);
278
279                 /* <id1> */
280                 resp = g_slist_nth_data(tokens, 0);
281                 if (NULL == resp) {
282                         err("Invalid call_id");
283                         continue;
284                 }
285                 call_id = atoi(resp);
286
287                 /* <dir> */
288                 resp = g_slist_nth_data(tokens, 1);
289                 if (NULL == resp) {
290                         err("Invalid direction");
291                         continue;
292                 }
293                 direction = (atoi(resp) == 0) ? 1 : 0;
294
295                 /* <stat> */
296                 resp = g_slist_nth_data(tokens, 2);
297                 if (NULL == resp) {
298                         err("Invalid state");
299                         continue;
300                 }
301                 state = __call_state(atoi(resp));
302
303                 /* <mode> */
304                 resp = g_slist_nth_data(tokens, 3);
305                 if (NULL == resp) {
306                         err("Invalid call_type");
307                         continue;
308                 }
309                 call_type = __call_type(atoi(resp));
310
311                 /* <mpty> */
312                 resp = g_slist_nth_data(tokens, 4);
313                 if (NULL == resp) {
314                         err("Invalid mpty");
315                         continue;
316                 }
317                 mpty = atoi(resp);
318
319                 /* <number> */
320                 resp = g_slist_nth_data(tokens, 5);
321                 if (NULL == resp) {
322                         err("Number is NULL");
323                 } else {
324                         /* Strike off double quotes */
325                         num = tcore_at_tok_extract(resp);
326                         dbg("Number: [%s]", num);
327
328                         /* <type> */
329                         resp = g_slist_nth_data(tokens, 6);
330                         if (!resp) {
331                                 err("Invalid num type");
332                         } else {
333                                 num_type = atoi(resp);
334                                 /* check number is international or national. */
335                                 ton = ((num_type) >> 4) & 0x07;
336                                 if (ton == 1 && num[0] != '+') {
337                                         /* international number */
338                                         number[0] = '+';
339                                         memcpy(&number[1], num, strlen(num));
340                                 } else {
341                                         memcpy(number, num, strlen(num));
342                                 }
343                         }
344                         g_free(num);
345                 }
346
347                 dbg("Call ID: [%d] Direction: [%s] Call Type: [%d] Multi-party: [%s] "
348                         "Number: [%s] TON: [%d] State: [%d]",
349                         call_id, (direction ? "Outgoing" : "Incoming"), call_type,
350                         (mpty ? "YES" : "NO"), number, ton, state);
351
352                 call_obj = tcore_call_object_find_by_id(co, call_id);
353                 if (NULL == call_obj) {
354                         call_obj = tcore_call_object_new(co, call_id);
355                         if (NULL == call_obj) {
356                                 err("unable to create call object");
357                                 continue;
358                         }
359                 }
360
361                 /* Set Call parameters */
362                 tcore_call_object_set_type(call_obj, call_type);
363                 tcore_call_object_set_direction(call_obj, direction);
364                 tcore_call_object_set_multiparty_state(call_obj, mpty);
365                 tcore_call_object_set_cli_info(call_obj, TEL_CALL_CLI_VALIDITY_VALID, number);
366                 tcore_call_object_set_active_line(call_obj, TEL_CALL_ACTIVE_LINE1);
367                 if (flag == TRUE)
368                         __call_branch_by_status(co, call_obj, state);
369                 else
370                         tcore_call_object_set_state(call_obj, state);
371         }
372 }
373
374 /* internal notification operation */
375 static void __on_notification_imc_call_incoming(CoreObject *co, unsigned int call_id,
376         void *user_data)
377 {
378         GSList *list = NULL;
379         CallObject *call_obj = NULL;
380         dbg("entry");
381
382         /* check call with incoming status already exist */
383         list = tcore_call_object_find_by_status(co, TEL_CALL_STATE_INCOMING);
384         if (list != NULL) {
385                 err("Incoming call already exist! Skip...");
386                 g_slist_free(list);
387                 return;
388         }
389
390         call_obj = tcore_call_object_find_by_id(co, call_id);
391         if (call_obj != NULL) {
392                 err("Call object for Call ID [%d] already exist! Skip...", call_id);
393                 return;
394         }
395
396         /* Create new Call object */
397         call_obj = tcore_call_object_new(co, (unsigned int)call_id);
398         if (NULL == call_obj) {
399                 err("Failed to create Call object");
400                 return;
401         }
402
403         /* Make request to get current Call list */
404         __call_list_get(co, TRUE);
405 }
406
407 static void __on_notification_imc_call_status(CoreObject *co, unsigned int call_id,
408         unsigned int call_state, void *user_data)
409 {
410         CallObject *call_obj = NULL;
411         TelCallState state;
412
413         state = __call_state(call_state);
414         dbg("state [%d]", state);
415
416         switch (state) {
417         case TEL_CALL_STATE_ACTIVE: {
418                 find_call_object(co, call_id, call_obj);
419                 /* Send notification to application */
420                 __call_branch_by_status(co, call_obj, state);
421         }
422         break;
423
424         case TEL_CALL_STATE_HELD: {
425                 find_call_object(co, call_id, call_obj);
426                 /* Send notification to application */
427                 __call_branch_by_status(co, call_obj, state);
428         }
429         break;
430
431         case TEL_CALL_STATE_DIALING: {
432                 call_obj = tcore_call_object_find_by_id(co, call_id);
433                 if (!call_obj) {
434                         call_obj = tcore_call_object_new(co, call_id);
435                         if (!call_obj) {
436                                 err("unable to create call object");
437                                 return;
438                         }
439                 }
440                 /* Make request to get current call list.Update CallObject with <number>
441                  * and send notification to application */
442                 __call_list_get(co, TRUE);
443         }
444         break;
445
446         case TEL_CALL_STATE_ALERT: {
447                 find_call_object(co, call_id, call_obj);
448                 /* Send notification to application */
449                 __call_branch_by_status(co, call_obj, TEL_CALL_STATE_ALERT);
450         }
451         break;
452
453         case TEL_CALL_STATE_IDLE: {
454                 find_call_object(co, call_id, call_obj);
455                 /* Send notification to application */
456                 __call_branch_by_status(co, call_obj, state);
457         }
458         break;
459
460         default:
461                 err("invalid call status");
462                 break;
463         }
464 }
465
466 /*internal response operation */
467 static void __on_response_imc_call_list_get(TcorePending *p, guint data_len, const void *data,
468         void *user_data)
469 {
470         const TcoreAtResponse *at_resp = data;
471         CoreObject *co = tcore_pending_ref_core_object(p);
472         ImcRespCbData *resp_cb_data = user_data;
473         GSList *lines = NULL;
474         TelCallResult result = TEL_CALL_RESULT_FAILURE; //TODO - CME error mapping required
475         gboolean *flag = IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data);
476         int count;
477         dbg("entry");
478
479         tcore_check_return_assert(co != NULL);
480         tcore_check_return_assert(resp_cb_data != NULL);
481
482         if (at_resp && at_resp->success) {
483                 if (NULL == at_resp->lines) {
484                         err("invalid response received");
485                         return;
486                 }
487
488                 lines = (GSList *) at_resp->lines;
489                 count = g_slist_length(lines);
490                 dbg("Total records : %d", count);
491                 if (0 == count) {
492                         err("Call count is zero");
493                         return;
494                 }
495                 result = TEL_CALL_RESULT_SUCCESS;
496                 dbg("RESPONSE OK");
497
498                 /* parse +CLCC notification parameter */
499                 __handle_call_list_get(co, *flag, lines);
500
501         } else {
502                 err("RESPONSE NOK");
503         }
504 }
505
506 /*internal request operation */
507 static TelReturn __send_call_request(CoreObject *co, TcoreObjectResponseCallback cb,
508         void *cb_data, gchar *at_cmd, gchar *func_name)
509 {
510         ImcRespCbData *resp_cb_data;
511         TelReturn ret;
512
513         /* Response callback data */
514         resp_cb_data = imc_create_resp_cb_data(cb, cb_data, func_name,
515                         strlen(func_name) + 1);
516
517         /* Send Request to modem */
518         ret = tcore_at_prepare_and_send_request(co,
519                 at_cmd, NULL,
520                 TCORE_AT_COMMAND_TYPE_NO_RESULT,
521                 NULL,
522                 on_response_imc_call_default, resp_cb_data,
523                 on_send_imc_request, NULL);
524         IMC_CHECK_REQUEST_RET(ret, resp_cb_data, func_name);
525
526         /* Free resources */
527         g_free(at_cmd);
528         return ret;
529 }
530
531  /*
532  * Operation -  Get current call list.
533  *
534  * Request -
535  * AT-Command: AT+CLCC
536  *
537  * Response -
538  * Success:
539  *[+CLCC: <id1>, <dir>, <stat>, <mode>,<mpty>[,<number>,<type>[,<alpha>[,<priority>]]]
540  *
541  * OK
542  * Failure:
543  * +CME ERROR: <error>
544  */
545 static TelReturn __call_list_get(CoreObject *co, gboolean flag)
546 {
547         ImcRespCbData *resp_cb_data;
548         TelReturn ret = TEL_RETURN_FAILURE;
549         dbg("Entry");
550
551         if (NULL == co) {
552                 err("Core Object is NULL");
553                 return ret;
554         }
555
556         /* Response callback data */
557         resp_cb_data = imc_create_resp_cb_data(NULL, NULL, &flag, sizeof(gboolean));
558
559         /* Send Request to modem */
560         ret = tcore_at_prepare_and_send_request(co,
561                 "AT+CLCC","+CLCC",
562                 TCORE_AT_COMMAND_TYPE_MULTILINE,
563                 NULL,
564                 __on_response_imc_call_list_get, resp_cb_data,
565                 on_send_imc_request, NULL);
566         IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Get current call list");
567
568         return ret;
569 }
570
571 /* Notification */
572
573 /*
574 * Operation -  call status notification from network.
575 * notification message format:
576 * +XCALLSTAT: <call_id><stat>
577 * where
578 * <call_id>
579 * indicates the call identification (GSM02.30 4.5.5.1)
580 * <stat>
581 * 0 active
582 * 1 hold
583 * 2 dialling (MO call)
584 * 3 alerting (MO call; ringing for the remote party)
585 * 4 ringing (MT call)
586 * 5 waiting (MT call)
587 * 6 disconnected
588 * 7 connected (indicates the completion of a call setup first time for MT and MO calls
589 *   this is reported in addition to state active)
590 */
591 static gboolean on_notification_imc_call_status(CoreObject *co, const void *data,
592         void *user_data)
593 {
594         GSList *tokens = NULL;
595         GSList *lines = NULL;
596         const char *line = NULL;
597         char *state = NULL, *call_handle = NULL;
598         unsigned int status, call_id;
599
600         dbg("Entry");
601
602         lines = (GSList *) data;
603         if (lines == NULL) {
604                 err("Invalid response received");
605                 return TRUE;
606         }
607         line = (char *) (lines->data);
608         tokens = tcore_at_tok_new(line);
609
610         call_handle = g_slist_nth_data(tokens, 0);
611         if (NULL == call_handle) {
612                 err("call id missing from %XCALLSTAT indication");
613                 goto OUT;
614         }
615         call_id = atoi(call_handle);
616         state = g_slist_nth_data(tokens, 1);
617         if (NULL == state) {
618                 err("call state is missing from %XCALLSTAT indication");
619                 goto OUT;
620         }
621         status = atoi(state);
622         dbg("call id[%d], status[%d]", call_id, status);
623
624         switch (status) {
625         case STATUS_INCOMING:
626         case STATUS_WAITING:
627                 __on_notification_imc_call_incoming(co, call_id, user_data);
628                 break;
629
630         case STATUS_CONNECTED:     /* ignore Connected state. */
631                 dbg("ignore connected state");
632                 break;
633
634         default:
635                 __on_notification_imc_call_status(co, call_id, status, user_data);
636                 break;
637         }
638 OUT:
639         // Free tokens
640         tcore_at_tok_free(tokens);
641         return TRUE;
642 }
643
644 /*
645  * Operation -  SS network initiated notification.
646  *
647  * notification message format:
648  * +CSSU: <code2>[<index> [,<number>,<type>]]
649  * <code2>
650  * (it is manufacturer specific, which of these codes are supported):
651  * 0 this is a forwarded call (MT call setup)
652  * 1 this is a CUG call (<index> present) (MT call setup)
653  * 2 call has been put on hold (during a voice call)
654  * 3 call has been retrieved (during a voice call)
655  * 4 multiparty call entered (during a voice call)
656  * 5 Call has been released - not a SS notification (during a voice call)
657  * 6 forward check SS message received (can be received whenever)
658  * 7 call is being connected (alerting) with the remote party in alerting state
659  *   in explicit call transfer operation
660  *   (during a voice call)
661  * 8 call has been connected with the other remote party in explicit call transfer
662  *   operation (during a voice call or MT call setup)
663  * 9 this is a deflected call (MT call setup)
664  * 10 additional incoming call forwarded
665  * <index>
666  * refer Closed user group +CCUG
667  * <number>
668  *  string type phone of format specified by <type>
669  * <type>
670  * type of address octet in integer format.
671  */
672 static gboolean on_notification_imc_call_ss_cssu_info(CoreObject *co, const void *event_data,
673         void *user_data)
674 {
675         GSList *tokens = NULL;
676         TcoreNotification command = TCORE_NOTIFICATION_UNKNOWN;
677         char *resp = NULL;
678         char *cmd = 0;
679         int index = 0;
680         int code2 = -1;
681         char *number = NULL;
682
683         dbg("entry");
684
685         if (1 != g_slist_length((GSList *) event_data)) {
686                 err("unsolicited msg but multiple line");
687                 return TRUE;
688         }
689
690         cmd = (char *) ((GSList *) event_data)->data;
691         dbg("ss notification message[%s]", cmd);
692
693         tokens = tcore_at_tok_new(cmd);
694
695         /* parse <code2> */
696         resp = g_slist_nth_data(tokens, 0);
697         if (NULL == resp) {
698                 err("Code2 is missing from +CSSU indication");
699                 tcore_at_tok_free(tokens);
700                 return TRUE;
701         }
702
703         code2 = atoi(resp);
704
705         /* parse [ <index>, <number> <type>] */
706         if ((resp = g_slist_nth_data(tokens, 1)))
707                 index = atoi(resp);
708
709         if ((resp = g_slist_nth_data(tokens, 2))) {
710                 /* Strike off double quotes */
711                 number = tcore_at_tok_extract(resp);
712         }
713
714         dbg("+CSSU: <code2> = %d <index> = %d <number> = %s ", code2, index, number);
715
716         /* <code2> - other values will be ignored */
717         switch (code2) {
718         case 0:
719                 command = TCORE_NOTIFICATION_CALL_INFO_MT_FORWARDED;
720                 break;
721         case 2:
722                 command = TCORE_NOTIFICATION_CALL_INFO_HELD;
723                 break;
724         case 3:
725                 command = TCORE_NOTIFICATION_CALL_INFO_ACTIVE;
726                 break;
727         case 4:
728                 command = TCORE_NOTIFICATION_CALL_INFO_JOINED;
729                 break;
730         case 7:
731         case 8:
732                 command = TCORE_NOTIFICATION_CALL_INFO_TRANSFERED;
733                 break;
734         case 9:
735                 command = TCORE_NOTIFICATION_CALL_INFO_MT_DEFLECTED;
736                 break;
737         default:
738                 dbg("Unsupported +CSSU notification : %d", code2);
739                 break;
740         }
741
742         if (command != TCORE_NOTIFICATION_UNKNOWN)
743                 tcore_object_send_notification(co, command, 0, NULL);
744         tcore_at_tok_free(tokens);
745         g_free(number);
746
747         return TRUE;
748 }
749
750 /*
751 * Operation -  SS network initiated notification.
752 * notification message format:
753 * +CSSI : <code1>[,<index>]
754 * where
755 * <code1>
756 * 0 unconditional call forwarding is active
757 * 1 some of the conditional call forwarding are active
758 * 2 call has been forwarded
759 * 3 call is waiting
760 * 4 this is a CUG call (also <index> present)
761 * 5 outgoing calls are barred
762 * 6 incoming calls are barred
763 * 7 CLIR suppression rejected
764 * 8 call has been deflected
765
766 * <index>
767 * refer Closed user group +CCUG.
768 */
769 static gboolean on_notification_imc_call_ss_cssi_info(CoreObject *co, const void *event_data,
770         void *user_data)
771 {
772         GSList *tokens = NULL;
773         TcoreNotification command = TCORE_NOTIFICATION_UNKNOWN;
774         char *resp = NULL;
775         char *cmd = 0;
776         int index = 0;
777         int code1 = -1;
778
779         dbg("entry");
780
781         if (1 != g_slist_length((GSList *) event_data)) {
782                 err("unsolicited msg but multiple line");
783                 return TRUE;
784         }
785         cmd = (char *) ((GSList *) event_data)->data;
786         dbg("ss notification message[%s]", cmd);
787
788         tokens = tcore_at_tok_new(cmd);
789         /* parse <code1> */
790         resp = g_slist_nth_data(tokens, 0);
791         if (NULL == resp) {
792                 err("<code1> is missing from %CSSI indication");
793                 tcore_at_tok_free(tokens);
794                 return TRUE;
795         }
796
797         code1 = atoi(resp);
798
799         /* parse [ <index>] */
800         if ((resp = g_slist_nth_data(tokens, 1)))
801                 index = atoi(resp);
802
803         dbg("+CSSI: <code1> = %d <index> = %d ", code1, index);
804
805         /* <code1> - other values will be ignored */
806         switch (code1) {
807         case 0:
808                 command = TCORE_NOTIFICATION_CALL_INFO_MO_FORWARD_UNCONDITIONAL;
809                 break;
810         case 1:
811                 command = TCORE_NOTIFICATION_CALL_INFO_MO_FORWARD_CONDITIONAL;
812                 break;
813         case 2:
814                 command = TCORE_NOTIFICATION_CALL_INFO_MO_FORWARDED;
815                 break;
816         case 3:
817                 command = TCORE_NOTIFICATION_CALL_INFO_MO_WAITING;
818                 break;
819         case 5:
820                 command = TCORE_NOTIFICATION_CALL_INFO_MO_BARRED_OUTGOING;
821                 break;
822         case 6:
823                 command = TCORE_NOTIFICATION_CALL_INFO_MO_BARRED_INCOMING;
824                 break;
825         case 8:
826                 command  = TCORE_NOTIFICATION_CALL_INFO_MO_DEFLECTED;
827                 break;
828         default:
829                 dbg("Unsupported +CSSI notification : %d", code1);
830                 break;
831         }
832
833         if (command != TCORE_NOTIFICATION_UNKNOWN)
834                 tcore_object_send_notification(co, command, 0, NULL);
835         tcore_at_tok_free(tokens);
836
837         return TRUE;
838 }
839
840 static gboolean on_notification_imc_call_clip_info(CoreObject *co, const void *data,
841         void *user_data)
842 {
843         dbg("entry");
844         /* TODO - handle +CLIP notification*/
845         return TRUE;
846 }
847
848 /* Response */
849 static void on_response_imc_call_default(TcorePending *p,
850         guint data_len, const void *data, void *user_data)
851 {
852         const TcoreAtResponse *at_resp = data;
853         CoreObject *co = tcore_pending_ref_core_object(p);
854         ImcRespCbData *resp_cb_data = user_data;
855
856         TelCallResult result = TEL_CALL_RESULT_FAILURE;
857         dbg("entry");
858
859         tcore_check_return_assert(co != NULL);
860         tcore_check_return_assert(resp_cb_data != NULL);
861
862         if (at_resp && at_resp->success) {
863                 result = TEL_CALL_RESULT_SUCCESS;
864         } else {
865                 if(at_resp){
866                         err("ERROR[%s]", at_resp->final_response);
867
868                         if(at_resp->lines)
869                                 err("CME error[%s]", at_resp->lines->data);
870                 }
871                 /*
872                  * TODO - need to map CME error and final
873                  * response error to TelCallResult
874                  */
875         }
876
877         dbg("%s: [%s]", IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data),
878                  (result == TEL_CALL_RESULT_SUCCESS ? "SUCCESS" : "FAIL"));
879
880         /* Invoke callback */
881         if (resp_cb_data->cb)
882                 resp_cb_data->cb(co, (gint)result, NULL, resp_cb_data->cb_data);
883
884         /* Free callback data */
885         imc_destroy_resp_cb_data(resp_cb_data);
886 }
887
888 static void on_response_imc_call_set_volume_info(TcorePending *p,
889         guint data_len, const void *data, void *user_data)
890 {
891         const TcoreAtResponse *at_resp = data;
892         CoreObject *co = tcore_pending_ref_core_object(p);
893         ImcRespCbData *resp_cb_data = user_data;
894         GSList *tokens = NULL;
895         GSList *line = NULL;
896         char *resp_str = NULL;
897         gboolean error;
898
899         /* TODO: XDRV error mapping required */
900         TelCallResult result = TEL_CALL_RESULT_FAILURE;
901         dbg("Enter");
902
903         tcore_check_return_assert(co != NULL);
904         tcore_check_return_assert(resp_cb_data != NULL);
905
906         if (at_resp && at_resp->success) {
907                 line = at_resp->lines;
908                 tokens = tcore_at_tok_new(line->data);
909
910                 if (!g_slist_nth_data(tokens, 0)) {
911                         err("group_id  missing");
912                         goto OUT;
913                 }
914
915                 if (!g_slist_nth_data(tokens, 1)) {
916                         err(" function_id  missing");
917                         goto OUT;
918                 }
919
920                 resp_str = g_slist_nth_data(tokens, 2);
921                 if (!resp_str) {
922                         err("xdrv result missing");
923                         goto OUT;
924                 } else {
925                         struct imc_set_volume_info *volume_info;
926                         gchar *vol = "";
927                         gchar *at_cmd;
928                         TelReturn ret;
929
930                         error = atoi(resp_str);
931                         if (error) {
932                                 err("RESPONSE NOK");
933                                 goto OUT;
934                         }
935
936                         /* Fetch volume_info from resp_cb_data */
937                         volume_info = (struct imc_set_volume_info *)
938                                         IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data);
939                         dbg("volume info index[%d]", volume_info->next_index);
940
941                         if (xdrv_set_volume[volume_info->next_index] == NULL) {
942                                 /*Processing of xdrv commands  completed */
943                                 dbg("RESPONSE OK");
944                                 result = TEL_CALL_RESULT_SUCCESS;
945                                 goto OUT;
946                         } else if (volume_info->next_index == 3) {
947                                 switch ((volume_info->volume) / 10) {
948                                 case 0 :
949                                         vol = "0";
950                                 break;
951                                 case 1 :
952                                         vol = "40";
953                                 break;
954                                 case 2 :
955                                         vol = "46";
956                                 break;
957                                 case 3 :
958                                         vol = "52";
959                                 break;
960                                 case 4 :
961                                         vol = "58";
962                                 break;
963                                 case 5 :
964                                         vol = "64";
965                                 break;
966                                 case 6 :
967                                         vol = "70";
968                                 break;
969                                 case 7 :
970                                         vol = "76";
971                                 break;
972                                 case 8 :
973                                         vol = "82";
974                                 break;
975                                 case 9 :
976                                 default :
977                                         vol = "88";
978                                 }
979                         }
980
981                         at_cmd = g_strdup_printf("%s%s",
982                                         xdrv_set_volume[volume_info->next_index], vol);
983
984                         /* Increment index to point to next xdrv command */
985                         volume_info->next_index += 1;
986
987                         /* Send Request to modem */
988                         ret = tcore_at_prepare_and_send_request(co,
989                                         at_cmd, "+XDRV",
990                                         TCORE_AT_COMMAND_TYPE_SINGLELINE,
991                                         NULL,
992                                         on_response_imc_call_set_volume_info,
993                                         resp_cb_data, on_send_imc_request, NULL);
994                         IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "imc_call_set_volume_info");
995                         g_free(at_cmd);
996
997                         return;
998                 }
999         }
1000
1001 OUT :
1002         dbg("Set Volume Info: [%s]",
1003                         (result == TEL_CALL_RESULT_SUCCESS ? "SUCCESS" : "FAIL"));
1004
1005         /* Invoke callback */
1006         if (resp_cb_data->cb)
1007                 resp_cb_data->cb(co, (gint)result, NULL, resp_cb_data->cb_data);
1008
1009         imc_destroy_resp_cb_data(resp_cb_data);
1010         tcore_at_tok_free(tokens);
1011 }
1012
1013 static void on_response_imc_call_set_sound_path(TcorePending *p,
1014         guint data_len, const void *data, void *user_data)
1015 {
1016         const TcoreAtResponse *at_resp = data;
1017         CoreObject *co = tcore_pending_ref_core_object(p);
1018         ImcRespCbData *resp_cb_data = user_data;
1019         GSList *tokens = NULL;
1020         GSList *line = NULL;
1021         char *resp_str = NULL;
1022         gboolean error;
1023         gint xdrv_func_id = -1;
1024
1025         TelCallResult result = TEL_CALL_RESULT_FAILURE;  // TODO: XDRV error mapping is required
1026         dbg("Enter");
1027
1028         tcore_check_return_assert(co != NULL);
1029         tcore_check_return_assert(resp_cb_data != NULL);
1030
1031         if (at_resp && at_resp->success) {
1032                 line = at_resp->lines;
1033                 tokens = tcore_at_tok_new(line->data);
1034                 if (!g_slist_nth_data(tokens, 0)) {
1035                         err("group_id  missing");
1036                         goto OUT;
1037                 }
1038
1039                 if (!(resp_str = g_slist_nth_data(tokens, 1))) {
1040                         err("function_id  missing");
1041                         goto OUT;
1042                 }
1043                 xdrv_func_id = atoi(resp_str);
1044
1045                 if (!(resp_str = g_slist_nth_data(tokens, 2))) {
1046                         err("RESPONSE NOK");
1047                         goto OUT;
1048                 }
1049                 error = atoi(resp_str);
1050                 if (error) {
1051                         err("RESPONSE NOK");
1052                         goto OUT;
1053                 }
1054
1055                 if (xdrv_func_id == 4) {
1056                         /* Send next command to configure destination device type */
1057                         gchar *at_cmd;
1058                         TelReturn ret;
1059                         gint *device_type = IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data);
1060
1061                         at_cmd = g_strdup_printf("AT+XDRV=40,5,2,0,0,0,0,0,1,0,1,0,%d",
1062                                                 *device_type);
1063
1064                         ret = tcore_at_prepare_and_send_request(co,
1065                                         at_cmd, "+XDRV",
1066                                         TCORE_AT_COMMAND_TYPE_SINGLELINE,
1067                                         NULL,
1068                                         on_response_imc_call_set_sound_path, resp_cb_data,
1069                                         on_send_imc_request, NULL);
1070                         IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "imc_call_set_sound_path");
1071                         g_free(at_cmd);
1072
1073                         return;
1074                 }
1075                 dbg("RESPONSE OK");
1076                 result = TEL_CALL_RESULT_SUCCESS;
1077         }
1078
1079 OUT :
1080         dbg("Set Sound Path: [%s]",
1081                         (result == TEL_CALL_RESULT_SUCCESS ? "SUCCESS" : "FAIL"));
1082
1083         tcore_at_tok_free(tokens);
1084
1085         /* Invoke callback */
1086         if (resp_cb_data->cb)
1087                 resp_cb_data->cb(co, (gint)result, NULL, resp_cb_data->cb_data);
1088
1089         imc_destroy_resp_cb_data(resp_cb_data);
1090 }
1091
1092 static void on_response_set_sound_path(TcorePending *p, guint data_len,
1093                                         const void *data, void *user_data)
1094 {
1095         const TcoreAtResponse *at_resp = data;
1096         ImcRespCbData *resp_cb_data = user_data;
1097         TelCallResult result = TEL_CALL_RESULT_FAILURE;
1098         CoreObject *co_call = tcore_pending_ref_core_object(p);
1099
1100         if (at_resp && at_resp->success)
1101                         result = TEL_CALL_RESULT_SUCCESS;
1102
1103         if(resp_cb_data->cb)
1104                 resp_cb_data->cb(co_call, (gint)result, NULL, resp_cb_data->cb_data);
1105
1106         imc_destroy_resp_cb_data(resp_cb_data);
1107 }
1108
1109 static void on_response_imc_call_set_mute(TcorePending *p, guint data_len,
1110         const void *data, void *user_data)
1111 {
1112         const TcoreAtResponse *at_resp = data;
1113         CoreObject *co = tcore_pending_ref_core_object(p);
1114         ImcRespCbData *resp_cb_data = user_data;
1115         GSList *tokens = NULL;
1116         const char *line = NULL;
1117         char *resp_str = NULL;
1118         gboolean error;
1119
1120         TelCallResult result = TEL_CALL_RESULT_FAILURE;  // TODO: XDRV error mapping is required
1121         dbg("Enter");
1122
1123         tcore_check_return_assert(co != NULL);
1124         tcore_check_return_assert(resp_cb_data != NULL);
1125
1126         if (at_resp && at_resp->success) {
1127                 line = (((GSList *)at_resp->lines)->data);
1128                 tokens = tcore_at_tok_new(line);
1129
1130                 resp_str = g_slist_nth_data(tokens, 0);
1131                 if (!g_slist_nth_data(tokens, 0)) {
1132                         err("group_id  missing");
1133                         goto OUT;
1134                 }
1135
1136                 if (!g_slist_nth_data(tokens, 1)) {
1137                         err("function_id  missing");
1138                         goto OUT;
1139                 }
1140
1141                 resp_str = g_slist_nth_data(tokens, 2);
1142                 if (!(resp_str = g_slist_nth_data(tokens, 1))) {
1143                         err("xdrv_result missing");
1144                         goto OUT;
1145                 }
1146                 error = atoi(resp_str);
1147                 if (!error) {
1148                         err(" RESPONSE NOK [%d]", error);
1149                         goto OUT;
1150                 }
1151                 result = TEL_CALL_RESULT_SUCCESS;
1152         }
1153
1154 OUT :
1155         dbg("Set Mute: [%s]",
1156                         (result == TEL_CALL_RESULT_SUCCESS ? "SUCCESS" : "FAIL"));
1157         tcore_at_tok_free(tokens);
1158
1159         /* Invoke callback */
1160         if (resp_cb_data->cb)
1161                 resp_cb_data->cb(co, (gint)result, NULL, resp_cb_data->cb_data);
1162
1163         imc_destroy_resp_cb_data(resp_cb_data);
1164 }
1165
1166
1167  /* Request */
1168  /*
1169  * Operation - dial
1170  *
1171  * Request -
1172  * AT-Command: ATD <num> [I] [G] [;]
1173  * <num> - dialed number
1174  * [I][i] - CLI presentation(supression or invocation)
1175  * [G] - control the CUG supplementary service information for this call.
1176  *
1177  * Response -
1178  * Success:
1179  * OK or CONNECT
1180  * Failure:
1181  * "ERROR"
1182  * "NO ANSWER"
1183  * "NO CARRIER"
1184  * "BUSY"
1185  * "NO DIALTONE"
1186  * +CME ERROR: <error>
1187  */
1188 static TelReturn imc_call_dial(CoreObject *co, const TelCallDial *dial_info,
1189                 TcoreObjectResponseCallback cb, void *cb_data)
1190 {
1191         gchar *at_cmd;
1192         const gchar *clir;
1193         gchar *num;
1194
1195         dbg("entry");
1196
1197         if (dial_info->call_type == TEL_CALL_TYPE_VIDEO) {
1198                 err("Video call is not supported in imc modem");
1199                  return TEL_RETURN_OPERATION_NOT_SUPPORTED;
1200         }
1201
1202         if (!strncmp(dial_info->number, "*31#", 4)) {
1203                 dbg("clir suppression");
1204                 clir = "i";
1205                 num = (gchar *)&(dial_info->number[4]);
1206         } else if (!strncmp(dial_info->number, "#31#", 4)) {
1207                 dbg("clir invocation");
1208                 clir = "I";
1209                 num = (gchar *)&(dial_info->number[4]);
1210         } else {
1211                 int cli = 0;
1212
1213                 dbg("no clir string in number");
1214
1215                 /* it will be removed when setting application use tapi_ss_set_cli()
1216                  * instead of his own vconfkey. (0 : By network, 1 : Show, 2 : Hide)
1217                  */
1218                 vconf_get_int("db/ciss/show_my_number", &cli);
1219                 if (cli == 2){
1220                         dbg("clir invocation from setting application");
1221                         clir = "I";
1222                 } else {
1223                         dbg("set clir state to default");
1224                         clir = "";
1225                 }
1226                 num = (gchar *)dial_info->number;
1227         }
1228
1229         /* AT-Command */
1230         at_cmd = g_strdup_printf("ATD%s%s;", num, clir);
1231         dbg(" at command : %s", at_cmd);
1232
1233         return __send_call_request(co, cb, cb_data, at_cmd, "imc_call_dial");
1234 }
1235
1236 /*
1237  * Operation - Answer/Reject/Replace/hold(current call) & accept incoming call.
1238  *
1239  * Request -
1240  *
1241  * 1. AT-Command: ATA
1242  * Response -
1243  * Success:
1244  * OK
1245  * Failure:
1246  * +CME ERROR: <error>
1247  *
1248  * 2. AT-Command: AT+CHLD=[<n>]
1249  * <n>
1250  * 0 - (deafult)release all held calls or set User Determined User Busy for a waiting/incoming
1251  * call; if both exists then only the waiting call will be rejected.
1252  * 1 -  release all active calls and accepts the other (held or waiting)
1253  * Note: In the scenario: An active call, a waiting call and held call, when the active call is
1254  * terminated, we will make the Waiting call as active.
1255  * 2 -  place all active calls (if exist) on hold and accepts the other call (held or waiting/in-coming).
1256  * If only one call exists which is active, place it on hold and if only held call exists make it active call.
1257  * Response -
1258  * Success:
1259  * OK
1260  * Failure:
1261  * +CME ERROR: <error>
1262  * For more informatiion refer 3GPP TS 27.007.
1263  */
1264 static TelReturn imc_call_answer(CoreObject *co, TelCallAnswerType ans_type,
1265         TcoreObjectResponseCallback cb, void *cb_data)
1266 {
1267         gchar *at_cmd;
1268         dbg("entry");
1269
1270         if (ans_type == TEL_CALL_ANSWER_ACCEPT) {
1271                 /* AT-Command */
1272                 at_cmd = g_strdup_printf("%s", "ATA");
1273         }else if (ans_type == TEL_CALL_ANSWER_REJECT) {
1274                 /* AT-Command */
1275                 at_cmd = g_strdup_printf("%s", "AT+CHLD=0");
1276         } else if (ans_type == TEL_CALL_ANSWER_REPLACE) {
1277                 /* AT-Command */
1278                 at_cmd = g_strdup_printf("%s", "AT+CHLD=1");
1279         } else if (ans_type == TEL_CALL_ANSWER_HOLD_AND_ACCEPT) {
1280                 /* AT-Command */
1281                 at_cmd = g_strdup_printf("%s", "AT+CHLD=2");
1282         }else {
1283                 err("Unsupported call answer type");
1284                 return TEL_RETURN_FAILURE;
1285         }
1286
1287         dbg("at command : %s", at_cmd);
1288
1289         return __send_call_request(co, cb, cb_data, at_cmd, "imc_call_answer");
1290 }
1291
1292 /*
1293  * Operation - release all calls/release specific call/release all active
1294  * call/release all held calls.
1295  *
1296  * Request -
1297  * 1. AT-Command: AT+CHLD=[<n>]
1298  * <n>
1299  * 0  - (defualt)release all held calls or set User Determined User -
1300  *       Busy for a waiting/incoming.
1301  * call; if both exists then only the waiting call will be rejected.
1302  * 1  - release all active calls and accepts the other (held or waiting).
1303  * 1x - release a specific call (x specific call number as indicated by call id).
1304  * 8  - release all calls.
1305  * Response -
1306  * Success:
1307  * OK
1308  * Failure:
1309  * +CME ERROR: <error>
1310  */
1311 static TelReturn imc_call_end(CoreObject *co, const TelCallEnd *end_info,
1312         TcoreObjectResponseCallback cb, void *cb_data)
1313 {
1314         gchar *at_cmd;
1315         dbg("entry");
1316
1317         if (end_info->end_type == TEL_CALL_END_ALL) {
1318                 /* AT-Command */
1319                 at_cmd = g_strdup_printf("%s", "AT+CHLD=8");
1320         }else if (end_info->end_type == TEL_CALL_END) {
1321                 /* AT-Command */
1322                 at_cmd = g_strdup_printf("%s%d", "AT+CHLD=1",end_info->call_id);
1323         } else if (end_info->end_type == TEL_CALL_END_ACTIVE_ALL) {
1324                 /* AT-Command */
1325                 at_cmd = g_strdup_printf("%s", "AT+CHLD=1");
1326         } else if (end_info->end_type == TEL_CALL_END_HOLD_ALL) {
1327                 /* AT-Command */
1328                 at_cmd = g_strdup_printf("%s", "AT+CHLD=0");
1329         }else {
1330                 err("Unsupported call end type");
1331                 return TEL_RETURN_FAILURE;
1332         }
1333
1334         dbg("at command : %s", at_cmd);
1335
1336         return __send_call_request(co, cb, cb_data, at_cmd, "imc_call_end");
1337 }
1338
1339 /*
1340  * Operation - send dtmf.
1341  *
1342  * Request -
1343  * 1. AT-Command: AT+VTS=<DTMF>,{<DTMF>,<duration>}.
1344  * where
1345  * <DTMF>:
1346  * is a single ASCII character in the set 0-9, #, *, A-D. Even it will support string DTMF.
1347  * <duration>:
1348  * integer in range 0-255, meaning 1/10(10 millisec) seconds multiples. The string parameter
1349  * of the command consists of combinations of the following separated by commas:
1350  * NOTE : There is a limit of 50 dtmf tones can be requested through a single VTS command.
1351  * Response -
1352  * Success:
1353  * OK
1354  * Failure:
1355  * +CME ERROR: <error>
1356  */
1357 static TelReturn imc_call_send_dtmf(CoreObject *co, const char *dtmf_str,
1358         TcoreObjectResponseCallback cb,  void *cb_data)
1359 {
1360         gchar *at_cmd;
1361         char *tmp_dtmf = NULL, *dtmf;
1362         unsigned int count;
1363
1364         dbg("entry");
1365
1366         //(void) _set_dtmf_tone_duration(o, dup);
1367
1368         /* DTMF digits + comma for each dtmf digit */
1369         tmp_dtmf = tcore_malloc0((strlen(dtmf_str) * 2) + 1);
1370         tcore_check_return_value_assert(tmp_dtmf != NULL, TEL_RETURN_FAILURE);
1371         /* Save initial pointer */
1372         dtmf = tmp_dtmf;
1373
1374         for (count = 0; count < strlen(dtmf_str); count++) {
1375                 *tmp_dtmf = dtmf_str[count];
1376                 tmp_dtmf++;
1377
1378                 *tmp_dtmf = COMMA;
1379                 tmp_dtmf++;
1380         }
1381
1382         /* last digit is having COMMA , overwrite it with '\0'*/
1383         *(--tmp_dtmf) = '\0';
1384
1385         /* (AT+VTS = <d1>,<d2>,<d3>,<d4>,<d5>,<d6>, ..... <d32> */
1386         at_cmd = g_strdup_printf("AT+VTS=%s", dtmf);
1387         dbg("at command : %s", at_cmd);
1388
1389         tcore_free(dtmf);
1390
1391         return __send_call_request(co, cb, cb_data, at_cmd, "imc_call_send_dtmf");
1392 }
1393
1394 /*
1395  * Operation - call hold.
1396  *
1397  * Request -
1398  * 1. AT-Command: AT+CHLD=[<n>]
1399  * Where
1400  * <n>
1401  * 2 - place all active calls (if exist) on hold and accepts the other call (held or waiting/incoming).
1402  * If only one call exists which is active, place it on hold and if only held call exists
1403  * make it active call
1404  * Response -
1405  * Success:
1406  * OK
1407  * Failure:
1408  * +CME ERROR: <error>
1409  */
1410 static TelReturn imc_call_hold(CoreObject *co, TcoreObjectResponseCallback cb,
1411         void *cb_data)
1412
1413 {
1414         gchar *at_cmd;
1415         dbg("entry");
1416
1417         at_cmd = g_strdup_printf("%s", "AT+CHLD=2");
1418         dbg("at command : %s", at_cmd);
1419
1420         return __send_call_request(co, cb, cb_data, at_cmd, "imc_call_hold");
1421 }
1422
1423 /*
1424  * Operation - call active.
1425  *
1426  * Request -
1427  * 1. AT-Command: AT+CHLD=[<n>]
1428  * Where
1429  * <n>
1430  * 2 - place all active calls (if exist) on hold and accepts the other call (held or waiting/incoming).
1431  * If only one call exists which is active, place it on hold and if only held call exists
1432  * make it active call
1433  * Response -
1434  * Success:
1435  * OK
1436  * Failure:
1437  * +CME ERROR: <error>
1438  */
1439 static TelReturn imc_call_active(CoreObject *co, TcoreObjectResponseCallback cb,
1440         void *cb_data)
1441 {
1442         gchar *at_cmd;
1443         dbg("entry");
1444
1445         at_cmd = g_strdup_printf("%s", "AT+CHLD=2");
1446         dbg("at command : %s", at_cmd);
1447
1448         return __send_call_request(co, cb, cb_data, at_cmd, "imc_call_active");
1449 }
1450
1451 /*
1452  * Operation - call swap.
1453  *
1454  * Request -
1455  * 1. AT-Command: AT+CHLD=[<n>]
1456  * Where
1457  * <n>
1458  * 2 - place all active calls (if exist) on hold and accepts the other call (held or waiting/incoming).
1459  * If only one call exists which is active, place it on hold and if only held call exists
1460  * make it active call
1461  * Response -
1462  * Success:
1463  * OK
1464  * Failure:
1465  * +CME ERROR: <error>
1466  */
1467 static TelReturn imc_call_swap(CoreObject *co, TcoreObjectResponseCallback cb,
1468         void *cb_data)
1469 {
1470         gchar *at_cmd;
1471         dbg("entry");
1472
1473         at_cmd = g_strdup_printf("%s", "AT+CHLD=2");
1474         dbg("at command : %s", at_cmd);
1475
1476         return __send_call_request(co, cb, cb_data, at_cmd, "imc_call_swap");
1477 }
1478
1479 /*
1480  * Operation - call join.
1481  *
1482  * Request -
1483  * 1. AT-Command: AT+CHLD=[<n>]
1484  * Where
1485  * <n>
1486  * 3 - adds a held call to the conversation
1487  * Response -
1488  * Success:
1489  * OK
1490  * Failure:
1491  * +CME ERROR: <error>
1492  */
1493 static TelReturn imc_call_join(CoreObject *co, TcoreObjectResponseCallback cb,
1494         void *cb_data)
1495 {
1496         gchar *at_cmd;
1497         dbg("entry");
1498
1499         at_cmd = g_strdup_printf("%s", "AT+CHLD=3");
1500         dbg("at command : %s", at_cmd);
1501
1502         return __send_call_request(co, cb, cb_data, at_cmd, "imc_call_join");
1503 }
1504
1505 /*
1506  * Operation - call split.
1507  *
1508  * Request -
1509  * 1. AT-Command: AT+CHLD=[<n>]
1510  * Where
1511  * <n>
1512  * 2x - place all active calls on hold except call x with which communication is supported
1513  * Response -
1514  * Success:
1515  * OK
1516  * Failure:
1517  * +CME ERROR: <error>
1518  */
1519 static TelReturn imc_call_split(CoreObject *co, unsigned int call_id,
1520         TcoreObjectResponseCallback cb, void *cb_data)
1521 {
1522         gchar *at_cmd;
1523         dbg("entry");
1524
1525         at_cmd = g_strdup_printf("%s%d", "AT+CHLD=2", call_id);
1526         dbg("at command : %s", at_cmd);
1527
1528         return __send_call_request(co, cb, cb_data, at_cmd, "imc_call_split");
1529 }
1530
1531 /*
1532  * Operation - call transfer.
1533  *
1534  * Request -
1535  * 1. AT-Command: AT+CHLD=[<n>]
1536  * Where
1537  * <n>
1538  * 4 connects the two calls and disconnects the subscriber from both calls (Explicit Call Transfer)
1539  * Response -
1540  * Success:
1541  * OK
1542  * Failure:
1543  * +CME ERROR: <error>
1544  */
1545 static TelReturn imc_call_transfer(CoreObject *co, TcoreObjectResponseCallback cb,
1546         void *cb_data)
1547 {
1548         gchar *at_cmd;
1549         dbg("entry");
1550
1551         at_cmd = g_strdup_printf("%s", "AT+CHLD=4");
1552         dbg("at command : %s", at_cmd);
1553
1554         return __send_call_request(co, cb, cb_data, at_cmd, "imc_call_transfer");
1555 }
1556
1557 /*
1558  * Operation - call deflect.
1559  *
1560  * Request -
1561  * 1. AT-Command: AT+CTFR= <number>[,<type>]
1562  * Where
1563  * number>
1564  * string type phone number
1565  * <type>
1566  * type of address octet in integer format. It is optional parameter.
1567  *
1568  * Response -
1569  * Success:
1570  * OK
1571  * Failure:
1572  * +CME ERROR: <error>
1573  */
1574 static TelReturn imc_call_deflect(CoreObject *co, const char *deflect_to,
1575         TcoreObjectResponseCallback cb, void *cb_data)
1576 {
1577         gchar *at_cmd;
1578         dbg("entry");
1579
1580         at_cmd = g_strdup_printf("AT+CTFR=%s", deflect_to);
1581         dbg("at command : %s", at_cmd);
1582
1583         return __send_call_request(co, cb, cb_data, at_cmd, "imc_call_deflect");
1584 }
1585
1586 static TelReturn imc_call_set_active_line(CoreObject *co, TelCallActiveLine active_line,
1587         TcoreObjectResponseCallback cb, void *cb_data)
1588 {
1589         dbg("entry");
1590
1591         dbg("exit");
1592         return TEL_RETURN_OPERATION_NOT_SUPPORTED;
1593 }
1594
1595 static TelReturn imc_call_get_active_line(CoreObject *co, TcoreObjectResponseCallback cb,
1596         void *cb_data)
1597 {
1598         dbg("entry");
1599
1600         dbg("exit");
1601         return TEL_RETURN_OPERATION_NOT_SUPPORTED;
1602 }
1603
1604 /*
1605  * Operation - Set voule info.
1606  *
1607  * Request -
1608  * AT-Command: AT+XDRV=<group_id>,<function_id>[,<param_n>]
1609  * The first command parameter defines the involved driver group.
1610  * The second command parameter defines a certain function in the selected driver group.
1611  * Other parameters are dependent on the first two parameters.
1612  * Nearly all parameters are integer values, also if they are represented by literals.
1613  * Only very few are strings or
1614  * hex data strings.
1615  *
1616  * Response -
1617  * +XDRV: <group_id>,<function_id>,<xdrv_result>[,<response_n>]
1618  * The first response parameter defines the involved driver group.
1619  * The second response parameter defines the current function in the selected driver group.
1620  * The third response parameter defines the xdrv_result of the operation.
1621  * Additional response parameters dependent on the first two parameters.
1622  */
1623 static TelReturn imc_call_set_volume_info(CoreObject *co, const TelCallVolumeInfo *volume_info,
1624         TcoreObjectResponseCallback cb, void *cb_data)
1625 {
1626         ImcRespCbData *resp_cb_data = NULL;
1627         gchar *at_cmd;
1628         TelReturn ret;
1629         struct imc_set_volume_info cb_volume_info;
1630
1631         dbg("entry");
1632
1633         cb_volume_info.next_index = 1;
1634         cb_volume_info.volume = volume_info->volume;
1635
1636         /* Response callback data */
1637         resp_cb_data = imc_create_resp_cb_data(cb, cb_data,
1638                                 &cb_volume_info, sizeof(struct imc_set_volume_info));
1639
1640         at_cmd = g_strdup_printf("%s", xdrv_set_volume[0]);
1641
1642         /* Send Request to modem */
1643         ret = tcore_at_prepare_and_send_request(co,
1644                         at_cmd, "+XDRV",
1645                         TCORE_AT_COMMAND_TYPE_SINGLELINE,
1646                         NULL,
1647                         on_response_imc_call_set_volume_info, resp_cb_data,
1648                         on_send_imc_request, NULL);
1649         IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "imc_call_set_volume_info");
1650
1651         g_free(at_cmd);
1652         return ret;
1653 }
1654
1655
1656 static TelReturn imc_call_get_volume_info(CoreObject *co, TelCallSoundDevice sound_device,
1657         TcoreObjectResponseCallback cb, void *cb_data)
1658 {
1659         dbg("Entry");
1660
1661         dbg("Exit");
1662         return TEL_RETURN_OPERATION_NOT_SUPPORTED;
1663 }
1664
1665 /*
1666  * Operation - Set sound path.
1667  *
1668  * Request -
1669  * AT-Command: AT+XDRV=<group_id>,<function_id>[,<param_n>]
1670  * The first command parameter defines the involved driver group.
1671  * The second command parameter defines a certain function in the selected driver group.
1672  * Other parameters are dependent on the first two parameters.
1673  * Nearly all parameters are integer values, also if they are represented by literals.
1674  * Only very few are strings or
1675  * hex data strings.
1676  *
1677  * Response -
1678  * +XDRV: <group_id>,<function_id>,<xdrv_result>[,<response_n>]
1679  * The first response parameter defines the involved driver group.
1680  * The second response parameter defines the current function in the selected driver group.
1681  * The third response parameter defines the xdrv_result of the operation.
1682  * Additional response parameters dependent on the first two parameters.
1683  */
1684
1685 static TelReturn imc_call_set_sound_path(CoreObject *co, const TelCallSoundPathInfo *sound_path_info,
1686         TcoreObjectResponseCallback cb, void *cb_data)
1687 {
1688         ImcRespCbData *resp_cb_data = NULL;
1689         TelReturn ret;
1690         gchar *at_cmd;
1691         gint device_type = -1;
1692         TcorePlugin *plugin = tcore_object_ref_plugin(co);
1693         const char *cp_name = tcore_server_get_cp_name_by_plugin(plugin);
1694
1695         dbg("audio device type - 0x%x", sound_path_info->path);
1696
1697         switch (sound_path_info->path) {
1698                 case TEL_SOUND_PATH_HANDSET:
1699                         device_type = 1;
1700                         break;
1701                 case TEL_SOUND_PATH_HEADSET:
1702                         device_type = 2;
1703                         break;
1704                 case TEL_SOUND_PATH_HEADSET_3_5PI:
1705                         device_type = 3;
1706                         break;
1707                 case TEL_SOUND_PATH_SPK_PHONE:
1708                         device_type = 4;
1709                         break;
1710                 case TEL_SOUND_PATH_HANDSFREE:
1711                         device_type = 5;
1712                         break;
1713                 case TEL_SOUND_PATH_HEADSET_HAC:
1714                         device_type = 6;
1715                         break;
1716                 case TEL_SOUND_PATH_BLUETOOTH:
1717                 case TEL_SOUND_PATH_STEREO_BLUETOOTH:
1718                         device_type = 7;
1719                         break;
1720                 case TEL_SOUND_PATH_BT_NSEC_OFF:
1721                 case TEL_SOUND_PATH_MIC1:
1722                 case TEL_SOUND_PATH_MIC2:
1723                 default:
1724                         dbg("unsupported device type");
1725                         return TEL_RETURN_INVALID_PARAMETER;
1726         }
1727
1728         if (g_str_has_prefix(cp_name, "imcmodem")) {
1729                 /* Response callback data */
1730                 resp_cb_data = imc_create_resp_cb_data(cb, cb_data, &device_type, sizeof(gint));
1731
1732                 at_cmd = g_strdup_printf("AT+XDRV=40,4,3,0,0,0,0,0,1,0,1,0,%d", device_type);
1733
1734                 ret = tcore_at_prepare_and_send_request(co,
1735                         at_cmd, "+XDRV",
1736                         TCORE_AT_COMMAND_TYPE_SINGLELINE,
1737                         NULL,
1738                         on_response_imc_call_set_sound_path, resp_cb_data,
1739                         on_send_imc_request, NULL);
1740                 IMC_CHECK_REQUEST_RET(ret, NULL, "imc_call_set_sound_path");
1741                 g_free(at_cmd);
1742         } else {
1743                 /* Response callback data */
1744                 resp_cb_data = imc_create_resp_cb_data(cb, cb_data, NULL, 0);
1745
1746                 /* Configure modem I2S1 to 8khz, mono, PCM if routing to bluetooth */
1747                 if (sound_path_info->path == TEL_SOUND_PATH_BLUETOOTH ||
1748                                 sound_path_info->path == TEL_SOUND_PATH_STEREO_BLUETOOTH) {
1749                         tcore_at_prepare_and_send_request(co,
1750                                         "AT+XDRV=40,4,3,0,1,0,0,0,0,0,0,0,21",
1751                                         NULL, TCORE_AT_COMMAND_TYPE_NO_RESULT,
1752                                         NULL, NULL, NULL, NULL, NULL);
1753
1754                         tcore_at_prepare_and_send_request(co,
1755                                         "AT+XDRV=40,5,2,0,1,0,0,0,0,0,0,0,22",
1756                                         NULL, TCORE_AT_COMMAND_TYPE_NO_RESULT,
1757                                         NULL, NULL, NULL, NULL, NULL);
1758                 } else {
1759                         tcore_at_prepare_and_send_request(co,
1760                                         "AT+XDRV=40,4,3,0,1,0,8,0,1,0,2,0,21",
1761                                         NULL, TCORE_AT_COMMAND_TYPE_NO_RESULT,
1762                                         NULL, NULL, NULL, NULL, NULL);
1763
1764                         tcore_at_prepare_and_send_request(co,
1765                                         "AT+XDRV=40,5,2,0,1,0,8,0,1,0,2,0,22",
1766                                         NULL, TCORE_AT_COMMAND_TYPE_NO_RESULT,
1767                                         NULL, NULL, NULL, NULL, NULL);
1768                 }
1769
1770                 /* Configure modem I2S2 and do the modem routing */
1771                 tcore_at_prepare_and_send_request(co,
1772                                 "AT+XDRV=40,4,4,0,0,0,8,0,1,0,2,0,21",
1773                                 NULL, TCORE_AT_COMMAND_TYPE_NO_RESULT,
1774                                 NULL, NULL, NULL, NULL, NULL);
1775
1776                 tcore_at_prepare_and_send_request(co,
1777                                 "AT+XDRV=40,5,3,0,0,0,8,0,1,0,2,0,22",
1778                                 NULL, TCORE_AT_COMMAND_TYPE_NO_RESULT,
1779                                 NULL, NULL, NULL, NULL, NULL);
1780
1781                 tcore_at_prepare_and_send_request(co, "AT+XDRV=40,6,0,4",
1782                                 NULL, TCORE_AT_COMMAND_TYPE_NO_RESULT,
1783                                 NULL, NULL, NULL, NULL, NULL);
1784
1785                 tcore_at_prepare_and_send_request(co, "AT+XDRV=40,6,3,0",
1786                                 NULL, TCORE_AT_COMMAND_TYPE_NO_RESULT,
1787                                 NULL, NULL, NULL, NULL, NULL);
1788
1789                 tcore_at_prepare_and_send_request(co, "AT+XDRV=40,6,4,2",
1790                                 NULL, TCORE_AT_COMMAND_TYPE_NO_RESULT,
1791                                 NULL, NULL, NULL, NULL, NULL);
1792
1793                 tcore_at_prepare_and_send_request(co, "AT+XDRV=40,6,5,2",
1794                                 NULL, TCORE_AT_COMMAND_TYPE_NO_RESULT,
1795                                 NULL, NULL, NULL, NULL, NULL);
1796
1797                 /* amc enable */
1798                 tcore_at_prepare_and_send_request(co, "AT+XDRV=40,2,4",
1799                                 NULL, TCORE_AT_COMMAND_TYPE_NO_RESULT,
1800                                 NULL, NULL, NULL, NULL, NULL);
1801
1802                 tcore_at_prepare_and_send_request(co, "AT+XDRV=40,2,3",
1803                                 NULL, TCORE_AT_COMMAND_TYPE_NO_RESULT,
1804                                 NULL, NULL, NULL, NULL, NULL);
1805
1806                 /* amc route: AMC_RADIO_RX => AMC_I2S1_TX */
1807                 ret = tcore_at_prepare_and_send_request(co, "AT+XDRV=40,6,0,2",
1808                                 "+XDRV", TCORE_AT_COMMAND_TYPE_SINGLELINE, NULL,
1809                                 on_response_set_sound_path, resp_cb_data, NULL, NULL);
1810
1811                 IMC_CHECK_REQUEST_RET(ret, NULL, "imc_call_set_sound_path");
1812         }
1813
1814         return ret;
1815 }
1816
1817 /*
1818  * Operation - Set/Unset mute status.
1819  *
1820  * Request -
1821  * AT-Command: AT+XDRV=<group_id>,<function_id>[,<param_n>]
1822  * The first command parameter defines the involved driver group.
1823  * The second command parameter defines a certain function in the selected driver group.
1824  * Other parameters are dependent on the first two parameters.
1825  * Nearly all parameters are integer values, also if they are represented by literals.
1826  * Only very few are strings or
1827  * hex data strings.
1828  *
1829  * Response -
1830  * +XDRV: <group_id>,<function_id>,<xdrv_result>[,<response_n>]
1831  * The first response parameter defines the involved driver group.
1832  * The second response parameter defines the current function in the selected driver group.
1833  * The third response parameter defines the xdrv_result of the operation.
1834  * Additional response parameters dependent on the first two parameters.
1835  */
1836 static TelReturn imc_call_set_mute(CoreObject *co, gboolean mute, TcoreObjectResponseCallback cb,
1837         void *cb_data)
1838 {
1839         ImcRespCbData *resp_cb_data = NULL;
1840         gchar *at_cmd;
1841         TelReturn ret;
1842
1843         dbg("entry");
1844
1845         /* Response callback data */
1846         resp_cb_data = imc_create_resp_cb_data(cb, cb_data, NULL, 0);
1847
1848         /* AT - Command */
1849         if (mute)
1850                 at_cmd = g_strdup_printf("%s", "AT+XDRV=40,8,0,0,0");  /*MUTE*/
1851         else
1852                 at_cmd = g_strdup_printf("%s", "AT+XDRV=40,8,0,0,88"); /*UNMUTE*/
1853
1854         /* Send Request to modem */
1855         ret = tcore_at_prepare_and_send_request(co,
1856                         at_cmd, "+XDRV",
1857                         TCORE_AT_COMMAND_TYPE_SINGLELINE,
1858                         NULL,
1859                         on_response_imc_call_set_mute, resp_cb_data,
1860                         on_send_imc_request, NULL);
1861         IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "imc_call_set_mute");
1862
1863         g_free(at_cmd);
1864
1865         return ret;
1866 }
1867
1868 static TelReturn imc_call_get_mute_status(CoreObject *co, TcoreObjectResponseCallback cb,
1869         void *cb_data)
1870 {
1871         dbg("entry");
1872
1873         dbg("exit");
1874         return TEL_RETURN_OPERATION_NOT_SUPPORTED;
1875 }
1876
1877
1878 static TelReturn imc_call_set_sound_recording(CoreObject *co, TelCallSoundRecording sound_rec,
1879         TcoreObjectResponseCallback cb, void *cb_data)
1880 {
1881         dbg("entry");
1882
1883         dbg("exit");
1884         return TEL_RETURN_OPERATION_NOT_SUPPORTED;
1885 }
1886
1887 static TelReturn imc_call_set_sound_equalization(CoreObject *co, const TelCallSoundEqualization *sound_eq,
1888         TcoreObjectResponseCallback cb, void *cb_data)
1889 {
1890         dbg("entry");
1891
1892         dbg("exit");
1893         return TEL_RETURN_OPERATION_NOT_SUPPORTED;
1894 }
1895
1896 /* Call Operations */
1897 static TcoreCallOps imc_call_ops = {
1898         .dial = imc_call_dial,
1899         .answer = imc_call_answer,
1900         .end = imc_call_end,
1901         .send_dtmf = imc_call_send_dtmf,
1902         .hold = imc_call_hold,
1903         .active = imc_call_active,
1904         .swap = imc_call_swap,
1905         .join = imc_call_join,
1906         .split = imc_call_split,
1907         .transfer = imc_call_transfer,
1908         .deflect = imc_call_deflect,
1909         .set_active_line = imc_call_set_active_line,
1910         .get_active_line = imc_call_get_active_line,
1911         .set_volume_info = imc_call_set_volume_info,
1912         .get_volume_info = imc_call_get_volume_info,
1913         .set_sound_path = imc_call_set_sound_path,
1914         .set_mute = imc_call_set_mute,
1915         .get_mute_status = imc_call_get_mute_status,
1916         .set_sound_recording = imc_call_set_sound_recording,
1917         .set_sound_equalization = imc_call_set_sound_equalization,
1918 };
1919
1920 gboolean imc_call_init(TcorePlugin *p, CoreObject *co)
1921 {
1922         dbg("Entry");
1923
1924         /* Set operations */
1925         tcore_call_set_ops(co, &imc_call_ops);
1926
1927         /* Add Callbacks */
1928         tcore_object_add_callback(co, "+XCALLSTAT", on_notification_imc_call_status, NULL);
1929         tcore_object_add_callback(co, "+CLIP", on_notification_imc_call_clip_info, NULL);
1930         tcore_object_add_callback(co, "+CSSU", on_notification_imc_call_ss_cssu_info, NULL);
1931         tcore_object_add_callback(co, "+CSSI", on_notification_imc_call_ss_cssi_info, NULL);
1932
1933         return TRUE;
1934 }
1935
1936 void imc_call_exit(TcorePlugin *p, CoreObject *co)
1937 {
1938         dbg("Exit");
1939 }