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);