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

SIM Phonebook access implementation.

This patch adds primitive-but-working support for SIM phonebook access,
including phonebook memory storage and entry read/write/delete.  Also,
libgsmd-tools shell is modified to perform listing actions.

API changes:
	lgsm_pb_read_entryies -> lgsm_pb_read_entries
	lgsm_pb_list_storage (new):
		List of supported phonebook memory storage.
	lgsm_pb_set_storage (new);
		Select phonebook memory storage.

	lgsmd_pb_del_entry -> lgsm_pb_del_entry
	lgsmd_pb_write_entry -> lgsm_pb_write_entry

Signed-off-by: Jim Huang <jserv@openmoko.org>
--
 include/gsmd/usock.h            |   11 ++
 include/libgsmd/phonebook.h     |   12 ++
 src/gsmd/usock.c                |  168 +++++++++++++++++++++++++++++----------
 src/libgsmd/libgsmd_phonebook.c |   41 ++++++++-
 src/util/Makefile.am            |    5 -
 src/util/shell.c                |  169 ++++++++++++++++++++++++++++++++++------
 6 files changed, 327 insertions(+), 79 deletions(-)

Index: gsm/include/gsmd/usock.h
===================================================================
--- gsm.orig/include/gsmd/usock.h	2007-08-15 00:34:14.000000000 +0800
+++ gsm/include/gsmd/usock.h	2007-08-15 00:34:28.000000000 +0800
@@ -2,6 +2,7 @@
 #define _GSMD_USOCK_H
 
 #include <gsmd/event.h>
+#include <common/linux_list.h>
 
 #define GSMD_UNIX_SOCKET "\0gsmd"
 //#define GSMD_UNIX_SOCKET_TYPE SOCK_SEQPACKET
@@ -192,6 +193,8 @@
 	GSMD_PHONEBOOK_WRITE		= 4,
 	GSMD_PHONEBOOK_DELETE		= 5,	
 	GSMD_PHONEBOOK_GET_SUPPORT	= 6,
+	GSMD_PHONEBOOK_LIST_STORAGE	= 7,
+	GSMD_PHONEBOOK_SET_STORAGE	= 8,
 };
 
 /* Type-of-Address, Numbering-Plan-Identification field, GSM 03.40, 9.1.2.5 */
@@ -423,6 +426,7 @@
 #define	GSMD_PB_NUMB_MAXLEN	44
 #define GSMD_PB_TEXT_MAXLEN	14
 struct gsmd_phonebook {
+	struct llist_head list;
 	u_int8_t index;
 	char numb[GSMD_PB_NUMB_MAXLEN+1];
 	u_int8_t type;
@@ -469,6 +473,11 @@
 	char opname_longalpha[16];
 };
 
