r3657 - in trunk/src/target/gsm: include/gsmd include/libgsmd src/gsmd src/libgsmd src/util

erin_yueh at sita.openmoko.org erin_yueh at sita.openmoko.org
Mon Dec 17 10:31:14 CET 2007


Author: erin_yueh
Date: 2007-12-17 10:31:02 +0100 (Mon, 17 Dec 2007)
New Revision: 3657

Modified:
   trunk/src/target/gsm/include/gsmd/usock.h
   trunk/src/target/gsm/include/libgsmd/phonebook.h
   trunk/src/target/gsm/include/libgsmd/voicecall.h
   trunk/src/target/gsm/src/gsmd/ext_response.c
   trunk/src/target/gsm/src/gsmd/gsmd.c
   trunk/src/target/gsm/src/gsmd/unsolicited.c
   trunk/src/target/gsm/src/gsmd/usock.c
   trunk/src/target/gsm/src/libgsmd/libgsmd_voicecall.c
   trunk/src/target/gsm/src/util/event.c
   trunk/src/target/gsm/src/util/shell.c
Log:
gsmd: conference call support (Sean Chiang)


Modified: trunk/src/target/gsm/include/gsmd/usock.h
===================================================================
--- trunk/src/target/gsm/include/gsmd/usock.h	2007-12-15 23:07:18 UTC (rev 3656)
+++ trunk/src/target/gsm/include/gsmd/usock.h	2007-12-17 09:31:02 UTC (rev 3657)
@@ -42,6 +42,7 @@
 	GSMD_VOICECALL_VOL_SET	= 5,
 	GSMD_VOICECALL_VOL_GET	= 6,
 	GSMD_VOICECALL_GET_STAT	= 7,
+	GSMD_VOICECALL_CTRL	= 8,
 };
 
 
@@ -81,6 +82,23 @@
 	GSMD_CALL_MPTY_YES	= 1,
 };
 
+/* 
+ * call related supplementary services from 3GPP TS 02.30 4.5.5.1 
+ * R - Release
+ * A - Accept
+ * H - Hold
+ * M - Multiparty
+ */
+enum gsmd_call_ctrl_proc {
+	GSMD_CALL_CTRL_R_HLDS			= 0,	// 0
+	GSMD_CALL_CTRL_UDUB			= 1,	// 0
+	GSMD_CALL_CTRL_R_ACTS_A_HLD_WAIT	= 2,	// 1	
+	GSMD_CALL_CTRL_R_ACT_X			= 3,	// 1x
+	GSMD_CALL_CTRL_H_ACTS_A_HLD_WAIT	= 4,	// 2
+	GSMD_CALL_CTRL_H_ACTS_EXCEPT_X		= 5,	// 2x
+	GSMD_CALL_CTRL_M_HELD			= 6,	// 3
+};
+
 /* Handset / MT related commands */
 enum gsmd_msg_phone_type {
 	GSMD_PHONE_VOLUME	= 1,
@@ -360,6 +378,12 @@
 	int is_last;	
 } __attribute__ ((packed));
 
+/* call status from 3GPP TS 07.07 clause 7.12 */
+struct gsmd_call_ctrl {
+	enum gsmd_call_ctrl_proc proc;	
+	u_int8_t idx;
+} __attribute__ ((packed));
+
 #define GSMD_PIN_MAXLEN		8
 struct gsmd_pin {
 	enum gsmd_pin_type type;
@@ -425,6 +449,12 @@
 		struct {
 			enum gsm0705_cms_error number;
 		} cms_err;
+		struct {
+			struct gsmd_addr addr;
+			u_int8_t classx;
+			char	alpha[16];
+			u_int8_t cli; 
+		} ccwa;
 	} u;
 	u_int8_t data[0];        
 } __attribute__ ((packed));

Modified: trunk/src/target/gsm/include/libgsmd/phonebook.h
===================================================================
--- trunk/src/target/gsm/include/libgsmd/phonebook.h	2007-12-15 23:07:18 UTC (rev 3656)
+++ trunk/src/target/gsm/include/libgsmd/phonebook.h	2007-12-17 09:31:02 UTC (rev 3657)
@@ -84,10 +84,4 @@
 /* Get the location range/nlength/tlength supported */
 extern int lgsm_pb_get_support(struct lgsm_handle *lh);
 
