From: Sean Chiang <sean_chiang@openmoko.com>
Subject: [PATCH] Improvement for find and read phonebooks in gsmd

This patch is an improvement for find and read phonebooks.
After clients make a request to find / read phonebooks, then clients
should make a request to retrieve all the records.

Signed-off-by: Jim Huang <jserv@openmoko.org>
---
 include/gsmd/gsmd.h             |    3 
 include/gsmd/usock.h            |   20 +++-
 include/libgsmd/phonebook.h     |    6 +
 src/gsmd/usock.c                |  184 +++++++++++++++++++++++++++++++++++-----
 src/libgsmd/libgsmd_phonebook.c |   48 ++++++++++
 5 files changed, 238 insertions(+), 23 deletions(-)

Index: gsm/include/libgsmd/phonebook.h
===================================================================
--- gsm.orig/include/libgsmd/phonebook.h	2007-08-31 16:15:29.000000000 +0800
+++ gsm/include/libgsmd/phonebook.h	2007-09-17 23:48:41.000000000 +0800
@@ -106,4 +106,10 @@
 /* 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
Index: gsm/include/gsmd/gsmd.h
===================================================================
--- gsm.orig/include/gsmd/gsmd.h	2007-08-31 16:15:29.000000000 +0800
+++ gsm/include/gsmd/gsmd.h	2007-09-17 23:48:41.000000000 +0800
@@ -92,6 +92,9 @@
 	struct gsmd *gsmd;
 	struct gsmd_fd gfd;				/* the socket */
 	u_int32_t subscriptions;		/* bitmaks of subscribed event groups */
+
+	struct llist_head pb_readrg_list;	/* our READRG phonebook list */
+	struct llist_head pb_find_list;		/* our FIND phonebook list */
 };
 
 #define GSMD_DEBUG	1	/* debugging information */
Index: gsm/include/gsmd/usock.h
===================================================================
--- gsm.orig/include/gsmd/usock.h	2007-08-31 16:15:29.000000000 +0800
+++ gsm/include/gsmd/usock.h	2007-09-17 23:48:56.000000000 +0800
@@ -194,6 +194,8 @@
 	GSMD_PHONEBOOK_GET_SUPPORT	= 6,
 	GSMD_PHONEBOOK_LIST_STORAGE	= 7,
 	GSMD_PHONEBOOK_SET_STORAGE	= 8,
+	GSMD_PHONEBOOK_RETRIEVE_READRG	= 9,
+	GSMD_PHONEBOOK_RETRIEVE_FIND	= 10,
 };
 
 /* Type-of-Address, Numbering-Plan-Identification field, GSM 03.40, 9.1.2.5 */
@@ -431,7 +433,6 @@
 	char text[GSMD_PB_TEXT_MAXLEN+1];
 } __attribute__ ((packed));
 
-
 /* Refer to GSM 07.07 subclause 8.13 */
 /* FIXME: the tlength depends on SIM, use +CPBR=? to get */ 
 struct gsmd_phonebook_find {	
@@ -471,8 +472,18 @@
 	char opname_longalpha[16];
 };
 
+/* Refer to GSM 07.07 subclause 8.11 */
+struct gsmd_phonebook_mem {
+	u_int8_t type[3];
+	u_int8_t pad;
+	u_int16_t used;
+	u_int16_t total;
+} __attribute__ ((packed));
+
 struct gsmd_phonebook_storage {
-	char storage[3];
+	/* FIXME the amount of phonebook storage should be dynamic */
+	u_int8_t num;
+	struct gsmd_phonebook_mem mem[20];
 } __attribute__ ((packed));
 
 /* Subscriber number information from 3GPP TS 07.07, Clause 7.1 */
@@ -517,6 +528,11 @@
 	char buf[];
 } __attribute__ ((packed));
 
+struct gsmd_phonebooks {
+	struct llist_head list;
+	struct gsmd_phonebook pb;
+} __attribute__ ((packed));
+
 extern struct gsmd_ucmd *ucmd_alloc(int extra_size);
 extern int usock_init(struct gsmd *g);
 extern void usock_cmd_enqueue(struct gsmd_ucmd *ucmd, struct gsmd_user *gu);