+struct gsmd_phonebook_storage {
+	struct llist_head list;
+	char storage[3];
+} __attribute__ ((packed));
+
 struct gsmd_msg_hdr {
 	u_int8_t version;
 	u_int8_t msg_type;
@@ -481,8 +490,6 @@
 
 #ifdef __GSMD__
 
-#include <common/linux_list.h>
-
 #include <gsmd/usock.h>
 #include <gsmd/gsmd.h>
 
Index: gsm/include/libgsmd/phonebook.h
===================================================================
--- gsm.orig/include/libgsmd/phonebook.h	2007-08-15 00:28:44.000000000 +0800
+++ gsm/include/libgsmd/phonebook.h	2007-08-15 00:34:28.000000000 +0800
@@ -78,6 +78,12 @@
 extern int lgsm_pb_set_entry(struct lgsm_handle *lh,
 			     struct lgsm_pb_entry *pb);
 
+/* List of supported phonebook memory storage */
+extern int lgsm_pb_list_storage(struct lgsm_handle *lh);
+
+/* Select phonebook memory storage */
+extern int lgsm_pb_set_storage(struct lgsm_handle *lh, char *storage);
+
 /* Find phonebook entires which alphanumeric filed start 
  * with string <findtext> */
 extern int lgsm_pb_find_entry(struct lgsm_handle *lh, 
@@ -87,14 +93,14 @@
 extern int lgsm_pb_read_entry(struct lgsm_handle *lh, int index);
 
 /* Read phonebook entries in location number range */
-extern int lgsm_pb_read_entryies(struct lgsm_handle *lh, 
+extern int lgsm_pb_read_entries(struct lgsm_handle *lh,
 		const struct lgsm_phonebook_readrg *pb_readrg);
 
 /* Delete phonebook entry in location index */
-extern int lgsmd_pb_del_entry(struct lgsm_handle *lh, int index);
+extern int lgsm_pb_del_entry(struct lgsm_handle *lh, int index);
 
 /* Write phonebook entry in location */
-extern int lgsmd_pb_write_entry(struct lgsm_handle *lh, 
+extern int lgsm_pb_write_entry(struct lgsm_handle *lh,
 		const struct lgsm_phonebook *pb);
 
 /* Get the location range/nlength/tlength supported */
Index: gsm/src/gsmd/usock.c
===================================================================
--- gsm.orig/src/gsmd/usock.c	2007-08-15 00:34:14.000000000 +0800
+++ gsm/src/gsmd/usock.c	2007-08-15 00:34:28.000000000 +0800
@@ -984,14 +984,16 @@
 }
 #endif
 
-#if 0
 static int phonebook_find_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp)
 {
 	struct gsmd_user *gu = ctx;	
 	struct gsmd_ucmd *ucmd;			
 	
-	/* FIXME: implementation */
-	ucmd = gsmd_ucmd_fill(strlen(resp)+1, GSMD_MSG_PHONEBOOK,
+	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,
 			      GSMD_PHONEBOOK_FIND, 0);
 	if (!ucmd)
 		return -ENOMEM;	
@@ -1009,42 +1011,58 @@
 	struct gsmd_ucmd *ucmd;
 	char *fcomma, *lcomma;
 	char *ptr;
-	/* FIXME: We should check this case "When the entry is empty" */
+
+	DEBUGP("resp: %s\n", resp);
+
 	ucmd = gsmd_ucmd_fill(sizeof(*gp), GSMD_MSG_PHONEBOOK,
 			      GSMD_PHONEBOOK_READ, 0);	
 
 	if (!ucmd)
-		return -ENOMEM;	
+		return -ENOMEM;
+
 	gp = (struct gsmd_phonebook *) ucmd->buf;
 	
-	ptr = strchr(resp, ' ');	
-	gp->index = atoi(ptr+1);		
 	
-	fcomma = strchr(resp, '"');
-	lcomma = strchr(fcomma+1, '"');		
-	strncpy(gp->numb, fcomma+1, (lcomma-fcomma-1));	
-	gp->numb[(lcomma-fcomma)-1] = '\0';			
+	/* check the record is empty or not */
+	if (!strncmp(resp, "+CPBR", 5)) {
+		ptr = strchr(resp, ' ');
+		gp->index = atoi(ptr + 1);
+
+		fcomma = strchr(resp, '"');
+		lcomma = strchr(fcomma + 1, '"');
+		strncpy(gp->numb, fcomma + 1, (lcomma - fcomma - 1));
+		gp->numb[(lcomma-fcomma) - 1] = '\0';
 		
-	gp->type = atoi(lcomma+2);		
+		gp->type = atoi(lcomma + 2);
+
+		ptr = strrchr(resp, ',');
+		fcomma = ptr + 1;
+		lcomma = strchr(fcomma + 1, '"');
+		strncpy(gp->text, fcomma + 1, (lcomma-fcomma - 1));
+		gp->text[(lcomma - fcomma) - 1] = '\0';
+	}
+	else
+		gp->index = 0;
 
-	ptr = strrchr(resp, ',');
-	fcomma = ptr+1;
-	lcomma = strchr(fcomma+1, '"');
-	strncpy(gp->text, fcomma+1, (lcomma-fcomma-1));
-	gp->text[(lcomma-fcomma)-1] = '\0';
-			
 	usock_cmd_enqueue(ucmd, gu);
-	
+
 	return 0;
 }
 
 static int phonebook_readrg_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp)
 {
 	struct gsmd_user *gu = ctx;
-	struct gsmd_ucmd *ucmd;	
-	
-	/* FIXME: implementation */
-	
+	struct gsmd_ucmd *ucmd;
+
+	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"
+	 *
+	 */
 	ucmd = gsmd_ucmd_fill(strlen(resp)+1, GSMD_MSG_PHONEBOOK,
 			      GSMD_PHONEBOOK_READRG, 0);
 	if (!ucmd)
@@ -1059,9 +1077,11 @@
 
 static int phonebook_write_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;
+
+	DEBUGP("resp: %s\n", resp);
+
 	ucmd = gsmd_ucmd_fill(strlen(resp)+1, GSMD_MSG_PHONEBOOK,
 			      GSMD_PHONEBOOK_WRITE, 0);
 	if (!ucmd)
@@ -1076,9 +1096,11 @@
 
 static int phonebook_delete_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;
+
+	DEBUGP("resp: %s\n", resp);
+
 	ucmd = gsmd_ucmd_fill(strlen(resp)+1, GSMD_MSG_PHONEBOOK,
 			      GSMD_PHONEBOOK_DELETE, 0);
 	if (!ucmd)
@@ -1091,19 +1113,23 @@
 	return 0;
 }
 
-static int phonebook_support_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp)
+static int phonebook_get_support_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp)
 {
+	/* TODO: Need to handle command error */
+	/* +CPBR: (1-100),44,16 */
 	struct gsmd_user *gu = ctx;
 	struct gsmd_phonebook_support *gps;
 	struct gsmd_ucmd *ucmd;
 	char *fcomma, *lcomma;
 	char *dash;
+
+	DEBUGP("resp: %s\n", resp);
 	
 	ucmd = gsmd_ucmd_fill(sizeof(*gps), GSMD_MSG_PHONEBOOK,
 			      GSMD_PHONEBOOK_GET_SUPPORT, 0);
 	if (!ucmd)
 		return -ENOMEM;
-	
+
 	gps = (struct gsmd_phonebook_support *) ucmd->buf;
 		
 	dash = strchr(resp, '-');
@@ -1111,7 +1137,7 @@
 		talloc_free(ucmd);
 		return -EIO;
 	}	
