From 4e578aa3ef5ec658a2ff7e8417fdbfb9d61c15f1 Mon Sep 17 00:00:00 2001 From: laforge Date: Fri, 17 Aug 2007 08:30:04 +0000 Subject: From: Andrzej Zaborowski Date: Thu, 26 Jul 2007 16:00:52 +0200 Subject: [PATCH] Cell Broadcast messages enabling/disabling and notifications. This adds GSMD_CB_SUBSCRIBE and GSMD_CB_UNSIBSCRIBE commands handling and proper handling of th +CMTI, +CMT, +CBMI, +CBM, +CDSI, +CDS unsolicited codes. It's also an overhaul of sms_cb.c which I first though stood for sms *callbacks* :) rather than "cell broadcast" so all SMS and CB related code now sits in this file. The Neo1973 modem doesn't seem to support storing CB messages and delivery status messages into memory, so the default is now set to output them directly to TE when they're enabled. None of the CB code is tested on real CBs, but I think it's a good start. git-svn-id: http://svn.openmoko.org/trunk/src/target/gsm@2721 99fdad57-331a-0410-800a-d7fa5415bdb3 --- src/gsmd/sms_cb.c | 555 +++++++++++++++++++++++++++++++++++++++++----- src/gsmd/unsolicited.c | 2 +- src/gsmd/usock.c | 7 +- src/libgsmd/libgsmd_sms.c | 10 + 4 files changed, 514 insertions(+), 60 deletions(-) (limited to 'src') 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 #include @@ -37,8 +37,9 @@ #include #include #include +#include -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 #include -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); +} -- cgit v1.2.3