-/* Retrieve the records of READRG request */
-extern int lgsm_pb_retrieve_readrg(struct lgsm_handle *lh, int num);
-
-/* Retrieve the records of FIND request */
-extern int lgsm_pb_retrieve_find(struct lgsm_handle *lh, int num);
-
 #endif

Modified: trunk/src/target/gsm/include/libgsmd/voicecall.h
===================================================================
--- trunk/src/target/gsm/include/libgsmd/voicecall.h	2007-12-15 23:07:18 UTC (rev 3656)
+++ trunk/src/target/gsm/include/libgsmd/voicecall.h	2007-12-17 09:31:02 UTC (rev 3657)
@@ -5,6 +5,29 @@
 
 /* Voice Calls */
 
+/* 
+ * call related supplementary services from 3GPP TS 02.30 4.5.5.1 
+ * R - Release
+ * A - Accept
+ * H - Hold
+ * M - Multiparty
+ */
+enum lgsm_voicecall_ctrl_proc {
+	LGSM_VOICECALL_CTRL_R_HLDS			= 0,	// 0
+	LGSM_VOICECALL_CTRL_UDUB			= 1,	// 0
+	LGSM_VOICECALL_CTRL_R_ACTS_A_HLD_WAIT		= 2,	// 1	
+	LGSM_VOICECALL_CTRL_R_ACT_X			= 3,	// 1x
+	LGSM_VOICECALL_CTRL_H_ACTS_A_HLD_WAIT		= 4,	// 2
+	LGSM_VOICECALL_CTRL_H_ACTS_EXCEPT_X		= 5,	// 2x
+	LGSM_VOICECALL_CTRL_M_HELD			= 6,	// 3
+};
+
+/* Refer to GSM 07.07 subclause 7.12 and 02.30 subclause 4.5.5.1 */
+struct lgsm_voicecall_ctrl {
+	enum lgsm_voicecall_ctrl_proc proc;	
+	int idx;
+};
+
 /* Initiate an outgoing voice call */
 extern int lgsm_voice_out_init(struct lgsm_handle *lh, 
 			       const struct lgsm_addr *number);
@@ -21,4 +44,8 @@
 /* Get call status */
 extern int lgsm_voice_get_status(struct lgsm_handle *lh); 
 
+/* Call control */
+extern int lgsm_voice_ctrl(struct lgsm_handle *lh, 
+			       const struct lgsm_voicecall_ctrl *ctrl);
+
 #endif

Modified: trunk/src/target/gsm/src/gsmd/ext_response.c
===================================================================
--- trunk/src/target/gsm/src/gsmd/ext_response.c	2007-12-15 23:07:18 UTC (rev 3656)
+++ trunk/src/target/gsm/src/gsmd/ext_response.c	2007-12-17 09:31:02 UTC (rev 3657)
@@ -109,16 +109,16 @@
 			}
 			break;
 		case TOKEN_NUMERIC:
-			if (isdigit(*cur)) {
-				*cur_buf = *cur;
-				cur_buf++;
-			}
-
-			if (*cur == ',' || *(cur+1) == '\0') {
+			if (*cur == ',') {
 				/* end of number */
 				cur_token->u.numeric = atoi(buf);
 				er->num_tokens++;
 				state = IDLE;
+			} else if (isdigit(*cur)) {
+				*cur_buf = *cur;
+				cur_buf++;
+			} else {
+				/* ERORR */
 			}
 			break;
 		case TOKEN_STRING:
@@ -170,6 +170,12 @@
 		cur++;
 	}
 
+	if (state == TOKEN_NUMERIC) {
+		/* end of number */
+		cur_token->u.numeric = atoi(buf);
+		er->num_tokens++;
+	}
+
 	//extrsp_dump(er);
 	return er;
 }

Modified: trunk/src/target/gsm/src/gsmd/gsmd.c
===================================================================
--- trunk/src/target/gsm/src/gsmd/gsmd.c	2007-12-15 23:07:18 UTC (rev 3656)
+++ trunk/src/target/gsm/src/gsmd/gsmd.c	2007-12-17 09:31:02 UTC (rev 3657)
@@ -171,6 +171,8 @@
 	rc |= gsmd_simplecmd(gsmd, "AT+CLIP=1");
 	/* use +COLP: to indicate COLP */
 	rc |= gsmd_simplecmd(gsmd, "AT+COLP=1");
