diff options
-rw-r--r-- | include/gsmd/event.h | 2 | ||||
-rw-r--r-- | include/gsmd/sms.h | 5 | ||||
-rw-r--r-- | include/gsmd/usock.h | 19 | ||||
-rw-r--r-- | include/libgsmd/sms.h | 7 | ||||
-rw-r--r-- | src/gsmd/sms_cb.c | 555 | ||||
-rw-r--r-- | src/gsmd/unsolicited.c | 2 | ||||
-rw-r--r-- | src/gsmd/usock.c | 7 | ||||
-rw-r--r-- | src/libgsmd/libgsmd_sms.c | 10 |
8 files changed, 542 insertions, 65 deletions
diff --git a/include/gsmd/event.h b/include/gsmd/event.h index 15d070d..395c488 100644 --- a/include/gsmd/event.h +++ b/include/gsmd/event.h @@ -16,6 +16,8 @@ enum gsmd_events { GSMD_EVT_TIMEZONE = 11, /* Timezone change */ GSMD_EVT_SUBSCRIPTIONS = 12, /* To which events are we subscribed to */ GSMD_EVT_CIPHER = 13, /* Chiphering Information */ + GSMD_EVT_IN_CBM = 14, /* Incoming Cell Broadcat message */ + GSMD_EVT_IN_DS = 15, /* SMS Status Report */ __NUM_GSMD_EVT }; diff --git a/include/gsmd/sms.h b/include/gsmd/sms.h index 3192472..f4def25 100644 --- a/include/gsmd/sms.h +++ b/include/gsmd/sms.h @@ -7,12 +7,13 @@ int sms_cb_init(struct gsmd *gsmd); +#define MAX_PDU_SIZE 180 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); -extern const char *ts0705_memtype_name[]; -int parse_memtype(char *memtype); +int usock_rcv_sms(struct gsmd_user *gu, struct gsmd_msg_hdr *gph, int len); +int usock_rcv_cb(struct gsmd_user *gu, struct gsmd_msg_hdr *gph, int len); #endif /* __GSMD__ */ diff --git a/include/gsmd/usock.h b/include/gsmd/usock.h index bcff129..18ffa5e 100644 --- a/include/gsmd/usock.h +++ b/include/gsmd/usock.h @@ -22,6 +22,7 @@ enum gsmd_msg_type { GSMD_MSG_PHONE = 7, GSMD_MSG_PIN = 8, GSMD_MSG_SMS = 9, + GSMD_MSG_CB = 10, __NUM_GSMD_MSGS }; @@ -259,10 +260,21 @@ struct gsmd_evt_auxdata { struct gsmd_addr addr; } colp; struct { + int inlined; u_int8_t memtype; int index; } sms; struct { + int inlined; + u_int8_t memtype; + int index; + } cbm; + struct { + int inlined; + u_int8_t memtype; + int index; + } ds; + struct { enum gsmd_pin_type type; } pin; struct { @@ -289,7 +301,8 @@ struct gsmd_evt_auxdata { u_int16_t net_state_gprs; } cipher; } u; -} __attribute__((packed)); + u_int8_t data[0]; +} __attribute__ ((packed)); /* Refer to GSM 07.05 subclause 3.5.4 */ struct gsmd_sms_delete { @@ -431,8 +444,10 @@ struct gsmd_ucmd { 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); -extern struct gsmd_ucmd *usock_build_event(u_int8_t type, u_int8_t subtype, u_int8_t len); +extern struct gsmd_ucmd *usock_build_event(u_int8_t type, u_int8_t subtype, u_int16_t len); extern int usock_evt_send(struct gsmd *gsmd, struct gsmd_ucmd *ucmd, u_int32_t evt); +extern struct gsmd_ucmd *gsmd_ucmd_fill(int len, u_int8_t msg_type, + u_int8_t msg_subtype, u_int16_t id); #endif /* __GSMD__ */ diff --git a/include/libgsmd/sms.h b/include/libgsmd/sms.h index d389b21..69363e7 100644 --- a/include/libgsmd/sms.h +++ b/include/libgsmd/sms.h @@ -109,5 +109,10 @@ extern int packing_UCS2_82(char *src, char *dest); /* Refer to 3GPP TS 11.11 Annex B */ extern int unpacking_UCS2_82(char *src, char *dest); -#endif +/* This phone wants to receive Cell Broadcast Messages */ +extern int lgsm_cb_subscribe(struct lgsm_handle *lh); + +/* This phone wants no more Cell Broadcast Messages */ +extern int lgsm_cb_unsubscribe(struct lgsm_handle *lh); +#endif diff --git a/src/gsmd/sms_cb.c b/src/gsmd/sms_cb.c index 97141c1..9aed070 100644 --- a/src/gsmd/sms_cb.c +++ b/src/gsmd/sms_cb.c @@ -18,7 +18,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - */ + */ #include <stdlib.h> #include <stdio.h> @@ -37,8 +37,9 @@ #include <gsmd/atcmd.h> #include <gsmd/usock.h> #include <gsmd/unsolicited.h> +#include <gsmd/sms.h> -const char *ts0705_memtype_name[] = { +static const char *ts0705_memtype_name[] = { [GSM0705_MEMTYPE_NONE] = "NONE", [GSM0705_MEMTYPE_BROADCAST] = "BM", [GSM0705_MEMTYPE_ME_MESSAGE] = "ME", @@ -48,7 +49,7 @@ const char *ts0705_memtype_name[] = { [GSM0705_MEMTYPE_SR] = "SR", }; -inline int parse_memtype(char *memtype) +static inline int parse_memtype(char *memtype) { int i; @@ -60,165 +61,597 @@ inline int parse_memtype(char *memtype) return GSM0705_MEMTYPE_NONE; } +static int sms_list_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp) +{ + struct gsmd_user *gu = ctx; + struct gsmd_ucmd *ucmd; + struct gsmd_sms_list msg; + int i, idx, stat, len, cr; + u_int8_t pdu[MAX_PDU_SIZE]; + + if (cmd->ret && cmd->ret != -255) + return 0; + + /* FIXME: TEXT mode */ + if ( + sscanf(resp, "+CMGL: %i,%i,,%i\n%n", + &idx, &stat, &len, &cr) < 3 && + sscanf(resp, "+CMGL: %i,%i,\"%*[^\"]\",%i\n%n", + &idx, &stat, &len, &cr) < 3) + return -EINVAL; + if (len > 164) + return -EINVAL; + + msg.index = idx; + msg.stat = stat; + msg.is_last = (cmd->ret == 0); + for (i = 0; resp[cr] >= '0' && resp[cr + 1] >= '0' && + i < MAX_PDU_SIZE; i ++) { + if (sscanf(resp + 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; + } + + ucmd = gsmd_ucmd_fill(sizeof(msg), GSMD_MSG_SMS, + GSMD_SMS_LIST, cmd->id); + if (!ucmd) + return -ENOMEM; + memcpy(ucmd->buf, &msg, sizeof(msg)); + + usock_cmd_enqueue(ucmd, gu); + + return 0; +} + +static int sms_read_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp) +{ + struct gsmd_user *gu = ctx; + struct gsmd_ucmd *ucmd; + struct gsmd_sms_list msg; + int i, stat, len, cr; + u_int8_t pdu[MAX_PDU_SIZE]; + + if (cmd->ret) + return 0; + + /* FIXME: TEXT mode */ + if ( + sscanf(resp, "+CMGR: %i,,%i\n%n", + &stat, &len, &cr) < 2 && + sscanf(resp, "+CMGR: %i,%*i,%i\n%n", + &stat, &len, &cr) < 2) + return -EINVAL; + if (len > 164) + return -EINVAL; + + msg.index = 0; + msg.stat = stat; + msg.is_last = 1; + for (i = 0; resp[cr] >= '0' && resp[cr + 1] >= '0' && + i < MAX_PDU_SIZE; i ++) { + if (sscanf(resp + 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; + } + + ucmd = gsmd_ucmd_fill(sizeof(msg), GSMD_MSG_SMS, + GSMD_SMS_READ, cmd->id); + if (!ucmd) + return -ENOMEM; + memcpy(ucmd->buf, &msg, sizeof(msg)); + + usock_cmd_enqueue(ucmd, gu); + + return 0; +} + +static int sms_send_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp) +{ + struct gsmd_user *gu = ctx; + struct gsmd_ucmd *ucmd; + int msgref; + + if (cmd->ret == 0 || cmd->ret == -255) { + if (sscanf(resp, "+CMGS: %i", &msgref) < 1) + return -EINVAL; + } else + msgref = -cmd->ret; + + ucmd = gsmd_ucmd_fill(sizeof(int), GSMD_MSG_SMS, + GSMD_SMS_SEND, cmd->id); + if (!ucmd) + return -ENOMEM; + *(int *) ucmd->buf = msgref; + + usock_cmd_enqueue(ucmd, gu); + + return 0; +} + +static int sms_write_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp) +{ + struct gsmd_user *gu = ctx; + struct gsmd_ucmd *ucmd; + int result; + + if (cmd->ret == 0) { + if (sscanf(resp, "+CMGW: %i", &result) < 1) + return -EINVAL; + } else + result = -cmd->ret; + + ucmd = gsmd_ucmd_fill(sizeof(int), GSMD_MSG_SMS, + GSMD_SMS_WRITE, cmd->id); + if (!ucmd) + return -ENOMEM; + *(int *) ucmd->buf = result; + + usock_cmd_enqueue(ucmd, gu); + + return 0; +} + +static int sms_delete_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp) +{ + struct gsmd_user *gu = ctx; + struct gsmd_ucmd *ucmd; + int *result; + + ucmd = gsmd_ucmd_fill(sizeof(int), GSMD_MSG_SMS, + GSMD_SMS_DELETE, cmd->id); + if (!ucmd) + return -ENOMEM; + + result = (int *) ucmd->buf; + *result = cmd->ret; + + usock_cmd_enqueue(ucmd, gu); + + return 0; +} + +static int usock_cpms_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp) +{ + 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_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; +} + +static int usock_get_smsc_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp) +{ + struct gsmd_user *gu = ctx; + struct gsmd_ucmd *ucmd; + struct gsmd_addr *ga; + + ucmd = gsmd_ucmd_fill(sizeof(struct gsmd_addr), GSMD_MSG_SMS, + GSMD_SMS_GET_SERVICE_CENTRE, cmd->id); + if (!ucmd) + return -ENOMEM; + + ga = (struct gsmd_addr *) ucmd->buf; + if (sscanf(resp, "+CSCA: \"%31[^\"]\",%hhi", + ga->number, &ga->type) < 2) { + talloc_free(ucmd); + return -EINVAL; + } + + usock_cmd_enqueue(ucmd, gu); + return 0; +} + +static const char *gsmd_cmgl_stat[] = { + "REC UNREAD", "REC READ", "STO UNSENT", "STO SENT", "ALL", +}; + +/* main unix socket Short Message receiver */ +int usock_rcv_sms(struct gsmd_user *gu, struct gsmd_msg_hdr *gph, int len) +{ + /* FIXME: TEXT mode support!! */ + struct gsmd_atcmd *cmd = NULL; + struct gsmd_sms_delete *gsd; + struct gsmd_sms_submit *gss; + struct gsmd_sms_write *gsw; + struct gsmd_addr *ga; + enum ts0705_mem_type *storage; + int *stat, *index; + int atcmd_len; + char buf[1024]; + + switch (gph->msg_subtype) { + case GSMD_SMS_LIST: + if(len < sizeof(*gph) + sizeof(int)) + return -EINVAL; + stat = (int *) ((void *)gph + sizeof(*gph)); + if (*stat < 0 || *stat > 4) + return -EINVAL; + + if (gu->gsmd->flags & GSMD_FLAG_SMS_FMT_TEXT) + atcmd_len = sprintf(buf, "AT+CMGL=\"%s\"", + gsmd_cmgl_stat[*stat]); + else + atcmd_len = sprintf(buf, "AT+CMGL=%i", *stat); + + cmd = atcmd_fill(buf, atcmd_len + 1, + &sms_list_cb, gu, gph->id); + break; + + case GSMD_SMS_READ: + if(len < sizeof(*gph) + sizeof(int)) + return -EINVAL; + index = (int *) ((void *)gph + sizeof(*gph)); + + atcmd_len = sprintf(buf, "AT+CMGR=%i", *index); + + cmd = atcmd_fill(buf, atcmd_len + 1, + &sms_read_cb, gu, gph->id); + break; + + case GSMD_SMS_SEND: + if (len < sizeof(*gph) + sizeof(*gss)) + return -EINVAL; + gss = (struct gsmd_sms_submit *) ((void *) gph + sizeof(*gph)); + + if (gu->gsmd->flags & GSMD_FLAG_SMS_FMT_TEXT) { + atcmd_len = sprintf(buf, "AT+CMGS=\"%s\"\n%.*s", + gss->addr.number, + gss->payload.length, + gss->payload.data); /* FIXME */ + } else { + atcmd_len = sprintf(buf, "AT+CMGS=%i\n", + sms_pdu_make_smssubmit(NULL, gss) - 1); + atcmd_len += sms_pdu_make_smssubmit(buf + atcmd_len, + gss) * 2; + } + buf[atcmd_len ++] = 26; /* ^Z ends the message */ + buf[atcmd_len ++] = 0; + + cmd = atcmd_fill(buf, atcmd_len, &sms_send_cb, gu, gph->id); + break; + + case GSMD_SMS_WRITE: + if (len < sizeof(*gph) + sizeof(*gsw)) + return -EINVAL; + gsw = (struct gsmd_sms_write *) ((void *) gph + sizeof(*gph)); + if (gsw->stat > 4) + return -EINVAL; + + if (gu->gsmd->flags & GSMD_FLAG_SMS_FMT_TEXT) { + atcmd_len = sprintf(buf, "AT+CMGW=\"%s\"\n%.*s", + gsw->sms.addr.number, + gsw->sms.payload.length, + gsw->sms.payload.data); /* FIXME */ + } else { + atcmd_len = sprintf(buf, "AT+CMGW=%i,%i\n", + sms_pdu_make_smssubmit(NULL, + &gsw->sms) - 1, gsw->stat); + atcmd_len += sms_pdu_make_smssubmit(buf + atcmd_len, + &gsw->sms) * 2; + } + buf[atcmd_len ++] = 26; /* ^Z ends the message */ + buf[atcmd_len ++] = 0; + + cmd = atcmd_fill(buf, atcmd_len, &sms_write_cb, gu, gph->id); + break; + + case GSMD_SMS_DELETE: + if(len < sizeof(*gph) + sizeof(*gsd)) + return -EINVAL; + gsd = (struct gsmd_sms_delete *) ((void *)gph + sizeof(*gph)); + + atcmd_len = sprintf(buf, "AT+CMGD=%d,%d", + gsd->index, gsd->delflg); + + cmd = atcmd_fill(buf, atcmd_len + 1, + &sms_delete_cb, gu, gph->id); + break; + + case GSMD_SMS_GET_MSG_STORAGE: + cmd = atcmd_fill("AT+CPMS?", 8 + 1, usock_cpms_cb, gu, 0); + break; + + case GSMD_SMS_SET_MSG_STORAGE: + if (len < sizeof(*gph) + 3 * sizeof(enum ts0705_mem_type)) + return -EINVAL; + storage = (enum ts0705_mem_type *) + ((void *) gph + sizeof(*gph)); + atcmd_len = sprintf(buf, "AT+CPMS=\"%s\",\"%s\",\"%s\"", + ts0705_memtype_name[storage[0]], + ts0705_memtype_name[storage[1]], + ts0705_memtype_name[storage[2]]); + cmd = atcmd_fill(buf, atcmd_len + 1, NULL, gu, gph->id); + break; + + case GSMD_SMS_GET_SERVICE_CENTRE: + cmd = atcmd_fill("AT+CSCA?", 8 + 1, &usock_get_smsc_cb, gu, 0); + break; + + case GSMD_SMS_SET_SERVICE_CENTRE: + if (len < sizeof(*gph) + sizeof(struct gsmd_addr)) + return -EINVAL; + ga = (struct gsmd_addr *) ((void *) gph + sizeof(*gph)); + atcmd_len = sprintf(buf, "AT+CSCA=\"%s\",%i", + ga->number, ga->type); + cmd = atcmd_fill(buf, atcmd_len + 1, NULL, gu, gph->id); + break; + + default: + return -ENOSYS; + } + + if (!cmd) + return -ENOMEM; + + gsmd_log(GSMD_DEBUG, "%s\n", cmd ? cmd->buf : 0); + return atcmd_submit(gu->gsmd, cmd); +} + /* main unix socket Cell Broadcast receiver */ -static int usock_rcv_cb(struct gsmd_user *gu, struct gsmd_msg_hdr *gph, - int len) +int usock_rcv_cb(struct gsmd_user *gu, struct gsmd_msg_hdr *gph, int len) { + struct gsmd_atcmd *cmd; + switch (gph->msg_subtype) { case GSMD_CB_SUBSCRIBE: + cmd = atcmd_fill("AT+CSCB=1", 9 + 1, NULL, gu->gsmd, 0); break; case GSMD_CB_UNSUBSCRIBE: + cmd = atcmd_fill("AT+CSCB=0", 9 + 1, NULL, gu->gsmd, 0); break; + default: + return -ENOSYS; } - return -ENOSYS; + if (!cmd) + return -ENOMEM; + + return atcmd_submit(gu->gsmd, cmd); } /* Unsolicited messages related to SMS / CB */ -static int cmti_parse(char *buf, int len, const char *param, - struct gsmd *gsmd) +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; + struct gsmd_evt_auxdata *aux; + struct gsmd_ucmd *ucmd = usock_build_event(GSMD_MSG_EVENT, + GSMD_EVT_IN_SMS, sizeof(struct gsmd_evt_auxdata)); 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); - + aux = (struct gsmd_evt_auxdata *) ucmd->buf; if (sscanf(param, "\"%2[A-Z]\",%i", memstr, &aux->u.sms.index) < 2) { talloc_free(ucmd); return -EINVAL; } + aux->u.sms.inlined = 0; 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) +static int cmt_parse(char *buf, int len, const char *param, struct gsmd *gsmd) { /* TODO: TEXT mode */ - u_int8_t pdu[180]; + u_int8_t pdu[MAX_PDU_SIZE]; const char *comma = strchr(param, ','); char *cr; int i; - struct gsmd_sms_list msg; + struct gsmd_evt_auxdata *aux; + struct gsmd_sms_list *msg; + struct gsmd_ucmd *ucmd = usock_build_event(GSMD_MSG_EVENT, + GSMD_EVT_IN_SMS, sizeof(struct gsmd_evt_auxdata) + + sizeof(struct gsmd_sms_list)); + + if (!ucmd) + return -ENOMEM; - if (!comma) + aux = (struct gsmd_evt_auxdata *) ucmd->buf; + msg = (struct gsmd_sms_list *) aux->data; + + if (!comma) { + talloc_free(ucmd); return -EINVAL; + } len = strtoul(comma + 1, &cr, 10); - if (cr[0] != '\n') + if (cr[0] != '\n') { + talloc_free(ucmd); return -EINVAL; + } cr ++; - for (i = 0; cr[0] >= '0' && cr[1] >= '0' && i < 180; i ++) { + for (i = 0; cr[0] >= '0' && cr[1] >= '0' && i < MAX_PDU_SIZE; i ++) { if (sscanf(cr, "%2hhX", &pdu[i]) < 1) { gsmd_log(GSMD_DEBUG, "malformed input (%i)\n", i); + talloc_free(ucmd); return -EINVAL; } cr += 2; } - if (sms_pdu_to_msg(&msg, pdu, len, i)) { + + aux->u.sms.inlined = 1; + if (sms_pdu_to_msg(msg, pdu, len, i)) { gsmd_log(GSMD_DEBUG, "malformed PDU\n"); + talloc_free(ucmd); return -EINVAL; } - /* FIXME: generate some kind of event */ - return -ENOSYS; + return usock_evt_send(gsmd, ucmd, GSMD_EVT_IN_SMS); } -static int cbmi_parse(char *buf, int len, const char *param, - struct gsmd *gsmd) +static int cbmi_parse(char *buf, int len, const char *param, struct gsmd *gsmd) { char memstr[3]; - int memtype, index; + struct gsmd_evt_auxdata *aux; + struct gsmd_ucmd *ucmd = usock_build_event(GSMD_MSG_EVENT, + GSMD_EVT_IN_CBM, sizeof(struct gsmd_evt_auxdata)); + + if (!ucmd) + return -ENOMEM; + + ucmd->hdr.version = GSMD_PROTO_VERSION; + ucmd->hdr.msg_type = GSMD_MSG_EVENT; + ucmd->hdr.msg_subtype = GSMD_EVT_IN_CBM; + ucmd->hdr.len = sizeof(*aux); - if (sscanf(param, "\"%2[A-Z]\",%i", memstr, &index) < 2) + aux = (struct gsmd_evt_auxdata *) ucmd->buf; + if (sscanf(param, "\"%2[A-Z]\",%i", memstr, &aux->u.cbm.index) < 2) { + talloc_free(ucmd); return -EINVAL; + } + + aux->u.cbm.inlined = 0; + aux->u.cbm.memtype = parse_memtype(memstr); - memtype = parse_memtype(memstr); - /* FIXME: generate some kind of event */ - return -ENOSYS; + return usock_evt_send(gsmd, ucmd, GSMD_EVT_IN_CBM); } -static int cbm_parse(char *buf, int len, const char *param, - struct gsmd *gsmd) +static int cbm_parse(char *buf, int len, const char *param, struct gsmd *gsmd) { /* TODO: TEXT mode */ - u_int8_t pdu[180]; + u_int8_t pdu[MAX_PDU_SIZE]; char *cr; int i; - struct gsmd_sms_list msg; + struct gsmd_evt_auxdata *aux; + struct gsmd_sms_list *msg; + struct gsmd_ucmd *ucmd = usock_build_event(GSMD_MSG_EVENT, + GSMD_EVT_IN_CBM, sizeof(struct gsmd_evt_auxdata) + + sizeof(struct gsmd_sms_list)); + + if (!ucmd) + return -ENOMEM; + + aux = (struct gsmd_evt_auxdata *) ucmd->buf; + msg = (struct gsmd_sms_list *) aux->data; len = strtoul(param, &cr, 10); if (cr[0] != '\n') return -EINVAL; cr ++; - for (i = 0; cr[0] >= '0' && cr[1] >= '0' && i < 180; i ++) { + for (i = 0; cr[0] >= '0' && cr[1] >= '0' && i < MAX_PDU_SIZE; i ++) { if (sscanf(cr, "%2hhX", &pdu[i]) < 1) { gsmd_log(GSMD_DEBUG, "malformed input (%i)\n", i); + talloc_free(ucmd); return -EINVAL; } cr += 2; } - if (sms_pdu_to_msg(&msg, pdu, len, i)) { + + aux->u.cbm.inlined = 1; + if (sms_pdu_to_msg(msg, pdu, len, i)) { gsmd_log(GSMD_DEBUG, "malformed PDU\n"); + talloc_free(ucmd); return -EINVAL; } - /* FIXME: generate some kind of event */ - return -ENOSYS; + return usock_evt_send(gsmd, ucmd, GSMD_EVT_IN_CBM); } -static int cdsi_parse(char *buf, int len, const char *param, - struct gsmd *gsmd) +static int cdsi_parse(char *buf, int len, const char *param, struct gsmd *gsmd) { char memstr[3]; - int memtype, index; + struct gsmd_evt_auxdata *aux; + struct gsmd_ucmd *ucmd = usock_build_event(GSMD_MSG_EVENT, + GSMD_EVT_IN_DS, sizeof(struct gsmd_evt_auxdata)); + + if (!ucmd) + return -ENOMEM; - if (sscanf(param, "\"%2[A-Z]\",%i", memstr, &index) < 2) + aux = (struct gsmd_evt_auxdata *) ucmd->buf; + if (sscanf(param, "\"%2[A-Z]\",%i", memstr, &aux->u.ds.index) < 2) { + talloc_free(ucmd); return -EINVAL; + } - memtype = parse_memtype(memstr); - /* FIXME: generate some kind of event */ - return -ENOSYS; + aux->u.ds.inlined = 0; + aux->u.ds.memtype = parse_memtype(memstr); + + return usock_evt_send(gsmd, ucmd, GSMD_EVT_IN_DS); } -static int cds_parse(char *buf, int len, const char *param, - struct gsmd *gsmd) +static int cds_parse(char *buf, int len, const char *param, struct gsmd *gsmd) { /* TODO: TEXT mode */ - u_int8_t pdu[180]; + u_int8_t pdu[MAX_PDU_SIZE]; char *cr; int i; - struct gsmd_sms_list msg; + struct gsmd_evt_auxdata *aux; + struct gsmd_sms_list *msg; + struct gsmd_ucmd *ucmd = usock_build_event(GSMD_MSG_EVENT, + GSMD_EVT_IN_DS, sizeof(struct gsmd_evt_auxdata) + + sizeof(struct gsmd_sms_list)); + + if (!ucmd) + return -ENOMEM; + + aux = (struct gsmd_evt_auxdata *) ucmd->buf; + msg = (struct gsmd_sms_list *) aux->data; len = strtoul(param, &cr, 10); if (cr[0] != '\n') return -EINVAL; cr ++; - for (i = 0; cr[0] >= '0' && cr[1] >= '0' && i < 180; i ++) { + for (i = 0; cr[0] >= '0' && cr[1] >= '0' && i < MAX_PDU_SIZE; i ++) { if (sscanf(cr, "%2hhX", &pdu[i]) < 1) { gsmd_log(GSMD_DEBUG, "malformed input (%i)\n", i); + talloc_free(ucmd); return -EINVAL; } cr += 2; } - if (sms_pdu_to_msg(&msg, pdu, len, i)) { + + aux->u.ds.inlined = 1; + if (sms_pdu_to_msg(msg, pdu, len, i)) { gsmd_log(GSMD_DEBUG, "malformed PDU\n"); + talloc_free(ucmd); return -EINVAL; } - /* FIXME: generate some kind of event */ - return -ENOSYS; + return usock_evt_send(gsmd, ucmd, GSMD_EVT_IN_DS); } static const struct gsmd_unsolicit gsm0705_unsolicit[] = { @@ -243,8 +676,16 @@ int sms_cb_init(struct gsmd *gsmd) return -ENOMEM; atcmd_submit(gsmd, atcmd); - /* Store and notify */ - atcmd = atcmd_fill("AT+CNMI=1,1,1", 13 + 1, NULL, gsmd, 0); + /* + * Set the New Message Indications properties to values that are + * likely supported. We will get a: + * +CMTI on a new incoming SMS, + * +CBM on a new incoming CB, + * +CDS on an SMS status report. + * + * FIXME: ask for supported +CNMI values first. + */ + atcmd = atcmd_fill("AT+CNMI=2,1,2,1,0", 17 + 1, NULL, gsmd, 0); if (!atcmd) return -ENOMEM; atcmd_submit(gsmd, atcmd); diff --git a/src/gsmd/unsolicited.c b/src/gsmd/unsolicited.c index 4bf4833..82a4f17 100644 --- a/src/gsmd/unsolicited.c +++ b/src/gsmd/unsolicited.c @@ -36,7 +36,7 @@ #include <gsmd/unsolicited.h> #include <gsmd/talloc.h> -struct gsmd_ucmd *usock_build_event(u_int8_t type, u_int8_t subtype, u_int8_t len) +struct gsmd_ucmd *usock_build_event(u_int8_t type, u_int8_t subtype, u_int16_t len) { struct gsmd_ucmd *ucmd = ucmd_alloc(len); diff --git a/src/gsmd/usock.c b/src/gsmd/usock.c index 543c3cf..08563cf 100644 --- a/src/gsmd/usock.c +++ b/src/gsmd/usock.c @@ -319,8 +319,8 @@ out_free_einval: return -EINVAL; } -static struct gsmd_ucmd *gsmd_ucmd_fill(int len, u_int8_t msg_type, u_int8_t msg_subtype, - u_int16_t id) +struct gsmd_ucmd *gsmd_ucmd_fill(int len, u_int8_t msg_type, + u_int8_t msg_subtype, u_int16_t id) { struct gsmd_ucmd *ucmd; @@ -511,6 +511,7 @@ static int usock_rcv_network(struct gsmd_user *gu, struct gsmd_msg_hdr *gph, return atcmd_submit(gu->gsmd, cmd); } +#if 0 static int sms_list_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp) { struct gsmd_user *gu = ctx; @@ -876,6 +877,7 @@ static int usock_rcv_sms(struct gsmd_user *gu, struct gsmd_msg_hdr *gph, gsmd_log(GSMD_DEBUG, "%s\n", cmd ? cmd->buf : 0); return atcmd_submit(gu->gsmd, cmd); } +#endif #if 0 static int phonebook_find_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp) @@ -1127,6 +1129,7 @@ static usock_msg_handler *pcmd_type_handlers[__NUM_GSMD_MSGS] = { [GSMD_MSG_PHONE] = &usock_rcv_phone, [GSMD_MSG_NETWORK] = &usock_rcv_network, [GSMD_MSG_SMS] = &usock_rcv_sms, + [GSMD_MSG_CB] = &usock_rcv_cb, //[GSMD_MSG_PHONEBOOK] = &usock_rcv_phonebook, }; diff --git a/src/libgsmd/libgsmd_sms.c b/src/libgsmd/libgsmd_sms.c index 29b92fb..72723c0 100644 --- a/src/libgsmd/libgsmd_sms.c +++ b/src/libgsmd/libgsmd_sms.c @@ -318,3 +318,13 @@ int unpacking_UCS2_82(char *src, char *dest) { return 0; } + +int lgsm_cb_subscribe(struct lgsm_handle *lh) +{ + return lgsm_send_simple(lh, GSMD_MSG_CB, GSMD_CB_SUBSCRIBE); +} + +int lgsm_cb_unsubscribe(struct lgsm_handle *lh) +{ + return lgsm_send_simple(lh, GSMD_MSG_CB, GSMD_CB_UNSUBSCRIBE); +} |