-	gps->index = atoi(dash+1);
+	gps->index = atoi(dash + 1);
 
 	fcomma = strchr(resp, ',');
 	if (!fcomma) {
@@ -1131,8 +1157,33 @@
 	return 0;
 }
 
-static int usock_rcv_phonebook(struct gsmd_user *gu, struct gsmd_msg_hdr *gph, 
-			 int len)
+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;
+
+	DEBUGP("resp: %s\n", resp);
+
+	ucmd = gsmd_ucmd_fill(strlen(resp) + 1,
+			GSMD_MSG_PHONEBOOK,
+			GSMD_PHONEBOOK_LIST_STORAGE, 0);
+
+        if (!ucmd)
+		return -ENOMEM;
+
+	strcpy(ucmd->buf, resp);
+
+	usock_cmd_enqueue(ucmd, gu);
+
+	return 0;
+}
+
+static int usock_rcv_phonebook(struct gsmd_user *gu,
+		struct gsmd_msg_hdr *gph,int len)
 {	
 	struct gsmd_atcmd *cmd = NULL;
 	struct gsmd_phonebook_readrg *gpr;
@@ -1140,15 +1191,38 @@
 	struct gsmd_phonebook_find *gpf;
 	int *index;
 	int atcmd_len;
+	char *storage;
 	char buf[1024];
-	
+
 	switch (gph->msg_subtype) {
+	case GSMD_PHONEBOOK_LIST_STORAGE:
+		cmd = atcmd_fill("AT+CPBS=?", 9 + 1,
+				&phonebook_list_storage_cb,
+				gu, gph->id);
+		break;
+	case GSMD_PHONEBOOK_SET_STORAGE:
+		if (len < sizeof(*gph) + 3)
+			return -EINVAL;
+
+		storage = (char*) ((void *)gph + sizeof(*gph));
+
+		/* ex. AT+CPBS="ME" */
+		atcmd_len = 1 + strlen("AT+CPBS=\"") + 2 + strlen("\"");
+		cmd = atcmd_fill("AT+CPBS=\"", atcmd_len,
+				&usock_cmd_cb, gu, gph->id);
+
+		if (!cmd)
+			return -ENOMEM;
+
+		sprintf(cmd->buf, "AT+CPBS=\"%s\"", storage);
+		break;
 	case GSMD_PHONEBOOK_FIND:
 		if(len < sizeof(*gph) + sizeof(*gpf))
 			return -EINVAL;
-		gpf = (struct gsmd_phonebook_find *) ((void *)gph + sizeof(*gph));		
-				
-		atcmd_len = 1 + strlen("AT+CPBF=\"") + strlen(gpf->findtext) + strlen("\"");
+		gpf = (struct gsmd_phonebook_find *) ((void *)gph + sizeof(*gph));
+
+		atcmd_len = 1 + strlen("AT+CPBF=\"") +
+			strlen(gpf->findtext) + strlen("\"");
 		cmd = atcmd_fill("AT+CPBF=\"", atcmd_len,
 				 &phonebook_find_cb, gu, gph->id);
 		if (!cmd)
@@ -1158,10 +1232,12 @@
 	case GSMD_PHONEBOOK_READ:
 		if(len < sizeof(*gph) + sizeof(int))
 			return -EINVAL;
-		index = (int *) ((void *)gph + sizeof(*gph));
 		
-		sprintf(buf, "%d", *index);		
+		index = (int *) ((void *)gph + sizeof(*gph));
+
+		sprintf(buf, "%d", *index);
 
+		/* ex, AT+CPBR=23 */
 		atcmd_len = 1 + strlen("AT+CPBR=") + strlen(buf);
 		cmd = atcmd_fill("AT+CPBR=", atcmd_len,
 				 &phonebook_read_cb, gu, gph->id);
@@ -1176,6 +1252,7 @@
 
 		sprintf(buf, "%d,%d", gpr->index1, gpr->index2);		
 
+		/* ex, AT+CPBR=1,100 */
 		atcmd_len = 1 + strlen("AT+CPBR=") + strlen(buf);
 		cmd = atcmd_fill("AT+CPBR=", atcmd_len,
 				 &phonebook_readrg_cb, gu, gph->id);
@@ -1188,8 +1265,9 @@
 			return -EINVAL;
 		gp = (struct gsmd_phonebook *) ((void *)gph + sizeof(*gph));
 
-		sprintf(buf, "%d,\"%s\",%d,\"%s\"", gp->index, gp->numb, gp->type, gp->text);
-		
+		sprintf(buf, "%d,\"%s\",%d,\"%s\"",
+				gp->index, gp->numb, gp->type, gp->text);
+
 		atcmd_len = 1 + strlen("AT+CPBW=") + strlen(buf);
 		cmd = atcmd_fill("AT+CPBW=", atcmd_len,
 				 &phonebook_write_cb, gu, gph->id);
@@ -1204,6 +1282,7 @@
 	    	
 		sprintf(buf, "%d", *index);
 		
+		/* ex, AT+CPBW=3*/
 		atcmd_len = 1 + strlen("AT+CPBW=") + strlen(buf);
 		cmd = atcmd_fill("AT+CPBW=", atcmd_len,
 				 &phonebook_delete_cb, gu, gph->id);
@@ -1213,7 +1292,7 @@
 		break;	
 	case GSMD_PHONEBOOK_GET_SUPPORT:
 		cmd = atcmd_fill("AT+CPBR=?", 9+1,
-				 &phonebook_support_cb, gu, gph->id);
+				 &phonebook_get_support_cb, gu, gph->id);
 		break;
 	default:
 		return -EINVAL;
@@ -1224,7 +1303,6 @@
 	else
 		return 0;
 }