+	/* use +CCWA: to indicate waiting call */
+	rc |= gsmd_simplecmd(gsmd, "AT+CCWA=1,1");
 	/* configure message format as PDU mode*/
 	/* FIXME: TEXT mode support!! */
 	rc |= gsmd_simplecmd(gsmd, "AT+CMGF=0");

Modified: trunk/src/target/gsm/src/gsmd/unsolicited.c
===================================================================
--- trunk/src/target/gsm/src/gsmd/unsolicited.c	2007-12-15 23:07:18 UTC (rev 3656)
+++ trunk/src/target/gsm/src/gsmd/unsolicited.c	2007-12-17 09:31:02 UTC (rev 3657)
@@ -253,34 +253,58 @@
 static int ccwa_parse(char *buf, int len, const char *param,
 		      struct gsmd *gsmd)
 {
-	const char *token;
-	unsigned int type;
+	struct gsmd_evt_auxdata *aux;
+	struct gsm_extrsp *er;
 	struct gsmd_ucmd *ucmd = usock_build_event(GSMD_MSG_EVENT, GSMD_EVT_CALL_WAIT,
-					     sizeof(struct gsmd_addr));
-	struct gsmd_addr *gaddr;
-
+					     sizeof(struct gsmd_evt_auxdata));
+	
 	if (!ucmd)
 		return -ENOMEM;
 
-	gaddr = (struct gsmd_addr *) ucmd->buf;
-	memset(gaddr, 0, sizeof(*gaddr));
+	aux = (struct gsmd_evt_auxdata *) ucmd->buf;
+	
+	er = extrsp_parse(gsmd_tallocs, param);
 
-	/* parse address (phone number) */
-	token = strtok(buf, ",");
-	if (!token)
-		return -EINVAL;
-	strncpy(gaddr->number, token, GSMD_ADDR_MAXLEN);
+	if ( !er ) 
+		return -ENOMEM;
 
-	/* parse type */
-	token = strtok(NULL, ",");
-	if (!token)
+	if ( er->num_tokens == 5 &&
+			er->tokens[0].type == GSMD_ECMD_RTT_STRING &&
+			er->tokens[1].type == GSMD_ECMD_RTT_NUMERIC &&
+			er->tokens[2].type == GSMD_ECMD_RTT_NUMERIC &&
+			er->tokens[3].type == GSMD_ECMD_RTT_EMPTY &&
+			er->tokens[4].type == GSMD_ECMD_RTT_NUMERIC ) {
+		/*
+		 * <number>,<type>,<class>,[<alpha>][,<CLI validity>]
+		 */
+		
+		strcpy(aux->u.ccwa.addr.number, er->tokens[0].u.string);
+		aux->u.ccwa.addr.type = er->tokens[1].u.numeric;
+		aux->u.ccwa.classx = er->tokens[2].u.numeric;
+		aux->u.ccwa.alpha[0] = '\0';
+		aux->u.ccwa.cli = er->tokens[4].u.numeric; 
+	} 
+	else if ( er->num_tokens == 5 &&
+			er->tokens[0].type == GSMD_ECMD_RTT_STRING &&
+			er->tokens[1].type == GSMD_ECMD_RTT_NUMERIC &&
+			er->tokens[2].type == GSMD_ECMD_RTT_NUMERIC &&
+			er->tokens[3].type == GSMD_ECMD_RTT_STRING &&
+			er->tokens[4].type == GSMD_ECMD_RTT_NUMERIC ) {
+		/*
+		 * <number>,<type>,<class>,[<alpha>][,<CLI validity>]
+		 */
+		
+		strcpy(aux->u.ccwa.addr.number, er->tokens[0].u.string);
+		aux->u.ccwa.addr.type = er->tokens[1].u.numeric;
+		aux->u.ccwa.classx = er->tokens[2].u.numeric;
+		strcpy(aux->u.ccwa.alpha, er->tokens[3].u.string);
+		aux->u.ccwa.cli = er->tokens[4].u.numeric; 
+	}
+	else {
+		DEBUGP("Invalid Input : Parse error\n");
 		return -EINVAL;
-	type = atoi(token) & 0xff;
-	gaddr->type = type;
+	}
 
-	/* FIXME: parse class */
-	token = strtok(NULL, ",");
-
 	return usock_evt_send(gsmd, ucmd, GSMD_EVT_CALL_WAIT);
 }
 

