From 8d8c6c94c06d4aba1d0f500d1a08735a3140b870 Mon Sep 17 00:00:00 2001
From: Grzegorz Sluja <grzegorz.sluja@iopsys.eu>
Date: Wed, 5 Mar 2025 15:37:32 +0000
Subject: [PATCH] Handle hangup cause for ringing and callwt stop signals, REF
 16384

The ringing and callwt stop signals received in voicemngr includes additional
information sent by asterisk about the hangup cause. If the
data=answered in mentioned signals then the call is answered by other
extension connected to the same line to which incoming call was proceeded.
Otherwise the signals are received with data=null what means it is a missed
call. Handle it properly in voicemngr, sending the corresponding information
to dectmngr about the reason of stop-ringing.
---
 libvoice/voice-types.h |  7 +++++++
 line-dect.c            |  1 +
 line.c                 | 14 +++++++++++---
 line.h                 |  2 ++
 ubus.c                 | 18 +++++++++++-------
 5 files changed, 32 insertions(+), 10 deletions(-)

diff --git a/libvoice/voice-types.h b/libvoice/voice-types.h
index d246732..95f1ef3 100644
--- a/libvoice/voice-types.h
+++ b/libvoice/voice-types.h
@@ -73,6 +73,12 @@ typedef enum flash_spec {
 	FLASH_SPEC_ETSI,
 } flash_spec;
 
+// The possible values of DECTMNGR_RPC_PARAM_HANGUPCAUSE
+enum hangup_cause {
+	HANGUPCAUSE_UNANSWERED = 0,
+	HANGUPCAUSE_ANSWERED_ELSEWERE,
+};
+
 /*
  * UBUS related definitions
  */
