http://bugzilla.openmoko.org/cgi-bin/bugzilla/show_bug.cgi?id=21

From 5b7c50fd08b8f76f761958c8a8243e6c23118fa3 Mon Sep 17 00:00:00 2001
From: Andrzej Zaborowski <balrog@zabor.org>
Date: Thu, 12 Jul 2007 14:26:46 +0200
Subject: [PATCH] Incoming SMS events

This is a proposed patch to emit a gsmd event when a new SMS arrives, also
modifies libgsmd-tool to display the notification.  It makes sms_cb.c compile
but only really implements the bits necessary to make it build and for the
notifications to work.	I chose AT+CNMI mode 1 (i.e. store messages in memory
and report the location through +CMTI, rather than print the message right away
through +CMT) because the parser doesn't support multiline unsolicited
responses - in fact it can't support those because in a situation when a normal
command is executing and an unsolicited response comes in (which is the case
when sending a message to yourself) it is impossible for the parser to
distinguish whether the line after the unsolicited response is part of that
response or part of the command's response.
---
 include/gsmd/sms.h   |    2 
 include/gsmd/usock.h |   23 ++++-
 src/gsmd/Makefile.am |    2 
 src/gsmd/gsmd.c      |    4 -
 src/gsmd/sms_cb.c    |  202 ++++++++++++++++++++++++++++++++++++++++++++-------
 src/gsmd/sms_pdu.c   |    2 
 src/gsmd/usock.c     |    2 
 src/util/event.c     |    8 ++
 8 files changed, 208 insertions(+), 37 deletions(-)

Index: gsm/include/gsmd/sms.h
===================================================================
--- gsm.orig/include/gsmd/sms.h	2007-08-15 00:31:28.000000000 +0800
+++ gsm/include/gsmd/sms.h	2007-08-15 00:31:46.000000000 +0800
@@ -5,6 +5,8 @@
 
 #include <gsmd/gsmd.h>
 
+int sms_cb_init(struct gsmd *gsmd);
+
 int sms_pdu_make_smssubmit(char *dest, const struct gsmd_sms_submit *src);
 int sms_pdu_to_msg(struct gsmd_sms_list *dst, const u_int8_t *src,
 		int pdulen, int len);
Index: gsm/include/gsmd/usock.h
===================================================================
--- gsm.orig/include/gsmd/usock.h	2007-08-15 00:31:28.000000000 +0800
+++ gsm/include/gsmd/usock.h	2007-08-15 00:31:46.000000000 +0800
@@ -55,6 +55,11 @@
 	GSMD_PHONE_POWERDOWN	= 2,
 };
 
+enum gsmd_msg_cb {
+	GSMD_CB_SUBSCRIBE	= 1,
+	GSMD_CB_UNSUBSCRIBE	= 2,
+};
+
 enum gsmd_msg_network {
 	GSMD_NETWORK_REGISTER	= 1,
 	GSMD_NETWORK_SIGQ_GET	= 2,
@@ -65,11 +70,15 @@
 };
 
 enum gsmd_msg_sms {
-	GSMD_SMS_LIST		= 1,
-	GSMD_SMS_READ		= 2,
-	GSMD_SMS_SEND		= 3,
-	GSMD_SMS_WRITE		= 4,
-	GSMD_SMS_DELETE		= 5,	
+	GSMD_SMS_LIST			= 1,
+	GSMD_SMS_READ			= 2,
+	GSMD_SMS_SEND			= 3,
+	GSMD_SMS_WRITE			= 4,
+	GSMD_SMS_DELETE			= 5,
+	GSMD_SMS_GET_MSG_STORAGE	= 6,
+	GSMD_SMS_SET_MSG_STORAGE	= 7,
+	GSMD_SMS_GET_SERVICE_CENTRE	= 8,
+	GSMD_SMS_SET_SERVICE_CENTRE	= 9,
 };
 
 /* SMS stat from 3GPP TS 07.05, Clause 3.1 */