Modified: trunk/src/target/gsm/src/gsmd/usock.c
===================================================================
--- trunk/src/target/gsm/src/gsmd/usock.c	2007-12-15 23:07:18 UTC (rev 3656)
+++ trunk/src/target/gsm/src/gsmd/usock.c	2007-12-17 09:31:02 UTC (rev 3657)
@@ -200,6 +200,23 @@
 			cmd->id, sizeof(gcs), &gcs);
 }
 
+static int voicecall_ctrl_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp) 
+{
+	struct gsmd_user *gu = ctx;
+	int ret = 0;
+	
+	DEBUGP("resp: %s\n", resp);
+	
+	if ( !strncmp(resp, "+CME", 4) ) {
+		/* +CME ERROR: <err> */
+		DEBUGP("+CME error\n");
+		ret = atoi(strpbrk(resp, "0123456789"));
+	}
+
+	return gsmd_ucmd_submit(gu, GSMD_MSG_VOICECALL, GSMD_VOICECALL_CTRL,
+			cmd->id, sizeof(ret), &ret);
+}
+
 static int usock_ringing_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp)
 {
         struct gsmd_user *gu = ctx;
@@ -217,6 +234,7 @@
 	struct gsmd_atcmd *cmd = NULL;
 	struct gsmd_addr *ga;
 	struct gsmd_dtmf *gd;
+	struct gsmd_call_ctrl *gcc; 
 	int atcmd_len;
 		
 	switch (gph->msg_subtype) {
@@ -274,6 +292,44 @@
 		if (!cmd)
 			return -ENOMEM;
 		break;
+	case GSMD_VOICECALL_CTRL:
+		if (len < sizeof(*gph) + sizeof(*gcc))
+			return -EINVAL;
+
+		gcc = (struct gsmd_call_ctrl *) ((void *)gph + sizeof(*gph));
+
+		atcmd_len = 1 + strlen("AT+CHLD=") + 2;
+		cmd = atcmd_fill("AT+CHLD=", atcmd_len, &voicecall_ctrl_cb,
+				 gu, gph->id, NULL);
+		if (!cmd)
+			return -ENOMEM;
+
+		switch (gcc->proc) {
+			case GSMD_CALL_CTRL_R_HLDS:			
+			case GSMD_CALL_CTRL_UDUB:			
+				sprintf(cmd->buf, "AT+CHLD=%d", 0);
+				break;
+			case GSMD_CALL_CTRL_R_ACTS_A_HLD_WAIT:	
+				sprintf(cmd->buf, "AT+CHLD=%d", 1);
+				break;
+			case GSMD_CALL_CTRL_R_ACT_X:
+				sprintf(cmd->buf, "AT+CHLD=%d%d", 1, gcc->idx);
+				break;
+			case GSMD_CALL_CTRL_H_ACTS_A_HLD_WAIT:
+				sprintf(cmd->buf, "AT+CHLD=%d", 2);
+				break;
+			case GSMD_CALL_CTRL_H_ACTS_EXCEPT_X:
+				sprintf(cmd->buf, "AT+CHLD=%d%d", 2, gcc->idx);
+				break;
+			case GSMD_CALL_CTRL_M_HELD:
+				sprintf(cmd->buf, "AT+CHLD=%d", 3);
+				break;
+			default:
+				return -EINVAL;
+		}
+
+		break;
+	
 	default:
 		return -EINVAL;
 	}

Modified: trunk/src/target/gsm/src/libgsmd/libgsmd_voicecall.c
===================================================================
--- trunk/src/target/gsm/src/libgsmd/libgsmd_voicecall.c	2007-12-15 23:07:18 UTC (rev 3656)
+++ trunk/src/target/gsm/src/libgsmd/libgsmd_voicecall.c	2007-12-17 09:31:02 UTC (rev 3657)
@@ -100,3 +100,28 @@
 {
 	return lgsm_send_simple(lh, GSMD_MSG_VOICECALL, GSMD_VOICECALL_GET_STAT);
 }
+
+int lgsm_voice_ctrl(struct lgsm_handle *lh, const struct lgsm_voicecall_ctrl *ctrl)
+{
+	struct gsmd_msg_hdr *gmh;
+	struct gsmd_call_ctrl *gcc;
+	int rc;
+
+	gmh = lgsm_gmh_fill(GSMD_MSG_VOICECALL,
+			    GSMD_VOICECALL_CTRL, sizeof(*gcc));
+	if (!gmh)
+		return -ENOMEM;
+	gcc = (struct gsmd_call_ctrl *) gmh->data;
+	gcc->proc = ctrl->proc;
+	gcc->idx = ctrl->idx;
+
+	rc = lgsm_send(lh, gmh);
+	if (rc < gmh->len + sizeof(*gmh)) {
+		lgsm_gmh_free(gmh);;
+		return -EIO;
+	}
+
+	lgsm_gmh_free(gmh);
+
+	return 0;
+}

Modified: trunk/src/target/gsm/src/util/event.c
===================================================================
--- trunk/src/target/gsm/src/util/event.c	2007-12-15 23:07:18 UTC (rev 3656)
+++ trunk/src/target/gsm/src/util/event.c	2007-12-17 09:31:02 UTC (rev 3657)
@@ -194,6 +194,12 @@
 	return 0;
 }
 