-#endif
 
 static usock_msg_handler *pcmd_type_handlers[__NUM_GSMD_MSGS] = {
 	[GSMD_MSG_PASSTHROUGH]	= &usock_rcv_passthrough,
@@ -1235,7 +1313,7 @@
 	[GSMD_MSG_NETWORK]	= &usock_rcv_network,
 	[GSMD_MSG_SMS]		= &usock_rcv_sms,
 	[GSMD_MSG_CB]		= &usock_rcv_cb,
-	//[GSMD_MSG_PHONEBOOK]	= &usock_rcv_phonebook,
+	[GSMD_MSG_PHONEBOOK]	= &usock_rcv_phonebook,
 };
 
 static int usock_rcv_pcmd(struct gsmd_user *gu, char *buf, int len)
Index: gsm/src/libgsmd/libgsmd_phonebook.c
===================================================================
--- gsm.orig/src/libgsmd/libgsmd_phonebook.c	2007-08-15 00:28:44.000000000 +0800
+++ gsm/src/libgsmd/libgsmd_phonebook.c	2007-08-15 00:34:28.000000000 +0800
@@ -11,6 +11,38 @@
 
 #include "lgsm_internals.h"
 
+
+int lgsm_pb_list_storage(struct lgsm_handle *lh)
+{
+	return lgsm_send_simple(lh, GSMD_MSG_PHONEBOOK,
+			GSMD_PHONEBOOK_LIST_STORAGE);
+}
+
+int lgsm_pb_set_storage(struct lgsm_handle *lh, char *storage)
+{
+	struct gsmd_msg_hdr *gmh;
+	int rc;
+
+	gmh = lgsm_gmh_fill(GSMD_MSG_PHONEBOOK,
+			GSMD_PHONEBOOK_SET_STORAGE, 3);
+
+	if (!gmh)
+		return -ENOMEM;
+
+	strncpy((char*)gmh->data, storage, 2);
+	gmh->data[2] = '\0';
+
+	rc = lgsm_send(lh, gmh);
+	if (rc < gmh->len + 3) {
+		lgsm_gmh_free(gmh);
+		return -EIO;
+	}
+
+	lgsm_gmh_free(gmh);
+
+	return 0;
+}
+
 int lgsm_pb_find_entry(struct lgsm_handle *lh, 
 		const struct lgsm_phonebook_find *pb_find)
 {
@@ -37,6 +69,7 @@
 	return 0;
 }
 