Index: gsm/src/libgsmd/libgsmd_phonebook.c
===================================================================
--- gsm.orig/src/libgsmd/libgsmd_phonebook.c	2007-08-31 16:15:29.000000000 +0800
+++ gsm/src/libgsmd/libgsmd_phonebook.c	2007-09-17 23:48:41.000000000 +0800
@@ -33,7 +33,7 @@
 	gmh->data[2] = '\0';
 
 	rc = lgsm_send(lh, gmh);
-	if (rc < gmh->len + 3) {
+	if (rc < gmh->len + sizeof(*gmh)) {
 		lgsm_gmh_free(gmh);
 		return -EIO;
 	}
@@ -177,3 +177,49 @@
 {
 	return lgsm_send_simple(lh, GSMD_MSG_PHONEBOOK, GSMD_PHONEBOOK_GET_SUPPORT);
 }
+
+int lgsm_pb_retrieve_readrg(struct lgsm_handle *lh, int num)
+{
+	struct gsmd_msg_hdr *gmh;
+	int rc;
+
+	gmh = lgsm_gmh_fill(GSMD_MSG_PHONEBOOK,
+			GSMD_PHONEBOOK_RETRIEVE_READRG, sizeof(int));
+	if (!gmh)
+		return -ENOMEM;
+
+	*(int *)(gmh->data) = num;
+
+	rc = lgsm_send(lh, gmh);
+	if (rc < gmh->len + sizeof(*gmh)) {
+		lgsm_gmh_free(gmh);
+		return -EIO;
+	}
+
+	lgsm_gmh_free(gmh);
+
+	return 0;
+}
+
+int lgsm_pb_retrieve_find(struct lgsm_handle *lh, int num)
+{
+	struct gsmd_msg_hdr *gmh;
+	int rc;
+
+	gmh = lgsm_gmh_fill(GSMD_MSG_PHONEBOOK,
+			GSMD_PHONEBOOK_RETRIEVE_FIND, sizeof(int));
+	if (!gmh)
+		return -ENOMEM;
+
+	*(int *)(gmh->data) = num;
+
+	rc = lgsm_send(lh, gmh);
+	if (rc < gmh->len + sizeof(*gmh)) {
+		lgsm_gmh_free(gmh);
+		return -EIO;
+	}
+
+	lgsm_gmh_free(gmh);
+
+	return 0;
+}
Index: gsm/src/gsmd/usock.c
===================================================================
--- gsm.orig/src/gsmd/usock.c	2007-08-31 16:15:30.000000000 +0800
+++ gsm/src/gsmd/usock.c	2007-09-17 23:53:34.000000000 +0800
@@ -1035,21 +1035,56 @@
 
 static int phonebook_find_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp)
 {
-	struct gsmd_user *gu = ctx;	
-	struct gsmd_ucmd *ucmd;			
-	
+	struct gsmd_user *gu = ctx;
+	struct gsmd_ucmd *ucmd;
+	struct gsmd_phonebooks *gps;
+	char *fcomma, *lcomma, *ptr1, *ptr2 = NULL;
+	int *num;
+
 	DEBUGP("resp: %s\n", resp);
 
-	/* FIXME: using link list, also we need to handle the case of
-	 * no query result */
-	ucmd = gsmd_ucmd_fill(strlen(resp) + 1, GSMD_MSG_PHONEBOOK,
+	/*
+	 * [+CPBF: <index1>,<number>,<type>,<text>[[...]
+	 * <CR><LF>+CPBF: <index2>,<unmber>,<type>,<text>]]
+	 */
+	ucmd = gsmd_ucmd_fill(sizeof(int), GSMD_MSG_PHONEBOOK,
 			      GSMD_PHONEBOOK_FIND, 0);
 	if (!ucmd)
 		return -ENOMEM;	
 
-	strcpy(ucmd->buf, resp);
+	num = (int*) ucmd->buf;
+
+	*num = 0;
+
+	ptr1 = strtok(resp, "\n");
+
+	while (ptr1) {
+		gps = (struct gsmd_phonebooks *) malloc(sizeof(struct gsmd_phonebooks));
+		ptr2 = strchr(ptr1, ' ');
+		gps->pb.index = atoi(ptr2+1);
+
+		fcomma = strchr(ptr1, '"');
+		lcomma = strchr(fcomma+1, '"');
+		strncpy(gps->pb.numb, fcomma + 1, (lcomma-fcomma-1));
+		gps->pb.numb[(lcomma - fcomma) - 1] = '\0';
+
+		gps->pb.type = atoi(lcomma + 2);
+
+		ptr2 = strrchr(ptr1, ',');
+		fcomma = ptr2 + 1;
+		lcomma = strchr(fcomma + 1, '"');
+		strncpy(gps->pb.text, fcomma + 1, (lcomma - fcomma - 1));
+		gps->pb.text[(lcomma - fcomma) - 1] = '\0';
+
+		llist_add_tail(&gps->list, &gu->pb_find_list);
+
+		(*num)++;
+
+		ptr1 = strtok(NULL, "\n");
+	}
 
 	usock_cmd_enqueue(ucmd, gu);
+
 	return 0;
 }
 
@@ -1102,22 +1137,51 @@
 {
 	struct gsmd_user *gu = ctx;
 	struct gsmd_ucmd *ucmd;
+	struct gsmd_phonebooks *gps;
+	char *fcomma, *lcomma, *ptr1, *ptr2 = NULL;
+	int *num;
 
 	DEBUGP("resp: %s\n", resp);
 
 	/*
-	 * +CPBR: 4,"1234",129,"6C5F745E7965"
-	 * +CPBR: 5,"5678",129,"800062115BB6"
-	 * +CPBR: 6,"7890",129,"810280AA591A"
-	 * +CPBR: 8,"36874",129,"005300650061006E"
-	 *
+	 * [+CPBR: <index1>,<number>,<type>,<text>[[...]
+	 * <CR><LF>+CPBR: <index2>,<unmber>,<type>,<text>]]
 	 */
-	ucmd = gsmd_ucmd_fill(strlen(resp)+1, GSMD_MSG_PHONEBOOK,
+	ucmd = gsmd_ucmd_fill(sizeof(int), GSMD_MSG_PHONEBOOK,
 			      GSMD_PHONEBOOK_READRG, 0);
 	if (!ucmd)
 		return -ENOMEM;	
 
-	strcpy(ucmd->buf, resp);
+	num = (int*) ucmd->buf;
+
+	*num = 0;
+
+	ptr1 = strtok(resp, "\n");
+
+	while(ptr1) {
+		gps = (struct gsmd_phonebooks *) malloc(sizeof(struct gsmd_phonebooks));
+		ptr2 = strchr(ptr1, ' ');
+		gps->pb.index = atoi(ptr2+1);
+
+		fcomma = strchr(ptr1, '"');
+		lcomma = strchr(fcomma+1, '"');
+		strncpy(gps->pb.numb, fcomma + 1, (lcomma-fcomma-1));
+		gps->pb.numb[(lcomma - fcomma) - 1] = '\0';
+
+		gps->pb.type = atoi(lcomma + 2);
+
+		ptr2 = strrchr(ptr1, ',');
+		fcomma = ptr2 + 1;
+		lcomma = strchr(fcomma + 1, '"');
+		strncpy(gps->pb.text, fcomma + 1, (lcomma - fcomma - 1));
+		gps->pb.text[(lcomma - fcomma) - 1] = '\0';
+
+		llist_add_tail(&gps->list, &gu->pb_readrg_list);
+
+		(*num)++;
+
+		ptr1 = strtok(NULL, "\n");
+	}
 
 	usock_cmd_enqueue(ucmd, gu);
 
@@ -1209,22 +1273,38 @@
 static int phonebook_list_storage_cb(struct gsmd_atcmd *cmd,
 		void *ctx, char *resp)
 {
-	/* +CPBS: ("EN","BD","FD","DC","LD","RC","LR","MT","AD",
-	 *         "SM","SD","MC","LM","AF","ON","UD") */
 	/* TODO; using link list ; need to handle command error */
 	struct gsmd_user *gu = ctx;
 	struct gsmd_ucmd *ucmd;
+	struct gsmd_phonebook_storage *gps;
+	char *ptr;
 
 	DEBUGP("resp: %s\n", resp);
 
-	ucmd = gsmd_ucmd_fill(strlen(resp) + 1,
+	/*
+	 * +CPBS: (<storage>s)
+	 */
+
+	ucmd = gsmd_ucmd_fill(sizeof(*gps),
 			GSMD_MSG_PHONEBOOK,
 			GSMD_PHONEBOOK_LIST_STORAGE, 0);
 
         if (!ucmd)
 		return -ENOMEM;
 
-	strcpy(ucmd->buf, resp);
+	gps = (struct gsmd_phonebook_storage *) ucmd->buf;
+	gps->num = 0;
+
+	if (!strncmp(resp, "+CPBS", 5)) {
+		char* delim = "(,";
+		ptr = strpbrk(resp, delim);
+		while ( ptr ) {
+			strncpy(gps->mem[gps->num].type, ptr+2, 2);
+			gps->mem[gps->num].type[2] = '\0';
+			ptr = strpbrk(ptr+2, delim);
+			gps->num++;
+		}
+	}
 
 	usock_cmd_enqueue(ucmd, gu);
 
@@ -1235,11 +1315,13 @@
 		struct gsmd_msg_hdr *gph,int len)
 {	
 	struct gsmd_atcmd *cmd = NULL;
+	struct gsmd_ucmd *ucmd = NULL;
 	struct gsmd_phonebook_readrg *gpr;
 	struct gsmd_phonebook *gp;
 	struct gsmd_phonebook_find *gpf;
-	int *index;
-	int atcmd_len;
+	struct gsmd_phonebooks *cur, *cur2;
+	int *index, *num;
+	int atcmd_len, i;
 	char *storage;
 	char buf[1024];
 
@@ -1343,6 +1425,66 @@
 		cmd = atcmd_fill("AT+CPBR=?", 9+1,
 				 &phonebook_get_support_cb, gu, gph->id);
 		break;
+	case GSMD_PHONEBOOK_RETRIEVE_READRG:
+		if (len < sizeof(*gph) + sizeof(int))
+			return -EINVAL;
+
+		num = (int *) ((void *)gph + sizeof(*gph));
+
+		ucmd = gsmd_ucmd_fill(sizeof(struct gsmd_phonebook)*(*num),
+				GSMD_MSG_PHONEBOOK,
+				GSMD_PHONEBOOK_RETRIEVE_READRG, 0);
+		if (!ucmd)
+			return -ENOMEM;
+
+		gp = (struct gsmd_phonebook*) ucmd->buf;
+
+		if (!llist_empty(&gu->pb_readrg_list)) {
+
+			llist_for_each_entry_safe(cur, cur2,
+					&gu->pb_readrg_list, list) {
+				gp->index = cur->pb.index;
+				strcpy(gp->numb, cur->pb.numb);
+				gp->type = cur->pb.type;
+				strcpy(gp->text, cur->pb.text);
+				gp++;
+
+				llist_del(&cur->list);
+				free(cur);
+			}
+		}
+
+		usock_cmd_enqueue(ucmd, gu);
+
+		break;
+	case GSMD_PHONEBOOK_RETRIEVE_FIND:
+		if (len < sizeof(*gph) + sizeof(int))
+			return -EINVAL;
+
+		num = (int *) ((void *)gph + sizeof(*gph));
+
+		ucmd = gsmd_ucmd_fill(sizeof(struct gsmd_phonebook)*(*num), GSMD_MSG_PHONEBOOK,
+				      GSMD_PHONEBOOK_RETRIEVE_FIND, 0);
+		if (!ucmd)
+			return -ENOMEM;
+
+		gp = (struct gsmd_phonebook*) ucmd->buf;
+
+		if (!llist_empty(&gu->pb_find_list)) {
+			llist_for_each_entry_safe(cur, cur2, &gu->pb_find_list, list) {
+				gp->index = cur->pb.index;
+				strcpy(gp->numb, cur->pb.numb);
+				gp->type = cur->pb.type;
+				strcpy(gp->text, cur->pb.text);
+				gp++;
+
+				llist_del(&cur->list);
+				free(cur);
+			}
+		}
+
+		usock_cmd_enqueue(ucmd, gu);
+		break;
 	default:
 		return -EINVAL;
 	}	
@@ -1468,6 +1610,8 @@
 		newuser->gsmd = g;
 		newuser->subscriptions = 0xffffffff;
 		INIT_LLIST_HEAD(&newuser->finished_ucmds);
+		INIT_LLIST_HEAD(&newuser->pb_readrg_list);
+		INIT_LLIST_HEAD(&newuser->pb_find_list);
 
 		llist_add(&newuser->list, &g->users);
 		gsmd_register_fd(&newuser->gfd);