+static int ccwa_handler(struct lgsm_handle *lh, int evt, struct gsmd_evt_auxdata *aux)
+{
+	printf("EVENT: Call Waiting: %s,%d\n", aux->u.ccwa.addr.number, aux->u.ccwa.addr.type);
+	return 0;
+}
+
 static const char *cprog_names[] = {
 	[GSMD_CALLPROG_SETUP]		= "SETUP",
 	[GSMD_CALLPROG_DISCONNECT]	= "DISCONNECT",
@@ -257,6 +263,7 @@
 	rc |= lgsm_evt_handler_register(lh, GSMD_EVT_SIGNAL, &sigq_handler);
 	rc |= lgsm_evt_handler_register(lh, GSMD_EVT_OUT_STATUS, &cprog_handler);
 	rc |= lgsm_evt_handler_register(lh, GSMD_EVT_IN_ERROR, &error_handler);
+	rc |= lgsm_evt_handler_register(lh, GSMD_EVT_CALL_WAIT, &ccwa_handler);
 	return rc;
 }
 

Modified: trunk/src/target/gsm/src/util/shell.c
===================================================================
--- trunk/src/target/gsm/src/util/shell.c	2007-12-15 23:07:18 UTC (rev 3656)
+++ trunk/src/target/gsm/src/util/shell.c	2007-12-17 09:31:02 UTC (rev 3657)
@@ -398,6 +398,7 @@
 static int call_msghandler(struct lgsm_handle *lh, struct gsmd_msg_hdr *gmh)
 {
 	struct gsmd_call_status *gcs;
+	int *ret;
 
 	switch (gmh->msg_subtype) {
 	case GSMD_VOICECALL_GET_STAT:
@@ -419,10 +420,14 @@
 		if (gcs->is_last)
 			pending_responses --;
 		break;
+	case GSMD_VOICECALL_CTRL:
+		ret = (int*)((char *)gmh + sizeof(*gmh));
+		 (*ret)? printf("+CME ERROR %d\n", *ret) : printf("OK\n");
+		pending_responses --;
+		break;
 	default:
 		return -EINVAL;
 	}
-	pending_responses --;
 	return 0;
 }
 
@@ -479,6 +484,13 @@
 		"\tim\tGet imsi\n"
 		"\tcs\tGet Call status\n"
 		"\tgp\tGet PIN status\n"
+		"\tRh\tRelease all held calls (+CHLD=0)\n"
+		"\tUDUB\tUser Determined User Busy (+CHLD=0)\n"
+		"\tRa\tRelease all active calls (+CHLD=1)\n"
+		"\tRx\tRelease specific active call x (Rx=x)(+CHLD=1x)\n"
+		"\tHa\tHold all active calls and accept held or waiting call (+CHLD=2)\n"
+		"\tHx\tHold all active calls except call x (Hx=x)(+CHLD=2x)\n"
+		"\tMP\tAdd a held call to the conversation (+CHLD=3)\n"
 		"\tq\tQuit\n"
 		);
 }