+
 int lgsm_pb_read_entry(struct lgsm_handle *lh, int index)
 {
 	struct gsmd_msg_hdr *gmh;
@@ -46,6 +79,7 @@
 			GSMD_PHONEBOOK_READ, sizeof(int));
 	if (!gmh)
 		return -ENOMEM;
+
 	*(int *) gmh->data = index;
 
 	rc = lgsm_send(lh, gmh);
@@ -59,7 +93,7 @@
 	return 0;
 }
 
-int lgsm_pb_read_entryies(struct lgsm_handle *lh, 
+int lgsm_pb_read_entries(struct lgsm_handle *lh,
 		const struct lgsm_phonebook_readrg *pb_readrg)
 {
 	struct gsmd_msg_hdr *gmh;
@@ -85,7 +119,7 @@
 	return 0;
 }
 
-int lgsmd_pb_del_entry(struct lgsm_handle *lh, int index)
+int lgsm_pb_del_entry(struct lgsm_handle *lh, int index)
 {
 	struct gsmd_msg_hdr *gmh;
 	int rc;
@@ -108,7 +142,7 @@
 	return 0;
 }
 
-int lgsmd_pb_write_entry(struct lgsm_handle *lh, 
+int lgsm_pb_write_entry(struct lgsm_handle *lh,
 		const struct lgsm_phonebook *pb)
 {
 	/* FIXME: only support alphabet now */
@@ -139,7 +173,6 @@
 	return 0;
 }
 
-
 int lgsm_pb_get_support(struct lgsm_handle *lh)
 {
 	return lgsm_send_simple(lh, GSMD_MSG_PHONEBOOK, GSMD_PHONEBOOK_GET_SUPPORT);
Index: gsm/src/util/shell.c
===================================================================
--- gsm.orig/src/util/shell.c	2007-08-15 00:32:43.000000000 +0800
+++ gsm/src/util/shell.c	2007-08-15 00:34:28.000000000 +0800
@@ -34,8 +34,17 @@
 #include <gsmd/usock.h>
 #include <gsmd/ts0705.h>
 
+#ifndef __GSMD__
+#define __GSMD__
+#include <gsmd/talloc.h>
+#undef __GSMD__
+#endif
+
 #define STDIN_BUF_SIZE	1024
 
+static LLIST_HEAD(storage_list);
+static LLIST_HEAD(phonebook_list);
+
 /* this is the handler for receiving passthrough responses */
 static int pt_msghandler(struct lgsm_handle *lh, struct gsmd_msg_hdr *gmh)
 {
@@ -48,28 +57,107 @@
 {
 	struct gsmd_phonebook *gp;
 	struct gsmd_phonebook_support *gps;
+	struct gsmd_phonebook_storage *gpst;
 	char *payload;
+	char *fcomma, *lcomma, *ptr = NULL;
+	char buf[128];
 
 	switch (gmh->msg_subtype) {
 	case GSMD_PHONEBOOK_FIND:		
-		break;
 	case GSMD_PHONEBOOK_READRG:
 		payload = (char *)gmh + sizeof(*gmh);
-		printf("%s\n", payload);	
+
+		if (!strncmp(payload, "+CPBR", 5) ||
+				!strncmp(payload, "+CPBF", 5)) {
+			gp = (struct gsmd_phonebook *) malloc(sizeof(struct gsmd_phonebook));
+			ptr = strchr(payload, ' ');
+	                gp->index = atoi(ptr+1);
+
+	                fcomma = strchr(payload, '"');
+	                lcomma = strchr(fcomma+1, '"');
+	                strncpy(gp->numb, fcomma + 1, (lcomma-fcomma-1));
+	                gp->numb[(lcomma - fcomma) - 1] = '\0';
+
+	                gp->type = atoi(lcomma + 2);
+
+	                ptr = strrchr(payload, ',');
+	                fcomma = ptr + 1;
+	                lcomma = strchr(fcomma + 1, '"');
+	                strncpy(gp->text, fcomma + 1, (lcomma - fcomma - 1));
+	                gp->text[(lcomma - fcomma) - 1] = '\0';
+
+			llist_add_tail(&gp->list, &phonebook_list);
+
+#if 0
+			llist_for_each_entry(gp, &phonebook_list, list) {
+				printf("%d, %s, %d, %s\n", gp->index, gp->numb, gp->type, gp->text);
+			}
+#endif
+			printf("%d, %s, %d, %s\n", gp->index, gp->numb, gp->type, gp->text);
+		}
+		else
+			printf("%s\n", payload);
 		break;
 	case GSMD_PHONEBOOK_READ:
 		gp = (struct gsmd_phonebook *) ((char *)gmh + sizeof(*gmh));
-		printf("%d, %s, %d, %s\n", gp->index, gp->numb, gp->type, gp->text);
-		break;
-	case GSMD_PHONEBOOK_WRITE:			
-	case GSMD_PHONEBOOK_DELETE:
-		payload = (char *)gmh + sizeof(*gmh);
-		printf("%s\n", payload);		
+		if (gp->index)
+			printf("%d, %s, %d, %s\n",
+					gp->index, gp->numb,
+					gp->type, gp->text);
+		else
+			printf("Empty\n");
 		break;
 	case GSMD_PHONEBOOK_GET_SUPPORT:
 		gps = (struct gsmd_phonebook_support *) ((char *)gmh + sizeof(*gmh));
 		printf("(1-%d), %d, %d\n", gps->index, gps->nlength, gps->tlength);
 		break;
+	case GSMD_PHONEBOOK_LIST_STORAGE:
+		payload = (char *)gmh + sizeof(*gmh);
+
+		if (!strncmp(payload, "+CPBS", 5)) {
+			char* delim = "(,";
+			struct gsmd_phonebook_storage *cur, *cur2;
+
+			/* Remove previous record */
+			if (!llist_empty(&storage_list)) {
+				llist_for_each_entry_safe(cur, cur2,
+						&storage_list, list) {
+					llist_del(&cur->list);
+					talloc_free(cur);
+				}
+			}
+
+			ptr = strpbrk(payload, delim);
+
+			while ( ptr ) {
+				gpst = (struct gsmd_phonebook_storage *) malloc(sizeof(struct gsmd_phonebook_storage));
+				strncpy(gpst->storage, ptr+2, 2);
+				gpst->storage[2] = '\0';
+
+				ptr = strpbrk(ptr+2, delim);
+
+				llist_add_tail(&gpst->list, &storage_list);
+			}
+
+			if (llist_empty(&storage_list))
+				return 0;
+
+			llist_for_each_entry(cur, &storage_list, list) {
+				printf("\n%s",cur->storage);
+			}
+
+			printf("\n");
+		}
+		else
+			printf("%s\n", payload);
+		break;
+	case GSMD_PHONEBOOK_WRITE:
+	case GSMD_PHONEBOOK_DELETE:
+	case GSMD_PHONEBOOK_SET_STORAGE:
+		/* TODO: Need to handle error */
+		payload = (char *)gmh + sizeof(*gmh);
+		printf("%s\n", payload);
+		break;
 	default:
 		return -EINVAL;
 	}	
@@ -270,6 +358,8 @@
 		"\tpf\tPB Find (pff=indtext)\n"
 		"\tpw\tPB Write (pw=index,number,text)\n"
 		"\tps\tPB Support\n"
+		"\tpm\tPB Memory\n"
+		"\tpp\tPB Set Memory (pp=storage)\n"
 		"\tsd\tSMS Delete (sd=index,delflg)\n"
 		"\tsl\tSMS List (sl=stat)\n"
 		"\tsr\tSMS Read (sr=index)\n"
@@ -392,27 +482,51 @@
 			} else if ( !strncmp(buf, "pd", 2)) {
 				printf("Delete Phonebook Entry\n");				
 				ptr = strchr(buf, '=');
-				lgsmd_pb_del_entry(lgsmh, atoi(ptr+1));
+				lgsm_pb_del_entry(lgsmh, atoi(ptr+1));
 			} else if ( !strncmp(buf, "prr", 3)) {	
 				printf("Read Phonebook Entries\n");
 				struct lgsm_phonebook_readrg pb_readrg;
+				struct gsmd_phonebook *gp_cur, *gp_cur2;
+
+				/* Remove records */
+				if (!llist_empty(&phonebook_list)) {
+					llist_for_each_entry_safe(gp_cur,
+							gp_cur2,
+							&phonebook_list,
+							list) {
+						llist_del(&gp_cur->list);
+						talloc_free(gp_cur);
+					}
+				}
 
 				ptr = strchr(buf, '=');
 				pb_readrg.index1 = atoi(ptr+1);				
 				ptr = strchr(buf, ',');
-				pb_readrg.index2 = atoi(ptr+1);	
-
-				lgsm_pb_read_entryies(lgsmh, &pb_readrg);
-			} else if ( !strncmp(buf, "pr", 2)) {	
-				printf("Read Phonebook Entry\n");
-				ptr = strchr(buf, '=');				
+				pb_readrg.index2 = atoi(ptr+1);
+				lgsm_pb_read_entries(lgsmh, &pb_readrg);
+			} else if ( !strncmp(buf, "pr", 2)) {
+				ptr = strchr(buf, '=');
 				lgsm_pb_read_entry(lgsmh, atoi(ptr+1));
 			} else if ( !strncmp(buf, "pf", 2)) {
 				printf("Find Phonebook Entry\n");
 				struct lgsm_phonebook_find pb_find;
+				struct gsmd_phonebook *gp_cur, *gp_cur2;
+
+				/* Remove records */
+				if (!llist_empty(&phonebook_list)) {
+					llist_for_each_entry_safe(gp_cur,
+							gp_cur2,
+							&phonebook_list,
+							list) {
+						llist_del(&gp_cur->list);
+						talloc_free(gp_cur);
+					}
+				}
 
 				ptr = strchr(buf, '=');
-				strncpy(pb_find.findtext, ptr+1, sizeof(pb_find.findtext)-1);
+				strncpy(pb_find.findtext,
+						ptr + 1,
+						sizeof(pb_find.findtext) - 1);
 				pb_find.findtext[strlen(ptr+1)] = '\0';	
 			
 				lgsm_pb_find_entry(lgsmh, &pb_find);
@@ -425,16 +539,25 @@
 
 				fcomma = strchr(buf, ',');
 				lcomma = strchr(fcomma+1, ',');
-				strncpy(pb.numb, fcomma+1, (lcomma-fcomma-1));
-				pb.numb[(lcomma-fcomma-1)] = '\0';				
-				if ( '+' == pb.numb[0] )
+				strncpy(pb.numb, fcomma + 1, (lcomma - fcomma - 1));
+				pb.numb[(lcomma - fcomma - 1)] = '\0';
+				if ('+' == pb.numb[0])
 					pb.type = LGSM_PB_ATYPE_INTL;
 				else 
 					pb.type = LGSM_PB_ATYPE_OTHE;				
-				strncpy(pb.text, lcomma+1, strlen(lcomma+1));
-				pb.text[strlen(lcomma+1)] = '\0';
-				
-				lgsmd_pb_write_entry(lgsmh, &pb);
+				strncpy(pb.text, lcomma + 1, strlen(lcomma + 1));
+				pb.text[strlen(lcomma + 1)] = '\0';
+
+				lgsm_pb_write_entry(lgsmh, &pb);
+			} else if ( !strncmp(buf, "pm", 2)) {
+				lgsm_pb_list_storage(lgsmh);
+			} else if ( !strncmp(buf, "pp", 2)) {
+				char storage[3];
+
+				ptr = strchr(buf, '=');
+				strncpy(storage, (ptr+1), 2);
+
+				lgsm_pb_set_storage(lgsmh, storage);
 			} else if ( !strncmp(buf, "ps", 2)) {	
 				printf("Get Phonebook Support\n");
 				lgsm_pb_get_support(lgsmh);
Index: gsm/src/util/Makefile.am
===================================================================
--- gsm.orig/src/util/Makefile.am	2007-08-15 00:28:44.000000000 +0800
+++ gsm/src/util/Makefile.am	2007-08-15 00:34:28.000000000 +0800
@@ -3,8 +3,9 @@
 
 bin_PROGRAMS = libgsmd-tool
 
-libgsmd_tool_SOURCES = libgsmd-tool.c shell.c event.c pin.c atcmd.c
-libgsmd_tool_LDADD = ../libgsmd/libgsmd.la
+libgsmd_tool_SOURCES = libgsmd-tool.c shell.c event.c pin.c atcmd.c \
+		       $(top_srcdir)/src/gsmd/talloc.c
+libgsmd_tool_LDADD = $(top_builddir)/src/libgsmd/libgsmd.la
 libgsmd_tool_LDFLAGS = -dynamic
 
 noinst_HEADERS = atcmd.h event.h pin.h shell.h