@@ -84,5 +90,6 @@ typedef enum flash_spec {
 // Parameters
 #define DECTMNGR_RPC_PARAM_EXTENSION_ID  "extension_id"
 #define DECTMNGR_RPC_PARAM_PCM_ID        "pcm_id"
+#define DECTMNGR_RPC_PARAM_HANGUPCAUSE   "hangupcause"
 
 #endif
diff --git a/line-dect.c b/line-dect.c
index af839a8..3d9454b 100644
--- a/line-dect.c
+++ b/line-dect.c
@@ -131,6 +131,7 @@ int ubus_process_queued_reqs_to_dectmngr(void) {
 		case ACTION_RINGING_STOP:
 			dectmngr_rpc.action = req->action;
 			dectmngr_rpc.extension_id = voicemngr_line_to_dectmngr_line(req->line);
+			dectmngr_rpc.params.hangupcause = req->hangupcause;
 			if(ubus_dectmngr_rpc(&dectmngr_rpc, req)) {
 				free(req);
 				return -1;
diff --git a/line.c b/line.c
index 5cb2203..3784e53 100644
--- a/line.c
+++ b/line.c
@@ -156,9 +156,9 @@ static void setCallerName(const char *data, char *callerName)
 static int line_signal_ring(int line, int pcm, enum VOICE_SIGNAL signal, const char *data, struct voice_ubus_req_t *ubus_req)
 {
 	struct line_req_t *line_req = NULL;
-	int start_ring = data && strcmp(data, "0") != 0;
+	int start_ring = data && strcmp(data, "0") != 0 && strcmp(data, "answered") != 0;
 
-	ENDPT_DBG("line=%d, pcm=%d, data=%s\n", line, pcm, data);
+	ENDPT_DBG("line=%d, pcm=%d, data=%s, start_ring: %d\n", line, pcm, data, start_ring);
 	pcm_states_dump(__func__, line);
 
 	// Relay the request to dectmngr if the line is DECT
@@ -210,6 +210,10 @@ static int line_signal_ring(int line, int pcm, enum VOICE_SIGNAL signal, const c
 					line_req->action = ACTION_SIG_RING;
 				} else {
 					line_req->action = ACTION_RINGING_STOP;
+					if (strcmp(data, "answered") == 0)
+						line_req->hangupcause = HANGUPCAUSE_ANSWERED_ELSEWERE;
+					else
+						line_req->hangupcause = HANGUPCAUSE_UNANSWERED;
 				}
 				line_req->caller_id[0] = 0; // Discard enable/disable char or it will become the caller ID
 			} else {
@@ -220,6 +224,10 @@ static int line_signal_ring(int line, int pcm, enum VOICE_SIGNAL signal, const c
 			if(line_req) {
 				if(!start_ring) {
 					line_req->action = ACTION_RINGING_STOP;
+					if (strcmp(data, "answered") == 0)
+						line_req->hangupcause = HANGUPCAUSE_ANSWERED_ELSEWERE;
+					else
+						line_req->hangupcause = HANGUPCAUSE_UNANSWERED;
 				}
 				line_req->caller_id[0] = 0; // Discard enable/disable char or it will become the caller ID
 				break;
@@ -323,7 +331,7 @@ int line_signal(int line, const char *signame, const char *data, struct voice_ub
 					res = line_signal_ring(line, get_callid_state(lines[line].pcm_callid[PCM_1]) == CALLID_INVALID ?
 							PCM_1 : PCM_0, VOICE_SIG_CALLID, data, ubus_req);
 					lines[line].signaled_call_waiting = 1;
-				} else if(data && (data[0] == '0')) {
+				} else if(data && ((data[0] == '0') || (strcmp(data, "answered") == 0))) {
 					// stop call waiting when accepted but not close the connection on the accepted line
 					res = line_signal_ring(line, get_callid_state(lines[line].pcm_callid[PCM_1]) == CALLID_OBTAINING ?
 							PCM_1 : PCM_0, VOICE_SIG_CALL_WAITING, data, ubus_req);
diff --git a/line.h b/line.h
index 64a212d..7287c37 100644
--- a/line.h
+++ b/line.h
@@ -42,6 +42,7 @@ struct line_req_t {
 	char caller_name[MAX_CALLER_NAME]; // Caller Name
 	struct voice_ubus_req_t ubus;
 	struct timespec time_stamp;
+	enum hangup_cause hangupcause;
 };
 
 struct dectmngr_rpc_t {
@@ -50,6 +51,7 @@ struct dectmngr_rpc_t {
 	int  pcm_id;
 	union {
 		// Action specific parameters will be added here
+		enum hangup_cause hangupcause;
 	} params;
 };
 
diff --git a/ubus.c b/ubus.c
index ce4f3cf..10c7d40 100644
--- a/ubus.c
+++ b/ubus.c
@@ -568,22 +568,24 @@ static int ubus_request_signal(struct ubus_context *uctx, struct ubus_object *ob
 	}
 
 	signame = blobmsg_get_string(keys[SIGNAL_TYPE]);
-	ENDPT_DBG("line=%d, signame=%s\n", line, signame);
 
 	// on or off signal?
 	enable = "0";
-	data = NULL;
 	state = blobmsg_get_string(keys[SIGNAL_STATE]);
 	if (strcmp(state, "on") == 0) {
 		enable = "1";
-		// Do we have extra data that should be passed to endpoint?
-		if (keys[SIGNAL_DATA])
-			data = blobmsg_get_string(keys[SIGNAL_DATA]);
 	} else if (strcmp(state, "off")) {
 		ENDPT_ERR("Error! invalid state %s\n", state);
 		return UBUS_STATUS_INVALID_ARGUMENT;
 	}
 
+	// Do we have extra data that should be passed to endpoint?
+	if (keys[SIGNAL_DATA])
+		data = blobmsg_get_string(keys[SIGNAL_DATA]);
+	else
+		data = NULL;
+
+	ENDPT_DBG("line=%d, signame=%s, state=%s, data=%s\n", line, signame, state, data?data:"");
 	// Prepare for possibly deferring the request
 	memset(&ubusReq, 0, sizeof(struct voice_ubus_req_t));
 	clock_gettime(CLOCK_MONOTONIC, &ubusReq.timeStamp);
@@ -1205,9 +1207,11 @@ int ubus_dectmngr_rpc(const struct dectmngr_rpc_t *dectmngr_rpc, const struct li
 	switch (dectmngr_rpc->action) {
 	case ACTION_RINGING_STOP:
 		blobmsg_add_u32(&bb, DECTMNGR_RPC_PARAM_EXTENSION_ID, dectmngr_rpc->extension_id);
+		blobmsg_add_u32(&bb, DECTMNGR_RPC_PARAM_HANGUPCAUSE, dectmngr_rpc->params.hangupcause);
 		res = ubus_invoke_async(ctx, dectmngr_rpc_id, DECTMNGR_RPC_RINGING_STOP, bb.head, req);
-		ENDPT_DBG("Invoke ubus call %s %s {'%s':%d}\n", DECTMNGR_RPC_UBUS_OBJECT, DECTMNGR_RPC_RINGING_STOP,
-				DECTMNGR_RPC_PARAM_EXTENSION_ID, dectmngr_rpc->extension_id);
+		ENDPT_DBG("Invoke ubus call %s %s {'%s':%d,'%s':%d}\n", DECTMNGR_RPC_UBUS_OBJECT, DECTMNGR_RPC_RINGING_STOP,
+				DECTMNGR_RPC_PARAM_EXTENSION_ID, dectmngr_rpc->extension_id,
+				DECTMNGR_RPC_PARAM_HANGUPCAUSE, dectmngr_rpc->params.hangupcause);
 		break;
 
 	case ACTION_CONN_CLOSE:
-- 
GitLab