From 82ba26101ab9f29396163625b5e0b6548bb85143 Mon Sep 17 00:00:00 2001 From: Marius Gripsgard Date: Wed, 19 Mar 2025 03:58:27 +0100 Subject: [PATCH] src: Add sms support --- Makefile | 3 +- src/qti_ims.c | 2 +- src/qti_ims_call.c | 1 + src/qti_ims_sms.c | 408 ++++++++++++++++++++++++++++++++++++++ src/qti_ims_sms.h | 38 ++++ src/qti_radio_ext.c | 188 +++++++++++++++++- src/qti_radio_ext.h | 44 ++++ src/qti_radio_ext_types.h | 161 ++++++++++++++- src/qti_slot.c | 5 + 9 files changed, 841 insertions(+), 9 deletions(-) create mode 100644 src/qti_ims_sms.c create mode 100644 src/qti_ims_sms.h diff --git a/Makefile b/Makefile index bf7562b..731647f 100644 --- a/Makefile +++ b/Makefile @@ -41,7 +41,8 @@ SRC = \ qti_plugin.c \ qti_slot.c \ qti_radio_ext.c \ - qti_ims_call.c + qti_ims_call.c \ + qti_ims_sms.c # # Directories diff --git a/src/qti_ims.c b/src/qti_ims.c index e8ebe5e..e33d7ad 100644 --- a/src/qti_ims.c +++ b/src/qti_ims.c @@ -315,7 +315,7 @@ qti_ims_iface_init( BinderExtImsInterface* iface) { iface->version = BINDER_EXT_IMS_INTERFACE_VERSION; - iface->flags = BINDER_EXT_IMS_INTERFACE_FLAG_VOICE_SUPPORT; + iface->flags = BINDER_EXT_IMS_INTERFACE_FLAG_VOICE_SUPPORT | BINDER_EXT_IMS_INTERFACE_FLAG_SMS_SUPPORT; iface->get_state = qti_ims_get_state; iface->set_registration = qti_ims_set_registration; iface->cancel = qti_ims_cancel; diff --git a/src/qti_ims_call.c b/src/qti_ims_call.c index 01ef057..fa6b2af 100644 --- a/src/qti_ims_call.c +++ b/src/qti_ims_call.c @@ -31,6 +31,7 @@ #include #include +#undef DBG #define DBG(fmt, ...) \ gutil_log(GLOG_MODULE_CURRENT, GLOG_LEVEL_ALWAYS, "ims:"fmt, ##__VA_ARGS__) diff --git a/src/qti_ims_sms.c b/src/qti_ims_sms.c new file mode 100644 index 0000000..4c033fc --- /dev/null +++ b/src/qti_ims_sms.c @@ -0,0 +1,408 @@ +/* + * oFono - Open Source Telephony - binder based adaptation QTI plugin + * + * Copyright (C) 2022 Jolla Ltd. + * Copyright (C) 2024 TheKit + * Copyright (C) 2024 Marius Gripsgard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include + +#include "qti_ims_sms.h" +#include "qti_radio_ext.h" +#include "qti_radio_ext_types.h" + +#include + +#include + +#include +#include + +#include + +#include +#include +#include +#include + +#define DBG(fmt, ...) \ + gutil_log(GLOG_MODULE_CURRENT, GLOG_LEVEL_ALWAYS, "ims:"fmt, ##__VA_ARGS__) + +typedef GObjectClass QtiImsSmsClass; +typedef struct qti_ims_sms { + GObject parent; + GUtilIdlePool* pool; + QtiRadioExt* radio_ext; + GPtrArray* sms; + GHashTable* id_map; +} QtiImsSms; + +typedef struct qti_ims_sms_result_request { + int ref_count; + guint id; + guint id_mapped; + guint param; + BinderExtSms* ext; + BinderExtSmsSendFunc complete; + GDestroyNotify destroy; + void* user_data; +} QtiImsSmsResultRequest; + +static +void +qti_ims_sms_iface_init( + BinderExtSmsInterface* iface); + +GType qti_ims_sms_get_type() G_GNUC_INTERNAL; +G_DEFINE_TYPE_WITH_CODE(QtiImsSms, qti_ims_sms, G_TYPE_OBJECT, +G_IMPLEMENT_INTERFACE(BINDER_EXT_TYPE_SMS, qti_ims_sms_iface_init)) + +#define THIS_TYPE qti_ims_sms_get_type() +#define THIS(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, THIS_TYPE, QtiImsSms) +#define PARENT_CLASS qti_ims_sms_parent_class + +#define ID_KEY(id) GUINT_TO_POINTER(id) +#define ID_VALUE(id) GUINT_TO_POINTER(id) + +enum qti_ims_sms_signal { + SIGNAL_SMS_STATE_CHANGED, + SIGNAL_SMS_RECEIVED, + SIGNAL_COUNT +}; + +#define SIGNAL_SMS_STATE_CHANGED_NAME "qti-ims-sms-state-changed" +#define SIGNAL_SMS_RECEIVED_NAME "qti-ims-sms-received" + +static guint qti_ims_sms_signals[SIGNAL_COUNT] = { 0 }; + +static +QtiImsSmsResultRequest* +qti_ims_sms_result_request_new( + BinderExtSms* self, + BinderExtSmsSendFunc complete, + GDestroyNotify destroy, + void* user_data) +{ + QtiImsSmsResultRequest* req = + g_slice_new0(QtiImsSmsResultRequest); + + req->ref_count = 1; + req->ext = binder_ext_sms_ref(self); + req->complete = complete; + req->destroy = destroy; + req->user_data = user_data; + return req; +} + +static +void +qti_ims_sms_result_request_free( + QtiImsSmsResultRequest* req) +{ + BinderExtSms* ext = req->ext; + + if (req->destroy) { + req->destroy(req->user_data); + } + if (req->id_mapped) { + g_hash_table_remove(THIS(ext)->id_map, ID_KEY(req->id_mapped)); + } + binder_ext_sms_unref(ext); + gutil_slice_free(req); +} + +static +gboolean +qti_ims_sms_result_request_unref( + QtiImsSmsResultRequest* req) +{ + if (!--(req->ref_count)) { + qti_ims_sms_result_request_free(req); + return TRUE; + } else { + return FALSE; + } +} + +static +void +qti_ims_sms_result_request_destroy( + gpointer req) +{ + qti_ims_sms_result_request_unref(req); +} + +static +void +qti_ims_sms_result_request_response( + QtiRadioExt* radio, + int msg_ref, + GBinderReader* reader, + void* user_data) +{ + gint32 result; + GBinderReader r; + QtiImsSmsResultRequest* req = user_data; + BINDER_EXT_SMS_SEND_RESULT send_result; + + gbinder_reader_copy(&r, reader); + if (!gbinder_reader_read_int32(&r, &result)) { + ofono_warn("Failed to parse response"); + result = QTI_RADIO_SEND_STATUS_ERROR; + } + + DBG("qti_ims_sms_result_request_response\n"); + DBG("result: %d\n", result); + + if (result == QTI_RADIO_SEND_STATUS_OK) { + send_result = BINDER_EXT_SMS_SEND_RESULT_OK; + } else { + send_result = BINDER_EXT_SMS_SEND_RESULT_ERROR; + } + + if (req->complete) { + req->complete(req->ext, send_result, 0, req->user_data); + } +} + +static +void +qti_ims_sms_incoming_sms_handler( + QtiRadioExt* radio, + const void* pdu, + guint pdu_len, + void* user_data) +{ + QtiImsSms* self = user_data; + + DBG("Incoming SMS!!!: pdu_len=%d", pdu_len); + + g_signal_emit(self, qti_ims_sms_signals[SIGNAL_SMS_RECEIVED], 0, pdu, pdu_len); +} + + +/*==========================================================================* + * BinderExtSmsInterface + *==========================================================================*/ + +static +guint +qti_ims_sms_send( + BinderExtSms* ext, + const char* smsc, + const void* pdu, + gsize pdu_len, + guint msg_ref, + BINDER_EXT_SMS_SEND_FLAGS flags, + BinderExtSmsSendFunc complete, + GDestroyNotify destroy, + void* user_data) +{ + QtiImsSms* self = THIS(ext); + QtiImsSmsResultRequest* req = qti_ims_sms_result_request_new(ext, + complete, destroy, user_data); + + guint id = qti_radio_ext_send_ims_sms(self->radio_ext, smsc, pdu, pdu_len, msg_ref, flags, + qti_ims_sms_result_request_response, qti_ims_sms_result_request_destroy, req); + + DBG("Sending SMS: pdu_len=%u, msg_ref=%u", pdu_len, msg_ref); + + if (id) { + req->id = id; + g_hash_table_insert(self->id_map, ID_KEY(id), ID_VALUE(id)); + } else { + qti_ims_sms_result_request_free(req); + } + + return id; +} + +static +void +qti_ims_sms_cancel( + BinderExtSms* ext, + guint id) +{ + QtiImsSms* self = THIS(ext); + const guint mapped = GPOINTER_TO_UINT(g_hash_table_lookup(self->id_map, + ID_KEY(id))); + + qti_radio_ext_cancel(self->radio_ext, mapped ? mapped : id); +} + +static +void +qti_ims_sms_ack_report( + BinderExtSms* ext, + guint msg_ref, + gboolean ok) +{ + QtiImsSms* self = THIS(ext); + + QtiImsSmsResultRequest* req = qti_ims_sms_result_request_new(ext, + NULL, NULL, NULL); + + guint id = qti_radio_ext_acknowledge_sms(self->radio_ext, msg_ref, ok, + qti_ims_sms_result_request_response, qti_ims_sms_result_request_destroy, req); + + DBG("Acknowledging SMS report: msg_ref=%u, ok=%d", msg_ref, ok); + + if (id) { + req->id = id; + g_hash_table_insert(self->id_map, ID_KEY(id), ID_VALUE(id)); + } else { + qti_ims_sms_result_request_free(req); + } +} + +static +void +qti_ims_sms_ack_incoming( + BinderExtSms* ext, + gboolean ok) +{ + QtiImsSms* self = THIS(ext); + + QtiImsSmsResultRequest* req = qti_ims_sms_result_request_new(ext, + NULL, NULL, NULL); + + // We *should* have message reference, but we don't + // so we use -1, we have to change upstream to fix this + // TODO: fix this + guint id = qti_radio_ext_acknowledge_sms(self->radio_ext, -1, ok, + qti_ims_sms_result_request_response, qti_ims_sms_result_request_destroy, req); + + DBG("Acknowledging incoming SMS: ok=%d", ok); + + if (id) { + req->id = id; + g_hash_table_insert(self->id_map, ID_KEY(id), ID_VALUE(id)); + } else { + qti_ims_sms_result_request_free(req); + } +} + +static +gulong +qti_ims_sms_add_report_handler( + BinderExtSms* ext, + BinderExtSmsReportFunc handler, + void* user_data) +{ + return g_signal_connect(ext, SIGNAL_SMS_STATE_CHANGED_NAME, G_CALLBACK(handler), user_data); +} + +static +gulong +qti_ims_sms_add_incoming_handler( + BinderExtSms* ext, + BinderExtSmsIncomingFunc handler, + void* user_data) +{ + return g_signal_connect(ext, SIGNAL_SMS_RECEIVED_NAME, G_CALLBACK(handler), user_data); +} + +static +void +qti_ims_sms_remove_handler( + BinderExtSms* ext, + gulong id) +{ + g_signal_handler_disconnect(ext, id); +} + +void +qti_ims_sms_iface_init( + BinderExtSmsInterface* iface) +{ + iface->flags |= BINDER_EXT_SMS_INTERFACE_FLAG_IMS_SUPPORT | + BINDER_EXT_SMS_INTERFACE_FLAG_IMS_REQUIRED; + iface->version = BINDER_EXT_SMS_INTERFACE_VERSION; + iface->send = qti_ims_sms_send; + iface->cancel = qti_ims_sms_cancel; + iface->ack_report = qti_ims_sms_ack_report; + iface->ack_incoming = qti_ims_sms_ack_incoming; + iface->add_report_handler = qti_ims_sms_add_report_handler; + iface->add_incoming_handler = qti_ims_sms_add_incoming_handler; + iface->remove_handler = qti_ims_sms_remove_handler; +} + +/*==========================================================================* + * API + *==========================================================================*/ + +BinderExtSms* +qti_ims_sms_new( + QtiRadioExt* radio_ext) +{ + if (G_LIKELY(radio_ext)) { + QtiImsSms* self = g_object_new(THIS_TYPE, NULL); + + self->radio_ext = qti_radio_ext_ref(radio_ext); + self->sms = g_ptr_array_new_with_free_func(g_free); + + qti_radio_ext_add_incoming_sms_handler(radio_ext, qti_ims_sms_incoming_sms_handler, self); + + return BINDER_EXT_SMS(self); + } + return NULL; +} + +/*==========================================================================* + * Internals + *==========================================================================*/ + +static +void +qti_ims_sms_finalize( + GObject* object) +{ + QtiImsSms* self = THIS(object); + qti_radio_ext_unref(self->radio_ext); + gutil_idle_pool_destroy(self->pool); + g_ptr_array_free(self->sms, TRUE); + G_OBJECT_CLASS(PARENT_CLASS)->finalize(object); +} + +static +void +qti_ims_sms_init( + QtiImsSms* self) +{ + self->pool = gutil_idle_pool_new(); +} + +static +void +qti_ims_sms_class_init( + QtiImsSmsClass* klass) +{ + GType type = G_OBJECT_CLASS_TYPE(klass); + + G_OBJECT_CLASS(klass)->finalize = qti_ims_sms_finalize; + qti_ims_sms_signals[SIGNAL_SMS_STATE_CHANGED] = + g_signal_new(SIGNAL_SMS_STATE_CHANGED_NAME, type, + G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0); + qti_ims_sms_signals[SIGNAL_SMS_RECEIVED] = + g_signal_new(SIGNAL_SMS_RECEIVED_NAME, type, + G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, G_TYPE_NONE, + 2, G_TYPE_POINTER, G_TYPE_UINT); +} + +/* + * Local Variables: + * mode: C + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/src/qti_ims_sms.h b/src/qti_ims_sms.h new file mode 100644 index 0000000..75d9f81 --- /dev/null +++ b/src/qti_ims_sms.h @@ -0,0 +1,38 @@ +/* + * oFono - Open Source Telephony - binder based adaptation QTI plugin + * + * Copyright (C) 2024 TheKit + * Copyright (C) 2024 Marius Gripsgard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef QTI_IMS_SMS_H +#define QTI_IMS_SMS_H + +#include + +typedef struct qti_radio_ext QtiRadioExt; +typedef struct radio_client RadioClient; + +BinderExtSms* +qti_ims_sms_new( + QtiRadioExt* radio_ext) + G_GNUC_INTERNAL; + +#endif /* QTI_IMS_SMS_H */ + +/* + * Local Variables: + * mode: C + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/src/qti_radio_ext.c b/src/qti_radio_ext.c index c3a0ecc..5c730de 100644 --- a/src/qti_radio_ext.c +++ b/src/qti_radio_ext.c @@ -23,8 +23,11 @@ #include #include #include +#include #include +#include + #include #include @@ -93,12 +96,14 @@ enum qti_radio_ext_signal { SIGNAL_IMS_REG_STATUS_CHANGED, SIGNAL_EXT_CALL_STATE_CHANGED, SIGNAL_EXT_ON_RING, + SIGNAL_EXT_ON_INCOMING_SMS, SIGNAL_COUNT }; #define SIGNAL_IMS_REG_STATUS_CHANGED_NAME "qti-radio-ext-ims-reg-status-changed" #define SIGNAL_EXT_CALL_STATE_CHANGED_NAME "qti-radio-ext-call-state-changed" #define SIGNAL_EXT_ON_RING_NAME "qti-radio-ext-on-ring" +#define SIGNAL_EXT_ON_INCOMING_SMS_NAME "qti-radio-ext-on-incoming-sms" static guint qti_radio_ext_signals[SIGNAL_COUNT] = { 0 }; @@ -440,6 +445,45 @@ qti_radio_ext_handle_call_state_indication( } } +/* +typedef struct qti_radio_incoming_ims_sms { + GBinderHidlString format RADIO_ALIGNED(8); + GBinderHidlVec pdu RADIO_ALIGNED(8); + guint32 verstat RADIO_ALIGNED(4); +} RADIO_ALIGNED(8) QtiRadioIncomingImsSms; +*/ + +static +void +qti_radio_ext_handle_incoming_sms_indication( + QtiRadioExt* self, + const GBinderReader* args) +{ + GBinderReader reader; + QtiRadioIncomingImsSms* sms; + + gbinder_reader_copy(&reader, args); + sms = gbinder_reader_read_hidl_struct(&reader, QtiRadioIncomingImsSms); + + if (sms) { + const char *format = sms->format.data.str ? sms->format.data.str : ""; + const guint32 verstat = sms->verstat; + const guint pdu_len = sms->pdu.count; + const void* pdu = sms->pdu.data.ptr; + + // copy pdu to a new buffer + const void* pdu_copy = g_memdup(pdu, pdu_len); + + DBG("%s: Incoming SMS indication format:%s verstat:%d pdu_len:%d", + self->slot, format, verstat, pdu_len); + gutil_log_dump(&qti_radio_ext_binder_dump_module, GLOG_LEVEL_VERBOSE, " ", pdu_copy, pdu_len); + + g_signal_emit(self, qti_radio_ext_signals[SIGNAL_EXT_ON_INCOMING_SMS], 0, pdu_copy, pdu_len); + } else { + DBG("%s: failed to parse incoming SMS data", self->slot); + } +} + static GBinderLocalReply* @@ -482,6 +526,12 @@ qti_radio_ext_indication( case QTI_RADIO_IND_CALL_STATE_INDICATION_1_2: qti_radio_ext_handle_call_state_indication(self, &args); return NULL; + case QTI_RADIO_IND_SMS_STATUS_REPORT_INDICATION: + DBG("SMS status report indication"); + return NULL; + case QTI_RADIO_IND_INCOMING_SMS_INDICATION: + qti_radio_ext_handle_incoming_sms_indication(self, &args); + return NULL; } } @@ -518,6 +568,16 @@ qti_radio_ext_add_ring_handler( SIGNAL_EXT_ON_RING_NAME, G_CALLBACK(handler), user_data) : 0; } +gulong +qti_radio_ext_add_incoming_sms_handler( + QtiRadioExt* self, + QtiRadioExtIncomingSmsFunc handler, + void* user_data) +{ + return (G_LIKELY(self) && G_LIKELY(handler)) ? g_signal_connect(self, + SIGNAL_EXT_ON_INCOMING_SMS_NAME, G_CALLBACK(handler), user_data) : 0; +} + static GBinderLocalReply* qti_radio_ext_response( @@ -1061,8 +1121,6 @@ qti_radio_ext_answer_args( gint32 presentation = va_arg(va, gint32); gint32 mode = va_arg(va, gint32); - // answer(CallType callType, IpPresentation presentation, RttMode mode); - gbinder_writer_append_int32(args, call_type); gbinder_writer_append_int32(args, presentation); gbinder_writer_append_int32(args, mode); @@ -1111,7 +1169,6 @@ qti_radio_ext_hangup_args( qti_radio_hangup_request_info_f }; - // hangup(HangupRequestInfo hangup); QtiRadioHangupRequestInfo* hangup_request_writer = gbinder_writer_new0(args, QtiRadioHangupRequestInfo); // empty vec @@ -1156,7 +1213,126 @@ qti_radio_ext_hangup( call_id); } -// GET_IMS_REG_STATE +static +void +qti_radio_ext_send_ims_sms_args( + GBinderWriter* args, + va_list va) +{ + const char* smsc = va_arg(va, const char*); + const void* pdu = va_arg(va, const void*); + gsize pdu_len = va_arg(va, gsize); + guint msg_ref = va_arg(va, guint); + BINDER_EXT_SMS_SEND_FLAGS flags = va_arg(va, BINDER_EXT_SMS_SEND_FLAGS); + + + static const GBinderWriterField qti_radio_ims_sms_message_f[] = { + GBINDER_WRITER_FIELD_HIDL_STRING + (QtiRadioImsSmsMessage, format), + GBINDER_WRITER_FIELD_HIDL_STRING + (QtiRadioImsSmsMessage, smsc), + GBINDER_WRITER_FIELD_HIDL_VEC_BYTE + (QtiRadioImsSmsMessage, pdu), + GBINDER_WRITER_FIELD_END() + }; + + static const GBinderWriterType qti_radio_ims_sms_message_t = { + GBINDER_WRITER_STRUCT_NAME_AND_SIZE(QtiRadioImsSmsMessage), + qti_radio_ims_sms_message_f + }; + + QtiRadioImsSmsMessage* sms = gbinder_writer_new0(args, QtiRadioImsSmsMessage); + + sms->message_ref = msg_ref; + + // I guess? + // we don't need to retry as ofono will handle it + sms->shall_retry = FALSE; + + binder_copy_hidl_string(args, &sms->format, "3gpp"); + binder_copy_hidl_string(args, &sms->smsc, smsc); + + GBinderHidlVec* pdu_vec = gbinder_writer_new0(args, GBinderHidlVec); + pdu_vec->count = pdu_len; + pdu_vec->data.ptr = gbinder_writer_memdup(args, pdu, pdu_len); + pdu_vec->owns_buffer = TRUE; + + sms->pdu = *pdu_vec; + + gbinder_writer_append_struct(args, sms, &qti_radio_ims_sms_message_t, NULL); +} + +guint +qti_radio_ext_send_ims_sms( + QtiRadioExt* self, + const char* smsc, + const void* pdu, + gsize pdu_len, + guint msg_ref, + BINDER_EXT_SMS_SEND_FLAGS flags, + QtiRadioExtResultFunc complete, + GDestroyNotify destroy, + void* user_data) +{ + return qti_radio_ext_result_request_submit(self, + QTI_RADIO_REQ_SEND_IMS_SMS, + QTI_RADIO_RESP_SEND_IMS_SMS, + qti_radio_ext_send_ims_sms_args, + complete, destroy, user_data, + smsc, pdu, pdu_len, msg_ref, flags); +} + +static +void +qti_radio_ext_acknowledge_sms_args( + GBinderWriter* args, + va_list va) +{ + guint32 message_ref = va_arg(va, guint32); + guint32 sms_result = va_arg(va, guint32); + + gbinder_writer_append_int32(args, message_ref); + gbinder_writer_append_int32(args, sms_result); +} + +guint +qti_radio_ext_acknowledge_sms( + QtiRadioExt* self, + guint32 message_ref, + gboolean sms_result, + QtiRadioExtResultFunc complete, + GDestroyNotify destroy, + void* user_data) +{ + QTI_RADIO_IMS_SMS_DELIVER_STATUS_RESULT sms_result_code = sms_result ? QTI_RADIO_DELIVER_STATUS_OK : QTI_RADIO_DELIVER_STATUS_ERROR; + + return qti_radio_ext_result_request_submit(self, + QTI_RADIO_REQ_ACK_SMS, + QTI_RADIO_RESP_ACK_SMS, + qti_radio_ext_acknowledge_sms_args, + complete, destroy, user_data, + message_ref, sms_result_code); +} + +guint +qti_radio_ext_acknowledge_sms_report( + QtiRadioExt* self, + guint32 message_ref, + gboolean sms_report, + QtiRadioExtResultFunc complete, + GDestroyNotify destroy, + void* user_data) +{ + QTI_RADIO_IMS_SMS_STATUS_REPORT_RESULT sms_report_code = sms_report ? QTI_RADIO_STATUS_REPORT_OK : QTI_RADIO_STATUS_REPORT_ERROR; + + return qti_radio_ext_result_request_submit(self, + QTI_RADIO_REQ_ACK_SMS_REPORT, + QTI_RADIO_RESP_ACK_SMS_REPORT, + qti_radio_ext_acknowledge_sms_args, + complete, destroy, user_data, + message_ref, sms_report_code); +} + static void @@ -1224,6 +1400,10 @@ qti_radio_ext_class_init( g_signal_new(SIGNAL_EXT_ON_RING_NAME, G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0); + qti_radio_ext_signals[SIGNAL_EXT_ON_INCOMING_SMS] = + g_signal_new(SIGNAL_EXT_ON_INCOMING_SMS_NAME, G_OBJECT_CLASS_TYPE(klass), + G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, G_TYPE_NONE, + 2, G_TYPE_POINTER, G_TYPE_UINT); } /* diff --git a/src/qti_radio_ext.h b/src/qti_radio_ext.h index f0d09dd..67ee233 100644 --- a/src/qti_radio_ext.h +++ b/src/qti_radio_ext.h @@ -20,6 +20,7 @@ #include #include #include +#include #include "qti_radio_ext_types.h" @@ -47,6 +48,13 @@ typedef void (*QtiRadioExtRingFunc)( QtiRadioExt* radio, void* user_data); + +typedef void (*QtiRadioExtIncomingSmsFunc)( + QtiRadioExt* radio, + const void* pdu, + guint pdu_len, + void* user_data); + QtiRadioExt* qti_radio_ext_new( const char* dev, @@ -107,6 +115,18 @@ qti_radio_ext_hangup( GDestroyNotify destroy, void* user_data); +guint +qti_radio_ext_send_ims_sms( + QtiRadioExt* self, + const char* smsc, + const void* pdu, + gsize pdu_len, + guint msg_ref, + BINDER_EXT_SMS_SEND_FLAGS flags, + QtiRadioExtResultFunc complete, + GDestroyNotify destroy, + void* user_data); + guint qti_radio_ext_get_ims_reg_state( QtiRadioExt* self, @@ -132,6 +152,30 @@ qti_radio_ext_add_ring_handler( QtiRadioExtRingFunc handler, void* user_data); +gulong +qti_radio_ext_add_incoming_sms_handler( + QtiRadioExt* self, + QtiRadioExtIncomingSmsFunc handler, + void* user_data); + +guint +qti_radio_ext_acknowledge_sms( + QtiRadioExt* self, + guint32 message_ref, + gboolean sms_result, + QtiRadioExtResultFunc complete, + GDestroyNotify destroy, + void* user_data); + +guint +qti_radio_ext_acknowledge_sms_report( + QtiRadioExt* self, + guint32 message_ref, + gboolean sms_report, + QtiRadioExtResultFunc complete, + GDestroyNotify destroy, + void* user_data); + #endif /* QTI_RADIO_EXT_H */ /* diff --git a/src/qti_radio_ext_types.h b/src/qti_radio_ext_types.h index 937190c..6f9f74f 100644 --- a/src/qti_radio_ext_types.h +++ b/src/qti_radio_ext_types.h @@ -2,6 +2,7 @@ * oFono - Open Source Telephony - binder based adaptation QTI plugin * * Copyright (C) 2024 TheKit + * Copyright (C) 2024 Marius Gripsgard * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -208,6 +209,157 @@ typedef enum qti_radio_rtt_mode { QTI_RADIO_RTT_MODE_INVALID = 2, } QTI_RADIO_RTT_MODE; + +/* +enum ImsSmsSendStatusResult : int32_t { + // Message was sent successfully. + SEND_STATUS_OK, + // IMS provider failed to send the message and platform + should not retry falling back to sending the message + using the radio. + SEND_STATUS_ERROR, + // IMS provider failed to send the message and platform + should retry again after setting TP-RD + SEND_STATUS_ERROR_RETRY, + // IMS provider failed to send the message and platform + should retry falling back to sending the message + using the radio. + SEND_STATUS_ERROR_FALLBACK, +}; +*/ + +typedef enum qti_radio_ims_sms_send_status_result { + QTI_RADIO_SEND_STATUS_OK = 0, + QTI_RADIO_SEND_STATUS_ERROR = 1, + QTI_RADIO_SEND_STATUS_ERROR_RETRY = 2, + QTI_RADIO_SEND_STATUS_ERROR_FALLBACK = 3, +} QTI_RADIO_IMS_SMS_SEND_STATUS_RESULT; + +/* +enum ImsSmsSendFailureReason : int32_t { + RESULT_ERROR_NONE, + // Generic failure cause + RESULT_ERROR_GENERIC_FAILURE, + // Failed because radio was explicitly turned off + RESULT_ERROR_RADIO_OFF, + // Failed because no pdu provided + RESULT_ERROR_NULL_PDU, + // Failed because service is currently unavailable + RESULT_ERROR_NO_SERVICE, + // Failed because we reached the sending queue limit. + RESULT_ERROR_LIMIT_EXCEEDED, + // Failed because user denied the sending of this short code. + RESULT_ERROR_SHORT_CODE_NOT_ALLOWED, + // Failed because the user has denied this app + ever send premium short codes. + RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED, +}; +*/ + +typedef enum qti_radio_ims_sms_send_failure_reason { + QTI_RADIO_RESULT_ERROR_NONE = 0, + QTI_RADIO_RESULT_ERROR_GENERIC_FAILURE = 1, + QTI_RADIO_RESULT_ERROR_RADIO_OFF = 2, + QTI_RADIO_RESULT_ERROR_NULL_PDU = 3, + QTI_RADIO_RESULT_ERROR_NO_SERVICE = 4, + QTI_RADIO_RESULT_ERROR_LIMIT_EXCEEDED = 5, + QTI_RADIO_RESULT_ERROR_SHORT_CODE_NOT_ALLOWED = 6, + QTI_RADIO_RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED = 7, +} QTI_RADIO_IMS_SMS_SEND_FAILURE_REASON; + + +/* +enum ImsSmsDeliverStatusResult : int32_t { + Message was delivered successfully. + DELIVER_STATUS_OK, + Message was not delivered. + DELIVER_STATUS_ERROR, +}; +*/ + +typedef enum qti_radio_ims_sms_deliver_status_result { + QTI_RADIO_DELIVER_STATUS_OK = 0, + QTI_RADIO_DELIVER_STATUS_ERROR = 1, +} QTI_RADIO_IMS_SMS_DELIVER_STATUS_RESULT; + +/* +enum ImsSmsStatusReportResult : int32_t { + // Status Report was set successfully. + STATUS_REPORT_STATUS_OK, + // Error while setting status report + STATUS_REPORT_STATUS_ERROR, +}; +*/ + +typedef enum qti_radio_ims_sms_status_report_result { + QTI_RADIO_STATUS_REPORT_OK = 0, + QTI_RADIO_STATUS_REPORT_ERROR = 1, +} QTI_RADIO_IMS_SMS_STATUS_REPORT_RESULT; + +/* +enum VerificationStatus : int32_t { + //Telephone number is not validated. + STATUS_VALIDATION_NONE, + //Telephone number validation passed. + STATUS_VALIDATION_PASS, + // Telephone number validation failed. + STATUS_VALIDATION_FAIL, +}; +*/ + +typedef enum qti_radio_verification_status { + QTI_RADIO_VALIDATION_NONE = 0, + QTI_RADIO_VALIDATION_PASS = 1, + QTI_RADIO_VALIDATION_FAIL = 2, +} QTI_RADIO_VERIFICATION_STATUS; + +/* +struct ImsSmsMessage { + uint32_t messageRef; + string format; + string smsc; + bool shallRetry; + vec pdu; +}; +*/ + +typedef struct qti_radio_ims_sms_message { + guint32 message_ref RADIO_ALIGNED(4); + GBinderHidlString format RADIO_ALIGNED(8); + GBinderHidlString smsc RADIO_ALIGNED(8); + guint8 shall_retry RADIO_ALIGNED(1); + GBinderHidlVec pdu RADIO_ALIGNED(8); +} RADIO_ALIGNED(8) QtiRadioImsSmsMessage; + +/* +struct ImsSmsSendStatusReport { + uint32_t messageRef; + string format; + vec pdu; +}; +*/ + +typedef struct qti_radio_ims_sms_send_status_report { + guint32 message_ref RADIO_ALIGNED(4); + GBinderHidlString format RADIO_ALIGNED(8); + GBinderHidlVec pdu RADIO_ALIGNED(8); +} RADIO_ALIGNED(8) QtiRadioImsSmsSendStatusReport; + +/* +struct IncomingImsSms { + string format; + vec pdu; + VerificationStatus verstat; +}; +*/ + +typedef struct qti_radio_incoming_ims_sms { + GBinderHidlString format RADIO_ALIGNED(8); + GBinderHidlVec pdu RADIO_ALIGNED(8); + guint32 verstat RADIO_ALIGNED(4); +} RADIO_ALIGNED(8) QtiRadioIncomingImsSms; + + /* struct RegistrationInfo { @@ -216,7 +368,7 @@ struct RegistrationInfo { string errorMessage; RadioTechType radioTech; string pAssociatedUris; -}; +}; */ typedef struct qti_radio_reg_info { @@ -273,7 +425,7 @@ struct ServiceStatusInfo { vec accTechStatus; RttMode rttMode; }; - + */ typedef struct qti_radio_service_status_info { @@ -490,7 +642,10 @@ typedef enum ims_radio_resp { e(23, callStateChanged_1_1, CALL_STATE_INDICATION_1_1) #define QTI_RADIO_IND_1_2(e) \ - e(24, callStateChanged_1_2, CALL_STATE_INDICATION_1_2) + e(24, callStateChanged_1_2, CALL_STATE_INDICATION_1_2) \ + e(25, onImsSmsStatusReport, SMS_STATUS_REPORT_INDICATION) \ + e(26, onIncomingImsSms, INCOMING_SMS_INDICATION) \ + e(27, onVopsChanged, VOPS_CHANGED_INDICATION) typedef enum ims_radio_ind { /* vendor.mediatek.hardware.qtiradioex@3.0::IImsRadioIndication */ diff --git a/src/qti_slot.c b/src/qti_slot.c index a4e3090..73cf032 100644 --- a/src/qti_slot.c +++ b/src/qti_slot.c @@ -40,6 +40,7 @@ #include "qti_ims.h" #include "qti_radio_ext.h" #include "qti_ims_call.h" +#include "qti_ims_sms.h" #include @@ -56,6 +57,7 @@ typedef struct qti_slot { BinderExtIms* ims; QtiRadioExt* radio_ext; BinderExtCall* call; + BinderExtSms* sms; } QtiSlot; GType qti_slot_get_type() G_GNUC_INTERNAL; @@ -92,6 +94,8 @@ qti_slot_get_interface( return self->ims; } else if (iface == BINDER_EXT_TYPE_CALL) { return self->call; + } else if (iface == BINDER_EXT_TYPE_SMS) { + return self->sms; } else { return BINDER_EXT_SLOT_CLASS(PARENT_CLASS)->get_interface(slot, iface); } @@ -123,6 +127,7 @@ qti_slot_new( if (self->radio_ext) { self->ims = qti_ims_new(radio_slot, self->radio_ext); self->call = qti_ims_call_new(self->radio_ext); + self->sms = qti_ims_sms_new(self->radio_ext); } else { DBG("slot->radio_ext is null "); }