@@ -248,8 +257,8 @@
 			struct gsmd_addr addr;
 		} colp;
 		struct {
-			/* TBD */
-			struct gsmd_addr addr;
+			u_int8_t memtype;
+			int index;
 		} sms;
 		struct {
 			enum gsmd_pin_type type;
Index: gsm/src/gsmd/Makefile.am
===================================================================
--- gsm.orig/src/gsmd/Makefile.am	2007-08-15 00:31:28.000000000 +0800
+++ gsm/src/gsmd/Makefile.am	2007-08-15 00:31:46.000000000 +0800
@@ -7,7 +7,7 @@
 gsmd_CFLAGS = -D PLUGINDIR=\"$(plugindir)\"
 gsmd_SOURCES = gsmd.c atcmd.c select.c machine.c vendor.c unsolicited.c log.c \
 	       usock.c talloc.c timer.c operator_cache.c ext_response.c \
-	       sms_pdu.c
+	       sms_cb.c sms_pdu.c
 gsmd_LDADD = -ldl
 gsmd_LDFLAGS = -Wl,--export-dynamic
 
Index: gsm/src/gsmd/gsmd.c
===================================================================
--- gsm.orig/src/gsmd/gsmd.c	2007-08-15 00:31:00.000000000 +0800
+++ gsm/src/gsmd/gsmd.c	2007-08-15 00:31:46.000000000 +0800
@@ -185,7 +185,9 @@
 #if 0
 	/* Select TE character set */		
 	rc |= gsmd_simplecmd(gsmd, "AT+CSCS=\"UCS2\"");
-#endif	
+#endif
+
+	sms_cb_init(gsmd);
 
 	if (gsmd->vendorpl && gsmd->vendorpl->initsettings)
 		return gsmd->vendorpl->initsettings(gsmd);
Index: gsm/src/gsmd/sms_cb.c
===================================================================
--- gsm.orig/src/gsmd/sms_cb.c	2007-08-15 00:31:28.000000000 +0800
+++ gsm/src/gsmd/sms_cb.c	2007-08-15 00:31:46.000000000 +0800
@@ -36,11 +36,11 @@
 #include <gsmd/select.h>
 #include <gsmd/atcmd.h>
 #include <gsmd/usock.h>
+#include <gsmd/unsolicited.h>
 
 enum ts0705_mem_type {
 	GSM0705_MEMTYPE_NONE,
 	GSM0705_MEMTYPE_BROADCAST,
-	GSM0705_MEMTYPE_BROADCAST,
 	GSM0705_MEMTYPE_ME_MESSAGE,
 	GSM0705_MEMTYPE_MT,
 	GSM0705_MEMTYPE_SIM,
@@ -48,7 +48,7 @@
 	GSM0705_MEMTYPE_SR,
 };
 
-static const char *ts0705_memtype_name = {
+static const char *ts0705_memtype_name[] = {
 	[GSM0705_MEMTYPE_NONE]		= "NONE",
 	[GSM0705_MEMTYPE_BROADCAST]	= "BM",
 	[GSM0705_MEMTYPE_ME_MESSAGE]	= "ME",
@@ -70,9 +70,10 @@
 	return GSM0705_MEMTYPE_NONE;
 }
 
+/* TODO: move to headers */
 struct __gsmd_sms_storage {
-	u_int8 memtype;
-	u_int8_t pad[3]
+	u_int8_t memtype;
+	u_int8_t pad[3];
 	u_int16_t used;
 	u_int16_t total;
 } __attribute__ ((packed));
@@ -85,21 +86,34 @@
 {
 	struct gsmd_user *gu = ctx;
 	struct gsmd_ucmd *ucmd = ucmd_alloc(sizeof(struct gsmd_sms_storage));
+	struct gsmd_sms_storage *gss = (typeof(gss)) ucmd->buf;
+	char buf[3][3];
 
 	DEBUGP("entering(cmd=%p, gu=%p)\n", cmd, gu);
 
 	if (!ucmd)
 		return -ENOMEM;
 
-
-	
-	
 	ucmd->hdr.version = GSMD_PROTO_VERSION;
 	ucmd->hdr.msg_type = GSMD_MSG_SMS;
-	ucmd->hdr.msg_subtype = GSMD_SMS_GETMSG_STORAGE;
-	ucmd->hdr.len = ...;
+	ucmd->hdr.msg_subtype = GSMD_SMS_GET_MSG_STORAGE;
+	ucmd->hdr.len = sizeof(struct gsmd_sms_storage);
 	ucmd->hdr.id = cmd->id;
-	
+
+	if (sscanf(resp, "+CPMS: \"%2[A-Z]\",%hi,%hi,"
+				"\"%2[A-Z]\",%hi,%hi,\"%2[A-Z]\",%hi,%hi",
+				buf[0], &gss->mem[0].used, &gss->mem[0].total,
+				buf[1], &gss->mem[1].used, &gss->mem[1].total,
+				buf[2], &gss->mem[2].used, &gss->mem[2].total)
+			< 9) {
+		talloc_free(ucmd);
+		return -EINVAL;
+	}
+
+	gss->mem[0].memtype = parse_memtype(buf[0]);
+	gss->mem[1].memtype = parse_memtype(buf[1]);
+	gss->mem[2].memtype = parse_memtype(buf[2]);
+
 	usock_cmd_enqueue(ucmd, gu);
 
 	return 0;
@@ -113,14 +127,13 @@
 
 	switch (gph->msg_subtype) {
 	case GSMD_SMS_GET_SERVICE_CENTRE:
-		
-		break;
+		return;
 	case GSMD_SMS_SET_SERVICE_CENTRE:
-		break;
+		return;
 	case GSMD_SMS_SET_MSG_STORAGE:
-		break;
+		return;
 	case GSMD_SMS_GET_MSG_STORAGE:
-		cmd = atcmd_fill("AT+CPMS?", 8, ...);
+		cmd = atcmd_fill("AT+CPMS?", 8 + 1, usock_cpms_cb, gu, 0);
 		break;
 	}
 
@@ -131,7 +144,6 @@
 static int usock_rcv_cb(struct gsmd_user *gu, struct gsmd_msg_hdr *gph,
 			int len)
 {
-
 	switch (gph->msg_subtype) {
 	case GSMD_CB_SUBSCRIBE:
 		break;
@@ -139,44 +151,158 @@
 		break;
 	}
 
-	return 
+	return -ENOSYS;
 }
 
-
 /* Unsolicited messages related to SMS / CB */
 static int cmti_parse(char *buf, int len, const char *param,
 		      struct gsmd *gsmd)
 {
+	char memstr[3];
+	struct gsmd_ucmd *ucmd = ucmd_alloc(sizeof(struct gsmd_evt_auxdata));
+	struct gsmd_evt_auxdata *aux = (struct gsmd_evt_auxdata *) ucmd->buf;
+
+	if (!ucmd)
+		return -ENOMEM;
+
+	ucmd->hdr.version = GSMD_PROTO_VERSION;
+	ucmd->hdr.msg_type = GSMD_MSG_EVENT;
+	ucmd->hdr.msg_subtype = GSMD_EVT_IN_SMS;
+	ucmd->hdr.len = sizeof(*aux);
+
+	if (sscanf(param, "\"%2[A-Z]\",%i", memstr, &aux->u.sms.index) < 2) {
+		talloc_free(ucmd);
+		return -EINVAL;
+	}
+
+	aux->u.sms.memtype = parse_memtype(memstr);
+
+	return usock_evt_send(gsmd, ucmd, GSMD_EVT_IN_SMS);
 }
 
 static int cmt_parse(char *buf, int len, const char *param,
 		     struct gsmd *gsmd)
 {
+	/* TODO: TEXT mode */
+	u_int8_t pdu[180];
+	const char *comma = strchr(param, ',');
+	char *cr;
+	int i;
+	struct gsmd_sms_list msg;
+
+	if (!comma)
+		return -EINVAL;
+	len = strtoul(comma + 1, &cr, 10);
+	if (cr[0] != '\n')
+		return -EINVAL;
+
+	cr ++;
+	for (i = 0; cr[0] >= '0' && cr[1] >= '0' && i < 180; i ++) {
+		if (sscanf(cr, "%2hhX", &pdu[i]) < 1) {
+			gsmd_log(GSMD_DEBUG, "malformed input (%i)\n", i);
+			return -EINVAL;
+		}
+		cr += 2;
+	}
+	if (sms_pdu_to_msg(&msg, pdu, len, i)) {
+		gsmd_log(GSMD_DEBUG, "malformed PDU\n");
+		return -EINVAL;
+	}
+
+	/* FIXME: generate some kind of event */
+	return -ENOSYS;
 }
 
 static int cbmi_parse(char *buf, int len, const char *param,
 		      struct gsmd *gsmd)
 {
+	char memstr[3];
+	int memtype, index;
+
+	if (sscanf(param, "\"%2[A-Z]\",%i", memstr, &index) < 2)
+		return -EINVAL;
+
+	memtype = parse_memtype(memstr);
+	/* FIXME: generate some kind of event */
+	return -ENOSYS;
 }
 
 static int cbm_parse(char *buf, int len, const char *param,
 		     struct gsmd *gsmd)
 {
+	/* TODO: TEXT mode */
+	u_int8_t pdu[180];
+	char *cr;
+	int i;
+	struct gsmd_sms_list msg;
+
+	len = strtoul(param, &cr, 10);
+	if (cr[0] != '\n')
+		return -EINVAL;
+
+	cr ++;
+	for (i = 0; cr[0] >= '0' && cr[1] >= '0' && i < 180; i ++) {
+		if (sscanf(cr, "%2hhX", &pdu[i]) < 1) {
+			gsmd_log(GSMD_DEBUG, "malformed input (%i)\n", i);
+			return -EINVAL;
+		}
+		cr += 2;
+	}
+	if (sms_pdu_to_msg(&msg, pdu, len, i)) {
+		gsmd_log(GSMD_DEBUG, "malformed PDU\n");
+		return -EINVAL;
+	}
+
+	/* FIXME: generate some kind of event */
+	return -ENOSYS;
 }
 
 static int cdsi_parse(char *buf, int len, const char *param,
 		      struct gsmd *gsmd)
 {
+	char memstr[3];
+	int memtype, index;
+
+	if (sscanf(param, "\"%2[A-Z]\",%i", memstr, &index) < 2)
+		return -EINVAL;
+
+	memtype = parse_memtype(memstr);
+	/* FIXME: generate some kind of event */
+	return -ENOSYS;
 }
 
 static int cds_parse(char *buf, int len, const char *param,
 		     struct gsmd *gsmd)
 {
-}
+	/* TODO: TEXT mode */
+	u_int8_t pdu[180];
+	char *cr;
+	int i;
+	struct gsmd_sms_list msg;
+
+	len = strtoul(param, &cr, 10);
+	if (cr[0] != '\n')
+		return -EINVAL;
+
+	cr ++;
+	for (i = 0; cr[0] >= '0' && cr[1] >= '0' && i < 180; i ++) {
+		if (sscanf(cr, "%2hhX", &pdu[i]) < 1) {
+			gsmd_log(GSMD_DEBUG, "malformed input (%i)\n", i);
+			return -EINVAL;
+		}
+		cr += 2;
+	}
+	if (sms_pdu_to_msg(&msg, pdu, len, i)) {
+		gsmd_log(GSMD_DEBUG, "malformed PDU\n");
+		return -EINVAL;
+	}
 
+	/* FIXME: generate some kind of event */
+	return -ENOSYS;
+}
 
-static const struct gsmd_unsolocit gsm0705_unsolicit[] = {
-	{ "+CMTI",	&cmti_parse },	/* SMS Deliver Index (stored in ME/TA) */
+static const struct gsmd_unsolicit gsm0705_unsolicit[] = {
+	{ "+CMTI",	&cmti_parse },	/* SMS Deliver Index (stored in ME/TA)*/
 	{ "+CMT",	&cmt_parse },	/* SMS Deliver to TE */
 	{ "+CBMI",	&cbmi_parse },	/* Cell Broadcast Message Index */
 	{ "+CBM",	&cbm_parse },	/* Cell Broadcast Message */
@@ -189,24 +315,43 @@
 	struct gsmd_atcmd *atcmd;
 	char buffer[10];
 
-	atcmd = atcmd_fill("AT+CSMS=0", NULL, gu, 0);
+	atcmd = atcmd_fill("AT+CSMS=0", 9 + 1, NULL, gsmd, 0);
+	if (!atcmd)
+		return -ENOMEM;
+	atcmd_submit(gsmd, atcmd);
+
+	/* Store and notify */
+	atcmd = atcmd_fill("AT+CNMI=1,1,1", 13 + 1, NULL, gsmd, 0);
+	if (!atcmd)
+		return -ENOMEM;
+	atcmd_submit(gsmd, atcmd);
+
+	/* Store into ME/TA and notify */
+	atcmd = atcmd_fill("AT+CSBS=1", 9 + 1, NULL, gsmd, 0);
+	if (!atcmd)
+		return -ENOMEM;
+	atcmd_submit(gsmd, atcmd);
+
+	/* Store into ME/TA and notify */
+	atcmd = atcmd_fill("AT+CSDS=2", 9 + 1, NULL, gsmd, 0);
 	if (!atcmd)
 		return -ENOMEM;
 	atcmd_submit(gsmd, atcmd);
 
 	/* If text mode, set the encoding */
-	if (gu->gsmd->flags & GSMD_FLAG_SMS_FMT_TEXT) {
-		atcmd = atcmd_fill("AT+CSCS=\"IRA\"", 13, NULL, gu, 0);
+	if (gsmd->flags & GSMD_FLAG_SMS_FMT_TEXT) {
+		atcmd = atcmd_fill("AT+CSCS=\"IRA\"", 13 + 1, NULL, gsmd, 0);
 		if (!atcmd)
 			return -ENOMEM;
 		atcmd_submit(gsmd, atcmd);
 	}
 
 	/* Switch into desired mode (Section 3.2.3) */
-	snprintf(buffer, sizeof(buffer), "AT+CMGF=%i",
-			(gu->gsmd->flags & GSMD_FLAG_SMS_FMT_TEXT) ?
-			GSMD_SMS_FMT_TEXT : GSMD_SMS_FMT_PDU);
-	atcmd = atcmd_fill(buffer, strlen(buffer) + 1, NULL, gu, 0);
+	atcmd = atcmd_fill(buffer, snprintf(buffer, sizeof(buffer),
+				"AT+CMGF=%i",
+				(gsmd->flags & GSMD_FLAG_SMS_FMT_TEXT) ?
+				GSMD_SMS_FMT_TEXT : GSMD_SMS_FMT_PDU) + 1,
+			NULL, gsmd, 0);
 	if (!atcmd)
 		return -ENOMEM;
 
Index: gsm/src/gsmd/sms_pdu.c
===================================================================
--- gsm.orig/src/gsmd/sms_pdu.c	2007-08-15 00:31:28.000000000 +0800
+++ gsm/src/gsmd/sms_pdu.c	2007-08-15 00:31:46.000000000 +0800
@@ -179,6 +179,8 @@
 
 		memset(dst->time_stamp, 0, 7);
 		break;
+	case GSMD_SMS_TP_MTI_STATUS_REPORT:
+		/* TODO */
 	default:
 		/* Unknown PDU type */
 		return 1;
Index: gsm/src/gsmd/usock.c
===================================================================
--- gsm.orig/src/gsmd/usock.c	2007-08-15 00:31:28.000000000 +0800
+++ gsm/src/gsmd/usock.c	2007-08-15 00:31:46.000000000 +0800
@@ -532,7 +532,7 @@
 	struct gsmd_ucmd *ucmd;
 	int msgref;
 
-	if (cmd->ret == 0) {
+	if (cmd->ret == 0 || cmd->ret == -255) {
 		if (sscanf(resp, "+CMGS: %i", &msgref) < 1)
 			return -EINVAL;
 	} else
Index: gsm/src/util/event.c
===================================================================
--- gsm.orig/src/util/event.c	2007-08-15 00:29:59.000000000 +0800
+++ gsm/src/util/event.c	2007-08-15 00:31:46.000000000 +0800
@@ -34,6 +34,13 @@
 	return 0;
 }
 
+static int insms_handler(struct lgsm_handle *lh, int evt, struct gsmd_evt_auxdata *aux)
+{
+	printf("EVENT: Incoming SMS stored at location %i\n", aux->u.sms.index);
+
+	return 0;
+}
+
 static int clip_handler(struct lgsm_handle *lh, int evt, struct gsmd_evt_auxdata *aux)
 {
 	printf("EVENT: Incoming call clip = %s\n", aux->u.clip.addr.number);
@@ -131,6 +138,7 @@
 
 	rc  = lgsm_evt_handler_register(lh, GSMD_EVT_IN_CALL, &incall_handler);
 	rc |= lgsm_evt_handler_register(lh, GSMD_EVT_IN_CLIP, &clip_handler);
+	rc |= lgsm_evt_handler_register(lh, GSMD_EVT_IN_SMS, &insms_handler);
 	rc |= lgsm_evt_handler_register(lh, GSMD_EVT_OUT_COLP, &colp_handler);
 	rc |= lgsm_evt_handler_register(lh, GSMD_EVT_NETREG, &netreg_handler);
 	rc |= lgsm_evt_handler_register(lh, GSMD_EVT_SIGNAL, &sigq_handler);
