From f6fa5175e76b859cb2a3d1d2f6de33835a857c8a Mon Sep 17 00:00:00 2001 From: Dongchul Lim Date: Mon, 7 Apr 2014 19:49:55 +0900 Subject: [PATCH] Initial refactoring merge Change-Id: If60d4cdba9a216134e133b993f84c363b22ca32b --- CMakeLists.txt | 30 +- include/common/TelErr.h | 186 -- include/{s_gps.h => imc_call.h} | 14 +- include/imc_common.h | 52 + include/{s_dispatch.h => imc_dispatch.h} | 10 +- include/{s_ss.h => imc_gps.h} | 14 +- include/{s_call.h => imc_modem.h} | 17 +- include/{s_sap.h => imc_network.h} | 14 +- include/{s_sms.h => imc_phonebook.h} | 14 +- include/imc_ps.h | 25 + include/imc_sap.h | 25 + include/imc_sat.h | 25 + include/{s_sat.h => imc_sim.h} | 15 +- include/imc_sms.h | 25 + include/imc_ss.h | 25 + include/nvm/nvm.h | 4 +- include/s_common.h | 32 - include/s_modem.h | 30 - include/s_network.h | 27 - include/s_phonebook.h | 27 - include/s_ps.h | 27 - include/s_sim.h | 27 - include/tel-plugin-imc.manifest | 11 + packaging/tel-plugin-imc.spec | 9 +- res/convert_to_sql.c | 4 +- src/desc-imc.c | 301 +++ src/desc.c | 294 --- src/imc_call.c | 1858 ++++++++++++++ src/{s_common.c => imc_common.c} | 38 +- src/{s_gps.c => imc_gps.c} | 836 +++---- src/imc_modem.c | 927 +++++++ src/imc_network.c | 1857 ++++++++++++++ src/imc_phonebook.c | 1090 ++++++++ src/imc_ps.c | 895 +++++++ src/imc_sap.c | 750 ++++++ src/imc_sat.c | 695 ++++++ src/imc_sim.c | 3976 ++++++++++++++++++++++++++++++ src/imc_sms.c | 2426 ++++++++++++++++++ src/imc_ss.c | 1725 +++++++++++++ src/nvm/nvm.c | 4 +- src/s_call.c | 3541 -------------------------- src/s_modem.c | 1035 -------- src/s_network.c | 2233 ----------------- src/s_phonebook.c | 1091 -------- src/s_ps.c | 665 ----- src/s_sap.c | 867 ------- src/s_sat.c | 466 ---- src/s_sim.c | 3931 ----------------------------- src/s_sms.c | 3185 ------------------------ src/s_ss.c | 2780 --------------------- 50 files changed, 17191 insertions(+), 20964 deletions(-) delete mode 100644 include/common/TelErr.h rename include/{s_gps.h => imc_call.h} (67%) create mode 100644 include/imc_common.h rename include/{s_dispatch.h => imc_dispatch.h} (81%) rename include/{s_ss.h => imc_gps.h} (67%) rename include/{s_call.h => imc_modem.h} (61%) rename include/{s_sap.h => imc_network.h} (66%) rename include/{s_sms.h => imc_phonebook.h} (66%) create mode 100644 include/imc_ps.h create mode 100644 include/imc_sap.h create mode 100644 include/imc_sat.h rename include/{s_sat.h => imc_sim.h} (63%) create mode 100644 include/imc_sms.h create mode 100644 include/imc_ss.h delete mode 100644 include/s_common.h delete mode 100644 include/s_modem.h delete mode 100644 include/s_network.h delete mode 100644 include/s_phonebook.h delete mode 100644 include/s_ps.h delete mode 100644 include/s_sim.h create mode 100644 include/tel-plugin-imc.manifest create mode 100644 src/desc-imc.c delete mode 100644 src/desc.c create mode 100644 src/imc_call.c rename src/{s_common.c => imc_common.c} (84%) rename src/{s_gps.c => imc_gps.c} (76%) create mode 100644 src/imc_modem.c create mode 100644 src/imc_network.c create mode 100644 src/imc_phonebook.c create mode 100644 src/imc_ps.c create mode 100644 src/imc_sap.c create mode 100644 src/imc_sat.c create mode 100644 src/imc_sim.c create mode 100644 src/imc_sms.c create mode 100644 src/imc_ss.c mode change 100755 => 100644 src/nvm/nvm.c delete mode 100644 src/s_call.c delete mode 100644 src/s_modem.c delete mode 100644 src/s_network.c delete mode 100644 src/s_phonebook.c delete mode 100644 src/s_ps.c delete mode 100644 src/s_sap.c delete mode 100644 src/s_sat.c delete mode 100644 src/s_sim.c delete mode 100644 src/s_sms.c delete mode 100644 src/s_ss.c diff --git a/CMakeLists.txt b/CMakeLists.txt index a5eb71d..c2f8743 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,7 +10,7 @@ SET(INCLUDEDIR "\${prefix}/include") # Set required packages INCLUDE(FindPkgConfig) -pkg_check_modules(pkgs REQUIRED glib-2.0 tcore dlog db-util libxml-2.0 libtzplatform-config) +pkg_check_modules(pkgs REQUIRED glib-2.0 tcore dlog db-util libxml-2.0 libtzplatform-config vconf) FOREACH(flag ${pkgs_CFLAGS}) SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") @@ -29,20 +29,20 @@ MESSAGE(${CMAKE_C_FLAGS}) MESSAGE(${CMAKE_EXE_LINKER_FLAGS}) SET(SRCS - src/desc.c - src/s_modem.c - src/s_common.c - src/s_network.c - src/s_sim.c - src/s_sat.c - src/s_call.c - src/s_ss.c - src/s_ps.c - src/s_sms.c - src/s_phonebook.c - src/s_sap.c - src/s_gps.c - src/nvm/nvm.c + src/desc-imc.c + src/imc_modem.c + src/imc_network.c + src/imc_sim.c + src/imc_sat.c + src/imc_call.c + src/imc_ss.c + src/imc_ps.c + src/imc_sms.c + src/imc_phonebook.c + src/imc_sap.c + src/imc_gps.c + src/imc_common.c + src/nvm/nvm.c ) diff --git a/include/common/TelErr.h b/include/common/TelErr.h deleted file mode 100644 index 4097fc5..0000000 --- a/include/common/TelErr.h +++ /dev/null @@ -1,186 +0,0 @@ -/* - * tel-plugin-imc - * - * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved. - * - * Contact: Hayoon Ko - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @open - * @ingroup TelephonyAPI - * @addtogroup COMMON_TAPI COMMON - * @{ - * These error codes are used by Applications. - */ - - -#ifndef _TEL_ERR_H_ -#define _TEL_ERR_H_ -/*================================================================================================== - INCLUDE FILES -==================================================================================================*/ - -#ifdef __cplusplus -extern "C" -{ -#endif - -/*================================================================================================== - CONSTANTS -==================================================================================================*/ - - -/*================================================================================================== - MACROS -==================================================================================================*/ - - -/*================================================================================================== - ENUMS -==================================================================================================*/ - -/************************************************************ -** Errors defined in "+CME ERROR" , -** - see 3GPP TS 27.007 -** - ranges are 0x00 ~ 0x7FFF -************************************************************/ -/** - Error codes sent by the modem in response to the above operations. -*/ -typedef enum { - /* GENERAL ERRORS */ - TAPI_OP_GEN_ERR_PHONE_FAILURE = 0, /* 0 */ - TAPI_OP_GEN_ERR_NO_CONNECTION_TO_PHONE, /* 1 */ - TAPI_OP_GEN_ERR_PHONE_ADAPTOR_LINK_RESERVED, /* 2 */ - TAPI_OP_GEN_ERR_OPER_NOT_ALLOWED, /* 3 */ - TAPI_OP_GEN_ERR_OPER_NOT_SUPPORTED, /* 4 */ - TAPI_OP_GEN_ERR_PH_SIM_PIN_REQU, /* 5 */ - TAPI_OP_GEN_ERR_PH_FSIM_PIN_REQU, /* 6 */ - TAPI_OP_GEN_ERR_PH_FSIM_PUK_REQU, /* 7 */ - TAPI_OP_GEN_ERR_SIM_NOT_INSERTED = 10, /* 10 */ - TAPI_OP_GEN_ERR_SIM_PIN_REQU, /* 11 */ - TAPI_OP_GEN_ERR_SIM_PUK_REQU, /* 12 */ - TAPI_OP_GEN_ERR_SIM_FAILURE, /* 13 */ - TAPI_OP_GEN_ERR_SIM_BUSY, /* 14 */ - TAPI_OP_GEN_ERR_SIM_WRONG, /* 15 */ - TAPI_OP_GEN_ERR_INCORRECT_PW, /* 16 */ - TAPI_OP_GEN_ERR_SIM_PIN2_REQU, /* 17 */ - TAPI_OP_GEN_ERR_SIM_PUK2_REQU, /* 18 */ - TAPI_OP_GEN_ERR_MEM_FULL = 20, /* 20 */ - TAPI_OP_GEN_ERR_INVALID_INDEX, /* 21 */ - TAPI_OP_GEN_ERR_NOT_FOUND, /* 22 */ - TAPI_OP_GEN_ERR_MEM_FAILURE, /* 23 */ - TAPI_OP_GEN_ERR_TEXT_STR_TOO_LONG, /* 24 */ - TAPI_OP_GEN_ERR_INVALID_CHARACTERS_IN_TEXT_STR, /* 25 */ - TAPI_OP_GEN_ERR_DIAL_STR_TOO_LONG, /* 26 */ - TAPI_OP_GEN_ERR_INVALID_CHARACTERS_IN_DIAL_STR, /* 27 */ - TAPI_OP_GEN_ERR_NO_NET_SVC = 30, /* 30 */ - TAPI_OP_GEN_ERR_NET_TIMEOUT, /* 31 */ - TAPI_OP_GEN_ERR_NET_NOT_ALLOWED_EMERGENCY_CALLS_ONLY, /* 32 */ - TAPI_OP_GEN_ERR_NET_PERS_PIN_REQU = 40, /* 40 */ - TAPI_OP_GEN_ERR_NET_PERS_PUK_REQU, /* 41 */ - TAPI_OP_GEN_ERR_NET_SUBSET_PERS_PIN_REQU, /* 42 */ - TAPI_OP_GEN_ERR_NET_SUBSET_PERS_PUK_REQU, /* 43 */ - TAPI_OP_GEN_ERR_SVC_PROVIDER_PERS_PIN_REQU, /* 44 */ - TAPI_OP_GEN_ERR_SVC_PROVIDER_PERS_PUK_REQU, /* 45 */ - TAPI_OP_GEN_ERR_CORPORATE_PERS_PIN_REQU, /* 46 */ - TAPI_OP_GEN_ERR_CORPORATE_PERS_PUK_REQU, /* 47 */ - TAPI_OP_GEN_ERR_HIDDEN_KEY_REQU, /* 48 */ - TAPI_OP_GEN_ERR_UNKNOWN = 100, /* 100 */ - - /* Errors related to a failure to perform an Attach */ - TAPI_OP_GEN_ERR_ILLEGAL_MS = 103, /* 103 */ - TAPI_OP_GEN_ERR_ILLEGAL_ME = 106, /* 106 */ - TAPI_OP_GEN_ERR_GPRS_SVC_NOT_ALLOWED, /* 107 */ - TAPI_OP_GEN_ERR_PLMN_NOT_ALLOWED = 111, /* 111 */ - TAPI_OP_GEN_ERR_LOCATION_AREA_NOT_ALLOWED, /* 112 */ - TAPI_OP_GEN_ERR_ROAMING_NOT_ALLOWED_IN_THIS_LOCATION_AREA, /* 113 */ - - /* Errors related to a failure to Activate a Context */ - TAPI_OP_GEN_ERR_SVC_OPT_NOT_SUPPORTED = 132, /* 132 */ - TAPI_OP_GEN_ERR_REQ_SVC_OPT_NOT_SUBSCRIBED, /* 133 */ - TAPI_OP_GEN_ERR_SVC_OPT_TEMPORARILY_OUT_OF_ORDER, /* 134 */ - TAPI_OP_GEN_ERR_UNSPECIFIED_GPRS_ERR = 148, /* 148 */ - TAPI_OP_GEN_ERR_PDP_AUTHENTICATION_FAILURE, /* 149 */ - TAPI_OP_GEN_ERR_INVALID_MOBILE_CLASS, /* 150 */ - - /* VBS / VGCS and eMLPP -related errors */ - TAPI_OP_GEN_ERR_VBS_VGCS_NOT_SUPPORTED_BY_THE_NET = 151, /* 151 */ - TAPI_OP_GEN_ERR_NO_SVC_SUBSCRIPTION_ON_SIM, /* 152 */ - TAPI_OP_GEN_ERR_NO_SUBSCRIPTION_FOR_GROUP_ID, /* 153 */ - TAPI_OP_GEN_ERR_GROUP_ID_NOT_ACTIVATED_ON_SIM, /* 154 */ - TAPI_OP_GEN_ERR_NO_MATCHING_NOTI = 155, /* 155 */ - TAPI_OP_GEN_ERR_VBS_VGCS_CALL_ALREADY_PRESENT, /* 156 */ - TAPI_OP_GEN_ERR_CONGESTION, /* 157 */ - TAPI_OP_GEN_ERR_NET_FAILURE, /* 158 */ - TAPI_OP_GEN_ERR_UPLINK_BUSY, /* 159 */ - TAPI_OP_GEN_ERR_NO_ACCESS_RIGHTS_FOR_SIM_FILE = 160, /* 160 */ - TAPI_OP_GEN_ERR_NO_SUBSCRIPTION_FOR_PRIORITY, /* 161 */ - TAPI_OP_GEN_ERR_OPER_NOT_APPLICABLE_OR_NOT_POSSIBLE, /* 162 */ - - - /************************************************************ - ** SAMSUNG ADDED ERRORS - ************************************************************/ - TAPI_OP_GEN_ERR_NONE = 0x8000, /* 0x8000 : No Errors */ - - /* General Common Errors : 0x8000 - 0x80FF */ - TAPI_OP_GEN_ERR_INVALID_FORMAT, /* 0x8001 : Invalid Parameter or Format */ - TAPI_OP_GEN_ERR_PHONE_OFFLINE, /* 0x8002 : */ - TAPI_OP_GEN_ERR_CMD_NOT_ALLOWED, /* 0x8003 : */ - TAPI_OP_GEN_ERR_PHONE_IS_INUSE, /* 0x8004 : */ - TAPI_OP_GEN_ERR_INVALID_STATE = 0x8005, /* 0x8005 : */ - - TAPI_OP_GEN_ERR_NO_BUFFER, /* 0x8006 : No internal free buffers */ - TAPI_OP_GEN_ERR_OPER_REJ, /* 0x8007 : Operation Rejected */ - TAPI_OP_GEN_ERR_INSUFFICIENT_RESOURCE, /* 0x8008 : insufficient resource */ - TAPI_OP_GEN_ERR_NET_NOT_RESPOND, /* 0x8009 : Network not responding */ - TAPI_OP_GEN_ERR_SIM_PIN_ENABLE_REQ = 0x800A, /* 0x800A : SIM Pin Enable Required */ - TAPI_OP_GEN_ERR_SIM_PERM_BLOCKED, /* 0x800B : SIM Permanent Blocked */ - TAPI_OP_GEN_ERR_SIM_PHONEBOOK_RESTRICTED, /*0x800C: SIM Phonebook Restricted*/ - TAPI_OP_GEM_ERR_FIXED_DIALING_NUMBER_ONLY, /*0x800D: Restricted By FDN Mode */ - - /* Reserved : 0x800E ~ 0x80FF */ - TAPI_OP_GEN_ERR_800E_RESERVED_START = 0x800E, /* 0x800E */ - - TAPI_OP_GEN_ERR_80FF_RESERVED_END = 0x80ff, /* 0x80FF */ - - /* the other errors */ - TAPI_OP_GEN_ERR_OTHERS = 0xFFFE, /* 0xFFFE */ - - TAPI_OP_GEN_ERR_MAX = 0xFFFF -} tapi_phone_err_t; - - -/*================================================================================================== - STRUCTURES AND OTHER TYPEDEFS -==================================================================================================*/ - - -/*================================================================================================== - FUNCTION PROTOTYPES -==================================================================================================*/ - - -#ifdef __cplusplus -} -#endif - -#endif // _TEL_ERR_H_ - -/** -* @} -*/ diff --git a/include/s_gps.h b/include/imc_call.h similarity index 67% rename from include/s_gps.h rename to include/imc_call.h index 73799f1..5e37f0a 100644 --- a/include/s_gps.h +++ b/include/imc_call.h @@ -1,9 +1,7 @@ /* * tel-plugin-imc * - * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved. - * - * Contact: Arun Shukla + * Copyright (c) 2013 Samsung Electronics Co. Ltd. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,10 +16,10 @@ * limitations under the License. */ -#ifndef __S_GPS_H__ -#define __S_GPS_H__ +#ifndef __IMC_CALL_H__ +#define __IMC_CALL_H__ -gboolean s_gps_init(TcorePlugin *cp, CoreObject *co_gps); -void s_gps_exit(TcorePlugin *cp, CoreObject *co_gps); +gboolean imc_call_init(TcorePlugin *p, CoreObject *co); +void imc_call_exit(TcorePlugin *p, CoreObject *co); -#endif +#endif /* __IMC_CALL_H__ */ diff --git a/include/imc_common.h b/include/imc_common.h new file mode 100644 index 0000000..23e3952 --- /dev/null +++ b/include/imc_common.h @@ -0,0 +1,52 @@ +/* + * tel-plugin-imc + * + * Copyright (c) 2013 Samsung Electronics Co. Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __IMC_COMMON_H__ +#define __IMC_COMMON_H__ + +#define IMC_SWAP_BYTES_16(x) \ +{ \ + unsigned short int data = *(unsigned short int *)&(x); \ + data = ((data & 0xff00) >> 8) | \ + ((data & 0x00ff) << 8); \ + *(unsigned short int *)&(x) = data; \ +} + +typedef struct { + TcoreObjectResponseCallback cb; + void *cb_data; + char data[]; /* Additional data */ +} ImcRespCbData; + +#define IMC_GET_DATA_FROM_RESP_CB_DATA(ptr) (gpointer)ptr->data +#define IMC_CHECK_REQUEST_RET(ret, resp_cb_data, request) \ +do {\ + if (ret != TEL_RETURN_SUCCESS) { \ + err("Failed to process request - [%s]", request); \ + imc_destroy_resp_cb_data(resp_cb_data); \ + } \ +} while(0) + +ImcRespCbData *imc_create_resp_cb_data(TcoreObjectResponseCallback cb, + void *cb_data, void *data, guint data_len); +void imc_destroy_resp_cb_data(ImcRespCbData *resp_cb_data); + +void on_send_imc_request(TcorePending *p, + TelReturn send_status, void *user_data); + +#endif /* __IMC_COMMON_H__ */ diff --git a/include/s_dispatch.h b/include/imc_dispatch.h similarity index 81% rename from include/s_dispatch.h rename to include/imc_dispatch.h index 5ee2f85..5e18bc5 100644 --- a/include/s_dispatch.h +++ b/include/imc_dispatch.h @@ -1,9 +1,7 @@ /* * tel-plugin-imc * - * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved. - * - * Contact: Ja-young Gu + * Copyright (c) 2013 Samsung Electronics Co. Ltd. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,11 +16,11 @@ * limitations under the License. */ -#ifndef __S_DISPATCH_H__ -#define __S_DISPATCH_H__ +#ifndef __IMC_DISPATCH_H__ +#define __IMC_DISPATCH_H__ void do_factory(TcoreHal *h, const ipc_message_type *ipc); void do_notification_message(TcorePlugin *p, const ipc_message_type *ipc); void do_notification_sys_message(TcorePlugin *p, const void *data); -#endif +#endif /* __IMC_DISPATCH_H__ */ diff --git a/include/s_ss.h b/include/imc_gps.h similarity index 67% rename from include/s_ss.h rename to include/imc_gps.h index 394ba8a..0351c96 100644 --- a/include/s_ss.h +++ b/include/imc_gps.h @@ -1,9 +1,7 @@ /* * tel-plugin-imc * - * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved. - * - * Contact: Sharanayya Mathapati + * Copyright (c) 2013 Samsung Electronics Co. Ltd. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,10 +16,10 @@ * limitations under the License. */ -#ifndef __S_SS_H__ -#define __S_SS_H__ +#ifndef __IMC_GPS_H__ +#define __IMC_GPS_H__ -gboolean s_ss_init(TcorePlugin *cp, CoreObject *co_ss); -void s_ss_exit(TcorePlugin *cp, CoreObject *co_ss); +gboolean imc_gps_init(TcorePlugin *p, CoreObject *co); +void imc_gps_exit(TcorePlugin *p, CoreObject *co); -#endif +#endif /* __IMC_GPS_H__ */ diff --git a/include/s_call.h b/include/imc_modem.h similarity index 61% rename from include/s_call.h rename to include/imc_modem.h index c1e83c1..5b48ec3 100644 --- a/include/s_call.h +++ b/include/imc_modem.h @@ -1,9 +1,7 @@ /* * tel-plugin-imc * - * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved. - * - * Contact: Sharanayya Mathapati + * Copyright (c) 2013 Samsung Electronics Co. Ltd. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,10 +16,13 @@ * limitations under the License. */ -#ifndef __S_CALL_H__ -#define __S_CALL_H__ +#ifndef __IMC_MODEM_H__ +#define __IMC_MODEM_H__ + +gboolean imc_modem_init(TcorePlugin *p, CoreObject *co); +void imc_modem_exit(TcorePlugin *p, CoreObject *co); -gboolean s_call_init(TcorePlugin *cp, CoreObject *co_call); -void s_call_exit(TcorePlugin *cp, CoreObject *co_call); +void imc_modem_register_nvm(CoreObject *co); +gboolean imc_modem_power_on_modem(TcorePlugin *plugin); -#endif +#endif /* __IMC_MODEM_H__ */ diff --git a/include/s_sap.h b/include/imc_network.h similarity index 66% rename from include/s_sap.h rename to include/imc_network.h index 8765f88..3f098b2 100644 --- a/include/s_sap.h +++ b/include/imc_network.h @@ -1,9 +1,7 @@ /* * tel-plugin-imc * - * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved. - * - * Contact: Hayoon Ko + * Copyright (c) 2013 Samsung Electronics Co. Ltd. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,10 +16,10 @@ * limitations under the License. */ -#ifndef S_SAP_H_ -#define S_SAP_H_ +#ifndef __IMC_NETWORK_H__ +#define __IMC_NETWORK_H__ -gboolean s_sap_init(TcorePlugin *cp, CoreObject *co_sap); -void s_sap_exit(TcorePlugin *cp, CoreObject *co_sap); +gboolean imc_network_init(TcorePlugin *p, CoreObject *co); +void imc_network_exit(TcorePlugin *p, CoreObject *co); -#endif /* S_SAP_H_ */ +#endif /* __IMC_NETWORK_H__ */ diff --git a/include/s_sms.h b/include/imc_phonebook.h similarity index 66% rename from include/s_sms.h rename to include/imc_phonebook.h index e818270..7e5c468 100644 --- a/include/s_sms.h +++ b/include/imc_phonebook.h @@ -1,9 +1,7 @@ /* * tel-plugin-imc * - * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved. - * - * Contact: Madhavi Akella + * Copyright (c) 2013 Samsung Electronics Co. Ltd. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,10 +16,10 @@ * limitations under the License. */ -#ifndef S_SMS_H_ -#define S_SMS_H_ +#ifndef __IMC_PHONEBOOK_H__ +#define __IMC_PHONEBOOK_H__ -gboolean s_sms_init(TcorePlugin *cp, CoreObject *co_sms); -void s_sms_exit(TcorePlugin *cp, CoreObject *co_sms); +gboolean imc_phonebook_init(TcorePlugin *p, CoreObject *co); +void imc_phonebook_exit(TcorePlugin *p, CoreObject *co); -#endif // S_SMS_H_ +#endif /* __IMC_PHONEBOOK_H__ */ diff --git a/include/imc_ps.h b/include/imc_ps.h new file mode 100644 index 0000000..02f5178 --- /dev/null +++ b/include/imc_ps.h @@ -0,0 +1,25 @@ +/* + * tel-plugin-imc + * + * Copyright (c) 2013 Samsung Electronics Co. Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __IMC_PS_H__ +#define __IMC_PS_H__ + +gboolean imc_ps_init(TcorePlugin *p, CoreObject *co); +void imc_ps_exit(TcorePlugin *p, CoreObject *co); + +#endif /*__IMC_PS_H__*/ diff --git a/include/imc_sap.h b/include/imc_sap.h new file mode 100644 index 0000000..836efa2 --- /dev/null +++ b/include/imc_sap.h @@ -0,0 +1,25 @@ +/* + * tel-plugin-imc + * + * Copyright (c) 2013 Samsung Electronics Co. Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __IMC_SAP_H__ +#define __IMC_SAP_H__ + +gboolean imc_sap_init(TcorePlugin *p, CoreObject *co); +void imc_sap_exit(TcorePlugin *p, CoreObject *co); + +#endif /* __IMC_SAP_H__ */ diff --git a/include/imc_sat.h b/include/imc_sat.h new file mode 100644 index 0000000..126f7ff --- /dev/null +++ b/include/imc_sat.h @@ -0,0 +1,25 @@ +/* + * tel-plugin-imc + * + * Copyright (c) 2013 Samsung Electronics Co. Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __IMC_SAT_H__ +#define __IMC_SAT_H__ + +gboolean imc_sat_init(TcorePlugin *p, CoreObject *co); +void imc_sat_exit(TcorePlugin *p, CoreObject *co); + +#endif /* __IMC_SAT_H__ */ diff --git a/include/s_sat.h b/include/imc_sim.h similarity index 63% rename from include/s_sat.h rename to include/imc_sim.h index 90eb826..8d6d199 100644 --- a/include/s_sat.h +++ b/include/imc_sim.h @@ -1,9 +1,7 @@ /* * tel-plugin-imc * - * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved. - * - * Contact: Harish Bishnoi + * Copyright (c) 2013 Samsung Electronics Co. Ltd. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,11 +16,12 @@ * limitations under the License. */ +#ifndef __IMC_SIM_H__ +#define __IMC_SIM_H__ -#ifndef S_SAT_H_ -#define S_SAT_H_ +gboolean imc_sim_get_smsp_info(TcorePlugin *plugin, int *rec_count, int *rec_len); -gboolean s_sat_init(TcorePlugin *cp, CoreObject *co_sat); -void s_sat_exit(TcorePlugin *cp, CoreObject *co_sat); +gboolean imc_sim_init(TcorePlugin *p, CoreObject *co); +void imc_sim_exit(TcorePlugin *p, CoreObject *co); -#endif /* S_SAT_H_ */ +#endif /* __IMC_SIM_H__ */ diff --git a/include/imc_sms.h b/include/imc_sms.h new file mode 100644 index 0000000..344de7c --- /dev/null +++ b/include/imc_sms.h @@ -0,0 +1,25 @@ +/* + * tel-plugin-imc + * + * Copyright (c) 2013 Samsung Electronics Co. Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __IMC_SMS_H__ +#define __IMC_SMS_H__ + +gboolean imc_sms_init(TcorePlugin *p, CoreObject *co); +void imc_sms_exit(TcorePlugin *p, CoreObject *co); + +#endif /* __IMC_SMS_H__ */ diff --git a/include/imc_ss.h b/include/imc_ss.h new file mode 100644 index 0000000..0b93897 --- /dev/null +++ b/include/imc_ss.h @@ -0,0 +1,25 @@ +/* + * tel-plugin-imc + * + * Copyright (c) 2013 Samsung Electronics Co. Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __IMC_SS_H__ +#define __IMC_SS_H__ + +gboolean imc_ss_init(TcorePlugin *p, CoreObject *co); +void imc_ss_exit(TcorePlugin *p, CoreObject *co); + +#endif /* __IMC_SS_H__ */ diff --git a/include/nvm/nvm.h b/include/nvm/nvm.h index a654bf2..0da96fc 100755 --- a/include/nvm/nvm.h +++ b/include/nvm/nvm.h @@ -1,9 +1,7 @@ /* * tel-plugin-imc * - * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved. - * - * Contact: Paresh Agarwal + * Copyright (c) 2013 Samsung Electronics Co. Ltd. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/include/s_common.h b/include/s_common.h deleted file mode 100644 index 5453f2c..0000000 --- a/include/s_common.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * tel-plugin-imc - * - * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved. - * - * Contact: Hayoon Ko - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __S_COMMON_H__ -#define __S_COMMON_H__ - -#include - -void util_hex_dump(char *pad, int size, const void *data); -unsigned char util_hexCharToInt(char c); -char *util_hex_to_string(const char *src, unsigned int src_len); -char* util_hexStringToBytes(char *s); -char* util_removeQuotes(void *data); - -#endif diff --git a/include/s_modem.h b/include/s_modem.h deleted file mode 100644 index 16d759a..0000000 --- a/include/s_modem.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * tel-plugin-imc - * - * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved. - * - * Contact: Hayoon Ko - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __S_MODEM_H__ -#define __S_MODEM_H__ - -gboolean s_modem_init(TcorePlugin *cp, CoreObject *co_modem); -void s_modem_exit(TcorePlugin *cp, CoreObject *co_modem); - -gboolean modem_power_on(TcorePlugin *plugin); -void modem_register_nvm(CoreObject *co_modem); - -#endif diff --git a/include/s_network.h b/include/s_network.h deleted file mode 100644 index d9db1f1..0000000 --- a/include/s_network.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * tel-plugin-imc - * - * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved. - * - * Contact: Harish Bishnoi - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __S_NETWORK_H__ -#define __S_NETWORK_H__ - -gboolean s_network_init(TcorePlugin *cp, CoreObject *co_network); -void s_network_exit(TcorePlugin *cp, CoreObject *co_network); - -#endif diff --git a/include/s_phonebook.h b/include/s_phonebook.h deleted file mode 100644 index beae5fa..0000000 --- a/include/s_phonebook.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * tel-plugin-imc - * - * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved. - * - * Contact: Ja-young Gu - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef S_PHONEBOOK_H_ -#define S_PHONEBOOK_H_ - -gboolean s_phonebook_init(TcorePlugin *cp, CoreObject *co_phonebook); -void s_phonebook_exit(TcorePlugin *cp, CoreObject *co_phonebook); - -#endif /* S_PHONEBOOK_H_ */ diff --git a/include/s_ps.h b/include/s_ps.h deleted file mode 100644 index 195b78f..0000000 --- a/include/s_ps.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * tel-plugin-imc - * - * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved. - * - * Contact: Arun Shukla - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __S_PS_H__ -#define __S_PS_H__ - -gboolean s_ps_init(TcorePlugin *cp, CoreObject *co_ps); -void s_ps_exit(TcorePlugin *cp, CoreObject *co_ps); - -#endif /*__S_PS_H__*/ diff --git a/include/s_sim.h b/include/s_sim.h deleted file mode 100644 index a7aac22..0000000 --- a/include/s_sim.h +++ /dev/null @@ -1,27 +0,0 @@ -/** - * tel-plugin-imc - * - * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd All Rights Reserved - * - * Contact: Ankit Jogi - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __S_SIM_H__ -#define __S_SIM_H__ - -gboolean s_sim_init(TcorePlugin *cp, CoreObject *co_sim); -void s_sim_exit(TcorePlugin *cp, CoreObject *co_sim); - -#endif diff --git a/include/tel-plugin-imc.manifest b/include/tel-plugin-imc.manifest new file mode 100644 index 0000000..143fb79 --- /dev/null +++ b/include/tel-plugin-imc.manifest @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/packaging/tel-plugin-imc.spec b/packaging/tel-plugin-imc.spec index 60f0886..eb6f02e 100644 --- a/packaging/tel-plugin-imc.spec +++ b/packaging/tel-plugin-imc.spec @@ -1,8 +1,12 @@ #sbs-git:slp/pkgs/t/tel-plugin-imc +%define major 3 +%define minor 0 +%define patchlevel 1 + Name: tel-plugin-imc Summary: imc plugin for telephony -Version: 0.1.42 -Release: 1 +Version: %{major}.%{minor}.%{patchlevel} +Release: 1 Group: Development/Libraries License: Apache-2.0 Source0: tel-plugin-imc-%{version}.tar.gz @@ -16,6 +20,7 @@ BuildRequires: pkgconfig(tcore) BuildRequires: pkgconfig(db-util) BuildRequires: pkgconfig(libxml-2.0) BuildRequires: pkgconfig(libtzplatform-config) +BuildRequires: pkgconfig(vconf) %description IMC plugin for telephony diff --git a/res/convert_to_sql.c b/res/convert_to_sql.c index 5b1b1ba..72a3bbf 100644 --- a/res/convert_to_sql.c +++ b/res/convert_to_sql.c @@ -1,9 +1,7 @@ /* * tel-plugin-imc * - * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved. - * - * Contact: Hayoon Ko + * Copyright (c) 2013 Samsung Electronics Co. Ltd. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/src/desc-imc.c b/src/desc-imc.c new file mode 100644 index 0000000..960706f --- /dev/null +++ b/src/desc-imc.c @@ -0,0 +1,301 @@ +/* + * tel-plugin-imc + * + * Copyright (c) 2013 Samsung Electronics Co. Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include "imc_modem.h" +#include "imc_sim.h" +#include "imc_sat.h" +#include "imc_sap.h" +#include "imc_network.h" +#include "imc_ps.h" +#include "imc_call.h" +#include "imc_ss.h" +#include "imc_sms.h" +#include "imc_phonebook.h" +#include "imc_gps.h" + +#include "imc_common.h" + +/* Initializer Table */ +TcoreObjectInitializer imc_init_table = { + .modem_init = imc_modem_init, + .sim_init = imc_sim_init, + .sat_init = imc_sat_init, + .sap_init = imc_sap_init, + .network_init = imc_network_init, + .ps_init = imc_ps_init, + .call_init = imc_call_init, + .ss_init = imc_ss_init, + .sms_init = imc_sms_init, + .phonebook_init = imc_phonebook_init, + .gps_init = imc_gps_init, +}; + +/* Deinitializer Table */ +TcoreObjectDeinitializer imc_deinit_table = { + .modem_deinit = imc_modem_exit, + .sim_deinit = imc_sim_exit, + .sat_deinit = imc_sat_exit, + .sap_deinit = imc_sap_exit, + .network_deinit = imc_network_exit, + .ps_deinit = imc_ps_exit, + .call_deinit = imc_call_exit, + .ss_deinit = imc_ss_exit, + .sms_deinit = imc_sms_exit, + .phonebook_deinit = imc_phonebook_exit, + .gps_deinit = imc_gps_exit, +}; + +static void __send_request(CoreObject *co, const gchar *at_cmd, + TcorePendingResponseCallback resp_cb, void *resp_cb_data) +{ + (void)tcore_at_prepare_and_send_request(co, at_cmd, NULL, + TCORE_AT_COMMAND_TYPE_NO_RESULT, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + resp_cb, resp_cb_data, + on_send_imc_request, NULL, + 0, NULL, NULL); +} + +static void __on_response_subscribe_bootup_notification(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + dbg("Entry"); + + if (at_resp && at_resp->success) { + dbg("Subscription for '%s' - [OK]", (gchar *)user_data); + } else { + err("Subscription for '%s' - [NOK]", (gchar *)user_data); + } + + /* Free resource */ + tcore_free(user_data); +} + +static void __on_response_subscribe_bootup_notification_last(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + TcorePlugin *plugin = tcore_pending_ref_plugin(p); + gboolean ret; + + if (at_resp && at_resp->success) { + dbg("[Last] Subscription for '%s' - [OK]", (gchar *)user_data); + } else { + err("[Last] Subscription for '%s' - [NOK]", (gchar *)user_data); + } + + /* Free resource */ + tcore_free(user_data); + + dbg("Boot-up configration completed for IMC modem, " + "Bring CP to ONLINE state based on Flight mode status"); + + /* Modem Power */ + ret = imc_modem_power_on_modem(plugin); + dbg("Modem Power ON: [%s]", (ret == TRUE ? "SUCCESS" : "FAIL")); + + /* NVM Registration */ + dbg("Registering modem for NVM manager"); + imc_modem_register_nvm(tcore_plugin_ref_core_object(plugin, CORE_OBJECT_TYPE_MODEM)); +} + +static void __subscribe_modem_notifications(TcorePlugin *plugin) +{ + CoreObject *call, *sim, *sms, *network, *ps, *gps; + dbg("Entry"); + + /* + * URC Subscriptions + */ + /****** SIM subscriptions ******/ + sim = tcore_plugin_ref_core_object(plugin, CORE_OBJECT_TYPE_SIM); + /* XSIMSTATE */ + __send_request(sim, "AT+XSIMSTATE=1", + __on_response_subscribe_bootup_notification, + tcore_strdup("AT+XSIMSTATE=1")); + + /****** CALL subscriptions ******/ + call = tcore_plugin_ref_core_object(plugin, CORE_OBJECT_TYPE_CALL); + /* XCALLSTAT */ + __send_request(call, "AT+XCALLSTAT=1", + __on_response_subscribe_bootup_notification, + tcore_strdup("AT+XCALLSTAT=1")); + + /* CSSN */ + __send_request(call, "AT+CSSN=1,1", + __on_response_subscribe_bootup_notification, + tcore_strdup("AT+CSSN=1,1")); + + /* CUSD */ + __send_request(call, "AT+CUSD=1", + __on_response_subscribe_bootup_notification, + tcore_strdup("AT+CUSD=1")); + + /* CLIP */ + __send_request(call, "AT+CLIP=1", + __on_response_subscribe_bootup_notification, + tcore_strdup("AT+CLIP=1")); + + /****** NETWORK subscriptions ******/ + network = tcore_plugin_ref_core_object(plugin, CORE_OBJECT_TYPE_NETWORK); + /* CREG */ + __send_request(network, "AT+CREG=2", + __on_response_subscribe_bootup_notification, + tcore_strdup("AT+CREG=2")); + + /* CGREG */ + __send_request(network, "AT+CGREG=2", + __on_response_subscribe_bootup_notification, + tcore_strdup("AT+CGREG=2")); + + /* Allow Automatic Time Zone updation via NITZ */ + __send_request(network, "AT+CTZU=1", + __on_response_subscribe_bootup_notification, + tcore_strdup("AT+CTZU=1")); + + /* TZ, Time & Daylight changing event reporting Subscription */ + __send_request(network, "AT+CTZR=1", + __on_response_subscribe_bootup_notification, + tcore_strdup("AT+CTZR=1")); + + /* XMER */ + __send_request(network, "AT+XMER=1", + __on_response_subscribe_bootup_notification, + tcore_strdup("AT+XMER=1")); + + /****** PS subscriptions ******/ + ps = tcore_plugin_ref_core_object(plugin, CORE_OBJECT_TYPE_PS); + /* CGEREP */ + __send_request(ps, "AT+CGEREP=1", + __on_response_subscribe_bootup_notification, + tcore_strdup("AT+CGEREP=1")); + + /* XDATASTAT */ + __send_request(ps, "AT+XDATASTAT=1", + __on_response_subscribe_bootup_notification, + tcore_strdup("AT+XDATASTAT=1")); + + /* XDNS */ + __send_request(ps, "AT+XDNS=1,1", + __on_response_subscribe_bootup_notification, + tcore_strdup("AT+XDNS=1,1")); + + /* CMEE */ + __send_request(ps, "AT+CMEE=2", + __on_response_subscribe_bootup_notification, + tcore_strdup("AT+CMEE=2")); + + /****** SMS subscriptions ******/ + sms = tcore_plugin_ref_core_object(plugin, CORE_OBJECT_TYPE_SMS); + /* CMEE */ + __send_request(sms, "AT+CMEE=2", + __on_response_subscribe_bootup_notification, + tcore_strdup("AT+CMEE=2")); + + /* Incoming SMS, Cell Broadcast, Status Report Subscription */ + __send_request(sms, "AT+CNMI=1,2,2,1,0", + __on_response_subscribe_bootup_notification, + tcore_strdup("AT+CNMI=1,2,2,1,0")); + + /* Text/PDU mode Subscription */ + __send_request(sms, "AT+CMGF=0", + __on_response_subscribe_bootup_notification, + tcore_strdup("AT+CMGF=0")); + +#if 0 /* Temporarily Blocking as modem doesn't support */ + /****** SAP subscriptions ******/ + sap = tcore_plugin_ref_core_object(plugin, CORE_OBJECT_TYPE_SAP); + /* XBCSTAT */ + __send_request(sap, "AT+XBCSTAT=1", + __on_response_subscribe_bootup_notification, + tcore_strdup("AT+XBCSTAT=1")); +#endif /* Temporarily Blocking as modem doesn't support */ + + /****** GPS subscriptions ******/ + gps = tcore_plugin_ref_core_object(plugin, CORE_OBJECT_TYPE_GPS); + /* AGPS- Assist Data and Reset Assist Data Subscription */ + __send_request(gps, "AT+CPOSR=1", + __on_response_subscribe_bootup_notification, + tcore_strdup("AT+CPOSR=1")); + + __send_request(gps, "AT+XCPOSR=1", + __on_response_subscribe_bootup_notification_last, + tcore_strdup("AT+XCPOSR=1")); + + dbg("Exit"); +} + +static gboolean on_load() +{ + dbg("Load!!!"); + + return TRUE; +} + +static gboolean on_init(TcorePlugin *p) +{ + dbg("Init!!!"); + tcore_check_return_value(p != NULL, FALSE); + + /* Initialize Modules (Core Objects) */ + if (tcore_object_init_objects(p, &imc_init_table) + != TEL_RETURN_SUCCESS) { + err("Failed to initialize Core Objects"); + return FALSE; + } + + /* Subscribe for the Events from CP */ + __subscribe_modem_notifications(p); + + dbg("Init - Successful"); + return TRUE; +} + +static void on_unload(TcorePlugin *p) +{ + dbg("Unload!!!"); + tcore_check_return(p != NULL); + + /* Deinitialize Modules (Core Objects) */ + tcore_object_deinit_objects(p, &imc_deinit_table); +} + +/* IMC - Modem Plug-in Descriptor */ +struct tcore_plugin_define_desc plugin_define_desc = { + .name = "imc", + .priority = TCORE_PLUGIN_PRIORITY_MID, + .version = 1, + .load = on_load, + .init = on_init, + .unload = on_unload +}; diff --git a/src/desc.c b/src/desc.c deleted file mode 100644 index f3e98f6..0000000 --- a/src/desc.c +++ /dev/null @@ -1,294 +0,0 @@ -/* - * tel-plugin-imc - * - * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved. - * - * Contact: Hayoon Ko - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "s_network.h" -#include "s_modem.h" -#include "s_sim.h" -#include "s_sap.h" -#include "s_ps.h" -#include "s_call.h" -#include "s_ss.h" -#include "s_sms.h" -#include "s_sat.h" -#include "s_phonebook.h" -#include "s_gps.h" - -static void on_confirmation_modem_message_send(TcorePending *p, - gboolean result, - void *user_data) -{ - dbg("msg out from queue"); - - dbg("%s", result == FALSE ? "SEND FAIL" : "SEND OK"); -} - -static void on_response_bootup_subscription(TcorePending *p, - int data_len, const void *data, void *user_data) -{ - const TcoreATResponse *resp = data; - dbg("Entry"); - - if (resp->success > 0) { - dbg("RESULT - OK"); - } else { - err("RESULT - ERROR"); - } -} - -static void on_response_last_bootup_subscription(TcorePending *p, - int data_len, const void *data, void *user_data) -{ - const TcoreATResponse *resp = data; - TcorePlugin *plugin = tcore_pending_ref_plugin(p); - gboolean ret; - dbg("Last Subscription - COMPLETED"); - - if (resp->success) { - dbg("RESULT - OK"); - } else { - err("RESULT - FAIL"); - } - - dbg("Boot-up configration completed for IMC modem. %s", - "Bring CP to ONLINE state based on Flightmode status"); - - /* Modem Power */ - ret = modem_power_on(plugin); - dbg("Modem Power ON: [%s]", (ret == TRUE ? "SUCCESS" : "FAIL")); - - /* NVM Registration */ - dbg("Registering modem for NVM manager"); - modem_register_nvm(tcore_plugin_ref_core_object(plugin, CORE_OBJECT_TYPE_MODEM)); -} - -static void _modem_subscribe_events(TcorePlugin *plugin) -{ - CoreObject *co_call = tcore_plugin_ref_core_object(plugin, CORE_OBJECT_TYPE_CALL); - CoreObject *co_sim = tcore_plugin_ref_core_object(plugin, CORE_OBJECT_TYPE_SIM); - CoreObject *co_sms = tcore_plugin_ref_core_object(plugin, CORE_OBJECT_TYPE_SMS); - CoreObject *co_network = tcore_plugin_ref_core_object(plugin, CORE_OBJECT_TYPE_NETWORK); - CoreObject *co_ps = tcore_plugin_ref_core_object(plugin, CORE_OBJECT_TYPE_PS); - CoreObject *co_sap = tcore_plugin_ref_core_object(plugin, CORE_OBJECT_TYPE_SAP); - CoreObject *co_gps = tcore_plugin_ref_core_object(plugin, CORE_OBJECT_TYPE_GPS); - - dbg("Entry"); - - /* URC Subscriptions per Module */ - - /****** SIM subscriptions ******/ - /* XSIMSTATE */ - tcore_prepare_and_send_at_request(co_sim, "at+xsimstate=1", NULL, TCORE_AT_NO_RESULT, NULL, - on_response_bootup_subscription, NULL, - on_confirmation_modem_message_send, NULL); - - /****** CALL subscriptions ******/ - /* XCALLSTAT */ - tcore_prepare_and_send_at_request(co_call, "at+xcallstat=1", NULL, TCORE_AT_NO_RESULT, NULL, - on_response_bootup_subscription, NULL, - on_confirmation_modem_message_send, NULL); - - /* CSSN */ - tcore_prepare_and_send_at_request(co_call, "at+cssn=1,1", NULL, TCORE_AT_NO_RESULT, NULL, - on_response_bootup_subscription, NULL, - on_confirmation_modem_message_send, NULL); - - /* CUSD */ - tcore_prepare_and_send_at_request(co_call, "at+cusd=1", NULL, TCORE_AT_NO_RESULT, NULL, - on_response_bootup_subscription, NULL, - on_confirmation_modem_message_send, NULL); - - /* CLIP */ - tcore_prepare_and_send_at_request(co_call, "at+clip=1", NULL, TCORE_AT_NO_RESULT, NULL, - on_response_bootup_subscription, NULL, - on_confirmation_modem_message_send, NULL); - - /****** NETWORK subscriptions ******/ - /* CREG */ - tcore_prepare_and_send_at_request(co_network, "at+creg=2", NULL, TCORE_AT_NO_RESULT, NULL, - on_response_bootup_subscription, NULL, - on_confirmation_modem_message_send, NULL); - - /* CGREG */ - tcore_prepare_and_send_at_request(co_network, "at+cgreg=2", NULL, TCORE_AT_NO_RESULT, NULL, - on_response_bootup_subscription, NULL, - on_confirmation_modem_message_send, NULL); - - /* Allow Automatic Time Zone updation via NITZ */ - tcore_prepare_and_send_at_request(co_network, "at+ctzu=1", NULL, TCORE_AT_NO_RESULT, NULL, - on_response_bootup_subscription, NULL, - on_confirmation_modem_message_send, NULL); - - /* TZ, Time & Daylight changing event reporting Subscription */ - tcore_prepare_and_send_at_request(co_network, "at+ctzr=1", NULL, TCORE_AT_NO_RESULT, NULL, - on_response_bootup_subscription, NULL, - on_confirmation_modem_message_send, NULL); - - /* XMER */ - tcore_prepare_and_send_at_request(co_network, "at+xmer=1", NULL, TCORE_AT_NO_RESULT, NULL, - on_response_bootup_subscription, NULL, - on_confirmation_modem_message_send, NULL); - - /****** PS subscriptions ******/ - /* CGEREP */ - tcore_prepare_and_send_at_request(co_ps, "at+cgerep=1", NULL, TCORE_AT_NO_RESULT, NULL, - on_response_bootup_subscription, NULL, - on_confirmation_modem_message_send, NULL); - - /* XDATASTAT */ - tcore_prepare_and_send_at_request(co_ps, "at+xdatastat=1", NULL, TCORE_AT_NO_RESULT, NULL, - on_response_bootup_subscription, NULL, - on_confirmation_modem_message_send, NULL); - - - /* XDNS */ - tcore_prepare_and_send_at_request(co_ps, "at+xdns=1,1", NULL, TCORE_AT_NO_RESULT, NULL, - on_response_bootup_subscription, NULL, - on_confirmation_modem_message_send, NULL); - - /* CMEE */ - tcore_prepare_and_send_at_request(co_ps, "at+cmee=2", NULL, TCORE_AT_NO_RESULT, NULL, - on_response_bootup_subscription, NULL, - on_confirmation_modem_message_send, NULL); - - /****** SMS subscriptions ******/ - /* CMEE */ - tcore_prepare_and_send_at_request(co_sms, "at+cmee=2", NULL, TCORE_AT_NO_RESULT, NULL, - on_response_bootup_subscription, NULL, - on_confirmation_modem_message_send, NULL); - - /* Incoming SMS, Cell Broadcast, Status Report Subscription */ - tcore_prepare_and_send_at_request(co_sms, "at+cnmi=1,2,2,1,0", NULL, TCORE_AT_NO_RESULT, NULL, - on_response_bootup_subscription, NULL, - on_confirmation_modem_message_send, NULL); - - /* Text/PDU mode Subscription */ - tcore_prepare_and_send_at_request(co_sms, "at+cmgf=0", NULL, TCORE_AT_NO_RESULT, NULL, - on_response_bootup_subscription, NULL, - on_confirmation_modem_message_send, NULL); - - /****** GPS subscriptions ******/ - /* AGPS- Assist Data and Reset Assist Data Subscription */ - tcore_prepare_and_send_at_request(co_gps, "at+cposr=1", NULL, TCORE_AT_NO_RESULT, NULL, - on_response_bootup_subscription, NULL, - on_confirmation_modem_message_send, NULL); - - tcore_prepare_and_send_at_request(co_gps, "at+xcposr=1", NULL, TCORE_AT_NO_RESULT, NULL, - on_response_bootup_subscription, NULL, - on_confirmation_modem_message_send, NULL); - - /****** SAP subscriptions ******/ - /* XBCSTAT */ - tcore_prepare_and_send_at_request(co_sap, "at+xbcstat=1", NULL, TCORE_AT_NO_RESULT, NULL, - on_response_last_bootup_subscription, NULL, - on_confirmation_modem_message_send, NULL); - - dbg("Exit"); -} - -/* Initializer Table */ -struct object_initializer init_table = { - .modem_init = s_modem_init, - .sim_init = s_sim_init, - .sat_init = s_sat_init, - .sap_init = s_sap_init, - .network_init = s_network_init, - .ps_init = s_ps_init, - .call_init = s_call_init, - .ss_init = s_ss_init, - .sms_init = s_sms_init, - .phonebook_init = s_phonebook_init, - .gps_init = s_gps_init, -}; - -/* Deinitializer Table */ -struct object_deinitializer deinit_table = { - .modem_deinit = s_modem_exit, - .sim_deinit = s_sim_exit, - .sat_deinit = s_sat_exit, - .sap_deinit = s_sap_exit, - .network_deinit = s_network_exit, - .ps_deinit = s_ps_exit, - .call_deinit = s_call_exit, - .ss_deinit = s_ss_exit, - .sms_deinit = s_sms_exit, - .phonebook_deinit = s_phonebook_exit, - .gps_deinit = s_gps_exit, -}; - -static gboolean on_load() -{ - dbg("Load!!!"); - - return TRUE; -} - -static gboolean on_init(TcorePlugin *p) -{ - dbg("Init!!!"); - if (p == NULL) - return FALSE; - - /* Initialize Modules (Core Objects) */ - if (tcore_object_init_objects(p, &init_table) - != TCORE_RETURN_SUCCESS) { - err("Failed to initialize Core Objects"); - return FALSE; - } - - /* Subscribe for the Events from CP */ - _modem_subscribe_events(p); - - dbg("Init - Successful"); - return TRUE; -} - -static void on_unload(TcorePlugin *p) -{ - dbg("Unload!!!"); - - if (p == NULL) - return; - - /* Deinitialize Modules (Core Objects) */ - tcore_object_deinit_objects(p, &deinit_table); -} - -/* IMC - Modem Plug-in Descriptor */ -struct tcore_plugin_define_desc plugin_define_desc = { - .name = "IMC", - .priority = TCORE_PLUGIN_PRIORITY_MID, - .version = 1, - .load = on_load, - .init = on_init, - .unload = on_unload -}; diff --git a/src/imc_call.c b/src/imc_call.c new file mode 100644 index 0000000..142ede3 --- /dev/null +++ b/src/imc_call.c @@ -0,0 +1,1858 @@ +/* + * tel-plugin-imc + * + * Copyright (c) 2013 Samsung Electronics Co. Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "imc_call.h" +#include "imc_common.h" + +#define COMMA 0X2c +#define STATUS_INCOMING 4 +#define STATUS_WAITING 5 +#define STATUS_CONNECTED 7 + +#define find_call_object(co, call_id, call_obj) \ + do { \ + call_obj = tcore_call_object_find_by_id(co, call_id); \ + if (!call_obj) { \ + err("unable to find call object"); \ + return; \ + } \ + } while (0) + +struct imc_set_volume_info { + guint next_index; + guint volume; +}; + +static gchar *xdrv_set_volume[] = { + "AT+XDRV=40,7,3,88", + "AT+XDRV=40,7,0,88", + "AT+XDRV=40,8,0,88", + "AT+XDRV=40,8,2,", + NULL +}; + +/*Forward Declarations*/ +static void on_response_imc_call_default(TcorePending *p, + guint data_len, const void *data, void *user_data); + +static TelReturn __call_list_get(CoreObject *co, gboolean flag); + + +static TelCallType __call_type(int type) +{ + dbg("Entry"); + + switch (type) { + case 0: + return TEL_CALL_TYPE_VOICE; + + case 1: + return TEL_CALL_TYPE_VIDEO; + + default: + err("invalid call type, returing default call type as voice"); + return TEL_CALL_TYPE_VOICE; + } +} + +static TelCallState __call_state(int state) +{ + dbg("Entry"); + + switch (state) { + case 0: + return TEL_CALL_STATE_ACTIVE; + + case 1: + return TEL_CALL_STATE_HELD; + + case 2: + return TEL_CALL_STATE_DIALING; + + case 3: + return TEL_CALL_STATE_ALERT; + + case 4: + case 5: + return TEL_CALL_STATE_INCOMING; + + default: + return TEL_CALL_STATE_IDLE; + } +} + +static void __call_branch_by_status(CoreObject *co, CallObject *call_obj, TelCallState call_state) +{ + unsigned int call_id; + TelCallType call_type; + TelCallState state; + TcoreNotification command = TCORE_NOTIFICATION_UNKNOWN; + dbg("Call State[%d]", call_state); + + if (tcore_call_object_get_state(call_obj, &state) == FALSE) { + err("unable to get call status"); + return; + } + + if (call_state == state) { + dbg("current call state and existing call state are same"); + return; + } + + if (tcore_call_object_get_call_type(call_obj, &call_type) == FALSE) { + err("unable to get call type"); + return; + } + + if (tcore_call_object_get_id(call_obj, &call_id) == FALSE) { + err("unable to get call id"); + return; + } + + /* Set Status */ + tcore_call_object_set_state(call_obj, call_state); + + if (call_type == TEL_CALL_TYPE_VOICE) { + /* voice call notification */ + switch (call_state) { + case TEL_CALL_STATE_ACTIVE: + command = TCORE_NOTIFICATION_CALL_STATUS_ACTIVE; + break; + + case TEL_CALL_STATE_HELD: + command = TCORE_NOTIFICATION_CALL_STATUS_HELD; + break; + + case TEL_CALL_STATE_DIALING: + command = TCORE_NOTIFICATION_CALL_STATUS_DIALING; + break; + + case TEL_CALL_STATE_ALERT: + command = TCORE_NOTIFICATION_CALL_STATUS_ALERT; + break; + + case TEL_CALL_STATE_INCOMING: + case TEL_CALL_STATE_WAITING: { + TelCallIncomingInfo incoming = {0,}; + command = TCORE_NOTIFICATION_CALL_STATUS_INCOMING; + incoming.call_id = call_id; + tcore_call_object_get_cli_validity(call_obj, &incoming.cli_validity); + tcore_call_object_get_number(call_obj, incoming.number); + tcore_call_object_get_cni_validity(call_obj, &incoming.cni_validity); + tcore_call_object_get_name(call_obj, incoming.name); + tcore_call_object_get_mt_forward(call_obj, &incoming.forward); + tcore_call_object_get_active_line(call_obj, &incoming.active_line); + + /* Send notification */ + tcore_object_send_notification(co, command, sizeof(TelCallIncomingInfo), &incoming); + return; + } + + case TEL_CALL_STATE_IDLE: { + TelCallStatusIdleNoti idle; + command = TCORE_NOTIFICATION_CALL_STATUS_IDLE; + idle.call_id = call_id; + + /* TODO - get proper call end cause. */ + idle.cause = TEL_CALL_END_CAUSE_NONE; + + /* Send notification */ + tcore_object_send_notification(co, command, + sizeof(TelCallStatusIdleNoti), &idle); + + /* Free Call object */ + tcore_call_object_free(co, call_obj); + return; + } + } + + } + else if (call_type == TEL_CALL_TYPE_VIDEO) { + /* video call notification */ + switch (call_state) { + case TEL_CALL_STATE_ACTIVE: + command = TCORE_NOTIFICATION_VIDEO_CALL_STATUS_ACTIVE; + break; + + case TEL_CALL_STATE_HELD: + err("invalid state"); + break; + + case TEL_CALL_STATE_DIALING: + command = TCORE_NOTIFICATION_VIDEO_CALL_STATUS_DIALING; + break; + + case TEL_CALL_STATE_ALERT: + command = TCORE_NOTIFICATION_VIDEO_CALL_STATUS_ALERT; + break; + + case TEL_CALL_STATE_INCOMING: + case TEL_CALL_STATE_WAITING: + command = TCORE_NOTIFICATION_VIDEO_CALL_STATUS_INCOMING; + break; + + case TEL_CALL_STATE_IDLE: { + TelCallStatusIdleNoti idle; + command = TCORE_NOTIFICATION_VIDEO_CALL_STATUS_IDLE; + idle.call_id = call_id; + + /* TODO - get proper call end cause. */ + idle.cause = TEL_CALL_END_CAUSE_NONE; + + /* Send notification */ + tcore_object_send_notification(co, command, + sizeof(TelCallStatusIdleNoti), &idle); + + /* Free Call object */ + tcore_call_object_free(co, call_obj); + return; + } + } + } + else { + err("Unknown Call type: [%d]", call_type); + } + + if (command != TCORE_NOTIFICATION_UNKNOWN) + tcore_object_send_notification(co, command, sizeof(call_id), &call_id); +} + +static void __handle_call_list_get(CoreObject *co, gboolean flag, void *data) +{ + int call_id; + int direction; + int call_type; + int state; + int mpty; + int ton; + GSList *tokens = NULL; + char *resp = NULL; + char *line; + char *num = NULL; + int num_type; + char number[TEL_CALL_CALLING_NUMBER_LEN_MAX +1] = {0,}; + GSList *lines = data; + CallObject *call_obj = NULL; + + while (lines != NULL) { + line = (char *)lines->data; + /* point to next node */ + lines = lines->next; + /* free previous tokens*/ + tcore_at_tok_free(tokens); + + tokens = tcore_at_tok_new(line); + + /* */ + resp = g_slist_nth_data(tokens, 0); + if (NULL == resp) { + err("Invalid call_id"); + continue; + } + call_id = atoi(resp); + + /* */ + resp = g_slist_nth_data(tokens, 1); + if (NULL == resp) { + err("Invalid direction"); + continue; + } + direction = (atoi(resp) == 0) ? 1 : 0; + + /* */ + resp = g_slist_nth_data(tokens, 2); + if (NULL == resp) { + err("Invalid state"); + continue; + } + state = __call_state(atoi(resp)); + + /* */ + resp = g_slist_nth_data(tokens, 3); + if (NULL == resp) { + err("Invalid call_type"); + continue; + } + call_type = __call_type(atoi(resp)); + + /* */ + resp = g_slist_nth_data(tokens, 4); + if (NULL == resp) { + err("Invalid mpty"); + continue; + } + mpty = atoi(resp); + + /* */ + resp = g_slist_nth_data(tokens, 5); + if (NULL == resp) { + err("Number is NULL"); + } else { + // Strike off double quotes + num = tcore_at_tok_extract(resp); + dbg("Number: [%s]", num); + + /* */ + resp = g_slist_nth_data(tokens, 6); + if (!resp) { + err("Invalid num type"); + } else { + num_type = atoi(resp); + /* check number is international or national. */ + ton = ((num_type) >> 4) & 0x07; + if (ton == 1 && num[0] != '+') { + /* international number */ + number[0] = '+'; + memcpy(&number[1], num, strlen(num)); + } else { + memcpy(number, num, strlen(num)); + } + } + g_free(num); + } + + dbg("Call ID: [%d] Direction: [%s] Call Type: [%d] Multi-party: [%s] " + "Number: [%s] TON: [%d] State: [%d]", + call_id, (direction ? "Outgoing" : "Incoming"), call_type, + (mpty ? "YES" : "NO"), number, ton, state); + + call_obj = tcore_call_object_find_by_id(co, call_id); + if (NULL == call_obj) { + call_obj = tcore_call_object_new(co, call_id); + if (NULL == call_obj) { + err("unable to create call object"); + continue; + } + } + + /* Set Call parameters */ + tcore_call_object_set_type(call_obj, call_type); + tcore_call_object_set_direction(call_obj, direction); + tcore_call_object_set_multiparty_state(call_obj, mpty); + tcore_call_object_set_cli_info(call_obj, TEL_CALL_CLI_VALIDITY_VALID, number); + tcore_call_object_set_active_line(call_obj, TEL_CALL_ACTIVE_LINE1); + if (flag == TRUE) + __call_branch_by_status(co, call_obj, state); + else + tcore_call_object_set_state(call_obj, state); + } +} + +/* internal notification operation */ +static void __on_notification_imc_call_incoming(CoreObject *co, unsigned int call_id, + void *user_data) +{ + GSList *list = NULL; + CallObject *call_obj = NULL; + dbg("entry"); + + /* check call with incoming status already exist */ + list = tcore_call_object_find_by_status(co, TEL_CALL_STATE_INCOMING); + if (list != NULL) { + err("Incoming call already exist! Skip..."); + g_slist_free(list); + return; + } + g_slist_free(list); + + call_obj = tcore_call_object_find_by_id(co, call_id); + if (call_obj != NULL) { + err("Call object for Call ID [%d] already exist! Skip...", call_id); + return; + } + + /* Create new Call object */ + call_obj = tcore_call_object_new(co, (unsigned int)call_id); + if (NULL == call_obj) { + err("Failed to create Call object"); + return; + } + + /* Make request to get current Call list */ + __call_list_get(co, TRUE); +} + +static void __on_notification_imc_call_status(CoreObject *co, unsigned int call_id, + unsigned int call_state, void *user_data) +{ + CallObject *call_obj = NULL; + TelCallState state; + + state = __call_state(call_state); + dbg("state [%d]", state); + + switch (state) { + case TEL_CALL_STATE_ACTIVE: { + find_call_object(co, call_id, call_obj); + /* Send notification to application */ + __call_branch_by_status(co, call_obj, state); + } + break; + + case TEL_CALL_STATE_HELD: { + find_call_object(co, call_id, call_obj); + /* Send notification to application */ + __call_branch_by_status(co, call_obj, state); + } + break; + + case TEL_CALL_STATE_DIALING: { + call_obj = tcore_call_object_find_by_id(co, call_id); + if (!call_obj) { + call_obj = tcore_call_object_new(co, call_id); + if (!call_obj) { + err("unable to create call object"); + return; + } + } + /* Make request to get current call list.Update CallObject with + * and send notification to application */ + __call_list_get(co, TRUE); + } + break; + + case TEL_CALL_STATE_ALERT: { + find_call_object(co, call_id, call_obj); + /* Send notification to application */ + __call_branch_by_status(co, call_obj, TEL_CALL_STATE_ALERT); + } + break; + + case TEL_CALL_STATE_IDLE: { + find_call_object(co, call_id, call_obj); + /* Send notification to application */ + __call_branch_by_status(co, call_obj, state); + } + break; + + default: + err("invalid call status"); + break; + } +} + +/*internal response operation */ +static void __on_response_imc_call_list_get(TcorePending *p, guint data_len, const void *data, + void *user_data) +{ + const TcoreAtResponse *at_resp = data; + CoreObject *co = tcore_pending_ref_core_object(p); + ImcRespCbData *resp_cb_data = user_data; + GSList *lines = NULL; + TelCallResult result = TEL_CALL_RESULT_FAILURE; //TODO - CME error mapping required + gboolean *flag = IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data); + int count; + dbg("entry"); + + tcore_check_return_assert(co != NULL); + tcore_check_return_assert(resp_cb_data != NULL); + + if (at_resp && at_resp->success) { + result = TEL_CALL_RESULT_SUCCESS; + if (NULL == at_resp->lines) { + err("invalid response received"); + return; + } + + lines = (GSList *) at_resp->lines; + count = g_slist_length(lines); + dbg("Total records : %d", g_slist_length(lines)); + if (0 == count) { + err("Call count is zero"); + return; + } + + dbg("RESPONSE OK"); + + /* parse +CLCC notification parameter */ + __handle_call_list_get(co, *flag, lines); + + } else { + err("RESPONSE NOK"); + } +} + +/*internal request operation */ +static TelReturn __send_call_request(CoreObject *co, TcoreObjectResponseCallback cb, + void *cb_data, gchar *at_cmd, gchar *func_name) +{ + ImcRespCbData *resp_cb_data; + TelReturn ret; + + /* Response callback data */ + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, func_name, strlen(func_name) + 1); + + /* Send Request to modem */ + ret = tcore_at_prepare_and_send_request(co, + at_cmd, NULL, + TCORE_AT_COMMAND_TYPE_NO_RESULT, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_call_default, resp_cb_data, + on_send_imc_request, NULL, + 0, NULL, NULL); + + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, func_name); + + /* Free resources */ + g_free(at_cmd); + return ret; +} + + /* + * Operation - Get current call list. + * + * Request - + * AT-Command: AT+CLCC + * + * Response - + * Success: + *[+CLCC: , , , ,[,,[,[,]]] + *[ +CLCC: ,,,,[,,[,[,]]][Â…]]] + * OK + * Failure: + * +CME ERROR: + */ +static TelReturn __call_list_get(CoreObject *co, gboolean flag) +{ + ImcRespCbData *resp_cb_data; + TelReturn ret =TEL_RETURN_FAILURE; + dbg("Entry"); + + if (NULL == co) { + err("Core Object is NULL"); + return ret; + } + + /* Response callback data */ + resp_cb_data = imc_create_resp_cb_data(NULL, NULL, &flag, sizeof(gboolean)); + + /* Send Request to modem */ + ret = tcore_at_prepare_and_send_request(co, + "AT+CLCC","+CLCC", + TCORE_AT_COMMAND_TYPE_MULTILINE, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + __on_response_imc_call_list_get, resp_cb_data, + on_send_imc_request, NULL, + 0, NULL, NULL); + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Get current call list"); + + return ret; +} + +/* Notification */ + +/* +* Operation - call status notification from network. +* notification message format: +* +XCALLSTAT: +* where +* +* indicates the call identification (GSM02.30 4.5.5.1) +* +* 0 active +* 1 hold +* 2 dialling (MO call) +* 3 alerting (MO call; ringing for the remote party) +* 4 ringing (MT call) +* 5 waiting (MT call) +* 6 disconnected +* 7 connected (indicates the completion of a call setup first time for MT and MO calls – this is reported in +addition to state active) +*/ +static gboolean on_notification_imc_call_status(CoreObject *co, const void *data, + void *user_data) +{ + GSList *tokens = NULL; + GSList *lines = NULL; + const char *line = NULL; + char *state = NULL, *call_handle = NULL; + unsigned int status, call_id; + + dbg("Entry"); + + lines = (GSList *) data; + if (lines == NULL) { + err("Invalid response received"); + return TRUE; + } + line = (char *) (lines->data); + tokens = tcore_at_tok_new(line); + + call_handle = g_slist_nth_data(tokens, 0); + if (NULL == call_handle) { + err("call_id missing from %XCALLSTAT indiaction"); + goto OUT; + } + call_id = atoi(call_handle); + state = g_slist_nth_data(tokens, 1); + if (NULL == state) { + err("State is missing from %XCALLSTAT indication"); + goto OUT; + } + status = atoi(state); + dbg("call_id[%d], status[%d]", call_id, status); + + switch (status) { + case STATUS_INCOMING: + case STATUS_WAITING: + __on_notification_imc_call_incoming(co, call_id, user_data); + break; + + case STATUS_CONNECTED: /* ignore Connected state. */ + dbg("ignore connected state"); + break; + + default: + __on_notification_imc_call_status(co, call_id, status, user_data); + break; + } +OUT: + // Free tokens + tcore_at_tok_free(tokens); + return TRUE; +} + +/* + * Operation - SS network initiated notification. + * + * notification message format: + * +CSSU: [ [,,]] + * + * (it is manufacturer specific, which of these codes are supported): + * 0 this is a forwarded call (MT call setup) + * 1 this is a CUG call ( present) (MT call setup) + * 2 call has been put on hold (during a voice call) + * 3 call has been retrieved (during a voice call) + * 4 multiparty call entered (during a voice call) + * 5 Call has been released - not a SS notification (during a voice call) + * 6 forward check SS message received (can be received whenever) + * 7 call is being connected (alerting) with the remote party in alerting state + * in explicit call transfer operation + * (during a voice call) + * 8 call has been connected with the other remote party in explicit call transfer + * operation (during a voice call or MT call setup) + * 9 this is a deflected call (MT call setup) + * 10 additional incoming call forwarded + * + * refer Closed user group +CCUG + * + * string type phone of format specified by + * + * type of address octet in integer format. + */ +static gboolean on_notification_imc_call_ss_cssu_info(CoreObject *co, const void *event_data, + void *user_data) +{ + GSList *tokens = NULL; + TcoreNotification command = TCORE_NOTIFICATION_UNKNOWN; + char *resp = NULL; + char *cmd = 0; + int index = 0; + int code2 = -1; + char number[TEL_CALL_CALLING_NUMBER_LEN_MAX + 1] = {'\0',}; + + dbg("entry"); + + if (1 != g_slist_length((GSList *) event_data)) { + err("unsolicited msg but multiple line"); + return TRUE; + } + + cmd = (char *) ((GSList *) event_data)->data; + dbg("ss notification message[%s]", cmd); + + tokens = tcore_at_tok_new(cmd); + + /* parse */ + resp = g_slist_nth_data(tokens, 0); + if (NULL == resp) { + err("Code2 is missing from %CSSU indiaction"); + tcore_at_tok_free(tokens); + return TRUE; + } + + code2 = atoi(resp); + + /* parse [ , ] */ + if ((resp = g_slist_nth_data(tokens, 1))) + index = atoi(resp); + + if ((resp = g_slist_nth_data(tokens, 2))) { + /* Strike off double quotes */ + int len = strlen(resp) - 2; + memcpy(number, resp + 1, len); + number[len] = '\0';; + } + + dbg("+CSSU: = %d = %d = %s ", code2, index, number); + + /* - other values will be ignored */ + switch (code2) { + case 0: + command = TCORE_NOTIFICATION_CALL_INFO_MT_FORWARDED; + break; + case 2: + command = TCORE_NOTIFICATION_CALL_INFO_HELD; + break; + case 3: + command = TCORE_NOTIFICATION_CALL_INFO_ACTIVE; + break; + case 4: + command = TCORE_NOTIFICATION_CALL_INFO_JOINED; + break; + case 7: + case 8: + command = TCORE_NOTIFICATION_CALL_INFO_TRANSFERED; + break; + case 9: + command = TCORE_NOTIFICATION_CALL_INFO_MT_DEFLECTED; + break; + default: + dbg("Unsupported +CSSU notification : %d", code2); + break; + } + + if (command != TCORE_NOTIFICATION_UNKNOWN) + tcore_object_send_notification(co, command, 0, NULL); + tcore_at_tok_free(tokens); + + return TRUE; +} + +/* +* Operation - SS network initiated notification. +* notification message format: +* +CSSI : [,] +* where +* +* 0 unconditional call forwarding is active +* 1 some of the conditional call forwarding are active +* 2 call has been forwarded +* 3 call is waiting +* 4 this is a CUG call (also present) +* 5 outgoing calls are barred +* 6 incoming calls are barred +* 7 CLIR suppression rejected +* 8 call has been deflected + +* +* refer Closed user group +CCUG. +*/ +static gboolean on_notification_imc_call_ss_cssi_info(CoreObject *co, const void *event_data, + void *user_data) +{ + GSList *tokens = NULL; + TcoreNotification command = TCORE_NOTIFICATION_UNKNOWN; + char *resp = NULL; + char *cmd = 0; + int index = 0; + int code1 = -1; + + dbg("entry"); + + if (1 != g_slist_length((GSList *) event_data)) { + err("unsolicited msg but multiple line"); + return TRUE; + } + cmd = (char *) ((GSList *) event_data)->data; + dbg("ss notification message[%s]", cmd); + + tokens = tcore_at_tok_new(cmd); + /* parse */ + resp = g_slist_nth_data(tokens, 0); + if (NULL == resp) { + err(" is missing from %CSSI indiaction"); + tcore_at_tok_free(tokens); + return TRUE; + } + + code1 = atoi(resp); + + /* parse [ ] */ + if ((resp = g_slist_nth_data(tokens, 1))) + index = atoi(resp); + + dbg("+CSSI: = %d = %d ", code1, index); + + /* - other values will be ignored */ + switch (code1) { + case 0: + command = TCORE_NOTIFICATION_CALL_INFO_MO_FORWARD_UNCONDITIONAL; + break; + case 1: + command = TCORE_NOTIFICATION_CALL_INFO_MO_FORWARD_CONDITIONAL; + break; + case 2: + command = TCORE_NOTIFICATION_CALL_INFO_MO_FORWARDED; + break; + case 3: + command = TCORE_NOTIFICATION_CALL_INFO_MO_WAITING; + break; + case 5: + command = TCORE_NOTIFICATION_CALL_INFO_MO_BARRED_OUTGOING; + break; + case 6: + command = TCORE_NOTIFICATION_CALL_INFO_MO_BARRED_INCOMING; + break; + case 8: + command = TCORE_NOTIFICATION_CALL_INFO_MO_DEFLECTED; + break; + default: + dbg("Unsupported +CSSI notification : %d", code1); + break; + } + + if (command != TCORE_NOTIFICATION_UNKNOWN) + tcore_object_send_notification(co, command, 0, NULL); + tcore_at_tok_free(tokens); + + return TRUE; +} + +static gboolean on_notification_imc_call_clip_info(CoreObject *co, const void *data, + void *user_data) +{ + dbg("entry"); + /* TODO - handle +CLIP notification*/ + return TRUE; +} + +/* Response */ +static void on_response_imc_call_default(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + CoreObject *co = tcore_pending_ref_core_object(p); + ImcRespCbData *resp_cb_data = user_data; + + TelCallResult result; + dbg("entry"); + + tcore_check_return_assert(co != NULL); + tcore_check_return_assert(resp_cb_data != NULL); + + if (at_resp && at_resp->success) { + result = TEL_CALL_RESULT_SUCCESS; + } else { + err("ERROR[%s]",at_resp->final_response); + result = TEL_CALL_RESULT_FAILURE; + /*TODO - need to map CME error and final response error to TelCallResult */ + } + + dbg("%s: [%s]", IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data), + (result == TEL_CALL_RESULT_SUCCESS ? "SUCCESS" : "FAIL")); + + /* Invoke callback */ + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, NULL, resp_cb_data->cb_data); + + /* Free callback data */ + imc_destroy_resp_cb_data(resp_cb_data); +} + +static void on_response_imc_call_set_volume_info(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + CoreObject *co = tcore_pending_ref_core_object(p); + ImcRespCbData *resp_cb_data = user_data; + GSList *tokens = NULL; + GSList *line = NULL; + char *resp_str = NULL; + gboolean error; + + TelCallResult result = TEL_CALL_RESULT_FAILURE; // TODO: XDRV error mapping is required + dbg("Enter"); + + tcore_check_return_assert(co != NULL); + tcore_check_return_assert(resp_cb_data != NULL); + + if (at_resp && at_resp->success) { + line = at_resp->lines; + tokens = tcore_at_tok_new(line->data); + + if (!g_slist_nth_data(tokens, 0)) { + err("group_id is missing"); + goto OUT; + } + + if (!g_slist_nth_data(tokens, 1)) { + err(" function_id is missing"); + goto OUT; + } + + resp_str = g_slist_nth_data(tokens, 2); + if (!resp_str) { + err("xdrv result missing"); + goto OUT; + } else { + struct imc_set_volume_info *volume_info; + gchar *vol = ""; + gchar *at_cmd; + TelReturn ret; + + error = atoi(resp_str); + if (error) { + err("RESPONSE NOK"); + goto OUT; + } + + /* Fetch from resp_cb_data */ + volume_info = (struct imc_set_volume_info *)IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data); + dbg("volume info index[%d]", volume_info->next_index); + + if (xdrv_set_volume[volume_info->next_index] == NULL) { + /*Processing of xdrv commands completed */ + dbg("RESPONSE OK"); + result = TEL_CALL_RESULT_SUCCESS; + goto OUT; + } else if (volume_info->next_index == 3) { + switch ((volume_info->volume) / 10) { + case 0 : + vol = "0"; + break; + case 1 : + vol = "40"; + break; + case 2 : + vol = "46"; + break; + case 3 : + vol = "52"; + break; + case 4 : + vol = "58"; + break; + case 5 : + vol = "64"; + break; + case 6 : + vol = "70"; + break; + case 7 : + vol = "76"; + break; + case 8 : + vol = "82"; + break; + case 9 : + default : + vol = "88"; + } + } + + at_cmd = g_strdup_printf("%s%s", + xdrv_set_volume[volume_info->next_index], vol); + + /* Increament index to point to next command */ + volume_info->next_index += 1; + + /* Send Request to modem */ + ret = tcore_at_prepare_and_send_request(co, + at_cmd, "+XDRV", + TCORE_AT_COMMAND_TYPE_SINGLELINE, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_call_set_volume_info, resp_cb_data, + on_send_imc_request, NULL, + (guint)0, NULL, NULL); + + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "imc_call_set_volume_info"); + g_free(at_cmd); + + return; + } + } + +OUT : + dbg("Set Volume Info: [%s]", + (result == TEL_CALL_RESULT_SUCCESS ? "SUCCESS" : "FAIL")); + + /* Invoke callback */ + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, NULL, resp_cb_data->cb_data); + + imc_destroy_resp_cb_data(resp_cb_data); + tcore_at_tok_free(tokens); +} + +static void on_response_imc_call_set_sound_path(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + CoreObject *co = tcore_pending_ref_core_object(p); + ImcRespCbData *resp_cb_data = user_data; + GSList *tokens = NULL; + GSList *line = NULL; + char *resp_str = NULL; + gboolean error; + gint xdrv_func_id = -1; + + TelCallResult result = TEL_CALL_RESULT_FAILURE; // TODO: XDRV error mapping is required + dbg("Enter"); + + tcore_check_return_assert(co != NULL); + tcore_check_return_assert(resp_cb_data != NULL); + + if (at_resp && at_resp->success) { + line = at_resp->lines; + tokens = tcore_at_tok_new(line->data); + if (!g_slist_nth_data(tokens, 0)) { + err("group_id is missing"); + goto OUT; + } + + if (!(resp_str = g_slist_nth_data(tokens, 1))) { + err(" function_id is missing"); + goto OUT; + } + + xdrv_func_id = atoi(resp_str); + + resp_str = g_slist_nth_data(tokens, 2); + if (resp_str) { + error = atoi(resp_str); + if (error) { + err("RESPONSE NOK"); + goto OUT; + } else { + if (xdrv_func_id == 4) { + /* Send next command to configure destination device type */ + gchar *at_cmd; + TelReturn ret; + gint *device_type = IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data); + + at_cmd = g_strdup_printf("AT+XDRV=40,5,2,0,0,0,0,0,1,0,1,0,%d", + *device_type); + + ret = tcore_at_prepare_and_send_request(co, + at_cmd, "+XDRV", + TCORE_AT_COMMAND_TYPE_SINGLELINE, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_call_set_sound_path, resp_cb_data, + on_send_imc_request, NULL, + (guint)0, NULL, NULL); + + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "imc_call_set_sound_path"); + g_free(at_cmd); + + return; + } + dbg("RESPONSE OK"); + result = TEL_CALL_RESULT_SUCCESS; + } + } + } + +OUT : + dbg("Set Sound Path: [%s]", + (result == TEL_CALL_RESULT_SUCCESS ? "SUCCESS" : "FAIL")); + + tcore_at_tok_free(tokens); + + /* Invoke callback */ + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, NULL, resp_cb_data->cb_data); + + imc_destroy_resp_cb_data(resp_cb_data); +} + +static void on_response_imc_call_set_mute(TcorePending *p, guint data_len, + const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + CoreObject *co = tcore_pending_ref_core_object(p); + ImcRespCbData *resp_cb_data = user_data; + GSList *tokens = NULL; + const char *line = NULL; + char *resp_str = NULL; + gboolean error; + + TelCallResult result = TEL_CALL_RESULT_FAILURE; // TODO: XDRV error mapping is required + dbg("Enter"); + + tcore_check_return_assert(co != NULL); + tcore_check_return_assert(resp_cb_data != NULL); + + if (at_resp && at_resp->success) { + result = TEL_CALL_RESULT_SUCCESS; + line = (((GSList *)at_resp->lines)->data); + tokens = tcore_at_tok_new(line); + + resp_str = g_slist_nth_data(tokens, 0); + if (!g_slist_nth_data(tokens, 0)) { + err("group_id is missing"); + result = TEL_CALL_RESULT_FAILURE; + goto OUT; + } + + if (!g_slist_nth_data(tokens, 1)) { + err(" function_id is missing"); + result = TEL_CALL_RESULT_FAILURE; + goto OUT; + } + + resp_str = g_slist_nth_data(tokens, 2); + if (resp_str) { + error = atoi(resp_str); + if (error) { + result = TEL_CALL_RESULT_FAILURE; + goto OUT; + } else { + result = TEL_CALL_RESULT_SUCCESS; + } + } + } + +OUT : + dbg("Set Mute: [%s]", + (result == TEL_CALL_RESULT_SUCCESS ? "SUCCESS" : "FAIL")); + tcore_at_tok_free(tokens); + + /* Invoke callback */ + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, NULL, resp_cb_data->cb_data); + + imc_destroy_resp_cb_data(resp_cb_data); +} + + + /* Request */ + /* + * Operation - dial + * + * Request - + * AT-Command: ATD [I] [G] [;] + * - dialed number + * [I][i] - CLI presentation(supression or invocation) + * [G] - control the CUG supplementary service information for this call. + * + * Response - + * Success: + * OK or CONNECT + * Failure: + * "ERROR" + * "NO ANSWER" + * "NO CARRIER" + * "BUSY" + * "NO DIALTONE" + * +CME ERROR: + */ +static TelReturn imc_call_dial(CoreObject *co, const TelCallDial *dial_info, + TcoreObjectResponseCallback cb, void *cb_data) +{ + gchar *at_cmd; + const gchar *clir; + gchar *num; + + dbg("entry"); + + if (dial_info->call_type == TEL_CALL_TYPE_VIDEO) { + err("Video call is not supported in imc modem"); + return TEL_RETURN_OPERATION_NOT_SUPPORTED; + } + + if (!strncmp(dial_info->number, "*31#", 4)) { + dbg("clir suppression"); + clir = "i"; + num = (gchar *)&(dial_info->number[4]); + } else if (!strncmp(dial_info->number, "#31#", 4)) { + dbg("clir invocation"); + clir = "I"; + num = (gchar *)&(dial_info->number[4]); + } else { + int cli = 0; + + dbg("no clir string in number"); + + /* it will be removed when setting application use tapi_ss_set_cli() + * instead of his own vconfkey. (0 : By network, 1 : Show, 2 : Hide) + */ + vconf_get_int("db/ciss/show_my_number", &cli); + if(cli == 2){ + dbg("clir invocation from setting application"); + clir = "I"; + } else { + dbg("set clir state to default"); + clir = ""; + } + num = (gchar *)dial_info->number; + } + + /* AT-Command */ + at_cmd = g_strdup_printf("ATD%s%s;", num, clir); + dbg(" at command : %s", at_cmd); + + return __send_call_request(co, cb, cb_data, at_cmd, "imc_call_dial"); +} + +/* + * Operation - Answer/Reject/Replace/hold(current call) & accept incoming call. + * + * Request - + * + * 1. AT-Command: ATA + * Response - + * Success: + * OK + * Failure: + * +CME ERROR: + * + * 2. AT-Command: AT+CHLD=[] + * + * 0 - (deafult)release all held calls or set User Determined User Busy for a waiting/incoming + * call; if both exists then only the waiting call will be rejected. + * 1 - release all active calls and accepts the other (held or waiting) + * Note: In the scenario: An active call, a waiting call and held call, when the active call is + * terminated, we will make the Waiting call as active. + * 2 - place all active calls (if exist) on hold and accepts the other call (held or waiting/in-coming). + * If only one call exists which is active, place it on hold and if only held call exists make it active call. + * Response - + * Success: + * OK + * Failure: + * +CME ERROR: + * For more informatiion refer 3GPP TS 27.007. + */ +static TelReturn imc_call_answer(CoreObject *co, TelCallAnswerType ans_type, + TcoreObjectResponseCallback cb, void *cb_data) +{ + gchar *at_cmd; + dbg("entry"); + + if (ans_type == TEL_CALL_ANSWER_ACCEPT) { + /* AT-Command */ + at_cmd = g_strdup_printf("%s", "ATA"); + }else if (ans_type == TEL_CALL_ANSWER_REJECT) { + /* AT-Command */ + at_cmd = g_strdup_printf("%s", "AT+CHLD=0"); + } else if (ans_type == TEL_CALL_ANSWER_REPLACE) { + /* AT-Command */ + at_cmd = g_strdup_printf("%s", "AT+CHLD=1"); + } else if (ans_type == TEL_CALL_ANSWER_HOLD_AND_ACCEPT) { + /* AT-Command */ + at_cmd = g_strdup_printf("%s", "AT+CHLD=2"); + }else { + err("Unsupported call answer type"); + return TEL_RETURN_FAILURE; + } + + dbg("at command : %s", at_cmd); + + return __send_call_request(co, cb, cb_data, at_cmd, "imc_call_answer"); +} + +/* + * Operation - release all calls/release specific call/release all active call/release all held calls. + * + * Request - + * 1. AT-Command: AT+CHLD=[] + * + * 0 - (defualt)release all held calls or set User Determined User Busy for a waiting/incoming. + * call; if both exists then only the waiting call will be rejected. + * 1 - release all active calls and accepts the other (held or waiting). + * 1x - release a specific call (x specific call number as indicated by call id). + * 8 - release all calls. + * Response - + * Success: + * OK + * Failure: + * +CME ERROR: + */ +static TelReturn imc_call_end(CoreObject *co, const TelCallEnd *end_info, + TcoreObjectResponseCallback cb, void *cb_data) +{ + gchar *at_cmd; + dbg("entry"); + + if (end_info->end_type == TEL_CALL_END_ALL) { + /* AT-Command */ + at_cmd = g_strdup_printf("%s", "AT+CHLD=8"); + }else if (end_info->end_type == TEL_CALL_END) { + /* AT-Command */ + at_cmd = g_strdup_printf("%s%d", "AT+CHLD=1",end_info->call_id); + } else if (end_info->end_type == TEL_CALL_END_ACTIVE_ALL) { + /* AT-Command */ + at_cmd = g_strdup_printf("%s", "AT+CHLD=1"); + } else if (end_info->end_type == TEL_CALL_END_HOLD_ALL) { + /* AT-Command */ + at_cmd = g_strdup_printf("%s", "AT+CHLD=0"); + }else { + err("Unsupported call end type"); + return TEL_RETURN_FAILURE; + } + + dbg("at command : %s", at_cmd); + + return __send_call_request(co, cb, cb_data, at_cmd, "imc_call_end"); +} + +/* + * Operation - send dtmf. + * + * Request - + * 1. AT-Command: AT+VTS=,{,}. + * where + * : + * is a single ASCII character in the set 0-9, #, *, A-D. Even it will support string DTMF. + * : + * integer in range 0-255, meaning 1/10(10 millisec) seconds multiples. The string parameter + * of the command consists of combinations of the following separated by commas: + * NOTE : There is a limit of 50 dtmf tones can be requested through a single VTS command. + * Response - + * Success: + * OK + * Failure: + * +CME ERROR: + */ +static TelReturn imc_call_send_dtmf(CoreObject *co, const char *dtmf_str, + TcoreObjectResponseCallback cb, void *cb_data) +{ + gchar *at_cmd; + char *tmp_dtmf = NULL, *dtmf; + unsigned int count; + + dbg("entry"); + + //(void) _set_dtmf_tone_duration(o, dup); + tmp_dtmf = tcore_malloc0((strlen(dtmf_str) * 2) + 1); // DTMF digits + comma for each dtmf digit. + tcore_check_return_value_assert(tmp_dtmf != NULL, TEL_RETURN_FAILURE); + /* Save initial pointer */ + dtmf = tmp_dtmf; + + for (count = 0; count < strlen(dtmf_str); count++) { + *tmp_dtmf = dtmf_str[count]; + tmp_dtmf++; + + *tmp_dtmf = COMMA; + tmp_dtmf++; + } + + // last digit is having COMMA , overwrite it with '\0' . + *(--tmp_dtmf) = '\0'; + + // AT+VTS = ,,,,,, ..... + at_cmd = g_strdup_printf("AT+VTS=%s", dtmf); + dbg("at command : %s", at_cmd); + + tcore_free(dtmf); + + return __send_call_request(co, cb, cb_data, at_cmd, "imc_call_send_dtmf"); +} + +/* + * Operation - call hold. + * + * Request - + * 1. AT-Command: AT+CHLD=[] + * Where + * + * 2 - place all active calls (if exist) on hold and accepts the other call (held or waiting/incoming). + * If only one call exists which is active, place it on hold and if only held call exists + * make it active call + * Response - + * Success: + * OK + * Failure: + * +CME ERROR: + */ +static TelReturn imc_call_hold(CoreObject *co, TcoreObjectResponseCallback cb, + void *cb_data) + +{ + gchar *at_cmd; + dbg("entry"); + + at_cmd = g_strdup_printf("%s", "AT+CHLD=2"); + dbg("at command : %s", at_cmd); + + return __send_call_request(co, cb, cb_data, at_cmd, "imc_call_hold"); +} + +/* + * Operation - call active. + * + * Request - + * 1. AT-Command: AT+CHLD=[] + * Where + * + * 2 - place all active calls (if exist) on hold and accepts the other call (held or waiting/incoming). + * If only one call exists which is active, place it on hold and if only held call exists + * make it active call + * Response - + * Success: + * OK + * Failure: + * +CME ERROR: + */ +static TelReturn imc_call_active(CoreObject *co, TcoreObjectResponseCallback cb, + void *cb_data) +{ + gchar *at_cmd; + dbg("entry"); + + at_cmd = g_strdup_printf("%s", "AT+CHLD=2"); + dbg("at command : %s", at_cmd); + + return __send_call_request(co, cb, cb_data, at_cmd, "imc_call_active"); +} + +/* + * Operation - call swap. + * + * Request - + * 1. AT-Command: AT+CHLD=[] + * Where + * + * 2 - place all active calls (if exist) on hold and accepts the other call (held or waiting/incoming). + * If only one call exists which is active, place it on hold and if only held call exists + * make it active call + * Response - + * Success: + * OK + * Failure: + * +CME ERROR: + */ +static TelReturn imc_call_swap(CoreObject *co, TcoreObjectResponseCallback cb, + void *cb_data) +{ + gchar *at_cmd; + dbg("entry"); + + at_cmd = g_strdup_printf("%s", "AT+CHLD=2"); + dbg("at command : %s", at_cmd); + + return __send_call_request(co, cb, cb_data, at_cmd, "imc_call_swap"); +} + +/* + * Operation - call join. + * + * Request - + * 1. AT-Command: AT+CHLD=[] + * Where + * + * 3 - adds a held call to the conversation + * Response - + * Success: + * OK + * Failure: + * +CME ERROR: + */ +static TelReturn imc_call_join(CoreObject *co, TcoreObjectResponseCallback cb, + void *cb_data) +{ + gchar *at_cmd; + dbg("entry"); + + at_cmd = g_strdup_printf("%s", "AT+CHLD=3"); + dbg("at command : %s", at_cmd); + + return __send_call_request(co, cb, cb_data, at_cmd, "imc_call_join"); +} + +/* + * Operation - call split. + * + * Request - + * 1. AT-Command: AT+CHLD=[] + * Where + * + * 2x - place all active calls on hold except call x with which communication is supported + * Response - + * Success: + * OK + * Failure: + * +CME ERROR: + */ +static TelReturn imc_call_split(CoreObject *co, unsigned int call_id, + TcoreObjectResponseCallback cb, void *cb_data) +{ + gchar *at_cmd; + dbg("entry"); + + at_cmd = g_strdup_printf("%s%d", "AT+CHLD=2", call_id); + dbg("at command : %s", at_cmd); + + return __send_call_request(co, cb, cb_data, at_cmd, "imc_call_split"); +} + +/* + * Operation - call transfer. + * + * Request - + * 1. AT-Command: AT+CHLD=[] + * Where + * + * 4 connects the two calls and disconnects the subscriber from both calls (Explicit Call Transfer) + * Response - + * Success: + * OK + * Failure: + * +CME ERROR: + */ +static TelReturn imc_call_transfer(CoreObject *co, TcoreObjectResponseCallback cb, + void *cb_data) +{ + gchar *at_cmd; + dbg("entry"); + + at_cmd = g_strdup_printf("%s", "AT+CHLD=4"); + dbg("at command : %s", at_cmd); + + return __send_call_request(co, cb, cb_data, at_cmd, "imc_call_transfer"); +} + +/* + * Operation - call transfer. + * + * Request - + * 1. AT-Command: AT+CTFR= [,] + * Where + * number> + * string type phone number + * + * type of address octet in integer format. It is optional parameter. + * + * Response - + * Success: + * OK + * Failure: + * +CME ERROR: + */ +static TelReturn imc_call_deflect(CoreObject *co, const char *deflect_to, + TcoreObjectResponseCallback cb, void *cb_data) +{ + gchar *at_cmd; + dbg("entry"); + + at_cmd = g_strdup_printf("AT+CTFR=%s", deflect_to); + dbg("at command : %s", at_cmd); + + return __send_call_request(co, cb, cb_data, at_cmd, "imc_call_deflect"); +} + +static TelReturn imc_call_set_active_line(CoreObject *co, TelCallActiveLine active_line, + TcoreObjectResponseCallback cb, void *cb_data) +{ + dbg("entry"); + + dbg("exit"); + return TEL_RETURN_OPERATION_NOT_SUPPORTED; +} + +static TelReturn imc_call_get_active_line(CoreObject *co, TcoreObjectResponseCallback cb, + void *cb_data) +{ + dbg("entry"); + + dbg("exit"); + return TEL_RETURN_OPERATION_NOT_SUPPORTED; +} + +/* + * Operation - Set voule info. + * + * Request - + * AT-Command: AT+XDRV=,[,] + * The first command parameter defines the involved driver group. + * The second command parameter defines a certain function in the selected driver group. + * Other parameters are dependent on the first two parameters. + * Nearly all parameters are integer values, also if they are represented by literals. + * Only very few are strings or + * hex data strings. + * + * Response - + * +XDRV: ,,[,] + * The first response parameter defines the involved driver group. + * The second response parameter defines the current function in the selected driver group. + * The third response parameter defines the xdrv_result of the operation. + * Additional response parameters dependent on the first two parameters. + */ +static TelReturn imc_call_set_volume_info(CoreObject *co, const TelCallVolumeInfo *volume_info, + TcoreObjectResponseCallback cb, void *cb_data) +{ + ImcRespCbData *resp_cb_data = NULL; + gchar *at_cmd; + TelReturn ret; + struct imc_set_volume_info cb_volume_info; + + dbg("entry"); + + cb_volume_info.next_index = 1; + cb_volume_info.volume = volume_info->volume; + + /* Response callback data */ + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, + &cb_volume_info, sizeof(struct imc_set_volume_info)); + + at_cmd = g_strdup_printf("%s", xdrv_set_volume[0]); + + /* Send Request to modem */ + ret = tcore_at_prepare_and_send_request(co, + at_cmd, "+XDRV", + TCORE_AT_COMMAND_TYPE_SINGLELINE, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_call_set_volume_info, resp_cb_data, + on_send_imc_request, NULL, + (guint)0, NULL, NULL); + + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "imc_call_set_volume_info"); + + g_free(at_cmd); + return ret; +} + + +static TelReturn imc_call_get_volume_info(CoreObject *co, TelCallSoundDevice sound_device, + TcoreObjectResponseCallback cb, void *cb_data) +{ + dbg("Entry"); + + dbg("Exit"); + return TEL_RETURN_OPERATION_NOT_SUPPORTED; +} + +/* + * Operation - Set sound path. + * + * Request - + * AT-Command: AT+XDRV=,[,] + * The first command parameter defines the involved driver group. + * The second command parameter defines a certain function in the selected driver group. + * Other parameters are dependent on the first two parameters. + * Nearly all parameters are integer values, also if they are represented by literals. + * Only very few are strings or + * hex data strings. + * + * Response - + * +XDRV: ,,[,] + * The first response parameter defines the involved driver group. + * The second response parameter defines the current function in the selected driver group. + * The third response parameter defines the xdrv_result of the operation. + * Additional response parameters dependent on the first two parameters. + */ + +static TelReturn imc_call_set_sound_path(CoreObject *co, const TelCallSoundPathInfo *sound_path_info, + TcoreObjectResponseCallback cb, void *cb_data) +{ + ImcRespCbData *resp_cb_data = NULL; + TelReturn ret; + gchar *at_cmd; + gint device_type = -1; + + dbg("audio device type - 0x%x", sound_path_info->path); + + switch (sound_path_info->path) { + case TEL_SOUND_PATH_HANDSET: + device_type = 1; + break; + case TEL_SOUND_PATH_HEADSET: + device_type = 2; + break; + case TEL_SOUND_PATH_HEADSET_3_5PI: + device_type = 3; + break; + case TEL_SOUND_PATH_SPK_PHONE: + device_type = 4; + break; + case TEL_SOUND_PATH_HANDSFREE: + device_type = 5; + break; + case TEL_SOUND_PATH_HEADSET_HAC: + device_type = 6; + break; + case TEL_SOUND_PATH_BLUETOOTH: + case TEL_SOUND_PATH_STEREO_BLUETOOTH: + device_type = 7; + break; + case TEL_SOUND_PATH_BT_NSEC_OFF: + case TEL_SOUND_PATH_MIC1: + case TEL_SOUND_PATH_MIC2: + default: + dbg("unsupported device type"); + return TEL_RETURN_INVALID_PARAMETER; + } + + /* Response callback data */ + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, &device_type, sizeof(gint)); + + at_cmd = g_strdup_printf("AT+XDRV=40,4,3,0,0,0,0,0,1,0,1,0,%d", device_type); + + ret = tcore_at_prepare_and_send_request(co, + at_cmd, "+XDRV", + TCORE_AT_COMMAND_TYPE_SINGLELINE, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_call_set_sound_path, resp_cb_data, + on_send_imc_request, NULL, + (guint)0, NULL, NULL); + + IMC_CHECK_REQUEST_RET(ret, NULL, "imc_call_set_sound_path"); + g_free(at_cmd); + + return ret; +} + +/* + * Operation - Set/Unset mute status. + * + * Request - + * AT-Command: AT+XDRV=,[,] + * The first command parameter defines the involved driver group. + * The second command parameter defines a certain function in the selected driver group. + * Other parameters are dependent on the first two parameters. + * Nearly all parameters are integer values, also if they are represented by literals. + * Only very few are strings or + * hex data strings. + * + * Response - + * +XDRV: ,,[,] + * The first response parameter defines the involved driver group. + * The second response parameter defines the current function in the selected driver group. + * The third response parameter defines the xdrv_result of the operation. + * Additional response parameters dependent on the first two parameters. + */ +static TelReturn imc_call_set_mute(CoreObject *co, gboolean mute, TcoreObjectResponseCallback cb, + void *cb_data) +{ + ImcRespCbData *resp_cb_data = NULL; + gchar *at_cmd; + TelReturn ret; + + dbg("entry"); + + /* Response callback data */ + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, NULL, 0); + + /* AT - Command */ + if (mute) + at_cmd = g_strdup_printf("%s", "AT+XDRV=40,8,0,0,0"); /*MUTE*/ + else + at_cmd = g_strdup_printf("%s", "AT+XDRV=40,8,0,0,88"); /*UNMUTE*/ + + /* Send Request to modem */ + ret = tcore_at_prepare_and_send_request(co, + at_cmd, "+XDRV", + TCORE_AT_COMMAND_TYPE_SINGLELINE, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_call_set_mute, resp_cb_data, + on_send_imc_request, NULL, + (guint)0, NULL, NULL); + + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "imc_call_set_mute"); + + g_free(at_cmd); + + return ret; +} + +static TelReturn imc_call_get_mute_status(CoreObject *co, TcoreObjectResponseCallback cb, + void *cb_data) +{ + dbg("entry"); + + dbg("exit"); + return TEL_RETURN_OPERATION_NOT_SUPPORTED; +} + + +static TelReturn imc_call_set_sound_recording(CoreObject *co, TelCallSoundRecording sound_rec, + TcoreObjectResponseCallback cb, void *cb_data) +{ + dbg("entry"); + + dbg("exit"); + return TEL_RETURN_OPERATION_NOT_SUPPORTED; +} + +static TelReturn imc_call_set_sound_equalization(CoreObject *co, const TelCallSoundEqualization *sound_eq, + TcoreObjectResponseCallback cb, void *cb_data) +{ + dbg("entry"); + + dbg("exit"); + return TEL_RETURN_OPERATION_NOT_SUPPORTED; +} + +/* Call Operations */ +static TcoreCallOps imc_call_ops = { + .dial = imc_call_dial, + .answer = imc_call_answer, + .end = imc_call_end, + .send_dtmf = imc_call_send_dtmf, + .hold = imc_call_hold, + .active = imc_call_active, + .swap = imc_call_swap, + .join = imc_call_join, + .split = imc_call_split, + .transfer = imc_call_transfer, + .deflect = imc_call_deflect, + .set_active_line = imc_call_set_active_line, + .get_active_line = imc_call_get_active_line, + .set_volume_info = imc_call_set_volume_info, + .get_volume_info = imc_call_get_volume_info, + .set_sound_path = imc_call_set_sound_path, + .set_mute = imc_call_set_mute, + .get_mute_status = imc_call_get_mute_status, + .set_sound_recording = imc_call_set_sound_recording, + .set_sound_equalization = imc_call_set_sound_equalization, +}; + +gboolean imc_call_init(TcorePlugin *p, CoreObject *co) +{ + dbg("Entry"); + + /* Set operations */ + tcore_call_set_ops(co, &imc_call_ops); + + /* Add Callbacks */ + tcore_object_add_callback(co, "+XCALLSTAT", on_notification_imc_call_status, NULL); + tcore_object_add_callback(co, "+CLIP", on_notification_imc_call_clip_info, NULL); + tcore_object_add_callback(co, "+CSSU", on_notification_imc_call_ss_cssu_info, NULL); + tcore_object_add_callback(co, "+CSSI", on_notification_imc_call_ss_cssi_info, NULL); + + return TRUE; +} + +void imc_call_exit(TcorePlugin *p, CoreObject *co) +{ + dbg("Exit"); +} diff --git a/src/s_common.c b/src/imc_common.c similarity index 84% rename from src/s_common.c rename to src/imc_common.c index f07f003..a4b51fb 100644 --- a/src/s_common.c +++ b/src/imc_common.c @@ -1,9 +1,7 @@ /* * tel-plugin-imc * - * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved. - * - * Contact: Ja-young Gu + * Copyright (c) 2013 Samsung Electronics Co. Ltd. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,15 +17,44 @@ */ #include -#include #include +#include #include + #include +#include + +#include "imc_common.h" + +void on_send_imc_request(TcorePending *p, + TelReturn send_status, void *user_data) +{ + dbg("Send - [%s]", + (send_status == TEL_RETURN_SUCCESS ? "OK" : "NOK")); +} + +ImcRespCbData *imc_create_resp_cb_data(TcoreObjectResponseCallback cb, + void *cb_data, void *data, guint data_len) +{ + ImcRespCbData *resp_cb_data; + resp_cb_data = tcore_malloc0(sizeof(ImcRespCbData) + data_len); + resp_cb_data->cb = cb; + resp_cb_data->cb_data = cb_data; + if ((data != NULL) && (data_len > 0)) + memcpy(resp_cb_data->data, data, data_len); -#include "s_common.h" + return resp_cb_data; +} + +void imc_destroy_resp_cb_data(ImcRespCbData *resp_cb_data) +{ + if (resp_cb_data) + tcore_free(resp_cb_data); +} +#if 0 #undef MAX #define MAX(a, b) (((a) > (b)) ? (a) : (b)) @@ -210,3 +237,4 @@ char* util_removeQuotes(void *data) return tmp; } +#endif diff --git a/src/s_gps.c b/src/imc_gps.c similarity index 76% rename from src/s_gps.c rename to src/imc_gps.c index c2517c7..c567a7c 100644 --- a/src/s_gps.c +++ b/src/imc_gps.c @@ -1,9 +1,7 @@ /* * tel-plugin-imc * - * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved. - * - * Contact: sharanayya mathapati + * Copyright (c) 2013 Samsung Electronics Co. Ltd. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,35 +26,38 @@ #include #include -#include -#include +#include #include +#include +#include #include -#include -#include -#include -#include +#include #include +#include + + #include #include #include + #include +#include -#include "s_common.h" -#include "s_gps.h" +#include "imc_gps.h" +#include "imc_common.h" -#define POSITION_NODE "pos" -#define POSITION_NODE_ATTR_XSI "xsi:noNamespaceSchemaLocation" -#define POSITION_NODE_ATTR_VAL_XSI "pos.xsd" -#define POSITION_NODE_ATTR_XMLNS "xmlns:xsi" -#define POSITION_NODE_ATTR_VAL_XMLNS "http://www.w3.org/2001/XMLSchema-instance" +#define POSITION_NODE "pos" +#define POSITION_NODE_ATTR_XSI "xsi:noNamespaceSchemaLocation" +#define POSITION_NODE_ATTR_VAL_XSI "pos.xsd" +#define POSITION_NODE_ATTR_XMLNS "xmlns:xsi" +#define POSITION_NODE_ATTR_VAL_XMLNS "http://www.w3.org/2001/XMLSchema-instance" #define MAX_NUM_OF_GPS_REF_TIME_ELEMENT 12 // max number of gps satalite -#define MAX_NUM_OF_GPS_NAV_ELEMENT 16 // max num of navigation gps element. -#define MAX_NUM_OF_GPS_ALMANC_ELEMENTS 64 // Max num of almanc elements. +#define MAX_NUM_OF_GPS_NAV_ELEMENT 16 // max num of navigation gps element. +#define MAX_NUM_OF_GPS_ALMANC_ELEMENTS 64 // Max num of almanc elements. -#define NUM_OF_ELEMENTS(array) (sizeof(array) / sizeof(*(array))) +#define NUM_OF_ELEMENTS(array) (sizeof(array) / sizeof(*(array))) static char node_name[128]; // max len of xml node static char node_value[128]; // max len of xml node value. @@ -121,7 +122,7 @@ typedef struct { unsigned long int gpsTow; unsigned long int gpsWeek; unsigned char nrOfSats; - union { // Not supported. + union { // Not supported. gps_gsm_time_t gsm_time; gps_utran_time_t UtranTime; } networkTimeInfo; @@ -180,35 +181,35 @@ typedef struct { } __attribute__((packed)) gps_navi_subframe_rsv_t; typedef struct { - unsigned char ephemCodeOnL2; // 0~3 - unsigned char ephemUra; // 0~15 - unsigned char ephemSvHealth; // 0~63 - unsigned short ephemIodc; // 0~1023 - unsigned char ephemL2PFlag; // 0~1 + unsigned char ephemCodeOnL2; // 0~3 + unsigned char ephemUra; // 0~15 + unsigned char ephemSvHealth; // 0~63 + unsigned short ephemIodc; // 0~1023 + unsigned char ephemL2PFlag; // 0~1 gps_navi_subframe_rsv_t NavigationSubFrameRsv; - signed char ephemTgd; // -128~127 - unsigned short ephemToc; // 0~37799 - signed char ephemAf2; // -128~12 - signed short ephemAf1; // -32768~32767 - signed long int ephemAf0; // -2097152~2097151 - signed short ephemCrs; // -32768~32767 - signed short ephemDeltaN; // -32768~32767 - signed long int ephemM0; // -2147483648~2147483647 - signed short ephemCuc; // -32768~32767 - unsigned long int ephemE; // 0~4294967295 - signed short ephemCus; // -32768~32767 - unsigned long int ephemAPowrHalf; // 0~4294967295 - unsigned short ephemToe; // 0~37799 - signed char ephemFitFlag; // 0~1 - unsigned char ephemAoda; // 0~31 - signed short ephemCic; // -32768~32767 - signed long int ephemOmegaA0; // -2147483648~2147483647 - signed short ephemCis; // -32768~32767 - signed long int ephemI0; // -2147483648~2147483647 - signed short ephemCrc; // -32768~32767 - signed long int ephemW; // -2147483648~2147483647 - signed long int ephemOmegaADot; // -8388608~8388607 - signed short ephemIDot; // -8192~8191 + signed char ephemTgd; // -128~127 + unsigned short ephemToc; // 0~37799 + signed char ephemAf2; // -128~12 + signed short ephemAf1; // -32768~32767 + signed long int ephemAf0; // -2097152~2097151 + signed short ephemCrs; // -32768~32767 + signed short ephemDeltaN; // -32768~32767 + signed long int ephemM0; // -2147483648~2147483647 + signed short ephemCuc; // -32768~32767 + unsigned long int ephemE; // 0~4294967295 + signed short ephemCus; // -32768~32767 + unsigned long int ephemAPowrHalf; // 0~4294967295 + unsigned short ephemToe; // 0~37799 + signed char ephemFitFlag; // 0~1 + unsigned char ephemAoda; // 0~31 + signed short ephemCic; // -32768~32767 + signed long int ephemOmegaA0; // -2147483648~2147483647 + signed short ephemCis; // -32768~32767 + signed long int ephemI0; // -2147483648~2147483647 + signed short ephemCrc; // -32768~32767 + signed long int ephemW; // -2147483648~2147483647 + signed long int ephemOmegaADot; // -8388608~8388607 + signed short ephemIDot; // -8192~8191 } __attribute__((packed)) gps_navi_ephe_t; typedef enum { @@ -258,16 +259,16 @@ typedef struct { signed char dataId; // only for 3G, 0~3, if this value is -1, it means this value is invalid unsigned char satId; unsigned short almanacE; // 0~65536 - unsigned char almanacToa; // 0~255 - signed short almanacKsii; // -32768~3276 - signed short almanacOmegaDot; // -32768~3276 - unsigned char almanacSvHealth; // 0~255 + unsigned char almanacToa; // 0~255 + signed short almanacKsii; // -32768~3276 + signed short almanacOmegaDot; // -32768~3276 + unsigned char almanacSvHealth; // 0~255 unsigned long int almanacAPowerHalf; // 0~16777215 signed long int almanacOmega0; // -8388608~8388607 signed long int almanacW; // -8388608~8388607 signed long int almanacM0; // -8388608~8388607 - signed short almanacAf0; // -1024~1023 - signed short almanacAf1; // -1024~1023 + signed short almanacAf0; // -1024~1023 + signed short almanacAf1; // -1024~1023 } __attribute__((packed)) gps_almanac_sat_info_t; typedef struct { @@ -297,10 +298,10 @@ typedef struct { typedef struct { unsigned long int gpsTow; - union { + union { gps_gsm_time_t gsm_time; gps_acq_utran_time_t AcqUtranTime; - } acquisitionTimeInfo; // --- not supported. + } acquisitionTimeInfo; // --- not supported. unsigned long int numberOfSat; gps_acq_sat_info_t lcsAcquisitionSatInfo[16]; } __attribute__((packed)) gps_acq_assist_t; @@ -553,53 +554,12 @@ static t_element elements[] = { {"acqu_assist", ACQU_ASSIST}, }; - -/************************************************************************** -* Local Function Prototypes -**************************************************************************/ - -static inline int _modem_sat_status_info_2_tel_sat_info(char *sat_info); - -static inline int _modem_acqa_assit_doppler_2_tel_doppler(char *doppler_info); - -static int _gps_element_compare(char *element[], char *element_str, int nelem); - -static enum gps_assist_element_type _get_element_type(char *element_str); - -static void _parse_ref_time_gps_elements(char *element_str, char *element_value, gps_assist_data_noti_t *gpsdata_assist, gboolean GPS_TOW_assist, int count); - -static void _parse_location_parameters(char *element_str, char *element_value, gps_assist_data_noti_t *gpsdata_assist); - -static void _parse_dgps_correction_gps_elements(char *element_str, char *element_value, gps_assist_data_noti_t *gpsdata_assist); - -static void _parse_ionospheric_model_gps_elements(char *element_str, char *element_value, gps_assist_data_noti_t *gpsdata_assist); - -static void _parse_utc_model_gps_elements(char *element_str, char *element_value, gps_assist_data_noti_t *gpsdata_assist); - -static void _parse_almanc_model_gps_elements(char *element_str, char *element_value, gps_assist_data_noti_t *gpsdata_assist, gboolean alm_elem, int count); - -static void _parse_acqu_assist_gps_elements(char *element_str, char *element_value, gps_assist_data_noti_t *gpsdata_assist); - -static void _parse_nav_model_gps_elements(char *element_str, char *element_value, gps_assist_data_noti_t *gpsdata_assist, gboolean ephem_and_clock, int element_count); - -static void _set_coordinate(xmlNodePtr node, gps_ellipsoid_po_t *point, int isalt, int altitude); - -static void _set_loc_info_ellipse_elements(xmlNodePtr node, void *elliplse, int is_unc_ellipse); - -static xmlChar* _generate_confirm_measure_pos_xml_text(gps_measure_position_confirm_t *gps_measure_position_confirm); - -static gboolean on_notification_gps_measure_position_from_modem(CoreObject *o, char *file_name, void *user_data); - -/************************************************************************** -* Local Function Definitions - **************************************************************************/ - static inline int _modem_sat_status_info_2_tel_sat_info(char *sat_info) { int count; for (count = 0; count < (int) (sizeof(sat_status_info_table) / sizeof(sat_status_info_t)); count++) { - if (strcmp(sat_status_info_table[count].psat_status, sat_info) == 0) + if (g_strcmp0(sat_status_info_table[count].psat_status, sat_info) == 0) return (sat_status_info_table[count].stat_status); } return (-1); @@ -610,7 +570,7 @@ static inline int _modem_acqa_assit_doppler_2_tel_doppler(char *doppler_info) int count; for (count = 0; count < (int) (sizeof(doppler_status_info_table) / sizeof(doppler_status_info_t)); count++) { - if (strcmp(doppler_status_info_table[count].pdoppler_status, doppler_info) == 0) + if (g_strcmp0(doppler_status_info_table[count].pdoppler_status, doppler_info) == 0) return (doppler_status_info_table[count].doppler_status); } return (-1); @@ -621,25 +581,23 @@ static int _gps_element_compare(char *element[], char *element_str, int nelem) int count; for (count = 0; count < nelem; count++) { - if (strcmp(element[count], element_str) == 0) + if (g_strcmp0(element[count], element_str) == 0) return count; } return -1; } - static enum gps_assist_element_type _get_element_type(char *element_str) { unsigned int index; for (index = 0; index < sizeof(elements) / sizeof(t_element); index++) { - if (strcmp(elements[index].name, element_str) == 0) + if (g_strcmp0(elements[index].name, element_str) == 0) return elements[index].type; } return -1; } - static void _parse_ref_time_gps_elements(char *element_str, char *element_value, gps_assist_data_noti_t *gpsdata_assist, gboolean GPS_TOW_assist, int count) { int node_count; @@ -648,7 +606,7 @@ static void _parse_ref_time_gps_elements(char *element_str, char *element_value, dbg("Enter"); if (count < 0 || count >= MAX_NUM_OF_GPS_REF_TIME_ELEMENT) { - dbg("invalid count"); + err("invalid count"); return; } nelem = (int) NUM_OF_ELEMENTS(element); @@ -708,7 +666,7 @@ static void _parse_ref_time_gps_elements(char *element_str, char *element_value, break; default: - dbg("Invalid gps element"); + err("Invalid gps element"); } } } @@ -733,7 +691,7 @@ static void _parse_location_parameters(char *element_str, char *element_value, g case 0: { // gpsdata_assist.ref_loc.latitude_data.north = atoi(element_str_text); - // dbg("gpsdata_assist.ref_loc.latitude_data.north - %d\n",gpsdata_assist.ref_loc.latitude_data.north); + // dbg("gpsdata_assist.ref_loc.latitude_data.north - %d\n",gpsdata_assist.ref_loc.latitude_data.north); } break; @@ -747,13 +705,13 @@ static void _parse_location_parameters(char *element_str, char *element_value, g case 2: { // gpsdata_assist.ref_loc.altitude_data.height_above_surface = atoi(element_str_text); - // dbg("altitude_data.height_above_surface - %d\n",gpsdata_assist.ref_loc.altitude_data.height_above_surface); + // dbg("altitude_data.height_above_surface - %d\n",gpsdata_assist.ref_loc.altitude_data.height_above_surface); } break; case 3: { - gpsdata_assist->ref_loc.altitude = atoi(element_value); // todo- need to confirm + gpsdata_assist->ref_loc.altitude = atoi(element_value); // todo- need to confirm dbg("altitude_data.height - %d\n", gpsdata_assist->ref_loc.altitude); } break; @@ -761,7 +719,7 @@ static void _parse_location_parameters(char *element_str, char *element_value, g case 4: { gpsdata_assist->ref_loc.longitude = atoi(element_value); - dbg("longitude - %d\n", gpsdata_assist->ref_loc.longitude); + dbg("longitude - %d\n", gpsdata_assist->ref_loc.longitude); } break; @@ -801,7 +759,7 @@ static void _parse_location_parameters(char *element_str, char *element_value, g break; default: - dbg("invalid element"); + err("invalid element"); } } @@ -809,19 +767,19 @@ static void _parse_dgps_correction_gps_elements(char *element_str, char *element { dbg("Enter"); - if (strcmp(element_str, "sat_id") == 0) { + if (g_strcmp0(element_str, "sat_id") == 0) { gpsdata_assist->dgps_corrections.seqOfSatElement[0].satId = *element_value; dbg("seqOfSatElement[0].satId - %d\n", gpsdata_assist->dgps_corrections.seqOfSatElement[0].satId); - } else if (strcmp(element_str, "IODE") == 0) { + } else if (g_strcmp0(element_str, "IODE") == 0) { gpsdata_assist->dgps_corrections.seqOfSatElement[0].iode = atoi(element_value); dbg("seqOfSatElement[0].iode - %d\n", gpsdata_assist->dgps_corrections.seqOfSatElement[0].iode); - } else if (strcmp(element_str, "UDRE") == 0) { + } else if (g_strcmp0(element_str, "UDRE") == 0) { gpsdata_assist->dgps_corrections.seqOfSatElement[0].udre = *element_value; dbg("seqOfSatElement[0].udre- %d\n", gpsdata_assist->dgps_corrections.seqOfSatElement[0].udre); - } else if (strcmp(element_str, "PRC") == 0) { + } else if (g_strcmp0(element_str, "PRC") == 0) { gpsdata_assist->dgps_corrections.seqOfSatElement[0].pseudoRangeCor = atoi(element_value); dbg("seqOfSatElement[0].pseudoRangeCor - %d\n", gpsdata_assist->dgps_corrections.seqOfSatElement[0].pseudoRangeCor); - } else if (strcmp(element_str, "RRC") == 0) { + } else if (g_strcmp0(element_str, "RRC") == 0) { gpsdata_assist->dgps_corrections.seqOfSatElement[0].rangeRateCor = atoi(element_value); dbg("seqOfSatElement[0].rangeRateCor - %d\n", gpsdata_assist->dgps_corrections.seqOfSatElement[0].rangeRateCor); } @@ -839,7 +797,7 @@ static void _parse_ionospheric_model_gps_elements(char *element_str, char *eleme case 0: { gpsdata_assist->iono_model.alfa0 = *element_value; - dbg("alfa0 - 0x%X\n", gpsdata_assist->iono_model.alfa0); + dbg("alfa0 - 0x%X\n", gpsdata_assist->iono_model.alfa0); } break; @@ -853,51 +811,51 @@ static void _parse_ionospheric_model_gps_elements(char *element_str, char *eleme case 2: { gpsdata_assist->iono_model.alfa2 = *element_value; - dbg("alfa2 - 0x%X\n", gpsdata_assist->iono_model.alfa2); + dbg("alfa2 - 0x%X\n", gpsdata_assist->iono_model.alfa2); } break; case 3: { gpsdata_assist->iono_model.alfa3 = *element_value; - dbg("alfa3 - 0x%X\n", gpsdata_assist->iono_model.alfa3); + dbg("alfa3 - 0x%X\n", gpsdata_assist->iono_model.alfa3); } break; case 4: { gpsdata_assist->iono_model.beta0 = *element_value; - dbg("beta0 - 0x%X\n", gpsdata_assist->iono_model.beta0); + dbg("beta0 - 0x%X\n", gpsdata_assist->iono_model.beta0); } break; case 5: { gpsdata_assist->iono_model.beta1 = *element_value; - dbg("beta1 -0x%X\n", gpsdata_assist->iono_model.beta1); + dbg("beta1 -0x%X\n", gpsdata_assist->iono_model.beta1); } break; case 6: { gpsdata_assist->iono_model.beta2 = *element_value; - dbg("beta2 - 0x%X\n", gpsdata_assist->iono_model.beta2); + dbg("beta2 - 0x%X\n", gpsdata_assist->iono_model.beta2); } break; case 7: { gpsdata_assist->iono_model.beta3 = *element_value; - dbg("beta3 - 0x%X\n", gpsdata_assist->iono_model.beta3); + dbg("beta3 - 0x%X\n", gpsdata_assist->iono_model.beta3); } break; default: - dbg("invalid gps element"); + err("invalid gps element"); } } -void _parse_utc_model_gps_elements(char *element_str, char *element_value, gps_assist_data_noti_t *gpsdata_assist) +static void _parse_utc_model_gps_elements(char *element_str, char *element_value, gps_assist_data_noti_t *gpsdata_assist) { static char *element[] = {"a1", "a0", "tot", "wnt", "dtls", "wnlsf", "dn", "dtlsf"}; int nelem = (int) NUM_OF_ELEMENTS(element); @@ -910,14 +868,14 @@ void _parse_utc_model_gps_elements(char *element_str, char *element_value, gps_a case 0: { gpsdata_assist->utc_model.utcA1 = atoi(element_value); - dbg("utcA1 - %d\n", gpsdata_assist->utc_model.utcA1); + dbg("utcA1 - %d\n", gpsdata_assist->utc_model.utcA1); } break; case 1: { gpsdata_assist->utc_model.utcA0 = atoi(element_value); - dbg("utcA0 - %d\n", gpsdata_assist->utc_model.utcA0); + dbg("utcA0 - %d\n", gpsdata_assist->utc_model.utcA0); } break; @@ -952,7 +910,7 @@ void _parse_utc_model_gps_elements(char *element_str, char *element_value, gps_a case 6: { gpsdata_assist->utc_model.utcDN = *element_value; - dbg("utcDN - 0x%X\n", gpsdata_assist->utc_model.utcDN); + dbg("utcDN - 0x%X\n", gpsdata_assist->utc_model.utcDN); } break; @@ -964,7 +922,7 @@ void _parse_utc_model_gps_elements(char *element_str, char *element_value, gps_a break; default: - dbg("invalid gps element"); + err("invalid gps element"); } } @@ -1004,7 +962,7 @@ static void _parse_almanc_model_gps_elements(char *element_str, char *element_va case 2: { gpsdata_assist->almanac.AlmanacSatInfo[count].satId = *element_value; - dbg("AlmanacSatInfo[%d].sat_id - 0x%X\n", count, gpsdata_assist->almanac.AlmanacSatInfo[count].satId); + dbg("AlmanacSatInfo[%d].sat_id - 0x%X\n", count, gpsdata_assist->almanac.AlmanacSatInfo[count].satId); } break; @@ -1018,7 +976,7 @@ static void _parse_almanc_model_gps_elements(char *element_str, char *element_va case 4: { gpsdata_assist->almanac.AlmanacSatInfo[count].almanacToa = *element_value; - dbg("AlmanacSatInfo[%d].almanacToa - 0x%X\n", count, gpsdata_assist->almanac.AlmanacSatInfo[count].almanacToa); + dbg("AlmanacSatInfo[%d].almanacToa - 0x%X\n", count, gpsdata_assist->almanac.AlmanacSatInfo[count].almanacToa); } break; @@ -1074,19 +1032,19 @@ static void _parse_almanc_model_gps_elements(char *element_str, char *element_va case 12: { gpsdata_assist->almanac.AlmanacSatInfo[count].almanacAf0 = atoi(element_value); - dbg("AlmanacSatInfo[%d].almanacAf0 - %d\n", count, gpsdata_assist->almanac.AlmanacSatInfo[count].almanacAf0); + dbg("AlmanacSatInfo[%d].almanacAf0 - %d\n", count, gpsdata_assist->almanac.AlmanacSatInfo[count].almanacAf0); } break; case 13: { gpsdata_assist->almanac.AlmanacSatInfo[count].almanacAf1 = atoi(element_value); - dbg("AlmanacSatInfo[%d].almanacAf1 - %d\n", count, gpsdata_assist->almanac.AlmanacSatInfo[count].almanacAf1); + dbg("AlmanacSatInfo[%d].almanacAf1 - %d\n", count, gpsdata_assist->almanac.AlmanacSatInfo[count].almanacAf1); } break; default: - dbg("invalid gps element"); + err("invalid gps element"); } } return; @@ -1104,7 +1062,7 @@ static void _parse_acqu_assist_gps_elements(char *element_str, char *element_val switch (count) { case 0: gpsdata_assist->acq_assist.gpsTow = atoi(element_value); - dbg("acq_assist.gpsTow - %d\n", gpsdata_assist->acq_assist.gpsTow); + dbg("acq_assist.gpsTow - %d\n", gpsdata_assist->acq_assist.gpsTow); break; case 1: @@ -1119,7 +1077,7 @@ static void _parse_acqu_assist_gps_elements(char *element_str, char *element_val case 3: gpsdata_assist->acq_assist.lcsAcquisitionSatInfo[0].doppler1 = *element_value; - dbg("lcsAcquisitionSatInfo[0].doppler1 - 0x%X\n", gpsdata_assist->acq_assist.lcsAcquisitionSatInfo[0].doppler1); + dbg("lcsAcquisitionSatInfo[0].doppler1 - 0x%X\n", gpsdata_assist->acq_assist.lcsAcquisitionSatInfo[0].doppler1); break; case 4: @@ -1129,7 +1087,7 @@ static void _parse_acqu_assist_gps_elements(char *element_str, char *element_val case 5: gpsdata_assist->acq_assist.lcsAcquisitionSatInfo[0].intCodePhase = *element_value; - dbg("lcsAcquisitionSatInfo[0].intCodePhase - 0x%X\n", gpsdata_assist->acq_assist.lcsAcquisitionSatInfo[0].intCodePhase); + dbg("lcsAcquisitionSatInfo[0].intCodePhase - 0x%X\n", gpsdata_assist->acq_assist.lcsAcquisitionSatInfo[0].intCodePhase); break; case 6: @@ -1153,7 +1111,7 @@ static void _parse_acqu_assist_gps_elements(char *element_str, char *element_val break; default: - dbg("invalid gps element"); + err("invalid gps element"); } } @@ -1169,7 +1127,7 @@ static void _parse_nav_model_gps_elements(char *element_str, char *element_value int count; if (element_count < 0 || element_count >= MAX_NUM_OF_GPS_NAV_ELEMENT) { - dbg("invalid count"); + err("invalid count"); return; } count = _gps_element_compare(element, element_str, nelem); @@ -1305,13 +1263,12 @@ static void _parse_nav_model_gps_elements(char *element_str, char *element_value break; default: - dbg("invalid gps element"); + err("invalid gps element"); } } } - -// Set coordinate elements : +// Set coordinate elements : static void _set_coordinate(xmlNodePtr node, gps_ellipsoid_po_t *point, int isalt, int altitude) { // .. .. (xmlNodePtr node) @@ -1355,6 +1312,8 @@ static void _set_coordinate(xmlNodePtr node, gps_ellipsoid_po_t *point, int isal return; } + + static void _set_loc_info_ellipse_elements(xmlNodePtr node, void *elliplse, int is_unc_ellipse) { gps_po_unc_ellipse_t *p_unc_ellipse; @@ -1404,81 +1363,81 @@ static xmlChar* _generate_confirm_measure_pos_xml_text(gps_measure_position_conf int count = 0, altitude, size; /* - Creates a new XML document + Creates a new XML document ================================================================================================================================ - - - - - - - - - - - - - < - - - - - - - - - - - <> <\> ... - - - - - <> <\>.. - - - - - - - <> <\>... - - - - - <> <\>.. - - - - - - - - <> <\>.. .. - - - - - - - - - - <> <\> .. - < - - - - - - - - - - - + + + + + + + + + + + + + < + + + + + + + + + + + <> <\> ... + + + + + <> <\>.. + + + + + + + <> <\>... + + + + + <> <\>.. + + + + + + + + <> <\>.. .. + + + + + + + + + + <> <\> .. + < + + + + + + + + + + + ================================================================================================================================ */ @@ -1660,7 +1619,103 @@ static xmlChar* _generate_confirm_measure_pos_xml_text(gps_measure_position_conf return xml; } -static gboolean on_notification_gps_assist_data(CoreObject *o, const void *event_info, void *user_data) + +static gboolean on_notification_gps_measure_position_from_modem(CoreObject *o, char *file_name, void *user_data) +{ + char *node = NULL, *node_value = NULL; + char *attribute = NULL; + char *attr_value = NULL; + gps_measure_position_indi_t gps_measure_position_indi; + gboolean rep_quant = FALSE; + xmlTextReaderPtr reader; + + memset(&gps_measure_position_indi, 0x00, sizeof(gps_measure_position_indi)); + reader = xmlReaderForFile(file_name, NULL, 0); + + while (xmlTextReaderRead(reader)) { + switch (xmlTextReaderNodeType(reader)) { + case XML_READER_TYPE_ELEMENT: + { + node = (char *) xmlTextReaderConstName(reader); + dbg("Element: %s", node); + if (node != NULL) { + // Read attribute value. + while (xmlTextReaderMoveToNextAttribute(reader)) { + attribute = (char *) xmlTextReaderConstName(reader); + dbg("Attribute value - %s\n", attribute); + attr_value = (char *) xmlTextReaderConstValue(reader); + dbg("=\"%s\"\n", attr_value); + + if (g_strcmp0(node, "mult_sets") == 0) { + if (g_strcmp0(attribute, "literal") == 0) { + if (g_strcmp0(attr_value, "one") == 0) + gps_measure_position_indi.use_multi_sets = GPS_MULTIPLESETS_ONESET; + else if (g_strcmp0(attr_value, "multiple") == 0) + gps_measure_position_indi.use_multi_sets = GPS_MULTIPLESETS_MULTIPLESETS; + } + dbg("gps_measure_position_indi.use_multi_sets - 0x%x\n", gps_measure_position_indi.use_multi_sets); + } else if (g_strcmp0(node, "rep_quant") == 0) { + rep_quant = TRUE; + if (g_strcmp0(attribute, "addl_assist_data_req") == 0) { + if (g_strcmp0(attr_value, "true") == 0) + gps_measure_position_indi.add_assist_req = GPS_ADDITIONAL_ASSISREQ_REQ; + else + gps_measure_position_indi.add_assist_req = GPS_ADDITIONAL_ASSISREQ_NOT_REQ; + } else if (g_strcmp0(attribute, "gps_timing_of_cell_wanted") == 0) { + if (g_strcmp0(attr_value, "true") == 0) + gps_measure_position_indi.cell_timing_wnt = GPS_CELLTIMING_WANTED; + else + gps_measure_position_indi.cell_timing_wnt = GPS_CELLTIMING_NOT_WANTED; + } + } + } // end of attribute check + + if (g_strcmp0(node, "ms_assisted") == 0) { + gps_measure_position_indi.method_type = GPS_METHODTYPE_MS_ASSISTED; + } else if (g_strcmp0(node, "ms_assisted_no_accuracy") == 0) { + gps_measure_position_indi.method_type = GPS_METHODTYPE_MS_ASSISTED; + } else if (g_strcmp0(node, "ms_based") == 0) { + gps_measure_position_indi.method_type = GPS_METHODTYPE_MS_BASED; + } else if (g_strcmp0(node, "ms_based_pref") == 0) { + gps_measure_position_indi.method_type = GPS_METHODTYPE_MS_BASED_PREF; + } else if (g_strcmp0(node, "ms_assisted_pref") == 0) { + gps_measure_position_indi.method_type = GPS_METHODTYPE_MS_ASSISTED_PREF; + } + } + xmlTextReaderMoveToElement(reader); + } + break; + + case XML_READER_TYPE_TEXT: + { + node_value = (char *) xmlTextReaderConstValue(reader); + dbg("element-value: %s", node_value); + if (node_value != NULL) { + if (g_strcmp0(node, "resp_time_seconds") == 0) { + gps_measure_position_indi.rsp_time = *node_value; + dbg("gps_measure_position_indi.rsp_time - 0x%x", gps_measure_position_indi.rsp_time); + } + if (rep_quant == TRUE) { + if (g_strcmp0(node, "hor_acc") == 0) + gps_measure_position_indi.accuracy.horizontalAccuracy = *node_value; + else if (g_strcmp0(node, "vert_acc") == 0) + gps_measure_position_indi.accuracy.vertcalAccuracy = *node_value; + } + } + } + break; + } + } + xmlFreeTextReader(reader); + xmlCleanupParser(); + + tcore_server_send_notification(tcore_plugin_ref_server(tcore_object_ref_plugin(o)),(tcore_object_ref_plugin(o)), + TCORE_NOTIFICATION_GPS_MEASURE_POSITION, sizeof(gps_measure_position_indi), &gps_measure_position_indi); + return TRUE; +} + + +static gboolean on_notification_imc_gps_assist_data(CoreObject *o, const void *event_info, void *user_data) { int fd; gps_assist_data_noti_t gps_data_assist; @@ -1681,49 +1736,49 @@ static gboolean on_notification_gps_assist_data(CoreObject *o, const void *event dbg("enter"); /* - Example:GPS assist XML data will be in below format. + Example:GPS assist XML data will be in below format. ================================================================================================================================ - +CPOSR: - - - - - <> <\>..<\GPS_time> <> <\> ..<\GPS_TOW_assist> - - - - <> <\>... <\altitude> - - - - - - - - - - - <> <\> .. .. <\ephem_and_clock> - - - - - - - - - - - 0 <> <\> ...<\alm_elem> - - - - <> <\> ... <\sat_info> - - - - - + +CPOSR: + + + + + <> <\>..<\GPS_time> <> <\> ..<\GPS_TOW_assist> + + + + <> <\>... <\altitude> + + + + + + + + + + + <> <\> .. .. <\ephem_and_clock> + + + + + + + + + + + 0 <> <\> ...<\alm_elem> + + + + <> <\> ... <\sat_info> + + + + + ================================================================================================================================ */ @@ -1741,13 +1796,13 @@ static gboolean on_notification_gps_assist_data(CoreObject *o, const void *event path = tzplatform_mkpath(TZ_SYS_ROOT, "sample.xml"); // open file. if ((fd = open(path, O_WRONLY | O_CREAT | O_TRUNC | S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH, S_IRWXU)) == -1) { - dbg("Cannot open file\n"); + err("Cannot open file\n"); g_free(line); return FALSE; } // write gps xml data into file. if (write(fd, (const void *) line, strlen(line)) == -1) { - dbg("Cannot write into file\n"); + err("Cannot write into file\n"); close(fd); g_free(line); return FALSE; @@ -1758,7 +1813,7 @@ static gboolean on_notification_gps_assist_data(CoreObject *o, const void *event dbg("read xml file"); reader = xmlReaderForFile(path, NULL, 0); - while (xmlTextReaderRead(reader) == 1) { + while (xmlTextReaderRead(reader)) { // Get the node type of the current node switch (xmlTextReaderNodeType(reader)) { case XML_READER_TYPE_ELEMENT: @@ -1769,13 +1824,13 @@ static gboolean on_notification_gps_assist_data(CoreObject *o, const void *event if (node != NULL) { // check type of sub element of set_element_type = _get_element_type(node); - if ((int) set_element_type != -1) // ignore negative value as excepted element type not set. + if ((int) set_element_type != -1) // ignore negative value as excepted element type not set. node_type = set_element_type; - dbg("xml node type : %d", node_type); + dbg("xml node type : %d", node_type); // Check for position measurement data. - if (strcmp(node, "pos_meas") == 0) { + if (g_strcmp0(node, "pos_meas") == 0) { // Deallocate all the resources associated to the reader xmlFreeTextReader(reader); xmlCleanupParser(); @@ -1803,46 +1858,46 @@ static gboolean on_notification_gps_assist_data(CoreObject *o, const void *event // Read attribute value of if (node_type == NAV_MODEL_ELEM) { - if (strcmp(node, "sat_status") == 0 && strcmp(attribute, "literal") == 0) { + if (g_strcmp0(node, "sat_status") == 0 && g_strcmp0(attribute, "literal") == 0) { gps_data_assist.navi_model.NavigationSatInfo[nav_model_node_count].NavigationSatStatus = _modem_sat_status_info_2_tel_sat_info(attr_value); dbg("navigation sat status of nav model element - %d\n", gps_data_assist.navi_model.NavigationSatInfo[nav_model_node_count].NavigationSatStatus); } } // Read attribute value of else if (node_type == ACQU_ASSIST) { - if (strcmp(node, "dopl1_uncert") == 0 && strcmp(attribute, "literal") == 0) { + if (g_strcmp0(node, "dopl1_uncert") == 0 && g_strcmp0(attribute, "literal") == 0) { gps_data_assist.acq_assist.lcsAcquisitionSatInfo[0].dopplerUncertainty = _modem_acqa_assit_doppler_2_tel_doppler(attr_value); dbg("doppler uncertainty of acqu assist data- %d", gps_data_assist.acq_assist.lcsAcquisitionSatInfo[0].dopplerUncertainty); } } - } // end of attribute check. + } // end of attribute check. // check GPS data is having GPS_assist data. - if (strcmp(node, "GPS_assist") == 0) { + if (g_strcmp0(node, "GPS_assist") == 0) { _gps_assist_data = TRUE; } if (_gps_assist_data == TRUE) { // number of GPS_TOW_assist elements. - if (strcmp(node, "GPS_TOW_assist") == 0) { + if (g_strcmp0(node, "GPS_TOW_assist") == 0) { gps_tow_assist_count++; gps_tow_assist = TRUE; - } else if (strcmp(node, "nav_model_elem") == 0) { + } else if (g_strcmp0(node, "nav_model_elem") == 0) { // number of nav_model_elem. nav_model_node_count++; - } else if (strcmp(node, "alm_elem") == 0) { + } else if (g_strcmp0(node, "alm_elem") == 0) { // number of alm_elem elements. alm_node_count++; dbg("alm_elem_count - %d", alm_node_count); if (node_type == ALMANAC) alm_elem = TRUE; - } else if (strcmp(node, "ephem_and_clock") == 0 && node_type == NAV_MODEL_ELEM) { + } else if (g_strcmp0(node, "ephem_and_clock") == 0 && node_type == NAV_MODEL_ELEM) { ephem_and_clock = TRUE; } } } xmlTextReaderMoveToElement(reader); - } // end of reading node type. + } // end of reading node type. break; case XML_READER_TYPE_TEXT: @@ -1886,10 +1941,10 @@ static gboolean on_notification_gps_assist_data(CoreObject *o, const void *event break; default: - dbg("invalid element"); + err("invalid element"); } } - } // end of reading node value. + } // end of reading node value. break; } } // end of parsing. @@ -1905,213 +1960,124 @@ static gboolean on_notification_gps_assist_data(CoreObject *o, const void *event dbg("file removed"); } - tcore_server_send_notification(tcore_plugin_ref_server(tcore_object_ref_plugin(o)), - o, TNOTI_GPS_ASSIST_DATA, sizeof(gps_data_assist), &gps_data_assist); + tcore_server_send_notification(tcore_plugin_ref_server(tcore_object_ref_plugin(o)),(tcore_object_ref_plugin(o)), + TCORE_NOTIFICATION_GPS_ASSIST_DATA, sizeof(gps_data_assist), &gps_data_assist); + return TRUE; } -static gboolean on_notification_gps_measure_position_from_modem(CoreObject *o, char *file_name, void *user_data) +static gboolean on_notification_imc_reset_assist_data(CoreObject *o, const void *event_info, void *user_data) { - char *node = NULL, *node_value = NULL; - char *attribute = NULL; - char *attr_value = NULL; - gps_measure_position_indi_t gps_measure_position_indi; - gboolean rep_quant = FALSE; - xmlTextReaderPtr reader; - - memset(&gps_measure_position_indi, 0x00, sizeof(gps_measure_position_indi)); - reader = xmlReaderForFile(file_name, NULL, 0); - - while (xmlTextReaderRead(reader) == 1) { - switch (xmlTextReaderNodeType(reader)) { - case XML_READER_TYPE_ELEMENT: - { - node = (char *) xmlTextReaderConstName(reader); - dbg("Element: %s", node); - if (node != NULL) { - // Read attribute value. - while (xmlTextReaderMoveToNextAttribute(reader)) { - attribute = (char *) xmlTextReaderConstName(reader); - dbg("Attribute value - %s\n", attribute); - attr_value = (char *) xmlTextReaderConstValue(reader); - dbg("=\"%s\"\n", attr_value); - - if (strcmp(node, "mult_sets") == 0) { - if (strcmp(attribute, "literal") == 0) { - if (strcmp(attr_value, "one") == 0) - gps_measure_position_indi.use_multi_sets = GPS_MULTIPLESETS_ONESET; - else if (strcmp(attr_value, "multiple") == 0) - gps_measure_position_indi.use_multi_sets = GPS_MULTIPLESETS_MULTIPLESETS; - } - dbg("gps_measure_position_indi.use_multi_sets - 0x%x\n", gps_measure_position_indi.use_multi_sets); - } else if (strcmp(node, "rep_quant") == 0) { - rep_quant = TRUE; - if (strcmp(attribute, "addl_assist_data_req") == 0) { - if (strcmp(attr_value, "true") == 0) - gps_measure_position_indi.add_assist_req = GPS_ADDITIONAL_ASSISREQ_REQ; - else - gps_measure_position_indi.add_assist_req = GPS_ADDITIONAL_ASSISREQ_NOT_REQ; - } else if (strcmp(attribute, "gps_timing_of_cell_wanted") == 0) { - if (strcmp(attr_value, "true") == 0) - gps_measure_position_indi.cell_timing_wnt = GPS_CELLTIMING_WANTED; - else - gps_measure_position_indi.cell_timing_wnt = GPS_CELLTIMING_NOT_WANTED; - } - } - } // end of attribute check - - if (strcmp(node, "ms_assisted") == 0) { - gps_measure_position_indi.method_type = GPS_METHODTYPE_MS_ASSISTED; - } else if (strcmp(node, "ms_assisted_no_accuracy") == 0) { - gps_measure_position_indi.method_type = GPS_METHODTYPE_MS_ASSISTED; - } else if (strcmp(node, "ms_based") == 0) { - gps_measure_position_indi.method_type = GPS_METHODTYPE_MS_BASED; - } else if (strcmp(node, "ms_based_pref") == 0) { - gps_measure_position_indi.method_type = GPS_METHODTYPE_MS_BASED_PREF; - } else if (strcmp(node, "ms_assisted_pref") == 0) { - gps_measure_position_indi.method_type = GPS_METHODTYPE_MS_ASSISTED_PREF; - } - } - xmlTextReaderMoveToElement(reader); - } - break; + dbg("enter!\n"); + tcore_server_send_notification(tcore_plugin_ref_server(tcore_object_ref_plugin(o)),(tcore_object_ref_plugin(o)), + TCORE_NOTIFICATION_GPS_RESET_ASSIST_DATA, 0, NULL); - case XML_READER_TYPE_TEXT: - { - node_value = (char *) xmlTextReaderConstValue(reader); - dbg("element-value: %s", node_value); - if (node_value != NULL) { - if (strcmp(node, "resp_time_seconds") == 0) { - gps_measure_position_indi.rsp_time = *node_value; - dbg("gps_measure_position_indi.rsp_time - 0x%x", gps_measure_position_indi.rsp_time); - } - if (rep_quant == TRUE) { - if (strcmp(node, "hor_acc") == 0) - gps_measure_position_indi.accuracy.horizontalAccuracy = *node_value; - else if (strcmp(node, "vert_acc") == 0) - gps_measure_position_indi.accuracy.vertcalAccuracy = *node_value; - } - } - } - break; - } - } - xmlFreeTextReader(reader); - xmlCleanupParser(); - tcore_server_send_notification(tcore_plugin_ref_server(tcore_object_ref_plugin(o)), - o, TNOTI_GPS_MEASURE_POSITION, sizeof(gps_measure_position_indi), &gps_measure_position_indi); return TRUE; } - -// CONFIRMATION -static void on_confirmation_gps_message_send(TcorePending *p, gboolean result, void *user_data) +/* GPS Responses */ +static void on_response_imc_gps_confirm_measure_pos(TcorePending *p, guint data_len, const void *data, void *user_data) { + //GPS server does not except confirmation for GPS measure position request. + const TcoreAtResponse *at_resp = data; + ImcRespCbData *resp_cb_data = user_data; + dbg("Entry"); - if (result == FALSE) { // Fail - dbg("SEND FAIL"); + if (at_resp && at_resp->success) { + dbg("Confirm measure position - [OK]"); } else { - dbg("SEND OK"); + err("Confirm measure position - [NOK]"); } - dbg("Exit"); - return; + imc_destroy_resp_cb_data(resp_cb_data); } -static gboolean on_notification_reset_assist_data(CoreObject *o, const void *event_info, void *user_data) -{ - dbg("enter!\n"); - tcore_server_send_notification(tcore_plugin_ref_server(tcore_object_ref_plugin(o)), - o, TNOTI_GPS_RESET_ASSIST_DATA, 0, NULL); - - return TRUE; -} -static void on_confirmation_gps_measure_position(TcorePending *p, int data_len, const void *data, void *user_data) -{ - //GPS server does not except confirmation for GPS measure position request. - dbg("enter"); - - dbg("exit"); -} +/* GPS Operations */ +/* + * Operation - confirm measure position + * + * Request - + * AT-Command: AT+CPOS= + * text is entered + * + * Success: + * OK + * + * Failure: + * +CME ERROR: + */ -static TReturn gps_confirm_measure_pos(CoreObject *o, UserRequest *ur) +static TelReturn imc_gps_confirm_measure_pos (CoreObject *co, const TelGpsDataInfo *gps_data, + TcoreObjectResponseCallback cb, void *cb_data) { - char *raw_str = NULL; + ImcRespCbData *resp_cb_data = NULL; char *cmd_str = NULL; - TcorePending *pending = NULL; - TcoreATRequest *req = NULL; - TcoreHal *hal = NULL; - gboolean ret = FALSE; xmlChar *xml = NULL; - unsigned char *data = NULL; - unsigned int data_len; gps_measure_position_confirm_t gps_measure_pos_confirm; + TelReturn ret; - dbg("enter!"); - if (!o || !ur) - return TCORE_RETURN_EINVAL; + memcpy(&gps_measure_pos_confirm, gps_data->data, gps_data->data_len); - data = (unsigned char *) tcore_user_request_ref_data(ur, &data_len); - memcpy(&gps_measure_pos_confirm, data, data_len); - - // make confirm measure postion request in xml format. xml = _generate_confirm_measure_pos_xml_text(&gps_measure_pos_confirm); if (!xml) { err("xml text generation failed"); - return TCORE_RETURN_EINVAL; + return TEL_RETURN_FAILURE; } - // AT+CPOStext is entered - raw_str = g_strdup_printf("AT+CPOS%s", "\r"); - cmd_str = g_strdup_printf("%s%s\x1A", raw_str, xml); - - dbg("command string : %s", cmd_str); - pending = tcore_pending_new(o, 0); - req = tcore_at_request_new(cmd_str, NULL, TCORE_AT_NO_RESULT); - dbg("cmd : %s, prefix(if any) :%s, cmd_len : %d", req->cmd, req->prefix, strlen(req->cmd)); - tcore_pending_set_request_data(pending, strlen(cmd_str), req); - tcore_pending_set_priority(pending, TCORE_PENDING_PRIORITY_DEFAULT); - tcore_pending_set_send_callback(pending, on_confirmation_gps_message_send, NULL); - tcore_pending_set_response_callback(pending, on_confirmation_gps_measure_position, NULL); - tcore_pending_link_user_request(pending, ur); - - // HAL - hal = tcore_object_get_hal(o); - // Send request to HAL - ret = tcore_hal_send_request(hal, pending); - if (TCORE_RETURN_SUCCESS != ret) { - err("Request send failed"); - ret = FALSE; - } + /* AT - Command */ + cmd_str = g_strdup_printf("AT+CPOS%s%s\x1A", "\r", xml); + + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, NULL, 0); + + /* Send Request to modem */ + ret = tcore_at_prepare_and_send_request(co, + cmd_str, NULL, + TCORE_AT_COMMAND_TYPE_NO_RESULT, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_gps_confirm_measure_pos, resp_cb_data, + on_send_imc_request, NULL, + (guint)0, NULL, NULL); + + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Confirm Measure Position"); - dbg("exit"); - g_free(raw_str); g_free(cmd_str); - xmlFree(xml); + return ret; + } -static struct tcore_gps_operations gps_ops = { - .confirm_measure_pos = gps_confirm_measure_pos, + + static TelReturn imc_gps_set_frequency_aiding (CoreObject *co, gboolean state, + TcoreObjectResponseCallback cb, void *cb_data) + { + return TEL_RETURN_OPERATION_NOT_SUPPORTED; + } + + +static TcoreGpsOps imc_gps_ops = { + .confirm_measure_pos = imc_gps_confirm_measure_pos, + .set_frequency_aiding = imc_gps_set_frequency_aiding }; -gboolean s_gps_init(TcorePlugin *cp, CoreObject *co_gps) +gboolean imc_gps_init(TcorePlugin *p, CoreObject *co) { dbg("Enter"); - tcore_gps_override_ops(co_gps, &gps_ops); + /* Set operations */ + tcore_gps_set_ops(co, &imc_gps_ops); - tcore_object_override_callback(co_gps, "+CPOSR", on_notification_gps_assist_data, NULL); - tcore_object_override_callback(co_gps, "+XCPOSR", on_notification_reset_assist_data, NULL); + /* Add Callbacks */ + tcore_object_override_callback(co, "+CPOSR", on_notification_imc_gps_assist_data, NULL); + tcore_object_override_callback(co, "+XCPOSR", on_notification_imc_reset_assist_data, NULL); dbg("Exit"); - return TRUE; } -void s_gps_exit(TcorePlugin *cp, CoreObject *co_gps) +void imc_gps_exit(TcorePlugin *p, CoreObject *co) { dbg("Exit"); } diff --git a/src/imc_modem.c b/src/imc_modem.c new file mode 100644 index 0000000..c636972 --- /dev/null +++ b/src/imc_modem.c @@ -0,0 +1,927 @@ +/* + * tel-plugin-imc + * + * Copyright (c) 2013 Samsung Electronics Co. Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "imc_modem.h" +#include "imc_common.h" +#include "nvm/nvm.h" + +static gboolean on_event_imc_nvm_update(CoreObject *co, + const void *event_info, void *user_data); + +/* NVM Req/Response */ +static gboolean __imc_modem_check_nvm_response(const void *data, int command) +{ + const TcoreAtResponse *at_resp = data; + const char *line; + char *resp_str; + GSList *tokens = NULL; + gboolean ret = FALSE; + + dbg("Entered"); + + /* +XDRV: ,,[,] */ + if (NULL == at_resp) { + err("Input data is NULL"); + return FALSE; + } + + if (at_resp->success > 0) { + dbg("RESPONSE OK"); + line = (const char *) (((GSList *) at_resp->lines)->data); + tokens = tcore_at_tok_new(line); + + /* Group ID */ + resp_str = g_slist_nth_data(tokens, 0); + if (NULL == resp_str) { + err("Group ID is missing "); + goto OUT; + } + else if (IUFP_GROUP_ID != atoi(resp_str)) { + err("Group ID mismatch"); + goto OUT; + } + + /* Function ID */ + resp_str = g_slist_nth_data(tokens, 1); + if (NULL == resp_str) { + err("Function ID is missing "); + goto OUT; + } + else if (command != atoi(resp_str)) { + err("Function ID mismatch"); + goto OUT; + } + + /* XDRV Result */ + resp_str = g_slist_nth_data(tokens, 2); + if (NULL == resp_str) { + err("XDRV result is missing "); + goto OUT; + } + else if (XDRV_RESULT_OK != atoi(resp_str)) { + err("XDRV result[%d] ", atoi(resp_str)); + goto OUT; + } + + /* Result code */ + resp_str = g_slist_nth_data(tokens, 3); + if (NULL == resp_str) { + err("UTA result is missing "); + goto OUT; + } + else if (UTA_SUCCESS != atoi(resp_str)) { + err("uta result[%d] ", atoi(resp_str)); + goto OUT; + } + + ret = TRUE; + } else { + dbg("Response NOK"); + } + +OUT: + tcore_at_tok_free(tokens); + + dbg("Exit"); + return ret; +} + +static void __on_response_modem_unsuspend_nvm_updates(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + /* Check NVM response */ + if (TRUE == __imc_modem_check_nvm_response(data, IUFP_SUSPEND)) { + dbg("Priority level is set to get all updates since Boot-up"); + + /* Create NV data file */ + if (nvm_create_nvm_data() == FALSE) { + err("Failed to Create NV data file"); + } + + return; + } + + err("Response NOT OK"); +} + +static void __imc_modem_unsuspend_nvm_updates(CoreObject *co) +{ + char *cmd_str; + TelReturn ret; + + /* Prepare AT-Command */ + cmd_str = g_strdup_printf("AT+XDRV=%d, %d, %d, %d", + IUFP_GROUP_ID, IUFP_SUSPEND, + 0, UTA_FLASH_PLUGIN_PRIO_UNSUSPEND_ALL); + + /* Send Request to modem */ + ret = tcore_at_prepare_and_send_request(co, + cmd_str, "+XDRV:", + TCORE_AT_COMMAND_TYPE_SINGLELINE, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + __on_response_modem_unsuspend_nvm_updates, NULL, + on_send_imc_request, NULL, + 0, NULL, NULL); + + IMC_CHECK_REQUEST_RET(ret, NULL, "Unsuspend Nvm Updates"); + + g_free(cmd_str); +} + +static void __on_response_modem_send_nvm_update_ack(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + /* Check NVM response */ + if (TRUE == __imc_modem_check_nvm_response(data, IUFP_UPDATE_ACK)) { + dbg("[UPDATE ACK] OK"); + return; + } + + err("[UPDATE ACK] NOT OK"); +} + +static void __imc_modem_send_nvm_update_ack(CoreObject *co) +{ + char *cmd_str; + TelReturn ret; + + /* Prepare AT-Command */ + cmd_str = g_strdup_printf("AT+XDRV=%s, %s", IUFP_GROUP, IUFP_UPDATE_ACK_STR); + + /* Send Request to modem */ + ret = tcore_at_prepare_and_send_request(co, + cmd_str, "+XDRV:", + TCORE_AT_COMMAND_TYPE_SINGLELINE, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + __on_response_modem_send_nvm_update_ack, NULL, + on_send_imc_request, NULL, + 0, NULL, NULL); + + IMC_CHECK_REQUEST_RET(ret, NULL, "Nvm Update Ack"); + + g_free(cmd_str); +} + +static void __on_response_modem_send_nvm_update_request_ack(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + /* Check NVM response */ + if (TRUE == __imc_modem_check_nvm_response(data, IUFP_UPDATE_REQ_ACK)) { + dbg("[REQUEST ACK] OK"); + return; + } + + err("[REQUEST ACK] NOT OK"); +} + +static void __imc_modem_send_nvm_update_request_ack(CoreObject *co) +{ + char *cmd_str; + TelReturn ret; + + /* Prepare AT-Command */ + cmd_str = g_strdup_printf("AT+XDRV=%s, %s", IUFP_GROUP, IUFP_UPDATE_REQ_ACK_STR); + + /* Send Request to modem */ + ret = tcore_at_prepare_and_send_request(co, + cmd_str, "+XDRV:", + TCORE_AT_COMMAND_TYPE_SINGLELINE, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + __on_response_modem_send_nvm_update_request_ack, NULL, + on_send_imc_request, NULL, + 0, NULL, NULL); + + IMC_CHECK_REQUEST_RET(ret, NULL, "Nvm Update Request Ack"); + + g_free(cmd_str); +} + +static void __on_response_modem_register_nvm(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + /* Check NVM response */ + if (TRUE == __imc_modem_check_nvm_response(data, IUFP_REGISTER)) { + dbg("Registering successful"); + + /* Send SUSPEND_UPDATE for all UPDATES */ + __imc_modem_unsuspend_nvm_updates(tcore_pending_ref_core_object(p)); + + dbg("Exit"); + return; + } + + err("Response NOT OK"); +} + +/* System function responses */ +static void on_response_modem_set_flight_mode_internal(TcorePlugin *plugin, + gint result, const void *response, void *user_data) +{ + CoreObject *co; + gboolean flight_mode; + dbg("Enter"); + + co = tcore_plugin_ref_core_object(plugin, CORE_OBJECT_TYPE_MODEM); + tcore_check_return_assert(co != NULL); + + tcore_check_return(result == TEL_MODEM_RESULT_SUCCESS); + + /* Get Flight mode state */ + (void)tcore_modem_get_flight_mode_state(co, &flight_mode); + + dbg("Setting Modem Fiight mode (internal) - [%s] - [SUCCESS]", + (flight_mode ? "ON": "OFF")); + + /* + * Send notification + * + * This is an internal request to set Flight mode, which is sent during + * boot-up based on AP-side configuration (VCONF). + * + * Need to notify TAPI through Notiifcation - + * TCORE_NOTIFICATION_MODEM_FLIGHT_MODE + */ + (void)tcore_object_send_notification(co, + TCORE_NOTIFICATION_MODEM_FLIGHT_MODE, + sizeof(gboolean), &flight_mode); +} + +/* System functions */ +gboolean imc_modem_power_on_modem(TcorePlugin *plugin) +{ + CoreObject *co; + TcoreStorage *strg; + gboolean flight_mode; + TelModemPowerStatus power_status; + + co = tcore_plugin_ref_core_object(plugin, CORE_OBJECT_TYPE_MODEM); + tcore_check_return_value_assert(co != NULL, FALSE); + + /* Set Modem Power State to 'ON' */ + tcore_modem_set_powered(co, TRUE); + + /* + * Set Flight mode (as per AP settings -VCONF) + */ + /* Get Flight mode from VCONFKEY */ + strg = tcore_server_find_storage(tcore_plugin_ref_server(plugin), "vconf"); + tcore_check_return_value_assert(strg != NULL, FALSE); + + flight_mode = tcore_storage_get_bool(strg, STORAGE_KEY_FLIGHT_MODE); + + /* + * Set Flight mode request is dispatched to Core Object (Modem) + * to ensure that 'Request Hooks' get executed. + */ + (void)tcore_object_dispatch_request(co, TRUE, + TCORE_COMMAND_MODEM_SET_FLIGHTMODE, + &flight_mode, sizeof(gboolean), + on_response_modem_set_flight_mode_internal, NULL); + + /* + * Send notification + * + * Need to notify Modem is Powered UP through Notiifcation - + * TCORE_NOTIFICATION_MODEM_POWER + */ + power_status = TEL_MODEM_POWER_ON; + (void)tcore_object_send_notification(co, + TCORE_NOTIFICATION_MODEM_POWER, + sizeof(TelModemPowerStatus), &power_status); + + return TRUE; +} + +/* Modem Responses */ +static void on_response_imc_modem_set_power_status(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + CoreObject *co = tcore_pending_ref_core_object(p); + ImcRespCbData *resp_cb_data = user_data; + TelModemPowerStatus *status; + gboolean powered = FALSE; + + TelModemResult result = TEL_MODEM_RESULT_FAILURE; + dbg("Enter"); + + tcore_check_return_assert(co != NULL); + tcore_check_return_assert(resp_cb_data != NULL); + + if (at_resp && at_resp->success) + result = TEL_MODEM_RESULT_SUCCESS; + + status = (TelModemPowerStatus *) + IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data); + + /* Update Core Object */ + switch (*status) { + case TEL_MODEM_POWER_ON: + dbg("Setting Modem Power status [ON] - [%s]", + (result == TEL_MODEM_RESULT_SUCCESS ? "SUCCESS" : "FAIL")); + powered = TRUE; + break; + case TEL_MODEM_POWER_OFF: + dbg("Setting Modem Power status [OFF] - [%s]", + (result == TEL_MODEM_RESULT_SUCCESS ? "SUCCESS" : "FAIL")); + powered = FALSE; + break; + default: + warn("Unexpected - Setting Modem Power status [RESET] - [%s]", + (result == TEL_MODEM_RESULT_SUCCESS ? "SUCCESS" : "FAIL")); + break; + } + tcore_modem_set_powered(co, powered); + + /* Invoke callback */ + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, NULL, resp_cb_data->cb_data); + + /* Free callback data */ + imc_destroy_resp_cb_data(resp_cb_data); +} + +static void on_response_imc_modem_set_flight_mode(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + CoreObject *co = tcore_pending_ref_core_object(p); + ImcRespCbData *resp_cb_data = user_data; + gboolean *enable; + + TelModemResult result = TEL_MODEM_RESULT_FAILURE; + dbg("Enter"); + + tcore_check_return_assert(co != NULL); + tcore_check_return_assert(resp_cb_data != NULL); + + if (at_resp && at_resp->success) + result = TEL_MODEM_RESULT_SUCCESS; + + enable = (gboolean *)IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data); + + dbg("Setting Modem Fiight mode - [%s] - [%s]", + (*enable ? "ON": "OFF"), + (result == TEL_MODEM_RESULT_SUCCESS ? "SUCCESS" : "FAIL")); + + /* Update Core Object */ + (void)tcore_modem_set_flight_mode_state(co, *enable); + + /* Invoke callback */ + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, NULL, resp_cb_data->cb_data); + + /* Free callback data */ + imc_destroy_resp_cb_data(resp_cb_data); + + /* + * In case Flight mode is set to OFF, we need to trigger + * Network Registration. + * + * This is taken care by Network module which hooks on + * Set Flight mode Request of Modem module. + */ +} + +/* Current modem does not support this operation */ +#if 0 +static void on_response_imc_modem_get_version(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + CoreObject *co = tcore_pending_ref_core_object(p); + ImcRespCbData *resp_cb_data = user_data; + TelModemVersion version = {{0}, {0}, {0}, {0}}; + + TelModemResult result = TEL_MODEM_RESULT_FAILURE; + dbg("Enter"); + + tcore_check_return_assert(co != NULL); + tcore_check_return_assert(resp_cb_data != NULL); + + if (at_resp) { + if (at_resp->lines) { + const gchar *line; + GSList *tokens = NULL; + + line = (const gchar *)at_resp->lines->data; + tokens = tcore_at_tok_new(line); + if (g_slist_length(tokens) > 0) { + if (at_resp->success) { + gchar *sw_ver = NULL, *hw_ver = NULL; + gchar *calib_date = NULL, *p_code = NULL; + + sw_ver = g_slist_nth_data(tokens, 0); + hw_ver = g_slist_nth_data(tokens, 1); + calib_date = g_slist_nth_data(tokens, 2); + p_code = g_slist_nth_data(tokens, 3); + if (sw_ver != NULL){ + g_strlcpy(version.software_version, + sw_ver, + TEL_MODEM_VERSION_LENGTH_MAX + 1); + } + if (hw_ver != NULL){ + g_strlcpy(version.hardware_version, + hw_ver, + TEL_MODEM_VERSION_LENGTH_MAX + 1); + } + if (calib_date != NULL){ + g_strlcpy(version.calibration_date, + calib_date, + TEL_MODEM_VERSION_LENGTH_MAX + 1); + } + if (p_code != NULL){ + g_strlcpy(version.product_code, + p_code, + TEL_MODEM_VERSION_LENGTH_MAX + 1); + } + dbg("Version - Software: [%s] Hardware: [%s] " + "Calibration date: [%s] Product " + "Code: [%s]", sw_ver, hw_ver, + calib_date, p_code); + + result = TEL_MODEM_RESULT_SUCCESS; + } else { + err("RESPONSE - [NOK]"); + err("[%s]", g_slist_nth_data(tokens, 0)); + } + } else { + err("Invalid response message"); + result = TEL_MODEM_RESULT_UNKNOWN_FAILURE; + } + tcore_at_tok_free(tokens); + } + } + + /* Invoke callback */ + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, &version, resp_cb_data->cb_data); + + /* Free callback data */ + imc_destroy_resp_cb_data(resp_cb_data); +} +#endif + +static void on_response_imc_modem_get_imei(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + CoreObject *co = tcore_pending_ref_core_object(p); + ImcRespCbData *resp_cb_data = user_data; + gchar imei[TEL_MODEM_IMEI_LENGTH_MAX +1] = {0}; + + TelModemResult result = TEL_MODEM_RESULT_FAILURE; + dbg("Enter"); + + tcore_check_return_assert(co != NULL); + tcore_check_return_assert(resp_cb_data != NULL); + + if (at_resp) { + if (at_resp->lines) { + const gchar *line; + GSList *tokens = NULL; + + line = (const gchar *)at_resp->lines->data; + tokens = tcore_at_tok_new(line); + if (g_slist_length(tokens) == 1) { + if (at_resp->success) { + dbg("RESPONSE - [OK]"); + g_strlcpy(imei, + (const gchar *)g_slist_nth_data(tokens, 0), + TEL_MODEM_IMEI_LENGTH_MAX+1); + dbg("IMEI: [%s]", imei); + + result = TEL_MODEM_RESULT_SUCCESS; + } else { + err("RESPONSE - [NOK]"); + err("[%s]", g_slist_nth_data(tokens, 0)); + } + } else { + err("Invalid response message"); + result = TEL_MODEM_RESULT_UNKNOWN_FAILURE; + } + tcore_at_tok_free(tokens); + } + } + + /* Invoke callback */ + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, imei, resp_cb_data->cb_data); + + /* Free callback data */ + imc_destroy_resp_cb_data(resp_cb_data); +} + +/* Modem Operations */ +/* + * Operation - set_power_status + * + * Request - + * AT-Command: AT+CFUN= + * where, + * + * 0 Mode to switch off MS + * ... Other modes are available for other oprations + * + * Response - + * Success: (No Result) + * OK + * Failure: + * +CME ERROR: + */ +static TelReturn imc_modem_set_power_status(CoreObject *co, + TelModemPowerStatus status, + TcoreObjectResponseCallback cb, void *cb_data) +{ + gchar *at_cmd; + guint power_mode; + + ImcRespCbData *resp_cb_data; + TelReturn ret; + + if (status == TEL_MODEM_POWER_ON) { + warn("Modem Power ON - Not supported by CP"); + return TEL_RETURN_OPERATION_NOT_SUPPORTED; + } else if (status == TEL_MODEM_POWER_ERROR) { + err("Modem Power ERROR - Invalid mode"); + return TEL_RETURN_INVALID_PARAMETER; + } else { + dbg("Modem Power OFF"); + power_mode = 0; + } + + /* AT-Command */ + at_cmd = g_strdup_printf("AT+CFUN=%d", power_mode); + + /* Response callback data */ + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, + &status, sizeof(TelModemPowerStatus)); + + /* Send Request to modem */ + ret = tcore_at_prepare_and_send_request(co, + at_cmd, NULL, + TCORE_AT_COMMAND_TYPE_NO_RESULT, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_modem_set_power_status, resp_cb_data, + on_send_imc_request, NULL, + 0, NULL, NULL); + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Set Power Status"); + + /* Free resources */ + g_free(at_cmd); + + return ret; +} + +/* + * Operation - set_flight_mode + * + * Request - + * AT-Command: AT+CFUN= + * where, + * + * 0 Mode to switch off MS + * 1 Full functionality + * 4 Mode to disable phone both transmit and receive + * RF circuits. Airplane mode. + * ... Other modes are available for other oprations + * + * Response - + * Success: (No Result) + * OK + * Failure: + * +CME ERROR: + */ +static TelReturn imc_modem_set_flight_mode(CoreObject *co, gboolean enable, + TcoreObjectResponseCallback cb, void *cb_data) +{ + gchar *at_cmd; + guint power_mode; + + ImcRespCbData *resp_cb_data; + TelReturn ret; + + if (enable) { + dbg("Flight mode - [ON]"); + power_mode = 4; + } else { + dbg("Flight mode - [OFF]"); + power_mode = 1; + } + + /* AT-Command */ + at_cmd = g_strdup_printf("AT+CFUN=%d", power_mode); + + /* Response callback data */ + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, + &enable, sizeof(gboolean)); + + /* Send Request to modem */ + ret = tcore_at_prepare_and_send_request(co, + at_cmd, NULL, + TCORE_AT_COMMAND_TYPE_NO_RESULT, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_modem_set_flight_mode, resp_cb_data, + on_send_imc_request, NULL, + 0, NULL, NULL); + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Set Flight mode"); + + /* Free resources */ + g_free(at_cmd); + + return ret; +} + +/* + * Operation - get_flight_mode + * + * Request - + * AT-Command: None + * Fetch information from Core Object + * + * Response - flight_mode (gboolean) + */ +static TelReturn imc_modem_get_flight_mode(CoreObject *co, + TcoreObjectResponseCallback cb, void *cb_data) +{ + gboolean flight_mode; + + /* Fetch Flight mode from Core Object */ + (void)tcore_modem_get_flight_mode_state(co, &flight_mode); + dbg("Modem Flight mode - [%s]", (flight_mode ? "ON": "OFF")); + + /* Invoke response callback */ + if (cb) + cb(co, (gint)TEL_MODEM_RESULT_SUCCESS, &flight_mode, cb_data); + + return TEL_RETURN_SUCCESS; +} + +/* + * Operation - get_version + * + * Request - + * AT-Command: AT+CGMR + * + * Response - version (TelModemVersion) + * Success: (Single line) - + * , , , + * OK + * Note: + * Success Response is different from standard 3GPP AT-Command (+CGMR) + * Failure: + * +CME ERROR: + */ +static TelReturn imc_modem_get_version(CoreObject *co, + TcoreObjectResponseCallback cb, void *cb_data) +{ + dbg("entry"); + +/* Current modem does not support this operation */ +#if 0 + ImcRespCbData *resp_cb_data; + TelReturn ret; + + /* Response callback data */ + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, + NULL, 0); + + /* Send Request to modem */ + ret = tcore_at_prepare_and_send_request(co, + "AT+CGMR", NULL, + TCORE_AT_COMMAND_TYPE_SINGLELINE, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_modem_get_version, resp_cb_data, + on_send_imc_request, NULL, + 0, NULL, NULL); + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Get Version"); + + return ret; +#endif + + dbg("exit"); + return TEL_RETURN_OPERATION_NOT_SUPPORTED; +} + +/* + * Operation - get_imei + * + * Request - + * AT-Command: AT+CGSN + * + * Response - imei (gchar array of length 20+'\0' bytes) + * Success: (Single line) + * + * OK + * Failure: + * +CME ERROR: + */ +static TelReturn imc_modem_get_imei(CoreObject *co, + TcoreObjectResponseCallback cb, void *cb_data) +{ + ImcRespCbData *resp_cb_data; + TelReturn ret; + + dbg("Enter"); + + /* Response callback data */ + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, + NULL, 0); + + /* Send Request to modem */ + ret = tcore_at_prepare_and_send_request(co, + "AT+CGSN", NULL, + TCORE_AT_COMMAND_TYPE_NUMERIC, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_modem_get_imei, resp_cb_data, + on_send_imc_request, NULL, + 0, NULL, NULL); + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Get IMEI"); + + return ret; +} + +/* Modem Operations */ +static TcoreModemOps imc_modem_ops = { + .set_power_status = imc_modem_set_power_status, + .set_flight_mode = imc_modem_set_flight_mode, + .get_flight_mode = imc_modem_get_flight_mode, + .get_version = imc_modem_get_version, + .get_imei = imc_modem_get_imei +}; + +gboolean imc_modem_init(TcorePlugin *p, CoreObject *co) +{ + dbg("Enter"); + + /* Set operations */ + tcore_modem_set_ops(co, &imc_modem_ops); + + /* Add Callbacks */ + tcore_object_add_callback(co, "+XDRVI:", on_event_imc_nvm_update, NULL); + + dbg("Exit"); + return TRUE; +} + +void imc_modem_exit(TcorePlugin *p, CoreObject *co) +{ + dbg("Exit"); +} + +/* + * NV Manager - Support for Remote File System + */ +/* NVM Hook */ +static gboolean __imc_nvm_modem_rfs_hook(const char *data) +{ + if (data != NULL) + if (data[NVM_FUNCTION_ID_OFFSET] == XDRV_INDICATION) + return TRUE; + + return FALSE; +} + +/* NVM Event */ +gboolean on_event_imc_nvm_update(CoreObject *co, + const void *event_info, void *user_data) +{ + GSList *tokens = NULL; + GSList *lines; + const char *line; + int function_id; + + gboolean ret = TRUE; + dbg("Entered"); + + lines = (GSList *)event_info; + line = lines->data; + dbg("Line: [%s]", line); + + function_id = nvm_sum_4_bytes(&line[NVM_FUNCTION_ID_OFFSET]); + dbg("Function ID: [%d]", function_id); + if (IUFP_UPDATE == function_id) { + dbg("Calling process nvm_update"); + + /* + * Process NV Update indication + * + * +XDRVI: IUFP_GROUP, IUFP_UPDATE, , + */ + if (NVM_NO_ERR == nvm_process_nv_update(line)) { + dbg("NV data processed successfully"); + + /* Acknowledge NV Update */ + __imc_modem_send_nvm_update_ack(co); + + return ret; + } else { + err("NV data processing failed"); + ret = FALSE; + } + } else { + tokens = tcore_at_tok_new(line); + if (g_slist_length(tokens) < 3) { + err("XDRVI event with less number of tokens, Ignore!!!"); + ret = FALSE; + } + else if (IUFP_GROUP_ID != atoi(g_slist_nth_data(tokens, 0))) { + err("Group ID mismatch, Ignore!!!"); + ret = FALSE; + } + else { + switch (atoi(g_slist_nth_data(tokens, 1))) { + case IUFP_UPDATE_REQ: + dbg("NV Update Request"); + + /* Acknowledge the Update Request */ + __imc_modem_send_nvm_update_request_ack(co); + break; + + case IUFP_NO_PENDING_UPDATE: + dbg("NO pending NV Update(s)!!!"); + /* Can send FLUSH request to get fresh updates */ + break; + + default: + err("Unspported Function ID [%d], Ignore", atoi(g_slist_nth_data(tokens, 1))); + ret = FALSE; + } + } + + tcore_at_tok_free(tokens); + } + + dbg("Exit"); + return ret; +} + +/* NVM Register */ +void imc_modem_register_nvm(CoreObject *co) +{ + char *cmd_str; + TelReturn ret; + + /* Prepare AT-Command */ + cmd_str = g_strdup_printf("AT+XDRV=%s, %s, %s", + IUFP_GROUP, IUFP_REGISTER_STR, XDRV_ENABLE); + + /* Send Request to modem */ + ret = tcore_at_prepare_and_send_request(co, + cmd_str, "+XDRV:", + TCORE_AT_COMMAND_TYPE_SINGLELINE, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + __on_response_modem_register_nvm, NULL, + on_send_imc_request, NULL, + 0, NULL, NULL); + if (ret != TEL_RETURN_SUCCESS) { + err("Failed to process request - [Register NVM]"); + } + else { + /* Add RFS hook */ + dbg("Adding NVM hook"); + tcore_at_add_hook(tcore_object_get_hal(co), __imc_nvm_modem_rfs_hook); + } + + g_free(cmd_str); +} diff --git a/src/imc_network.c b/src/imc_network.c new file mode 100644 index 0000000..d92b17d --- /dev/null +++ b/src/imc_network.c @@ -0,0 +1,1857 @@ +/* + * tel-plugin-imc + * + * Copyright (c) 2013 Samsung Electronics Co. Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "imc_network.h" +#include "imc_common.h" + +#define IMC_NETWORK_BASE_16 16 + +static TelNetworkAct __imc_network_map_act(guint act) +{ + /* + * + * 0 GSM + * 2 UTRAN + * 3 GSM w/EGPRS + * 4 UTRAN w/HSDPA + * 5 UTRAN w/HSUPA + * 6 UTRAN w/HSDPA and HSUPA + */ + switch (act) { + case 0: + return TEL_NETWORK_ACT_GSM; + case 2: + return TEL_NETWORK_ACT_UMTS; + case 3: + return TEL_NETWORK_ACT_EGPRS; + case 4: + return TEL_NETWORK_ACT_HSDPA; + case 5: + return TEL_NETWORK_ACT_HSUPA; + case 6: + return TEL_NETWORK_ACT_HSPA; + default: + return TEL_NETWORK_ACT_UNKNOWN; + } +} + +static TelNetworkRegStatus __imc_network_map_stat(guint stat) +{ + /* + * + * 0 Not registered, ME is not currently searching a + * new operator to register to + * 1 Registered, home network + * 2 Not registered, but ME is currently searching a + * new operator to register + * 3 Registration denied + * 4 Unknown + * 5 Registered, in roaming + */ + switch (stat) { + case 0: + return TEL_NETWORK_REG_STATUS_UNREGISTERED; + case 1: + return TEL_NETWORK_REG_STATUS_REGISTERED; + case 2: + return TEL_NETWORK_REG_STATUS_SEARCHING; + case 3: + return TEL_NETWORK_REG_STATUS_DENIED; + case 4: + return TEL_NETWORK_REG_STATUS_UNKNOWN; + case 5: + return TEL_NETWORK_REG_STATUS_ROAMING; + default: + return TEL_NETWORK_REG_STATUS_UNKNOWN; + } +} + +static void __on_response_imc_network_registration(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + dbg("Entry"); + + if (at_resp && at_resp->success) { + dbg("Network Registration - [OK]"); + } else { + err("Network Registration - [NOK]"); + } +} + +static void __imc_network_register_to_network(CoreObject *co) +{ + TelReturn ret; + + /* Send Request to modem */ + ret = tcore_at_prepare_and_send_request(co, + "AT+COPS=0", NULL, + TCORE_AT_COMMAND_TYPE_NO_RESULT, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + __on_response_imc_network_registration, NULL, + on_send_imc_request, NULL, + 0, NULL, NULL); + dbg("Sending Network Registration request: [%s]", + (ret == TEL_RETURN_SUCCESS ? "SUCCESS" : "FAIL")); +} + +static void __on_response_imc_network_fetch_nw_name_internal(CoreObject *co, + gint result, const void *response, void *user_data) +{ + TelNetworkIdentityInfo *identity = (TelNetworkIdentityInfo *)response; + + /* Send notification if result is SUCCESS */ + if (result == TEL_NETWORK_RESULT_SUCCESS) + tcore_object_send_notification(co, + TCORE_NOTIFICATION_NETWORK_IDENTITY, + sizeof(TelNetworkIdentityInfo), identity); +} + +static TcoreHookReturn __on_response_imc_hook_set_flight_mode(CoreObject *co, + gint result, TcoreCommand command, const void *response, const void *user_data) +{ + + tcore_check_return_value(result == TEL_MODEM_RESULT_SUCCESS, + TCORE_HOOK_RETURN_CONTINUE); + + dbg("Flight mode 'disabled', register to Network"); + + /* + * TODO - Check for selection_mode + * Need to check if it is Manual or Automatic and based on + * that need to initiate Network Registratin accordingly. + */ + __imc_network_register_to_network(co); + + return TCORE_HOOK_RETURN_CONTINUE; +} + +static void __on_response_imc_network_fetch_nw_name(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + CoreObject *co = tcore_pending_ref_core_object(p); + ImcRespCbData *resp_cb_data = user_data; + TelNetworkIdentityInfo identity = {0, }; + + TelNetworkResult result = TEL_NETWORK_RESULT_FAILURE; + + dbg("Enter"); + + tcore_check_return_assert(co != NULL); + tcore_check_return_assert(resp_cb_data != NULL); + + if (at_resp && at_resp->success) { + if (at_resp->lines) { + const gchar *line; + GSList *tokens = NULL; + gchar *token_str; + guint i, nol; + + /* Validate that only 3 lines of response is received */ + nol = g_slist_length(at_resp->lines); + if (nol > 3) { + err("Invalid response message"); + return; + } + + /* Process the Multi-line response */ + for (i = 0; i < nol; i++) { + line = g_slist_nth_data(at_resp->lines, i); + + /* + * Tokenize + * + * +XCOPS: [,[,]] + */ + dbg(" : [%s]", line); + tokens = tcore_at_tok_new(line); + + if ((token_str = tcore_at_tok_nth(tokens, 0))) { + guint type = atoi(token_str); + dbg(" : [%d]", type); + + switch (type) { + case 0: /* PLMN (mcc, mnc) */ + if ((token_str = tcore_at_tok_nth(tokens, 1))) { + if (strlen(token_str) > 0) { + identity.plmn = tcore_at_tok_extract((const char *)token_str); + + /* Update PLMN */ + tcore_network_set_plmn( co, identity.plmn); + } + } + break; + + case 1: /* Short Name in ROM (NV-RAM) */ + case 3: /* Short Network Operator Name (CPHS) */ + case 5: /* Short NITZ Name */ + if ((token_str = tcore_at_tok_nth(tokens, 1))) { + if (strlen(token_str) > 0) { + identity.short_name = tcore_at_tok_extract((const char *)token_str); + + + /* Update Short name */ + tcore_network_set_short_name(co, identity.short_name); + } + } + break; + + case 2: /* Long Name in ROM (NV-RAM) */ + case 4: /* Long Network Operator Name (CPHS) */ + case 6: /* Full NITZ Name */ + if ((token_str = tcore_at_tok_nth(tokens, 1))) { + if (strlen(token_str) > 0) { + identity.long_name = tcore_at_tok_extract((const char *)token_str); + + /* Update Long name */ + tcore_network_set_long_name(co, identity.long_name); + } + } + break; + + default: + break; + } + } + + /* Free resource */ + tcore_at_tok_free(tokens); + } + + /* Send Notification - Network identity */ + dbg("Network name - Long name: [%s] Short name: [%s] " + "PLMN: [%s]", identity.long_name, + identity.short_name, identity.plmn); + + result = TEL_NETWORK_RESULT_SUCCESS; + } + } + + /* Invoke callback */ + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, &identity, resp_cb_data->cb_data); + + /* Free resource */ + tcore_free(identity.long_name); + tcore_free(identity.short_name); + tcore_free(identity.plmn); + + /* Free callback data */ + imc_destroy_resp_cb_data(resp_cb_data); +} + +/* + * Operation - fetch_nw_name + * + * Request - + * AT-Command: AT+XCOPS= + * + * may be + * 0 numeric format of network MCC/MNC (three BCD + * digit country code and two/three BCD digit network code) + * 1 Short Name in ROM (NV-RAM) + * 2 Long Name in ROM (NV-RAM) + * 3 Short Network Operator Name (CPHS) + * 4 Long Network Operator Name (CPHS) + * 5 Short NITZ Name + * 6 Full NITZ Name + * 7 Service Provider Name + * 8 EONS short operator name from EF-PNN + * 9 EONS long operator name from EF-PNN + * 11 Short PLMN name (When PS or CS is registered) + * 12 Long PLMN name (When PS or CS is registered) + * 13 numeric format of network MCC/MNC even in limited service + * + * Response - Network name + * Success: (Multiple Single line) + * +XCOPS: [,[,]] + * OK + * Failure: + * +CME ERROR: + */ +static TelReturn __imc_network_fetch_nw_name(CoreObject *co, + TcoreObjectResponseCallback cb, void *cb_data) +{ + ImcRespCbData *resp_cb_data = NULL; + TelReturn ret; + + /* Response callback data */ + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, NULL, 0); + + /* Send Request to modem */ + ret = tcore_at_prepare_and_send_request(co, + "AT+XCOPS=0;+XCOPS=5;+XCOPS=6", "+XCOPS", + TCORE_AT_COMMAND_TYPE_MULTILINE, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + __on_response_imc_network_fetch_nw_name, resp_cb_data, + on_send_imc_request, NULL, + 0, NULL, NULL); + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Fetch Network name"); + + return ret; +} + +/* Hook functions */ +static TcoreHookReturn on_hook_imc_set_flight_mode(CoreObject *co, + TcoreCommand command, const void *request, const void *user_data, + TcoreObjectResponseCallback cb, const void *cb_data) +{ + gboolean *flight_mode = (gboolean *)request; + + /* + * Hook Set Flight mode request. + * + * Disable Flight mode - Hook response (if success Register to Network) + * Enable Flight mode - return + */ + if(*flight_mode != TRUE) { + /* Add response hook */ + tcore_object_add_response_hook(co, command, request, + __on_response_imc_hook_set_flight_mode, NULL); + + return TCORE_HOOK_RETURN_CONTINUE; + } + + dbg("Flight mode - [Enabled]"); + return TCORE_HOOK_RETURN_CONTINUE; +} + +static TcoreHookReturn on_hook_imc_sim_status(TcorePlugin *plugin, + TcoreNotification command, guint data_len, void *data, void *user_data) +{ + const TelSimCardStatus *sim_status = (TelSimCardStatus *)data; + + tcore_check_return_value(sim_status != NULL, + TCORE_HOOK_RETURN_CONTINUE); + + /* + * Hook SIM initialization Notification + * + * SIM INIT complete - Attach to network (Register to network) + * SIM INIT not complete - return + */ + if (*sim_status == TEL_SIM_STATUS_SIM_INIT_COMPLETED) { + CoreObject *co = (CoreObject *)user_data; + dbg("SIM Initialized!!! Attach to Network"); + + tcore_check_return_value_assert(co != NULL, + TCORE_HOOK_RETURN_CONTINUE); + + /* + * TODO - Check for selection_mode + * Need to check if it is Manual or Automatic and based on + * that need to initiate Network Registratin accordingly. + */ + __imc_network_register_to_network(co); + + return TCORE_HOOK_RETURN_CONTINUE; + } + + dbg("SIM not yet initialized - SIM Status: [%d]", *sim_status); + return TCORE_HOOK_RETURN_CONTINUE; +} + +/* Notification callbacks */ +/* + * Notification: +CREG: [,,[,]] + * + * Possible values of can be + * 0 Not registered, ME is not currently searching + * a new operator to register to + * 1 Registered, home network + * 2 Not registered, but ME is currently searching + * a new operator to register + * 3 Registration denied + * 4 Unknown + * 5 Registered, in roaming + * + * + * string type; two byte location area code in + * hexadecimal format (e.g. 00C3) + * + * + * string type; four byte cell ID in hexadecimal + * format (e.g. 0000A13F) + * + * + * 0 GSM + * 2 UTRAN + * 3 GSM w/EGPRS + * 4 UTRAN w/HSDPA + * 5 UTRAN w/HSUPA + * 6 UTRAN w/HSDPA and HSUPA + */ +static gboolean on_notification_imc_cs_network_info(CoreObject *co, + const void *event_info, void *user_data) +{ + GSList *lines = NULL; + gchar *line = NULL; + + dbg("Network notification - CS network info: [+CREG]"); + + lines = (GSList *)event_info; + if (g_slist_length(lines) != 1) { + err("+CREG unsolicited message expected to be Single line " + "but received multiple lines"); + return TRUE; + } + + line = (gchar *) (lines->data); + if (line != NULL) { + TelNetworkRegStatusInfo registration_status = {0, }; + TelNetworkCellInfo cell_info = {0, }; + GSList *tokens = NULL; + gchar *token_str; + guint stat = 0, act = 0, lac = 0, ci = 0; + gboolean roam_state = FALSE; + + /* + * Tokenize + * + * +CREG: [,,[,]] + */ + tokens = tcore_at_tok_new(line); + if (g_slist_length(tokens) < 1) { + err("Invalid notification message"); + goto out; + } + + /* */ + if ((token_str = g_slist_nth_data(tokens, 0)) == NULL) { + err("No in +CREG"); + goto out; + } + stat = __imc_network_map_stat(atoi(token_str)); + (void)tcore_network_set_cs_reg_status(co, stat); + + /* */ + if ((token_str = g_slist_nth_data(tokens, 1))) { + token_str = tcore_at_tok_extract((const gchar *)token_str); + + lac = (guint)strtol(token_str, NULL, IMC_NETWORK_BASE_16); + + /* Update Location Area Code (lac) information */ + (void)tcore_network_set_lac(co, lac); + + tcore_free(token_str); + } else { + dbg("No in +CREG"); + (void)tcore_network_get_lac(co, &lac); + } + + /* */ + if ((token_str = g_slist_nth_data(tokens, 2))) { + token_str = tcore_at_tok_extract((const gchar *)token_str); + + ci = (guint)strtol(token_str, NULL, IMC_NETWORK_BASE_16); + + /* Update Cell ID (ci) information */ + (void)tcore_network_set_cell_id(co, ci); + + tcore_free(token_str); + } else { + dbg("No in +CREG"); + (void)tcore_network_get_cell_id(co, &ci); + } + + /* */ + if ((token_str = g_slist_nth_data(tokens, 3))) { + act = __imc_network_map_act(atoi(token_str)); + (void)tcore_network_set_access_technology(co, act); + } else { + dbg("No in +CREG"); + (void)tcore_network_get_access_technology(co, &act); + } + dbg(": %d : 0x%x : 0x%x : %d", stat, lac, ci, act); + + /* Send Notification - Network (CS) Registration status */ + registration_status.cs_status = stat; + registration_status.act = act; + (void)tcore_network_get_ps_reg_status(co, ®istration_status.ps_status); + + tcore_object_send_notification(co, + TCORE_NOTIFICATION_NETWORK_REGISTRATION_STATUS, + sizeof(TelNetworkRegStatusInfo), ®istration_status); + + switch (stat) { + case TEL_NETWORK_REG_STATUS_ROAMING: + roam_state = TRUE; // no break + case TEL_NETWORK_REG_STATUS_REGISTERED: + /* Fetch Network name - Internal request */ + (void)__imc_network_fetch_nw_name(co, + __on_response_imc_network_fetch_nw_name_internal, NULL); + break; + default: + break; + } + + /* Set Roaming state */ + tcore_network_set_roam_state(co, roam_state); + + /* Send Notification - Cell info */ + cell_info.lac = (gint)lac; + cell_info.cell_id = (gint)ci; + (void)tcore_network_get_rac(co, &cell_info.rac); + + tcore_object_send_notification(co, + TCORE_NOTIFICATION_NETWORK_LOCATION_CELLINFO, + sizeof(TelNetworkCellInfo), &cell_info); + +out: + /* Free resource */ + tcore_at_tok_free(tokens); + } + + return TRUE; +} + +/* + * Notification: +CGREG: [,,[,,]] + * + * Possible values of can be + * 0 Not registered, ME is not currently searching a + * new operator to register to + * 1 Registered, home network + * 2 Not registered, but ME is currently searching a + * new operator to register + * 3 Registration denied + * 4 Unknown + * 5 Registered, in roaming + * + * + * string type; two byte location area code in + * hexadecimal format (e.g. 00C3) + * + * + * string type; four byte cell ID in hexadecimal + * format (e.g. 0000A13F) + * + * + * 0 GSM + * 2 UTRAN + * 3 GSM w/EGPRS + * 4 UTRAN w/HSDPA + * 5 UTRAN w/HSUPA + * 6 UTRAN w/HSDPA and HSUPA + * + * : + * string type; one byte routing area code in hexadecimal format + */ +static gboolean on_notification_imc_ps_network_info(CoreObject *co, + const void *event_info, void *user_data) +{ + GSList *lines = NULL; + gchar *line = NULL; + + dbg("Network notification - PS network info: [+CGREG]"); + + lines = (GSList *)event_info; + if (g_slist_length(lines) != 1) { + err("+CGREG unsolicited message expected to be Single line " + "but received multiple lines"); + return TRUE; + } + + line = (gchar *) (lines->data); + if (line != NULL) { + TelNetworkRegStatusInfo registration_status = {0, }; + TelNetworkCellInfo cell_info = {0, }; + GSList *tokens = NULL; + gchar *token_str; + guint stat = 0, act = 0, lac = 0, ci = 0, rac = 0; + gboolean roam_state = FALSE; + + /* + * Tokenize + * + * +CGREG: [,,[,,]] + */ + tokens = tcore_at_tok_new(line); + if (g_slist_length(tokens) < 1) { + err("Invalid notification message"); + goto out; + } + + /* */ + if ((token_str = g_slist_nth_data(tokens, 0)) == NULL) { + err("No in +CGREG"); + goto out; + } + stat = __imc_network_map_stat(atoi(token_str)); + (void)tcore_network_set_ps_reg_status(co, stat); + + /* */ + if ((token_str = g_slist_nth_data(tokens, 1))) { + token_str = tcore_at_tok_extract((const gchar *)token_str); + + lac = (guint)strtol(token_str, NULL, IMC_NETWORK_BASE_16); + + /* Update Location Area Code (lac) information */ + (void)tcore_network_set_lac(co, lac); + + tcore_free(token_str); + } else { + dbg("No in +CGREG"); + (void)tcore_network_get_lac(co, &lac); + } + + /* */ + if ((token_str = g_slist_nth_data(tokens, 2))) { + token_str = tcore_at_tok_extract((const gchar *)token_str); + + ci = (guint)strtol(token_str, NULL, IMC_NETWORK_BASE_16); + + /* Update Cell ID (ci) information */ + (void)tcore_network_set_cell_id(co, ci); + + tcore_free(token_str); + } else { + dbg("No in +CGREG"); + (void)tcore_network_get_cell_id(co, &ci); + } + + /* */ + if ((token_str = g_slist_nth_data(tokens, 3))) { + act = __imc_network_map_act(atoi(token_str)); + (void)tcore_network_set_access_technology(co, act); + } else { + dbg("No in +CGREG"); + (void)tcore_network_get_access_technology(co, &act); + } + + /* */ + if ((token_str = g_slist_nth_data(tokens, 4))) { + token_str = tcore_at_tok_extract((const gchar *)token_str); + + rac = (guint)strtol(token_str, NULL, IMC_NETWORK_BASE_16); + + /* Update Routing Area Code (rac) information */ + (void)tcore_network_set_rac(co, rac); + + tcore_free(token_str); + } else { + err("No in +CGREG"); + (void)tcore_network_get_rac(co, &rac); + } + dbg(": %d : 0x%x : 0x%x : %d : 0x%x", stat, lac, ci, act, rac); + + /* Send Notification - Network (PS) Registration status */ + registration_status.ps_status = stat; + registration_status.act = act; + (void)tcore_network_get_cs_reg_status(co, ®istration_status.cs_status); + + tcore_object_send_notification(co, + TCORE_NOTIFICATION_NETWORK_REGISTRATION_STATUS, + sizeof(TelNetworkRegStatusInfo), ®istration_status); + + /* Set Roaming state */ + if (registration_status.ps_status == TEL_NETWORK_REG_STATUS_ROAMING) + roam_state = TRUE; + + tcore_network_set_roam_state(co, roam_state); + + /* Send Notification - Cell info */ + cell_info.lac = lac; + cell_info.cell_id = ci; + cell_info.rac = rac; + tcore_object_send_notification(co, + TCORE_NOTIFICATION_NETWORK_LOCATION_CELLINFO, + sizeof(TelNetworkCellInfo), &cell_info); + +out: + /* Free resource */ + tcore_at_tok_free(tokens); + } + + return TRUE; +} + +/* + * Notification: +XNITZINFO: ,,,, + * + * + * string type; Network name in long alphanumeric format. + * + * + * string type; Network name in short alphanumeric format. + * + * + * Local Time Zone; represented as 1 unit = 15 minutes. + * + * + * string type value; Universal Time + * format is "yy/MM/dd,hh:mm:ss", + * wherein characters indicates year, month, day, hour, + * minutes, seconds. + * + * Daylight Saving Time; represented in hours. + */ +static gboolean on_notification_imc_network_time_info(CoreObject *co, + const void *event_info, void *user_data) +{ + GSList *lines = NULL; + gchar *line = NULL; + + dbg("Network notification - Time info: [+XNITZINFO]"); + + lines = (GSList *)event_info; + if (g_slist_length(lines) != 1) { + err("+XNITZINFO unsolicited message expected to be Single line " + "but received multiple lines"); + return TRUE; + } + + line = (gchar *)lines->data; + if (line != NULL) { + GSList *tokens = NULL; + TelNetworkNitzInfoNoti nitz_info = {0, }; + gchar *fullname, *shortname; + gchar *ltz, *time; + gchar tmp_time[8] = {0}; + gchar *dstoff; + + /* + * Tokenize + * + * +XNITZINFO: ,,,, + */ + tokens = tcore_at_tok_new(line); + + /* */ + if ((fullname = tcore_at_tok_nth(tokens, 1))) { + if (strlen(fullname) > 0) { + fullname = tcore_at_tok_extract((const char *)fullname); + + /* Update Long name */ + tcore_network_set_long_name(co, fullname); + + tcore_free(fullname); + } + } + + /* */ + if ((shortname = tcore_at_tok_nth(tokens, 1))) { + if (strlen(shortname) > 0) { + shortname = tcore_at_tok_extract((const char *)shortname); + + /* Update Short name */ + tcore_network_set_short_name(co, shortname); + + tcore_free(shortname); + } + } + + /* */ + if ((ltz = g_slist_nth_data(tokens, 2))) + nitz_info.gmtoff = atoi(ltz) * 15;/* gmtoff in minutes */ + + if ((time = g_slist_nth_data(tokens, 3)) + && (strlen(time) > 18)) { + /* (time + 1) - Skip past initial quote (") */ + g_strlcpy(tmp_time, time + 1, 2+1); + nitz_info.year = atoi(tmp_time); + + /* skip slash (/) after year param */ + g_strlcpy(tmp_time, time + 4, 2+1); + nitz_info.month = atoi(tmp_time); + + /* skip past slash (/) after month param */ + g_strlcpy(tmp_time, time + 7, 2+1); + nitz_info.day = atoi(tmp_time); + + /* skip past comma (,) after day param */ + g_strlcpy(tmp_time, time + 10, 2+1); + nitz_info.hour = atoi(tmp_time); + + /* skip past colon (:) after hour param */ + g_strlcpy(tmp_time, time + 13, 2+1); + nitz_info.minute = atoi(tmp_time); + + /* skip past colon (:) after minute param */ + g_strlcpy(tmp_time, time + 16, 2+1); + nitz_info.second = atoi(tmp_time); + } + + /* */ + if ((dstoff = g_slist_nth_data(tokens, 4))) { + nitz_info.dstoff = atoi(dstoff); + nitz_info.isdst = TRUE; + } + + /* Get PLMN */ + tcore_network_get_plmn(co, &nitz_info.plmn); + + /* Send Notification - Network time info */ + tcore_object_send_notification(co, + TCORE_NOTIFICATION_NETWORK_TIMEINFO, + sizeof(TelNetworkNitzInfoNoti), &nitz_info); + + /* Free resource */ + tcore_free(nitz_info.plmn); + tcore_at_tok_free(tokens); + } + + return TRUE; +} + +/* + * Notification: + * +XCIEV: , + * or + * +XCIEV:, + * + * 'Radio Signal Strength' can have the values + * 0 -107 dBm or less or unknown + * 1 -99 dBm or less + * 2 -91 dBm or less + * 3 -83 dBm or less + * 4 -75 dBm or less + * 5 -67 dBm or less + * 6 -59 dBm or less + * 7 -51 dBm or less + * + * 'Battery Level' can have the values + * 0 0 % <= level < 5 % + * 1 5 % <= level < 15 % + * 2 15 % <= level < 25 % + * 3 25 % <= level < 40 % + * 4 40 % <= level < 55 % + * 5 55 % <= level < 70 % + * 6 70 % <= level < 85 % + * 7 85 % <= level <= 100 % + * + * NOTE: + * is not consider for + * TCORE_NOTIFICATION_NETWORK_RSSI notification + */ +static gboolean on_notification_imc_network_rssi(CoreObject *co, + const void *event_info, void *user_data) +{ + GSList *lines = NULL; + gchar *line = NULL; + + dbg("Network notification - Icon (rssi) info: [+XCIEV]"); + + lines = (GSList *)event_info; + if (g_slist_length(lines) != 1) { + err("+XCIEV unsolicited message expected to be Single line " + "but received multiple lines"); + return TRUE; + } + + line = (gchar *)lines->data; + if (line != NULL) { + GSList *tokens = NULL; + gchar *rssi_token; + + /* + * Tokenize + * + * +XCIEV: , + */ + tokens = tcore_at_tok_new(line); + + rssi_token = (gchar *)g_slist_nth_data(tokens, 0); + if (rssi_token && strlen(rssi_token)) { + guint rssi_bar = atoi(rssi_token); + dbg("RSSI Level: [%d]", rssi_bar); + + /* Send Notification - Network Rssi */ + tcore_object_send_notification(co, + TCORE_NOTIFICATION_NETWORK_RSSI, + sizeof(guint), &rssi_bar); + } + + /* Free resource */ + tcore_at_tok_free(tokens); + } + + return TRUE; +} + +/* Network Responses */ + +static void on_response_imc_network_search(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + CoreObject *co = tcore_pending_ref_core_object(p); + ImcRespCbData *resp_cb_data = user_data; + TelNetworkResult result = TEL_NETWORK_RESULT_FAILURE; //TODO - CME Error mapping required. + TelNetworkPlmnList plmn_list = {0,}; + guint num_network_avail; + guint count; + GSList *tokens = NULL; + + dbg("Enter"); + tcore_check_return_assert(co != NULL); + tcore_check_return_assert(resp_cb_data != NULL); + + if (at_resp && at_resp->success) { + const gchar *line; + GSList *net_token = NULL; + gchar *resp; + gint act; + + if (!at_resp->lines) { + err("invalid response received"); + goto END; + } + + line = (char *) at_resp->lines->data; + tokens = tcore_at_tok_new(line); + num_network_avail = g_slist_length(tokens); + if (num_network_avail < 1) { + err("invalid message"); + goto END; + } + + plmn_list.network_list = tcore_malloc0(sizeof(TelNetworkInfo) * num_network_avail); + dbg("RESPONSE OK"); + plmn_list.count = 0; + for (count = 0; count < num_network_avail; count++) { + + net_token = tcore_at_tok_new(g_slist_nth_data(tokens, count)); + if (NULL == net_token) + continue; + + resp = tcore_at_tok_nth(net_token, 0); + if (resp != NULL) { + plmn_list.network_list[count].plmn_status = atoi(resp); + dbg("status[%d]", plmn_list.network_list[count].plmn_status); + } + + if ((resp = tcore_at_tok_nth(net_token, 1))) { + /* Long Alpha name */ + dbg("long alpha name[%s]", resp); + plmn_list.network_list[count].network_identity.long_name = + tcore_at_tok_extract(resp); + } + + if ((resp = tcore_at_tok_nth(net_token, 2))) { + /* Short Alpha name */ + dbg("Short Alpha name[%s]", resp); + plmn_list.network_list[count].network_identity.short_name = + tcore_at_tok_extract(resp); + } + + /* PLMN ID */ + if ((resp = tcore_at_tok_nth(net_token, 3))) { + dbg("PLMN ID[%s]", resp); + plmn_list.network_list[count].network_identity.plmn = + tcore_at_tok_extract(resp); + } + + /* Parse Access Technology */ + if ((resp = tcore_at_tok_nth(tokens, 4))) { + act = atoi(resp); + if (0 == act) + plmn_list.network_list[count].act = TEL_NETWORK_ACT_GSM; + else if (2 == act) + plmn_list.network_list[count].act = TEL_NETWORK_ACT_UMTS; + } + + dbg("Operator [%d] :: status = %d, long_name = %s, short_name = %s plmn = %s, AcT=%d", + plmn_list.count, + plmn_list.network_list[count].plmn_status, + plmn_list.network_list[count].network_identity.long_name, + plmn_list.network_list[count].network_identity.short_name, + plmn_list.network_list[count].network_identity.plmn, + plmn_list.network_list[count].act); + + plmn_list.count ++; + tcore_at_tok_free(net_token); + } + result = TEL_NETWORK_RESULT_SUCCESS; + } else { + err("RESPONSE NOK"); + if (at_resp->lines) + err("CME Error[%s]",(char *)at_resp->lines->data); + } + +END: + dbg("Network search : [%s]", + (result == TEL_NETWORK_RESULT_SUCCESS ? "SUCCESS" : "FAIL")); + + /* Invoke callback */ + if(resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, &plmn_list, resp_cb_data->cb_data); + + imc_destroy_resp_cb_data(resp_cb_data); + /* Free resources*/ + for (count = 0; count < num_network_avail; count++) { + g_free(plmn_list.network_list[count].network_identity.long_name); + g_free(plmn_list.network_list[count].network_identity.short_name); + g_free(plmn_list.network_list[count].network_identity.plmn); + } + + tcore_free(plmn_list.network_list); + tcore_at_tok_free(tokens); +} + +static void on_response_imc_network_get_selection_mode(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + CoreObject *co = tcore_pending_ref_core_object(p); + ImcRespCbData *resp_cb_data = user_data; + TelNetworkSelectionMode selection_mode = -1; + GSList *tokens = NULL; + + TelNetworkResult result = TEL_NETWORK_RESULT_FAILURE; //TODO - CME Error mapping required. + dbg("Enter"); + + tcore_check_return_assert(co != NULL); + tcore_check_return_assert(resp_cb_data != NULL); + + if (at_resp && at_resp->success) { + const gchar *line; + gint mode; + + if (!at_resp->lines) { + err("invalid response received"); + goto END; + } + + line = (char *) at_resp->lines->data; + tokens = tcore_at_tok_new(line); + if (g_slist_length(tokens) < 1) { + msg("invalid message"); + goto END; + } + dbg("RESPONSE OK"); + + mode = atoi(tcore_at_tok_nth(tokens, 0)); + if(mode == 0) + selection_mode = TEL_NETWORK_SELECTION_MODE_AUTOMATIC; + else if (mode == 1) + selection_mode = TEL_NETWORK_SELECTION_MODE_MANUAL; + + result = TEL_NETWORK_RESULT_SUCCESS; + dbg("selection mode[%d]", selection_mode); + + } else { + err("RESPONSE NOK"); + } + +END: + dbg("Get selection mode : [%s]", + (result == TEL_NETWORK_RESULT_SUCCESS ? "SUCCESS" : "FAIL")); + /* Invoke callback */ + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, &selection_mode, resp_cb_data->cb_data); + + /* Free callback data */ + imc_destroy_resp_cb_data(resp_cb_data); + /* Free resource*/ + tcore_at_tok_free(tokens); +} + +static void on_response_imc_network_default(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + CoreObject *co = tcore_pending_ref_core_object(p); + ImcRespCbData *resp_cb_data = user_data; + TelNetworkResult result = TEL_NETWORK_RESULT_FAILURE; //TODO - CME Error mapping required. + + dbg("Enter"); + tcore_check_return_assert(co != NULL); + tcore_check_return_assert(resp_cb_data != NULL); + + if (at_resp && at_resp->success) { + dbg("RESPONSE OK"); + result = TEL_NETWORK_RESULT_SUCCESS; + } else { + err("RESPONSE NOK"); + if (at_resp->lines) + err("CME Error[%s]",(char *)at_resp->lines->data); + } + + /* Invoke callback */ + if(resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, NULL, resp_cb_data->cb_data); + + imc_destroy_resp_cb_data(resp_cb_data); +} + + +static void on_response_imc_network_get_mode(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + CoreObject *co = tcore_pending_ref_core_object(p); + ImcRespCbData *resp_cb_data = user_data; + TelNetworkResult result = TEL_NETWORK_RESULT_FAILURE; //TODO - CME Error mapping required. + TelNetworkMode mode = -1; + GSList *tokens = NULL; + + dbg("Enter"); + tcore_check_return_assert(co != NULL); + tcore_check_return_assert(resp_cb_data != NULL); + + if (at_resp && at_resp->success) { + const gchar *line; + gint net_mode; + + if (!at_resp->lines) { + err("invalid response received"); + goto END; + } + + line = (char *) at_resp->lines->data; + tokens = tcore_at_tok_new(line); + if (g_slist_length(tokens) < 1) { + err("invalid message"); + goto END; + } + + dbg("RESPONSE OK"); + net_mode = atoi(tcore_at_tok_nth(tokens, 0)); + dbg("mode = %d", net_mode); + + switch(net_mode) { + case 0: + mode = TEL_NETWORK_MODE_2G; + break; + case 1: + mode = TEL_NETWORK_MODE_AUTO; + break; + case 2: + mode = TEL_NETWORK_MODE_3G; + break; + default: + err("Unsupported mode [%d]", net_mode); + goto END; + } + result = TEL_NETWORK_RESULT_SUCCESS; + } else { + err("RESPONSE NOK"); + } +END: + /* Invoke callback */ + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, &mode, resp_cb_data->cb_data); + + /* Free callback data */ + imc_destroy_resp_cb_data(resp_cb_data); + /* Free resource*/ + tcore_at_tok_free(tokens); +} + +static void on_response_imc_network_get_preferred_plmn(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + CoreObject *co = tcore_pending_ref_core_object(p); + ImcRespCbData *resp_cb_data = user_data; + TelNetworkPreferredPlmnList plmn_list = {0,}; + guint count = 0, total_lines = 0; + TelNetworkResult result = TEL_NETWORK_RESULT_FAILURE; //TODO - CME Error mapping required. + dbg("Enter"); + + tcore_check_return_assert(co != NULL); + tcore_check_return_assert(resp_cb_data != NULL); + + if (at_resp && at_resp->success) { + GSList *tokens; + gchar *resp; + gchar *line; + gboolean gsm_act2 = FALSE, gsm_compact_act2 = FALSE; + gboolean utran_act2 = FALSE; + + if (!at_resp->lines) { + err("invalid response received"); + goto END; + } + + total_lines = g_slist_length(at_resp->lines); + if (total_lines < 1) { + msg("invalid message"); + goto END; + } + + dbg("RESPONSE OK"); + result = TEL_NETWORK_RESULT_SUCCESS; + + plmn_list.list = tcore_malloc0(sizeof(TelNetworkPreferredPlmnInfo) * total_lines); + plmn_list.count = 0; + + for (count = 0; count < total_lines; count++) { + /* Take each line response at a time & parse it */ + line = tcore_at_tok_nth(at_resp->lines, count); + tokens = tcore_at_tok_new(line); + + /*Index */ + if ((resp = tcore_at_tok_nth(tokens, 0))) { + plmn_list.list[count].index = atoi(resp); + } + + /* PLMN ID */ + if ((resp = tcore_at_tok_nth(tokens, 2))) { + plmn_list.list[count].plmn = tcore_at_tok_extract(resp); + } + + /*GSM_AcT1 */ + if ((resp = tcore_at_tok_nth(tokens, 3))) { + gsm_act2 = atoi(resp); + } + + /*GSM_Compact_AcT2 */ + if ((resp = tcore_at_tok_nth(tokens, 4))) { + gsm_compact_act2 = atoi(resp); + } + + /*UTRAN_AcT2 */ + if ((resp = tcore_at_tok_nth(tokens, 5))) { + utran_act2 = atoi(resp); + } + + if (gsm_act2) + plmn_list.list[count].act = TEL_NETWORK_ACT_UMTS; + else if (utran_act2 || gsm_compact_act2) + plmn_list.list[count].act = TEL_NETWORK_ACT_GSM; + + /* free tokens*/ + tcore_at_tok_free(tokens); + + dbg("index[%d], plmn[%s], act[%d]", + plmn_list.list[count].index, + plmn_list.list[count].plmn, + plmn_list.list[count].act); + + } + plmn_list.count = count; + } else { + err("RESPONSE NOK"); + if (at_resp->lines) + err("CME Error[%s]",(char *)at_resp->lines->data); + } + +END: + dbg("get preferred plmn : [%s]", + (result == TEL_NETWORK_RESULT_SUCCESS ? "SUCCESS" : "FAIL")); + + /* Invoke callback */ + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, &plmn_list, resp_cb_data->cb_data); + + /* Free callback data */ + imc_destroy_resp_cb_data(resp_cb_data); + + for(count = 0; count < total_lines; count++) { + g_free(plmn_list.list[count].plmn); + } + tcore_free(plmn_list.list); +} + + +/* Network Operations */ +/* + * Operation - set_power_status + * + * Request - + * AT-Command: AT+XCOPS= + * + * may be + * 0 numeric format of network MCC/MNC (three BCD + * digit country code and two/three BCD digit network code) + * 1 Short Name in ROM (NV-RAM) + * 2 Long Name in ROM (NV-RAM) + * 3 Short Network Operator Name (CPHS) + * 4 Long Network Operator Name (CPHS) + * 5 Short NITZ Name + * 6 Full NITZ Name + * 7 Service Provider Name + * 8 EONS short operator name from EF-PNN + * 9 EONS long operator name from EF-PNN + * 11 Short PLMN name (When PS or CS is registered) + * 12 Long PLMN name (When PS or CS is registered) + * 13 numeric format of network MCC/MNC even in limited service + * + * Response - Network name + * Success: (Multiple Single line) + * +XCOPS: [,[,]] + * OK + * Failure: + * +CME ERROR: + */ +static TelReturn imc_network_get_identity_info(CoreObject *co, + TcoreObjectResponseCallback cb, void *cb_data) +{ + return __imc_network_fetch_nw_name(co, cb, cb_data); +} + +/* + * Operation - network search + * Request - + * AT-Command: AT+COPS=? + * + * Response - + * Success: (Single line) + * +COPS: [list of supported (,long alphanumeric + * ,short alphanumeric ,numeric [,< AcT>] + * [,,(list of supported s),(list of supported s)] + + * + * describes the format in which operator name is to be displayed. Different values of can be: + * 0 format presentations are set to long alphanumeric. If Network name not available it displays + * combination of Mcc and MNC in string format. + * 1 format presentation is set to short alphanumeric. + * 2 format presentations set to numeric. + * : + * string type given in format ; this field may be up to 16 character long for long alphanumeric format, up + * to 8 characters for short alphanumeric format and 5 Characters long for numeric format (MCC/MNC codes) + * : + * describes the status of the network. It is one of the response parameter for test command. + * 0 Unknown Networks + * 1 Network Available + * 2 Current + * 3 Forbidden Network + * + * indicates the radio access technology and values can be: + * 0 GSM + * 2 UMTS + * OK + * Failure: + * +CME ERROR: + */ + +static TelReturn imc_network_search(CoreObject *co, + TcoreObjectResponseCallback cb, void *cb_data) +{ + ImcRespCbData *resp_cb_data; + TelReturn ret = TEL_RETURN_INVALID_PARAMETER; + + /* Response callback data */ + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, NULL, 0); + + /* Send Request to modem */ + ret = tcore_at_prepare_and_send_request(co, + "AT+COPS=?", "+COPS", + TCORE_AT_COMMAND_TYPE_SINGLELINE, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_network_search, resp_cb_data, + on_send_imc_request, NULL, + 0, NULL, NULL); + + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Network Search"); + return ret; +} + +static TelReturn imc_network_cancel_search(CoreObject *co, + TcoreObjectResponseCallback cb, void *cb_data) +{ + ImcRespCbData *resp_cb_data; + TelReturn ret = TEL_RETURN_INVALID_PARAMETER; + + /* Response callback data */ + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, NULL, 0); + + /* Send Request to modem */ + ret = tcore_at_prepare_and_send_request(co, + "\e", NULL, + TCORE_AT_COMMAND_TYPE_NO_RESULT, + TCORE_PENDING_PRIORITY_IMMEDIATELY, + NULL, + on_response_imc_network_default, resp_cb_data, + on_send_imc_request, NULL, + 0, NULL, NULL); + + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Cancel network search"); + return ret; +} + +/* + * Operation - automatic network selection + * Request - + * AT-Command: AT+COPS= [ [, [, > [, ]]]] + * where + * + * is used to select, whether the selection is done automatically by the ME or is forced by this command to + * operator given in the format . + * The values of can be: + * 0 Automatic, in this case other fields are ignored and registration is done automatically by ME + * 1 Manual. Other parameters like format and operator need to be passed + * 2 Deregister from network + * 3 It sets value. In this case becomes a mandatory input + * 4 Manual / Automatic. In this case if manual selection fails then automatic mode is entered + * + * Response - + * Success:(No result) + * OK or + * +CME ERROR: + */ +static TelReturn imc_network_select_automatic(CoreObject *co, + TcoreObjectResponseCallback cb, void *cb_data) +{ + ImcRespCbData *resp_cb_data; + TelReturn ret = TEL_RETURN_INVALID_PARAMETER; + dbg("entry"); + + /* Response callback data */ + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, NULL, 0); + + /* Send Request to modem */ + ret = tcore_at_prepare_and_send_request(co, + "AT+COPS=0", NULL, + TCORE_AT_COMMAND_TYPE_NO_RESULT, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_network_default, resp_cb_data, + on_send_imc_request, NULL, + 0, NULL, NULL); + + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Automatic network selection"); + return ret; +} + +/* + * Operation - manual network selection + * Request - + * AT-Command: AT+COPS= [ [, [, > [, ]]]] + * where + * + * is used to select, whether the selection is done automatically by the ME or is forced by this command to + * operator given in the format . + * The values of can be: + * 0 Automatic, in this case other fields are ignored and registration is done automatically by ME + * 1 Manual. Other parameters like format and operator need to be passed + * 2 Deregister from network + * 3 It sets value. In this case becomes a mandatory input + * 4 Manual / Automatic. In this case if manual selection fails then automatic mode is entered. + * + * string type given in format ; this field may be up to 16 character long for long alphanumeric format, up + * to 8 characters for short alphanumeric format and 5 Characters long for numeric format (MCC/MNC codes) + * + * indicates the radio access technology and values can be: + * 0 GSM + * 2 UMTS + * + * Response - + * Success:(No result) + * OK or + * +CME ERROR: + */ +static TelReturn imc_network_select_manual(CoreObject *co, + const TelNetworkSelectManualInfo *sel_manual, + TcoreObjectResponseCallback cb, void *cb_data) +{ + ImcRespCbData *resp_cb_data; + TelReturn ret = TEL_RETURN_INVALID_PARAMETER; + gchar *at_cmd; + gint act; + dbg("entry"); + + switch(sel_manual->act) { + case TEL_NETWORK_ACT_GSM: + case TEL_NETWORK_ACT_GPRS: + case TEL_NETWORK_ACT_EGPRS: + act = 0; + break; + case TEL_NETWORK_ACT_UMTS: + case TEL_NETWORK_ACT_GSM_AND_UMTS: + case TEL_NETWORK_ACT_HSDPA: + case TEL_NETWORK_ACT_HSPA: + act = 2; + break; + default: + err("unsupported AcT"); + return ret; + } + + /* AT-Command */ + at_cmd = g_strdup_printf("AT+COPS=1,2,\"%s\",%d", sel_manual->plmn, act); + + /* Response callback data */ + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, NULL, 0); + + /* Send Request to modem */ + ret = tcore_at_prepare_and_send_request(co, + at_cmd, NULL, + TCORE_AT_COMMAND_TYPE_NO_RESULT, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_network_default, resp_cb_data, + on_send_imc_request, NULL, + 0, NULL, NULL); + + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Manual network selection"); + /* Free resources*/ + g_free(at_cmd); + return ret; +} + +/* + * Operation - get network selection mode + * Request - + * AT-Command: AT+COPS? + * + * Response - + * Success: (Single line) + * +COPS: [,,[,< AcT>]] + * + * is used to select, whether the selection is done automatically by the ME or is forced by this command to + * operator given in the format . + * The values of can be: + * 0 Automatic, in this case other fields are ignored and registration is done automatically by ME + * 1 Manual. Other parameters like format and operator need to be passed + * 2 Deregister from network + * 3 It sets value. In this case becomes a mandatory input + * 4 Manual / Automatic. In this case if manual selection fails then automatic mode is entered + * OK + * Failure: + * +CME ERROR: + */ +static TelReturn imc_network_get_selection_mode(CoreObject *co, + TcoreObjectResponseCallback cb, void *cb_data) +{ + ImcRespCbData *resp_cb_data; + TelReturn ret = TEL_RETURN_INVALID_PARAMETER; + + /* Response callback data */ + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, NULL, 0); + + /* Send Request to modem */ + ret = tcore_at_prepare_and_send_request(co, + "AT+COPS?", "+COPS", + TCORE_AT_COMMAND_TYPE_SINGLELINE, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_network_get_selection_mode, resp_cb_data, + on_send_imc_request, NULL, + 0, NULL, NULL); + + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Get selection mode"); + return ret; +} + +/* + * Operation - set preferred plmn + * Request - + * AT-Command: AT+CPOL=][,[,[,,,]]] + * where + * integer type; the order number of operator in the SIM/USIM preferred operator list + * + * 0 long format alphanumeric + * 1 short format alphanumeric + * 2 numeric + * string type; indicates if the format is alphanumeric or numeric (see +COPS) + * : GSM access technology + * 0 access technology not selected + * 1 access technology selected + * : GSM compact access technology + * 0 access technology not selected + * 1 access technology selected + * : UTRA access technology + * 0 access technology not selected + * 1 access technology selected + * + * Response - + * Success:(No Result) + * OK + * Failure: + * +CME ERROR: + */ +static TelReturn imc_network_set_preferred_plmn(CoreObject *co, + const TelNetworkPreferredPlmnInfo *pref_plmn, + TcoreObjectResponseCallback cb, void *cb_data) +{ + ImcRespCbData *resp_cb_data; + gchar *at_cmd; + gboolean gsm_act = FALSE; + gboolean gsm_compact_act = FALSE; + gboolean utran_act = FALSE; + TelReturn ret = TEL_RETURN_INVALID_PARAMETER; + dbg("entry"); + + switch(pref_plmn->act) { + case TEL_NETWORK_ACT_GSM: + case TEL_NETWORK_ACT_GPRS: + case TEL_NETWORK_ACT_EGPRS: + gsm_act = TRUE; + break; + case TEL_NETWORK_ACT_UMTS: + case TEL_NETWORK_ACT_HSDPA: + case TEL_NETWORK_ACT_HSPA: + utran_act = TRUE; + break; + case TEL_NETWORK_ACT_GSM_AND_UMTS: + gsm_act = utran_act = TRUE; + break; + default: + warn("unsupported AcT"); + } + + /* AT-Command */ + at_cmd = g_strdup_printf("AT+CPOL=%d,%d,\"%s\",%d,%d,%d", + pref_plmn->index, 2, pref_plmn->plmn, gsm_act, gsm_compact_act, utran_act); + + /* Response callback data */ + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, NULL, 0); + + /* Send Request to modem */ + ret = tcore_at_prepare_and_send_request(co, + at_cmd, NULL, + TCORE_AT_COMMAND_TYPE_NO_RESULT, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_network_default, resp_cb_data, + on_send_imc_request, NULL, + 0, NULL, NULL); + + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Set preferred plmn"); + g_free(at_cmd); + return ret; +} + +/* + * Operation - get preferred plmn + * Request - + * AT-Command: AT+CPOL? + * Response - + * Success: (multiline) + * +CPOL: ,, + * [,,,][ + * +CPOL: ,,[,,,] [Â…]] + * OK + * Failure + * +CME ERROR: + */ +static TelReturn imc_network_get_preferred_plmn(CoreObject *co, + TcoreObjectResponseCallback cb, void *cb_data) +{ + ImcRespCbData *resp_cb_data; + TelReturn ret = TEL_RETURN_INVALID_PARAMETER; + dbg("entry"); + + /* Response callback data */ + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, NULL, 0); + + /* Send Request to modem */ + ret = tcore_at_prepare_and_send_request(co, + "AT+CPOL=,2;+CPOL?", "+CPOL", //to make sure is numeric type in reponse. + TCORE_AT_COMMAND_TYPE_MULTILINE, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_network_get_preferred_plmn, resp_cb_data, + on_send_imc_request, NULL, + 0, NULL, NULL); + + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Get preferred plmn"); + return ret; +} + +/* + * Operation - set network mode + * Request - + * AT-Command: AT+XRAT= [, ] + * where + * indicates the radio access technology and may be + * 0 GSM single mode + * 1 GSM / UMTS Dual mode + * 2 UTRAN (UMTS) + * 3-7 Reserved for future use. + * 8 This option is to swap the RAT mode between the two stacks. Example: If Stack1 is in GSM mode and + * Stack2 is in UMTS mode, this will configure Stack1 in UMTS mode and Stack2 in GSM mode. + * Note : = 8 is used only for dual sim configuration. In this case < PreferredAct > is ignored + * + * This parameter is used for network registration in case of =1. + * 0 RAT GSM + * 2 RAT UMTS + * Response - + * Success: (No result) + * OK + * Failure: + * +CME ERROR: + */ +static TelReturn imc_network_set_mode(CoreObject *co, TelNetworkMode mode, + TcoreObjectResponseCallback cb, void *cb_data) +{ + ImcRespCbData *resp_cb_data; + TelReturn ret = TEL_RETURN_INVALID_PARAMETER; + int act; + gchar *at_cmd; + + switch(mode) { + case TEL_NETWORK_MODE_AUTO: + act = 1; + break; + case TEL_NETWORK_MODE_2G: + act = 0; + break; + case TEL_NETWORK_MODE_3G: + act = 2; + break; + case TEL_NETWORK_MODE_LTE: + default: + err("Unsupported mode"); + return ret; + } + + if (act == 1) + /* AT-Command */ + at_cmd = g_strdup_printf("AT+XRAT=%d,2", act); //PreferredAct is UMTS + else + /* AT-Command */ + at_cmd = g_strdup_printf("AT+XRAT=%d", act); + + /* Response callback data */ + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, NULL, 0); + + /* Send Request to modem */ + ret = tcore_at_prepare_and_send_request(co, + at_cmd, NULL , + TCORE_AT_COMMAND_TYPE_NO_RESULT, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_network_default, resp_cb_data, + on_send_imc_request, NULL, + 0, NULL, NULL); + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Set network mode"); + g_free(at_cmd); + return ret; +} + +/* + * Operation - get network mode + * Request - + * AT-Command: AT+XRAT? + * + * Response - + * Success: (Single line) + * +XRAT : , + * indicates the radio access technology and may be + * 0 GSM single mode + * 1 GSM / UMTS Dual mode + * 2 UTRAN (UMTS) + * 3-7 Reserved for future use. + * 8 This option is to swap the RAT mode between the two stacks. Example: If Stack1 is in GSM mode and + * Stack2 is in UMTS mode, this will configure Stack1 in UMTS mode and Stack2 in GSM mode. + * Note : = 8 is used only for dual sim configuration. In this case < PreferredAct > is ignored + * + * This parameter is used for network registration in case of =1. + * 0 RAT GSM + * 2 RAT UMTS + * OK + * Failure: + * +CME ERROR: + */ + +static TelReturn imc_network_get_mode(CoreObject *co, + TcoreObjectResponseCallback cb, void *cb_data) +{ + ImcRespCbData *resp_cb_data; + TelReturn ret; + dbg("entry"); + + /* Response callback data */ + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, NULL, 0); + + /* Send Request to modem */ + ret = tcore_at_prepare_and_send_request(co, + "AT+XRAT?", "+XRAT", + TCORE_AT_COMMAND_TYPE_SINGLELINE, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_network_get_mode, resp_cb_data, + on_send_imc_request, NULL, + 0, NULL, NULL); + + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Get network mode"); + return ret; +} + +static TelReturn imc_network_get_neighboring_cell_info(CoreObject *co, + TcoreObjectResponseCallback cb, void *cb_data) +{ + /* TODO*/ + dbg("entry"); + return TEL_RETURN_OPERATION_NOT_SUPPORTED; +} + +/* Network Operations */ +static TcoreNetworkOps imc_network_ops = { + .get_identity_info = imc_network_get_identity_info, + .search = imc_network_search, + .cancel_search = imc_network_cancel_search, + .select_automatic = imc_network_select_automatic, + .select_manual = imc_network_select_manual, + .get_selection_mode = imc_network_get_selection_mode, + .set_preferred_plmn = imc_network_set_preferred_plmn, + .get_preferred_plmn = imc_network_get_preferred_plmn, + .set_mode = imc_network_set_mode, + .get_mode = imc_network_get_mode, + .get_neighboring_cell_info = imc_network_get_neighboring_cell_info +}; + +gboolean imc_network_init(TcorePlugin *p, CoreObject *co) +{ + dbg("Enter"); + + /* Set operations */ + tcore_network_set_ops(co, &imc_network_ops); + + /* Add Callbacks */ + tcore_object_add_callback(co, "+CREG", on_notification_imc_cs_network_info, NULL); + tcore_object_add_callback(co, "+CGREG", on_notification_imc_ps_network_info, NULL); + tcore_object_add_callback(co, "+XNITZINFO", on_notification_imc_network_time_info, NULL); + tcore_object_add_callback(co, "+XCIEV", on_notification_imc_network_rssi, NULL); + + /* + * Add Hooks - Request and Notification + */ + tcore_plugin_add_request_hook(p, + TCORE_COMMAND_MODEM_SET_FLIGHTMODE, + on_hook_imc_set_flight_mode, NULL); + tcore_plugin_add_notification_hook(p, + TCORE_NOTIFICATION_SIM_STATUS, + on_hook_imc_sim_status, co); + + //_insert_mcc_mnc_oper_list(cp, co_network); + + dbg("Exit"); + return TRUE; +} + +void imc_network_exit(TcorePlugin *p, CoreObject *co) +{ + dbg("Exit"); +} diff --git a/src/imc_phonebook.c b/src/imc_phonebook.c new file mode 100644 index 0000000..c5d2c93 --- /dev/null +++ b/src/imc_phonebook.c @@ -0,0 +1,1090 @@ +/* + * tel-plugin-imc + * + * Copyright (c) 2013 Samsung Electronics Co. Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "imc_phonebook.h" +#include "imc_common.h" + +typedef struct { + GSList *used_index_fdn; + gboolean used_index_fdn_valid; + + GSList *used_index_adn; + gboolean used_index_adn_valid; + + GSList *used_index_sdn; + gboolean used_index_sdn_valid; + + GSList *used_index_usim; + gboolean used_index_usim_valid; +} PrivateInfo; + +static gboolean __imc_phonebook_get_sim_type(CoreObject *co_pb, + TelSimCardType *sim_type) +{ + TcorePlugin *plugin; + CoreObject *co_sim; + tcore_check_return_value_assert(co_pb != NULL, FALSE); + tcore_check_return_value_assert(sim_type != NULL, FALSE); + + plugin = tcore_object_ref_plugin(co_pb); + co_sim = tcore_plugin_ref_core_object(plugin, CORE_OBJECT_TYPE_SIM); + return tcore_sim_get_type(co_sim, sim_type); +} + +static gboolean __imc_phonebook_get_pb_type_str(TelPbType pb_type, + gchar **req_type_str) +{ + tcore_check_return_value_assert(req_type_str != NULL, FALSE); + + switch (pb_type) { + case TEL_PB_FDN: + *req_type_str = g_strdup("FD"); + break; + case TEL_PB_ADN: + case TEL_PB_USIM: + *req_type_str = g_strdup("SM"); + break; + case TEL_PB_SDN: + *req_type_str = g_strdup("SN"); + break; + } + + return TRUE; +} + +static gboolean __imc_phonebook_check_and_select_type(CoreObject *co, + TelPbType req_type, gchar **set_pb_cmd) +{ + TelPbList *support_list; + TelPbType current_type; + + /* Check whether pb_type is supported or not */ + tcore_phonebook_get_support_list(co, &support_list); + if ((req_type == TEL_PB_FDN && support_list->fdn == FALSE) + || (req_type == TEL_PB_ADN && support_list->adn == FALSE) + || (req_type == TEL_PB_SDN && support_list->sdn == FALSE) + || (req_type == TEL_PB_USIM && support_list->usim == FALSE)) { + err("Not supported pb_type"); + g_free(support_list); + return FALSE; + } + g_free(support_list); + + /* Check Current type & Request type */ + tcore_phonebook_get_selected_type(co, ¤t_type); + if (current_type != req_type) { + gchar *req_type_str = NULL; + __imc_phonebook_get_pb_type_str(req_type, &req_type_str); + dbg("Add AT-Command to change [%s] Type", req_type_str); + /* Select Phonebook type */ + *set_pb_cmd = g_strdup_printf("AT+CPBS=\"%s\";", req_type_str); + } else { + *set_pb_cmd = g_strdup_printf("AT"); + } + + return TRUE; +} + +static gboolean __imc_phonebook_get_index_list_by_type(CoreObject *co, + TelPbType pb_type, GSList **list) +{ + PrivateInfo *private_info = tcore_object_ref_user_data(co); + tcore_check_return_value_assert(private_info != NULL, FALSE); + + switch (pb_type) { + case TEL_PB_FDN: + if (private_info->used_index_fdn_valid != TRUE) + return FALSE; + *list = private_info->used_index_fdn; + break; + case TEL_PB_ADN: + if (private_info->used_index_adn_valid != TRUE) + return FALSE; + *list = private_info->used_index_adn; + break; + case TEL_PB_SDN: + if (private_info->used_index_sdn_valid != TRUE) + return FALSE; + *list = private_info->used_index_sdn; + break; + case TEL_PB_USIM: + if (private_info->used_index_usim_valid != TRUE) + return FALSE; + *list = private_info->used_index_usim; + break; + } + + return TRUE; +} + +static void __imc_phonebook_check_used_index(CoreObject *co, + TelPbType pb_type, guint req_index, guint *used_index) +{ + GSList *list = NULL; + + /* Get used_index list by req_type */ + if (__imc_phonebook_get_index_list_by_type(co, pb_type, &list) != TRUE) { + err("used_index list is NOT valid"); + *used_index = req_index; + return; + } + + /* Use first used_index in case req_index is not used */ + *used_index = (guint)g_slist_nth_data(list, 0); + while (list) { + if ((guint)list->data == req_index) { + /* req_index is equal to one of used_index */ + *used_index = req_index; + return; + } + list = g_slist_next(list); + } +} + +static gint __imc_phonebook_compare_index(gconstpointer a, gconstpointer b) +{ + guint index1 = (guint)a; + guint index2 = (guint)b; + + return index1 - index2; +} + +static void on_response_imc_phonebook_get_used_index(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + ImcRespCbData *resp_cb_data = user_data; + CoreObject *co = tcore_pending_ref_core_object(p); + tcore_check_return_assert(at_resp != NULL); + tcore_check_return_assert(resp_cb_data != NULL); + + dbg("Entry"); + + if (at_resp->success != TRUE) { + err("Response NOK"); + return; + } + + dbg("Response OK"); + + if (at_resp->lines == NULL) { + err("at_resp->lines is NULL"); + } else { + GSList *lines = at_resp->lines; + TelPbType *req_type; + GSList **list = NULL; + PrivateInfo *private_info = tcore_object_ref_user_data(co); + tcore_check_return_assert(private_info != NULL); + + /* Select used_index_list by req_type */ + req_type = (TelPbType *)IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data); + switch (*req_type) { + case TEL_PB_FDN: + list = &private_info->used_index_fdn; + private_info->used_index_fdn_valid = TRUE; + break; + case TEL_PB_ADN: + list = &private_info->used_index_adn; + private_info->used_index_adn_valid = TRUE; + break; + case TEL_PB_SDN: + list = &private_info->used_index_sdn; + private_info->used_index_sdn_valid = TRUE; + break; + case TEL_PB_USIM: + list = &private_info->used_index_usim; + private_info->used_index_usim_valid = TRUE; + break; + } + + while (lines) { + const gchar *line = lines->data; + GSList *tokens = NULL; + gchar *temp; + + dbg("Line: [%s]", line); + + tokens = tcore_at_tok_new(line); + if (tokens == NULL) { + err("tokens is NULL"); + return; + } + + /* Get only used_index */ + temp = g_slist_nth_data(tokens, 0); + if (temp) { + /* Insert used_index in PrivateInfo sorted in ascending */ + *list = g_slist_insert_sorted(*list, (gpointer)atoi(temp), + __imc_phonebook_compare_index); + } + tcore_at_tok_free(tokens); + + /* Get next lines */ + lines = g_slist_next(lines); + } + dbg("pb_type: [%d], used_index Length: [%d]", + *req_type, g_slist_length(*list)); + } +} + +static void __imc_phonebook_get_used_index(CoreObject *co, TelPbType pb_type, guint max_index) +{ + gchar *at_cmd; + ImcRespCbData *resp_cb_data; + TelReturn ret = TEL_RETURN_FAILURE; + + dbg("Entry"); + + /* AT-Command */ + at_cmd = g_strdup_printf("AT+CPBR=1,%d", max_index); + + /* Response callback data */ + resp_cb_data = imc_create_resp_cb_data(NULL, NULL, + (void *)&pb_type, sizeof(TelPbType)); + + /* Send Request to Modem */ + ret = tcore_at_prepare_and_send_request(co, + at_cmd, "+CPBR", + TCORE_AT_COMMAND_TYPE_MULTILINE, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_phonebook_get_used_index, resp_cb_data, + on_send_imc_request, NULL, + 0, NULL, NULL); + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Get Used Index"); + + /* Free resources */ + g_free(at_cmd); +} + +static void on_response_imc_phonebook_get_support_list(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + CoreObject *co = tcore_pending_ref_core_object(p); + TelPbInitInfo init_info = {0, }; + tcore_check_return_assert(at_resp != NULL); + + dbg("Entry"); + + if (at_resp->success != TRUE) { + err("Response NOK"); + return; + } + + dbg("Response OK"); + + if (at_resp->lines == NULL) { + err("at_resp->lines is NULL"); + return; + } else { + const gchar *line = (const gchar *)at_resp->lines->data; + GSList *tokens = NULL; + gchar *pb_type_list; + gchar *pb_type; + + dbg("Line: [%s]", line); + + tokens = tcore_at_tok_new(line); + if (tokens == NULL) { + err("tokens is NULL"); + return; + } + + pb_type_list = g_slist_nth_data(tokens, 0); + pb_type = strtok(pb_type_list, "(,)"); + while (pb_type) { + pb_type = tcore_at_tok_extract(pb_type); + if (g_strcmp0(pb_type, "FD") == 0) { + init_info.pb_list.fdn = TRUE; + } else if (g_strcmp0(pb_type, "SN") == 0) { + init_info.pb_list.sdn = TRUE; + } else if (g_strcmp0(pb_type, "SM") == 0) { + TelSimCardType sim_type; + __imc_phonebook_get_sim_type(co, &sim_type); + if (sim_type == TEL_SIM_CARD_TYPE_USIM) + init_info.pb_list.usim = TRUE; + else + init_info.pb_list.adn = TRUE; + } + g_free(pb_type); + /* Get Next pb_type */ + pb_type = strtok(NULL, "(,)"); + } + tcore_at_tok_free(tokens); + } + + dbg("FDN: [%s], ADN: [%s], SDN: [%s], USIM: [%s]", + init_info.pb_list.fdn ? "TRUE" : "FALSE", + init_info.pb_list.adn ? "TRUE" : "FALSE", + init_info.pb_list.sdn ? "TRUE" : "FALSE", + init_info.pb_list.usim ? "TRUE" : "FALSE"); + + init_info.init_status = TRUE; + tcore_phonebook_set_support_list(co, &init_info.pb_list); + tcore_phonebook_set_status(co, init_info.init_status); + + /* Send Notification */ + tcore_object_send_notification(co, + TCORE_NOTIFICATION_PHONEBOOK_STATUS, + sizeof(TelPbInitInfo), &init_info); +} + +/* + * Operation - get_support_list + * + * Request - + * AT-Command: AT+CPBS=? + * + * Response - + * Success: (Single line) + * (list of supported s) + * OK + * Failure: + * +CME ERROR: + */ +static void __imc_phonebook_get_support_list(CoreObject *co) +{ + TelReturn ret; + + dbg("Entry"); + + /* Send Request to Modem */ + ret = tcore_at_prepare_and_send_request(co, + "AT+CPBS=?", "+CPBS", + TCORE_AT_COMMAND_TYPE_SINGLELINE, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_phonebook_get_support_list, NULL, + on_send_imc_request, NULL, + 0, NULL, NULL); + IMC_CHECK_REQUEST_RET(ret, NULL, "Get Support List"); +} + +static gboolean on_notification_imc_phonebook_status(CoreObject *co, + const void *event_info, void *user_data) +{ + dbg("Phonebook Init Completed"); + + /* Get Supported list */ + __imc_phonebook_get_support_list(co); + + return TRUE; +} + +static void on_response_imc_phonebook_get_info(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + ImcRespCbData *resp_cb_data = user_data; + CoreObject *co = tcore_pending_ref_core_object(p); + TelPbResult result = TEL_PB_RESULT_FAILURE; + TelPbInfo pb_info = {0, }; + tcore_check_return_assert(at_resp != NULL); + tcore_check_return_assert(resp_cb_data != NULL); + + dbg("Entry"); + + if (at_resp->success != TRUE) { + err("Response NOK"); + goto out; + } + + dbg("Response OK"); + + if (at_resp->lines == NULL) { + err("at_resp->lines is NULL"); + } else { + GSList *lines = at_resp->lines; + const gchar *line; + GSList *tokens = NULL; + gchar *temp; + gint used = 0, total = 0; + gint nlen = 0, tlen = 0; + TelPbType *req_type; + PrivateInfo *private_info; + + /* +CPBS: [,][,total] */ + line = g_slist_nth_data(lines, 0); + dbg("First Line: [%s]", line); + tokens = tcore_at_tok_new(line); + if (tokens == NULL) { + err("tokens is NULL"); + goto out; + } + + /* Get used_count */ + temp = g_slist_nth_data(tokens, 1); + if (temp) + used = atoi(temp); + /* Get total_count */ + temp = g_slist_nth_data(tokens, 2); + if (temp) + total = atoi(temp); + + tcore_at_tok_free(tokens); + + /* +CPBF: [],[],[],[],[] */ + line = g_slist_nth_data(lines, 1); + dbg("Second Line: [%s]", line); + tokens = tcore_at_tok_new(line); + if (tokens == NULL) { + err("tokens is NULL"); + goto out; + } + + /* Get number Length */ + temp = g_slist_nth_data(tokens, 0); + if (temp) + nlen = atoi(temp); + /* Get text Length */ + temp = g_slist_nth_data(tokens, 1); + if (temp) + tlen = atoi(temp); + + /* Set Response Data */ + req_type = (TelPbType *)IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data); + pb_info.pb_type = *req_type; + if (*req_type == TEL_PB_USIM) { + pb_info.info_u.usim.max_count = total; + pb_info.info_u.usim.used_count = used; + pb_info.info_u.usim.max_num_len = nlen; + pb_info.info_u.usim.max_text_len = tlen; + /* Get group name Length */ + temp = g_slist_nth_data(tokens, 2); + if (temp) + pb_info.info_u.usim.max_gas_len = atoi(temp); + /* Get second name Length */ + temp = g_slist_nth_data(tokens, 3); + if (temp) + pb_info.info_u.usim.max_sne_len = atoi(temp); + /* Get email Length */ + temp = g_slist_nth_data(tokens, 4); + if (temp) + pb_info.info_u.usim.max_email_len = atoi(temp); + } else { + pb_info.info_u.sim.max_count = total; + pb_info.info_u.sim.used_count = used; + pb_info.info_u.sim.max_num_len = nlen; + pb_info.info_u.sim.max_text_len = tlen; + } + + /* Set Request type in PrivateObject */ + tcore_phonebook_set_selected_type(co, *req_type); + result = TEL_PB_RESULT_SUCCESS; + tcore_at_tok_free(tokens); + + /* If don't have valid used_index, get used_index by req_type */ + private_info = tcore_object_ref_user_data(co); + if ((*req_type == TEL_PB_FDN && private_info->used_index_fdn_valid == FALSE) + || (*req_type == TEL_PB_ADN && private_info->used_index_adn_valid == FALSE) + || (*req_type == TEL_PB_SDN && private_info->used_index_sdn_valid == FALSE) + || (*req_type == TEL_PB_USIM && private_info->used_index_usim_valid == FALSE)) + __imc_phonebook_get_used_index(co, *req_type, total); + } + +out: + /* Invoke callback */ + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, &pb_info, resp_cb_data->cb_data); + + /* Free callback data */ + imc_destroy_resp_cb_data(resp_cb_data); +} + +static void on_response_imc_phonebook_read_record(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + ImcRespCbData *resp_cb_data = user_data; + CoreObject *co = tcore_pending_ref_core_object(p); + TelPbResult result = TEL_PB_RESULT_FAILURE; + GSList *tokens = NULL; + gchar *index = NULL, *number = NULL, *name = NULL; + TelPbReadRecord read_record = {0, }; + tcore_check_return_assert(at_resp != NULL); + tcore_check_return_assert(resp_cb_data != NULL); + + dbg("Entry"); + + if (at_resp->success != TRUE) { + err("Response NOK"); + goto out; + } + + dbg("Response OK"); + + if (at_resp->lines == NULL) { + err("at_resp->lines is NULL"); + } else { + const gchar *line = (const gchar *)at_resp->lines->data; + TelPbType *req_type; + GSList *list = NULL; + + dbg("Line: [%s]", line); + + tokens = tcore_at_tok_new(line); + if (tokens == NULL) { + err("tokens is NULL"); + goto out; + } + + /* Get index */ + index = g_slist_nth_data(tokens, 0); + if (index == NULL) { + err("No index"); + goto out; + } + + /* Get number */ + number = g_slist_nth_data(tokens, 1); + if (number) { + number = tcore_at_tok_extract(number); + } else { + err("No number"); + goto out; + } + + /* Get name */ + name = g_slist_nth_data(tokens, 3); + if (name) { + name = tcore_at_tok_extract(name); + } else { + err("No name"); + goto out; + } + + /* Set Request type in PrivateObject */ + req_type = (TelPbType *)IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data); + tcore_phonebook_set_selected_type(co, *req_type); + + /* Set Response Data */ + read_record.index = atoi(index); + read_record.pb_type = *req_type; + + /* Get used_index list by req_type */ + if (__imc_phonebook_get_index_list_by_type(co, *req_type, &list) == TRUE) { + while (list) { + if ((guint)list->data == read_record.index) { + if ((list = g_slist_next(list)) != NULL) { + /* If exist, set next_index */ + read_record.next_index = (guint)list->data; + dbg("next_index is [%u]", read_record.next_index); + } else { + /* read_record.index is the end of used_index */ + read_record.next_index = -1; + dbg("End of used_index"); + } + break; + } + list = g_slist_next(list); + } + } else { + /* No PrivateInfo */ + read_record.next_index = 0; + } + + if (*req_type == TEL_PB_USIM) { + gchar *hidden, *group, *anr, *sne, *email; + + /* Get Name and Number */ + g_strlcpy(read_record.rec_u.usim.name, name, TEL_PB_TEXT_MAX_LEN + 1); + g_strlcpy(read_record.rec_u.usim.number, number, TEL_PB_NUMBER_MAX_LEN + 1); + + /* Get Hidden */ + hidden = g_slist_nth_data(tokens, 4); + if (hidden) { + read_record.rec_u.usim.hidden = atoi(hidden); + } + + /* Get Group name */ + group = g_slist_nth_data(tokens, 5); + if (group) { + group = tcore_at_tok_extract(group); + g_strlcpy(read_record.rec_u.usim.grp_name, group, TEL_PB_TEXT_MAX_LEN + 1); + g_free(group); + } + + /* Get ANR */ + anr = g_slist_nth_data(tokens, 6); + if (anr) { + anr = tcore_at_tok_extract(anr); + if (strlen(anr)) { + g_strlcpy(read_record.rec_u.usim.anr[0].number, + anr, TEL_PB_NUMBER_MAX_LEN + 1); + read_record.rec_u.usim.anr_count = 1; + } + g_free(anr); + } + + /* Get SNE */ + sne = g_slist_nth_data(tokens, 8); + if (sne) { + sne = tcore_at_tok_extract(sne); + g_strlcpy(read_record.rec_u.usim.sne, sne, TEL_PB_TEXT_MAX_LEN + 1); + g_free(sne); + } + + /* Get email */ + email = g_slist_nth_data(tokens, 9); + if (email) { + email = tcore_at_tok_extract(email); + if (strlen(email)) { + g_strlcpy(read_record.rec_u.usim.email[0], email, TEL_PB_TEXT_MAX_LEN + 1); + read_record.rec_u.usim.email_count = 1; + } + g_free(email); + } + } + else { + /* Get Name and Number */ + g_strlcpy(read_record.rec_u.sim.name, name, TEL_PB_TEXT_MAX_LEN + 1); + g_strlcpy(read_record.rec_u.sim.number, number, TEL_PB_NUMBER_MAX_LEN + 1); + } + + result = TEL_PB_RESULT_SUCCESS; + } + +out: + /* Invoke callback */ + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, &read_record, resp_cb_data->cb_data); + + /* Free callback data */ + imc_destroy_resp_cb_data(resp_cb_data); + + /* Free resources */ + tcore_at_tok_free(tokens); + g_free(number); + g_free(name); +} + +static void on_response_imc_phonebook_update_record(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + ImcRespCbData *resp_cb_data = user_data; + CoreObject *co = tcore_pending_ref_core_object(p); + TelPbUpdateRecord *req_data; + TelPbResult result = TEL_PB_RESULT_FAILURE; + GSList *list = NULL; + tcore_check_return_assert(at_resp != NULL); + tcore_check_return_assert(resp_cb_data != NULL); + + dbg("Entry"); + + if (at_resp->success != TRUE) { + err("Response NOK"); + goto out; + } + + dbg("Response OK"); + result = TEL_PB_RESULT_SUCCESS; + + /* Set Request type in PrivateObject */ + req_data = (TelPbUpdateRecord *)IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data); + tcore_phonebook_set_selected_type(co, req_data->pb_type); + + /* Get used_index list by req_type */ + if (__imc_phonebook_get_index_list_by_type(co, + req_data->pb_type, &list) != TRUE) { + err("used_index list is NOT valid"); + } else { + list = g_slist_insert_sorted(list, (gpointer)req_data->index, + __imc_phonebook_compare_index); + } + +out: + /* Invoke callback */ + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, NULL, resp_cb_data->cb_data); + + /* Free callback data */ + imc_destroy_resp_cb_data(resp_cb_data); +} + +static void on_response_imc_phonebook_delete_record(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + ImcRespCbData *resp_cb_data = user_data; + CoreObject *co = tcore_pending_ref_core_object(p); + TelPbRecordInfo *req_data; + GSList *list = NULL; + TelPbResult result = TEL_PB_RESULT_FAILURE; + tcore_check_return_assert(at_resp != NULL); + tcore_check_return_assert(resp_cb_data != NULL); + + dbg("Entry"); + + if (at_resp->success != TRUE) { + err("Response NOK"); + goto out; + } + + dbg("Response OK"); + result = TEL_PB_RESULT_SUCCESS; + + /* Set Request type in PrivateObject */ + req_data = (TelPbRecordInfo *)IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data); + tcore_phonebook_set_selected_type(co, req_data->pb_type); + + /* Get used_index list by req_type */ + if (__imc_phonebook_get_index_list_by_type(co, + req_data->pb_type, &list) != TRUE) { + err("used_index list is NOT valid"); + } else { + list = g_slist_remove(list, (gconstpointer)req_data->index); + dbg("Remove index: [%u]", req_data->index); + } + +out: + /* Invoke callback */ + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, NULL, resp_cb_data->cb_data); + + /* Free callback data */ + imc_destroy_resp_cb_data(resp_cb_data); +} + +/* + * Operation - get_info + * + * Request - + * AT-Command: AT+CPBS?;+CPBF=? + * + * Response - + * Success: (Multi line) + * +CPBS: [,][,total] + * +CPBF: [],[],[],[],[] + * OK + * where, + * Maximum length of field + * Maximum length of field + * Maximum length of field + * Maximum length of field + * Maximum length of field + * + * Failure: + * +CME ERROR: + */ +static TelReturn imc_phonebook_get_info(CoreObject *co, + const TelPbType pb_type, + TcoreObjectResponseCallback cb, void *cb_data) +{ + gchar *at_cmd; + gchar *set_pb_cmd; + ImcRespCbData *resp_cb_data; + TelReturn ret = TEL_RETURN_FAILURE; + + dbg("Entry"); + + /* Check whether pb_type is supported or not, and Select pb_type */ + if (__imc_phonebook_check_and_select_type(co, pb_type, &set_pb_cmd) != TRUE) { + return ret; + } + + /* AT-Command */ + at_cmd = g_strdup_printf("%s+CPBS?;+CPBF=?", set_pb_cmd); + + /* Response callback data */ + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, + (void *)&pb_type, sizeof(TelPbType)); + + /* Send Request to Modem */ + ret = tcore_at_prepare_and_send_request(co, + at_cmd, "+CPB", + TCORE_AT_COMMAND_TYPE_MULTILINE, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_phonebook_get_info, resp_cb_data, + on_send_imc_request, NULL, + 0, NULL, NULL); + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Get Info"); + + /* Free resources */ + g_free(at_cmd); + g_free(set_pb_cmd); + + return ret; +} + +/* + * Operation - read_record + * + * Request - + * AT-Command: AT+CPBR= + * where, + * + * 1 Integer type values in range of location numbers of phonebook memory + * ... + * + * Response - + * Success: (Single line); + * +CPBR: ,,,[,][,] + * [,][,][,][,]] + * OK + * where, + * String type phone number of format + * Type of address octet in integer format + * String type field of maximum length + * Indicates if the entry is hidden or not – only available, + * if a UICC with an active USIM application is present + * 0 Phonebook entry not hidden + * 1 Phonebook entry hidden + * String type field of maximum length + * String type phone number of format + * Type of address octet in integer format + * String type field of maximum length + * String type field of maximum length + * + * Failure: + * +CME ERROR: + */ +static TelReturn imc_phonebook_read_record(CoreObject *co, + const TelPbRecordInfo *record, + TcoreObjectResponseCallback cb, void *cb_data) +{ + gchar *at_cmd; + gchar *set_pb_cmd; + ImcRespCbData *resp_cb_data; + guint used_index = 0; + TelReturn ret = TEL_RETURN_FAILURE; + + dbg("Entry"); + + /* Check whether pb_type is supported or not, and Select pb_type */ + if (__imc_phonebook_check_and_select_type(co, record->pb_type, &set_pb_cmd) != TRUE) { + return ret; + } + + /* Check whether index is used or not */ + __imc_phonebook_check_used_index(co, record->pb_type, record->index, &used_index); + + /* AT-Command */ + at_cmd = g_strdup_printf("%s+CPBR=%u", set_pb_cmd, used_index); + + /* Response callback data */ + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, + (void *)&(record->pb_type), sizeof(TelPbType)); + + /* Send Request to Modem */ + ret = tcore_at_prepare_and_send_request(co, + at_cmd, "+CPBR", + TCORE_AT_COMMAND_TYPE_SINGLELINE, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_phonebook_read_record, resp_cb_data, + on_send_imc_request, NULL, + 0, NULL, NULL); + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Read Record"); + + /* Free resources */ + g_free(at_cmd); + g_free(set_pb_cmd); + + return ret; +} + +/* + * Operation - update_record + * + * Request - + * AT-Command: AT+CPBW=[][,[,[,[,[, + * [,[,[,[,]]]]]]]]] + * where, + * ... same read_record Operation + * + * Response - + * Success: (No Result) + * OK + * Failure: + * +CME ERROR: + */ +static TelReturn imc_phonebook_update_record(CoreObject *co, + const TelPbUpdateRecord *req_data, + TcoreObjectResponseCallback cb, void *cb_data) +{ + gchar *at_cmd; + gchar *set_pb_cmd; + ImcRespCbData *resp_cb_data; + TelReturn ret = TEL_RETURN_FAILURE; + + dbg("Entry"); + + /* Check whether pb_type is supported or not, and Select pb_type */ + if (__imc_phonebook_check_and_select_type(co, req_data->pb_type, &set_pb_cmd) != TRUE) { + return ret; + } + + /* Set AT-Command according pb_type */ + if (req_data->pb_type == TEL_PB_USIM) { + at_cmd = g_strdup_printf("%s+CPBW=%u,\"%s\",,\"%s\",\"%s\",\"%s\",,\"%s\",\"%s\",%d", + set_pb_cmd, req_data->index, + req_data->rec_u.usim.number, req_data->rec_u.usim.name, + req_data->rec_u.usim.grp_name, req_data->rec_u.usim.anr[0].number, + req_data->rec_u.usim.sne, req_data->rec_u.usim.email[0], + req_data->rec_u.usim.hidden); + } else { + at_cmd = g_strdup_printf("%s+CPBW=%u,\"%s\",,\"%s\"", + set_pb_cmd, req_data->index, + req_data->rec_u.sim.number, + req_data->rec_u.sim.name); + } + + /* Response callback data */ + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, + (void *)req_data, sizeof(TelPbUpdateRecord)); + + /* Send Request to Modem */ + ret = tcore_at_prepare_and_send_request(co, + at_cmd, NULL, + TCORE_AT_COMMAND_TYPE_NO_RESULT, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_phonebook_update_record, resp_cb_data, + on_send_imc_request, NULL, + 0, NULL, NULL); + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Update Record"); + + /* Free resources */ + g_free(at_cmd); + g_free(set_pb_cmd); + + return ret; +} + +/* + * Operation - delete_record + * + * Request - + * AT-Command: AT+CPBW= + * where, + * + * 1 Integer type values in range of location numbers of phonebook memory + * ... + * + * Response - + * Success: (No Result) + * OK + * Failure: + * +CME ERROR: + */ +static TelReturn imc_phonebook_delete_record(CoreObject *co, + const TelPbRecordInfo *record, + TcoreObjectResponseCallback cb, void *cb_data) +{ + gchar *at_cmd; + gchar *set_pb_cmd; + ImcRespCbData *resp_cb_data; + TelReturn ret = TEL_RETURN_FAILURE; + + dbg("Entry"); + + /* Check whether pb_type is supported or not, and Select pb_type */ + if (__imc_phonebook_check_and_select_type(co, record->pb_type, &set_pb_cmd) != TRUE) { + return ret; + } + + /* AT-Command */ + at_cmd = g_strdup_printf("%s+CPBW=%u", set_pb_cmd, record->index); + + /* Response callback data */ + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, + (void *)record, sizeof(TelPbRecordInfo)); + + /* Send Request to Modem */ + ret = tcore_at_prepare_and_send_request(co, + at_cmd, NULL, + TCORE_AT_COMMAND_TYPE_NO_RESULT, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_phonebook_delete_record, resp_cb_data, + on_send_imc_request, NULL, + 0, NULL, NULL); + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Delete Record"); + + /* Free resources */ + g_free(at_cmd); + g_free(set_pb_cmd); + + return ret; +} + +/* Phonebook Operations */ +static TcorePbOps imc_phonebook_ops = { + .get_info = imc_phonebook_get_info, + .read_record = imc_phonebook_read_record, + .update_record = imc_phonebook_update_record, + .delete_record = imc_phonebook_delete_record, +}; + +gboolean imc_phonebook_init(TcorePlugin *p, CoreObject *co) +{ + PrivateInfo *private_info; + + dbg("Entry"); + + /* Set PrivateInfo */ + private_info = tcore_malloc0(sizeof(PrivateInfo)); + tcore_object_link_user_data(co, private_info); + + /* Set operations */ + tcore_phonebook_set_ops(co, &imc_phonebook_ops); + + /* Add Callbacks */ + tcore_object_add_callback(co, "+PBREADY", on_notification_imc_phonebook_status, NULL); + + dbg("Exit"); + return TRUE; +} + +void imc_phonebook_exit(TcorePlugin *p, CoreObject *co) +{ + PrivateInfo *private_info; + + private_info = tcore_object_ref_user_data(co); + tcore_check_return_assert(private_info != NULL); + + /* Free PrivateInfo */ + g_slist_free_full(private_info->used_index_fdn, g_free); + g_slist_free_full(private_info->used_index_adn, g_free); + g_slist_free_full(private_info->used_index_sdn, g_free); + g_slist_free_full(private_info->used_index_usim, g_free); + tcore_free(private_info); + + dbg("Exit"); +} diff --git a/src/imc_ps.c b/src/imc_ps.c new file mode 100644 index 0000000..c9afd16 --- /dev/null +++ b/src/imc_ps.c @@ -0,0 +1,895 @@ +/* + * tel-plugin-imc + * + * Copyright (c) 2013 Samsung Electronics Co. Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "imc_ps.h" +#include "imc_common.h" + +typedef struct { + TcorePsCallState ps_call_status; +} PrivateInfo; + +static void __notify_context_status_changed(CoreObject *co_ps, guint context_id, + TcorePsCallState status) +{ + PrivateInfo *private_info = tcore_object_ref_user_data(co_ps); + TcorePsCallStatusInfo data_resp = {0,}; + tcore_check_return_assert(private_info != NULL); + + private_info->ps_call_status = status; + data_resp.context_id = context_id; + data_resp.state = status; + dbg("Sending PS Call Status Notification - Context ID: [%d] Context State: [%d]", + data_resp.context_id, data_resp.state); + + /* Send PS CALL Status Notification */ + (void)tcore_object_send_notification(co_ps, + TCORE_NOTIFICATION_PS_CALL_STATUS, + sizeof(TcorePsCallStatusInfo), + &data_resp); + +} + +static TcoreHookReturn on_hook_imc_nw_registration_status(TcorePlugin *plugin, + TcoreNotification command, guint data_len, void *data, void *user_data) +{ + const TelNetworkRegStatusInfo *nw_reg_status = (TelNetworkRegStatusInfo *)data; + gboolean state = FALSE; + + tcore_check_return_value(nw_reg_status != NULL, + TCORE_HOOK_RETURN_CONTINUE); + + + dbg("nw_reg_status->ps_status [%d]",nw_reg_status->ps_status); + dbg("nw_reg_status->cs_status [%d]",nw_reg_status->cs_status); + + /* Setting if PS is online or not */ + if(nw_reg_status->ps_status == TEL_NETWORK_REG_STATUS_REGISTERED || + nw_reg_status->ps_status == TEL_NETWORK_REG_STATUS_ROAMING) { + /* Set PS is online */ + state = TRUE; + } + + dbg("PS online state [%d]", state); + + /* Set Online state */ + tcore_ps_set_online((CoreObject *)user_data, state); + return TCORE_HOOK_RETURN_CONTINUE; +} + +/* + * Notification - GPRS event reporting + * + * Notification - + * +CGEV: NW DEACT , , [] + * The network has forced a context deactivation. The that was used to activate the context is provided if + * known to the MT + */ +static gboolean on_notification_imc_ps_cgev(CoreObject *co_ps, + const void *data, void *user_data) +{ + GSList *tokens = NULL; + GSList *lines = (GSList *)data; + const gchar *line = lines->data; + gchar *noti_data; + guint context_id; + TcoreHal *hal; + + dbg("Entry"); + + if (line == NULL) { + err("Ignore, No data present in notification received for CGEV"); + return TRUE; + } + + dbg("Lines->data :%s", line); + + tokens = tcore_at_tok_new(line); + if (g_slist_length(tokens) != 3) { + err("Ignore, sufficient data not present for deactivation"); + goto out; + + } + noti_data = g_slist_nth_data(tokens, 0); + + /* Only care about NW context deactivation */ + if (g_str_has_prefix(noti_data, "NW DEACT") == FALSE) { + err("Ignore, only care about nw deactivation"); + goto out; + } + + noti_data = g_slist_nth_data(tokens, 1); + dbg("PDP Address: %s", noti_data); + + noti_data = g_slist_nth_data(tokens, 2); + /*TODO: Need to handle context id with multiple PDP*/ + if (noti_data != NULL) + context_id = (guint)atoi(noti_data); + else{ + err("No Context ID!"); + goto out; + } + + dbg("Context %d deactivated", context_id); + + __notify_context_status_changed(co_ps, context_id, TCORE_PS_CALL_STATE_NOT_CONNECTED); + + hal = tcore_object_get_hal(co_ps); + if (tcore_hal_setup_netif(hal, co_ps, NULL, NULL, context_id, + FALSE) != TEL_RETURN_SUCCESS) + err("Failed to disable network interface"); +out: + tcore_at_tok_free(tokens); + return TRUE; +} + +static void __imc_ps_setup_pdp(CoreObject *co_ps, gint result, const gchar *netif_name, + void *user_data) +{ + CoreObject *ps_context = user_data; + guint context_id; + + tcore_check_return_assert(ps_context != NULL); + + dbg("Enter"); + + if (result < 0) { + err("Result [%d],Hence Deactivating context ", result); + /* Deactivate PDP context */ + (void)tcore_object_dispatch_request(co_ps, TRUE, + TCORE_COMMAND_PS_DEACTIVATE_CONTEXT, + NULL, 0, + NULL, NULL); + + return; + } + + dbg("devname = [%s]", netif_name); + + tcore_context_set_ipv4_devname(ps_context, netif_name); + + (void)tcore_context_get_id(ps_context, &context_id); + dbg("Context ID : %d", context_id); + + __notify_context_status_changed(co_ps, context_id, TCORE_PS_CALL_STATE_CONNECTED); + + dbg("Exit"); +} + +static void __on_response_imc_ps_send_get_dns_cmd(TcorePending *p, guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + CoreObject *ps_context = user_data; + CoreObject *co_ps = tcore_pending_ref_core_object(p); + guint context_id; + GSList *tokens = NULL; + GSList *lines; + const char *line = NULL; + char *dns_prim = NULL; + char *dns_sec = NULL; + char *token_dns = NULL; + gint no_pdp_active = 0; + TcoreHal *hal = tcore_object_get_hal(co_ps); + + dbg("Entered"); + + tcore_check_return_assert(at_resp != NULL); + tcore_check_return_assert(ps_context != NULL); + + + (void)tcore_context_get_id(ps_context, &context_id); + dbg("Context ID : %d", context_id); + + if (at_resp && at_resp->success) { + dbg("Response OK"); + if (at_resp->lines) { + dbg("DNS data present in the Response"); + lines = (GSList *) at_resp->lines; + no_pdp_active = g_slist_length(lines); + dbg("Total Number of Active PS Context: [%d]", no_pdp_active); + if (0 == no_pdp_active) { + goto fail; + } + + while (lines) { + line = (const char *) lines->data; + dbg("Received Data: [%s]", line); + tokens = tcore_at_tok_new(line); + + /* Check if Context ID is matching */ + if (context_id == (guint)(atoi(g_slist_nth_data(tokens, 0)))) { + dbg("Found the DNS details for the Current Context - Context ID: [%d]", context_id); + break; + } + + tcore_at_tok_free(tokens); + tokens = NULL; + + /* Move to next line */ + lines = lines->next; + } + + /* Read primary DNS */ + { + token_dns = g_slist_nth_data(tokens, 1); + dns_prim = tcore_at_tok_extract(token_dns); + dbg("Primary DNS: [%s]", dns_prim); + } + + /* Read Secondary DNS */ + { + token_dns = g_slist_nth_data(tokens, 2); + dns_sec = tcore_at_tok_extract(token_dns); + dbg("Secondary DNS: [%s]", dns_sec); + } + + if ((g_strcmp0("0.0.0.0", dns_prim) == 0) + && (g_strcmp0("0.0.0.0", dns_sec) == 0)) { + dbg("Invalid DNS"); + + tcore_free(dns_prim); + tcore_free(dns_sec); + + tcore_at_tok_free(tokens); + tokens = NULL; + + goto fail; + } + + /* Set DNS Address */ + tcore_context_set_ipv4_dns(ps_context, dns_prim, dns_sec); + tcore_free(dns_prim); + tcore_free(dns_sec); + + tcore_at_tok_free(tokens); + tokens = NULL; + goto success; + } else { + dbg("No data present in the Response"); + } + } + dbg("Response NOK"); + +fail: + dbg("Adding default DNS"); + tcore_context_set_ipv4_dns(ps_context, "8.8.8.8", "8.8.4.4"); + +success: + /* Mount network interface */ + if (tcore_hal_setup_netif(hal, co_ps, __imc_ps_setup_pdp, ps_context, context_id, TRUE) + != TEL_RETURN_SUCCESS) { + err("Setup network interface failed"); + return; + } +} + +static void __imc_ps_send_get_dns_cmd(CoreObject *co_ps, CoreObject *ps_context) +{ + TelReturn ret = TEL_RETURN_FAILURE; + guint context_id; + PrivateInfo *private_info = tcore_object_ref_user_data(co_ps); + + dbg("Entered"); + + tcore_check_return_assert(private_info != NULL); + + (void)tcore_context_get_id(ps_context, &context_id); + dbg("Context ID : %d", context_id); + + /* Send Request to modem */ + ret = tcore_at_prepare_and_send_request(co_ps, + "AT+XDNS?", "+XDNS", + TCORE_AT_COMMAND_TYPE_MULTILINE, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + __on_response_imc_ps_send_get_dns_cmd, + ps_context, + on_send_imc_request, NULL, + 0, NULL, NULL); + + if (ret != TEL_RETURN_SUCCESS){ + TcorePsCallState curr_call_status; + err("Failed to prepare and send AT request"); + curr_call_status = private_info->ps_call_status; + __notify_context_status_changed(co_ps, context_id, curr_call_status); + } +} + +static void __on_response_imc_ps_get_pdp_address(TcorePending *p, guint data_len, + const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + CoreObject *co_ps = tcore_pending_ref_core_object(p); + CoreObject *ps_context = user_data; + GSList *tokens = NULL; + const char *line; + char *pdp_address; + char *real_pdp_address; + + dbg("Entered"); + + tcore_check_return_assert(at_resp != NULL); + tcore_check_return_assert(ps_context != NULL); + + if (at_resp->success != TRUE) { + err("Response NOt OK"); + goto error; + } + + dbg("Response OK"); + + if (at_resp->lines == NULL) { + err("Invalid response line"); + goto error; + } + + line = (const char *)at_resp->lines->data; + tokens = tcore_at_tok_new(line); + if (g_slist_length(tokens) < 2) { + err("Invalid message"); + goto error; + } + + dbg("Line: %s", line); + + /* Skip CID & read directly IP address */ + pdp_address = g_slist_nth_data(tokens, 1); + real_pdp_address = tcore_at_tok_extract(pdp_address); + + tcore_context_set_ipv4_addr(ps_context, real_pdp_address); + + dbg("PDP address: %s", real_pdp_address); + + tcore_free(real_pdp_address); + + /* Get DNS Address */ + dbg("Getting DNS Address"); + __imc_ps_send_get_dns_cmd(co_ps, ps_context); + goto exit; + +error: + err("Failed to get PDP address deactivating context..."); + /* Deactivate PDP context */ + (void)tcore_object_dispatch_request(co_ps, TRUE, + TCORE_COMMAND_PS_DEACTIVATE_CONTEXT, + NULL, 0, + NULL, NULL); +exit: + tcore_at_tok_free(tokens); + dbg("Exit"); +} + +static void __imc_ps_get_pdp_address(CoreObject *co_ps, CoreObject *ps_context) +{ + TelReturn ret; + gchar *at_cmd = NULL; + guint context_id; + + dbg("Entered"); + + (void)tcore_context_get_id(ps_context, &context_id); + dbg("Context ID : %d", context_id); + + /* AT-Command */ + at_cmd = g_strdup_printf("AT+CGPADDR=%d", context_id); + dbg(" at command : %s", at_cmd); + + /* Send Request to modem */ + ret = tcore_at_prepare_and_send_request(co_ps, + at_cmd, NULL, + TCORE_AT_COMMAND_TYPE_SINGLELINE, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + __on_response_imc_ps_get_pdp_address, + ps_context, + on_send_imc_request, NULL, + 0, NULL, NULL); + + if (ret != TEL_RETURN_SUCCESS){ + err("Failed to prepare and send AT request"); + /* Deactivate PDP context */ + (void)tcore_object_dispatch_request(co_ps, TRUE, + TCORE_COMMAND_PS_DEACTIVATE_CONTEXT, + &ps_context, sizeof(CoreObject *), + NULL, NULL); + } + tcore_free(at_cmd); +} + +static void __on_response_imc_ps_send_xdns_enable_cmd(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + CoreObject *co_ps = tcore_pending_ref_core_object(p); + CoreObject *ps_context = (CoreObject *) user_data; + guint context_id; + TcorePsCallState status = TCORE_PS_CALL_STATE_NOT_CONNECTED; + + tcore_check_return_assert(at_resp != NULL); + tcore_check_return_assert(ps_context != NULL); + + dbg("Entered"); + + (void)tcore_context_get_id(ps_context, &context_id); + dbg("Context ID : %d", context_id); + + if (at_resp->success) { + dbg("Response OK, Dynamic DNS is enabled successfully"); + status = TCORE_PS_CALL_STATE_CTX_DEFINED; + } else { + PrivateInfo *private_info = tcore_object_ref_user_data(co_ps); + tcore_check_return_assert(private_info != NULL); + + status = private_info->ps_call_status; + err("ERROR [%s]", at_resp->final_response); + } + /* Send PS CALL Status Notification */ + __notify_context_status_changed(co_ps, context_id, status); +} + +static TelReturn __imc_ps_send_xdns_enable_cmd(CoreObject *co_ps, CoreObject *ps_context) +{ + guint context_id; + gchar *at_cmd = NULL; + TelReturn ret; + PrivateInfo *private_info = tcore_object_ref_user_data(co_ps); + + tcore_check_return_value_assert(private_info != NULL, TEL_RETURN_INVALID_PARAMETER); + + dbg("Entered"); + + (void)tcore_context_get_id(ps_context, &context_id); + dbg("Context ID : %d", context_id); + + /* AT-Command */ + at_cmd = g_strdup_printf("AT+XDNS=%d,1", context_id); + dbg("AT Command : %s", at_cmd); + + /* Send Request to modem */ + ret = tcore_at_prepare_and_send_request(co_ps, + at_cmd, NULL, + TCORE_AT_COMMAND_TYPE_SINGLELINE, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + __on_response_imc_ps_send_xdns_enable_cmd, + ps_context, + on_send_imc_request, NULL, + 0, NULL, NULL); + + if (ret != TEL_RETURN_SUCCESS){ + TcorePsCallState curr_call_status; + + err("Failed to prepare and send AT request"); + curr_call_status = private_info->ps_call_status; + __notify_context_status_changed(co_ps, context_id, curr_call_status); + } + return ret; +} + +static void on_response_imc_ps_activate_context(TcorePending *p, guint data_len, + const void *data, + void *user_data) +{ + const TcoreAtResponse *at_resp = data; + CoreObject *co_ps = tcore_pending_ref_core_object(p); + CoreObject *ps_context = user_data; + PrivateInfo *private_info = tcore_object_ref_user_data(co_ps); + + dbg("Entered"); + + tcore_check_return_assert(at_resp != NULL); + tcore_check_return_assert(ps_context != NULL); + tcore_check_return_assert(private_info != NULL); + + if (at_resp->success) { + dbg("Response OK, Get IP address of data session"); + __imc_ps_get_pdp_address(co_ps, ps_context); + } else { + guint context_id; + TcorePsCallState curr_call_status; + (void)tcore_context_get_id(ps_context, &context_id); + err("Response NOT OK,Sending call disconnect notification"); + curr_call_status = private_info->ps_call_status; + __notify_context_status_changed(co_ps, context_id, curr_call_status); + } +} + +static void on_response_imc_ps_deactivate_context(TcorePending *p, guint data_len, + const void *data, + void *user_data) +{ + const TcoreAtResponse *at_resp = data; + CoreObject *co_ps = tcore_pending_ref_core_object(p); + CoreObject *ps_context = user_data; + TcoreHal *hal = tcore_object_get_hal(co_ps); + guint context_id; + + dbg("Entered"); + + tcore_check_return_assert(at_resp != NULL); + tcore_check_return_assert(ps_context != NULL); + + (void)tcore_context_get_id(ps_context, &context_id); + dbg("Context ID : %d", context_id); + + /* + * AT+CGACT = 0 is returning NO CARRIER or an error. Just test if the + * response contains NO CARRIER else decode CME error. + */ +#if 0 + if (at_resp->success) { + const gchar *line; + + line = (const gchar *)at_resp->lines->data; + if (g_strcmp0(line, "NO CARRIER") != 0) { + err("%s", line); + err("Context %d has not been deactivated", context_id); + + goto out; + } + } + +#endif + __notify_context_status_changed(co_ps, context_id, TCORE_PS_CALL_STATE_NOT_CONNECTED); + + if (tcore_hal_setup_netif(hal, co_ps, NULL, NULL, context_id, FALSE) != TEL_RETURN_SUCCESS) + err("Failed to disable network interface"); +} + +static void on_response_imc_ps_define_context(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + CoreObject *ps_context = (CoreObject *) user_data; + CoreObject *co_ps = tcore_pending_ref_core_object(p); + PrivateInfo *private_info = tcore_object_ref_user_data(co_ps); + + dbg("Entred"); + + tcore_check_return_assert(at_resp != NULL); + tcore_check_return_assert(ps_context != NULL); + tcore_check_return_assert(private_info != NULL); + + if (at_resp->success) { + dbg("Response OK,Sending DNS enable command"); + __imc_ps_send_xdns_enable_cmd(co_ps, ps_context); + } else { + guint context_id; + TcorePsCallState curr_call_status; + + err("ERROR[%s]", at_resp->final_response); + (void)tcore_context_get_id(ps_context, &context_id); + curr_call_status = private_info->ps_call_status; + __notify_context_status_changed(co_ps, context_id, curr_call_status); + } +} + +/* + * Operation - PDP Context Activate + * + * Request - + * AT-Command: AT+CGACT= [ [, [, [,...]]]] + * + * where, + * + * indicates the state of PDP context activation + * + * 1 activated + * + * + * It is a numeric parameter which specifies a particular PDP context definition + * + * Response - + * Success: (No Result) + * OK + * Failure: + * +CME ERROR: + */ + +static TelReturn imc_ps_activate_context(CoreObject *co_ps, CoreObject *ps_context, + TcoreObjectResponseCallback cb, void *cb_data) +{ + TelReturn ret = TEL_RETURN_FAILURE; + gchar *at_cmd = NULL; + guint context_id; + PrivateInfo *private_info = tcore_object_ref_user_data(co_ps); + + tcore_check_return_value_assert(private_info != NULL, TEL_RETURN_INVALID_PARAMETER); + + dbg("Entered"); + + (void)tcore_context_get_id(ps_context, &context_id); + dbg("Context ID : %d", context_id); + + at_cmd = g_strdup_printf("AT+CGACT=1,%d", context_id); + dbg(" at command : %s", at_cmd); + + /* Send Request to modem */ + ret = tcore_at_prepare_and_send_request(co_ps, + at_cmd, NULL, + TCORE_AT_COMMAND_TYPE_NO_RESULT, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_ps_activate_context, + ps_context, + on_send_imc_request, NULL, + 0, NULL, NULL); + + if (ret != TEL_RETURN_SUCCESS){ + TcorePsCallState curr_call_status; + curr_call_status = private_info->ps_call_status; + err("AT request failed. Send notification for call status [%d]", curr_call_status); + __notify_context_status_changed(co_ps, context_id, curr_call_status); + } + tcore_free(at_cmd); + return ret; +} + +/* + * Operation - PDP Context Deactivate + * + * Request - + * AT-Command: AT+CGACT= [ [, [, [,...]]]] + * + * where, + * + * indicates the state of PDP context activation + * + * 0 deactivated + * + * + * It is a numeric parameter which specifies a particular PDP context definition + * + * Response - + * Success: (No Result) + * OK + * Failure: + * +CME ERROR: + */ +static TelReturn imc_ps_deactivate_context(CoreObject *co_ps, CoreObject *ps_context, + TcoreObjectResponseCallback cb, void *cb_data) +{ + TelReturn ret = TEL_RETURN_FAILURE; + gchar *at_cmd = NULL; + guint context_id; + PrivateInfo *private_info = tcore_object_ref_user_data(co_ps); + + tcore_check_return_value_assert(private_info != NULL, TEL_RETURN_INVALID_PARAMETER); + + dbg("Entered"); + + (void)tcore_context_get_id(ps_context, &context_id); + dbg("Context ID : %d", context_id); + + at_cmd = g_strdup_printf("AT+CGACT=0,%d", context_id); + dbg(" at command : %s", at_cmd); + + /* Send Request to modem */ + ret = tcore_at_prepare_and_send_request(co_ps, + at_cmd, NULL, + TCORE_AT_COMMAND_TYPE_NO_RESULT, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_ps_deactivate_context, + ps_context, + on_send_imc_request, NULL, + 0, NULL, NULL); + + if (ret != TEL_RETURN_SUCCESS){ + TcorePsCallState curr_call_status; + curr_call_status = private_info->ps_call_status; + err("AT request failed. Send notification for call status [%d]", curr_call_status); + __notify_context_status_changed(co_ps, context_id, curr_call_status); + } + tcore_free(at_cmd); + return ret; +} + +/* + * Operation - Define PDP Context + * + * Request - + * AT-Command: AT+CGDCONT= [ [, [, [, [, + * [, [, [... [, pdN]]]]]]]]] + * where, + * + * It is a numeric parameter, which specifies a particular PDP context definition + * + * + * "IP" Internet Protocol (IETF STD 5) + * "IPV6" Internet Protocol, version 6 (IETF RFC 2460) + * "IPV4V6" Virtual introduced to handle dual IP stack UE capability (see 3GPP + * TS 24.301[83]) + * + * + * Access Point Name + * + * + * It is the string parameter that identifies the MT in the address space applicable to the PDP + * The allocated address may be read using the command +CGPADDR command + * + * + * A numeric parameter that controls PDP data compression + * 0 off + * 1 on + * 2 V.42 bis + * + * + * A numeric parameter that controls PDP header compression + * 0 off + * 1 on + * 2 RFC1144 + * 3 RFC2507 + * 4 RFC3095 + * + * ... + * zero to N string parameters whose meanings are specific to the + * + * Response - + * Success: (No Result) + * OK + * Failure: + * +CME ERROR: + */ +static TelReturn imc_ps_define_context(CoreObject *co_ps, CoreObject *ps_context, + TcoreObjectResponseCallback cb, void *cb_data) +{ + TelReturn ret = TEL_RETURN_FAILURE; + gchar *at_cmd = NULL; + guint context_id = 0; + gchar *apn = NULL; + gchar *pdp_type_str = NULL; + TcoreContextType pdp_type; + TcoreContextDComp d_comp; + TcoreContextHComp h_comp; + TcorePsCallState curr_call_status; + + PrivateInfo *private_info = tcore_object_ref_user_data(co_ps); + + tcore_check_return_value_assert(private_info != NULL, TEL_RETURN_INVALID_PARAMETER); + + dbg("Entred"); + + (void)tcore_context_get_id(ps_context, &context_id); + (void)tcore_context_get_type(ps_context, &pdp_type); + + switch (pdp_type) { + case TCORE_CONTEXT_TYPE_X25: + dbg("CONTEXT_TYPE_X25"); + pdp_type_str = g_strdup("X.25"); + break; + + case TCORE_CONTEXT_TYPE_IP: + dbg("CONTEXT_TYPE_IP"); + pdp_type_str = g_strdup("IP"); + break; + + case TCORE_CONTEXT_TYPE_PPP: + dbg("CONTEXT_TYPE_PPP"); + pdp_type_str = g_strdup("PPP"); + break; + + case TCORE_CONTEXT_TYPE_IPV6: + dbg("CONTEXT_TYPE_IPV6"); + pdp_type_str = g_strdup("IPV6"); + break; + + default: + /*PDP Type not supported*/ + dbg("Unsupported PDP type: %d", pdp_type); + goto error; + } + + (void)tcore_context_get_data_compression(ps_context, &d_comp); + (void)tcore_context_get_header_compression(ps_context, &h_comp); + (void)tcore_context_get_apn(ps_context, &apn); + + dbg("Define context for CID: %d", context_id); + + /* AT-Command */ + at_cmd = g_strdup_printf("AT+CGDCONT=%d,\"%s\",\"%s\",,%d,%d", context_id, pdp_type_str, apn, d_comp, h_comp); + dbg("AT Command : %s", at_cmd); + + /* Send Request to modem */ + ret = tcore_at_prepare_and_send_request(co_ps, + at_cmd, NULL, + TCORE_AT_COMMAND_TYPE_NO_RESULT, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_ps_define_context, + ps_context, + on_send_imc_request, NULL, + 0, NULL, NULL); + + tcore_free(pdp_type_str); + tcore_free(at_cmd); + tcore_free(apn); + + if (ret == TEL_RETURN_SUCCESS) + goto out; + +error: + err("Failed to prepare and send AT request"); + + curr_call_status = private_info->ps_call_status; + __notify_context_status_changed(co_ps, context_id, curr_call_status); + +out: + return ret; +} + +/* PS Operations */ +static TcorePsOps imc_ps_ops = { + .define_context = imc_ps_define_context, + .activate_context = imc_ps_activate_context, + .deactivate_context = imc_ps_deactivate_context +}; + + +gboolean imc_ps_init(TcorePlugin *p, CoreObject *co) +{ + PrivateInfo *private_info; + + dbg("Entry"); + + /* Set PrivateInfo */ + private_info = tcore_malloc0(sizeof(PrivateInfo)); + tcore_object_link_user_data(co, private_info); + + /* Set operations */ + tcore_ps_set_ops(co, &imc_ps_ops); + + /* Add Callbacks */ + tcore_object_add_callback(co, "+CGEV", on_notification_imc_ps_cgev, NULL); + + tcore_plugin_add_notification_hook(p, + TCORE_NOTIFICATION_NETWORK_REGISTRATION_STATUS, + on_hook_imc_nw_registration_status, co); + + dbg("Exit"); + return TRUE; +} + +void imc_ps_exit(TcorePlugin *p, CoreObject *co) +{ + PrivateInfo *private_info; + + private_info = tcore_object_ref_user_data(co); + tcore_check_return_assert(private_info != NULL); + + tcore_free(private_info); + + dbg("Exit"); +} diff --git a/src/imc_sap.c b/src/imc_sap.c new file mode 100644 index 0000000..f6667ea --- /dev/null +++ b/src/imc_sap.c @@ -0,0 +1,750 @@ +/* + * tel-plugin-imc + * + * Copyright (c) 2013 Samsung Electronics Co. Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "imc_sap.h" +#include "imc_common.h" + +static TelSapResult __map_sap_status_to_result(int sap_status) +{ + switch(sap_status){ + case 0: + return TEL_SAP_RESULT_SUCCESS; + case 1: + return TEL_SAP_RESULT_FAILURE_NO_REASON; + case 2: + return TEL_SAP_RESULT_CARD_NOT_ACCESSIBLE; + case 3: + return TEL_SAP_RESULT_CARD_ALREADY_POWERED_OFF; + case 4: + return TEL_SAP_RESULT_CARD_REMOVED; + case 5: + return TEL_SAP_RESULT_CARD_ALREADY_POWERED_ON; + case 6: + return TEL_SAP_RESULT_DATA_NOT_AVAILABLE; + case 7: + return TEL_SAP_RESULT_NOT_SUPPORTED; + default: + return TEL_SAP_RESULT_FAILURE_NO_REASON; + } +} + +/* Notification */ +static gboolean on_notification_imc_sap_status(CoreObject *co, + const void *event_info, void *user_data) +{ + GSList *tokens = NULL; + GSList *lines = NULL; + const char *line = NULL; + TelSapCardStatus status; + + dbg("Entry"); + + lines = (GSList *) event_info; + if (g_slist_length(lines) != 1) { + err("unsolicited msg but multiple lines"); + return FALSE; + } + + line = (char *)lines->data; + tokens = tcore_at_tok_new(line); + tcore_check_return_value(tokens != NULL, FALSE); + + status = atoi(g_slist_nth_data(tokens, 0)); + + switch(status){ + case 0: + status = TEL_SAP_CARD_STATUS_UNKNOWN; + break; + case 1: + status = TEL_SAP_CARD_STATUS_RESET; + break; + case 2: + status = TEL_SAP_CARD_STATUS_NOT_ACCESSIBLE; + break; + case 3: + status = TEL_SAP_CARD_STATUS_REMOVED; + break; + case 4: + status = TEL_SAP_CARD_STATUS_INSERTED; + break; + case 5: + status = TEL_SAP_CARD_STATUS_RECOVERED; + break; + default: + status = TEL_SAP_CARD_STATUS_NOT_ACCESSIBLE; + break; + } + + tcore_at_tok_free(tokens); + tcore_object_send_notification(co, + TCORE_NOTIFICATION_SAP_STATUS, + sizeof(TelSapCardStatus), &status); + return TRUE; +} + +/* Response */ +static void on_response_imc_sap_req_connect(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + CoreObject *co = tcore_pending_ref_core_object(p); + ImcRespCbData *resp_cb_data = user_data; + TelSapResult result = TEL_SAP_RESULT_UNABLE_TO_ESTABLISH; + unsigned int max_msg_size = 0; + dbg("entry"); + + tcore_check_return_assert(co != NULL); + tcore_check_return_assert(resp_cb_data != NULL); + + if (at_resp && at_resp->success) { + result = TEL_SAP_RESULT_SUCCESS; + memcpy(&max_msg_size, IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data), sizeof(unsigned int)); + } else { + err("CME error[%s]", at_resp->lines->data); + /*TODO - need to map CME error to TelSapResult */ + } + + dbg("Request to sap connection : [%s]", + (result == TEL_SAP_RESULT_SUCCESS ? "SUCCESS" : "FAIL")); + + /* Invoke callback */ + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, &max_msg_size, resp_cb_data->cb_data); + + /* Free callback data */ + imc_destroy_resp_cb_data(resp_cb_data); +} + +static void on_response_imc_sap_req_disconnect(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + CoreObject *co = tcore_pending_ref_core_object(p); + ImcRespCbData *resp_cb_data = user_data; + TelSapResult result = TEL_SAP_RESULT_FAILURE_NO_REASON; + dbg("entry"); + + tcore_check_return_assert(co != NULL); + tcore_check_return_assert(resp_cb_data != NULL); + + if (at_resp && at_resp->success) { + result = TEL_SAP_RESULT_SUCCESS; + } else { + err("CME error[%s]", at_resp->lines->data); + /*TODO - need to map CME error to TelSapResult */ + } + + dbg("Request to sap connection : [%s]", + (result == TEL_SAP_RESULT_SUCCESS ? "SUCCESS" : "FAIL")); + + /* Invoke callback */ + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, NULL, resp_cb_data->cb_data); + + /* Free callback data */ + imc_destroy_resp_cb_data(resp_cb_data); +} + +static void on_response_imc_sap_get_atr(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + CoreObject *co = tcore_pending_ref_core_object(p); + ImcRespCbData *resp_cb_data = user_data; + TelSapResult result = TEL_SAP_RESULT_FAILURE_NO_REASON; + TelSapAtr atr_resp = {0,}; + + dbg("entry"); + + if (at_resp && at_resp->success) { + const gchar *line; + char *atr_data; + GSList *tokens = NULL; + + dbg("RESPONSE OK"); + if (at_resp->lines == NULL) { + err("invalid response recieved"); + goto END; + } + + line = (const char*)at_resp->lines->data; + tokens = tcore_at_tok_new(line); + if (g_slist_length(tokens) < 1) { + err("invalid response message"); + tcore_at_tok_free(tokens); + goto END; + } + atr_data = (char *) g_slist_nth_data(tokens, 1); + atr_resp.atr_len = strlen(atr_data); + if (atr_resp.atr_len > TEL_SAP_ATR_LEN_MAX) { + err(" invalid atr data length"); + tcore_at_tok_free(tokens); + goto END; + } + memcpy(atr_resp.atr, atr_data, atr_resp.atr_len); + + result = __map_sap_status_to_result(atoi(g_slist_nth_data(tokens, 0))); + tcore_at_tok_free(tokens); + } else { + err("RESPONSE NOK"); + } + +END: + dbg("Request to get sap atr : [%s]", + (result == TEL_SAP_RESULT_SUCCESS ? "SUCCESS" : "FAIL")); + + /* Invoke callback */ + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, &atr_resp, resp_cb_data->cb_data); + + /* Free callback data */ + imc_destroy_resp_cb_data(resp_cb_data); +} + +static void on_response_imc_sap_req_transfer_apdu(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + CoreObject *co = tcore_pending_ref_core_object(p); + ImcRespCbData *resp_cb_data = user_data; + TelSapResult result = TEL_SAP_RESULT_FAILURE_NO_REASON; + TelSapApduResp apdu_resp = {0,}; + + dbg("entry"); + + if (at_resp && at_resp->success) { + const gchar *line; + int sap_status; + char *apdu_data; + GSList *tokens = NULL; + + dbg("RESPONSE OK"); + if (at_resp->lines == NULL) { + err("invalid response recieved"); + goto END; + } + + line = (const char*)at_resp->lines->data; + tokens = tcore_at_tok_new(line); + if (g_slist_length(tokens) < 1) { + err("invalid response message"); + tcore_at_tok_free(tokens); + goto END; + } + + apdu_data = (char *) g_slist_nth_data(tokens, 1); + apdu_resp.apdu_resp_len = strlen(apdu_data); + if (apdu_resp.apdu_resp_len > TEL_SAP_APDU_RESP_LEN_MAX) { + err(" invalid apdu data length"); + tcore_at_tok_free(tokens); + goto END; + } + memcpy(apdu_resp.apdu_resp, apdu_data, apdu_resp.apdu_resp_len); + + sap_status = atoi(g_slist_nth_data(tokens, 0)); + if (sap_status > 4) + /* In this case modem does not provide sap_status 5 ('Card already powered ON'), + instead it will provide status 5 ('Data not available') and 6 ('Not Supported'), + So to align 'sap_status' value with __map_sap_status_to_result(), it is increased by 1. + */ + result = __map_sap_status_to_result(sap_status + 1); + else + result = __map_sap_status_to_result(sap_status); + + tcore_at_tok_free(tokens); + } else { + err("RESPONSE NOK"); + } + +END: + dbg("Request to transfer apdu : [%s]", + (result == TEL_SAP_RESULT_SUCCESS ? "SUCCESS" : "FAIL")); + + /* Invoke callback */ + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, &apdu_resp, resp_cb_data->cb_data); + + /* Free callback data */ + imc_destroy_resp_cb_data(resp_cb_data); +} + +static void on_response_imc_sap_req_power_operation(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + CoreObject *co = tcore_pending_ref_core_object(p); + ImcRespCbData *resp_cb_data = user_data; + TelSapResult result = TEL_SAP_RESULT_FAILURE_NO_REASON; + + dbg("entry"); + + if (at_resp && at_resp->success) { + const gchar *line; + GSList *tokens = NULL; + + dbg("RESPONSE OK"); + if (at_resp->lines == NULL) { + err("invalid response recieved"); + goto END; + } + + line = (const char*)at_resp->lines->data; + tokens = tcore_at_tok_new(line); + if (g_slist_length(tokens) < 1) { + err("invalid response message"); + tcore_at_tok_free(tokens); + goto END; + } + result = __map_sap_status_to_result(atoi(g_slist_nth_data(tokens, 0))); + tcore_at_tok_free(tokens); + } else { + err("RESPONSE NOK"); + } + +END: + dbg("Request to sap power operation : [%s]", + (result == TEL_SAP_RESULT_SUCCESS ? "SUCCESS" : "FAIL")); + + /* Invoke callback */ + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, NULL, resp_cb_data->cb_data); + + /* Free callback data */ + imc_destroy_resp_cb_data(resp_cb_data); +} + +static void on_response_imc_sap_get_cardreader_status(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + CoreObject *co = tcore_pending_ref_core_object(p); + ImcRespCbData *resp_cb_data = user_data; + TelSapResult result = TEL_SAP_RESULT_FAILURE_NO_REASON; + TelSapCardStatus card_status = TEL_SAP_CARD_STATUS_UNKNOWN; + dbg("entry"); + + if (at_resp && at_resp->success) { + const gchar *line; + GSList *tokens = NULL; + unsigned char card_reader_status; + int count; + + dbg("RESPONSE OK"); + if (at_resp->lines == NULL) { + err("invalid response recieved"); + goto END; + } + + line = (const char*)at_resp->lines->data; + tokens = tcore_at_tok_new(line); + if (g_slist_length(tokens) < 1) { + err("invalid response message"); + tcore_at_tok_free(tokens); + goto END; + } + result = __map_sap_status_to_result(atoi(g_slist_nth_data(tokens, 0))); + + card_reader_status = (unsigned char)atoi(g_slist_nth_data(tokens, 1)); + card_reader_status = card_reader_status >> 3; + for (count = 8; count > 3; count--) { //check bit 8 to 3 + if ((card_reader_status & 0x80) == TRUE) { //Check most significant bit + //card_status = //TODO - Need to map card reader status to TelSapCardStatus. + break; + } + card_reader_status = card_reader_status << 1; //left shift by 1 + } + tcore_at_tok_free(tokens); + } else { + err("RESPONSE NOK"); + result = TEL_SAP_RESULT_FAILURE_NO_REASON; + } + +END: + dbg("Request to get card reader status : [%s]", + (result == TEL_SAP_RESULT_SUCCESS ? "SUCCESS" : "FAIL")); + + /* Invoke callback */ + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, &card_status, resp_cb_data->cb_data); + + /* Free callback data */ + imc_destroy_resp_cb_data(resp_cb_data); +} + +/* Sap operations */ + +/* + * Operation - switch the modem to the BT SAP server mode. + * + * Request - + * AT-Command: AT+ XBCON = , , + * where, + * + * 0 - BT SAP Server modes + * 1 - BT SAP Client mode (Client mode is currently not supported) + * + * 0 - gracefully, or Time out + * 1 - immediately + * + * 0 - Reject is not allowed. + * 1 - Reject is allowed. + * Response - + * Success: (No Result) + * OK + * Failure: + * +CME ERROR: + */ +static TelReturn imc_sap_req_connect(CoreObject *co, unsigned int max_msg_size, + TcoreObjectResponseCallback cb, void *cb_data) +{ + ImcRespCbData *resp_cb_data; + TelReturn ret; + + /* Response callback data */ + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, + &max_msg_size, sizeof(unsigned int)); + + /* Send Request to modem */ + ret = tcore_at_prepare_and_send_request(co, + "AT+XBCON=0,0,0", NULL, + TCORE_AT_COMMAND_TYPE_NO_RESULT, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_sap_req_connect, resp_cb_data, + on_send_imc_request, NULL, + 0, NULL, NULL); + + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "imc_sap_req_connect"); + return ret; +} + +/* + * Operation - disconnects BT SAP. + * + * Request - + * AT-Command: AT+ XBDISC + * + * Response - + * Success: (No Result) + * OK + * Failure: + * +CME ERROR: + */ +static TelReturn imc_sap_req_disconnect(CoreObject *co, TcoreObjectResponseCallback cb, + void *cb_data) +{ + ImcRespCbData *resp_cb_data; + TelReturn ret; + + /* Response callback data */ + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, + NULL, 0); + + /* Send Request to modem */ + ret = tcore_at_prepare_and_send_request(co, + "AT+XBDISC", NULL, + TCORE_AT_COMMAND_TYPE_NO_RESULT, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_sap_req_disconnect, resp_cb_data, + on_send_imc_request, NULL, + 0, NULL, NULL); + + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "imc_sap_req_disconnect"); + return ret; +} + +/* + * Operation - In BT SAP server mode, request the ATR from the stack to the Application. + * + * Request - + * AT-Command: AT+ XBATR + * + * Response - + * Success: +XBATR: , + * OK + * where + * + * 0 OK, request processed correctly + * 1 No Reason defined + * 2 Card not accessible + * 3 Card (already) powered off + * 4 Card Removed + * 6 Data Not available + * 7 Not Supported + * + * Hex Data (an array of bytes) + * + * Failure: + * +CME ERROR: + */ +static TelReturn imc_sap_get_atr(CoreObject *co, TcoreObjectResponseCallback cb, + void *cb_data) +{ + ImcRespCbData *resp_cb_data; + TelReturn ret; + + /* Response callback data */ + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, + NULL, 0); + + /* Send Request to modem */ + ret = tcore_at_prepare_and_send_request(co, + "AT+XBATR", "+XBATR:", + TCORE_AT_COMMAND_TYPE_SINGLELINE, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_sap_get_atr, resp_cb_data, + on_send_imc_request, NULL, + 0, NULL, NULL); + + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "imc_sap_get_atr"); + return ret; +} + +/* + * Operation - BT SAP server mode, Forward command APDU from application to SIM. + * + * Request - + * AT-Command: AT+ XBAPDU = + * where + * + * Hex Data (an array of bytes). CP supports Command_APDU up to 261 bytes long. + * + * Response - + * Success: +XBAPDU: , [] + * OK + * where + * + * 0 OK, request processed correctly + * 1 No Reason defined + * 2 Card not accessible + * 3 Card (already) powered off + * 4 Card Removed + * 5 Data not available + * 6 Not Supported + * + * Hex Data (an array of bytes). CP supports Response_APDU up to 258 bytes long + * Failure: + * +CME ERROR: + */ +static TelReturn imc_sap_req_transfer_apdu(CoreObject *co, const TelSapApdu *apdu_data, + TcoreObjectResponseCallback cb, void *cb_data) +{ + ImcRespCbData *resp_cb_data; + TelReturn ret; + gchar *at_cmd; + + /* AT-Command */ + at_cmd = g_strdup_printf("AT+XBAPDU=\"%s\"", apdu_data->apdu); + + /* Response callback data */ + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, + NULL, 0); + + /* Send Request to modem */ + ret = tcore_at_prepare_and_send_request(co, + at_cmd, "+XBAPDU:", + TCORE_AT_COMMAND_TYPE_SINGLELINE, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_sap_req_transfer_apdu, resp_cb_data, + on_send_imc_request, NULL, + 0, NULL, NULL); + + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "imc_sap_req_transfer_apdu"); + g_free(at_cmd); + return ret; +} + +static TelReturn imc_sap_req_transport_protocol(CoreObject *co, TelSimSapProtocol protocol, + TcoreObjectResponseCallback cb, void *cb_data) +{ + err("Operation not supported"); + return TEL_RETURN_OPERATION_NOT_SUPPORTED; +} + +/* + * Operation - In BT SAP server mode, Power ON,OFF and Reset the SIM. + * + * Request - + * AT-Command: AT+ XBPWR = + * where + * : + * 0 SIM Power ON + * 1 SIM Power OFF + * 2 SIM RESET + * + * Response - + * Success: + XBPWR: + * OK + * where + * + * 0 OK, Request processed correctly + * 1 Error no reason defined + * 2 Card not Accessible + * 3 Card already powered OFF + * 4 Card removed + * 5 Card already powered ON + * 6 Data Not vailable + * 7 Not Supported + * Failure: + * +CME ERROR: + */ +static TelReturn imc_sap_req_power_operation(CoreObject *co, TelSapPowerMode power_mode, + TcoreObjectResponseCallback cb, void *cb_data) +{ + ImcRespCbData *resp_cb_data; + TelReturn ret = TEL_RETURN_FAILURE; + gchar *at_cmd; + int action; + + if(power_mode == TEL_SAP_SIM_POWER_ON_REQ) { + action = 0; + } else if(power_mode == TEL_SAP_SIM_POWER_OFF_REQ) { + action = 1; + } else if (power_mode == TEL_SAP_SIM_RESET_REQ) { + action = 2; + } else { + err("invalid power mode"); + return ret; + } + + /* AT-Command */ + at_cmd = g_strdup_printf("AT+XBPWR=%d", action); + + /* Response callback data */ + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, + NULL, 0); + + /* Send Request to modem */ + ret = tcore_at_prepare_and_send_request(co, + at_cmd, "+XBPWR:", + TCORE_AT_COMMAND_TYPE_SINGLELINE, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_sap_req_power_operation, resp_cb_data, + on_send_imc_request, NULL, + 0, NULL, NULL); + + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "imc_sap_req_power_operation"); + g_free(at_cmd); + return ret; +} + +/* + * Operation - In BT SAP server mode, get the Card reader Status. + * + * Request - + * AT-Command: AT+XBCRDSTAT + * + * Response - + * Success: +XBCRDSTAT: , + * OK + * where + * + * 0 OK, Request processed correctly + * 1 Error no reason defined + * 2 Card not Accessible + * 3 Card already powered OFF + * 4 Card removed + * 5 Card already powered ON + * 6 Data Not vailable + * 7 Not Supported + * + * One byte. It represents card reader identity and status. + * The value of this byte indicates the identity and status of a card reader. + * Bits 1-3 = identity of card reader x. + * bit 4, 0 = Card reader is not removable, 1 = Card reader is removable + * bit 5, 0 = Card reader is not present, 1 = Card reader is present + * bit 6, 0 = Card reader present is not ID-1 size, 1 = Card reader present is ID-1 size + * bit 7, 0 = No card present, 1 = Card is present in reader + * bit 8, 0 = No card powered, 1 = Card in reader is powered + * Failure: + * +CME ERROR: + */ +static TelReturn imc_sap_get_cardreader_status(CoreObject *co, TcoreObjectResponseCallback cb, + void *cb_data) +{ + ImcRespCbData *resp_cb_data; + TelReturn ret; + + /* Response callback data */ + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, + NULL, 0); + + /* Send Request to modem */ + ret = tcore_at_prepare_and_send_request(co, + "AT+XBCRDSTAT", "+XBCRDSTAT:", + TCORE_AT_COMMAND_TYPE_SINGLELINE, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_sap_get_cardreader_status, resp_cb_data, + on_send_imc_request, NULL, + 0, NULL, NULL); + + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "imc_sap_get_cardreader_status"); + return ret; +} + +/* SAP Operations */ +static TcoreSapOps imc_sap_ops = { + .req_connect = imc_sap_req_connect, + .req_disconnect = imc_sap_req_disconnect, + .get_atr = imc_sap_get_atr, + .req_transfer_apdu = imc_sap_req_transfer_apdu, + .req_transport_protocol = imc_sap_req_transport_protocol, + .req_power_operation = imc_sap_req_power_operation, + .get_cardreader_status = imc_sap_get_cardreader_status +}; + +gboolean imc_sap_init(TcorePlugin *p, CoreObject *co) +{ + dbg("Entry"); + + /* Set operations */ + tcore_sap_set_ops(co, &imc_sap_ops); + + /* Add Callbacks */ + tcore_object_add_callback(co, "+XBCSTAT", on_notification_imc_sap_status, NULL); + + dbg("Exit"); + return TRUE; +} + +void imc_sap_exit(TcorePlugin *p, CoreObject *co) +{ + dbg("Exit"); +} diff --git a/src/imc_sat.c b/src/imc_sat.c new file mode 100644 index 0000000..8c002f1 --- /dev/null +++ b/src/imc_sat.c @@ -0,0 +1,695 @@ +/* + * tel-plugin-imc + * + * Copyright (c) 2013 Samsung Electronics Co. Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "imc_sat.h" +#include "imc_common.h" + +#define PROACTV_CMD_LEN 256 + +static void on_response_enable_sat(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + + if (at_resp && at_resp->success) { + dbg("Enable SAT (Proactive command) - [OK]"); + } + else { + err("Enable SAT (Proactive command) - [NOK]"); + } +} + +/* Hook functions */ +static TcoreHookReturn on_hook_imc_sim_status(TcorePlugin *plugin, + TcoreNotification command, guint data_len, void *data, void *user_data) +{ + const TelSimCardStatus *sim_status = (TelSimCardStatus *)data; + CoreObject *co = (CoreObject *)user_data; + + tcore_check_return_value(sim_status != NULL, TCORE_HOOK_RETURN_CONTINUE); + + /* + * If SIM is initialized - + * * Enable SAT + */ + dbg("SIM Status: [%d]", *sim_status); + if (*sim_status == TEL_SIM_STATUS_SIM_INIT_COMPLETED) { + dbg("SIM Initialized!!! Enable SAT"); + + /* Enable SAT - Send AT+CFUN=6 */ + tcore_at_prepare_and_send_request(co, + "AT+CFUN=6", NULL, + TCORE_AT_COMMAND_TYPE_NO_RESULT, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_enable_sat, NULL, + on_send_imc_request, NULL, + 0, NULL, NULL); + } + + return TCORE_HOOK_RETURN_CONTINUE; +} + +static gboolean on_response_imc_sat_terminal_response_confirm + (CoreObject *co, const void *event_info, void *user_data) +{ + dbg("Entry"); + return TRUE; +} + +static gboolean on_notification_imc_sat_proactive_command + (CoreObject *co, const void *event_info, void *user_data) +{ + TelSatDecodedProactiveData decoded_data; + TelSatNotiProactiveData proactive_noti; + gint proactive_cmd_len = 0; + GSList *lines = NULL; + GSList *tokens = NULL; + gchar *line = NULL; + gchar *hex_data = NULL; + gchar *tmp = NULL; + gchar *record_data = NULL; + guint record_data_len; + gint decode_err; + gboolean decode_ret = FALSE; + + dbg("Entry"); + + tcore_check_return_value_assert(co != NULL, FALSE); + memset(&proactive_noti, 0x00, sizeof(TelSatNotiProactiveData)); + memset(&decoded_data, 0x00, sizeof(TelSatDecodedProactiveData)); + + lines = (GSList *) event_info; + line = (gchar *) lines->data; + tokens = tcore_at_tok_new(line); + if (g_slist_length(tokens) != 1) { + err("Invalid message"); + tcore_at_tok_free(tokens); + return TRUE; + } + + hex_data = (gchar *)g_slist_nth_data(tokens, 0); + dbg("SAT data: [%s] SAT data length: [%d]", hex_data, strlen(hex_data)); + + tmp = (gchar *)tcore_at_tok_extract((gchar *)hex_data); + tcore_util_hexstring_to_bytes(tmp, &record_data, &record_data_len); + dbg("record_data: %x", record_data); + tcore_free(tmp); + + tcore_util_hex_dump(" ", strlen(hex_data) / 2, record_data); + proactive_cmd_len = strlen(record_data); + dbg("proactive_cmd_len = %d", proactive_cmd_len); + + decode_ret = tcore_sat_decode_proactive_command((guchar *) record_data, + record_data_len, &decoded_data, &decode_err); + if (!decode_ret) { + err("Proactive Command decoding failed"); + tcore_at_tok_free(tokens); + return TRUE; + } + + tcore_free(record_data); + + proactive_noti.cmd_number = decoded_data.cmd_num; + proactive_noti.cmd_type = decoded_data.cmd_type; + proactive_noti.decode_err_code = decode_err; + + switch (decoded_data.cmd_type) { + case TEL_SAT_PROATV_CMD_DISPLAY_TEXT: + dbg("decoded command is display text!!"); + memcpy(&proactive_noti.proactive_ind_data.display_text, + &decoded_data.data.display_text, + sizeof(TelSatDisplayTextTlv)); + break; + + case TEL_SAT_PROATV_CMD_GET_INKEY: + dbg("decoded command is get inkey!!"); + memcpy(&proactive_noti.proactive_ind_data.get_inkey, + &decoded_data.data.get_inkey, + sizeof(TelSatGetInkeyTlv)); + break; + + case TEL_SAT_PROATV_CMD_GET_INPUT: + dbg("decoded command is get input!!"); + memcpy(&proactive_noti.proactive_ind_data.get_input, + &decoded_data.data.get_input, + sizeof(TelSatGetInputTlv)); + break; + + case TEL_SAT_PROATV_CMD_MORE_TIME: + dbg("decoded command is more time!!"); + memcpy(&proactive_noti.proactive_ind_data.more_time, + &decoded_data.data.more_time, + sizeof(TelSatMoreTimeTlv)); + break; + + case TEL_SAT_PROATV_CMD_PLAY_TONE: + dbg("decoded command is play tone!!"); + memcpy(&proactive_noti.proactive_ind_data.play_tone, + &decoded_data.data.play_tone, + sizeof(TelSatPlayToneTlv)); + break; + + case TEL_SAT_PROATV_CMD_SETUP_MENU: + dbg("decoded command is SETUP MENU!!"); + memcpy(&proactive_noti.proactive_ind_data.setup_menu, + &decoded_data.data.setup_menu, sizeof(TelSatSetupMenuTlv)); + break; + + case TEL_SAT_PROATV_CMD_SELECT_ITEM: + dbg("decoded command is select item!!"); + memcpy(&proactive_noti.proactive_ind_data.select_item, + &decoded_data.data.select_item, + sizeof(TelSatSelectItemTlv)); + break; + + case TEL_SAT_PROATV_CMD_SEND_SMS: + dbg("decoded command is send sms!!"); + memcpy(&proactive_noti.proactive_ind_data.send_sms, + &decoded_data.data.send_sms, + sizeof(TelSatSendSmsTlv)); + break; + + case TEL_SAT_PROATV_CMD_SEND_SS: + dbg("decoded command is send ss!!"); + memcpy(&proactive_noti.proactive_ind_data.send_ss, + &decoded_data.data.send_ss, + sizeof(TelSatSendSsTlv)); + break; + + case TEL_SAT_PROATV_CMD_SEND_USSD: + dbg("decoded command is send ussd!!"); + memcpy(&proactive_noti.proactive_ind_data.send_ussd, + &decoded_data.data.send_ussd, + sizeof(TelSatSendUssdTlv)); + break; + + case TEL_SAT_PROATV_CMD_SETUP_CALL: + dbg("decoded command is setup call!!"); + memcpy(&proactive_noti.proactive_ind_data.setup_call, + &decoded_data.data.setup_call, + sizeof(TelSatSetupCallTlv)); + break; + + case TEL_SAT_PROATV_CMD_REFRESH: + dbg("decoded command is refresh"); + memcpy(&proactive_noti.proactive_ind_data.refresh, + &decoded_data.data.refresh, sizeof(TelSatRefreshTlv)); + break; + + case TEL_SAT_PROATV_CMD_PROVIDE_LOCAL_INFO: + dbg("decoded command is provide local info"); + memcpy(&proactive_noti.proactive_ind_data.provide_local_info, + &decoded_data.data.provide_local_info, + sizeof(TelSatProvideLocalInfoTlv)); + break; + + case TEL_SAT_PROATV_CMD_SETUP_EVENT_LIST: + dbg("decoded command is setup event list!!"); + memcpy(&proactive_noti.proactive_ind_data.setup_event_list, + &decoded_data.data.setup_event_list, + sizeof(TelSatSetupEventListTlv)); + // setup_event_rsp_get(o, &decoded_data.data.setup_event_list); + break; + + case TEL_SAT_PROATV_CMD_SETUP_IDLE_MODE_TEXT: + dbg("decoded command is setup idle mode text"); + memcpy(&proactive_noti.proactive_ind_data.setup_idle_mode_text, + &decoded_data.data.setup_idle_mode_text, + sizeof(TelSatSetupIdleModeTextTlv)); + break; + + case TEL_SAT_PROATV_CMD_SEND_DTMF: + dbg("decoded command is send dtmf"); + memcpy(&proactive_noti.proactive_ind_data.send_dtmf, + &decoded_data.data.send_dtmf, + sizeof(TelSatSendDtmfTlv)); + break; + + case TEL_SAT_PROATV_CMD_LANGUAGE_NOTIFICATION: + dbg("decoded command is language notification"); + memcpy(&proactive_noti.proactive_ind_data.language_notification, + &decoded_data.data.language_notification, + sizeof(TelSatLanguageNotificationTlv)); + break; + + case TEL_SAT_PROATV_CMD_LAUNCH_BROWSER: + dbg("decoded command is launch browser"); + memcpy(&proactive_noti.proactive_ind_data.launch_browser, + &decoded_data.data.launch_browser, + sizeof(TelSatLaunchBrowserTlv)); + break; + + case TEL_SAT_PROATV_CMD_OPEN_CHANNEL: + dbg("decoded command is open channel!!"); + memcpy(&proactive_noti.proactive_ind_data.open_channel, + &decoded_data.data.open_channel, + sizeof(TelSatOpenChannelTlv)); + break; + + case TEL_SAT_PROATV_CMD_CLOSE_CHANNEL: + dbg("decoded command is close channel!!"); + memcpy(&proactive_noti.proactive_ind_data.close_channel, + &decoded_data.data.close_channel, + sizeof(TelSatCloseChannelTlv)); + break; + + case TEL_SAT_PROATV_CMD_RECEIVE_DATA: + dbg("decoded command is receive data!!"); + memcpy(&proactive_noti.proactive_ind_data.receive_data, + &decoded_data.data.receive_data, + sizeof(TelSatReceiveChannelTlv)); + break; + + case TEL_SAT_PROATV_CMD_SEND_DATA: + dbg("decoded command is send data!!"); + memcpy(&proactive_noti.proactive_ind_data.send_data, + &decoded_data.data.send_data, + sizeof(TelSatSendChannelTlv)); + break; + + case TEL_SAT_PROATV_CMD_GET_CHANNEL_STATUS: + dbg("decoded command is get channel status!!"); + memcpy(&proactive_noti.proactive_ind_data.get_channel_status, + &decoded_data.data.get_channel_status, + sizeof(TelSatGetChannelStatusTlv)); + break; + + default: + dbg("invalid command:[%d]", decoded_data.cmd_type); + break; + } + + if (decoded_data.cmd_type == TEL_SAT_PROATV_CMD_REFRESH) { + /*Not supported*/ + dbg("Not suported Proactive command"); + tcore_at_tok_free(tokens); + return TRUE; + } + + /* Send notification */ + tcore_object_send_notification(co, + TCORE_NOTIFICATION_SAT_PROACTIVE_CMD, + sizeof(TelSatNotiProactiveData), &proactive_noti); + + tcore_at_tok_free(tokens); + + dbg("Exit"); + return TRUE; +} + +/* SAT Responses */ +static void on_response_imc_sat_send_envelop_cmd(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + CoreObject *co = tcore_pending_ref_core_object(p); + ImcRespCbData *resp_cb_data = user_data; + TelSatEnvelopeResp envelop_resp; + TelSatResult result = TEL_SAT_RESULT_FAILURE; + GSList *tokens = NULL; + const gchar *line = NULL; + const gchar *env_res = NULL; + gint sw2 = -1; + + dbg("Entry"); + + tcore_check_return_assert(co != NULL); + tcore_check_return_assert(resp_cb_data != NULL); + tcore_check_return_assert(resp_cb_data->cb != NULL); + + if (at_resp && at_resp->success) { + result = TEL_SAT_RESULT_SUCCESS; + dbg("RESPONSE OK"); + if (at_resp->lines) { + line = (const gchar *) at_resp->lines->data; + tokens = tcore_at_tok_new(line); + if (g_slist_length(tokens) < 1) { + err("invalid message"); + tcore_at_tok_free(tokens); + return; + } + } + env_res = g_slist_nth_data(tokens, 0); + envelop_resp = TEL_SAT_ENVELOPE_SUCCESS; + dbg("RESPONSE tokens present"); + if (NULL != g_slist_nth_data(tokens, 1)) { + sw2 = atoi(g_slist_nth_data(tokens, 1)); + dbg("status word SW2:[%d]", sw2); + if (sw2 == 0) { + dbg("Response is processed completely and sending session end notification"); + /* Send Session End notification */ + tcore_object_send_notification(co, + TCORE_NOTIFICATION_SAT_SESSION_END, 0, NULL); + } + } + } else { + dbg("RESPONSE NOK"); + envelop_resp = TEL_SAT_ENVELOPE_FAILED; + } + + /* Invoke callback */ + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, &envelop_resp, resp_cb_data->cb_data); + + imc_destroy_resp_cb_data(resp_cb_data); + tcore_at_tok_free(tokens); + dbg("Exit"); +} + +static void on_response_imc_sat_send_terminal_response(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + CoreObject *co = tcore_pending_ref_core_object(p); + ImcRespCbData *resp_cb_data = user_data; + TelSatResult result = TEL_SAT_RESULT_FAILURE; + + dbg("Entry"); + + tcore_check_return_assert(co != NULL); + tcore_check_return_assert(resp_cb_data != NULL); + tcore_check_return_assert(resp_cb_data->cb != NULL); + + if (at_resp && at_resp->success) { + result = TEL_SAT_RESULT_SUCCESS; + dbg("RESPONSE OK"); + dbg(" at_resp->success = %d", at_resp->success); + /* Send Session End notification */ + tcore_object_send_notification(co, TCORE_NOTIFICATION_SAT_SESSION_END, 0, NULL); + } + + /* Invoke callback */ + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, NULL, resp_cb_data->cb_data); + + imc_destroy_resp_cb_data(resp_cb_data); + dbg("Exit"); +} + +static void on_response_imc_sat_send_user_confirmation(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + CoreObject *co = tcore_pending_ref_core_object(p); + ImcRespCbData *resp_cb_data = user_data; + TelSatResult result = TEL_SAT_RESULT_FAILURE; + + dbg("Entry"); + + tcore_check_return_assert(co != NULL); + tcore_check_return_assert(resp_cb_data != NULL); + tcore_check_return_assert(resp_cb_data->cb != NULL); + + if (at_resp && at_resp->success) { + dbg("RESPONSE OK"); + result = TEL_SAT_RESULT_SUCCESS; + } + + /* Invoke callback */ + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, NULL, resp_cb_data->cb_data); + + imc_destroy_resp_cb_data(resp_cb_data); + dbg("Exit"); +} + +/* SAT Requests */ +/* + * Operation - Send Envelop Command + * + * Request - + * AT-Command: AT+SATE + * + * Response - SW + * Success: (Single line) + * , + * OK + * Failure: + * +CME ERROR: + */ +static TelReturn imc_sat_send_envelope(CoreObject *co, + const TelSatRequestEnvelopCmdData *envelop_data, + TcoreObjectResponseCallback cb, void *cb_data) +{ + gchar *at_cmd; + gint envelope_cmd_len = 0; + gchar envelope_cmd[PROACTV_CMD_LEN]; + gint count = 0; + gchar hex_string[PROACTV_CMD_LEN * 2]; + gchar *buffer = NULL; + gboolean encode_ret = FALSE; + + ImcRespCbData *resp_cb_data; + TelReturn ret; + + dbg("Entry"); + memset(&hex_string, 0x00, sizeof(hex_string)); + buffer = hex_string; + + encode_ret = tcore_sat_encode_envelop_cmd(envelop_data, + (gchar *)envelope_cmd, (gint *)&envelope_cmd_len); + if (!encode_ret) { + err("Envelope Command encoding failed"); + return TEL_RETURN_FAILURE; + } + + dbg("envelope_cmd_len after encoding :[%d]", envelope_cmd_len); + if (envelope_cmd_len == 0) { + err("Envelope command length after encoding is NULL"); + return TEL_RETURN_INVALID_PARAMETER; + } + + for (count = 0; count < envelope_cmd_len; count++) { + dbg("envelope_cmd: %02x", (guchar)envelope_cmd[count]); + sprintf(buffer, "%02x", (guchar)envelope_cmd[count]); + buffer += 2; + } + dbg("hex_string: %s", hex_string); + + /* AT-Command */ + at_cmd = g_strdup_printf("AT+SATE=\"%s\"", hex_string); + + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, + (void *)&envelop_data->sub_cmd, sizeof(TelSatEnvelopSubCmd)); + + /* Send Request to modem */ + ret = tcore_at_prepare_and_send_request(co, + at_cmd, NULL, + TCORE_AT_COMMAND_TYPE_SINGLELINE, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_sat_send_envelop_cmd, resp_cb_data, + on_send_imc_request, NULL, + 0, NULL, NULL); + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Send Envelop Command"); + + /* Free resources */ + tcore_free(at_cmd); + dbg("Exit"); + return ret; +} + +/* + * Operation - Send Terminal Response + * + * Request - + * AT-Command: AT+SATR + * + * Response - OK + * Success: (NO Result) + * OK + * Failure: + * +CME ERROR: + */ +static TelReturn imc_sat_send_terminal_response(CoreObject *co, + const TelSatRequestTerminalResponseData *terminal_rsp_data, + TcoreObjectResponseCallback cb, void *cb_data) +{ + gchar *at_cmd; + gint terminal_resp_len = 0; + gchar terminal_resp[PROACTV_CMD_LEN]; + gint i = 0; + gchar *hex_string = NULL; + gboolean encode_ret = FALSE; + + ImcRespCbData *resp_cb_data; + TelReturn ret; + + dbg("Entry"); + + encode_ret = tcore_sat_encode_terminal_response(terminal_rsp_data, + (gchar *)terminal_resp, (gint *)&terminal_resp_len); + if (!encode_ret) { + err("Envelope Command encoding failed"); + return TEL_RETURN_FAILURE; + } + + dbg("terminal_resp after encoding: %s", terminal_resp); + dbg("terminal_resp length after encoding:[%d]", strlen(terminal_resp)); + if (terminal_resp_len == 0) { + err("Terminal Response length after encoding is NULL"); + return TEL_RETURN_INVALID_PARAMETER; + } + hex_string = calloc((terminal_resp_len * 2) + 1, 1); + + for (i = 0; i < terminal_resp_len * 2; i += 2) { + gchar value = 0; + value = (terminal_resp[i / 2] & 0xf0) >> 4; + if (value < 0xA) + hex_string[i] = ((terminal_resp[i / 2] & 0xf0) >> 4) + '0'; + else + hex_string[i] = ((terminal_resp[i / 2] & 0xf0) >> 4) + 'A' - 10; + + value = terminal_resp[i / 2] & 0x0f; + if (value < 0xA) + hex_string[i + 1] = (terminal_resp[i / 2] & 0x0f) + '0'; + else + hex_string[i + 1] = (terminal_resp[i / 2] & 0x0f) + 'A' - 10; + } + dbg("hex_string: %s", hex_string); + + /* AT-Command */ + at_cmd = g_strdup_printf("AT+SATR=\"%s\"", hex_string); + + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, NULL, 0); + + /* Send Request to modem */ + ret = tcore_at_prepare_and_send_request(co, + at_cmd, NULL, + TCORE_AT_COMMAND_TYPE_NO_RESULT, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_sat_send_terminal_response, resp_cb_data, + on_send_imc_request, NULL, + 0, NULL, NULL); + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Send Terminal Response"); + + /* Free resources */ + tcore_free(at_cmd); + dbg("Exit"); + return ret; +} + +/* + * Operation - Send User Confirmation + * + * Request - + * AT-Command: AT+SATD + * + * Response - OK + * Success: (NO Result) + * OK + * Failure: + * +CME ERROR: + */ +static TelReturn imc_sat_send_user_confirmation(CoreObject *co, + const TelSatRequestUserConfirmationData *user_conf_data, + TcoreObjectResponseCallback cb, void *cb_data) +{ + gchar *at_cmd; + guint usr_conf; + ImcRespCbData *resp_cb_data; + TelReturn ret; + + dbg("Entry"); + + usr_conf = (guint)user_conf_data->user_conf; + dbg("User confirmation:[%d]", usr_conf); + + /* AT-Command */ + at_cmd = g_strdup_printf("AT+SATD=%d", usr_conf); + + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, NULL, 0); + + /* Send Request to modem */ + ret = tcore_at_prepare_and_send_request(co, + at_cmd, NULL, + TCORE_AT_COMMAND_TYPE_NO_RESULT, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_sat_send_user_confirmation, resp_cb_data, + on_send_imc_request, NULL, + 0, NULL, NULL); + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Send User Confirmation"); + + /* Free resources */ + tcore_free(at_cmd); + dbg("Exit"); + return ret; + +} + +/* SAT Operations */ +static TcoreSatOps imc_sat_ops = { + .send_envelope = imc_sat_send_envelope, + .send_terminal_response = imc_sat_send_terminal_response, + .send_user_confirmation = imc_sat_send_user_confirmation +}; + +/* SAT Init */ +gboolean imc_sat_init(TcorePlugin *p, CoreObject *co) +{ + dbg("Entry"); + + /* Set operations */ + tcore_sat_set_ops(co, &imc_sat_ops); + + /* Add Callbacks */ + /* + * At present keeping the same notification processing for + * both SATI and SATN command. But in future notification processing + * will be seperated for both command depending on SAT re-architecure. + */ + tcore_object_add_callback(co, "+SATI", + on_notification_imc_sat_proactive_command, NULL); + tcore_object_add_callback(co, "+SATN", + on_notification_imc_sat_proactive_command, NULL); + tcore_object_add_callback(co, "+SATF", + on_response_imc_sat_terminal_response_confirm, NULL); + + /* Hooks */ + tcore_plugin_add_notification_hook(p, + TCORE_NOTIFICATION_SIM_STATUS, on_hook_imc_sim_status, co); + + dbg("Exit"); + return TRUE; +} + +/* SAT Exit */ +void imc_sat_exit(TcorePlugin *p, CoreObject *co) +{ + dbg("Exit"); +} diff --git a/src/imc_sim.c b/src/imc_sim.c new file mode 100644 index 0000000..94f9ca4 --- /dev/null +++ b/src/imc_sim.c @@ -0,0 +1,3976 @@ +/* + * tel-plugin-imc + * + * Copyright (c) 2013 Samsung Electronics Co. Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "imc_sim.h" +#include "imc_common.h" + +#define ENABLE_FLAG 1 +#define DISABLE_FLAG 2 + +#define IMC_SIM_ACCESS_READ_BINARY 176 +#define IMC_SIM_ACCESS_READ_RECORD 178 +#define IMC_SIM_ACCESS_GET_RESPONSE 192 +#define IMC_SIM_ACCESS_UPDATE_BINARY 214 +#define IMC_SIM_ACCESS_UPDATE_RECORD 220 + +#define IMC_SIM_READ_FILE(co, cb, cb_data, fileId, ret) \ +{ \ + ImcSimMetaInfo file_meta = {0, }; \ + ImcRespCbData *resp_cb_data = NULL; \ + \ + file_meta.file_id = fileId; \ + file_meta.file_result = TEL_SIM_RESULT_FAILURE; \ + \ + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, &file_meta, sizeof(ImcSimMetaInfo)); \ + \ + ret = __imc_sim_get_response(co, resp_cb_data); \ + dbg("Request reading '%s' - [%s]", #fileId, (ret == TEL_RETURN_SUCCESS ? "SUCCESS" : "FAILURE")); \ +} + +typedef enum { + IMC_SIM_FILE_TYPE_DEDICATED = 0x00, /**< Dedicated */ + IMC_SIM_FILE_TYPE_TRANSPARENT = 0x01, /**< Transparent -binary type*/ + IMC_SIM_FILE_TYPE_LINEAR_FIXED = 0x02, /**< Linear fixed - record type*/ + IMC_SIM_FILE_TYPE_CYCLIC = 0x04, /**< Cyclic - record type*/ + IMC_SIM_FILE_TYPE_INVALID_TYPE = 0xFF /**< Invalid type */ +} ImcSimFileType; + +typedef enum { + IMC_SIM_CURR_SEC_OP_PIN1_VERIFY, + IMC_SIM_CURR_SEC_OP_PIN2_VERIFY, + IMC_SIM_CURR_SEC_OP_PUK1_VERIFY, + IMC_SIM_CURR_SEC_OP_PUK2_VERIFY, + IMC_SIM_CURR_SEC_OP_SIM_VERIFY, + IMC_SIM_CURR_SEC_OP_ADM_VERIFY, + IMC_SIM_CURR_SEC_OP_PIN1_CHANGE, + IMC_SIM_CURR_SEC_OP_PIN2_CHANGE, + IMC_SIM_CURR_SEC_OP_PIN1_ENABLE, + IMC_SIM_CURR_SEC_OP_PIN1_DISABLE, + IMC_SIM_CURR_SEC_OP_PIN2_ENABLE, + IMC_SIM_CURR_SEC_OP_PIN2_DISABLE, // 10 + IMC_SIM_CURR_SEC_OP_SIM_ENABLE, + IMC_SIM_CURR_SEC_OP_SIM_DISABLE, + IMC_SIM_CURR_SEC_OP_NET_ENABLE, + IMC_SIM_CURR_SEC_OP_NET_DISABLE, + IMC_SIM_CURR_SEC_OP_NS_ENABLE, + IMC_SIM_CURR_SEC_OP_NS_DISABLE, + IMC_SIM_CURR_SEC_OP_SP_ENABLE, + IMC_SIM_CURR_SEC_OP_SP_DISABLE, + IMC_SIM_CURR_SEC_OP_CP_ENABLE, + IMC_SIM_CURR_SEC_OP_CP_DISABLE, // 20 + IMC_SIM_CURR_SEC_OP_FDN_ENABLE, + IMC_SIM_CURR_SEC_OP_FDN_DISABLE, + IMC_SIM_CURR_SEC_OP_PIN1_STATUS, + IMC_SIM_CURR_SEC_OP_PIN2_STATUS, + IMC_SIM_CURR_SEC_OP_FDN_STATUS, + IMC_SIM_CURR_SEC_OP_NET_STATUS, + IMC_SIM_CURR_SEC_OP_NS_STATUS, + IMC_SIM_CURR_SEC_OP_SP_STATUS, + IMC_SIM_CURR_SEC_OP_CP_STATUS, + IMC_SIM_CURR_SEC_OP_SIM_STATUS, + IMC_SIM_CURR_SEC_OP_SIM_UNKNOWN = 0xff +} ImcSimCurrSecOp; + +typedef struct { + guint smsp_count; /**< SMSP record count */ + guint smsp_rec_len; /**< SMSP record length */ +} ImcSimPrivateInfo; + +typedef struct { + gboolean b_valid; /**< Valid or not */ + guint rec_length; /**< Length of one record in file */ + guint rec_count; /**< Number of records in file */ + guint data_size; /**< File size */ + guint current_index; /**< Current index to read */ + ImcSimFileType file_type; /**< File type and structure */ + ImcSimCurrSecOp sec_op; /**< Current index to read */ + TelSimMailboxList mbi_list; /**< Mailbox List */ + TelSimMailBoxNumber mb_list[TEL_SIM_MSP_CNT_MAX*5]; /**< Mailbox number */ + TelSimFileId file_id; /**< Current file id */ + TelSimResult file_result; /**< File access result */ + TelSimFileResult files; /**< File read data */ + TcoreCommand req_command; /**< Request command Id */ + TelSimImsiInfo imsi; /**< Stored locally as of now, + Need to store in secure storage*/ +} ImcSimMetaInfo; + +/* Utility Function Declaration */ +static TelSimResult __imc_sim_decode_status_word(unsigned short status_word1, unsigned short status_word2); +static void __imc_sim_update_sim_status(CoreObject *co, TelSimCardStatus sim_status); +static void __imc_sim_notify_sms_state(CoreObject *co, gboolean sms_ready); +static TelReturn __imc_sim_start_to_cache(CoreObject *co); +static gboolean __imc_sim_get_sim_type(CoreObject *co, TcoreObjectResponseCallback cb, void *cb_data); +static void __imc_sim_next_from_read_binary(CoreObject *co, ImcRespCbData *resp_cb_data, TelSimResult sim_result, gboolean decode_ret); +static void __imc_sim_next_from_get_response(CoreObject *co, ImcRespCbData *resp_cb_data, TelSimResult sim_result); +static TelReturn __imc_sim_update_file(CoreObject *co, ImcRespCbData *resp_cb_data, int cmd, TelSimFileId ef, + int p1, int p2, int p3, char *encoded_data); +static void __imc_sim_read_record(CoreObject *co, ImcRespCbData *resp_cb_data); +static void __imc_sim_read_binary(CoreObject *co, ImcRespCbData *resp_cb_data); +static TelReturn __imc_sim_get_response (CoreObject *co, ImcRespCbData *resp_cb_data); +static TelReturn __imc_sim_get_retry_count(CoreObject *co, ImcRespCbData *resp_cb_data); +static TelSimLockType __imc_sim_lock_type(int lock_type); +static char *__imc_sim_get_fac_from_lock_type(TelSimLockType lock_type, ImcSimCurrSecOp *sec_op, int flag); +static int __imc_sim_get_lock_type(ImcSimCurrSecOp sec_op); + +/* Internal Response Functions*/ +static void __on_response_imc_sim_get_sim_type_internal(CoreObject *co, gint result, const void *response, void *user_data); +static void __on_response_imc_sim_get_sim_type(TcorePending *p, guint data_len, const void *data, void *user_data); +static void __on_response_imc_sim_read_data(TcorePending *p, guint data_len, const void *data, void *user_data); +static void __on_response_imc_sim_get_response(TcorePending *p, guint data_len, const void *data, void *user_data); +static void __on_response_imc_sim_get_retry_count(TcorePending *p, guint data_len, const void *data, void *user_data); +static void __on_response_imc_sim_update_file(TcorePending *p, guint data_len, const void *data, void *user_data); + +/* GET SMSP info for SMS module */ +gboolean imc_sim_get_smsp_info(TcorePlugin *plugin, int *rec_count, int *rec_len) +{ + CoreObject *co = NULL; + ImcSimPrivateInfo *priv_info = NULL; + + dbg("Entry"); + + co = tcore_plugin_ref_core_object(plugin, CORE_OBJECT_TYPE_SIM); + priv_info = tcore_sim_ref_userdata(co); + if(!priv_info) + return FALSE; + + *rec_count = priv_info->smsp_count; + *rec_len = priv_info->smsp_rec_len; + + dbg("smsp_count:[%d], smsp_rec_len:[%d]", priv_info->smsp_count, priv_info->smsp_rec_len); + return TRUE; +} + +static void __imc_sim_set_identity(CoreObject *co, TelSimImsiInfo *imsi) +{ + gchar new_imsi[15 + 1] = {0, }; + gchar *old_imsi; + + memcpy(&new_imsi, imsi->mcc, strlen(imsi->mcc)); + memcpy(&new_imsi[strlen(imsi->mcc)], imsi->mnc, strlen(imsi->mnc)); + memcpy(&new_imsi[strlen(imsi->mcc) + strlen(imsi->mnc)], imsi->msin, strlen(imsi->msin)); + + /* TODO: This is temporary code, we should use secure storage instead of vconf */ + old_imsi = vconf_get_str("db/telephony/imsi"); + if (old_imsi) { + if (g_strcmp0(old_imsi, new_imsi) != 0) { + dbg("New SIM"); + vconf_set_str("db/telephony/imsi", new_imsi); + tcore_sim_set_identification(co, TRUE); + } else { + dbg("Same SIM"); + tcore_sim_set_identification(co, FALSE); + } + } else { + dbg("Old IMSI value is NULL, set IMSI"); + vconf_set_str("db/telephony/imsi", new_imsi); + tcore_sim_set_identification(co, TRUE); + } +} + +/* Utility Functions */ +static TelSimResult __imc_sim_decode_status_word(unsigned short status_word1, unsigned short status_word2) +{ + TelSimResult rst = TEL_SIM_RESULT_FAILURE; + + if (status_word1 == 0x93 && status_word2 == 0x00) { + /*Failed SIM request command*/ + dbg("error - SIM application toolkit busy [%x][%x]", status_word1, status_word2); + } else if (status_word1 == 0x94 && status_word2 == 0x00) { + /*Failed SIM request command*/ + dbg("error - No EF Selected [%x][%x]", status_word1, status_word2); + } else if (status_word1 == 0x94 && status_word2 == 0x02) { + /*Failed SIM request command*/ + dbg("error - Out of Range - Invalid address or record number[%x][%x]", + status_word1, status_word2); + } else if (status_word1 == 0x94 && status_word2 == 0x04) { + /*Failed SIM request command*/ + dbg("error - File ID not found [%x][%x]", status_word1, status_word2); + } else if (status_word1 == 0x94 && status_word2 == 0x08) { + /*Failed SIM request command*/ + dbg("error - File is inconsistent with command - Modem not support or USE IPC [%x][%x]", + status_word1, status_word2); + } else if (status_word1 == 0x98 && status_word2 == 0x02) { + /*Failed SIM request command*/ + dbg("error - CHV not initialized [%x][%x]", status_word1, status_word2); + } else if (status_word1 == 0x98 && status_word2 == 0x04) { + /*Failed SIM request command*/ + dbg("error - Access condition not fullfilled [%x][%x]", status_word1, status_word2); + dbg("error -Unsuccessful CHV verification - at least one attempt left [%x][%x]", + status_word1, status_word2); + dbg("error - Unsuccessful Unblock CHV - at least one attempt left [%x][%x]", + status_word1, status_word2); + dbg("error - Authentication failure [%x][%x]", status_word1, status_word2); + } else if (status_word1 == 0x98 && status_word2 == 0x08) { + /*Failed SIM request command*/ + dbg("error - Contradiction with CHV status [%x][%x]", status_word1, status_word2); + } else if (status_word1 == 0x98 && status_word2 == 0x10) { + /*Failed SIM request command*/ + dbg("error - Contradiction with invalidation status [%x][%x]", + status_word1, status_word2); + } else if (status_word1 == 0x98 && status_word2 == 0x40) { + /*Failed SIM request command*/ + dbg("error -Unsuccessful CHV verification - no attempt left [%x][%x]", + status_word1, status_word2); + dbg("error - Unsuccessful Unblock CHV - no attempt left [%x][%x]", + status_word1, status_word2); + dbg("error - CHV blocked [%x][%x]", status_word1, status_word2); + } else if (status_word1 == 0x67 && status_word2 == 0x00) { + dbg("error -Incorrect Parameter 3 [%x][%x]", status_word1, status_word2); + } else if (status_word1 == 0x6B && status_word2 == 0x00) { + dbg("error -Incorrect Parameter 1 or 2 [%x][%x]", status_word1, status_word2); + } else if (status_word1 == 0x6D && status_word2 == 0x00) { + dbg("error -Unknown instruction given as command [%x][%x]", status_word1, status_word2); + } else if (status_word1 == 0x6E && status_word2 == 0x00) { + dbg("error -Unknown instruction given as command [%x][%x]", status_word1, status_word2); + } else if (status_word1 == 0x69 && status_word2 == 0x82) { + dbg("error -Access denied [%x][%x]", status_word1, status_word2); + } else if (status_word1 == 0x6A && status_word2 == 0x87) { + dbg("error -Incorrect parameters [%x][%x]", status_word1, status_word2); + } else if (status_word1 == 0x6A && status_word2 == 0x82) { + dbg("error -File Not found [%x][%x]", status_word1, status_word2); + } else if (status_word1 == 0x6A && status_word2 == 0x83) { + dbg("error -Record Not found [%x][%x]", status_word1, status_word2); + } else { + rst = TEL_SIM_RESULT_CARD_ERROR; + dbg("error -Unknown state [%x][%x]", status_word1, status_word2); + } + return rst; +} + +static void __imc_sim_update_sim_status(CoreObject *co, TelSimCardStatus sim_status) +{ + TelSimCardStatus curr_sim_status; + + /* + * Send SIM Init status, if not sent already + */ + (void)tcore_sim_get_status(co, &curr_sim_status); + if (sim_status != curr_sim_status) { + TelSimCardStatusInfo sim_status_noti = {0, }; + + dbg("Change in SIM State - Old State: [0x%02x] --> New State: [0x%02x]", + curr_sim_status, sim_status); + + /* Update SIM Status */ + tcore_sim_set_status(co, sim_status); + sim_status_noti.status = sim_status; + tcore_sim_get_identification(co, &sim_status_noti.change_status); + + /* Send notification: SIM Status */ + tcore_object_send_notification(co, + TCORE_NOTIFICATION_SIM_STATUS, + sizeof(sim_status_noti), &sim_status_noti); + } +} + +static void __imc_sim_notify_sms_state(CoreObject *co, + gboolean sms_ready) +{ + TcorePlugin *plugin; + CoreObject *co_sms; + gboolean sms_status = FALSE; + + dbg("Entry"); + + plugin = tcore_object_ref_plugin(co); + co_sms = tcore_plugin_ref_core_object(plugin, CORE_OBJECT_TYPE_SMS); + tcore_check_return_assert(co_sms != NULL); + + (void)tcore_sms_get_ready_status(co_sms, &sms_status); + if (sms_status == sms_ready) { + dbg("No change in SMS Status: [%s]", + (sms_status ? "INITIALIZED" : "UNINITIALIZED")); + } else { + TelSimCardStatus sim_status; + + /* Update SMS State */ + tcore_sms_set_ready_status(co_sms, sms_ready); + + dbg("SMS Status - Changed [%s] --> [%s]", + (sms_status ? "INITIALIZED" : "UNINITIALIZED"), + (sms_ready ? "INITIALIZED" : "UNINITIALIZED")); + + /* + * Send SMS device ready notification, if SIM is initialiazed. + */ + (void)tcore_sim_get_status(co, &sim_status); + if (sim_status == TEL_SIM_STATUS_SIM_INIT_COMPLETED) { + /* Send notification: SMS Device ready */ + tcore_object_send_notification(co_sms, + TCORE_NOTIFICATION_SMS_DEVICE_READY, + sizeof(sms_ready), &sms_ready); + } + } +} + +TelReturn __imc_sim_start_to_cache(CoreObject *co) +{ + TelReturn ret; + IMC_SIM_READ_FILE(co, NULL, NULL, TEL_SIM_EF_IMSI, ret); + IMC_SIM_READ_FILE(co, NULL, NULL, TEL_SIM_EF_CPHS_CPHS_INFO, ret); + IMC_SIM_READ_FILE(co, NULL, NULL, TEL_SIM_EF_ICCID, ret); + IMC_SIM_READ_FILE(co, NULL, NULL, TEL_SIM_EF_SPN, ret); + IMC_SIM_READ_FILE(co, NULL, NULL, TEL_SIM_EF_SST, ret); + IMC_SIM_READ_FILE(co, NULL, NULL, TEL_SIM_EF_ECC, ret); + IMC_SIM_READ_FILE(co, NULL, NULL, TEL_SIM_EF_MSISDN, ret); + IMC_SIM_READ_FILE(co, NULL, NULL, TEL_SIM_EF_SMSP, ret); + + return ret; +} + +static void __on_response_imc_sim_get_sim_type_internal(CoreObject *co, + gint result, const void *response, void *user_data) +{ + dbg("SIM Response - SIM Type (internal): [+XUICC]"); + + if (result == TEL_SIM_RESULT_SUCCESS) { + TelSimCardType *sim_type = (TelSimCardType *)response; + dbg("SIM Type: [%d]", *sim_type); + + /* Update SIM type */ + tcore_sim_set_type(co, *sim_type); + if (*sim_type != TEL_SIM_CARD_TYPE_UNKNOWN) { + TelReturn ret; + + /* Start Caching SIM files */ + ret = __imc_sim_start_to_cache(co); + + /* Send SIM Type notification */ + tcore_object_send_notification(co, + TCORE_NOTIFICATION_SIM_TYPE, + sizeof(TelSimCardType), sim_type); + } + } +} + +static void __on_response_imc_sim_get_sim_type(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + CoreObject *co = tcore_pending_ref_core_object(p); + ImcRespCbData *resp_cb_data = user_data; + TelSimCardType sim_type = TEL_SIM_CARD_TYPE_UNKNOWN; + + TelSimResult result = TEL_SIM_RESULT_FAILURE; + + dbg("SIM Response - SIM Type: [+XUICC]"); + + tcore_check_return_assert(co != NULL); + tcore_check_return_assert(resp_cb_data != NULL); + + if (at_resp && at_resp->success) { + if (at_resp->lines) { + const gchar *line; + GSList *tokens; + + line = (const gchar *)at_resp->lines->data; + + /* + * Tokenize + * + * +XUICC: + */ + tokens = tcore_at_tok_new(line); + + /* */ + if (g_slist_length(tokens) == 1) { + guint state = atoi(g_slist_nth_data(tokens, 0)); + + if (state == 0) /* 0 - 2G SIM */ + sim_type = TEL_SIM_CARD_TYPE_GSM; + else if (state == 1) /* 1 - 3G SIM */ + sim_type = TEL_SIM_CARD_TYPE_USIM; + + result = TEL_SIM_RESULT_SUCCESS; + } + else { + err("Invalid message"); + } + + tcore_at_tok_free(tokens); + } + } + + /* Invoke callback */ + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, &sim_type, resp_cb_data->cb_data); + + /* Free callback data */ + imc_destroy_resp_cb_data(resp_cb_data); +} + +/* + * Operation - get_sim_type + * + * Request - + * AT-Command: AT+XUICC? + * + * Response - sim_type (TelSimCardType) + * Success: (Single line) - + * + XUICC: + * OK + * Failure: + * +CME ERROR: + */ +gboolean __imc_sim_get_sim_type(CoreObject *co, + TcoreObjectResponseCallback cb, void *cb_data) +{ + ImcRespCbData *resp_cb_data; + TelReturn ret; + + /* Response callback data */ + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, + NULL, 0); + + /* Send Request to modem */ + ret = tcore_at_prepare_and_send_request(co, + "AT+XUICC?", "+XUICC:", + TCORE_AT_COMMAND_TYPE_SINGLELINE, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + __on_response_imc_sim_get_sim_type, resp_cb_data, + on_send_imc_request, NULL, + 0, NULL, NULL); + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Get SIM Type"); + + return ret; +} + +static void __imc_sim_process_sim_status(CoreObject *co, guint sim_state) +{ + TelSimCardStatus sim_card_status; + + switch (sim_state) { + case 0: + sim_card_status = TEL_SIM_STATUS_CARD_NOT_PRESENT; + dbg("NO SIM"); + break; + + case 1: + sim_card_status = TEL_SIM_STATUS_SIM_PIN_REQUIRED; + dbg("PIN REQUIRED"); + break; + + case 2: + sim_card_status = TEL_SIM_STATUS_SIM_INITIALIZING; + dbg("PIN DISABLED AT BOOT UP"); + break; + + case 3: + sim_card_status = TEL_SIM_STATUS_SIM_INITIALIZING; + dbg("PIN VERIFIED"); + break; + + case 4: + sim_card_status = TEL_SIM_STATUS_SIM_PUK_REQUIRED; + dbg("PUK REQUIRED"); + break; + + case 5: + sim_card_status = TEL_SIM_STATUS_SIM_PUK_REQUIRED; + dbg("CARD PERMANENTLY BLOCKED"); + break; + + case 6: + sim_card_status = TEL_SIM_STATUS_CARD_ERROR; + dbg("SIM CARD ERROR"); + break; + + case 7: + sim_card_status = TEL_SIM_STATUS_SIM_INIT_COMPLETED; + dbg("SIM INIT COMPLETED"); + break; + + case 8: + sim_card_status = TEL_SIM_STATUS_CARD_ERROR; + dbg("SIM CARD ERROR"); + break; + + case 9: + sim_card_status = TEL_SIM_STATUS_CARD_REMOVED; + dbg("SIM REMOVED"); + break; + + case 12: + dbg("SIM SMS Ready"); + + /* Notify SMS status */ + return __imc_sim_notify_sms_state(co, TRUE); + + case 99: + sim_card_status = TEL_SIM_STATUS_UNKNOWN; + dbg("SIM STATE UNKNOWN"); + break; + + default: + err("Unknown/Unsupported SIM state: [%d]", sim_state); + return; + } + + switch (sim_card_status) { + case TEL_SIM_STATUS_SIM_INIT_COMPLETED: { + TelSimCardType sim_type; + + dbg("SIM INIT COMPLETED"); + + (void)tcore_sim_get_type(co, &sim_type); + if (sim_type == TEL_SIM_CARD_TYPE_UNKNOWN) { + /* + * SIM is initialized for first time, need to + * fetch SIM type + */ + (void)__imc_sim_get_sim_type(co, + __on_response_imc_sim_get_sim_type_internal, NULL); + + return; + } + } + break; + + case TEL_SIM_STATUS_CARD_REMOVED: + dbg("SIM CARD REMOVED"); + tcore_sim_set_type(co, TEL_SIM_CARD_TYPE_UNKNOWN); + break; + + case TEL_SIM_STATUS_CARD_NOT_PRESENT: + dbg("SIM CARD NOT PRESENT"); + tcore_sim_set_type(co, TEL_SIM_CARD_TYPE_UNKNOWN); + break; + + case TEL_SIM_STATUS_CARD_ERROR: + dbg("SIM CARD ERROR"); + tcore_sim_set_type(co, TEL_SIM_CARD_TYPE_UNKNOWN); + break; + + default: + err("SIM Status: [0x%02x]", sim_card_status); + break; + } + + /* Update SIM Status */ + return __imc_sim_update_sim_status(co, sim_card_status); +} + +static void __on_response_imc_sim_get_sim_status(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + CoreObject *co = tcore_pending_ref_core_object(p); + ImcRespCbData *resp_cb_data = (ImcRespCbData *)user_data; + dbg("Enter"); + + dbg("SIM Response - SIM status: [+XSIMSTATE]"); + + tcore_check_return_assert(co != NULL); + tcore_check_return_assert(resp_cb_data != NULL); + + if (at_resp && at_resp->success) { + if (at_resp->lines) { + const gchar *line = NULL; + + /* Process +XSIMSTATE response */ + line = (const gchar *) (at_resp->lines->data); + if (line != NULL) { + GSList *tokens; + guint sim_state, sms_state; + + /* + * Tokenize + * + * +XSIMSTATE: ,,, + */ + tokens = tcore_at_tok_new(line); + + if (g_slist_length(tokens) == 4) { + /* */ + sim_state = atoi(g_slist_nth_data(tokens, 1)); + + /* Process SIM Status */ + __imc_sim_process_sim_status(co, sim_state); + + /* */ + sms_state = atoi(g_slist_nth_data(tokens, 3)); + + /* Notify SMS status */ + __imc_sim_notify_sms_state(co, (sms_state > 0)); + + } else { + err("Invalid message"); + } + + tcore_at_tok_free(tokens); + } + } + } + + /* Free callback data */ + imc_destroy_resp_cb_data(resp_cb_data); +} + +/* + * Operation - get_sim_status + * + * Request - + * AT-Command: AT+XSIMSTATE? + * + * Response - sim_status + * Success: (Single line) - + * +XSIMSTATE: ,,, + * OK + * Failure: + * +CME ERROR: + */ +static gboolean __imc_sim_get_sim_status(CoreObject *co, + TcoreObjectResponseCallback cb, void *cb_data) +{ + ImcRespCbData *resp_cb_data; + TelReturn ret; + + /* Response callback data */ + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, + NULL, 0); + + /* Send Request to modem */ + ret = tcore_at_prepare_and_send_request(co, + "AT+XSIMSTATE?", "+XSIMSTATE:", + TCORE_AT_COMMAND_TYPE_SINGLELINE, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + __on_response_imc_sim_get_sim_status, resp_cb_data, + on_send_imc_request, NULL, + 0, NULL, NULL); + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Get SIM Status"); + + return TRUE; +} + +static void __imc_sim_next_from_read_binary(CoreObject *co, ImcRespCbData *resp_cb_data, TelSimResult sim_result, gboolean decode_ret) +{ + ImcSimMetaInfo *file_meta = (ImcSimMetaInfo *)IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data); + TelSimCardType card_type = TEL_SIM_CARD_TYPE_UNKNOWN; + + dbg("Entry"); + + dbg("[SIM]EF[0x%x] read sim_result[%d] Decode rt[%d]", file_meta->file_id, sim_result, decode_ret); + switch (file_meta->file_id) { + case TEL_SIM_EF_ELP: + case TEL_SIM_EF_USIM_PL: + case TEL_SIM_EF_LP: + case TEL_SIM_EF_USIM_LI: + if (decode_ret == TRUE) { + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)sim_result, &file_meta->files.data, resp_cb_data->cb_data); + } else { + tcore_sim_get_type(co, &card_type); + /* 2G */ + /* The ME requests the Extended Language Preference. The ME only requests the Language Preference (EFLP) if at least one of the following conditions holds: + - EFELP is not available; + - EFELP does not contain an entry corresponding to a language specified in ISO 639[30]; + - the ME does not support any of the languages in EFELP. + */ + /* 3G */ + /* The ME only requests the Language Preference (EFPL) if at least one of the following conditions holds: + - if the EFLI has the value 'FFFF' in its highest priority position + - if the ME does not support any of the language codes indicated in EFLI , or if EFLI is not present + */ + if (TEL_SIM_CARD_TYPE_GSM == card_type) { + if (file_meta->file_id == TEL_SIM_EF_LP) { + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)sim_result, &file_meta->files.data, resp_cb_data->cb_data); + } else { + file_meta->file_id = TEL_SIM_EF_LP; + __imc_sim_get_response(co, resp_cb_data); + } + } else if (TEL_SIM_CARD_TYPE_USIM) { + if (file_meta->file_id == TEL_SIM_EF_LP || file_meta->file_id == TEL_SIM_EF_USIM_LI) { + file_meta->file_id = TEL_SIM_EF_ELP; + __imc_sim_get_response(co, resp_cb_data); + } else { + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)sim_result, &file_meta->files.data, resp_cb_data->cb_data); + } + } + } + break; + + case TEL_SIM_EF_ECC: + tcore_sim_get_type(co, &card_type); + if (TEL_SIM_CARD_TYPE_USIM == card_type) { + if (file_meta->current_index == file_meta->rec_count) { + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)sim_result, &file_meta->files.data, resp_cb_data->cb_data); + } else { + file_meta->current_index++; + __imc_sim_read_record(co, resp_cb_data); + } + } else if (TEL_SIM_CARD_TYPE_GSM == card_type) { + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)sim_result, &file_meta->files.data, resp_cb_data->cb_data); + } else { + dbg("[SIM DATA]Invalid CardType[%d] Unable to handle", card_type); + } + break; + + case TEL_SIM_EF_IMSI: + if (resp_cb_data->cb) { + resp_cb_data->cb(co, (gint)sim_result, &file_meta->imsi, resp_cb_data->cb_data); + } else { + file_meta->file_id = TEL_SIM_EF_CPHS_CPHS_INFO; + file_meta->file_result = TEL_SIM_RESULT_FAILURE; + __imc_sim_get_response(co, resp_cb_data); + } + /* Update SIM INIT status - INIT COMPLETE */ + __imc_sim_update_sim_status(co, TEL_SIM_STATUS_SIM_INIT_COMPLETED); + break; + + case TEL_SIM_EF_MSISDN: + if (file_meta->current_index == file_meta->rec_count) { + guint i; + dbg("rec_count [%d], msisdn_count[%d]", file_meta->rec_count, + file_meta->files.data.msisdn_list.count); + if (resp_cb_data->cb) { + resp_cb_data->cb(co, (gint)sim_result, + &file_meta->files.data.msisdn_list, resp_cb_data->cb_data); + } + + /* Free resources */ + for (i = 0; i < file_meta->files.data.msisdn_list.count; i++) { + tcore_free(file_meta->files.data.msisdn_list.list[i].alpha_id); + tcore_free(file_meta->files.data.msisdn_list.list[i].num); + } + tcore_free(file_meta->files.data.msisdn_list.list); + } else { + file_meta->current_index++; + __imc_sim_read_record(co, resp_cb_data); + } + break; + + case TEL_SIM_EF_OPL: + if (file_meta->current_index == file_meta->rec_count) { + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)sim_result, &file_meta->files.data, resp_cb_data->cb_data); + + } else { + file_meta->current_index++; + __imc_sim_read_record(co, resp_cb_data); + } + break; + + case TEL_SIM_EF_PNN: + if (file_meta->current_index == file_meta->rec_count) { + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)sim_result, &file_meta->files.data, resp_cb_data->cb_data); + } else { + file_meta->current_index++; + __imc_sim_read_record(co, resp_cb_data); + } + break; + + case TEL_SIM_EF_USIM_CFIS: + case TEL_SIM_EF_USIM_MWIS: + case TEL_SIM_EF_USIM_MBI: + case TEL_SIM_EF_MBDN: + case TEL_SIM_EF_CPHS_MAILBOX_NUMBERS: + case TEL_SIM_EF_CPHS_INFORMATION_NUMBERS: + if (file_meta->current_index == file_meta->rec_count) { + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)sim_result, &file_meta->files.data, resp_cb_data->cb_data); + } else { + file_meta->current_index++; + __imc_sim_read_record(co, resp_cb_data); + } + break; + + case TEL_SIM_EF_CPHS_OPERATOR_NAME_STRING: + { + ImcSimMetaInfo *file_meta_new = (ImcSimMetaInfo *)IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data); + + file_meta->files.result = sim_result; + if (decode_ret == TRUE && sim_result == TEL_SIM_RESULT_SUCCESS) { + file_meta_new->files.data.cphs_net.full_name = file_meta->files.data.cphs_net.full_name; + dbg("file_meta_new->files.data.cphs_net.full_name[%s]", file_meta_new->files.data.cphs_net.full_name); + } + + file_meta_new->file_id = TEL_SIM_EF_CPHS_OPERATOR_NAME_SHORT_FORM_STRING; + file_meta_new->file_result = TEL_SIM_RESULT_FAILURE; + + __imc_sim_get_response(co, resp_cb_data); + } + break; + + case TEL_SIM_EF_CPHS_OPERATOR_NAME_SHORT_FORM_STRING: + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)sim_result, &file_meta->files.data.cphs_net, resp_cb_data->cb_data); + + tcore_free(file_meta->files.data.cphs_net.full_name); + tcore_free(file_meta->files.data.cphs_net.short_name); + file_meta->files.data.cphs_net.full_name = NULL; + file_meta->files.data.cphs_net.short_name = NULL; + break; + + case TEL_SIM_EF_ICCID: + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)sim_result, &file_meta->files.data.iccid, resp_cb_data->cb_data); + break; + + case TEL_SIM_EF_SST: + case TEL_SIM_EF_SPN: + case TEL_SIM_EF_SPDI: + case TEL_SIM_EF_OPLMN_ACT: + case TEL_SIM_EF_CPHS_CPHS_INFO: + case TEL_SIM_EF_CPHS_CALL_FORWARD_FLAGS: + case TEL_SIM_EF_CPHS_VOICE_MSG_WAITING: + case TEL_SIM_EF_CPHS_DYNAMICFLAGS: + case TEL_SIM_EF_CPHS_DYNAMIC2FLAG: + case TEL_SIM_EF_CPHS_CUSTOMER_SERVICE_PROFILE: + case TEL_SIM_EF_CPHS_CUSTOMER_SERVICE_PROFILE_LINE2: + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)sim_result, &file_meta->files.data, resp_cb_data->cb_data); + break; + + default: + err("File id not handled [0x%x]", file_meta->file_id); + break; + } +} + +static void __imc_sim_next_from_get_response(CoreObject *co, ImcRespCbData *resp_cb_data, TelSimResult sim_result) +{ + ImcSimMetaInfo *file_meta = (ImcSimMetaInfo *)IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data); + TelSimCardType card_type = TEL_SIM_CARD_TYPE_UNKNOWN; + + dbg("EF[0x%x] access Result[%d]", file_meta->file_id, sim_result); + + file_meta->files.result = sim_result; + if (file_meta->file_id != TEL_SIM_EF_CPHS_OPERATOR_NAME_SHORT_FORM_STRING) + memset(&file_meta->files.data, 0x00, sizeof(file_meta->files.data)); + + if ((file_meta->file_id != TEL_SIM_EF_ELP && file_meta->file_id != TEL_SIM_EF_LP && + file_meta->file_id != TEL_SIM_EF_USIM_PL && file_meta->file_id != TEL_SIM_EF_CPHS_CPHS_INFO) + && (sim_result != TEL_SIM_RESULT_SUCCESS)) { + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)sim_result, &file_meta->files.data, resp_cb_data->cb_data); + return; + } + + switch (file_meta->file_id) { + case TEL_SIM_EF_ELP: + if (sim_result == TEL_SIM_RESULT_SUCCESS) { + dbg("[SIM DATA] exist EFELP/PL(0x2F05)"); + __imc_sim_read_binary(co, resp_cb_data); + } else { + tcore_sim_get_type(co, &card_type); + if (TEL_SIM_CARD_TYPE_GSM == card_type) { + ImcSimMetaInfo file_meta_new = {0,}; + + dbg("[SIM DATA]SIM_EF_ELP(2F05) access fail. Request SIM_EF_LP(0x6F05) info"); + /* The ME requests the Language Preference (EFLP) if EFELP is not available */ + file_meta_new.file_id = TEL_SIM_EF_LP; + file_meta_new.file_result = TEL_SIM_RESULT_FAILURE; + file_meta_new.req_command = TCORE_COMMAND_SIM_GET_LANGUAGE; + + memcpy(resp_cb_data->data, &file_meta_new, sizeof(ImcSimMetaInfo)); + + __imc_sim_get_response(co, resp_cb_data); + } else if (TEL_SIM_CARD_TYPE_USIM == card_type) { + dbg(" [SIM DATA]fail to get Language information in USIM(EF-LI(6F05),EF-PL(2F05))"); + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)sim_result, &file_meta->files.data, resp_cb_data->cb_data); + return; + } + } + break; + + case TEL_SIM_EF_LP: + if (sim_result == TEL_SIM_RESULT_SUCCESS) { + dbg("[SIM DATA] exist EFLP/LI(0x6F05)"); + __imc_sim_read_binary(co, resp_cb_data); + } else { + tcore_sim_get_type(co, &card_type); + dbg("[SIM DATA]SIM_EF_LP/LI(6F05) access fail. Current CardType[%d]", card_type); + if (TEL_SIM_CARD_TYPE_GSM == card_type) { + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)sim_result, &file_meta->files.data, resp_cb_data->cb_data); + return; + } + /* if EFLI is not present, then the language selection shall be as defined in EFPL at the MF level */ + else if (TEL_SIM_CARD_TYPE_USIM == card_type) { + ImcSimMetaInfo file_meta_new = {0,}; + + dbg("[SIM DATA] try USIM EFPL(0x2F05)"); + file_meta_new.file_id = TEL_SIM_EF_ELP; + file_meta_new.file_result = TEL_SIM_RESULT_FAILURE; + file_meta_new.req_command = TCORE_COMMAND_SIM_GET_LANGUAGE; + + memcpy(resp_cb_data->data, &file_meta_new, sizeof(ImcSimMetaInfo)); + + __imc_sim_get_response(co, resp_cb_data); + } + } + break; + + case TEL_SIM_EF_USIM_PL: + if (sim_result == TEL_SIM_RESULT_SUCCESS) { + dbg("[SIM DATA] exist EFELP/PL(0x2F05)"); + __imc_sim_read_binary(co, resp_cb_data); + } else { + /* EFELIand EFPL not present, so set language count as zero and select ECC */ + dbg( + " [SIM DATA]SIM_EF_USIM_PL(2A05) access fail. Request SIM_EF_ECC(0x6FB7) info"); + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)sim_result, &file_meta->files.data, resp_cb_data->cb_data); + return; + } + break; + + case TEL_SIM_EF_ECC: + tcore_sim_get_type(co, &card_type); + if (TEL_SIM_CARD_TYPE_GSM == card_type) { + __imc_sim_read_binary(co, resp_cb_data); + } else if (TEL_SIM_CARD_TYPE_USIM == card_type) { + if (file_meta->rec_count > TEL_SIM_ECC_LIST_MAX) { + file_meta->rec_count = TEL_SIM_ECC_LIST_MAX; + } + file_meta->current_index++; + __imc_sim_read_record(co, resp_cb_data); + } + break; + + case TEL_SIM_EF_ICCID: + case TEL_SIM_EF_IMSI: + case TEL_SIM_EF_SST: + case TEL_SIM_EF_SPN: + case TEL_SIM_EF_SPDI: + case TEL_SIM_EF_CPHS_CALL_FORWARD_FLAGS: + case TEL_SIM_EF_CPHS_VOICE_MSG_WAITING: + case TEL_SIM_EF_CPHS_OPERATOR_NAME_STRING: + case TEL_SIM_EF_CPHS_OPERATOR_NAME_SHORT_FORM_STRING: + case TEL_SIM_EF_CPHS_DYNAMICFLAGS: + case TEL_SIM_EF_CPHS_DYNAMIC2FLAG: + case TEL_SIM_EF_CPHS_CUSTOMER_SERVICE_PROFILE: + case TEL_SIM_EF_CPHS_CUSTOMER_SERVICE_PROFILE_LINE2: + __imc_sim_read_binary(co, resp_cb_data); + break; + + case TEL_SIM_EF_CPHS_CPHS_INFO: + if (sim_result == TEL_SIM_RESULT_SUCCESS) { + tcore_sim_set_cphs_status(co, TRUE); + __imc_sim_read_binary(co, resp_cb_data); + } else { + tcore_sim_set_cphs_status(co, FALSE); + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)sim_result, &file_meta->files.data, resp_cb_data->cb_data); + } + break; + + + case TEL_SIM_EF_USIM_CFIS: + if (file_meta->rec_count > TEL_SIM_CALL_FORWARDING_TYPE_MAX) { + file_meta->rec_count = TEL_SIM_CALL_FORWARDING_TYPE_MAX; + } + file_meta->current_index++; + __imc_sim_read_record(co, resp_cb_data); + break; + + case TEL_SIM_EF_MSISDN: + file_meta->files.data.msisdn_list.list = + tcore_malloc0(sizeof(TelSimSubscriberInfo) * file_meta->rec_count); + + case TEL_SIM_EF_OPL: + case TEL_SIM_EF_PNN: + case TEL_SIM_EF_USIM_MWIS: + case TEL_SIM_EF_USIM_MBI: + case TEL_SIM_EF_MBDN: + case TEL_SIM_EF_CPHS_MAILBOX_NUMBERS: + case TEL_SIM_EF_CPHS_INFORMATION_NUMBERS: + file_meta->current_index++; + __imc_sim_read_record(co, resp_cb_data); + break; + + case TEL_SIM_EF_SMSP: + { + ImcSimPrivateInfo *priv_info = NULL; + + priv_info = tcore_sim_ref_userdata(co); + + dbg("SMSP info set to tcore : count:[%d], rec_len:[%d]",file_meta->rec_count, file_meta->rec_length); + priv_info->smsp_count = file_meta->rec_count; + priv_info->smsp_rec_len = file_meta->rec_length; + break; + } + + default: + dbg("error - File id for get file info [0x%x]", file_meta->file_id); + break; + } + return; +} + +static void __on_response_imc_sim_update_file(TcorePending *p, guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *resp = data; + CoreObject *co_sim = NULL; + GSList *tokens = NULL; + TelSimResult sim_result = TEL_SIM_RESULT_CARD_ERROR; + const char *line; + ImcRespCbData *resp_cb_data = (ImcRespCbData *) user_data; + ImcSimMetaInfo *file_meta = (ImcSimMetaInfo *)IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data); + + dbg("Entry"); + + co_sim = tcore_pending_ref_core_object(p); + + dbg("file_id:[0x%x]", file_meta->file_id); + + if (resp->success > 0) { + int sw1 = 0; + int sw2 = 0; + dbg("RESPONSE OK"); + if (resp->lines) { + line = (const char *)resp->lines->data; + tokens = tcore_at_tok_new(line); + if (g_slist_length(tokens) != 2) { + err("Invalid message"); + goto OUT; + } + sw1 = atoi(g_slist_nth_data(tokens, 0)); + sw2 = atoi(g_slist_nth_data(tokens, 1)); + } + + if ((sw1 == 0x90 && sw2 == 0x00) || sw1 == 0x91) { + sim_result = TEL_SIM_RESULT_SUCCESS; + } else { + sim_result = __imc_sim_decode_status_word(sw1, sw2); + } + } else { + err("RESPONSE NOK"); + sim_result = TEL_SIM_RESULT_FAILURE; + } +OUT: + /* Send Response */ + if (resp_cb_data->cb) + resp_cb_data->cb(co_sim, (gint)sim_result, NULL, resp_cb_data->cb_data); + + tcore_at_tok_free(tokens); + dbg("Exit"); +} + +static void __on_response_imc_sim_read_data(TcorePending *p, guint data_len, + const void *data, void *user_data) +{ + const TcoreAtResponse *resp = data; + CoreObject *co = NULL; + GSList *tokens = NULL; + TelSimResult sim_result; + gboolean dr = FALSE; + const char *line = NULL; + char *res = NULL; + char *tmp = NULL; + int res_len; + int sw1 = 0; + int sw2 = 0; + TelSimCardType card_type = TEL_SIM_CARD_TYPE_UNKNOWN; + ImcRespCbData *resp_cb_data = (ImcRespCbData *) user_data; + ImcSimMetaInfo *file_meta = (ImcSimMetaInfo *)IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data); + + dbg("Entry"); + + co = tcore_pending_ref_core_object(p); + + if (resp->success > 0) { + dbg("RESPONSE OK"); + if (resp->lines) { + line = (const char *)resp->lines->data; + tokens = tcore_at_tok_new(line); + if (g_slist_length(tokens) != 3) { + err("Invalid message"); + tcore_at_tok_free(tokens); + return; + } + } + sw1 = atoi(g_slist_nth_data(tokens, 0)); + sw2 = atoi(g_slist_nth_data(tokens, 1)); + res = g_slist_nth_data(tokens, 2); + + tmp = tcore_at_tok_extract(res); + tcore_util_hexstring_to_bytes(tmp, &res, (guint *)&res_len); + dbg("Response: [%s] Response length: [%d]", res, res_len); + + if ((sw1 == 0x90 && sw2 == 0x00) || sw1 == 0x91) { + sim_result = TEL_SIM_RESULT_SUCCESS; + file_meta->files.result = sim_result; + + dbg("File ID: [0x%x]", file_meta->file_id); + switch (file_meta->file_id) { + case TEL_SIM_EF_IMSI: { + dbg("Data: [%s]", res); + dr = tcore_sim_decode_imsi((unsigned char *)res, res_len, &file_meta->imsi); + if (dr == FALSE) { + err("IMSI decoding failed"); + } else { + __imc_sim_set_identity(co, &file_meta->imsi); + + /* Update IMSI */ + tcore_sim_set_imsi(co, &file_meta->imsi); + } + } + break; + + case TEL_SIM_EF_ICCID: { + dr = tcore_sim_decode_iccid((unsigned char *)res, res_len, + file_meta->files.data.iccid); + } + break; + + case TEL_SIM_EF_ELP: /* 2G EF - 2 bytes decoding */ + case TEL_SIM_EF_USIM_LI: /* 3G EF - 2 bytes decoding */ + case TEL_SIM_EF_USIM_PL: /* 3G EF - same as EFELP, so 2 byte decoding */ + case TEL_SIM_EF_LP: /* 1 byte encoding */ + { + tcore_sim_get_type(co, &card_type); + if ((TEL_SIM_CARD_TYPE_GSM == card_type) + && (file_meta->file_id == TEL_SIM_EF_LP)) { + /* + * 2G LP(0x6F05) has 1 byte for each language + */ + dr = tcore_sim_decode_lp((unsigned char *)res, res_len, &file_meta->files.data.language); + } else { + /* + * 3G LI(0x6F05)/PL(0x2F05), + * 2G ELP(0x2F05) has 2 bytes for each language + */ + dr = tcore_sim_decode_li((unsigned char *)res, res_len, + file_meta->file_id, &file_meta->files.data.language); + } + } + break; + + case TEL_SIM_EF_SPN: + dr = tcore_sim_decode_spn((unsigned char *)res, res_len, &file_meta->files.data.spn); + break; + + case TEL_SIM_EF_SPDI: + dr = tcore_sim_decode_spdi((unsigned char *)res, res_len, &file_meta->files.data.spdi); + break; + + case TEL_SIM_EF_SST: + { + TelSimServiceTable *svct = NULL; + + svct = g_try_new0(TelSimServiceTable, 1); + tcore_sim_get_type(co, &card_type); + svct->sim_type = card_type; + if (TEL_SIM_CARD_TYPE_GSM == card_type) { + dr = tcore_sim_decode_sst((unsigned char *)res, res_len, svct->table.sst_service); + } else if (TEL_SIM_CARD_TYPE_USIM == card_type) { + dr = tcore_sim_decode_ust((unsigned char *)res, res_len, svct->table.ust_service); + } else { + err("Not handled card_type[%d]", card_type); + } + + if (dr == FALSE) { + err("SST/UST decoding failed"); + } else { + tcore_sim_set_service_table(co, svct); + } + + /* Free memory */ + g_free(svct); + } + break; + + case TEL_SIM_EF_ECC: + { + tcore_sim_get_type(co, &card_type); + if (TEL_SIM_CARD_TYPE_GSM == card_type) { + dr = tcore_sim_decode_ecc((unsigned char *)res, res_len, &file_meta->files.data.ecc); + } else if (TEL_SIM_CARD_TYPE_USIM == card_type) { + TelSimEcc *ecc = NULL; + + ecc = g_try_new0(TelSimEcc, 1); + dbg("Index [%d]", file_meta->current_index); + + dr = tcore_sim_decode_uecc((unsigned char *)res, res_len, ecc); + if (dr == TRUE) { + memcpy(&file_meta->files.data.ecc.list[file_meta->files.data.ecc.count], ecc, sizeof(TelSimEcc)); + file_meta->files.data.ecc.count++; + } + + /* Free memory */ + g_free(ecc); + } else { + dbg("Unknown/Unsupported SIM card Type: [%d]", card_type); + } + } + break; + + case TEL_SIM_EF_MSISDN: + { + TelSimSubscriberInfo *msisdn = NULL; + + dbg("Index [%d]", file_meta->current_index); + msisdn = tcore_malloc0(sizeof(TelSimSubscriberInfo)); + dr = tcore_sim_decode_msisdn((unsigned char *)res, res_len, msisdn); + if (dr == TRUE) { + memcpy(&file_meta->files.data.msisdn_list.list[file_meta->files.data.msisdn_list.count], + msisdn, sizeof(TelSimSubscriberInfo)); + + file_meta->files.data.msisdn_list.count++; + } + + /* Free memory */ + dbg("Freeing resources"); + tcore_free(msisdn); + } + break; + + case TEL_SIM_EF_OPL: + { + TelSimOpl *opl = NULL; + + dbg("decode w/ index [%d]", file_meta->current_index); + opl = g_try_new0(TelSimOpl, 1); + + dr = tcore_sim_decode_opl((unsigned char *)res, res_len, opl); + if (dr == TRUE) { + memcpy(&file_meta->files.data.opl.list[file_meta->files.data.opl.opl_count], + opl, sizeof(TelSimOpl)); + + file_meta->files.data.opl.opl_count++; + } + + /* Free memory */ + g_free(opl); + } + break; + + case TEL_SIM_EF_PNN: + { + TelSimPnn *pnn = NULL; + + dbg("decode w/ index [%d]", file_meta->current_index); + pnn = g_try_new0(TelSimPnn, 1); + + dr = tcore_sim_decode_pnn((unsigned char *)res, res_len, pnn); + if (dr == TRUE) { + memcpy(&file_meta->files.data.pnn.list[file_meta->files.data.pnn.pnn_count], + pnn, sizeof(TelSimPnn)); + + file_meta->files.data.pnn.pnn_count++; + } + + /* Free memory */ + g_free(pnn); + } + break; + + case TEL_SIM_EF_OPLMN_ACT: + /*dr = tcore_sim_decode_oplmnwact(&file_meta->files.data.opwa, + (unsigned char *)res, res_len);*/ + break; + + case TEL_SIM_EF_CPHS_CUSTOMER_SERVICE_PROFILE: + /*dr = tcore_sim_decode_csp(&po->p_cphs->csp, + p_data->response, p_data->response_len);*/ + break; + + case TEL_SIM_EF_USIM_MBI: /* linear type */ + { + TelSimMbi *mbi = NULL; + + mbi = g_try_new0(TelSimMbi, 1); + dr = tcore_sim_decode_mbi((unsigned char *)res, res_len, mbi); + if (dr == TRUE) { + memcpy(&file_meta->mbi_list.list[file_meta->mbi_list.count], + mbi, sizeof(TelSimMbi)); + file_meta->mbi_list.count++; + + dbg("mbi count[%d]", file_meta->mbi_list.count); + } + + /* Free memory */ + g_free(mbi); + } + break; + + case TEL_SIM_EF_CPHS_MAILBOX_NUMBERS: /* linear type */ + case TEL_SIM_EF_MBDN: /* linear type */ + dr = tcore_sim_decode_xdn((unsigned char *)res, res_len, + file_meta->mb_list[file_meta->current_index-1].alpha_id, + file_meta->mb_list[file_meta->current_index-1].number); + file_meta->mb_list[file_meta->current_index-1].alpha_id_len = strlen(file_meta->mb_list[file_meta->current_index-1].alpha_id); + file_meta->mb_list[file_meta->current_index-1].profile_id = file_meta->current_index; + break; + + case TEL_SIM_EF_CPHS_VOICE_MSG_WAITING: /* transparent type */ + dr = tcore_sim_decode_vmwf((unsigned char *)res, res_len, file_meta->files.data.mw.mw); + break; + + case TEL_SIM_EF_USIM_MWIS: { /* linear type */ + TelSimMwis *mw = NULL; + + mw = g_try_new0(TelSimMwis, 1); + + dr = tcore_sim_decode_mwis((unsigned char *)res, res_len, mw); + if (dr == TRUE) { + guint count = file_meta->files.data.mw.profile_count; + + memcpy(&file_meta->files.data.mw.mw[count], mw, sizeof(TelSimMwis)); + + /** + * The Profile Identity shall be between 1 and 4 as defined + * in TS 23.097 for MSP + */ + file_meta->files.data.mw.mw[count].profile_id = count+1; + + file_meta->files.data.mw.profile_count++; + } + + /* Free memory */ + g_free(mw); + } + break; + + case TEL_SIM_EF_CPHS_CALL_FORWARD_FLAGS: /* transparent type */ + dr = tcore_sim_decode_cff((unsigned char *)res, res_len, file_meta->files.data.mw.mw); + break; + + case TEL_SIM_EF_USIM_CFIS: /* linear type */ + { + TelSimCfis *cf = NULL; + + cf = g_try_new0(TelSimCfis, 1); + dr = tcore_sim_decode_cfis((unsigned char *)res, res_len, cf); + if (dr == TRUE) { + memcpy(&file_meta->files.data.cf.cf[file_meta->files.data.cf.profile_count], + cf, sizeof(TelSimCfis)); + file_meta->files.data.cf.profile_count++; + } + + /* Free memory */ + g_free(cf); + } + break; + + case TEL_SIM_EF_CPHS_SERVICE_STRING_TABLE: + dbg("not handled - TEL_SIM_EF_CPHS_SERVICE_STRING_TABLE "); + break; + + case TEL_SIM_EF_CPHS_OPERATOR_NAME_STRING: + file_meta->files.data.cphs_net.full_name = tcore_malloc0(TEL_SIM_CPHS_OPERATOR_NAME_LEN_MAX+1); + dr = tcore_sim_decode_ons((unsigned char *)res, res_len, + (unsigned char*)file_meta->files.data.cphs_net.full_name); + dbg("file_meta->files.result[%d],file_meta->files.data.cphs_net.full_name[%s]", + file_meta->files.result, file_meta->files.data.cphs_net.full_name); + break; + + case TEL_SIM_EF_CPHS_DYNAMICFLAGS: + /*dr = tcore_sim_decode_dynamic_flag(&po->p_cphs->dflagsinfo, + p_data->response, p_data->response_len);*/ + break; + + case TEL_SIM_EF_CPHS_DYNAMIC2FLAG: + /*dr = tcore_sim_decode_dynamic2_flag(&po->p_cphs->d2flagsinfo, p_data->response, + p_data->response_len);*/ + break; + + case TEL_SIM_EF_CPHS_CPHS_INFO: + /*dr = tcore_sim_decode_cphs_info(&file_meta->files.data.cphs, + (unsigned char *)res, res_len);*/ + break; + + case TEL_SIM_EF_CPHS_OPERATOR_NAME_SHORT_FORM_STRING: + file_meta->files.data.cphs_net.short_name = tcore_malloc0(TEL_SIM_CPHS_OPERATOR_NAME_SHORT_FORM_LEN_MAX+1); + dr = tcore_sim_decode_short_ons((unsigned char *)res, res_len, + (unsigned char*)file_meta->files.data.cphs_net.short_name); + dbg("file_meta->files.result[%d],file_meta->files.data.cphs_net.short_name[%s]", + file_meta->files.result, file_meta->files.data.cphs_net.short_name); + break; + + case TEL_SIM_EF_CPHS_INFORMATION_NUMBERS: + /*dr = tcore_sim_decode_information_number(&po->p_cphs->infn, p_data->response, p_data->response_len);*/ + break; + + default: + dbg("File Decoding Failed - not handled File[0x%x]", file_meta->file_id); + dr = 0; + break; + } + } else { + sim_result = __imc_sim_decode_status_word(sw1, sw2); + file_meta->files.result = sim_result; + } + + /* Free memory */ + g_free(tmp); + g_free(res); + + /* Free tokens */ + tcore_at_tok_free(tokens); + } else { + err("RESPONSE NOK"); + dbg("Error - File ID: [0x%x]", file_meta->file_id); + sim_result = TEL_SIM_RESULT_FAILURE; + } + + /* Get File data */ + __imc_sim_next_from_read_binary(tcore_pending_ref_core_object(p), resp_cb_data, sim_result, dr); + + dbg("Exit"); +} + +static void __on_response_imc_sim_get_response(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *resp = data; + CoreObject *co = NULL; + TelSimResult sim_result; + GSList *tokens = NULL; + const char *line = NULL; + int sw1 = 0; + int sw2 = 0; + ImcRespCbData *resp_cb_data = (ImcRespCbData *)user_data; + ImcSimMetaInfo *file_meta = + (ImcSimMetaInfo *)IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data); + + dbg("SIM Response - SIM File info: [+CRSM]"); + + co = tcore_pending_ref_core_object(p); + + if (resp->success > 0) { + dbg("RESPONSE OK"); + if (resp->lines) { + line = (const char *)resp->lines->data; + tokens = tcore_at_tok_new(line); + if (g_slist_length(tokens) < 2) { + err("Invalid message"); + tcore_at_tok_free(tokens); + return; + } + } + sw1 = atoi(g_slist_nth_data(tokens, 0)); + sw2 = atoi(g_slist_nth_data(tokens, 1)); + + /*1. SIM access success case*/ + if ((sw1 == 0x90 && sw2 == 0x00) || sw1 == 0x91) { + unsigned char tag_len = 0; + unsigned short record_len = 0; + char num_of_records = 0; + unsigned char file_id_len = 0; + unsigned short file_id = 0; + unsigned short file_size = 0; + unsigned short file_type = 0; + unsigned short arr_file_id = 0; + int arr_file_id_rec_num = 0; + TelSimCardType card_type = TEL_SIM_CARD_TYPE_UNKNOWN; + + /* handling only last 3 bits */ + unsigned char file_type_tag = 0x07; + unsigned char *ptr_data; + + char *hexData; + char *tmp; + char *record_data = NULL; + guint record_data_len; + hexData = g_slist_nth_data(tokens, 2); + dbg("hexData: %s", hexData); + dbg("hexData: %s", hexData + 1); + + tmp = tcore_at_tok_extract(hexData); + tcore_util_hexstring_to_bytes(tmp, &record_data, &record_data_len); + tcore_util_hex_dump(" ", record_data_len, record_data); + g_free(tmp); + + ptr_data = (unsigned char *)record_data; + tcore_sim_get_type(co, &card_type); + if (TEL_SIM_CARD_TYPE_USIM == card_type) { + /* + ETSI TS 102 221 v7.9.0 + - Response Data + '62' FCP template tag + - Response for an EF + '82' M File Descriptor + '83' M File Identifier + 'A5' O Proprietary information + '8A' M Life Cycle Status Integer + '8B', '8C' or 'AB' C1 Security attributes + '80' M File size + '81' O Total file size + '88' O Short File Identifier (SFI) + */ + + /* rsim.res_len has complete data length received */ + + /* FCP template tag - File Control Parameters tag*/ + if (*ptr_data == 0x62) { + /* parse complete FCP tag*/ + /* increment to next byte */ + ptr_data++; + tag_len = *ptr_data++; + dbg("tag_len: %02x", tag_len); + /* FCP file descriptor - file type, accessibility, DF, ADF etc*/ + if (*ptr_data == 0x82) { + /* increment to next byte */ + ptr_data++; + /* 2 or 5 value*/ + ptr_data++; + /* consider only last 3 bits*/ + dbg("file_type_tag: %02x", file_type_tag); + file_type_tag = file_type_tag & (*ptr_data); + dbg("file_type_tag: %02x", file_type_tag); + + switch (file_type_tag) { + /* increment to next byte */ + // ptr_data++; + case 0x1: + dbg("Getting FileType: [Transparent file type]"); + file_type = IMC_SIM_FILE_TYPE_TRANSPARENT; + + /* increment to next byte */ + ptr_data++; + /* increment to next byte */ + ptr_data++; + break; + + case 0x2: + dbg("Getting FileType: [Linear fixed file type]"); + /* increment to next byte */ + ptr_data++; + /* data coding byte - value 21 */ + ptr_data++; + /* 2bytes */ + memcpy(&record_len, ptr_data, 2); + /* swap bytes */ + IMC_SWAP_BYTES_16(record_len); + ptr_data = ptr_data + 2; + num_of_records = *ptr_data++; + /* Data lossy conversation from enum (int) to unsigned char */ + file_type = IMC_SIM_FILE_TYPE_LINEAR_FIXED; + break; + + case 0x6: + dbg("Cyclic fixed file type"); + /* increment to next byte */ + ptr_data++; + /* data coding byte - value 21 */ + ptr_data++; + /* 2bytes */ + memcpy(&record_len, ptr_data, 2); + /* swap bytes */ + IMC_SWAP_BYTES_16(record_len); + ptr_data = ptr_data + 2; + num_of_records = *ptr_data++; + file_type = IMC_SIM_FILE_TYPE_CYCLIC; + break; + + default: + dbg("not handled file type [0x%x]", *ptr_data); + break; + } + } else { + dbg("INVALID FCP received - DEbug!"); + tcore_at_tok_free(tokens); + g_free(record_data); + return; + } + + /*File identifier - 0x84,0x85,0x86 etc are currently ignored and not handled */ + if (*ptr_data == 0x83) { + /* increment to next byte */ + ptr_data++; + file_id_len = *ptr_data++; + dbg("file_id_len: %02x", file_id_len); + + memcpy(&file_id, ptr_data, file_id_len); + dbg("file_id: %x", file_id); + + /* swap bytes */ + IMC_SWAP_BYTES_16(file_id); + dbg("file_id: %x", file_id); + + ptr_data = ptr_data + 2; + dbg("Getting FileID=[0x%x]", file_id); + } else { + dbg("INVALID FCP received - DEbug!"); + tcore_at_tok_free(tokens); + g_free(record_data); + return; + } + + /* proprietary information */ + if (*ptr_data == 0xA5) { + unsigned short prop_len; + /* increment to next byte */ + ptr_data++; + + /* length */ + prop_len = *ptr_data; + dbg("prop_len: %02x", prop_len); + + /* skip data */ + ptr_data = ptr_data + prop_len + 1; + } else { + dbg("INVALID FCP received - DEbug!"); + } + + /* life cycle status integer [8A][length:0x01][status]*/ + /* + status info b8~b1 + 00000000 : No information given + 00000001 : creation state + 00000011 : initialization state + 000001-1 : operation state -activated + 000001-0 : operation state -deactivated + 000011-- : Termination state + b8~b5 !=0, b4~b1=X : Proprietary + Any other value : RFU + */ + if (*ptr_data == 0x8A) { + /* increment to next byte */ + ptr_data++; + /* length - value 1 */ + ptr_data++; + + switch (*ptr_data) { + case 0x04: + case 0x06: + dbg(" operation state -deactivated"); + ptr_data++; + break; + + case 0x05: + case 0x07: + dbg(" operation state -activated"); + ptr_data++; + break; + + default: + dbg(" DEBUG! LIFE CYCLE STATUS =[0x%x]", *ptr_data); + ptr_data++; + break; + } + } + + /* related to security attributes : currently not handled*/ + if (*ptr_data == 0x86 || *ptr_data == 0x8B || *ptr_data == 0x8C || *ptr_data == 0xAB) { + /* increment to next byte */ + ptr_data++; + /* if tag length is 3 */ + if (*ptr_data == 0x03) { + /* increment to next byte */ + ptr_data++; + /* EFARR file id */ + memcpy(&arr_file_id, ptr_data, 2); + /* swap byes */ + IMC_SWAP_BYTES_16(arr_file_id); + ptr_data = ptr_data + 2; + arr_file_id_rec_num = *ptr_data++; + dbg("arr_file_id_rec_num:[%d]", arr_file_id_rec_num); + } else { + /* if tag length is not 3 */ + /* ignoring bytes */ + // ptr_data = ptr_data + 4; + dbg("Useless security attributes, so jump to next tag"); + ptr_data = ptr_data + (*ptr_data + 1); + } + } else { + dbg("INVALID FCP received[0x%x] - DEbug!", *ptr_data); + tcore_at_tok_free(tokens); + g_free(record_data); + return; + } + + dbg("Current ptr_data value is [%x]", *ptr_data); + + /* file size excluding structural info*/ + if (*ptr_data == 0x80) { + /* for EF file size is body of file and for Linear or cyclic it is + * number of recXsizeof(one record) + */ + /* increment to next byte */ + ptr_data++; + /* length is 1 byte - value is 2 bytes or more */ + ptr_data++; + memcpy(&file_size, ptr_data, 2); + /* swap bytes */ + IMC_SWAP_BYTES_16(file_size); + ptr_data = ptr_data + 2; + } else { + dbg("INVALID FCP received - DEbug!"); + tcore_at_tok_free(tokens); + g_free(record_data); + return; + } + + /* total file size including structural info*/ + if (*ptr_data == 0x81) { + int len; + /* increment to next byte */ + ptr_data++; + /* length */ + len = *ptr_data; + dbg("len:[%d]", len); + /* ignored bytes */ + ptr_data = ptr_data + 3; + } else { + dbg("INVALID FCP received - DEbug!"); + /* 0x81 is optional tag?? check out! so do not return -1 from here! */ + } + /*short file identifier ignored*/ + if (*ptr_data == 0x88) { + dbg("0x88: Do Nothing"); + /*DO NOTHING*/ + } + } else { + dbg("INVALID FCP received - DEbug!"); + tcore_at_tok_free(tokens); + g_free(record_data); + return; + } + } else if (TEL_SIM_CARD_TYPE_GSM == card_type) { + unsigned char gsm_specific_file_data_len = 0; + /* ignore RFU byte1 and byte2 */ + ptr_data++; + ptr_data++; + /* file size */ + // file_size = p_info->response_len; + memcpy(&file_size, ptr_data, 2); + /* swap bytes */ + IMC_SWAP_BYTES_16(file_size); + /* parsed file size */ + ptr_data = ptr_data + 2; + /* file id */ + memcpy(&file_id, ptr_data, 2); + IMC_SWAP_BYTES_16(file_id); + dbg("FILE id --> [%x]", file_id); + ptr_data = ptr_data + 2; + /* save file type - transparent, linear fixed or cyclic */ + file_type_tag = (*(ptr_data + 7)); + + switch (*ptr_data) { + case 0x0: + /* RFU file type */ + dbg("RFU file type- not handled - Debug!"); + break; + + case 0x1: + /* MF file type */ + dbg("MF file type - not handled - Debug!"); + break; + + case 0x2: + /* DF file type */ + dbg("DF file type - not handled - Debug!"); + break; + + case 0x4: + /* EF file type */ + dbg("EF file type [%d] ", file_type_tag); + /* increment to next byte */ + ptr_data++; + + if (file_type_tag == 0x00 || file_type_tag == 0x01) { + /* increament to next byte as this byte is RFU */ + ptr_data++; + file_type = + (file_type_tag == 0x00) ? IMC_SIM_FILE_TYPE_TRANSPARENT : IMC_SIM_FILE_TYPE_LINEAR_FIXED; + } else { + /* increment to next byte */ + ptr_data++; + /* For a cyclic EF all bits except bit 7 are RFU; b7=1 indicates that */ + /* the INCREASE command is allowed on the selected cyclic file. */ + file_type = IMC_SIM_FILE_TYPE_CYCLIC; + } + /* bytes 9 to 11 give SIM file access conditions */ + ptr_data++; + /* byte 10 has one nibble that is RF U and another for INCREASE which is not used currently */ + ptr_data++; + /* byte 11 is invalidate and rehabilate nibbles */ + ptr_data++; + /* byte 12 - file status */ + ptr_data++; + /* byte 13 - GSM specific data */ + gsm_specific_file_data_len = *ptr_data; + dbg("gsm_specific_file_data_len:[%d]", gsm_specific_file_data_len); + ptr_data++; + /* byte 14 - structure of EF - transparent or linear or cyclic , already saved above */ + ptr_data++; + /* byte 15 - length of record for linear and cyclic , for transparent it is set to 0x00. */ + record_len = *ptr_data; + dbg("record length[%d], file size[%d]", record_len, file_size); + if (record_len != 0) + num_of_records = (file_size / record_len); + + dbg("Number of records [%d]", num_of_records); + break; + + default: + dbg("not handled file type"); + break; + } + } else { + err("Unknown Card Type - [%d]", card_type); + } + + dbg("req ef[0x%x] resp ef[0x%x] size[%ld] Type[0x%x] NumOfRecords[%ld] RecordLen[%ld]", + file_meta->file_id, file_id, file_size, file_type, num_of_records, record_len); + + file_meta->file_type = file_type; + file_meta->data_size = file_size; + file_meta->rec_length = record_len; + file_meta->rec_count = num_of_records; + file_meta->current_index = 0; /* reset for new record type EF */ + sim_result = TEL_SIM_RESULT_SUCCESS; + g_free(record_data); + } else { + /*2. SIM access fail case*/ + err("Failed to get ef[0x%x] (file_meta->file_id) ", file_meta->file_id); + sim_result = __imc_sim_decode_status_word(sw1, sw2); + } + + tcore_at_tok_free(tokens); + } else { + err("RESPONSE NOK"); + err("Failed to get ef[0x%x] (file_meta->file_id) ", file_meta->file_id); + sim_result = TEL_SIM_RESULT_FAILURE; + } + + dbg("Calling __imc_sim_next_from_get_response"); + __imc_sim_next_from_get_response(co, resp_cb_data, sim_result); + dbg("Exit"); +} + +static TelReturn __imc_sim_update_file(CoreObject *co, ImcRespCbData *resp_cb_data, int cmd, TelSimFileId ef, + int p1, int p2, int p3, char *encoded_data) +{ + char *cmd_str = NULL; + TelReturn ret = TEL_RETURN_FAILURE; + ImcSimMetaInfo *file_meta = (ImcSimMetaInfo *)IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data); + + dbg("Entry File-id:[0x%02x]", file_meta->file_id); + + cmd_str = g_strdup_printf("AT+CRSM=%d,%d,%d,%d,%d,\"%s\"", cmd, ef, p1, p2, p3, encoded_data); + + ret = tcore_at_prepare_and_send_request(co, cmd_str, "+CRSM:", + TCORE_AT_COMMAND_TYPE_SINGLELINE, + TCORE_PENDING_PRIORITY_DEFAULT, NULL, + __on_response_imc_sim_update_file, resp_cb_data, + on_send_imc_request, NULL, 0, NULL, NULL); + + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Update SIM File"); + + tcore_free(encoded_data); + g_free(cmd_str); + + dbg("Exit"); + return ret; +} +static void __imc_sim_read_record(CoreObject *co, ImcRespCbData *resp_cb_data) +{ + gchar *at_cmd = NULL; + int p1 = 0; + int p2 = 0; + int p3 = 0; + ImcSimMetaInfo *file_meta = (ImcSimMetaInfo *)IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data); + TelReturn ret = TEL_RETURN_FAILURE; + + dbg("Entry File-id:[0x%02x]", file_meta->file_id); + + /* According to TS 102 221, values of p1, p2, p3 can be as below: + * 11.1.5 READ RECORD + * P1: Record number + * P2: Mode, see table 11.11 + * Lc: Not present + * Data: Not present + * Le: Number of bytes to be read (P3) + */ + + p1 = (unsigned char) file_meta->current_index; + p2 = (unsigned char) 0x04; /* 0x4 for absolute mode */ + p3 = (unsigned char) file_meta->rec_length; + + at_cmd = g_strdup_printf("AT+CRSM=%d, %d, %d, %d, %d", + IMC_SIM_ACCESS_READ_RECORD, file_meta->file_id, p1, p2, p3); + + ret = tcore_at_prepare_and_send_request(co, at_cmd, "+CRSM:", + TCORE_AT_COMMAND_TYPE_SINGLELINE, + TCORE_PENDING_PRIORITY_DEFAULT, NULL, + __on_response_imc_sim_read_data, resp_cb_data, + on_send_imc_request, NULL, 0, NULL, NULL); + + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Get File Record"); + + dbg("ret:[%d]", ret); + g_free(at_cmd); + + dbg("Exit"); +} + +static void __imc_sim_read_binary(CoreObject *co, ImcRespCbData *resp_cb_data) +{ + gchar *at_cmd = NULL; + int p1 = 0; + int p2 = 0; + int p3 = 0; + int offset = 0; + ImcSimMetaInfo *file_meta = (ImcSimMetaInfo *)IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data); + TelReturn ret = TEL_RETURN_FAILURE; + + dbg("Entry File-id:[0x%02x]", file_meta->file_id); + + /* According to TS 102 221, values of P1, P2, P3 can be as below: + * 11.1.3 READ BINARY + * P1: See table 11.10 + * P2: Offset low + * Lc: Not present + * Data: Not present + * Le: Number of bytes to be read (P3) + */ + + p1 = (unsigned char) (offset & 0xFF00) >> 8; + p2 = (unsigned char) offset & 0x00FF; /* offset low */ + p3 = (unsigned char) file_meta->data_size; + + at_cmd = g_strdup_printf("AT+CRSM=%d, %d, %d, %d, %d", + IMC_SIM_ACCESS_READ_BINARY, file_meta->file_id, p1, p2, p3); + + ret = tcore_at_prepare_and_send_request(co, at_cmd, "+CRSM:", + TCORE_AT_COMMAND_TYPE_SINGLELINE, + TCORE_PENDING_PRIORITY_DEFAULT, NULL, + __on_response_imc_sim_read_data, resp_cb_data, + on_send_imc_request, NULL, 0, NULL, NULL); + + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Get File Data"); + + dbg("ret:[%d]", ret); + g_free(at_cmd); + + dbg("Exit"); +} + +static TelReturn __imc_sim_get_response(CoreObject *co, ImcRespCbData *resp_cb_data) +{ + gchar *at_cmd = NULL; + ImcSimMetaInfo *file_meta = + (ImcSimMetaInfo *)IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data); + TelReturn ret = TEL_RETURN_FAILURE; + + dbg("Entry File-id:[0x%02x]", file_meta->file_id); + + at_cmd = g_strdup_printf("AT+CRSM=%d, %d", + IMC_SIM_ACCESS_GET_RESPONSE, file_meta->file_id); + + ret = tcore_at_prepare_and_send_request(co, + at_cmd, "+CRSM:", + TCORE_AT_COMMAND_TYPE_SINGLELINE, + TCORE_PENDING_PRIORITY_DEFAULT, NULL, + __on_response_imc_sim_get_response, resp_cb_data, + on_send_imc_request, NULL, + 0, NULL, NULL); + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Get File Info"); + + g_free(at_cmd); + dbg("Exit"); + return ret; +} + +static void __on_response_imc_sim_get_retry_count(TcorePending *p, guint data_len, + const void *data, void *user_data) +{ + TelSimResult result = TEL_SIM_RESULT_INCORRECT_PASSWORD; + const TcoreAtResponse *at_resp = data; + ImcRespCbData *resp_cb_data = user_data; + CoreObject *co = tcore_pending_ref_core_object(p); + ImcSimCurrSecOp *sec_op = NULL; + GSList *tokens = NULL; + const char *line = NULL; + int lock_type = 0; + int attempts_left = 0; + int time_penalty = 0; + + dbg("Entry"); + + tcore_check_return_assert(co != NULL); + tcore_check_return_assert(resp_cb_data != NULL); + + sec_op = (ImcSimCurrSecOp *)IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data); + + if (at_resp && at_resp->success) { + dbg("Sim Get Retry Count [OK]"); + + if (at_resp->lines) { + line = (const char *)at_resp->lines->data; + tokens = tcore_at_tok_new(line); + if (g_slist_length(tokens) < 3) { + err("Invalid message"); + goto Failure; + } + } + lock_type = atoi(g_slist_nth_data(tokens, 0)); + attempts_left = atoi(g_slist_nth_data(tokens, 1)); + time_penalty = atoi(g_slist_nth_data(tokens, 2)); + + dbg("lock_type = %d, attempts_left = %d, time_penalty = %d", + lock_type, attempts_left, time_penalty); + + switch (*sec_op) { + case IMC_SIM_CURR_SEC_OP_PIN1_VERIFY: + case IMC_SIM_CURR_SEC_OP_PIN2_VERIFY: + { + TelSimSecPinResult verify_pin = {0, }; + + if (*sec_op == IMC_SIM_CURR_SEC_OP_PIN1_VERIFY) + verify_pin.pin_type = TEL_SIM_PIN_TYPE_PIN1; + else if (*sec_op == IMC_SIM_CURR_SEC_OP_PIN2_VERIFY) + verify_pin.pin_type = TEL_SIM_PIN_TYPE_PIN2; + + verify_pin.retry_count = attempts_left; + + if(resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, + &verify_pin, resp_cb_data->cb_data); + break; + } + case IMC_SIM_CURR_SEC_OP_PUK1_VERIFY: + case IMC_SIM_CURR_SEC_OP_PUK2_VERIFY: + { + TelSimSecPukResult verify_puk = {0, }; + + if (*sec_op == IMC_SIM_CURR_SEC_OP_PUK1_VERIFY) + verify_puk.puk_type = TEL_SIM_PUK_TYPE_PUK1; + else if (*sec_op == IMC_SIM_CURR_SEC_OP_PUK2_VERIFY) + verify_puk.puk_type = TEL_SIM_PUK_TYPE_PUK2; + + verify_puk.retry_count = attempts_left; + + if(resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, + &verify_puk, resp_cb_data->cb_data); + break; + } + case IMC_SIM_CURR_SEC_OP_PIN1_CHANGE: + case IMC_SIM_CURR_SEC_OP_PIN2_CHANGE: + { + TelSimSecPinResult change_pin = {0, }; + + if (*sec_op == IMC_SIM_CURR_SEC_OP_PIN1_CHANGE) + change_pin.pin_type = TEL_SIM_PIN_TYPE_PIN1; + else if (*sec_op == IMC_SIM_CURR_SEC_OP_PIN2_CHANGE) + change_pin.pin_type = TEL_SIM_PIN_TYPE_PIN2; + + change_pin.retry_count = attempts_left; + + if(resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, + &change_pin, resp_cb_data->cb_data); + break; + } + case IMC_SIM_CURR_SEC_OP_PIN1_DISABLE: + case IMC_SIM_CURR_SEC_OP_PIN2_DISABLE: + case IMC_SIM_CURR_SEC_OP_FDN_DISABLE: + case IMC_SIM_CURR_SEC_OP_SIM_DISABLE: + case IMC_SIM_CURR_SEC_OP_NET_DISABLE: + case IMC_SIM_CURR_SEC_OP_NS_DISABLE: + case IMC_SIM_CURR_SEC_OP_SP_DISABLE: + case IMC_SIM_CURR_SEC_OP_CP_DISABLE: + { + TelSimFacilityResult disable_facility = {0, }; + int lock_type; + + lock_type = __imc_sim_get_lock_type(*sec_op); + if (lock_type == -1) + goto Failure; + + disable_facility.type = lock_type; + disable_facility.retry_count = attempts_left; + + if(resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, + &disable_facility, resp_cb_data->cb_data); + break; + } + case IMC_SIM_CURR_SEC_OP_PIN1_ENABLE: + case IMC_SIM_CURR_SEC_OP_PIN2_ENABLE: + case IMC_SIM_CURR_SEC_OP_FDN_ENABLE: + case IMC_SIM_CURR_SEC_OP_SIM_ENABLE: + case IMC_SIM_CURR_SEC_OP_NET_ENABLE: + case IMC_SIM_CURR_SEC_OP_NS_ENABLE: + case IMC_SIM_CURR_SEC_OP_SP_ENABLE: + case IMC_SIM_CURR_SEC_OP_CP_ENABLE: + { + TelSimFacilityResult enable_facility = {0, }; + int lock_type; + + lock_type = __imc_sim_get_lock_type(*sec_op); + if (lock_type == -1) + goto Failure; + + enable_facility.type = lock_type; + enable_facility.retry_count = attempts_left; + + if(resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, + &enable_facility, resp_cb_data->cb_data); + break; + } + default: + err("Unhandled sec op [%d]", *sec_op); + break; + } + + tcore_at_tok_free(tokens); + imc_destroy_resp_cb_data(resp_cb_data); + return; + } + err("Sim Get Retry Count [NOK]"); +Failure : + /*TODO - send response for verify pin, puk etc., + * when get_retry_count fails + */ + tcore_at_tok_free(tokens); + imc_destroy_resp_cb_data(resp_cb_data); +} + +static TelReturn __imc_sim_get_retry_count(CoreObject *co, + ImcRespCbData *resp_cb_data) +{ + TelReturn ret = TEL_RETURN_FAILURE; + ImcSimCurrSecOp *sec_op = ( + ImcSimCurrSecOp *)IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data); + int lock_type = 0; + gchar *cmd_str = NULL; + + dbg("Entry"); + + switch (*sec_op) { + case IMC_SIM_CURR_SEC_OP_PIN1_VERIFY: + case IMC_SIM_CURR_SEC_OP_PIN1_CHANGE: + case IMC_SIM_CURR_SEC_OP_PIN1_ENABLE: + case IMC_SIM_CURR_SEC_OP_PIN1_DISABLE: + lock_type = 1; + break; + case IMC_SIM_CURR_SEC_OP_PIN2_VERIFY: + case IMC_SIM_CURR_SEC_OP_PIN2_CHANGE: + case IMC_SIM_CURR_SEC_OP_PIN2_ENABLE: + case IMC_SIM_CURR_SEC_OP_PIN2_DISABLE: + case IMC_SIM_CURR_SEC_OP_FDN_ENABLE: + case IMC_SIM_CURR_SEC_OP_FDN_DISABLE: + lock_type = 2; + break; + case IMC_SIM_CURR_SEC_OP_PUK1_VERIFY: + lock_type = 3; + break; + case IMC_SIM_CURR_SEC_OP_PUK2_VERIFY: + lock_type = 4; + break; + case IMC_SIM_CURR_SEC_OP_NET_ENABLE: + case IMC_SIM_CURR_SEC_OP_NET_DISABLE: + lock_type = 5; + break; + case IMC_SIM_CURR_SEC_OP_NS_ENABLE: + case IMC_SIM_CURR_SEC_OP_NS_DISABLE: + lock_type = 6; + break; + case IMC_SIM_CURR_SEC_OP_SP_ENABLE: + case IMC_SIM_CURR_SEC_OP_SP_DISABLE: + lock_type = 7; + break; + case IMC_SIM_CURR_SEC_OP_CP_ENABLE: + case IMC_SIM_CURR_SEC_OP_CP_DISABLE: + lock_type = 8; + break; + case IMC_SIM_CURR_SEC_OP_ADM_VERIFY: + lock_type = 9; + break; + default: + break; + } + cmd_str = g_strdup_printf("AT+XPINCNT=%d", lock_type); + + ret = tcore_at_prepare_and_send_request(co, cmd_str, NULL, + TCORE_AT_COMMAND_TYPE_SINGLELINE, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + __on_response_imc_sim_get_retry_count, + resp_cb_data, + on_send_imc_request, + NULL, 0, NULL, NULL); + + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Get Retry Count"); + g_free(cmd_str); + return ret; +} + +static TelSimLockType __imc_sim_lock_type(int lock_type) +{ + switch(lock_type) { + case 1 : + return TEL_SIM_LOCK_SC; + case 2 : + return TEL_SIM_LOCK_FD; + case 5 : + return TEL_SIM_LOCK_PN; + case 6 : + return TEL_SIM_LOCK_PU; + case 7 : + return TEL_SIM_LOCK_PP; + case 8 : + return TEL_SIM_LOCK_PC ; + case 9 : + return TEL_SIM_LOCK_PS ; + default : + err("Invalid lock_type [%d]", lock_type); + return -1; + } +} + +static char *__imc_sim_get_fac_from_lock_type(TelSimLockType lock_type, + ImcSimCurrSecOp *sec_op, int flag) +{ + char *fac = NULL; + switch(lock_type) { + case TEL_SIM_LOCK_PS : + fac = "PS"; + if (flag == ENABLE_FLAG) + *sec_op = IMC_SIM_CURR_SEC_OP_SIM_ENABLE; + else if (flag == DISABLE_FLAG) + *sec_op = IMC_SIM_CURR_SEC_OP_SIM_DISABLE; + else + *sec_op = IMC_SIM_CURR_SEC_OP_SIM_STATUS; + break; + case TEL_SIM_LOCK_SC : + fac = "SC"; + if (flag == ENABLE_FLAG) + *sec_op = IMC_SIM_CURR_SEC_OP_PIN1_ENABLE; + else if (flag == DISABLE_FLAG) + *sec_op = IMC_SIM_CURR_SEC_OP_PIN1_DISABLE; + else + *sec_op = IMC_SIM_CURR_SEC_OP_PIN1_STATUS; + break; + case TEL_SIM_LOCK_FD : + fac = "FD"; + if (flag == ENABLE_FLAG) + *sec_op = IMC_SIM_CURR_SEC_OP_FDN_ENABLE; + else if (flag == DISABLE_FLAG) + *sec_op = IMC_SIM_CURR_SEC_OP_FDN_DISABLE; + else + *sec_op = IMC_SIM_CURR_SEC_OP_FDN_STATUS; + break; + case TEL_SIM_LOCK_PN : + fac = "PN"; + if (flag == ENABLE_FLAG) + *sec_op = IMC_SIM_CURR_SEC_OP_NET_ENABLE; + else if (flag == DISABLE_FLAG) + *sec_op = IMC_SIM_CURR_SEC_OP_NET_DISABLE; + else + *sec_op = IMC_SIM_CURR_SEC_OP_NET_STATUS; + break; + case TEL_SIM_LOCK_PU : + fac = "PU"; + if (flag == ENABLE_FLAG) + *sec_op = IMC_SIM_CURR_SEC_OP_NS_ENABLE; + else if (flag == DISABLE_FLAG) + *sec_op = IMC_SIM_CURR_SEC_OP_NS_DISABLE; + else + *sec_op = IMC_SIM_CURR_SEC_OP_NS_STATUS; + break; + case TEL_SIM_LOCK_PP : + fac = "PP"; + if (flag == ENABLE_FLAG) + *sec_op = IMC_SIM_CURR_SEC_OP_SP_ENABLE; + else if (flag == DISABLE_FLAG) + *sec_op = IMC_SIM_CURR_SEC_OP_SP_DISABLE; + else + *sec_op = IMC_SIM_CURR_SEC_OP_SP_STATUS; + break; + case TEL_SIM_LOCK_PC : + fac = "PC"; + if (flag == ENABLE_FLAG) + *sec_op = IMC_SIM_CURR_SEC_OP_CP_ENABLE; + else if (flag == DISABLE_FLAG) + *sec_op = IMC_SIM_CURR_SEC_OP_CP_DISABLE; + else + *sec_op = IMC_SIM_CURR_SEC_OP_CP_STATUS; + break; + default : + err("Unhandled sim lock type [%d]", lock_type); + } + return fac; +} + +static int __imc_sim_get_lock_type(ImcSimCurrSecOp sec_op) +{ + switch(sec_op) { + case IMC_SIM_CURR_SEC_OP_SIM_DISABLE : + case IMC_SIM_CURR_SEC_OP_SIM_ENABLE : + case IMC_SIM_CURR_SEC_OP_SIM_STATUS : + return TEL_SIM_LOCK_PS; + case IMC_SIM_CURR_SEC_OP_PIN1_DISABLE : + case IMC_SIM_CURR_SEC_OP_PIN1_ENABLE : + case IMC_SIM_CURR_SEC_OP_PIN1_STATUS : + return TEL_SIM_LOCK_SC; + case IMC_SIM_CURR_SEC_OP_FDN_DISABLE : + case IMC_SIM_CURR_SEC_OP_FDN_ENABLE : + case IMC_SIM_CURR_SEC_OP_FDN_STATUS : + return TEL_SIM_LOCK_FD; + case IMC_SIM_CURR_SEC_OP_NET_DISABLE : + case IMC_SIM_CURR_SEC_OP_NET_ENABLE : + case IMC_SIM_CURR_SEC_OP_NET_STATUS : + return TEL_SIM_LOCK_PN; + case IMC_SIM_CURR_SEC_OP_NS_DISABLE : + case IMC_SIM_CURR_SEC_OP_NS_ENABLE : + case IMC_SIM_CURR_SEC_OP_NS_STATUS : + return TEL_SIM_LOCK_PU; + case IMC_SIM_CURR_SEC_OP_SP_DISABLE : + case IMC_SIM_CURR_SEC_OP_SP_ENABLE : + case IMC_SIM_CURR_SEC_OP_SP_STATUS : + return TEL_SIM_LOCK_PP; + case IMC_SIM_CURR_SEC_OP_CP_DISABLE : + case IMC_SIM_CURR_SEC_OP_CP_ENABLE : + case IMC_SIM_CURR_SEC_OP_CP_STATUS : + return TEL_SIM_LOCK_PC ; + default : + err("Invalid sec op [%d]", sec_op); + return -1; + } +} + +/* Notifications */ +/* + * Notification: +XSIM: + * + * Possible values of can be + * 0 SIM not present + * 1 PIN verification needed + * 2 PIN verification not needed - Ready + * 3 PIN verified - Ready + * 4 PUK verification needed + * 5 SIM permanently blocked + * 6 SIM Error + * 7 ready for attach (+COPS) + * 8 SIM Technical Problem + * 9 SIM Removed + * 10 SIM Reactivating + * 11 SIM Reactivated + * 12 SIM SMS Caching Completed. (Sent only when SMS caching enabled) + * 99 SIM State Unknown + */ +static gboolean on_notification_imc_sim_status(CoreObject *co, + const void *event_info, void *user_data) +{ + GSList *lines = (GSList *)event_info; + const gchar *line; + + dbg("SIM notification - SIM status: [+XSIM]"); + + if (g_slist_length(lines) != 1) { + err("+XSIM unsolicited message expected to be " + "Single line but received multiple lines"); + return TRUE; + } + + line = (const gchar *) (lines->data); + if (line != NULL) { + GSList *tokens; + guint sim_state; + + /* + * Tokenize + * + * +XSIM: + */ + tokens = tcore_at_tok_new(line); + if (g_slist_length(tokens) == 1) { + /* */ + sim_state = atoi(g_slist_nth_data(tokens, 0)); + + /* Process SIM Status */ + __imc_sim_process_sim_status(co, sim_state); + } else { + err("Invalid message"); + } + + tcore_at_tok_free(tokens); + } + + return TRUE; +} + +/* Hooks */ +static TcoreHookReturn on_hook_imc_modem_power(TcorePlugin *source, + TcoreNotification command, guint data_len, void *data, void *user_data) +{ + CoreObject *co = (CoreObject *)user_data; + + tcore_check_return_value(co != NULL, TCORE_HOOK_RETURN_CONTINUE); + + dbg("Get SIM status"); + (void)__imc_sim_get_sim_status(co, NULL, NULL); + + return TCORE_HOOK_RETURN_CONTINUE; +} + +/* Response Functions */ +static void on_response_imc_sim_req_authentication(TcorePending *p, guint data_len, + const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + GSList *tokens = NULL; + CoreObject *co = tcore_pending_ref_core_object(p); + TelSimAuthenticationResponse auth_resp = {0, }; + TelSimResult sim_result = TEL_SIM_RESULT_FAILURE; + ImcRespCbData *resp_cb_data = user_data; + TelSimAuthenticationType *auth_type = (TelSimAuthenticationType *)IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data); + + dbg("Entry"); + + if (NULL == at_resp) { + err("at_resp is NULL"); + auth_resp.detailed_result = TEL_SIM_AUTH_CANNOT_PERFORM; + goto out; + } + + auth_resp.auth_type = *auth_type; + + if (at_resp->success == TRUE) { + const char *line; + int status; + + dbg("RESPONSE OK"); + if (at_resp->lines != NULL) { + line = at_resp->lines->data; + dbg("Received data: [%s]", line); + } else { + err("at_resp->lines is NULL"); + auth_resp.detailed_result = TEL_SIM_AUTH_CANNOT_PERFORM; + goto out; + } + + tokens = tcore_at_tok_new(line); + if (tokens == NULL) { + err("tokens is NULL"); + auth_resp.detailed_result = TEL_SIM_AUTH_CANNOT_PERFORM; + goto out; + } + + status = atoi(g_slist_nth_data(tokens, 0)); + switch (status) { + case 0: + dbg("Authentications successful"); + auth_resp.detailed_result = TEL_SIM_AUTH_NO_ERROR; + break; + case 1: + err("Synchronize fail"); + auth_resp.detailed_result = TEL_SIM_AUTH_SYNCH_FAILURE; + goto out; + case 2: + err("MAC wrong"); + auth_resp.detailed_result = TEL_SIM_AUTH_MAK_CODE_FAILURE; + goto out; + case 3: + err("Does not support security context"); + auth_resp.detailed_result = TEL_SIM_AUTH_UNSUPPORTED_CONTEXT; + goto out; + default: + err("Other failure"); + auth_resp.detailed_result = TEL_SIM_AUTH_CANNOT_PERFORM; + goto out; + } + + if (auth_resp.auth_type == TEL_SIM_AUTH_GSM) { + char *kc, *sres; + char *convert_kc, *convert_sres; + + kc = g_slist_nth_data(tokens, 1); + if (kc != NULL) { + guint convert_kc_len = 0; + kc = tcore_at_tok_extract(kc); + dbg("Kc: [%s]", kc); + + tcore_util_hexstring_to_bytes(kc, &convert_kc, &convert_kc_len); + if (convert_kc_len && convert_kc_len <= TEL_SIM_AUTH_MAX_RESP_DATA_LEN) { + auth_resp.authentication_key_length = convert_kc_len; + memcpy(&auth_resp.authentication_key, convert_kc, convert_kc_len); + } else { + err("Invalid Kc"); + auth_resp.detailed_result = TEL_SIM_AUTH_CANNOT_PERFORM; + } + g_free(kc); + g_free(convert_kc); + } else { + err("Invalid Kc"); + auth_resp.detailed_result = TEL_SIM_AUTH_CANNOT_PERFORM; + goto out; + } + + sres = g_slist_nth_data(tokens, 2); + if (sres != NULL) { + guint convert_sres_len = 0; + sres = tcore_at_tok_extract(sres); + dbg("SRES: [%s]", sres); + + tcore_util_hexstring_to_bytes(sres, &convert_sres, &convert_sres_len); + if (convert_sres_len && convert_sres_len <= TEL_SIM_AUTH_MAX_RESP_DATA_LEN) { + auth_resp.resp_length = convert_sres_len; + memcpy(&auth_resp.resp_data, convert_sres, convert_sres_len); + } else { + err("Invalid SRES"); + auth_resp.detailed_result = TEL_SIM_AUTH_CANNOT_PERFORM; + } + g_free(sres); + g_free(convert_sres); + } else { + err("Invalid SRES"); + auth_resp.detailed_result = TEL_SIM_AUTH_CANNOT_PERFORM; + goto out; + } + } else if (auth_resp.auth_type == TEL_SIM_AUTH_3G_CTX) { + char *res, *ck, *ik, *kc; + char *convert_res, *convert_ck; + char *convert_ik, *convert_kc; + + res = g_slist_nth_data(tokens, 1); + if (res != NULL) { + guint convert_res_len = 0; + res = tcore_at_tok_extract(res); + dbg("RES/AUTS: [%s]", res); + + tcore_util_hexstring_to_bytes(res, &convert_res, &convert_res_len); + if (convert_res_len && convert_res_len <= TEL_SIM_AUTH_MAX_RESP_DATA_LEN) { + auth_resp.resp_length = convert_res_len; + memcpy(auth_resp.resp_data, convert_res, convert_res_len); + } else { + err("Invalid RES/AUTS"); + auth_resp.detailed_result = TEL_SIM_AUTH_CANNOT_PERFORM; + } + g_free(res); + g_free(convert_res); + } else { + err("Invalid RES/AUTS"); + auth_resp.detailed_result = TEL_SIM_AUTH_CANNOT_PERFORM; + goto out; + } + + ck = g_slist_nth_data(tokens, 2); + if (ck != NULL) { + guint convert_ck_len = 0; + ck = tcore_at_tok_extract(ck); + dbg("CK: [%s]", ck); + + tcore_util_hexstring_to_bytes(ck, &convert_ck, &convert_ck_len); + if (convert_ck_len && convert_ck_len <= TEL_SIM_AUTH_MAX_RESP_DATA_LEN) { + auth_resp.cipher_length = convert_ck_len; + memcpy(&auth_resp.cipher_data, convert_ck, convert_ck_len); + } else { + err("Invalid CK"); + auth_resp.detailed_result = TEL_SIM_AUTH_CANNOT_PERFORM; + } + g_free(ck); + g_free(convert_ck); + } else { + err("Invalid CK"); + auth_resp.detailed_result = TEL_SIM_AUTH_CANNOT_PERFORM; + goto out; + } + + ik = g_slist_nth_data(tokens, 3); + if (ik != NULL) { + guint convert_ik_len = 0; + ik = tcore_at_tok_extract(ik); + dbg("IK: [%s]", ik); + + tcore_util_hexstring_to_bytes(ik, &convert_ik, &convert_ik_len); + if (convert_ik_len && convert_ik_len <= TEL_SIM_AUTH_MAX_RESP_DATA_LEN) { + auth_resp.integrity_length = convert_ik_len; + memcpy(&auth_resp.integrity_data, convert_ik, convert_ik_len); + } else { + err("Invalid IK"); + auth_resp.detailed_result = TEL_SIM_AUTH_CANNOT_PERFORM; + } + g_free(ik); + g_free(convert_ik); + } else { + err("Invalid IK"); + auth_resp.detailed_result = TEL_SIM_AUTH_CANNOT_PERFORM; + goto out; + } + + kc = g_slist_nth_data(tokens, 4); + if (kc != NULL) { + guint convert_kc_len = 0; + kc = tcore_at_tok_extract(kc); + dbg("Kc: [%s]", kc); + + tcore_util_hexstring_to_bytes(kc, &convert_kc, &convert_kc_len); + if (convert_kc_len && convert_kc_len <= TEL_SIM_AUTH_MAX_RESP_DATA_LEN) { + auth_resp.authentication_key_length = convert_kc_len; + memcpy(&auth_resp.authentication_key, convert_kc, convert_kc_len); + } else { + err("Invalid Kc"); + auth_resp.detailed_result = TEL_SIM_AUTH_CANNOT_PERFORM; + } + g_free(kc); + g_free(convert_kc); + } else { + err("Invalid Kc"); + auth_resp.detailed_result = TEL_SIM_AUTH_CANNOT_PERFORM; + goto out; + } + } else { + err("Not supported"); + auth_resp.detailed_result = TEL_SIM_AUTH_CANNOT_PERFORM; + goto out; + } + sim_result = TEL_SIM_RESULT_SUCCESS; + } else { + err("RESPONSE NOK"); + auth_resp.detailed_result = TEL_SIM_AUTH_CANNOT_PERFORM; + } + +out: + if(resp_cb_data->cb) + resp_cb_data->cb(co, (gint)sim_result, &auth_resp, resp_cb_data->cb_data); + + tcore_at_tok_free(tokens); +} + +static void on_response_imc_sim_verify_pins(TcorePending *p, guint data_len, + const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + ImcRespCbData *resp_cb_data = user_data; + CoreObject *co = tcore_pending_ref_core_object(p); + TelSimResult result = TEL_SIM_RESULT_FAILURE; + ImcSimCurrSecOp *sec_op = NULL; + TelSimSecPinResult verify_pin_resp = {0, }; + + dbg("Entry"); + + tcore_check_return_assert(co != NULL); + tcore_check_return_assert(resp_cb_data != NULL); + + sec_op = (ImcSimCurrSecOp *)IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data); + + if (at_resp && at_resp->success) { + dbg("Sim Verify Pin Response- [OK]"); + + result = TEL_SIM_RESULT_SUCCESS; + + if (*sec_op == IMC_SIM_CURR_SEC_OP_PIN1_VERIFY) { + TelSimCardStatus status; + + verify_pin_resp.pin_type = TEL_SIM_PIN_TYPE_PIN1; + + tcore_sim_get_status(co, &status); + if (status != TEL_SIM_STATUS_SIM_INIT_COMPLETED) { + /*Update sim status*/ + __imc_sim_update_sim_status(co, + TEL_SIM_STATUS_SIM_INITIALIZING); + } + } else if (*sec_op == IMC_SIM_CURR_SEC_OP_PIN2_VERIFY) { + verify_pin_resp.pin_type = TEL_SIM_PIN_TYPE_PIN2; + } + + /*Invoke callback*/ + if(resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, + &verify_pin_resp, + resp_cb_data->cb_data); + imc_destroy_resp_cb_data(resp_cb_data); + } else { + err("Sim Verify Pin Response- [NOK]"); + /* Get retry count */ + __imc_sim_get_retry_count(co, resp_cb_data); + } +} + +static void on_response_imc_sim_verify_puks(TcorePending *p, guint data_len, + const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + ImcRespCbData *resp_cb_data = user_data; + CoreObject *co = tcore_pending_ref_core_object(p); + TelSimResult result = TEL_SIM_RESULT_FAILURE; + ImcSimCurrSecOp *sec_op = NULL; + TelSimSecPukResult verify_puk_resp = {0, }; + + dbg("Entry"); + + tcore_check_return_assert(co != NULL); + tcore_check_return_assert(resp_cb_data != NULL); + + sec_op = (ImcSimCurrSecOp *)IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data); + + if (at_resp && at_resp->success) { + dbg("Sim Verify Puk Response- [OK]"); + + result = TEL_SIM_RESULT_SUCCESS; + + if (*sec_op == IMC_SIM_CURR_SEC_OP_PUK1_VERIFY) { + verify_puk_resp.puk_type = TEL_SIM_PUK_TYPE_PUK1; + } else if (*sec_op == IMC_SIM_CURR_SEC_OP_PUK2_VERIFY) { + verify_puk_resp.puk_type = TEL_SIM_PUK_TYPE_PUK2; + } + /*Invoke callback*/ + if(resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, + &verify_puk_resp, + resp_cb_data->cb_data); + imc_destroy_resp_cb_data(resp_cb_data); + } else { + err("Sim Verify Puk Response- [NOK]"); + /* Get retry count */ + __imc_sim_get_retry_count(co, resp_cb_data); + } +} + +static void on_response_imc_sim_change_pins(TcorePending *p, guint data_len, + const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + ImcRespCbData *resp_cb_data = user_data; + CoreObject *co = tcore_pending_ref_core_object(p); + TelSimResult result = TEL_SIM_RESULT_FAILURE; + ImcSimCurrSecOp *sec_op = NULL; + TelSimSecPinResult change_pin_resp = {0, }; + + dbg("Entry"); + + tcore_check_return_assert(co != NULL); + tcore_check_return_assert(resp_cb_data != NULL); + + sec_op = (ImcSimCurrSecOp *)IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data); + + if (at_resp && at_resp->success) { + dbg("Sim Change Pin Response- [OK]"); + + result = TEL_SIM_RESULT_SUCCESS; + + if (*sec_op == IMC_SIM_CURR_SEC_OP_PIN1_CHANGE) { + change_pin_resp.pin_type = TEL_SIM_PIN_TYPE_PIN1; + } else if (*sec_op == IMC_SIM_CURR_SEC_OP_PIN2_CHANGE) { + change_pin_resp.pin_type = TEL_SIM_PIN_TYPE_PIN2; + } + /*Invoke callback*/ + if(resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, + &change_pin_resp, + resp_cb_data->cb_data); + imc_destroy_resp_cb_data(resp_cb_data); + } else { + err("Sim Change Pin Response- [NOK]"); + /* Get retry count */ + __imc_sim_get_retry_count(co, resp_cb_data); + } +} + +static void on_response_imc_sim_disable_facility(TcorePending *p, guint data_len, + const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + ImcRespCbData *resp_cb_data = user_data; + CoreObject *co = tcore_pending_ref_core_object(p); + TelSimResult result = TEL_SIM_RESULT_FAILURE; + ImcSimCurrSecOp *sec_op = NULL; + TelSimFacilityResult disable_facility_resp = {0, }; + + dbg("Entry"); + + tcore_check_return_assert(co != NULL); + tcore_check_return_assert(resp_cb_data != NULL); + + sec_op = (ImcSimCurrSecOp *)IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data); + + if (at_resp && at_resp->success) { + int lock_type; + dbg("Sim Disable Facility Response- [OK]"); + + lock_type = __imc_sim_get_lock_type(*sec_op); + if (lock_type == -1) { + result = TEL_SIM_RESULT_INVALID_PARAMETER; + + /*Invoke callback*/ + if(resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, + NULL, + resp_cb_data->cb_data); + imc_destroy_resp_cb_data(resp_cb_data); + return; + } + + disable_facility_resp.type = lock_type; + result = TEL_SIM_RESULT_SUCCESS; + + /*Invoke callback*/ + if(resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, + &disable_facility_resp, + resp_cb_data->cb_data); + imc_destroy_resp_cb_data(resp_cb_data); + } else { + err("Sim Disable Facility Response- [NOK]"); + /* Get retry count */ + __imc_sim_get_retry_count(co, resp_cb_data); + } +} + +static void on_response_imc_sim_enable_facility(TcorePending *p, guint data_len, + const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + ImcRespCbData *resp_cb_data = user_data; + CoreObject *co = tcore_pending_ref_core_object(p); + TelSimResult result = TEL_SIM_RESULT_FAILURE; + ImcSimCurrSecOp *sec_op = NULL; + TelSimFacilityResult enable_facility_resp = {0, }; + + dbg("Entry"); + + tcore_check_return_assert(co != NULL); + tcore_check_return_assert(resp_cb_data != NULL); + + sec_op = (ImcSimCurrSecOp *)IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data); + + if (at_resp && at_resp->success) { + int lock_type; + dbg("Sim Enable Facility Response- [OK]"); + + lock_type = __imc_sim_get_lock_type(*sec_op); + if (lock_type == -1) { + result = TEL_SIM_RESULT_INVALID_PARAMETER; + + /*Invoke callback*/ + if(resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, + NULL, + resp_cb_data->cb_data); + imc_destroy_resp_cb_data(resp_cb_data); + return; + } + + enable_facility_resp.type = lock_type; + result = TEL_SIM_RESULT_SUCCESS; + + /*Invoke callback*/ + if(resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, + &enable_facility_resp, + resp_cb_data->cb_data); + imc_destroy_resp_cb_data(resp_cb_data); + } else { + err("Sim Enable Facility Response- [NOK]"); + /* Get retry count */ + __imc_sim_get_retry_count(co, resp_cb_data); + } +} + +static void on_response_imc_sim_get_facility(TcorePending *p, guint data_len, + const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + ImcRespCbData *resp_cb_data = user_data; + CoreObject *co = tcore_pending_ref_core_object(p); + TelSimResult result = TEL_SIM_RESULT_FAILURE; + ImcSimCurrSecOp *sec_op = NULL; + TelSimFacilityInfo get_facility_resp = {0, }; + + dbg("Entry"); + + tcore_check_return_assert(co != NULL); + tcore_check_return_assert(resp_cb_data != NULL); + + sec_op = (ImcSimCurrSecOp *)IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data); + + if (at_resp && at_resp->success) { + GSList *tokens = NULL; + const char *line; + int lock_type; + + dbg("Sim Get Facility Response- [OK]"); + + lock_type = __imc_sim_get_lock_type(*sec_op); + if (lock_type == -1) { + result = TEL_SIM_RESULT_INVALID_PARAMETER; + goto EXIT; + } + if (at_resp->lines) { + line = (const char *)at_resp->lines->data; + tokens = tcore_at_tok_new(line); + if (g_slist_length(tokens) != 1) { + err("Invalid message"); + tcore_at_tok_free(tokens); + goto EXIT; + } + get_facility_resp.f_status = atoi(g_slist_nth_data(tokens, 0)); + get_facility_resp.type = lock_type; + result = TEL_SIM_RESULT_SUCCESS; + } + + tcore_at_tok_free(tokens); + } else { + err("Sim Get Facility Response- [NOK]"); + } +EXIT: + /* Invoke callback */ + if(resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, &get_facility_resp, resp_cb_data->cb_data); + imc_destroy_resp_cb_data(resp_cb_data); +} + +static void on_response_imc_sim_get_lock_info(TcorePending *p, guint data_len, + const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + ImcRespCbData *resp_cb_data = user_data; + CoreObject *co = tcore_pending_ref_core_object(p); + TelSimResult result = TEL_SIM_RESULT_FAILURE; + TelSimLockInfo get_lock_info_resp = {0, }; + + dbg("Entry"); + + tcore_check_return_assert(co != NULL); + tcore_check_return_assert(resp_cb_data != NULL); + + if(at_resp && at_resp->success) { + GSList *tokens = NULL; + const char *line; + int lock_type = 0; + int attempts_left = 0; + int time_penalty = 0; + + dbg("Sim Get Lock Info Response- [OK]"); + + if (at_resp->lines) { + line = (const char *)at_resp->lines->data; + tokens = tcore_at_tok_new(line); + if (g_slist_length(tokens) < 3) { + err("Invalid message"); + tcore_at_tok_free(tokens); + goto EXIT; + } + + lock_type = atoi(g_slist_nth_data(tokens, 0)); + attempts_left = atoi(g_slist_nth_data(tokens, 1)); + time_penalty = atoi(g_slist_nth_data(tokens, 2)); + + dbg("lock_type = %d, attempts_left = %d, time_penalty = %d", + lock_type, attempts_left, time_penalty); + + get_lock_info_resp.lock_type = __imc_sim_lock_type(lock_type); + get_lock_info_resp.retry_count = attempts_left; + result = TEL_SIM_RESULT_SUCCESS; + } + tcore_at_tok_free(tokens); + } else { + err("Sim Get Lock Info Response- [NOK]"); + } +EXIT: + /* Invoke callback */ + if(resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, &get_lock_info_resp, resp_cb_data->cb_data); + imc_destroy_resp_cb_data(resp_cb_data); +} + +static void on_response_imc_sim_req_apdu (TcorePending *p, guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *resp = data; + CoreObject *co = NULL; + TelSimApduResp apdu_resp = {0,}; + TelSimResult sim_result = TEL_SIM_RESULT_FAILURE; + GSList *tokens = NULL; + const char *line; + ImcRespCbData *resp_cb_data = (ImcRespCbData *) user_data; + + dbg("Entry"); + + co = tcore_pending_ref_core_object(p); + + if (resp->success > 0) { + dbg("RESPONSE OK"); + if (resp->lines) { + char *tmp = NULL; + char *decoded_data = NULL; + guint decoded_data_len = 0; + line = (const char *)resp->lines->data; + tokens = tcore_at_tok_new(line); + if (g_slist_length(tokens) != 2) { + err("Invalid message"); + goto OUT; + } + + tmp = tcore_at_tok_extract(g_slist_nth_data(tokens, 1)); + tcore_util_hexstring_to_bytes(tmp, &decoded_data, &decoded_data_len); + + apdu_resp.apdu_resp_len = decoded_data_len; + memcpy((char *)apdu_resp.apdu_resp, decoded_data, decoded_data_len); + g_free(tmp); + g_free(decoded_data); + sim_result = TEL_SIM_RESULT_SUCCESS; + } + } else { + err("RESPONSE NOK"); + } + +OUT: + /* Send Response */ + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)sim_result, &apdu_resp, resp_cb_data->cb_data); + tcore_at_tok_free(tokens); + dbg("Exit"); +} + +static void on_response_imc_sim_req_atr(TcorePending *p, guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *resp = data; + CoreObject *co = NULL; + TelSimAtr atr_res = {0,}; + TelSimResult sim_result = TEL_SIM_RESULT_FAILURE; + GSList *tokens = NULL; + const char *line; + ImcRespCbData *resp_cb_data = (ImcRespCbData *) user_data; + + dbg("Entry"); + + co = tcore_pending_ref_core_object(p); + + if (resp->success > 0) { + dbg("RESPONSE OK"); + if (resp->lines) { + char *tmp = NULL; + char *decoded_data = NULL; + guint decoded_data_len = 0; + line = (const char *)resp->lines->data; + tokens = tcore_at_tok_new(line); + if (g_slist_length(tokens) < 1) { + err("Invalid message"); + goto OUT; + } + + tmp = tcore_at_tok_extract(g_slist_nth_data(tokens, 0)); + tcore_util_hexstring_to_bytes(tmp, &decoded_data, &decoded_data_len); + + atr_res.atr_len = decoded_data_len; + memcpy((char *)atr_res.atr, decoded_data, decoded_data_len); + g_free(tmp); + g_free(decoded_data); + sim_result = TEL_SIM_RESULT_SUCCESS; + } + } else { + err("RESPONSE NOK"); + } + +OUT: + /* Send Response */ + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)sim_result, &atr_res, resp_cb_data->cb_data); + tcore_at_tok_free(tokens); + dbg("Exit"); +} + +/* SIM Operations */ +/* + * Operation - get_imsi + * + * Request - + * AT-Command: AT+CRSM= [,[,,,[,[,]]]] + * where, + * + * 176 READ BINARY + * 178 READ RECORD + * 192 GET RESPONSE + * 214 UPDATE BINARY + * 220 UPDATE RECORD + * 242 STATUS + * + * + * 28423 meaning IMSI file (6F07) + * 28473 meaning ACM file (6F39) + * 28481 meaning PUKT file (6F41) + * 28482 meaning SMS file (6F42) + * + * , , + * Integer type defining the request. + * These parameters are mandatory for every command, except GET RESPONSE and STATUS. + * + * + * Information which shall be written to the SIM + * + * + * String type, contains the path of an elementary file on the SIM/USIM in hexadecimal format + * + * + * 0 not active + * 1 active + * + * Success: + * OK + * +CRSM: ,[,] + * + * , + * Integer type containing the SIM information + * + * + * Response of successful completion of the command previously issued + * + * Failure: + * +CME ERROR: + */ +static TelReturn imc_sim_get_imsi (CoreObject *co, + TcoreObjectResponseCallback cb, void *cb_data) +{ + TelReturn ret; + dbg("Entry"); + + IMC_SIM_READ_FILE(co, cb, cb_data, TEL_SIM_EF_IMSI, ret); + + return ret; +} + +static TelReturn imc_sim_get_ecc (CoreObject *co, + TcoreObjectResponseCallback cb, void *cb_data) +{ + TelReturn ret; + dbg("Entry"); + + IMC_SIM_READ_FILE(co, cb, cb_data, TEL_SIM_EF_ECC, ret); + + return ret; +} + +static TelReturn imc_sim_get_iccid (CoreObject *co, + TcoreObjectResponseCallback cb, void *cb_data) +{ + TelReturn ret; + dbg("Entry"); + + IMC_SIM_READ_FILE(co, cb, cb_data, TEL_SIM_EF_ICCID, ret); + + return ret; +} + +static TelReturn imc_sim_get_language (CoreObject *co, + TcoreObjectResponseCallback cb, void *cb_data) +{ + TelReturn ret; + dbg("Entry"); + + IMC_SIM_READ_FILE(co, cb, cb_data, TEL_SIM_EF_LP, ret); + + return ret; +} + +static TelReturn imc_sim_set_language (CoreObject *co, + TelSimLanguagePreferenceCode language, + TcoreObjectResponseCallback cb, void *cb_data) +{ + ImcSimMetaInfo file_meta = {0, }; + TelSimCardType card_type = TEL_SIM_CARD_TYPE_UNKNOWN; + ImcRespCbData *resp_cb_data = NULL; + char *tmp = NULL; + int tmp_len = 0; + char *encoded_data = NULL; + int encoded_data_len = 0; + int p1 = 0; + int p2 = 0; + int p3 = 0; + + dbg("Entry"); + + file_meta.file_id = TEL_SIM_EF_LP; + file_meta.file_result = TEL_SIM_RESULT_FAILURE; + + tcore_sim_get_type(co, &card_type); + + dbg("language[%d], card_type[%d]", language, card_type); + + if (TEL_SIM_CARD_TYPE_GSM == card_type) { + dbg("2G"); + tcore_sim_encode_lp(language, &tmp, &tmp_len); + } else if (TEL_SIM_CARD_TYPE_USIM == card_type) { + dbg("3G"); + tcore_sim_encode_li(language, &tmp, &tmp_len); + } else { + err("Invalid card_type:[%d]", card_type); + return TEL_RETURN_OPERATION_NOT_SUPPORTED; + } + if (!tmp_len) { + err("Failed to encode Language [%d]", language); + return TEL_RETURN_FAILURE; + } + dbg("Encoded Language [%s]", tmp); + + encoded_data_len = 2 * tmp_len; + encoded_data = (char *)tcore_malloc0(encoded_data_len + 1); + tcore_util_byte_to_hex(tmp, encoded_data, tmp_len); + tcore_free(tmp); + + p1 = 0; + p2 = 0; + p3 = encoded_data_len; + dbg("encoded_data - [%s], encoded_data_len - %d", encoded_data, encoded_data_len); + + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, &file_meta, sizeof(ImcSimMetaInfo)); + + return __imc_sim_update_file(co, resp_cb_data, IMC_SIM_ACCESS_UPDATE_BINARY, + TEL_SIM_EF_LP, p1, p2, p3, encoded_data); +} + +static TelReturn imc_sim_get_callforwarding_info (CoreObject *co, + TcoreObjectResponseCallback cb, void *cb_data) +{ + TelReturn ret; + dbg("Entry"); + + IMC_SIM_READ_FILE(co, cb, cb_data, TEL_SIM_EF_USIM_CFIS, ret); + + return ret; +} + +static TelReturn imc_sim_get_messagewaiting_info (CoreObject *co, + TcoreObjectResponseCallback cb, void *cb_data) +{ + TelReturn ret; + dbg("Entry"); + + IMC_SIM_READ_FILE(co, cb, cb_data, TEL_SIM_EF_USIM_MWIS, ret); + + return ret; +} + +static TelReturn imc_sim_set_messagewaiting_info (CoreObject *co, + const TelSimMwis *request, TcoreObjectResponseCallback cb, void *cb_data) +{ + ImcSimMetaInfo file_meta = {0, }; + ImcRespCbData *resp_cb_data = NULL; + gchar *encoded_mwis; + guint encoded_mwis_len = 0; + gchar *encoded_data = NULL; + guint encoded_data_len = 0; + int p1 = 0; + int p2 = 0; + int p3 = 0; + + dbg("Entry"); + + /* + * Videomail is not supported. + */ + if (!tcore_sim_encode_mwis(request, TEL_SIM_MAILBOX_TYPE_MAX, + &encoded_mwis, &encoded_mwis_len)) { + err("Failed to encode mwis"); + return TEL_RETURN_FAILURE; + } + + encoded_data_len = 2 * encoded_mwis_len; + encoded_data = (char *)tcore_malloc0(encoded_data_len + 1); + tcore_util_byte_to_hex(encoded_mwis, encoded_data, encoded_mwis_len); + tcore_free(encoded_mwis); + dbg("Encoded data: [%s] Encoded data length: [%d]", encoded_data, encoded_data_len); + + p1 = 1; + p2 = 0x04; + p3 = TEL_SIM_MAILBOX_TYPE_MAX; /* Indicator Status | Voicemail | Fax | Electronic Mail | Others */ + dbg("p1: [%d] p2: [%d] p3: [%d]", p1, p2, p3); + + file_meta.file_id = TEL_SIM_EF_USIM_MWIS; + file_meta.file_result = TEL_SIM_RESULT_FAILURE; + + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, &file_meta, sizeof(ImcSimMetaInfo)); + + return __imc_sim_update_file(co, resp_cb_data, IMC_SIM_ACCESS_UPDATE_RECORD, + TEL_SIM_EF_USIM_MWIS, p1, p2, p3, encoded_data); +} + +static TelReturn imc_sim_get_mailbox_info (CoreObject *co, + TcoreObjectResponseCallback cb, void *cb_data) +{ + TelReturn ret; + dbg("Entry"); + + IMC_SIM_READ_FILE(co, cb, cb_data, TEL_SIM_EF_USIM_MBI, ret); + + return ret; +} + +static TelReturn imc_sim_set_mailbox_info (CoreObject *co, + const TelSimMailBoxNumber *request, TcoreObjectResponseCallback cb, void *cb_data) +{ + ImcSimMetaInfo file_meta = {0, }; + ImcRespCbData *resp_cb_data = NULL; + char *tmp = NULL; + int tmp_len = 0; + char *encoded_data = NULL; + int encoded_data_len = 0; + int p1 = 0; + int p2 = 0; + int p3 = 0; + + dbg("Entry"); + + file_meta.file_id = TEL_SIM_EF_USIM_MBI; + file_meta.file_result = TEL_SIM_RESULT_FAILURE; + + /* TBD - Do Encoding. + if (!tcore_sim_encode_mbi(request, sizeof(request), tmp, &tmp_len)) { + err("Failed to encode mwis"); + return TEL_RETURN_FAILURE; + } */ + + encoded_data_len = tmp_len * 2; + encoded_data = (char *)tcore_malloc0(encoded_data_len + 1); + tcore_util_byte_to_hex(tmp, encoded_data, tmp_len); + if (!encoded_data) { + err("Failed to convert byte to hex"); + tcore_free(encoded_data); + return TEL_RETURN_FAILURE; + } + + p1 = 1; + p2 = 0x04; + p3 = encoded_data_len; + dbg("encoded_data - [%s], encoded_data_len - %d", encoded_data, encoded_data_len); + + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, &file_meta, sizeof(ImcSimMetaInfo)); + + return __imc_sim_update_file(co, resp_cb_data, IMC_SIM_ACCESS_UPDATE_RECORD, + TEL_SIM_EF_USIM_MBI, p1, p2, p3, encoded_data); +} + +static TelReturn imc_sim_get_msisdn (CoreObject *co, + TcoreObjectResponseCallback cb, void *cb_data) +{ + TelReturn ret; + dbg("Entry"); + + IMC_SIM_READ_FILE(co, cb, cb_data, TEL_SIM_EF_MSISDN, ret); + + return ret; +} + +static TelReturn imc_sim_get_spn (CoreObject *co, + TcoreObjectResponseCallback cb, void *cb_data) +{ + TelReturn ret; + dbg("Entry"); + + IMC_SIM_READ_FILE(co, cb, cb_data, TEL_SIM_EF_SPN, ret); + + return ret; +} + +static TelReturn imc_sim_get_cphs_netname (CoreObject *co, + TcoreObjectResponseCallback cb, void *cb_data) +{ + TelReturn ret; + dbg("Entry"); + + IMC_SIM_READ_FILE(co, cb, cb_data, TEL_SIM_EF_CPHS_OPERATOR_NAME_STRING, ret); + + return ret; +} + +static TelReturn imc_sim_get_sp_display_info (CoreObject *co, + TcoreObjectResponseCallback cb, void *cb_data) +{ + TelReturn ret; + dbg("Entry"); + + IMC_SIM_READ_FILE(co, cb, cb_data, TEL_SIM_EF_SPDI, ret); + + return ret; +} + +static TelReturn imc_sim_req_authentication (CoreObject *co, + const TelSimAuthenticationData *request, + TcoreObjectResponseCallback cb, void *cb_data) +{ + gchar *cmd_str = NULL; + ImcRespCbData *resp_cb_data = NULL; + TelReturn ret = TEL_RETURN_FAILURE; + TelSimCardType card_type = TEL_SIM_CARD_TYPE_UNKNOWN; + char *convert_rand = NULL; + char *convert_autn = NULL; + int session_id; + int context_type; + + dbg("Entry"); + + tcore_sim_get_type(co, &card_type); + if (TEL_SIM_CARD_TYPE_GSM == card_type || TEL_SIM_CARD_TYPE_USIM == card_type) { + session_id = 0; + } else { + err("Not Supported SIM type:[%d]", card_type); + return TEL_SIM_RESULT_OPERATION_NOT_SUPPORTED; + } + + if (request->rand_data != NULL) { + convert_rand = tcore_malloc0(request->rand_length*2 + 1); + tcore_util_byte_to_hex(request->rand_data, convert_rand, request->rand_length); + dbg("Convert RAND hex to string: [%s]", convert_rand); + } else { + err("rand_data is NULL"); + goto EXIT; + } + + switch (request->auth_type) { + case TEL_SIM_AUTH_GSM: + context_type = 2; + cmd_str = g_strdup_printf("AT+XAUTH=%d,%d,\"%s\"", + session_id, context_type, convert_rand); + break; + case TEL_SIM_AUTH_3G_CTX: + context_type = 1; + if (request->autn_data != NULL) { + convert_autn = tcore_malloc0(request->autn_length*2 + 1); + tcore_util_byte_to_hex(request->autn_data, convert_autn, request->autn_length); + dbg("Convert AUTN hex to string: [%s]", convert_autn); + } else { + err("autn_data is NULL"); + goto EXIT; + } + cmd_str = g_strdup_printf("AT+XAUTH=%d,%d,\"%s\",\"%s\"", + session_id, context_type, convert_rand, convert_autn); + break; + default: + err("Not supported Authentication type:[%d]", request->auth_type); + ret = TEL_SIM_RESULT_OPERATION_NOT_SUPPORTED; + goto EXIT; + } + + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, (void *)&request->auth_type, sizeof(TelSimAuthenticationType)); + + ret = tcore_at_prepare_and_send_request(co, cmd_str, "+XAUTH:", + TCORE_AT_COMMAND_TYPE_SINGLELINE, + TCORE_PENDING_PRIORITY_DEFAULT, NULL, + on_response_imc_sim_req_authentication, resp_cb_data, + on_send_imc_request, NULL, 0, NULL, NULL); + + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Sim request authentication"); +EXIT: + g_free(cmd_str); + tcore_free(convert_rand); + tcore_free(convert_autn); + dbg("Exit"); + return ret; +} + +/* + * Operation - verify_pins/verify_puks + * + * Request - + * For SIM PIN + * AT-Command: AT+CPIN= [, ] + * where, + * , + * String type values + * + * For SIM PIN2 + * AT-Command: AT+CPIN2= [, ]andAT+CPIN2= + * where, + * , + * String type values + * + * Success: + * OK + * + * Failure: + * +CME ERROR: + */ +static TelReturn imc_sim_verify_pins(CoreObject *co, const TelSimSecPinPw *request, + TcoreObjectResponseCallback cb, void *cb_data) +{ + TelReturn ret = TEL_RETURN_FAILURE; + ImcRespCbData *resp_cb_data = NULL; + ImcSimCurrSecOp sec_op; + gchar *cmd_str = NULL; + + dbg("Entry"); + + if (request->pin_type == TEL_SIM_PIN_TYPE_PIN1) { + sec_op = IMC_SIM_CURR_SEC_OP_PIN1_VERIFY; + cmd_str = g_strdup_printf("AT+CPIN=\"%s\"", request->pw); + } else if (request->pin_type == TEL_SIM_PIN_TYPE_PIN2) { + sec_op = IMC_SIM_CURR_SEC_OP_PIN2_VERIFY; + cmd_str = g_strdup_printf("AT+CPIN2=\"%s\"", request->pw); + } else { + err("Invalid pin type [%d]", request->pin_type); + return TEL_RETURN_INVALID_PARAMETER; + } + + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, + &sec_op, sizeof(sec_op)); + + ret = tcore_at_prepare_and_send_request(co, cmd_str, NULL, + TCORE_AT_COMMAND_TYPE_NO_RESULT, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_sim_verify_pins, + resp_cb_data, + on_send_imc_request, + NULL, 0, NULL, NULL); + + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Sim Verify Pins"); + g_free(cmd_str); + return ret; +} + +static TelReturn imc_sim_verify_puks(CoreObject *co, const TelSimSecPukPw *request, + TcoreObjectResponseCallback cb, void *cb_data) +{ + TelReturn ret = TEL_RETURN_FAILURE; + ImcRespCbData *resp_cb_data = NULL; + ImcSimCurrSecOp sec_op; + gchar *cmd_str = NULL; + + dbg("Entry"); + + if (request->puk_type == TEL_SIM_PUK_TYPE_PUK1) { + sec_op = IMC_SIM_CURR_SEC_OP_PUK1_VERIFY; + cmd_str = g_strdup_printf("AT+CPIN=\"%s\", \"%s\"", + request->puk_pw, request->new_pin_pw); + } else if (request->puk_type == TEL_SIM_PUK_TYPE_PUK2) { + sec_op = IMC_SIM_CURR_SEC_OP_PUK2_VERIFY; + cmd_str = g_strdup_printf("AT+CPIN2=\"%s\", \"%s\"", + request->puk_pw, request->new_pin_pw); + } else { + err("Invalid puk type [%d]", request->puk_type); + return TEL_RETURN_INVALID_PARAMETER; + } + + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, + &sec_op, sizeof(sec_op)); + + ret = tcore_at_prepare_and_send_request(co, cmd_str, NULL, + TCORE_AT_COMMAND_TYPE_NO_RESULT, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_sim_verify_puks, + resp_cb_data, + on_send_imc_request, + NULL, 0, NULL, NULL); + + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Sim Verify Puks"); + g_free(cmd_str); + return ret; +} + +/* + * Operation - change_pins + * + * Request - + * AT-Command: AT+CPWD= ,, + * where, + * + * SIM facility + * + * + * Old Password + * + * + * New Password + * + * Success: + * OK + * + * Failure: + * +CME ERROR: + */ +static TelReturn imc_sim_change_pins(CoreObject *co, const TelSimSecChangePinPw *request, + TcoreObjectResponseCallback cb, void *cb_data) +{ + TelReturn ret = TEL_RETURN_FAILURE; + ImcRespCbData *resp_cb_data = NULL; + ImcSimCurrSecOp sec_op; + gchar *cmd_str = NULL; + char *pin1_fac = "SC"; + char *pin2_fac = "P2"; + + dbg("Entry"); + + if (request->pin_type == TEL_SIM_PIN_TYPE_PIN1) { + sec_op = IMC_SIM_CURR_SEC_OP_PIN1_CHANGE; + cmd_str = g_strdup_printf("AT+CPWD=\"%s\",\"%s\",\"%s\"", + pin1_fac, request->old_pw, request->new_pw); + } else if (request->pin_type == TEL_SIM_PIN_TYPE_PIN2) { + sec_op = IMC_SIM_CURR_SEC_OP_PIN2_CHANGE; + cmd_str = g_strdup_printf("AT+CPWD=\"%s\",\"%s\",\"%s\"", + pin2_fac, request->old_pw, request->new_pw); + } else { + err("Invalid pin type [%d]", request->pin_type); + return TEL_RETURN_INVALID_PARAMETER; + } + + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, + &sec_op, sizeof(sec_op)); + + ret = tcore_at_prepare_and_send_request(co, cmd_str, NULL, + TCORE_AT_COMMAND_TYPE_NO_RESULT, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_sim_change_pins, + resp_cb_data, + on_send_imc_request, + NULL, 0, NULL, NULL); + + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Sim Change Pins"); + g_free(cmd_str); + return ret; +} + +/* + * Operation - disable_facility/enable_facility/get_facility + * + * Request - + * AT-Command: AT+CLCK = , [, [, ]] + * where, + * + * SIM facility + * + * + * 0 unlock + * 1 lock + * 2 query status + * + * + * Password string + * + * + * 0 not active + * 1 active + * + * Success: when =2: + * OK + * +CLCK: [, [ + * +CLCK: , [...]] + * + * Failure: + */ +static TelReturn imc_sim_disable_facility(CoreObject *co, const TelSimFacilityPw *request, + TcoreObjectResponseCallback cb, void *cb_data) +{ + TelReturn ret = TEL_RETURN_FAILURE; + ImcRespCbData *resp_cb_data = NULL; + ImcSimCurrSecOp sec_op; + gchar *cmd_str = NULL; + char *fac = "SC"; + int mode = 0; /*mode = 0 for disable lock*/ + + dbg("Entry"); + + fac = __imc_sim_get_fac_from_lock_type(request->lock_type, + &sec_op, DISABLE_FLAG); + if (!fac) + return TEL_RETURN_INVALID_PARAMETER; + + cmd_str = g_strdup_printf("AT+CLCK=\"%s\", %d, \"%s\"", + fac, mode, request->pw); + + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, + &sec_op, sizeof(sec_op)); + + ret = tcore_at_prepare_and_send_request(co, cmd_str, "+CLCK:", + TCORE_AT_COMMAND_TYPE_SINGLELINE, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_sim_disable_facility, + resp_cb_data, + on_send_imc_request, + NULL, 0, NULL, NULL); + + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Sim Disable Facility"); + g_free(cmd_str); + return ret; +} + +static TelReturn imc_sim_enable_facility(CoreObject *co, const TelSimFacilityPw *request, + TcoreObjectResponseCallback cb, void *cb_data) +{ + TelReturn ret = TEL_RETURN_FAILURE; + ImcRespCbData *resp_cb_data = NULL; + ImcSimCurrSecOp sec_op; + gchar *cmd_str = NULL; + char *fac = "SC"; + int mode = 1; /*mode = 1 for enable lock*/ + + dbg("Entry"); + + fac = __imc_sim_get_fac_from_lock_type(request->lock_type, + &sec_op, ENABLE_FLAG); + if (!fac) + return TEL_RETURN_INVALID_PARAMETER; + + cmd_str = g_strdup_printf("AT+CLCK=\"%s\", %d, \"%s\"", + fac, mode, request->pw); + + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, + &sec_op, sizeof(sec_op)); + + ret = tcore_at_prepare_and_send_request(co, cmd_str, "+CLCK:", + TCORE_AT_COMMAND_TYPE_SINGLELINE, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_sim_enable_facility, + resp_cb_data, + on_send_imc_request, + NULL, 0, NULL, NULL); + + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Sim Disable Facility"); + g_free(cmd_str); + return ret; +} + +static TelReturn imc_sim_get_facility(CoreObject *co, TelSimLockType lock_type, + TcoreObjectResponseCallback cb, void *cb_data) +{ + TelReturn ret = TEL_RETURN_FAILURE; + ImcRespCbData *resp_cb_data = NULL; + ImcSimCurrSecOp sec_op; + gchar *cmd_str = NULL; + char *fac = "SC"; + int mode = 2; /*mode = 2 for Get Facility*/ + + dbg("Entry"); + + fac = __imc_sim_get_fac_from_lock_type(lock_type, + &sec_op, 0); + if (!fac) + return TEL_RETURN_INVALID_PARAMETER; + + cmd_str = g_strdup_printf("AT+CLCK=\"%s\", %d", fac, mode); + + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, + &sec_op, sizeof(sec_op)); + + ret = tcore_at_prepare_and_send_request(co, cmd_str, "+CLCK:", + TCORE_AT_COMMAND_TYPE_SINGLELINE, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_sim_get_facility, + resp_cb_data, + on_send_imc_request, + NULL, 0, NULL, NULL); + + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Sim Get Facility"); + g_free(cmd_str); + return ret; +} + +static TelReturn imc_sim_get_lock_info(CoreObject *co, TelSimLockType lock_type, + TcoreObjectResponseCallback cb, void *cb_data) +{ + TelReturn ret = TEL_RETURN_FAILURE; + ImcRespCbData *resp_cb_data = NULL; + gchar *cmd_str = NULL; + int lockType = 0; + + dbg("Entry"); + + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, NULL, 0); + + switch (lock_type) { + case TEL_SIM_LOCK_PS: + lockType = 9; + break; + + case TEL_SIM_LOCK_SC: + lockType = 1; + break; + + case TEL_SIM_LOCK_FD: + lockType = 2; + break; + + case TEL_SIM_LOCK_PN: + lockType = 5; + break; + + case TEL_SIM_LOCK_PU: + lockType = 6; + break; + + case TEL_SIM_LOCK_PP: + lockType = 7; + break; + + case TEL_SIM_LOCK_PC: + lockType = 8; + break; + + default: + break; + } + + cmd_str = g_strdup_printf("AT+XPINCNT=%d", lockType); + + ret = tcore_at_prepare_and_send_request(co, cmd_str, "+XPINCNT:", + TCORE_AT_COMMAND_TYPE_SINGLELINE, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_sim_get_lock_info, + resp_cb_data, + on_send_imc_request, + NULL, 0, NULL, NULL); + + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Sim Get Lock Info"); + g_free(cmd_str); + return ret; +} + +static TelReturn imc_sim_req_apdu (CoreObject *co, const TelSimApdu *request, TcoreObjectResponseCallback cb, void *cb_data) +{ + gchar *cmd_str = NULL; + char *apdu = NULL; + ImcRespCbData *resp_cb_data = NULL; + TelReturn ret = TEL_RETURN_FAILURE; + + dbg("Entry"); + + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, NULL, 0); + + apdu = (char *)tcore_malloc0((2 * request->apdu_len) + 1); + tcore_util_byte_to_hex((char *)request->apdu, apdu, request->apdu_len); + + cmd_str = g_strdup_printf("AT+CSIM=%d,\"%s\"", strlen((const char *)apdu), apdu); + + ret = tcore_at_prepare_and_send_request(co, cmd_str, "+CSIM:", + TCORE_AT_COMMAND_TYPE_SINGLELINE, + TCORE_PENDING_PRIORITY_DEFAULT, NULL, + on_response_imc_sim_req_apdu, resp_cb_data, + on_send_imc_request, NULL, 0, NULL, NULL); + + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Sim Request APDU"); + + g_free(cmd_str); + g_free(apdu); + + dbg("Exit"); + return ret; +} + +static TelReturn imc_sim_req_atr (CoreObject *co, TcoreObjectResponseCallback cb, void *cb_data) +{ + gchar *cmd_str = NULL; + ImcRespCbData *resp_cb_data = NULL; + TelReturn ret = TEL_RETURN_FAILURE; + + dbg("Entry"); + + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, NULL, 0); + + cmd_str = g_strdup_printf("AT+XGATR"); + + ret = tcore_at_prepare_and_send_request(co, cmd_str, "+XGATR:", + TCORE_AT_COMMAND_TYPE_SINGLELINE, + TCORE_PENDING_PRIORITY_DEFAULT, NULL, + on_response_imc_sim_req_atr, resp_cb_data, + on_send_imc_request, NULL, 0, NULL, NULL); + + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Sim Request ATR"); + + g_free(cmd_str); + + dbg("Exit"); + return ret; +} + +/* SIM Operations */ +static TcoreSimOps imc_sim_ops = { + .get_imsi = imc_sim_get_imsi, + .get_ecc = imc_sim_get_ecc, + .get_iccid = imc_sim_get_iccid, + .get_language = imc_sim_get_language, + .set_language = imc_sim_set_language, + .get_callforwarding_info = imc_sim_get_callforwarding_info, + .get_messagewaiting_info = imc_sim_get_messagewaiting_info, + .set_messagewaiting_info = imc_sim_set_messagewaiting_info, + .get_mailbox_info = imc_sim_get_mailbox_info, + .set_mailbox_info = imc_sim_set_mailbox_info, + .get_msisdn = imc_sim_get_msisdn, + .get_spn = imc_sim_get_spn, + .get_cphs_netname = imc_sim_get_cphs_netname, + .get_sp_display_info = imc_sim_get_sp_display_info, + .req_authentication = imc_sim_req_authentication, + .verify_pins = imc_sim_verify_pins, + .verify_puks = imc_sim_verify_puks, + .change_pins = imc_sim_change_pins, + .disable_facility = imc_sim_disable_facility, + .enable_facility = imc_sim_enable_facility, + .get_facility = imc_sim_get_facility, + .get_lock_info = imc_sim_get_lock_info, + .req_apdu = imc_sim_req_apdu, + .req_atr = imc_sim_req_atr +}; + +gboolean imc_sim_init(TcorePlugin *p, CoreObject *co) +{ + ImcSimPrivateInfo *priv_info = NULL; + + dbg("Entry"); + + priv_info = g_try_new0(ImcSimPrivateInfo, 1); + if (priv_info == NULL) + return FALSE; + + tcore_sim_link_userdata(co, priv_info); + + /* Set operations */ + tcore_sim_set_ops(co, &imc_sim_ops); + + /* Add Callbacks */ + tcore_object_add_callback(co, "+XSIM:", + on_notification_imc_sim_status, NULL); + + /* Hooks */ + tcore_plugin_add_notification_hook(p, + TCORE_NOTIFICATION_MODEM_POWER, + on_hook_imc_modem_power, co); + + dbg("Exit"); + return TRUE; +} + +void imc_sim_exit(TcorePlugin *plugin, CoreObject *co) +{ + ImcSimPrivateInfo *priv_info = NULL; + + dbg("Entry"); + + priv_info = tcore_sim_ref_userdata(co); + g_free(priv_info); + + dbg("Exit"); +} diff --git a/src/imc_sms.c b/src/imc_sms.c new file mode 100644 index 0000000..83678bb --- /dev/null +++ b/src/imc_sms.c @@ -0,0 +1,2426 @@ +/* + * tel-plugin-imc + * + * Copyright (c) 2013 Samsung Electronics Co. Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "imc_sms.h" +#include "imc_sim.h" +#include "imc_common.h" + +#define CR '\r' +#define CTRL_Z '\x1A' + +#define AT_MT_UNREAD 0 /* Received and Unread */ +#define AT_MT_READ 1 /* Received and Read */ +#define AT_MO_UNSENT 2 /* Unsent */ +#define AT_MO_SENT 3 /* Sent */ +#define AT_ALL 4 /* Unknown */ + +#define IMC_NUM_PLAN_ID(sca) (gchar)(sca & 0x0F) +#define IMC_TYPE_OF_NUM(sca) (gchar)((sca & 0x70) >> 4) + +/* SCA 12 bytes long and TDPU is 164 bytes long */ +#define PDU_LEN_MAX 176 +#define HEX_PDU_LEN_MAX ((PDU_LEN_MAX * 2) + 1) + +#define IMC_SIM_TON_INTERNATIONAL 1 +#define IMC_SIM_TON_NATIONAL 2 + +#define IMC_AT_EF_SMS_RECORD_LEN 176 + +typedef struct { + guint total_param_count; + guint count; + guint index; + TelSmsParamsInfo *params; +} ImcSmsParamsCbData; + +/* + * Notification - SMS-DELIVER + * +CMT = [], (PDU mode enabled) + * + * where, + * alpha_id + * length of the PDU + * Incomming SMS PDU + * + * Notification - SMS-STATUS-REPORT + * +CDS: (PDU mode enabled) + * + * where, + * length of the PDU + * Incomming SMS PDU + * + */ +static gboolean on_notification_imc_sms_incoming_msg(CoreObject *co, + const void *event_info, void *user_data) +{ + GSList *tokens = NULL; + GSList *lines = NULL; + char *line = NULL; + int pdu_len = 0, no_of_tokens = 0; + + TelSmsDatapackageInfo incoming_msg = {{0}, }; + int sca_length = 0; + gchar *byte_pdu; + guint byte_pdu_len; + dbg("Enter"); + + lines = (GSList *)event_info; + if (2 != g_slist_length(lines)) { + err("Invalid number of lines for +CMT. Must be 2"); + return TRUE; + } + + line = (char *)g_slist_nth_data(lines, 0); /* Fetch Line 1 */ + if (!line) { + err("Line 1 is invalid"); + return TRUE; + } + dbg("Line 1: [%s]", line); + + /* Split Line 1 into tokens */ + tokens = tcore_at_tok_new(line); + no_of_tokens = g_slist_length(tokens); + + /* + * Incoming SMS: +CMT + * Number of tokens: 2 + * + * Incoming SMS-STATUS-REPORT: +CDS + * Number of tokens: 1 + */ + if (2 == no_of_tokens) { + /* Token 0: Alpha ID */ + dbg("Alpha ID: [0x%x]", g_slist_nth_data(tokens, 0)); + + /* Token 1: PDU Length */ + pdu_len = atoi((char *)g_slist_nth_data(tokens, 1)); + dbg("pdu_len: [%d]", pdu_len); + } else if (1 == no_of_tokens) { + /* Token 0: PDU Length */ + pdu_len = atoi((char *)g_slist_nth_data(tokens, 0)); + dbg("pdu_len: [%d]", pdu_len); + } + tcore_at_tok_free(tokens); + + /* Fetch Line 2 */ + line = (char *)g_slist_nth_data(lines, 1); + if (!line) { + err("Line 2 is invalid"); + return TRUE; + } + dbg("Line 2: [%s]", line); + + /* Convert to Bytes */ + tcore_util_hexstring_to_bytes(line, &byte_pdu, &byte_pdu_len); + + sca_length = byte_pdu[0]; + dbg("SCA length = %d", sca_length); + if (sca_length) { + gchar *decoded_sca; + guint encoded_sca_len; + /* + * byte_pdu[1] - sca_address_type + * Excluding sca_address_type and copy SCA + */ + encoded_sca_len = sca_length - 1; + decoded_sca = + tcore_util_convert_bcd_to_ascii(&byte_pdu[2], encoded_sca_len, encoded_sca_len*2); + dbg("Decoded SCA: [%s]", decoded_sca); + g_strlcpy(incoming_msg.sca.number, decoded_sca, strlen(decoded_sca)+1); + tcore_free(decoded_sca); + + /*SCA Conversion for Address type*/ + incoming_msg.sca.ton = IMC_TYPE_OF_NUM(byte_pdu[1]); + incoming_msg.sca.npi = IMC_NUM_PLAN_ID(byte_pdu[1]); + dbg("TON: [%d] NPI: [%d] SCA: [%s]", + incoming_msg.sca.ton, incoming_msg.sca.npi, + incoming_msg.sca.number); + } + else { + dbg("NO SCA Present"); + } + + /* TPDU */ + incoming_msg.tpdu_length = pdu_len; + memcpy(incoming_msg.tpdu, + &byte_pdu[sca_length+1], incoming_msg.tpdu_length); + + tcore_util_hex_dump(" ",incoming_msg.tpdu_length, &byte_pdu[sca_length+1]); + + /* Send notification */ + tcore_object_send_notification(co, + TCORE_NOTIFICATION_SMS_INCOM_MSG, + sizeof(TelSmsDatapackageInfo), &incoming_msg); + + g_free(byte_pdu); + return TRUE; +} + +/* + * Notification + * +CBM: (PDU mode enabled); + * + * where, + * length of the PDU + * Incomming SMS CB PDU + * + */ +static gboolean on_notification_imc_sms_cb_incom_msg(CoreObject *co, + const void *event_info, void *user_data) +{ + char * line = NULL, *pdu = NULL, *line_token = NULL; + GSList *tokens = NULL; + unsigned char *byte_pdu = NULL; + guint byte_pdu_len = 0; + GSList *lines = NULL; + + TelSmsCbMsgInfo cb_noti = { 0, }; + dbg("Enter"); + + lines = (GSList *)event_info; + + line = (char *)(lines->data);/*Fetch Line 1*/ + if (line != NULL) { + tokens = tcore_at_tok_new(line); /* Split Line 1 into tokens */ + line_token = g_slist_nth_data(tokens, 0); + if (line_token) { + cb_noti.length = atoi(line_token); + } else { + dbg("token 0 is NULL"); + tcore_at_tok_free(tokens); + return TRUE; + } + pdu = g_slist_nth_data(lines, 1); + if (pdu != NULL) { + cb_noti.cb_type = TEL_SMS_CB_MSG_GSM; + + dbg("CB Msg LENGTH [%d]", cb_noti.length); + + if ((cb_noti.length > 0) && (TEL_SMS_CB_DATA_SIZE_MAX >= cb_noti.length)) { + tcore_util_hexstring_to_bytes(pdu, (gchar **)&byte_pdu, &byte_pdu_len); + + memcpy(cb_noti.cb_data, (char*)byte_pdu, cb_noti.length); + } else { + err("Invalid Message Length"); + tcore_at_tok_free(tokens); + return TRUE; + } + } else { + err("NULL PDU Recieved "); + tcore_at_tok_free(tokens); + return TRUE; + } + tcore_object_send_notification(co, + TCORE_NOTIFICATION_SMS_CB_INCOM_MSG, sizeof(TelSmsCbMsgInfo), &cb_noti); + g_free(byte_pdu); + } else { + err("Response NOK"); + } + + tcore_at_tok_free(tokens); + return TRUE; +} + +/* + * Notification + * TODO - AT Command Description Not available + * + */ +static gboolean on_notification_imc_sms_memory_status(CoreObject *co, + const void *event_info, void *user_data) +{ + gboolean memory_status = TRUE; + + GSList *tokens = NULL; + GSList *lines = NULL; + char *line = NULL , *line_token = NULL; + dbg(" Enter"); + + lines = (GSList *)event_info; + if (1 != g_slist_length(lines)) { + dbg("Unsolicited msg but multiple line"); + return TRUE; + } + + line = (char*)(lines->data); + if (line) { + tokens = tcore_at_tok_new(line); + line_token = g_slist_nth_data(tokens, 0); + if (line_token) { + /* SIM Full condition */ + if (0 == atoi(line_token)) + memory_status = FALSE; + + /* Send notification */ + tcore_object_send_notification(co, + TCORE_NOTIFICATION_SMS_MEMORY_STATUS, + sizeof(gboolean), &memory_status); + } + tcore_at_tok_free(tokens); + } else { + err("Response NOK"); + } + + return TRUE; +} + +static void on_response_imc_class2_sms_incom_msg(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + CoreObject *co = tcore_pending_ref_core_object(p); + + TelSmsDatapackageInfo incoming_msg = { { 0 }, }; + + GSList *tokens=NULL; + char *gslist_line = NULL, *line_token = NULL, *byte_pdu = NULL, *hex_pdu = NULL; + gint sca_length = 0; + guint byte_pdu_len = 0; + dbg("Enter"); + + if (at_resp && at_resp->success) { + dbg("RESPONSE OK"); + if (at_resp->lines) { + /* + * TCORE_AT_PDU: + * Multi-line output + * + * Fetching First Line + */ + gslist_line = (char *)at_resp->lines->data; + dbg("gslist_line: [%s]", gslist_line); + + /*Tokenize*/ + tokens = tcore_at_tok_new(gslist_line); + dbg("Number of tokens: [%d]", g_slist_length(tokens)); + + /* First Token : status + * Second Token: Alpha ID - not needed + */ + line_token = g_slist_nth_data(tokens, 2); /* Third Token: PDU Length */ + if (line_token != NULL) { + incoming_msg.tpdu_length = atoi(line_token); + dbg("Length: [%d]", incoming_msg.tpdu_length); + } + else { + err("Line Token for PDU Length is NULL"); + return; + } + + /* Fetching line: Second line is PDU */ + hex_pdu = (char *) at_resp->lines->next->data; + dbg("EF-SMS PDU: [%s]", hex_pdu); + + tcore_at_tok_free(tokens); /* free the consumed token */ + if (NULL != hex_pdu) { + tcore_util_hexstring_to_bytes(hex_pdu, &byte_pdu, &byte_pdu_len); + + sca_length = (int)byte_pdu[0]; + + dbg("SCA Length [%d], msgLength: [%d]", sca_length, incoming_msg.tpdu_length); + + if (ZERO == sca_length) { + memcpy(incoming_msg.tpdu, &byte_pdu[1], incoming_msg.tpdu_length); + } + else { + char sca_toa; + + /* + * byte_pdu[1] - sca_address_type + * Excluding sca_address_type and copy SCA + */ + memcpy(incoming_msg.sca.number, &byte_pdu[2], (sca_length-1)); + + /* + * SCA Conversion: Address Type + * 3GPP TS 23.040 V6.5.0 Section: 9.1.2.5 + */ + sca_toa = byte_pdu[1]; + incoming_msg.sca.npi = IMC_NUM_PLAN_ID(sca_toa); + incoming_msg.sca.ton = IMC_TYPE_OF_NUM(sca_toa); + + memcpy(incoming_msg.tpdu, + &byte_pdu[sca_length+1], + incoming_msg.tpdu_length); + } + } + + tcore_object_send_notification(co, + TCORE_NOTIFICATION_SMS_INCOM_MSG, + sizeof(TelSmsDatapackageInfo), &incoming_msg); + tcore_at_tok_free(tokens); + g_free(byte_pdu); + } + else { + err("Invalid Response Received"); + } + } + else { + err("RESPONSE NOK"); + } +} + +/* + * Notification + * +CMTI: , + * + * where, + * memory location + * index where msg is stored + */ +static gboolean on_notification_imc_sms_class2_incoming_msg(CoreObject *co, const void *event_info, void *user_data) +{ + gchar *at_cmd; + TelReturn ret; + + GSList *tokens = NULL , *lines = NULL; + char *line = NULL; + gint index, mem_type = 0; + dbg("Enter"); + + lines = (GSList *)event_info; + line = (char *)g_slist_nth_data(lines, 0); /* Fetch Line 1 */ + if (!line) { + err("Line 1 is invalid"); + return TRUE; + } + dbg("Line 1: [%s]", line); + + tokens = tcore_at_tok_new(line); /* Split Line 1 into tokens */ + mem_type = atoi(g_slist_nth_data(tokens, 0));/* Type of Memory stored */ + dbg("mem_type=[%d]", mem_type); + index = atoi((char *) g_slist_nth_data(tokens, 1)); + dbg("index: [%d]", index); + + /* + * Operation - read_sms_in_sim + * + * Request - + * AT-Command: At+CMGR= + * where + * index of the message to be read. + * + * Response - + * Success: (PDU: Multi-line output) + * +CMGR: ,[], + * + * Failure: + * +CMS ERROR: + */ + /*AT Command*/ + at_cmd = g_strdup_printf("AT+CMGR=%d", index); + + /* Send Request to modem */ + ret = tcore_at_prepare_and_send_request(co, + at_cmd, "+CMGR:", + TCORE_AT_COMMAND_TYPE_PDU, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_class2_sms_incom_msg, NULL, + on_send_imc_request, NULL, + 0, NULL, NULL); + if (ret != TEL_RETURN_SUCCESS) { + err("Failed to Read Class2 Incomming Message"); + } + g_free(at_cmd); + return TRUE; +} + +static void on_response_imc_sms_send_more_msg(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + + dbg("Enter"); + + if (at_resp && at_resp->success) + dbg("Response OK for AT+CMMS: More msgs to send!!"); + else + err("Response NOK for AT+CMMS: More msgs to send"); + + /* Need not send any response */ +} + +static void on_response_imc_sms_send_sms(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + CoreObject *co = tcore_pending_ref_core_object(p); + ImcRespCbData *resp_cb_data = user_data; + + TelSmsResult result = TEL_SMS_RESULT_FAILURE;/*TODO: CMS error mapping required */ + dbg("Enter"); + + tcore_check_return_assert(co != NULL); + tcore_check_return_assert(resp_cb_data != NULL); + + if (at_resp && at_resp->success) { + dbg("Response OK"); + if (at_resp->lines) { + const gchar *line; + gchar* line_token; + GSList *tokens = NULL; + gint msg_ref = 0; + + line = (const gchar *)at_resp->lines->data; + tokens = tcore_at_tok_new(line); + line_token = g_slist_nth_data(tokens, 0); + if (line_token != NULL) { + /*Response from MODEM for send SMS: +CMGS: [,]*/ + /*Message Reference is not used by MSG_SERVER and application.So Filling only result*/ + msg_ref = atoi(line_token); + + dbg("Message Reference: [%d]", msg_ref); + + result = TEL_SMS_RESULT_SUCCESS; + } + else { + dbg("No Message Reference received"); + } + tcore_at_tok_free(tokens); + } + } + else { + err("Response NOK"); + } + + /* Invoke callback */ + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, NULL, resp_cb_data->cb_data); + + /* Free callback data */ + imc_destroy_resp_cb_data(resp_cb_data); +} + +static void on_response_imc_sms_write_sms_in_sim(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + CoreObject *co = tcore_pending_ref_core_object(p); + ImcRespCbData *resp_cb_data = user_data; + + TelSmsResult result = TEL_SMS_RESULT_FAILURE; + + GSList *tokens = NULL; + char *line = NULL, *line_token = NULL; + guint index = -1; + + dbg("Enter"); + + if (at_resp && at_resp->success) { + dbg("Response OK"); + if (at_resp->lines) { + line = (char *)at_resp->lines->data; + tokens = tcore_at_tok_new(line); + line_token = g_slist_nth_data(tokens, 0); + if (line_token) { + index = (atoi(line_token)); + dbg("SMS written to '%d' index", index); + result = TEL_SMS_RESULT_SUCCESS; + } + else { + dbg("No Tokens"); + result = TEL_SMS_RESULT_FAILURE; + } + } + else { + err("Lines NOT present"); + } + } + else { + dbg("Response NOK"); + } + + /* Invoke callback */ + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, &index, resp_cb_data->cb_data); + + /* Free callback data */ + imc_destroy_resp_cb_data(resp_cb_data); +} + +static void on_response_imc_sms_read_sms_in_sim(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + CoreObject *co = tcore_pending_ref_core_object(p); + ImcRespCbData *resp_cb_data = user_data; + TelSmsSimDataInfo read_resp; + GSList *tokens = NULL; + + TelSmsResult result = TEL_SMS_RESULT_FAILURE;/* CMS error mapping required */ + dbg("Enter"); + + memset(&read_resp, 0x0, sizeof(TelSmsSimDataInfo)); + + if (at_resp && at_resp->success) { + dbg("RESPONSE OK"); + if (at_resp->lines) { + char *gslist_line = NULL,*line_token = NULL,*byte_pdu = NULL,*hex_pdu = NULL; + gint msg_status = 0, pdu_len = 0, alpha_id = 0; + + /* + * TCORE_AT_PDU: + * Multi-line output + * + * Fetching First Line + */ + gslist_line = (char *)at_resp->lines->data; + dbg("gslist_line: [%s]", gslist_line); + + /*Tokenize*/ + tokens = tcore_at_tok_new(gslist_line); + dbg("Number of tokens: [%d]", g_slist_length(tokens)); + + /*+CMGR: ,[],*/ + line_token = g_slist_nth_data(tokens, 0); /*First Token: Message status*/ + if (line_token == NULL) { + err("Invalid stat"); + goto OUT; + } + + msg_status = atoi(line_token); + dbg("msg_status is %d",msg_status); + + switch (msg_status) { + case AT_MT_UNREAD: + read_resp.status = TEL_SMS_STATUS_MT_UNREAD; + break; + case AT_MT_READ: + read_resp.status = TEL_SMS_STATUS_MT_READ; + break; + case AT_MO_UNSENT: + read_resp.status = TEL_SMS_STATUS_MO_NOT_SENT; + break; + case AT_MO_SENT: + read_resp.status = TEL_SMS_STATUS_MO_SENT; + break; + case AT_ALL: + default: + read_resp.status = TEL_SMS_STATUS_REPLACED; + break; + } + + /*Second Token: Alpha ID*/ + line_token = g_slist_nth_data(tokens, 1); + if (line_token != NULL) { + alpha_id = atoi(line_token); + dbg("alpha_id: [%d]", alpha_id); + } + + /*Third Token: Length*/ + line_token = g_slist_nth_data(tokens, 2); + if (line_token == NULL) { + err("Invalid PDU length"); + goto OUT; + } + pdu_len = atoi(line_token); + dbg("PDU length: [%d]", pdu_len); + + /*Fetching line: Second line is PDU*/ + hex_pdu = (char *) at_resp->lines->next->data; + dbg("EF-SMS PDU: [%s]", hex_pdu); + + if (NULL != hex_pdu) { + gint sca_length = 0; + guint byte_pdu_len = 0; + + tcore_util_hex_dump(" ", sizeof(hex_pdu), (void *)hex_pdu); + + tcore_util_hexstring_to_bytes(hex_pdu, &byte_pdu, &byte_pdu_len); + + sca_length = byte_pdu[0]; + dbg("SCA length = %d", sca_length); + if (sca_length) { + gchar *decoded_sca; + guint encoded_sca_len; + + /* + * byte_pdu[1] - sca_address_type + * Excluding sca_address_type and copy SCA + */ + encoded_sca_len = sca_length - 1; + decoded_sca = + tcore_util_convert_bcd_to_ascii(&byte_pdu[2], + encoded_sca_len, encoded_sca_len*2); + + dbg("Decoded SCA: [%s]", decoded_sca); + memcpy(read_resp.data.sca.number, decoded_sca, TEL_SMS_SCA_LEN_MAX); + tcore_free(decoded_sca); + + /*SCA Conversion for Address type*/ + read_resp.data.sca.ton = IMC_TYPE_OF_NUM(byte_pdu[1]); + read_resp.data.sca.npi = IMC_NUM_PLAN_ID(byte_pdu[1]); + dbg("TON: [%d] NPI: [%d] SCA: [%s]", + read_resp.data.sca.ton, read_resp.data.sca.npi, + read_resp.data.sca.number); + } else { + err("NO SCA Present"); + } + + /* TPDU */ + read_resp.data.tpdu_length = pdu_len; + if ((read_resp.data.tpdu_length > 0) + && (read_resp.data.tpdu_length <= TEL_SMS_SMDATA_SIZE_MAX)) { + memcpy(read_resp.data.tpdu, &byte_pdu[sca_length+1], + read_resp.data.tpdu_length); + } else { + warn("Invalid TPDU length: [%d]", read_resp.data.tpdu_length); + } + + result = TEL_SMS_RESULT_SUCCESS; + g_free(byte_pdu); + } + } else { + err("Invalid Response Received"); + } + } + else { + err("RESPONSE NOK"); + } +OUT: + /* Invoke callback */ + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, &read_resp, resp_cb_data->cb_data); + + /* Free callback data */ + imc_destroy_resp_cb_data(resp_cb_data); + + /*free the consumed token*/ + tcore_at_tok_free(tokens); +} + +static void on_response_imc_sms_delete_sms_in_sim(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + CoreObject *co = tcore_pending_ref_core_object(p); + ImcRespCbData *resp_cb_data = user_data; + + TelSmsResult result = TEL_SMS_RESULT_FAILURE; + dbg("Enter"); + + tcore_check_return_assert(co != NULL); + + if (at_resp && at_resp->success) { + dbg("Response OK"); + result = TEL_SMS_RESULT_SUCCESS; + } + else { + dbg("Response NOK"); + } + + /* Invoke callback */ + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, NULL, resp_cb_data->cb_data); + + /* Free callback data */ + imc_destroy_resp_cb_data(resp_cb_data); +} + +static void on_response_imc_sms_get_msg_indices(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + TelSmsStoredMsgCountInfo *count_info;/*Response from get_count Request*/ + TelSmsResult result = TEL_SMS_RESULT_FAILURE;/*TODO: CMS error mapping required */ + + const TcoreAtResponse *at_resp = data; + CoreObject *co = tcore_pending_ref_core_object(p); + ImcRespCbData *resp_cb_data = user_data; + dbg("Enter"); + + count_info = (TelSmsStoredMsgCountInfo *)IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data); + + if (at_resp && at_resp->success) { + dbg("RESPONSE OK"); + if (at_resp->lines) { + char *gslist_line = NULL; + gint gslist_line_count = 0, ctr_loop = 0; + + gslist_line_count = g_slist_length(at_resp->lines); + + if (gslist_line_count > TEL_SMS_GSM_MSG_NUM_MAX) + gslist_line_count = TEL_SMS_GSM_MSG_NUM_MAX; + dbg("Number of lines: [%d]", gslist_line_count); + + for (ctr_loop = 0; ctr_loop < gslist_line_count; ctr_loop++) { + /* Fetch Line 'ctr_loop' */ + gslist_line = (char *)g_slist_nth_data(at_resp->lines, ctr_loop); + dbg("gslist_line [%d] is [%s]", ctr_loop, gslist_line); + + if (NULL != gslist_line) { + GSList *tokens = NULL; + char *line_token = NULL; + + tokens = tcore_at_tok_new(gslist_line); + + line_token = g_slist_nth_data(tokens, 0); + if (NULL != line_token) { + count_info->index_list[ctr_loop] = atoi(line_token); + } + else { + dbg("line_token of gslist_line [%d] is NULL", ctr_loop); + } + + tcore_at_tok_free(tokens); + } + else { + err("gslist_line is NULL"); + goto ERROR; + } + } + + result = TEL_SMS_RESULT_SUCCESS; + } + else { + err("Invalid Response received. No Lines present in Response"); + + /* Check if used count is zero*/ + if (count_info->used_count == 0) + result = TEL_SMS_RESULT_SUCCESS; + } + } + else { + err("RESPONSE NOK"); + } + +ERROR: + /* Invoke callback */ + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, count_info, resp_cb_data->cb_data); + + /* Free callback data */ + imc_destroy_resp_cb_data(resp_cb_data); +} + +static void on_response_imc_sms_get_sms_count(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + gchar *at_cmd; + TelReturn ret; + + TelSmsStoredMsgCountInfo count_info = {0, }; + TelSmsResult result = TEL_SMS_RESULT_FAILURE; + int used_count = 0, total_count = 0; + + const TcoreAtResponse *at_resp = data; + CoreObject *co = tcore_pending_ref_core_object(p); + ImcRespCbData *resp_cb_data = user_data; + ImcRespCbData *getcnt_resp_cb_data; + dbg("Enter"); + + if (at_resp && at_resp->success) { + dbg("RESPONSE OK"); + if (at_resp->lines) { + GSList *tokens = NULL; + char *line = NULL, *line_token = NULL; + + line = (char *)at_resp->lines->data; + dbg("line: [%s]",line); + + /* + * Tokenize + * + * +CPMS: , , , , , + */ + tokens = tcore_at_tok_new(line); + + /* */ + line_token = g_slist_nth_data(tokens, 0); + if (line_token) { + used_count =atoi(line_token); + dbg("used cnt is %d",used_count); + } + else { + err("Line Token for used count is NULL"); + tcore_at_tok_free(tokens); + goto ERROR; + } + + /* */ + line_token = g_slist_nth_data(tokens, 1); + if (line_token) { + total_count = atoi(line_token); + + count_info.total_count = total_count; + count_info.used_count = used_count; + dbg("Count - used: [%d] total: [%d]", used_count, total_count); + + /* + * Operation - get_msg_indices_in_sim + * + * Request - + * AT-Command: AT+CMGL + * +CPMS=[, [,]] + * where + * memory storage to read. + * + * Response - + * Success: (Multi-line output) + * +CMGL=] + * + * status of the message. + * Failure: + * +CMS ERROR: + */ + + /* Sending the Second AT Request to fetch msg indices */ + at_cmd = g_strdup_printf("AT+CMGL=4"); + + /* Response callback data */ + getcnt_resp_cb_data = imc_create_resp_cb_data(resp_cb_data->cb, + resp_cb_data->cb_data, + &count_info, sizeof(TelSmsStoredMsgCountInfo)); + + /* Free previous request callback data */ + imc_destroy_resp_cb_data(resp_cb_data); + + /* Send Request to modem */ + ret = tcore_at_prepare_and_send_request(co, + at_cmd, "+CMGL", + TCORE_AT_COMMAND_TYPE_MULTILINE, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_sms_get_msg_indices, getcnt_resp_cb_data, + on_send_imc_request, NULL, + 0, NULL, NULL); + + /* free the consumed token */ + tcore_at_tok_free(tokens); + g_free(at_cmd); + + IMC_CHECK_REQUEST_RET(ret, getcnt_resp_cb_data, "Get Indices in SIM"); + if (ret != TEL_RETURN_SUCCESS) { + err("Failed to Process Get Msg Indices Request"); + goto ERROR; + } + + dbg("Exit"); + return; + } + else { + err("Line Token for Total count is NULL"); + + /* free the consumed token */ + tcore_at_tok_free(tokens); + goto ERROR; + } + } + else { + err("Invalid Response Received: NO Lines Present"); + } + } + else { + err("RESPONSE NOK"); + } + +ERROR: + /* Invoke callback in case of error*/ + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, NULL, resp_cb_data->cb_data); + + /* Free callback data */ + imc_destroy_resp_cb_data(resp_cb_data); +} + +static void on_response_imc_sms_set_sca(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + CoreObject *co = tcore_pending_ref_core_object(p); + ImcRespCbData *resp_cb_data = user_data; + + TelSmsResult result = TEL_SMS_RESULT_FAILURE; + dbg("Enter"); + + if (at_resp && at_resp->success) { + dbg("Response OK"); + result = TEL_SMS_RESULT_SUCCESS; + } + else { + err("Response NOK"); + } + + /* Invoke callback */ + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, NULL, resp_cb_data->cb_data); + + /* Free callback data */ + imc_destroy_resp_cb_data(resp_cb_data); +} + +static void on_response_imc_sms_get_sca(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + CoreObject *co = tcore_pending_ref_core_object(p); + ImcRespCbData *resp_cb_data = user_data; + + TelSmsSca sca_resp = { 0, }; + TelSmsResult result = TEL_SMS_RESULT_FAILURE; + dbg("Enter"); + + if (at_resp && at_resp->success) { + dbg("Response OK"); + if (at_resp->lines) { + GSList *tokens = NULL; + const char *sca_tok_addr; + gchar *line = NULL, *sca_addr = NULL, *sca_toa = NULL; + + line = (char *)at_resp->lines->data; + tokens = tcore_at_tok_new(line); + sca_tok_addr = g_slist_nth_data(tokens, 0); + sca_toa = g_slist_nth_data(tokens, 1); + + sca_addr = tcore_at_tok_extract(sca_tok_addr); + dbg("SCA: [%s] SCA-TOA: [%s]", sca_addr, sca_toa); + if ((NULL != sca_addr) && (NULL != sca_toa)) { + memcpy(sca_resp.number, sca_addr, strlen(sca_addr)); + + /* Type-of-Address */ + if (145 == atoi(sca_toa)) { + sca_resp.ton = IMC_SIM_TON_INTERNATIONAL; + } + else { + sca_resp.ton = IMC_SIM_TON_NATIONAL; + } + sca_resp.npi = 0;/* TODO */ + result = TEL_SMS_RESULT_SUCCESS; + } + else { + err("SCA is NULL"); + } + tcore_at_tok_free(tokens); + g_free(sca_addr); + } + else { + err("Invalid Response.No Lines Received"); + } + } + else { + err("Response NOK"); + } + + /* Invoke callback */ + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, &sca_resp, resp_cb_data->cb_data); + + /* Free callback data */ + imc_destroy_resp_cb_data(resp_cb_data); +} + +static void on_response_imc_sms_set_cb_config(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + CoreObject *co = tcore_pending_ref_core_object(p); + ImcRespCbData *resp_cb_data = user_data; + + TelSmsResult result = TEL_SMS_RESULT_FAILURE;/*TODO: CME error mapping required */ + dbg("Enter"); + + if (at_resp && at_resp->success) { + dbg("Response OK"); + result = TEL_SMS_RESULT_SUCCESS; + } + else { + err("Response NOK"); + } + + /* Invoke callback */ + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, NULL, resp_cb_data->cb_data); + + /* Free callback data */ + imc_destroy_resp_cb_data(resp_cb_data); +} + +static void on_response_imc_sms_get_cb_config(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + CoreObject *co = tcore_pending_ref_core_object(p); + ImcRespCbData *resp_cb_data = user_data; + + GSList *cb_tokens = NULL; + char *cb_str_token = NULL; + int num_cb_tokens = 0; + char *mid_tok = NULL; + char *first_tok = NULL, *second_tok = NULL; + gint i = 0, mode = 0; + char delim[] = "-"; + + TelSmsCbConfigInfo get_cb_conf = {0, }; + TelSmsResult result = TEL_SMS_RESULT_FAILURE; + dbg("Enter"); + + if (at_resp && at_resp->success) { + dbg("Response OK"); + if (at_resp->lines) { + GSList *tokens = NULL; + char *line_token = NULL, *line = NULL; + line = (char*)at_resp->lines->data; + if (line != NULL) { + tokens = tcore_at_tok_new(line); + /* + * Response - + * +CSCB: ,, + */ + line_token = g_slist_nth_data(tokens, 0); + if (line_token) { + mode = atoi(line_token); + dbg("mode:[%d]", mode); + get_cb_conf.cb_enabled = mode; + } + else { + err("Line Token for Mode is NULL"); + tcore_at_tok_free(tokens); + goto OUT; + } + line_token = g_slist_nth_data(tokens, 1); + if (line_token) { + cb_str_token = tcore_at_tok_extract(line_token); + cb_tokens = tcore_at_tok_new((const char *)cb_str_token); + + num_cb_tokens = g_slist_length(cb_tokens); + dbg("num_cb_tokens = %d", num_cb_tokens); + if (num_cb_tokens == 0) { + if (mode == 1) { /* All CBS Enabled */ + get_cb_conf.msg_id_range_cnt = 1; + get_cb_conf.msg_ids[0].from_msg_id = 0x0000; + get_cb_conf.msg_ids[0].to_msg_id = TEL_SMS_GSM_CBMI_LIST_SIZE_MAX + 1; + get_cb_conf.msg_ids[0].selected = TRUE; + } + else { /* All CBS Disabled */ + get_cb_conf.msg_id_range_cnt = 0; + get_cb_conf.msg_ids[0].selected = FALSE; + } + } + + for(i = 0; i < num_cb_tokens; i++) { + get_cb_conf.msg_ids[i].selected = TRUE; + dbg("msgIdRangeCount:[%d]", get_cb_conf.msg_id_range_cnt); + get_cb_conf.msg_id_range_cnt++; + dbg("Incremented msgIdRangeCount:[%d]", get_cb_conf.msg_id_range_cnt); + + mid_tok = tcore_at_tok_nth(cb_tokens, i); + first_tok = strtok(mid_tok, delim); + second_tok = strtok(NULL, delim); + + if ((first_tok != NULL) && (second_tok != NULL)) {/* mids in range (320-478) */ + get_cb_conf.msg_ids[i].from_msg_id = atoi(first_tok); + get_cb_conf.msg_ids[i].to_msg_id = atoi(second_tok); + } + else {/* single mid value (0,1,5, 922)*/ + get_cb_conf.msg_ids[i].from_msg_id = atoi(mid_tok); + get_cb_conf.msg_ids[i].to_msg_id = atoi(mid_tok); + } + } + } + else { + err("Line Token for MID is NULL"); + tcore_at_tok_free(tokens); + goto OUT; + } + } + else { + err("Line is NULL"); + } + result = TEL_SMS_RESULT_SUCCESS; + tcore_at_tok_free(tokens); + tcore_at_tok_free(cb_tokens); + g_free(cb_str_token); + } + else { + err("Invalid Response.No Lines Received"); + } + } + else { + err("Response NOK"); + } + +OUT: + /* Invoke callback */ + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, &get_cb_conf, resp_cb_data->cb_data); + + /* Free callback data */ + imc_destroy_resp_cb_data(resp_cb_data); +} + +static void on_response_imc_sms_set_memory_status(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + CoreObject *co = tcore_pending_ref_core_object(p); + ImcRespCbData *resp_cb_data = user_data; + + TelSmsResult result = TEL_SMS_RESULT_FAILURE; + dbg("Enter"); + + if (at_resp && at_resp->success) { + dbg("Response OK"); + result = TEL_SMS_RESULT_SUCCESS; + } + else { + err("Response NOK"); + } + + /* Invoke callback */ + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, NULL, resp_cb_data->cb_data); + + /* Free callback data */ + imc_destroy_resp_cb_data(resp_cb_data); +} + +static void on_response_imc_sms_set_message_status(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + CoreObject *co = tcore_pending_ref_core_object(p); + ImcRespCbData *resp_cb_data = user_data; + + TelSmsResult result = TEL_SMS_RESULT_FAILURE; + int response = 0, sw1 = 0, sw2 = 0; + const char *line = NULL; + char *line_token = NULL; + GSList *tokens = NULL; + dbg("Enter"); + + if (at_resp && at_resp->success) { + dbg("RESPONSE OK"); + if (at_resp->lines) { + line = (const char *) at_resp->lines->data; + tokens = tcore_at_tok_new(line); + line_token = g_slist_nth_data(tokens, 0); + if (line_token != NULL) { + sw1 = atoi(line_token); + } + else { + dbg("sw1 is NULL"); + } + line_token = g_slist_nth_data(tokens, 1); + if (line_token != NULL) { + sw2 = atoi(line_token); + if ((sw1 == 0x90) && (sw2 == 0)) { + result = TEL_SMS_RESULT_SUCCESS; + } + } + else { + dbg("sw2 is NULL"); + } + line_token = g_slist_nth_data(tokens, 3); + + if (line_token != NULL) { + response = atoi(line_token); + dbg("response is %s", response); + } + tcore_at_tok_free(tokens); + } + else { + dbg("No lines"); + } + } + else { + err("RESPONSE NOK"); + } + + /* Invoke callback */ + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, NULL, resp_cb_data->cb_data); + + /* Free callback data */ + imc_destroy_resp_cb_data(resp_cb_data); +} + +static void _response_get_efsms_data(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + gchar *at_cmd; + const TcoreAtResponse *at_resp = data; + CoreObject *co = tcore_pending_ref_core_object(p); + ImcRespCbData *resp_cb_data = user_data; + + TelSmsStatusInfo *status_info; + TelSmsResult result = TEL_SMS_RESULT_FAILURE; + TelReturn ret; + + char *encoded_data = NULL; + int encoded_len = 0; + char msg_status = 0; + char *line_token = NULL; + GSList *tokens=NULL; + const char *line = NULL; + int sw1 = 0; + int sw2 = 0; + dbg("Enter"); + + status_info = (TelSmsStatusInfo *)IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data); + if (at_resp && at_resp->success) { + dbg("RESPONSE OK"); + if (at_resp->lines) { + dbg("Entry:lines Ok"); + line = (const char *) at_resp->lines->data; + tokens = tcore_at_tok_new(line); + + sw1 = atoi(g_slist_nth_data(tokens, 0)); + sw2 = atoi(g_slist_nth_data(tokens, 1)); + line_token = g_slist_nth_data(tokens, 2); + + dbg("line_token:[%s], Length of line token:[%d]", line_token, strlen(line_token)); + + if ((sw1 == 0x90 && sw2 == 0x00) || sw1 == 0x91) { + switch (status_info->status) { + case TEL_SMS_STATUS_MT_READ: + msg_status = 0x01; + break; + + case TEL_SMS_STATUS_MT_UNREAD: + msg_status = 0x03; + break; + + case TEL_SMS_STATUS_MO_NOT_SENT: + msg_status = 0x07; + break; + + case TEL_SMS_STATUS_MO_SENT: + msg_status = 0x05; + break; + + case TEL_SMS_STATUS_MO_DELIVERED: + msg_status = 0x1D; + break; + + case TEL_SMS_STATUS_MO_DELIVERY_NOT_CONFIRMED: + msg_status = 0xD; + break; + + case TEL_SMS_STATUS_REPLACED:/*Fall Through*/ + default: + msg_status = 0x03; + break; + } + } + encoded_len = strlen(line_token); + dbg("Encoded data length:[%d]", encoded_len); + + encoded_data = tcore_malloc0(2*encoded_len + 1); + + memcpy(encoded_data, line_token, encoded_len); + dbg("encoded_data: [%s]", encoded_data); + + /* overwrite Status byte information */ + tcore_util_byte_to_hex((const char *)&msg_status, encoded_data, 1); + + /* + * Updating EF-SMS File with status byte + * Rest 175 bytes are same as received in Read Record + * + */ + at_cmd = g_strdup_printf("AT+CRSM=220,28476,%d, 4, %d, \"%s\"", + (status_info->index), IMC_AT_EF_SMS_RECORD_LEN, encoded_data); + + /* Send Request to modem */ + ret = tcore_at_prepare_and_send_request(co, + at_cmd, "+CRSM:", + TCORE_AT_COMMAND_TYPE_SINGLELINE, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_sms_set_message_status, resp_cb_data, + on_send_imc_request, NULL, + 0, NULL, NULL); + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, + "Set Message Status-Updating status in Record"); + + g_free(encoded_data); + g_free(status_info); + tcore_at_tok_free(tokens); + return; + } + else { + err("Invalid Response Received"); + } + } + else { + err("Response NOK"); + } + + /* Invoke callback */ + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, NULL, resp_cb_data->cb_data); + + /* Free callback data */ + imc_destroy_resp_cb_data(resp_cb_data); +} + +static void on_response_imc_sms_get_sms_params(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + CoreObject *co = tcore_pending_ref_core_object(p); + ImcRespCbData *resp_cb_data = user_data; + ImcSmsParamsCbData *params_req_data; + gint sw1 = 0, sw2 = 0, decoding_length = 0; + const char *line = NULL; + char *hex_data = NULL, *record_data = NULL; + GSList *tokens = NULL; + + TelSmsResult result = TEL_SMS_RESULT_FAILURE; + dbg("Enter"); + + params_req_data = (ImcSmsParamsCbData *)IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data); + + if (at_resp && at_resp->success) { + dbg("RESPONSE OK"); + if (at_resp->lines) { + line = (const char *) at_resp->lines->data; + tokens = tcore_at_tok_new(line); + + sw1 = atoi(g_slist_nth_data(tokens, 0)); + sw2 = atoi(g_slist_nth_data(tokens, 1)); + dbg("sw1 [0x%x], sw2[0x%x]", sw1, sw2); + + if (!(sw1 == 0x90 && sw2 == 0x00) || sw1 == 0x91) { + err("invalid response received"); + goto OUT; + } + + hex_data = g_slist_nth_data(tokens, 2); + if (hex_data == NULL) { + err("invalid response received"); + goto OUT; + } + + tcore_util_hexstring_to_bytes(hex_data, &record_data, (guint*)&decoding_length); + /* + * Decrementing the Record Count and Filling the ParamsInfo List + * Final Response will be posted when Record count is ZERO + */ + params_req_data->params[params_req_data->index].index = params_req_data->index; + + tcore_util_decode_sms_parameters((unsigned char *)record_data, + decoding_length, + ¶ms_req_data->params[params_req_data->index]); + + params_req_data->total_param_count -= 1; + + if (params_req_data->total_param_count == 0) { + dbg("Reading all Records - Complete"); + result = TEL_SMS_RESULT_SUCCESS; + goto OUT; + } else { + dbg("Reading all records incomplete [%d - Pending]", + params_req_data->total_param_count); + tcore_at_tok_free(tokens); + return; + } + } else { + err("Invalid Response Received"); + } + } else { + err("RESPONSE NOK"); + } + +OUT: + { + TelSmsParamsInfoList param_info_list = {0, }; + + if (result == TEL_SMS_RESULT_SUCCESS) { + param_info_list.params = params_req_data->params; + param_info_list.count = params_req_data->count; + } + + /* Invoke callback */ + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, (void *)¶m_info_list, resp_cb_data->cb_data); + } + + /* Free resource */ + tcore_at_tok_free(tokens); + + tcore_free(params_req_data->params); + g_free(record_data); + + /* Free callback data */ + imc_destroy_resp_cb_data(resp_cb_data); +} + +static void on_response_imc_sms_set_sms_params(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + CoreObject *co = tcore_pending_ref_core_object(p); + ImcRespCbData *resp_cb_data = user_data; + + TelSmsResult result = TEL_SMS_RESULT_FAILURE; + gint sw1 = 0 , sw2 = 0; + const char *line = NULL; + GSList *tokens=NULL; + dbg("Enter"); + + if (at_resp && at_resp->success) { + dbg("Response OK"); + if (at_resp->lines) { + line = (const char *) at_resp->lines->data; + tokens = tcore_at_tok_new(line); + + sw1 = atoi(g_slist_nth_data(tokens, 0)); + sw2 = atoi(g_slist_nth_data(tokens, 1)); + + if ((sw1 == 0x90 && sw2 == 0x00) || sw1 == 0x91) { + result = TEL_SMS_RESULT_SUCCESS; + } + else { + result = TEL_SMS_RESULT_FAILURE; + } + } + tcore_at_tok_free(tokens); + } else { + err("Response NOK"); + } + + /* Invoke callback */ + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, NULL, resp_cb_data->cb_data); + + /* Free callback data */ + imc_destroy_resp_cb_data(resp_cb_data); +} + +static gboolean async_callback(gpointer data) +{ + ImcRespCbData *resp_cb_data = data; + CoreObject **co; + TelSmsResult result = TEL_SMS_RESULT_SUCCESS; + + co = ((CoreObject **)IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data)); + + /* Invoke callback */ + if (resp_cb_data->cb) + resp_cb_data->cb(*co, (gint)result, NULL, resp_cb_data->cb_data); + + /* Free callback data */ + imc_destroy_resp_cb_data(resp_cb_data); + + return FALSE; +} + +/* SMS Operations */ +/* + * Operation - send_sms + * + * Request - + * AT-Command: AT+CMGS + * For PDU mode (+CMGF=0): + * +CMGS= + * PDU is given + * where, + * Length of the pdu. + * PDU to send. + * + * Response - + *+CMGS: [,] + * OK + * Failure: + * +CMS ERROR: + */ +static TelReturn imc_sms_send_sms(CoreObject *co, + const TelSmsSendInfo *send_info, TcoreObjectResponseCallback cb, void *cb_data) +{ + gchar *at_cmd; + + ImcRespCbData *resp_cb_data; + TelReturn ret; + + const unsigned char *tpdu_byte_data; + gint tpdu_byte_len, pdu_byte_len; + char buf[HEX_PDU_LEN_MAX]; + char pdu[PDU_LEN_MAX]; + dbg("Enter"); + + tpdu_byte_data = send_info->send_data.tpdu; + + /* TPDU length is in byte */ + tpdu_byte_len = send_info->send_data.tpdu_length; + + /* Use same Radio Resource Channel :More Messages to send*/ + dbg("More messages: [%d]", send_info->more_msgs); + + /* Prepare PDU for hex encoding */ + pdu_byte_len = tcore_util_encode_pdu(&(send_info->send_data.sca), + tpdu_byte_data, tpdu_byte_len, pdu); + tcore_util_hex_dump(" ", pdu_byte_len, pdu); + + tcore_util_encode_hex((unsigned char *)pdu, pdu_byte_len, buf); + + /* Response callback data */ + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, NULL, 0); + + if (send_info->more_msgs == TRUE) { + /* AT Command: More Msgs to Send */ + ret = tcore_at_prepare_and_send_request(co, + "AT+CMMS=1", "+CMMS:", + TCORE_AT_COMMAND_TYPE_SINGLELINE, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_sms_send_more_msg, NULL, + on_send_imc_request, NULL, + 0, NULL, NULL); + IMC_CHECK_REQUEST_RET(ret, NULL, "More Msgs to Send"); + } + + /* AT-Command : Send SMS*/ + at_cmd = g_strdup_printf("AT+CMGS=%d\r%s\x1A", tpdu_byte_len, buf); + + /* Send Request to modem */ + ret = tcore_at_prepare_and_send_request(co, + at_cmd, "+CMGS:", + TCORE_AT_COMMAND_TYPE_SINGLELINE, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_sms_send_sms, resp_cb_data, + on_send_imc_request, NULL, + 0, NULL, NULL); + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Send SMS"); + + /* Free resources */ + g_free(at_cmd); + + return ret; +} + +/* + * Operation - write_sms_in_sim + * + * Request - + * AT-Command: AT+CMGW + * AT+CMGW = [,]PDU is given + * where + * length of the tpdu + * status of the message + * PDu of the message + * + * Response - + * +CMGW: + * Success: (Single line) + * OK + * Failure: + * +CMS ERROR: + */ +static TelReturn imc_sms_write_sms_in_sim(CoreObject *co, + const TelSmsSimDataInfo *wdata, TcoreObjectResponseCallback cb, void *cb_data) +{ + gchar *at_cmd; + + ImcRespCbData *resp_cb_data; + TelReturn ret; + + const unsigned char *tpdu_byte_data; + int tpdu_byte_len, pdu_byte_len; + char buf[HEX_PDU_LEN_MAX]; + char hex_pdu[PDU_LEN_MAX]; + gint status = 0; + dbg("Enter"); + + switch (wdata->status) { + case TEL_SMS_STATUS_MT_UNREAD: + status = AT_MT_UNREAD; + break; + + case TEL_SMS_STATUS_MT_READ: + status = AT_MT_READ; + break; + + case TEL_SMS_STATUS_MO_NOT_SENT: + status = AT_MO_UNSENT; + break; + + case TEL_SMS_STATUS_MO_SENT: + status = AT_MO_SENT; + break; + + default: + err("Invalid Message Status"); + return TEL_RETURN_INVALID_PARAMETER; + } + tpdu_byte_data = wdata->data.tpdu; + + tpdu_byte_len = wdata->data.tpdu_length; + dbg("TDPU length: [%d]", tpdu_byte_len); + + /* Prepare PDU for hex encoding */ + pdu_byte_len = tcore_util_encode_pdu(&(wdata->data.sca), + tpdu_byte_data, tpdu_byte_len, hex_pdu); + tcore_util_hex_dump(" ", pdu_byte_len, hex_pdu); + + tcore_util_encode_hex((unsigned char *)hex_pdu, pdu_byte_len, buf); + + /*AT Command*/ + at_cmd = g_strdup_printf("AT+CMGW=%d,%d%c%s%c", + tpdu_byte_len, status, CR, buf, CTRL_Z); + + /* Response callback data */ + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, NULL, 0); + + /* Send Request to modem */ + ret = tcore_at_prepare_and_send_request(co, + at_cmd, "+CMGW:", + TCORE_AT_COMMAND_TYPE_SINGLELINE, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_sms_write_sms_in_sim, resp_cb_data, + on_send_imc_request, NULL, + 0, NULL, NULL); + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Write SMS in SIM"); + + /* Free resources */ + g_free(at_cmd); + + return ret; +} + +/* + * Operation - read_sms_in_sim + * + * Request - + * AT-Command: At+CMGR= + * where + * index of the message to be read. + * + * Response - + * Success: (PDU: Multi-line output) + * +CMGR: ,[], + * + * Failure: + * +CMS ERROR: + */ +static TelReturn imc_sms_read_sms_in_sim(CoreObject *co, + unsigned int index, TcoreObjectResponseCallback cb, void *cb_data) +{ + gchar *at_cmd; + + ImcRespCbData *resp_cb_data; + TelReturn ret; + dbg("Enter"); + + /* AT+Command */ + at_cmd = g_strdup_printf("AT+CMGR=%d", index); + + /* Response callback data */ + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, NULL, ZERO); + + /* Send Request to modem */ + ret = tcore_at_prepare_and_send_request(co, + at_cmd, "+CMGR:", + TCORE_AT_COMMAND_TYPE_PDU, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_sms_read_sms_in_sim, resp_cb_data, + on_send_imc_request, NULL, + 0, NULL, NULL); + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Read SMS in SIM"); + + /* Free resources */ + g_free(at_cmd); + + return ret; +} + +/* + * Operation - delete_sms_in_sim + * + * Request - + * AT-Command: AT+CGMD + * +CMGD=[,] + * + * Response - + * Success: (NO RESULT) - + * OK + * Failure: + * +CMS ERROR: + */ +static TelReturn imc_sms_delete_sms_in_sim(CoreObject *co, + unsigned int index, + TcoreObjectResponseCallback cb, void *cb_data) +{ + gchar *at_cmd; + + ImcRespCbData *resp_cb_data; + TelReturn ret; + dbg("Enter"); + + /* Response callback data */ + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, NULL, 0); + /* + * TODO: Delete All Messages + * + * at_cmd = g_strdup_printf("AT+CMGD=0,4"); + * Need to convey MSG_SERVICE to pass an index of + * guint value to delete all Messages.probably as 0. + */ + + /* AT-Command */ + at_cmd = g_strdup_printf("AT+CMGD=%d,0", index); /*Delete specified index*/ + + /* Send Request to modem */ + ret = tcore_at_prepare_and_send_request(co, + at_cmd, "+CMGD:", + TCORE_AT_COMMAND_TYPE_NO_RESULT, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_sms_delete_sms_in_sim, resp_cb_data, + on_send_imc_request, NULL, + 0, NULL, NULL); + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Delete SMS in SIM"); + + /* Free resources */ + g_free(at_cmd); + + return ret; +} + +/* + * Operation - get_sms_count_in_sim + * + * Request - + * AT-Command: AT+CPMS + * +CPMS=[, [,]] + * where + * memory storage to read. + * + * Response - + * Success: (Single-line output) + * +CPMS: ,,,,,, + * ,, + * OK + * + * Failure: + * +CMS ERROR: + */ +static TelReturn imc_sms_get_msg_count_in_sim(CoreObject *co, + TcoreObjectResponseCallback cb, void *cb_data) +{ + gchar *at_cmd; + + ImcRespCbData *resp_cb_data; + TelReturn ret; + dbg("Enter"); + + /*AT Command*/ + at_cmd = g_strdup_printf("AT+CPMS=\"SM\""); + + /* Response callback data */ + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, NULL, 0); + + /* Send Request to modem */ + ret = tcore_at_prepare_and_send_request(co, + at_cmd, "+CPMS", + TCORE_AT_COMMAND_TYPE_SINGLELINE, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_sms_get_sms_count, resp_cb_data, + on_send_imc_request, NULL, + 0, NULL, NULL); + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Get SMS Count"); + + /* Free resources */ + g_free(at_cmd); + + return ret; +} + +/* + * Operation - set SCA + * + * Request - + * AT-Command: AT+CSCA + * AT+CSCA=[,] + * where + * Service center number + * address type of SCA + * + * Response - + * Success: No result + * OK + * + * Failure: + * +CMS ERROR: + */ + static TelReturn imc_sms_set_sca(CoreObject *co, + const TelSmsSca *sca, TcoreObjectResponseCallback cb, void *cb_data) +{ + gchar *at_cmd; + + ImcRespCbData *resp_cb_data; + TelReturn ret; + gint address_type; + + address_type = ((sca->ton << 4) | sca->npi ) | 0x80; + + /* AT Command */ + at_cmd = g_strdup_printf("AT+CSCA=\"%s\",%d", sca->number, address_type); + + /* Response callback data */ + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, NULL, 0); + + /* Send Request to modem */ + ret = tcore_at_prepare_and_send_request(co, + at_cmd, NULL, + TCORE_AT_COMMAND_TYPE_NO_RESULT, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_sms_set_sca, resp_cb_data, + on_send_imc_request, NULL, + 0, NULL, NULL); + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Set SCA"); + + /* Free resources */ + g_free(at_cmd); + + return ret; +} + +/* + * Operation - get SCA + * + * Request - + * AT-Command: AT+CSCA? + * + * Response - + * Success: Single-Line + * +CSCA: , + * OK + * where + * Service center number + * address type of SCA + * + */ + static TelReturn imc_sms_get_sca(CoreObject *co, + TcoreObjectResponseCallback cb, void *cb_data) +{ + gchar *at_cmd; + + ImcRespCbData *resp_cb_data; + TelReturn ret; + dbg("Enter"); + + /* AT Command */ + at_cmd = g_strdup_printf("AT+CSCA?"); + + /* Response callback data */ + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, NULL, 0); + + /* Send Request to modem */ + ret = tcore_at_prepare_and_send_request(co, + at_cmd, "+CSCA", + TCORE_AT_COMMAND_TYPE_SINGLELINE, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_sms_get_sca, resp_cb_data, + on_send_imc_request, NULL, + 0, NULL, NULL); + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Get SCA"); + + /* Free resources */ + g_free(at_cmd); + + return ret; +} + +/* + * Operation - set_cb_config + * + * Request - + * AT-Command: AT+CSCB + * +CSCB=[[,[,]]] + * + * Response - + * Success + * OK + * + * Failure: + * +CME ERROR: + */ +static TelReturn imc_sms_set_cb_config(CoreObject *co, + const TelSmsCbConfigInfo *cb_conf, + TcoreObjectResponseCallback cb, void *cb_data) +{ + gchar *at_cmd; + + ImcRespCbData *resp_cb_data; + TelReturn ret; + + unsigned short ctr1 = 0, ctr2 = 0, msg_id_range = 0; + unsigned short append_msg_id = 0; + dbg("Enter"); + + if (cb_conf->msg_id_range_cnt != 0) { /* Enable Specific Msgid's */ + gchar *mids_str = NULL; + GString *mid_string = NULL; + at_cmd = NULL; + + mid_string = g_string_new("AT+CSCB=0,\""); + for(ctr1 = 0; ctr1 < cb_conf->msg_id_range_cnt; ctr1++) { + if (cb_conf->msg_ids[ctr1].selected == FALSE) + continue; + msg_id_range = ((cb_conf->msg_ids[ctr1].to_msg_id) - (cb_conf->msg_ids[ctr1].from_msg_id)); + + if (TEL_SMS_GSM_CBMI_LIST_SIZE_MAX <= msg_id_range) { + mid_string = g_string_new("AT+CSCB=1"); /* Enable All CBS */ + break; + } + append_msg_id = cb_conf->msg_ids[ctr1].from_msg_id; + dbg( "%x", append_msg_id); + + for(ctr2 = 0; ctr2 <= msg_id_range; ctr2++) { + mid_string = g_string_append(mid_string, g_strdup_printf("%d", append_msg_id)); + if (ctr2 == msg_id_range) { + mid_string = g_string_append(mid_string, "\""); /*Mids string termination*/ + } + else { + mid_string = g_string_append(mid_string, ","); + } + append_msg_id++; + } + } + mids_str = g_string_free(mid_string, FALSE); + at_cmd = g_strdup_printf("%s", mids_str); + g_free(mids_str); + } + else { + at_cmd = g_strdup_printf("AT+CSCB=%d", cb_conf->cb_enabled); /* Enable or Disable MsgId's */ + } + + /* Response callback data */ + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, NULL, 0); + + /* Send Request to modem */ + ret = tcore_at_prepare_and_send_request(co, + at_cmd, NULL, + TCORE_AT_COMMAND_TYPE_NO_RESULT, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_sms_set_cb_config, resp_cb_data, + on_send_imc_request, NULL, + 0, NULL, NULL); + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Set Cb Config"); + + /* Free resources */ + g_free(at_cmd); + + return ret; +} + +/* + * Operation - get_cb_config + * + * Request - + * AT-Command: AT+CSCB + * +CSCB? + * + * Response - + * Success - (Single line) + * +CSCB : ,, + * OK + * + */ + static TelReturn imc_sms_get_cb_config(CoreObject *co, + TcoreObjectResponseCallback cb, void *cb_data) +{ + gchar *at_cmd; + + ImcRespCbData *resp_cb_data; + TelReturn ret; + dbg("Enter"); + + /* AT Command */ + at_cmd = g_strdup_printf("AT+CSCB?"); + + /* Response callback data */ + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, NULL, 0); + + /* Send Request to modem */ + ret = tcore_at_prepare_and_send_request(co, + at_cmd, NULL, + TCORE_AT_COMMAND_TYPE_SINGLELINE, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_sms_get_cb_config, resp_cb_data, + on_send_imc_request, NULL, + 0, NULL, NULL); + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Get Cb Config"); + + /* Free resources */ + g_free(at_cmd); + + return ret; +} + +/* + * Operation - send_deliver_report + * + * Request - + * Modem Takes care of sending the ACK to the network + * + * Response - + * Success: Default response always SUCCESS posted + * + */ +static TelReturn imc_sms_send_deliver_report(CoreObject *co, + const TelSmsDeliverReportInfo *dr_info, + TcoreObjectResponseCallback cb, void *cb_data) +{ + ImcRespCbData *resp_cb_data; + TelReturn ret = TEL_RETURN_FAILURE; + + dbg("CP takes care of sending SMS ack to network for all " + "classes of SMS. Sending default success.!!!"); + ret = TEL_RETURN_SUCCESS; + + /* Response callback data */ + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, + (void *)&co, sizeof(CoreObject*)); + + g_idle_add(async_callback, (gpointer)resp_cb_data); + + return ret; +} + + +/* Operation - set memory status + * + * Request - + * AT-Command: AT+XTESM= + * status of the external SMS storage which may be: + * 0: memory capacity free + * 1: memory capacity full + * + * Response -No Result + * Success + * OK + * + * Failure: + * +CME ERROR: + */ +static TelReturn imc_sms_set_memory_status(CoreObject *co, + gboolean available, TcoreObjectResponseCallback cb, void *cb_data) +{ + gchar *at_cmd; + + ImcRespCbData *resp_cb_data; + TelReturn ret; + + /*AT+Command*/ + at_cmd = g_strdup_printf("AT+XTESM=%d", available? 0: 1); + + /* Response callback data */ + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, NULL, 0); + + /* Send Request to modem */ + ret = tcore_at_prepare_and_send_request(co, + at_cmd, NULL, + TCORE_AT_COMMAND_TYPE_NO_RESULT, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_sms_set_memory_status, resp_cb_data, + on_send_imc_request, NULL, + 0, NULL, NULL); + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Set Memory Status"); + + /* Free resources */ + g_free(at_cmd); + + return ret; +} + +/* Operation - set Message status + * + * Request - + * AT-Command: AT+CRSM= command>[,[,,,[,[,]]]] + * p1 Index + * p3 SMSP record length + * + * + * Response -Single Line + * Success + * OK + * + * Failure: + * +CME ERROR: + */ +static TelReturn imc_sms_set_message_status(CoreObject *co, + const TelSmsStatusInfo *status_info, + TcoreObjectResponseCallback cb, void *cb_data) +{ + gchar *at_cmd; + + ImcRespCbData *resp_cb_data; + TelReturn ret; + + /*AT+Command*/ + at_cmd = g_strdup_printf("AT+CRSM=178,28476,%d,4,%d", + (status_info->index), IMC_AT_EF_SMS_RECORD_LEN); + + /* Response callback data */ + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, + (void *)status_info, sizeof(TelSmsStatusInfo)); + + /* Send Request to modem */ + ret = tcore_at_prepare_and_send_request(co, + at_cmd, "+CRSM:", + TCORE_AT_COMMAND_TYPE_SINGLELINE, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + _response_get_efsms_data, resp_cb_data, + on_send_imc_request, NULL, + 0, NULL, NULL); + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Set Message Status"); + + /* Free resources */ + g_free(at_cmd); + + return ret; +} + +/* + * Operation - get_sms_parameters + * + * Request - + * AT-Command: AT+CRSM + * AT+CRSM= command>[,[,,,[,[,]]]] + * + * Response - + * Success: (Single-line output) + * +CRSM: + * ,[,] + * OK + * + * Failure: + * +CME ERROR: + */ +static TelReturn imc_sms_get_sms_params(CoreObject *co, + TcoreObjectResponseCallback cb, void *cb_data) +{ + TcorePlugin *plugin; + ImcRespCbData *resp_cb_data; + ImcSmsParamsCbData params_req_data = {0, }; + gint loop_count, record_count = 0, smsp_record_len = 0; + TelReturn ret = TEL_RETURN_INVALID_PARAMETER; + + dbg("Enter"); + + plugin = tcore_object_ref_plugin(co); + + /* Get Record count and SMSP record length*/ + if (FALSE == (imc_sim_get_smsp_info(plugin, &record_count, + &smsp_record_len))) { + err("Failed to get SMSP record Count and Record length"); + return ret; + } + + dbg("Record Count: [%d] SMSP Record Length: [%d]", + record_count, smsp_record_len); + + /* Allocate Memory for params list data */ + params_req_data.params = tcore_malloc0(sizeof(TelSmsParamsInfo) * record_count); + /* Counter */ + params_req_data.total_param_count = record_count; + /* Saving actual count to be returned */ + params_req_data.count = record_count; + /* Response callback data */ + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, + (void *)¶ms_req_data, + sizeof(ImcSmsParamsCbData)); + + for (loop_count = 1; loop_count <= record_count; loop_count++) { + gchar *at_cmd; + + /* Updating the Index */ + params_req_data.index = loop_count; + /* AT-Command */ + at_cmd = g_strdup_printf("AT+CRSM=178,28482,%d,4,%d", + params_req_data.index, smsp_record_len); + + /* Send Request to modem */ + ret = tcore_at_prepare_and_send_request(co, + at_cmd, "+CRSM", + TCORE_AT_COMMAND_TYPE_SINGLELINE, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_sms_get_sms_params, resp_cb_data, + on_send_imc_request, NULL, + 0, NULL, NULL); + + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Get SMS Parameters"); + + /* Free resources */ + if (ret != TEL_RETURN_SUCCESS) + tcore_free(params_req_data.params); + g_free(at_cmd); + } + + return ret; +} + +/* + * Operation - set_sms_params + * + * Request - + * AT-Command: AT+CRSM + * AT+CRSM= command>[,[,,,[,[,]]]] + * + * Response - + * Success: (Single-line output) + * +CRSM: + * ,[,] + * OK + * + * Failure: + * +CME ERROR: + */ +static TelReturn imc_sms_set_sms_params(CoreObject *co, + const TelSmsParamsInfo *params, + TcoreObjectResponseCallback cb, void *cb_data) +{ + gchar *at_cmd; + ImcRespCbData *resp_cb_data; + TelReturn ret; + + TcorePlugin *plugin; + gint smsp_record_len = 0; + gchar *set_params_data = NULL; + gchar *encoded_data = NULL; + gint record_count; + dbg("Enter"); + + plugin = tcore_object_ref_plugin(co); + + if (FALSE == imc_sim_get_smsp_info(plugin, &record_count, &smsp_record_len)) { + err("Failed to get SMSP record Count and Record length"); + return TEL_RETURN_INVALID_PARAMETER; + } + + dbg("SMSP Record Length: [%d]", smsp_record_len); + + /* Allocate memory for set_params_data */ + set_params_data = tcore_malloc0(sizeof(smsp_record_len)); + + /* Allocate memory for encoded data*/ + encoded_data = tcore_malloc0((2 * sizeof(smsp_record_len)+1)); + + tcore_util_encode_sms_parameters((TelSmsParamsInfo *)params, + set_params_data, smsp_record_len); + + tcore_util_byte_to_hex((const char *)set_params_data, + (char *)encoded_data, smsp_record_len); + + /* Response callback data */ + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, NULL, sizeof(gint)); + + /* AT+ Command*/ + at_cmd = g_strdup_printf("AT+CRSM=220,28482,%d,4,%d,\"%s\"", + params->index, smsp_record_len, encoded_data); + dbg("at_cmd - %s", at_cmd); + /* Send Request to modem */ + ret = tcore_at_prepare_and_send_request(co, + at_cmd, "+CRSM", + TCORE_AT_COMMAND_TYPE_SINGLELINE, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_sms_set_sms_params, resp_cb_data, + on_send_imc_request, NULL, + 0, NULL, NULL); + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Set SMS Parameters"); + + /* Free resources */ + g_free(at_cmd); + g_free(set_params_data); + g_free(encoded_data); + + return ret; +} + +/* SMS Operations */ +static TcoreSmsOps imc_sms_ops = { + .send_sms = imc_sms_send_sms, + .read_in_sim = imc_sms_read_sms_in_sim, + .write_in_sim = imc_sms_write_sms_in_sim, + .delete_in_sim = imc_sms_delete_sms_in_sim, + .get_count = imc_sms_get_msg_count_in_sim, + .set_cb_config = imc_sms_set_cb_config, + .get_cb_config = imc_sms_get_cb_config, + .get_parameters = imc_sms_get_sms_params, + .set_parameters = imc_sms_set_sms_params, + .send_deliver_report = imc_sms_send_deliver_report, + .set_sca = imc_sms_set_sca, + .get_sca = imc_sms_get_sca, + .set_memory_status = imc_sms_set_memory_status, + .set_message_status = imc_sms_set_message_status +}; + +gboolean imc_sms_init(TcorePlugin *p, CoreObject *co) +{ + dbg("Entry"); + + /* Set operations */ + tcore_sms_set_ops(co, &imc_sms_ops); + + /* Add Callbacks */ + tcore_object_add_callback(co, "\e+CMT:", + on_notification_imc_sms_incoming_msg, NULL); + tcore_object_add_callback(co, "\e+CDS", + on_notification_imc_sms_incoming_msg, NULL); + + tcore_object_add_callback(co, "\e+CBM", + on_notification_imc_sms_cb_incom_msg, NULL); + tcore_object_add_callback(co, "+CMTI", + on_notification_imc_sms_class2_incoming_msg, NULL); + + /* + * Notification + * TODO - AT Command Description Not available + */ + tcore_object_add_callback(co, "+XSMSMMSTAT", + on_notification_imc_sms_memory_status, NULL); + + dbg("Exit"); + return TRUE; +} + +void imc_sms_exit(TcorePlugin *p, CoreObject *co) +{ + dbg("Exit"); +} diff --git a/src/imc_ss.c b/src/imc_ss.c new file mode 100644 index 0000000..ac5b876 --- /dev/null +++ b/src/imc_ss.c @@ -0,0 +1,1725 @@ +/* + * tel-plugin-imc + * + * Copyright (c) 2013 Samsung Electronics Co. Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "imc_ss.h" +#include "imc_common.h" + +/* AT+CUSD = [ [, [, ]]] + * where, + * + * 0 Disable + * 1 Enable + * 2 Cancel the session + * + * + * Ussd string + * + * + * Decoding format + */ +static gboolean on_notification_imc_ss_ussd(CoreObject *co, const void *event_data, void *user_data) +{ + gchar *cmd = 0; + gchar *resp_str = NULL; + guchar *dcs_str = NULL; + TelUtilAlphabetFormat dcs = TEL_UTIL_ALPHABET_FORMAT_SMS_DEFAULT; + gushort len; + GSList *tokens = NULL; + GSList *lines = NULL; + int ussd_status = 0; + TelSsUssdNoti ussd_noti = {0,}; + + lines = (GSList *) event_data; + + if (g_slist_length(lines) != 1) { + dbg("Unsolicited message but multiple lines"); + return TRUE; + } + + cmd = (char *) (lines->data); + tokens = tcore_at_tok_new(cmd); + + /* Parse USSD status */ + resp_str = g_slist_nth_data(tokens, 0); + if (NULL == resp_str) { + err("status is missing from %CUSD Notification"); + tcore_at_tok_free(tokens); + return TRUE; + } else { + ussd_status = atoi(resp_str); + dbg("USSD status[%d]", ussd_status); + + if (ussd_status < TEL_SS_USSD_STATUS_NO_ACTION_REQUIRED || + ussd_status > TEL_SS_USSD_STATUS_TIME_OUT) { + err("invalid USSD status"); + tcore_at_tok_free(tokens); + return TRUE; + } + + /* When network terminated the USSD session, no need to send notification to application */ + if (ussd_status == TEL_SS_USSD_STATUS_TERMINATED_BY_NETWORK) { + /* destroy USSD session if any */ + UssdSession *ussd_session; + ussd_session = tcore_ss_ussd_get_session(co); + + if (ussd_session) + tcore_ss_ussd_destroy_session(ussd_session); + + tcore_at_tok_free(tokens); + return TRUE; + } + + /* Parse USSD string */ + resp_str = g_slist_nth_data(tokens, 1); + + resp_str = tcore_at_tok_extract(resp_str); + if (resp_str) { + len = strlen((gchar *)resp_str); + dbg("USSD String: [%s], len: [%d]", resp_str, len); + } else { + dbg("Ussd strings is missing from %CUSD Notification"); + tcore_at_tok_free(tokens); + return TRUE; + } + + dcs_str = g_slist_nth_data(tokens, 2); + } + + if (dcs_str) { + dcs = tcore_util_get_cbs_coding_scheme(atoi((gchar *)dcs_str)); + } else { + warn("No dcs string. Using default dcs value"); + } + + ussd_noti.str = tcore_malloc0(len+1); + + if ((tcore_util_convert_str_to_utf8(ussd_noti.str, &len, dcs, + (const guchar *)resp_str, len+1)) == FALSE) { + /* In case of Unhandled dcs type(Reserved), ussd string to ussd_noti.str */ + memcpy(ussd_noti.str, resp_str, len); + } + + dbg("ussd_noti.str[%s]", ussd_noti.str); + + ussd_noti.status = ussd_status; + + tcore_object_send_notification(co, + TCORE_NOTIFICATION_SS_USSD, + sizeof(TelSsUssdNoti), (void *)&ussd_noti); + + tcore_at_tok_free(tokens); + tcore_free(resp_str); + tcore_free(ussd_noti.str); + + return TRUE; +} + +static gboolean __imc_ss_convert_modem_class_to_class(gint classx, TelSsClass *class) +{ + switch(classx) + { + case 7: + *class = TEL_SS_CLASS_ALL_TELE; + break; + + case 1: + *class = TEL_SS_CLASS_VOICE; + break; + + case 2: + *class = TEL_SS_CLASS_ALL_DATA_TELE; + break; + + case 4: + *class = TEL_SS_CLASS_FAX; + break; + + case 8: + *class = TEL_SS_CLASS_SMS; + break; + + case 16: + *class = TEL_SS_CLASS_ALL_CS_SYNC; + break; + + case 32: + *class = TEL_SS_CLASS_ALL_CS_ASYNC; + break; + + case 64: + *class = TEL_SS_CLASS_ALL_DEDI_PS; + break; + + case 128: + *class = TEL_SS_CLASS_ALL_DEDI_PAD; + break; + + default: + err("Invalid modem class: [%d]", classx); + return FALSE; + } + + return TRUE; +} + +static guint __imc_ss_convert_class_to_imc_class(TelSsClass class) +{ + switch(class) + { + case TEL_SS_CLASS_ALL_TELE: + return 7; + + case TEL_SS_CLASS_VOICE: + return 1; + + case TEL_SS_CLASS_ALL_DATA_TELE: + return 2; + + case TEL_SS_CLASS_FAX: + return 4; + + case TEL_SS_CLASS_SMS: + return 8; + + case TEL_SS_CLASS_ALL_CS_SYNC: + return 16; + + case TEL_SS_CLASS_ALL_CS_ASYNC: + return 32; + + case TEL_SS_CLASS_ALL_DEDI_PS: + return 64; + + case TEL_SS_CLASS_ALL_DEDI_PAD: + return 128; + + default: + dbg("Unsupported class: [%d], returning default value 7", class); + return 7; + } +} + +static gboolean __imc_ss_convert_barring_type_to_facility(TelSsBarringType type, gchar **facility) +{ + switch(type) + { + case TEL_SS_CB_TYPE_BAOC: + *facility = "AO"; + break; + + case TEL_SS_CB_TYPE_BOIC: + *facility = "OI"; + break; + + case TEL_SS_CB_TYPE_BOIC_NOT_HC: + *facility = "OX"; + break; + + case TEL_SS_CB_TYPE_BAIC: + *facility = "AI"; + break; + + case TEL_SS_CB_TYPE_BIC_ROAM: + *facility = "IR"; + break; + + case TEL_SS_CB_TYPE_AB: + *facility = "AB"; + break; + + case TEL_SS_CB_TYPE_AOB: + *facility = "AG"; + break; + + case TEL_SS_CB_TYPE_AIB: + *facility = "AC"; + break; + + case TEL_SS_CB_TYPE_NS: + *facility = "NS"; + break; + + default: + err("Unspported type: [%d]", type); + return FALSE; + } + return TRUE; +} + +static gboolean __imc_ss_convert_forwarding_mode_to_modem_mode(TelSsForwardMode mode, guint *modex) +{ + switch(mode) + { + case TEL_SS_CF_MODE_DISABLE: + *modex = 0; + break; + + case TEL_SS_CF_MODE_ENABLE: + *modex = 1; + break; + + case TEL_SS_CF_MODE_REGISTER: + *modex = 3; + break; + + case TEL_SS_CF_MODE_DEREGISTER: + *modex = 4; + break; + + default: + err("Unspported mode: [%d]", mode); + return FALSE; + } + return TRUE; +} + +static gboolean __imc_ss_convert_forwarding_condition_to_modem_reason(TelSsForwardCondition condition, guint *reason) +{ + switch (condition) { + case TEL_SS_CF_COND_CFU: + *reason = 0; + break; + + case TEL_SS_CF_COND_CFB: + *reason = 1; + break; + + case TEL_SS_CF_COND_CFNRY: + *reason = 2; + break; + + case TEL_SS_CF_COND_CFNRC: + *reason = 3; + break; + + case TEL_SS_CF_COND_ALL: + *reason = 4; + break; + + case TEL_SS_CF_COND_ALL_CFC: + *reason = 5; + break; + + default: + dbg("Unsupported condition: [%d]", condition); + return FALSE; + } + return TRUE; +} + +static gint __imc_ss_convert_cli_status_modem_status(gint cli_status) +{ + if (cli_status == TEL_SS_CLI_DISABLE) + return 0; + else if (cli_status == TEL_SS_CLI_ENABLE) + return 1; + else { + err("Invalid CLI status: [%d]", cli_status); + return -1; + } +} + +static gint __imc_ss_convert_clir_status_modem_status(gint clir_status) +{ + if (clir_status == TEL_CLIR_STATUS_DEFAULT) + return 0; + else if (clir_status == TEL_CLIR_STATUS_INVOCATION) + return 1; + else if (clir_status == TEL_CLIR_STATUS_SUPPRESSION) + return 2; + else { + err("Invalid CLIR status: [%d]", clir_status); + return -1; + } +} + +static gboolean __imc_ss_convert_cli_info_modem_info(const TelSsCliInfo **cli_info, gint *status, + gchar **cmd_prefix) +{ + switch((*cli_info)->type) + { + case TEL_SS_CLI_CLIR: + if ((*status = __imc_ss_convert_clir_status_modem_status((*cli_info)->status.clir)) != -1) + *cmd_prefix = "+CLIR"; + else + err("invalid clir status"); + break; + + case TEL_SS_CLI_CLIP: + if ((*status =__imc_ss_convert_cli_status_modem_status((*cli_info)->status.clip) != -1)) + *cmd_prefix = "+CLIP"; + else + err("invalid cli status"); + break; + case TEL_SS_CLI_COLP: + if ((*status =__imc_ss_convert_cli_status_modem_status((*cli_info)->status.colp) != -1)) + *cmd_prefix = "+COLP"; + else + err("invalid cli status"); + break; + case TEL_SS_CLI_COLR: + if ((*status =__imc_ss_convert_cli_status_modem_status((*cli_info)->status.colr) != -1)) + *cmd_prefix = "+COLR"; + else + err("invalid cli status"); + break; + + case TEL_SS_CLI_CNAP: + if ((*status =__imc_ss_convert_cli_status_modem_status((*cli_info)->status.cnap) != -1)) + *cmd_prefix = "+CNAP"; + else + err("invalid cli status"); + + break; + case TEL_SS_CLI_CDIP: + default: + err("Unsupported CLI type: [%d]", (*cli_info)->type); + return FALSE; + } + + if (*cmd_prefix == NULL) + return FALSE; + + return TRUE; +} + +static gboolean __imc_ss_convert_modem_cli_net_status_cli_status(TelSsCliType cli_type, gint net_status, + gint *status) +{ + if (cli_type == TEL_SS_CLI_CLIR) { + switch (net_status) { + case 0: + *status = TEL_CLIR_STATUS_NOT_PROVISIONED; + break; + case 1: + *status = TEL_CLIR_STATUS_PROVISIONED; + break; + case 2: + *status = TEL_CLIR_STATUS_UNKNOWN; + break; + case 3: + *status = TEL_CLIR_STATUS_TEMP_RESTRICTED; + break; + case 4: + *status = TEL_CLIR_STATUS_TEMP_ALLOWED; + break; + default: + err("Invalid clir net status: [%d]", net_status); + return FALSE; + } + } else { //CLIP, COLP,COLR,CNAP. + switch (net_status) { + case 0: + *status = TEL_SS_CLI_NOT_PROVISIONED; + break; + case 1: + *status = TEL_SS_CLI_PROVISIONED; + break; + case 2: + *status = TEL_SS_CLI_UNKNOWN; + break; + default: + err("Invalid status: [%d]", net_status); + return FALSE; + } + } + return TRUE; +} + +static gboolean __imc_ss_convert_modem_cli_dev_status_cli_status(TelSsCliType cli_type, + gint dev_status, gint *status) +{ + if (cli_type == TEL_SS_CLI_CLIR) { + switch (dev_status) { + case 0: + *status = TEL_CLIR_STATUS_DEFAULT; + break; + case 1: + *status = TEL_CLIR_STATUS_INVOCATION; + break; + case 2: + *status = TEL_CLIR_STATUS_SUPPRESSION; + break; + default: + err("Invalid dev status: [%d]", dev_status); + return FALSE; + } + } else { //CLIP, COLP,COLR,CNAP. + switch(dev_status) { + case 0: + *status = TEL_SS_CLI_DISABLE; + break; + case 1: + *status = TEL_SS_CLI_ENABLE; + break; + default: + err("Invalid dev status: [%d]", dev_status); + return FALSE; + } + } + return TRUE; +} + +/* SS Responses */ +static void on_response_imc_ss_set_barring(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + CoreObject *co = tcore_pending_ref_core_object(p); + ImcRespCbData *resp_cb_data = user_data; + + TelSsResult result = TEL_SS_RESULT_FAILURE; // TODO: CMEE error mapping is required + dbg("Enter"); + + tcore_check_return_assert(co != NULL); + tcore_check_return_assert(resp_cb_data != NULL); + + if (at_resp && at_resp->success) + result = TEL_SS_RESULT_SUCCESS; + + dbg("Setting Barring status: [%s]", + (result == TEL_SS_RESULT_SUCCESS ? "SUCCESS" : "FAIL")); + + /* Invoke callback */ + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, NULL, resp_cb_data->cb_data); + + imc_destroy_resp_cb_data(resp_cb_data); +} + +static void on_response_imc_ss_get_barring_status(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + CoreObject *co = tcore_pending_ref_core_object(p); + ImcRespCbData *resp_cb_data = user_data; + TelSsBarringResp barring_resp = {0,}; + TelSsBarringGetInfo *req_info; + gint valid_records = 0; + GSList *resp_data = NULL; + + TelSsResult result = TEL_SS_RESULT_FAILURE; // TODO: CMEE error mapping is required + dbg("Enter"); + + tcore_check_return_assert(co != NULL); + tcore_check_return_assert(resp_cb_data != NULL); + + req_info = (TelSsBarringGetInfo *)IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data); + + if (at_resp) { + if (at_resp->lines && at_resp->success) { + resp_data = (GSList *) at_resp->lines; + barring_resp.record_num= g_slist_length(resp_data); + dbg("Total records: [%d]", barring_resp.record_num); + } + else { + err("RESPONSE - [NOK]"); + } + } else { + err("No response data"); + } + + if (barring_resp.record_num > 0) { + barring_resp.records = tcore_malloc0((barring_resp.record_num) * + sizeof(TelSsBarringInfoRecord)); + for (valid_records = 0; resp_data != NULL; resp_data = resp_data->next) { + const gchar *line; + GSList *tokens = NULL; + + line = (const char *) resp_data->data; + tokens = tcore_at_tok_new(line); + if (g_slist_length(tokens) > 0) { + gchar *classx_str; + gchar *status = NULL; + + status = g_slist_nth_data(tokens, 0); + if (!status) { + dbg("Status is missing"); + tcore_at_tok_free(tokens); + continue; + } + + if (atoi(status) == 1) { + barring_resp.records[valid_records].enable = TRUE; + } else { + barring_resp.records[valid_records].enable = FALSE; + } + + classx_str = g_slist_nth_data(tokens, 1); + if (!classx_str) { + dbg("Class error. Setting to the requested class: [%d]", req_info->class); + barring_resp.records[valid_records].class = req_info->class; + } else { + if (__imc_ss_convert_modem_class_to_class(atoi(classx_str), + &(barring_resp.records[valid_records].class)) == FALSE) { + tcore_at_tok_free(tokens); + continue; + } + } + + barring_resp.records[valid_records].type= req_info->type; + result = TEL_SS_RESULT_SUCCESS; + valid_records++; + } else { + err("Invalid response message"); + } + tcore_at_tok_free(tokens); + } + } + + dbg("Getting Barring status: [%s]", + (result == TEL_SS_RESULT_SUCCESS ? "SUCCESS" : "FAIL")); + barring_resp.record_num = valid_records; + + /* Invoke callback */ + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, &barring_resp, resp_cb_data->cb_data); + + imc_destroy_resp_cb_data(resp_cb_data); + + if (barring_resp.records) { + tcore_free(barring_resp.records); + } +} + +static void on_response_imc_ss_change_barring_password(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + CoreObject *co = tcore_pending_ref_core_object(p); + ImcRespCbData *resp_cb_data = user_data; + + TelSsResult result = TEL_SS_RESULT_FAILURE; // TODO: CMEE error mapping is required + dbg("Enter"); + + tcore_check_return_assert(co != NULL); + tcore_check_return_assert(resp_cb_data != NULL); + + if (at_resp && at_resp->success) + result = TEL_SS_RESULT_SUCCESS; + + dbg("Change Barring Password: [%s]", + (result == TEL_SS_RESULT_SUCCESS ? "SUCCESS" : "FAIL")); + + /* Invoke callback */ + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, NULL, resp_cb_data->cb_data); + + imc_destroy_resp_cb_data(resp_cb_data); +} + +static void on_response_imc_ss_set_forwarding(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + CoreObject *co = tcore_pending_ref_core_object(p); + ImcRespCbData *resp_cb_data = user_data; + + TelSsResult result = TEL_SS_RESULT_FAILURE; // TODO: CMEE error mapping is required + dbg("Enter"); + + tcore_check_return_assert(co != NULL); + tcore_check_return_assert(resp_cb_data != NULL); + + if (at_resp && at_resp->success) + result = TEL_SS_RESULT_SUCCESS; + + dbg("Set Forwarding Status: [%s]", + (result == TEL_SS_RESULT_SUCCESS ? "SUCCESS" : "FAIL")); + + /* Invoke callback */ + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, NULL, resp_cb_data->cb_data); + + imc_destroy_resp_cb_data(resp_cb_data); +} + +static void on_response_imc_ss_get_forwarding_status(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + CoreObject *co = tcore_pending_ref_core_object(p); + ImcRespCbData *resp_cb_data = user_data; + TelSsForwardingResp forwarding_resp = {0,}; + TelSsForwardGetInfo *req_info; + gint valid_records = 0; + GSList *resp_data = NULL; + + TelSsResult result = TEL_SS_RESULT_FAILURE; // TODO: CMEE error mapping is required + dbg("Enter"); + + tcore_check_return_assert(co != NULL); + tcore_check_return_assert(resp_cb_data != NULL); + + req_info = (TelSsForwardGetInfo *)IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data); + + if (at_resp) { + if (at_resp->lines && at_resp->success) { + resp_data = (GSList *) at_resp->lines; + forwarding_resp.record_num= g_slist_length(resp_data); + dbg("Total records: [%d]", forwarding_resp.record_num); + } + else { + err("RESPONSE - [NOK]"); + } + } else { + err("No response data"); + } + + if (forwarding_resp.record_num > 0) { + forwarding_resp.records = tcore_malloc0((forwarding_resp.record_num) * + sizeof(TelSsForwardingInfoRecord)); + for (valid_records = 0; resp_data != NULL; resp_data = resp_data->next) { + const gchar *line; + GSList *tokens = NULL; + + line = (const char *) resp_data->data; + tokens = tcore_at_tok_new(line); + if (g_slist_length(tokens) > 0) { + gchar *classx_str; + gchar *status = NULL; + gchar *number = NULL; + gchar *time_str = NULL; + + status = g_slist_nth_data(tokens, 0); + if (!status) { + dbg("Status is missing"); + tcore_at_tok_free(tokens); + continue; + } + + if (atoi(status) == 1) { + forwarding_resp.records[valid_records].enable = TRUE; + } else { + forwarding_resp.records[valid_records].enable = FALSE; + } + + classx_str = g_slist_nth_data(tokens, 1); + if (!classx_str) { + dbg("Class error. Setting to the requested class: [%d]", req_info->class); + forwarding_resp.records[valid_records].class = req_info->class; + } else { + if (__imc_ss_convert_modem_class_to_class(atoi(classx_str), + &(forwarding_resp.records[valid_records].class)) == FALSE) { + tcore_at_tok_free(tokens); + continue; + } + } + + number = g_slist_nth_data(tokens, 2); + if (number) { + number = tcore_at_tok_extract(number); + memcpy((forwarding_resp.records[valid_records].number), number, strlen(number)); + g_free(number); + } + + time_str = g_slist_nth_data(tokens, 6); + if (time_str) + forwarding_resp.records[valid_records].wait_time = atoi(time_str); + + forwarding_resp.records[valid_records].condition = req_info->condition; + + result = TEL_SS_RESULT_SUCCESS; + valid_records++; + } else { + err("Invalid response message"); + } + tcore_at_tok_free(tokens); + } + } + + dbg("Getting Forwarding Status: [%s]", + (result == TEL_SS_RESULT_SUCCESS ? "SUCCESS" : "FAIL")); + forwarding_resp.record_num = valid_records; + + /* Invoke callback */ + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, &forwarding_resp, resp_cb_data->cb_data); + + imc_destroy_resp_cb_data(resp_cb_data); + + if (forwarding_resp.records) { + tcore_free(forwarding_resp.records); + } +} + +static void on_response_imc_ss_set_waiting(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + CoreObject *co = tcore_pending_ref_core_object(p); + ImcRespCbData *resp_cb_data = user_data; + + TelSsResult result = TEL_SS_RESULT_FAILURE; // TODO: CMEE error mapping is required + dbg("Enter"); + + tcore_check_return_assert(co != NULL); + tcore_check_return_assert(resp_cb_data != NULL); + + if (at_resp && at_resp->success) + result = TEL_SS_RESULT_SUCCESS; + + dbg("Set Waiting Status: [%s]", + (result == TEL_SS_RESULT_SUCCESS ? "SUCCESS" : "FAIL")); + + /* Invoke callback */ + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, NULL, resp_cb_data->cb_data); + + imc_destroy_resp_cb_data(resp_cb_data); +} + +static void on_response_imc_ss_get_waiting_status(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + CoreObject *co = tcore_pending_ref_core_object(p); + ImcRespCbData *resp_cb_data = user_data; + TelSsWaitingResp waiting_resp = {0,}; + TelSsClass *class; + gint valid_records = 0; + GSList *resp_data = NULL; + + TelSsResult result = TEL_SS_RESULT_FAILURE; // TODO: CMEE error mapping is required + dbg("Enter"); + + tcore_check_return_assert(co != NULL); + tcore_check_return_assert(resp_cb_data != NULL); + + class = (TelSsClass *)IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data); + + if (at_resp) { + if (at_resp->lines && at_resp->success) { + resp_data = (GSList *) at_resp->lines; + waiting_resp.record_num= g_slist_length(resp_data); + dbg("Total records: [%d]", waiting_resp.record_num); + } + else { + err("RESPONSE - [NOK]"); + } + } else { + err("No response data"); + } + + if (waiting_resp.record_num > 0) { + waiting_resp.records = tcore_malloc0((waiting_resp.record_num) * sizeof(TelSsWaitingInfo)); + for (valid_records = 0; resp_data != NULL; resp_data = resp_data->next) { + const gchar *line; + GSList *tokens = NULL; + + line = (const char *) resp_data->data; + tokens = tcore_at_tok_new(line); + if (g_slist_length(tokens) > 0) { + gchar *classx_str; + gchar *status = NULL; + + status = g_slist_nth_data(tokens, 0); + if (!status) { + dbg("Status is missing"); + tcore_at_tok_free(tokens); + continue; + } + + if (atoi(status) == 1) { + waiting_resp.records[valid_records].enable= TRUE; + } else { + waiting_resp.records[valid_records].enable = FALSE; + } + + classx_str = g_slist_nth_data(tokens, 1); + if (!classx_str) { + dbg("Class error. Setting to the requested class: [%d]", *class); + waiting_resp.records[valid_records].class = *class; + } else { + if (__imc_ss_convert_modem_class_to_class(atoi(classx_str), &(waiting_resp.records[valid_records].class)) == FALSE) { + tcore_at_tok_free(tokens); + continue; + } + } + + result = TEL_SS_RESULT_SUCCESS; + valid_records++; + } else { + err("Invalid response message"); + } + tcore_at_tok_free(tokens); + } + } + + dbg("Getting Waiting Status: [%s]", + (result == TEL_SS_RESULT_SUCCESS ? "SUCCESS" : "FAIL")); + waiting_resp.record_num = valid_records; + + /* Invoke callback */ + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, &waiting_resp, resp_cb_data->cb_data); + + imc_destroy_resp_cb_data(resp_cb_data); + + if (waiting_resp.records) { + tcore_free(waiting_resp.records); + } +} + +static void on_response_imc_ss_set_cli(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + CoreObject *co = tcore_pending_ref_core_object(p); + ImcRespCbData *resp_cb_data = user_data; + + TelSsResult result = TEL_SS_RESULT_FAILURE; // TODO: CMEE error mapping is required + dbg("Enter"); + + tcore_check_return_assert(co != NULL); + tcore_check_return_assert(resp_cb_data != NULL); + + if (at_resp && at_resp->success) + result = TEL_SS_RESULT_SUCCESS; + + dbg("Set Cli Status: [%s]", + (result == TEL_SS_RESULT_SUCCESS ? "SUCCESS" : "FAIL")); + + /* Invoke callback */ + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, NULL, resp_cb_data->cb_data); + + imc_destroy_resp_cb_data(resp_cb_data); +} + +static void on_response_imc_ss_get_cli_status(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + CoreObject *co = tcore_pending_ref_core_object(p); + ImcRespCbData *resp_cb_data = user_data; + TelSsCliResp cli_resp = {0,}; + TelSsCliType *cli_type; + GSList *tokens = NULL; + + TelSsResult result = TEL_SS_RESULT_FAILURE; // TODO: CMEE error mapping is required + dbg("Enter"); + + tcore_check_return_assert(co != NULL); + tcore_check_return_assert(resp_cb_data != NULL); + + cli_type = (TelSsCliType *)IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data); + + if (*cli_type == TEL_SS_CLI_CDIP) { + err("Unsupported CLI type: [%d]", *cli_type); + result = TEL_SS_RESULT_INVALID_PARAMETER; + goto END; + } + + if (at_resp && at_resp->success) { + const gchar *line; + gchar *status = NULL; + gint net_status; + gint dev_status; + + if (!at_resp->lines) { + err("Invalid response message"); + goto END; + } + line = (const gchar *)at_resp->lines->data; + tokens = tcore_at_tok_new(line); + if (g_slist_length(tokens) < 1) { + err("Invalid response message"); + goto END; + } + + dbg("RESPONSE OK"); + status = g_slist_nth_data(tokens, 0); + if (!status) { + err("dev_status is missing"); + goto END; + } + if (!__imc_ss_convert_modem_cli_dev_status_cli_status(*cli_type, atoi(status), &dev_status)) + goto END; + + status = g_slist_nth_data(tokens, 1); + if (!status) { + err("net_status is missing"); + goto END; + } + if (!__imc_ss_convert_modem_cli_net_status_cli_status(*cli_type, atoi(status), &net_status)) + goto END; + + switch(*cli_type){ + case TEL_SS_CLI_CLIR: + cli_resp.status.clir.net_status = net_status; + cli_resp.status.clir.dev_status = dev_status; + break; + case TEL_SS_CLI_CLIP: + cli_resp.status.clip.net_status = net_status; + cli_resp.status.clip.dev_status = dev_status; + break; + case TEL_SS_CLI_COLP: + cli_resp.status.colp.net_status = net_status; + cli_resp.status.colp.dev_status = dev_status; + break; + case TEL_SS_CLI_COLR: + cli_resp.status.colr.net_status = net_status; + cli_resp.status.colr.dev_status = dev_status; + break; + case TEL_SS_CLI_CNAP: + cli_resp.status.cnap.net_status = net_status; + cli_resp.status.cnap.dev_status = dev_status; + break; + default: + err("Unsupported CLI type: [%d]", *cli_type); + result = TEL_SS_RESULT_INVALID_PARAMETER; + goto END; + } + + cli_resp.type = *cli_type; + result = TEL_SS_RESULT_SUCCESS; + } else{ + err("RESPONSE NOK"); + } + +END: + tcore_at_tok_free(tokens); + + /* Invoke callback */ + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, &cli_resp, resp_cb_data->cb_data); + + imc_destroy_resp_cb_data(resp_cb_data); +} + +static void on_response_imc_ss_send_ussd_request(TcorePending *p, + guint data_len, const void *data, void *user_data) +{ + const TcoreAtResponse *at_resp = data; + CoreObject *co = tcore_pending_ref_core_object(p); + ImcRespCbData *resp_cb_data = user_data; + TelSsUssdResp ussd_resp = {0,}; + UssdSession *ussd_s = NULL; + + TelSsResult result = TEL_SS_RESULT_FAILURE; // TODO: CMEE error mapping is required + dbg("Enter"); + + tcore_check_return_assert(co != NULL); + tcore_check_return_assert(resp_cb_data != NULL); + + ussd_s = tcore_ss_ussd_get_session(co); + tcore_check_return(ussd_s != NULL); + + tcore_ss_ussd_get_session_type(ussd_s, &ussd_resp.type); + + if (at_resp && at_resp->success) { + result = TEL_SS_RESULT_SUCCESS; + /* Need to initialise ussd response string */ + ussd_resp.str = (unsigned char *)g_strdup("Operation success"); + } else { + ussd_resp.str = (unsigned char *)g_strdup("Operation failed"); + } + + + dbg("Send Ussd Request: [%s]", + (result == TEL_SS_RESULT_SUCCESS ? "SUCCESS" : "FAIL")); + + tcore_ss_ussd_destroy_session(ussd_s); + + + /* Invoke callback */ + if (resp_cb_data->cb) + resp_cb_data->cb(co, (gint)result, &ussd_resp, resp_cb_data->cb_data); + + imc_destroy_resp_cb_data(resp_cb_data); + g_free(ussd_resp.str); +} + +/* SS Operations */ +/* + * Operation - set_barring/get_barring_status + * + * Request - + * AT-Command: AT+CLCK=,[,[,]] + * where, + * + * Barring facility type. Ref #TelSsBarringType + * + * + * 0 unlock + * 1 lock + * 2 query status + * + * + * Barring Password + * + * + * SS class. Ref #TelSsClass + * + * + * 0 not active + * 1 active + * + * Success: when =2: + * OK + * +CLCK: [, [ + * +CLCK: , [...]] + * + * Failure: + * +CME ERROR: + */ +static TelReturn imc_ss_set_barring(CoreObject *co, const TelSsBarringInfo *barring_info, + TcoreObjectResponseCallback cb, void *cb_data) +{ + gchar *at_cmd = NULL; + guint mode; + guint classx; + gchar *facility = NULL; + ImcRespCbData *resp_cb_data = NULL; + TelReturn ret = TEL_RETURN_INVALID_PARAMETER; + + if (barring_info->enable == TRUE) + mode = 1; + else + mode = 0; + + if (__imc_ss_convert_barring_type_to_facility(barring_info->type, &facility) == FALSE) { + err("Invalid arguments"); + return ret; + } + + classx = __imc_ss_convert_class_to_imc_class(barring_info->class); + + dbg("facility: [%s], classx:[%d], mode: [%d]", facility, classx, mode); + + /* AT-Command */ + at_cmd = g_strdup_printf("AT+CLCK=\"%s\",%d,\"%s\",%d", facility, mode, barring_info->pwd, classx); + + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, NULL, 0); + + /* Send Request to modem */ + ret = tcore_at_prepare_and_send_request(co, + at_cmd, NULL, + TCORE_AT_COMMAND_TYPE_NO_RESULT, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_ss_set_barring, resp_cb_data, + on_send_imc_request, NULL, + 0, NULL, NULL); + + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Set Barring"); + + g_free(at_cmd); + + return ret; +} + +static TelReturn imc_ss_get_barring_status(CoreObject *co, const TelSsBarringGetInfo *get_barring_info, + TcoreObjectResponseCallback cb, void *cb_data) +{ + gchar *at_cmd = NULL; + guint mode; + guint classx; + gchar *facility = NULL; + ImcRespCbData *resp_cb_data = NULL; + TelReturn ret = TEL_RETURN_INVALID_PARAMETER; + + mode = 2; /* query status - mode is fixed to 2 */ + + if (__imc_ss_convert_barring_type_to_facility(get_barring_info->type, &facility) == FALSE) { + err("Invalid arguments"); + return ret; + } + + classx = __imc_ss_convert_class_to_imc_class(get_barring_info->class); + + dbg("facility: [%s], classx:[%d], mode: [%d]", facility, classx, mode); + + /* AT-Command */ + at_cmd = g_strdup_printf("AT+CLCK=\"%s\",%d,,%d", facility, mode, classx); + + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, (void *)get_barring_info, sizeof(TelSsBarringGetInfo)); + + /* Send Request to modem */ + ret = tcore_at_prepare_and_send_request(co, + at_cmd, "+CLCK", + TCORE_AT_COMMAND_TYPE_MULTILINE, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_ss_get_barring_status, resp_cb_data, + on_send_imc_request, NULL, + 0, NULL, NULL); + + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Get Barring Status"); + + g_free(at_cmd); + + return ret; +} + +/* + * Operation - change_barring_password + * + * Request - + * AT-Command: AT+CPWD= ,, + * where, + * + * Barring facility type. Ref #TelSsBarringType + * Eg: "AB" All Barring services + * + * + * Old Barring Password + * + * + * New Barring Password + * + * Success: + * OK + * + * Failure: + * +CME ERROR: + */ +static TelReturn imc_ss_change_barring_password(CoreObject *co, const TelSsBarringPwdInfo *barring_pwd_info, + TcoreObjectResponseCallback cb, void *cb_data) +{ + gchar *at_cmd = NULL; + ImcRespCbData *resp_cb_data = NULL; + TelReturn ret = TEL_RETURN_INVALID_PARAMETER; + + if (barring_pwd_info->old_pwd== NULL || barring_pwd_info->new_pwd == NULL) { + err("Invalid data"); + return ret; + } + + dbg("Old password: [%s], New password: [%s]", barring_pwd_info->old_pwd, barring_pwd_info->new_pwd); + + at_cmd = g_strdup_printf("AT+CPWD=\"%s\",\"%s\",\"%s\"", "AB", barring_pwd_info->old_pwd, barring_pwd_info->new_pwd); + + resp_cb_data = imc_create_resp_cb_data(cb, cb_data, NULL, 0); + + /* Send Request to modem */ + ret = tcore_at_prepare_and_send_request(co, + at_cmd, NULL, + TCORE_AT_COMMAND_TYPE_NO_RESULT, + TCORE_PENDING_PRIORITY_DEFAULT, + NULL, + on_response_imc_ss_change_barring_password, resp_cb_data, + on_send_imc_request, NULL, + 0, NULL, NULL); + + IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "Change Barring Password"); + + g_free(at_cmd); + + return ret; +} + +/* + * Operation - set_forwarding/get_forwarding_status + * + * Request - + * AT-Command: AT+CCFC=,[,[,[,[,[,[,