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] Dynamic registration of unsolicited responses.

---
 include/gsmd/unsolicited.h |    3 +
 src/gsmd/gsmd.c            |    2 +
 src/gsmd/sms_cb.c          |    3 +
 src/gsmd/unsolicited.c     |   77 ++++++++++++++++++++++++++-------------------
 4 files changed, 54 insertions(+), 31 deletions(-)

Index: gsm/include/gsmd/unsolicited.h
===================================================================
--- gsm.orig/include/gsmd/unsolicited.h	2007-08-15 00:29:58.000000000 +0800
+++ gsm/include/gsmd/unsolicited.h	2007-08-15 00:32:04.000000000 +0800
@@ -12,6 +12,9 @@
 
 extern int unsolicited_parse(struct gsmd *g, char *buf, int len, const char *param);
 extern int generate_event_from_cme(struct gsmd *g, unsigned int cme_error);
+extern void unsolicited_generic_init(struct gsmd *g);
+extern int unsolicited_register_array(const struct gsmd_unsolicit *arr,
+		int len);
 
 #endif /* __GSMD__ */
 
Index: gsm/src/gsmd/gsmd.c
===================================================================
--- gsm.orig/src/gsmd/gsmd.c	2007-08-15 00:31:46.000000000 +0800
+++ gsm/src/gsmd/gsmd.c	2007-08-15 00:32:04.000000000 +0800
@@ -477,6 +477,8 @@
 	/* select a vendor plugin */
 	gsmd_vendor_plugin_find(&g);
 
+	unsolicited_init(&g);
+
 	if (g.interpreter_ready) {
 		gsmd_initsettings(&g);
 	
Index: gsm/src/gsmd/unsolicited.c
===================================================================
--- gsm.orig/src/gsmd/unsolicited.c	2007-08-15 00:31:08.000000000 +0800
+++ gsm/src/gsmd/unsolicited.c	2007-08-15 00:32:04.000000000 +0800
@@ -358,49 +358,31 @@
 	*/
 };
 
+static struct gsmd_unsolicit unsolicit[256] = {{ 0, 0 }};
+
 /* called by midlevel parser if a response seems unsolicited */
 int unsolicited_parse(struct gsmd *g, char *buf, int len, const char *param)
 {
-	int i, rc;
+	struct gsmd_unsolicit *i;
+	int rc;
 	struct gsmd_vendor_plugin *vpl = g->vendorpl;
 
-	/* call vendor-specific unsolicited code parser */
-	if (vpl && vpl->num_unsolicit) {
-		for (i = 0; i < vpl->num_unsolicit; i++) {
-			const char *colon;
-			if (strncmp(buf, vpl->unsolicit[i].prefix,
-				     strlen(vpl->unsolicit[i].prefix)))
-				continue;
-
-			colon = strchr(buf, ':') + 2;
-			if (colon > buf+len)
-				colon = NULL;
-
-			rc = vpl->unsolicit[i].parse(buf, len, colon, g);
-			if (rc < 0) 
-				gsmd_log(GSMD_ERROR, "error %d during parse of "
-					 "vendor unsolicied response `%s'\n",
-					 rc, buf);
-			return rc;
-		}
-	}
-
-	/* call generic unsolicited code parser */
-	for (i = 0; i < ARRAY_SIZE(gsm0707_unsolicit); i++) {
+	/* call unsolicited code parser */
+	for (i = unsolicit; i->prefix; i ++) {
 		const char *colon;
-		if (strncmp(buf, gsm0707_unsolicit[i].prefix,
-			     strlen(gsm0707_unsolicit[i].prefix)))
+		if (strncmp(buf, i->prefix, strlen(i->prefix)))
 			continue;
-		
+
 		colon = strchr(buf, ':') + 2;
 		if (colon > buf+len)
 			colon = NULL;
 
-		rc = gsm0707_unsolicit[i].parse(buf, len, colon, g);
+		rc = i->parse(buf, len, colon, g);
 		if (rc < 0) 
-			gsmd_log(GSMD_ERROR, "error %d during parse of "
-				 "unsolicied response `%s'\n", rc, buf);
-		return rc;
+			gsmd_log(GSMD_ERROR, "error %d during parsing of "
+				 "an unsolicied response `%s'\n",
+				 rc, buf);
+			return rc;
 	}
 
 	gsmd_log(GSMD_NOTICE, "no parser for unsolicited response `%s'\n", buf);
@@ -408,6 +390,39 @@
 	return -ENOENT;
 }
 
+int unsolicited_register_array(const struct gsmd_unsolicit *arr, int len)
+{
+	int curlen = 0;
+
+	while (unsolicit[curlen ++].prefix);
+	if (len + curlen > ARRAY_SIZE(unsolicit))
+		return -ENOMEM;
+
+	/* Add at the beginning for overriding to be possible */
+	memmove(&unsolicit[len], unsolicit,
+			sizeof(struct gsmd_unsolicit) * curlen);
+	memcpy(unsolicit, arr,
+			sizeof(struct gsmd_unsolicit) * len);
+
+	return 0;
+}
+
+void unsolicited_init(struct gsmd *g)
+{
+	struct gsmd_vendor_plugin *vpl = g->vendorpl;
+
+	/* register generic unsolicited code parser */
+	unsolicited_register_array(gsm0707_unsolicit,
+			ARRAY_SIZE(gsm0707_unsolicit));
+
+	/* register vendor-specific unsolicited code parser */
+	if (vpl && vpl->num_unsolicit)
+		if (unsolicited_register_array(vpl->unsolicit,
+					vpl->num_unsolicit))
+			gsmd_log(GSMD_ERROR, "registering vendor-specific "
+					"unsolicited responses failed\n");
+}
+
 static unsigned int errors_creating_events[] = {
 	GSM0707_CME_PHONE_FAILURE,
 	GSM0707_CME_PHONE_NOCONNECT,
Index: gsm/src/gsmd/sms_cb.c
===================================================================
--- gsm.orig/src/gsmd/sms_cb.c	2007-08-15 00:31:46.000000000 +0800
+++ gsm/src/gsmd/sms_cb.c	2007-08-15 00:32:04.000000000 +0800
@@ -315,6 +315,9 @@
 	struct gsmd_atcmd *atcmd;
 	char buffer[10];
 
+	unsolicited_register_array(gsm0705_unsolicit,
+			ARRAY_SIZE(gsm0705_unsolicit));
+
 	atcmd = atcmd_fill("AT+CSMS=0", 9 + 1, NULL, gsmd, 0);
 	if (!atcmd)
 		return -ENOMEM;