@@ -562,7 +574,7 @@
 			} else if (!strcmp(buf, "r")) {
 				printf("Register\n");
 				lgsm_netreg_register(lgsmh, "\0     ");
-			} else if (buf[0] == 'R') {
+			} else if (!strcmp(buf,"R")) {
 				printf("Register to operator\n");
 				ptr = strchr(buf, '=');
 				if (!ptr || strlen(ptr) < 6)
@@ -600,7 +612,7 @@
 				printf("DTMF: %c\n", buf[1]);
 				lgsm_voice_dtmf(lgsmh, buf[1]);
 			} else if ( !strncmp(buf, "pd", 2)) {
-				printf("Delete Phonebook Entry\n");				
+				printf("Delete Phonebook Entry\n");			
 				ptr = strchr(buf, '=');
 				lgsm_pb_del_entry(lgsmh, atoi(ptr+1));
 			} else if ( !strncmp(buf, "prr", 3)) {	
@@ -642,7 +654,7 @@
 				if ('+' == pb.numb[0])
 					pb.type = LGSM_PB_ATYPE_INTL;
 				else 
-					pb.type = LGSM_PB_ATYPE_OTHE;				
+					pb.type = LGSM_PB_ATYPE_OTHE;			
 				strncpy(pb.text, lcomma + 1, strlen(lcomma + 1));
 				pb.text[strlen(lcomma + 1)] = '\0';
 
@@ -758,7 +770,7 @@
 				printf("Get imsi\n");
 				lgsm_get_imsi(lgsmh);
 				pending_responses ++;
-			} else if (!strncmp(buf, "M", 1)) {
+			} else if ( strlen(buf)==1 && !strncmp(buf, "M", 1)) {
 				printf("Modem Power On\n");
 				lgsm_modem_power(lgsmh, 1);
 				pending_responses ++;
@@ -774,6 +786,53 @@
 				printf("Get PIN status\n");
 				lgsm_pin_status(lgsmh);
 				pending_responses ++;
+			} else if ( !strncmp(buf, "Rh", 2)) {
+				struct lgsm_voicecall_ctrl ctrl;	
+				ctrl.proc = LGSM_VOICECALL_CTRL_R_HLDS; 
+				printf("Release all held calls\n");
+				lgsm_voice_ctrl(lgsmh, &ctrl);
+				pending_responses ++;
+			} else if ( !strncmp(buf, "UDUB", 4)) {
+				struct lgsm_voicecall_ctrl ctrl;	
+				ctrl.proc = LGSM_VOICECALL_CTRL_UDUB; 
+				printf("User Determined User Busy\n");
+				lgsm_voice_ctrl(lgsmh, &ctrl);
+				pending_responses ++;
+			} else if ( !strncmp(buf, "Ra", 2)) {
+				struct lgsm_voicecall_ctrl ctrl;	
+				ctrl.proc = LGSM_VOICECALL_CTRL_R_ACTS_A_HLD_WAIT; 
+				printf("Release all active calls\n");
+				lgsm_voice_ctrl(lgsmh, &ctrl);
+				pending_responses ++;
+			} else if ( !strncmp(buf, "Rx", 2)) {
+				struct lgsm_voicecall_ctrl ctrl;	
+				ctrl.proc = LGSM_VOICECALL_CTRL_R_ACT_X; 
+				printf("Release specific active call x\n");
+				ptr = strchr(buf, '=');
+				ctrl.idx = atoi(ptr+1);
+				lgsm_voice_ctrl(lgsmh, &ctrl);
+				pending_responses ++;
+			} else if ( !strncmp(buf, "Ha", 2)) {
+				struct lgsm_voicecall_ctrl ctrl;	
+				ctrl.proc = LGSM_VOICECALL_CTRL_H_ACTS_A_HLD_WAIT; 
+				printf("Hold all active calls and accept held or waiting"
+				        " call\n");
+				lgsm_voice_ctrl(lgsmh, &ctrl);
+				pending_responses ++;
+			} else if ( !strncmp(buf, "Hx", 2)) {
+				struct lgsm_voicecall_ctrl ctrl;	
+				ctrl.proc = LGSM_VOICECALL_CTRL_H_ACTS_EXCEPT_X; 
+				printf("Hold all active calls except call x\n");
+				ptr = strchr(buf, '=');
+				ctrl.idx = atoi(ptr+1);
+				lgsm_voice_ctrl(lgsmh, &ctrl);
+				pending_responses ++;
+			} else if ( !strncmp(buf, "MP", 2)) {
+				struct lgsm_voicecall_ctrl ctrl;
+				ctrl.proc = LGSM_VOICECALL_CTRL_M_HELD; 
+				printf("Add a held call to the conversation\n");
+				lgsm_voice_ctrl(lgsmh, &ctrl);
+				pending_responses ++;
 			} else {
 				printf("Unknown command `%s'\n", buf);
 			}





More information about the commitlog mailing list