From 3e5832569d3b29a90b29b5d5ac0ffad4765bcff3 Mon Sep 17 00:00:00 2001 From: Andrzej Zaborowski Date: Fri, 6 Jul 2007 06:55:12 +0200 Subject: [PATCH] SMS hacks 2 --- include/gsmd/gsmd.h | 8 ++- include/gsmd/usock.h | 35 ++++++++- include/gsmd/vendorplugin.h | 2 +- include/libgsmd/sms.h | 2 +- src/gsmd/atcmd.c | 130 +++++++++++++++++++------------- src/gsmd/sms_cb.c | 19 ++++- src/gsmd/usock.c | 175 +++++++++++++++++++++++++++++++++++++----- src/gsmd/vendor_ti.c | 2 +- src/libgsmd/libgsmd_sms.c | 26 +++++-- 11 files changed, 320 insertions(+), 91 deletions(-) Index: gsm/include/gsmd/gsmd.h =================================================================== --- gsm.orig/include/gsmd/gsmd.h 2007-07-31 14:09:02.000000000 +0200 +++ gsm/include/gsmd/gsmd.h 2007-07-31 14:23:32.000000000 +0200 @@ -27,6 +27,7 @@ u_int32_t buflen; u_int16_t id; u_int8_t flags; + char *cur; char buf[]; }; @@ -36,6 +37,8 @@ LLPARSE_STATE_IDLE_LF, /* LF before response (V1) */ LLPARSE_STATE_RESULT, /* within result payload */ LLPARSE_STATE_RESULT_CR, /* CR after result */ + LLPARSE_STATE_PROMPT, /* within a "> " prompt */ + LLPARSE_STATE_PROMPT_SPC, /* a complete "> " prompt */ LLPARSE_STATE_ERROR, /* something went wrong */ /* ... idle again */ }; @@ -52,6 +55,7 @@ unsigned int flags; void *ctx; int (*cb)(const char *buf, int len, void *ctx); + int (*prompt_cb)(void *ctx); char *cur; char buf[LLPARSE_BUF_SIZE]; }; @@ -59,6 +63,7 @@ struct gsmd; #define GSMD_FLAG_V0 0x0001 /* V0 responses to be expected from TA */ +#define GSMD_FLAG_SMS_FMT 0x0002 /* Use TEXT rather than PDU mode */ struct gsmd { unsigned int flags; @@ -94,7 +99,8 @@ extern int gsmdlog_init(const char *path); /* write a message to the daemons' logfile */ -void __gsmd_log(int level, const char *file, int line, const char *function, const char *message, ...); +void __gsmd_log(int level, const char *file, int line, const char *function, const char *message, ...) + __attribute__ ((__format__ (__printf__, 5, 6))); /* macro for logging including filename and line number */ #define gsmd_log(level, format, args ...) \ __gsmd_log(level, __FILE__, __LINE__, __FUNCTION__, format, ## args) Index: gsm/include/gsmd/usock.h =================================================================== --- gsm.orig/include/gsmd/usock.h 2007-07-31 13:58:37.000000000 +0200 +++ gsm/include/gsmd/usock.h 2007-07-31 14:23:32.000000000 +0200 @@ -139,7 +139,7 @@ /* for SMS-SUBMIT, SMS-DELIVER */ enum gsmd_sms_tp_udhi { GSMD_SMS_TP_UDHI_NO_HEADER = (0<<6), - GSMD_SMS_TP_UDHI_WTIH_HEADER = (1<<6), + GSMD_SMS_TP_UDHI_WITH_HEADER = (1<<6), }; /* SMS delflg from 3GPP TS 07.05, Clause 3.5.4 */ @@ -160,6 +160,34 @@ GSMD_PHONEBOOK_GET_SUPPORT = 6, }; +/* Type-of-Address, Numbering Plan Identification field */ +enum gsmd_toa_npi { + GSMD_TOA_NPI_UNKNOWN = 0x0, + GSMD_TOA_NPI_ISDN = 0x1, + GSMD_TOA_NPI_DATA = 0x3, + GSMD_TOA_NPI_TELEX = 0x4, + GSMD_TOA_NPI_NATIONAL = 0x8, + GSMD_TOA_NPI_PRIVATE = 0x9, + GSMD_TOA_NPI_ERMES = 0xa, + GSMD_TOA_NPI_RESERVED = 0xf, +}; + +/* Type-of-Address, Type-of-Number field */ +enum gsmd_toa_ton { + GSMD_TOA_TON_UNKNOWN = (0<<4), + GSMD_TOA_TON_INTERNATIONAL = (1<<4), + GSMD_TOA_TON_NATIONAL = (2<<4), + GSMD_TOA_TON_NETWORK = (3<<4), + GSMD_TOA_TON_SUBSCRIBER = (4<<4), + GSMD_TOA_TON_ALPHANUMERIC = (5<<4), + GSMD_TOA_TON_ABBREVIATED = (6<<4), +}; + +/* Type-of-Address, bit 7 always 1 */ +enum gsmd_toa_reserved { + GSMD_TOA_RESERVED = (1<<7), +}; + /* Length from 3GPP TS 04.08, Clause 10.5.4.7 */ #define GSMD_ADDR_MAXLEN 32 @@ -269,6 +297,11 @@ char user_data[140]; } __attribute__ ((packed)); +struct gsmd_sms_send { + struct gsmd_addr addr; + struct gsmd_sms payload; +}; + /* Refer to GSM 07.07 subclause 8.12 */ struct gsmd_phonebook_readrg { u_int8_t index1; Index: gsm/include/gsmd/vendorplugin.h =================================================================== --- gsm.orig/include/gsmd/vendorplugin.h 2007-07-31 13:58:38.000000000 +0200 +++ gsm/include/gsmd/vendorplugin.h 2007-07-31 14:23:32.000000000 +0200 @@ -12,7 +12,7 @@ struct gsmd_vendor_plugin { struct llist_head list; unsigned char *name; - unsigned char *ext_chars; + char *ext_chars; unsigned int num_unsolicit; const struct gsmd_unsolicit *unsolicit; int (*detect)(struct gsmd *g); Index: gsm/include/libgsmd/sms.h =================================================================== --- gsm.orig/include/libgsmd/sms.h 2007-07-31 13:58:38.000000000 +0200 +++ gsm/include/libgsmd/sms.h 2007-07-31 14:23:32.000000000 +0200 @@ -83,7 +83,7 @@ extern int lgsmd_sms_send(struct lgsm_handle *lh, const struct lgsm_sms *sms); /* Write Message to Memory */ -extern int lgsmd_sms_write(struct lgsm_handle *lh, +extern int lgsmd_sms_write(struct lgsm_handle *lh, const struct lgsm_sms_write *sms_write); /* Packing of 7-bit characters, refer to GSM 03.38 subclause 6.1.2.1.1 */ Index: gsm/src/gsmd/atcmd.c =================================================================== --- gsm.orig/src/gsmd/atcmd.c 2007-07-31 14:13:00.000000000 +0200 +++ gsm/src/gsmd/atcmd.c 2007-07-31 14:23:32.000000000 +0200 @@ -82,9 +82,12 @@ switch (llp->state) { case LLPARSE_STATE_IDLE: + case LLPARSE_STATE_PROMPT_SPC: if (llp->flags & LGSM_ATCMD_F_EXTENDED) { if (byte == '\r') llp->state = LLPARSE_STATE_IDLE_CR; + else if (byte == '>') + llp->state = LLPARSE_STATE_PROMPT; else { #ifdef STRICT llp->state = LLPARSE_STATE_ERROR; @@ -108,6 +111,8 @@ /* can we really go directly into result_cr ? */ if (byte == '\r') llp->state = LLPARSE_STATE_RESULT_CR; + else if (byte == '>') + llp->state = LLPARSE_STATE_PROMPT; else { llp->state = LLPARSE_STATE_RESULT; ret = llparse_append(llp, byte); @@ -127,6 +132,16 @@ memset(llp->buf, 0, LLPARSE_BUF_SIZE); } break; + case LLPARSE_STATE_PROMPT: + if (byte == ' ') + llp->state = LLPARSE_STATE_PROMPT_SPC; + else { + /* this was not a real "> " prompt */ + llparse_append(llp, '>'); + ret = llparse_append(llp, byte); + llp->state = LLPARSE_STATE_RESULT; + } + break; case LLPARSE_STATE_ERROR: break; } @@ -147,6 +162,10 @@ /* FIXME: what to do with return value ? */ llp->cb(llp->buf, llp->cur - llp->buf, llp->ctx); } + + /* if a full SMS-style prompt was received, poke the select */ + if (llp->state == LLPARSE_STATE_PROMPT_SPC) + llp->prompt_cb(llp->ctx); } return 0; @@ -175,7 +194,7 @@ { struct gsmd *g = ctx; struct gsmd_atcmd *cmd = NULL; - int rc = 0, final = 0; + int rc = 0; DEBUGP("buf=`%s'(%d)\n", buf, len); @@ -229,7 +248,6 @@ DEBUGP("error number %lu\n", err_nr); if (cmd) cmd->ret = err_nr; - final = 1; goto final_cb; } if (!strncmp(buf+1, "CMS ERROR", 9)) { @@ -239,7 +257,6 @@ DEBUGP("error number %lu\n", err_nr); if (cmd) cmd->ret = err_nr; - final = 1; goto final_cb; } @@ -271,7 +288,7 @@ /* it might be a multiline response, so if there's a previous response, send out mlbuf and start afresh with an empty buffer */ - if (g->mlbuf[0] != 0) { + if (g->mlbuf_len) { if (!cmd->cb) { gsmd_log(GSMD_NOTICE, "command without cb!!!\n"); } else { @@ -279,8 +296,8 @@ cmd->resp = g->mlbuf; rc = cmd->cb(cmd, cmd->ctx, cmd->resp); DEBUGP("Clearing mlbuf\n"); - g->mlbuf[0] = 0; } + g->mlbuf_len = 0; } /* the current buf will be appended to mlbuf below */ @@ -299,7 +316,6 @@ DEBUGP("unspecified error\n"); if (cmd) cmd->ret = 4; - final = 1; goto final_cb; } @@ -308,7 +324,6 @@ /* Part of Case 'C' */ if (cmd) cmd->ret = 0; - final = 1; goto final_cb; } @@ -317,14 +332,12 @@ if (!strncmp(buf, "NO CARRIER", 11) || ((g->flags & GSMD_FLAG_V0) && buf[0] == '3')) { /* Part of Case 'D' */ - final = 1; goto final_cb; } if (!strncmp(buf, "BUSY", 4) || ((g->flags & GSMD_FLAG_V0) && buf[0] == '7')) { /* Part of Case 'D' */ - final = 1; goto final_cb; } } @@ -332,21 +345,13 @@ /* we reach here, if we are at an information response that needs to be * passed on */ - if (g->mlbuf[0] == 0) { - DEBUGP("Filling mlbuf\n"); - strncat(g->mlbuf, buf, MLPARSE_BUF_SIZE-1); - } else { - DEBUGP("Appending buf to mlbuf\n"); - g->mlbuf_len = strlen(g->mlbuf); - if (g->mlbuf_len+1 < MLPARSE_BUF_SIZE) { - g->mlbuf[g->mlbuf_len] = '\n'; - g->mlbuf[g->mlbuf_len+1] = '\0'; - strncat(g->mlbuf, buf, MLPARSE_BUF_SIZE-g->mlbuf_len-2); - } else { - DEBUGP("response too big for mlbuf!!!\n"); - return -EFBIG; - } - } + if (g->mlbuf_len) + g->mlbuf[g->mlbuf_len ++] = '\n'; + DEBUGP("Appending buf to mlbuf\n"); + if (len > MLPARSE_BUF_SIZE - g->mlbuf_len) + len = MLPARSE_BUF_SIZE - g->mlbuf_len; + memcpy(g->mlbuf + g->mlbuf_len, buf, len); + g->mlbuf_len += len; return 0; final_cb: @@ -363,13 +368,16 @@ } else { DEBUGP("Calling final cmd->cb()\n"); /* send final result code if there is no information response in mlbuf */ - if (g->mlbuf[0] == 0) - cmd->resp = buf; - else + if (g->mlbuf_len) { cmd->resp = g->mlbuf; + g->mlbuf[g->mlbuf_len] = 0; + gsmd_log(GSMD_NOTICE, + "the text discarded is %s\n", buf); + } else + cmd->resp = buf; rc = cmd->cb(cmd, cmd->ctx, cmd->resp); DEBUGP("Clearing mlbuf\n"); - g->mlbuf[0] = 0; + g->mlbuf_len = 0; } /* remove from list of currently executing cmds */ @@ -382,7 +390,15 @@ g->gfd_uart.when |= GSMD_FD_WRITE; return rc; -} +} + +/* called when the modem asked for a new line of a multiline atcmd */ +static int atcmd_prompt(void *data) +{ + struct gsmd *g = data; + + g->gfd_uart.when |= GSMD_FD_WRITE; +} /* callback to be called if [virtual] UART has some data for us */ static int atcmd_select_cb(int fd, unsigned int what, void *data) @@ -390,6 +406,7 @@ int len, rc; static char rxbuf[1024]; struct gsmd *g = data; + char *cr; if (what & GSMD_FD_READ) { memset(rxbuf, 0, sizeof(rxbuf)); @@ -413,8 +430,12 @@ if ((what & GSMD_FD_WRITE) && g->interpreter_ready) { struct gsmd_atcmd *pos, *pos2; llist_for_each_entry_safe(pos, pos2, &g->pending_atcmds, list) { - len = strlen(pos->buf); - rc = write(fd, pos->buf, strlen(pos->buf)); + cr = strchr(pos->cur, '\n'); + if (cr) + len = cr - pos->cur; + else + len = pos->buflen; + rc = write(fd, pos->cur, len); if (rc == 0) { gsmd_log(GSMD_ERROR, "write returns 0, aborting\n"); break; @@ -423,27 +444,32 @@ fd, rc); return rc; } - if (rc < len) { - gsmd_log(GSMD_FATAL, "short write!!! FIXME!\n"); - exit(3); - } + if (cr && rc == len) + rc ++; /* Skip the \n */ + pos->buflen -= rc; + pos->cur += rc; write(fd, "\r", 1); - /* success: remove from global list of to-be-sent atcmds */ - llist_del(&pos->list); - /* append to global list of executing atcmds */ - llist_add_tail(&pos->list, &g->busy_atcmds); + + if (!pos->buflen) { + /* success: remove from global list of + * to-be-sent atcmds */ + llist_del(&pos->list); + /* append to global list of executing atcmds */ + llist_add_tail(&pos->list, &g->busy_atcmds); /* we only send one cmd at the moment */ - g->gfd_uart.when &= ~GSMD_FD_WRITE; break; + } else { + /* The write was short or the atcmd has more + * lines to send after a "> ". */ + if (!(rc < len)) + break; + } } - } -#if 0 - if (llist_empty(&g->pending_atcmds)) + /* Either pending_atcmds is empty or a command has to wait */ g->gfd_uart.when &= ~GSMD_FD_WRITE; -#endif - + } return 0; } @@ -454,10 +480,10 @@ { int buflen = strlen(cmd); struct gsmd_atcmd *atcmd; - + if (rlen > buflen) buflen = rlen; - + atcmd = talloc_size(__atcmd_ctx, sizeof(*atcmd)+ buflen); if (!atcmd) return NULL; @@ -468,6 +494,7 @@ atcmd->ret = -255; atcmd->buflen = buflen; atcmd->buf[buflen-1] = '\0'; + atcmd->cur = atcmd->buf; atcmd->cb = cb; atcmd->resp = NULL; strncpy(atcmd->buf, cmd, buflen-1); @@ -480,8 +507,9 @@ { DEBUGP("submitting command `%s'\n", cmd->buf); + if (llist_empty(&g->pending_atcmds)) + g->gfd_uart.when |= GSMD_FD_WRITE; llist_add_tail(&cmd->list, &g->pending_atcmds); - g->gfd_uart.when |= GSMD_FD_WRITE; return 0; } @@ -517,9 +545,9 @@ g->llp.cur = g->llp.buf; g->llp.len = sizeof(g->llp.buf); g->llp.cb = &ml_parse; + g->llp.prompt_cb = &atcmd_prompt; g->llp.ctx = g; g->llp.flags = LGSM_ATCMD_F_EXTENDED; return gsmd_register_fd(&g->gfd_uart); -} - +} Index: gsm/src/gsmd/sms_cb.c =================================================================== --- gsm.orig/src/gsmd/sms_cb.c 2007-07-31 13:58:37.000000000 +0200 +++ gsm/src/gsmd/sms_cb.c 2007-07-31 14:23:32.000000000 +0200 @@ -91,9 +91,6 @@ if (!ucmd) return -ENOMEM; - - - ucmd->hdr.version = GSMD_PROTO_VERSION; ucmd->hdr.msg_type = GSMD_MSG_SMS; ucmd->hdr.msg_subtype = GSMD_SMS_GETMSG_STORAGE; @@ -188,14 +185,26 @@ int sms_cb_init(struct gsmd *gsmd) { struct gsmd_atcmd *atcmd; + char buffer[10]; atcmd = atcmd_fill("AT+CSMS=0", NULL, gu, 0); if (!atcmd) return -ENOMEM; atcmd_submit(gsmd, atcmd); - /* Switch into "text mode" (Section 3.2.3) */ - atcdm = atcmd_fill("AT+CMGF=1", 9, &sms_cb_init_cb, gu, 0); + /* If text mode, set the encoding */ + if (gu->gsmd->flags & GSMD_FLAG_SMS_FMT) { + atcmd = atcmd_fill("AT+CSCS=\"IRA\"", 13, NULL, gu, 0); + if (!atcmd) + return -ENOMEM; + atcmd_submit(gsmd, atcmd); + } + + /* Switch into desired mode (Section 3.2.3) */ + snprintf(buffer, sizeof(buffer), "AT+CMGF=%i", + (gu->gsmd->flags & GSMD_FLAG_SMS_FMT) ? + GSMD_SMS_FMT_TEXT : GSMD_SMS_FMT_PDU); + atcmd = atcmd_fill(buffer, strlen(buffer), &sms_cb_init_cb, gu, 0); if (!atcmd) return -ENOMEM; Index: gsm/src/gsmd/usock.c =================================================================== --- gsm.orig/src/gsmd/usock.c 2007-07-31 13:58:37.000000000 +0200 +++ gsm/src/gsmd/usock.c 2007-07-31 14:23:32.000000000 +0200 @@ -75,7 +75,7 @@ ucmd->hdr.version = GSMD_PROTO_VERSION; ucmd->hdr.msg_type = GSMD_MSG_PASSTHROUGH; ucmd->hdr.msg_subtype = GSMD_PASSTHROUGH_RESP; - ucmd->hdr.len = strlen(resp)+1; + ucmd->hdr.len = rlen; ucmd->hdr.id = cmd->id; memcpy(ucmd->buf, resp, ucmd->hdr.len); @@ -100,7 +100,7 @@ static int usock_rcv_event(struct gsmd_user *gu, struct gsmd_msg_hdr *gph, int len) { - u_int32_t *evtmask = (u_int32_t *) ((char *)gph + sizeof(*gph), gph->id); + u_int32_t *evtmask = (u_int32_t *) ((char *)gph + sizeof(*gph)); if (len < sizeof(*gph) + sizeof(u_int32_t)) return -EINVAL; @@ -471,18 +471,15 @@ static int sms_send_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp) { - struct gsmd_user *gu = ctx; + struct gsmd_user *gu = (struct gsmd_user *) ctx; struct gsmd_ucmd *ucmd; - - ucmd = gsmd_ucmd_fill(strlen(resp)+1, GSMD_MSG_SMS, - GSMD_SMS_SEND, 0); + + ucmd = gsmd_ucmd_fill(strlen(resp) + 1, + GSMD_MSG_SMS, GSMD_SMS_SEND, cmd->id); if (!ucmd) return -ENOMEM; - strcpy(ucmd->buf, resp); - usock_cmd_enqueue(ucmd, gu); - return 0; } @@ -520,34 +517,142 @@ return 0; } +int packing_7bit_character(char *src, char *dest) +{ + int i,j = 0; + unsigned char ch1, ch2; + char tmp[2]; + int shift = 0; + + *dest = '\0'; + + for ( i=0; i> shift; + ch2 = src[(i+1)] & 0x7F; + ch2 = ch2 << (7-shift); + + ch1 = ch1 | ch2; + + j = strlen(dest); + sprintf(tmp, "%X", (ch1 >> 4)); + dest[j++] = tmp[0]; + sprintf(tmp, "%X", (ch1 & 0x0F)); + dest[j++] = tmp[0]; + dest[j++] = '\0'; + + shift++; + + if ( 7 == shift ) { + shift = 0; + i++; + } + } + + return 0; +} + +/* Refer to GSM 03.40 subclause 9.2.3.3, for SMS-SUBMIT */ +static int usock_pdu_make_smssubmit(char *dest, struct gsmd_sms_send *src) +{ + u_int8_t header[10 + GSMD_ADDR_MAXLEN]; + int pos = 0, i, coding7bit = 1; + + /* (Should be optional but some modems require it) SMSC Length octet + * is prepended. If omitted or zero, use SMSC stored in the phone. */ + header[pos ++] = 0x00; + + header[pos ++] = + GSMD_SMS_TP_MTI_SUBMIT | + (0 << 2) | /* Reject Duplicates: 0 */ + GSMD_SMS_TP_VPF_NOT_PRESENT | + GSMD_SMS_TP_SRR_NOT_REQUEST | + GSMD_SMS_TP_UDHI_NO_HEADER | + GSMD_SMS_TP_RP_NOT_SET; + + /* TP-Message-Reference - 00 lets the phone set the number itself */ + header[pos ++] = 0x00; + + header[pos ++] = strlen(src->addr.number); + header[pos ++] = src->addr.type; + for (i = 0; src->addr.number[i]; i ++) { + header[pos] = src->addr.number[i ++] - '0'; + if (src->addr.number[i]) + header[pos ++] |= (src->addr.number[i] - '0') << 4; + else { + header[pos ++] |= 0xf0; + break; + } + } + + /* TP-Protocol-Identifier - 00 means implicit */ + header[pos ++] = 0x00; + + /* TP-Data-Coding-Scheme - 00 for 7-bit default alphabet */ + header[pos ++] = coding7bit ? 0x00 : 0x04; + + /* TP-Validity-Period, if present, would go here */ + + header[pos ++] = src->payload.length; + + if (dest) { + for (i = 0; i < pos; i ++) { + sprintf(dest, "%02X", header[i]); + dest += 2; + } + if (coding7bit) + packing_7bit_character(src->payload.data, dest); + else + for (i = 0; i < src->payload.length; i ++) { + sprintf(dest, "%02X", src->payload.data[i]); + dest += 2; + } + } + + if (coding7bit) + return ((src->payload.length * 7 + 7) >> 3) + pos; + else + return src->payload.length + pos; +} + +static const char *gsmd_cmgl_stat[] = { + "REC UNREAD", "REC READ", "STO UNSENT", "STO SENT", "ALL", +}; + static 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 *gs; + struct gsmd_sms_send *gss; struct gsmd_sms_write *gsw; int *stat, *index; int atcmd_len; char buf[1024]; - + switch (gph->msg_subtype) { case GSMD_SMS_LIST: /* FIXME: only support PDU mode!! */ if(len < sizeof(*gph) + sizeof(int)) return -EINVAL; - stat = (int *) ((void *)gph + sizeof(*gph)); + stat = (int *) ((void *)gph + sizeof(*gph)); + if (*stat < 0 || *stat > 4) + return -EINVAL; - sprintf(buf, "%d", *stat); - - atcmd_len = 1 + strlen("AT+CMGL=") + strlen(buf); - cmd = atcmd_fill("AT+CMGL=", atcmd_len, - &sms_list_cb, gu, gph->id); + if (gu->gsmd->flags & GSMD_FLAG_SMS_FMT) + 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); if (!cmd) return -ENOMEM; - sprintf(cmd->buf, "AT+CMGL=%s", buf); break; + case GSMD_SMS_READ: /* FIXME: only support PDU mode!! */ if(len < sizeof(*gph) + sizeof(int)) @@ -563,6 +668,34 @@ return -ENOMEM; sprintf(cmd->buf, "AT+CMGR=%s", buf); break; + + case GSMD_SMS_SEND: + if (len < sizeof(*gph) + sizeof(*gss)) + return -EINVAL; + gss = (struct gsmd_sms_send *) ((void *) gph + sizeof(*gph)); + + if (gu->gsmd->flags & GSMD_FLAG_SMS_FMT) { + atcmd_len = sprintf(buf, "AT+CMGS=\"%s\"\n%.*s", + gss->addr.number, + gss->payload.length, + gss->payload.data); + } else { + atcmd_len = sprintf(buf, "AT+CMGS=%i\n", + usock_pdu_make_smssubmit(NULL, + gss) - 1); + atcmd_len += usock_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); + if (!cmd) + return -ENOMEM; + break; + case GSMD_SMS_WRITE: + gsmd_log(GSMD_DEBUG, "sms write\n"); + break; #if 0 case GSMD_SMS_SEND: /* FIXME: only support PDU mode!! */ @@ -610,8 +743,8 @@ default: return -EINVAL; } - - gsmd_log(GSMD_DEBUG, "%s\n", cmd->buf); + + gsmd_log(GSMD_DEBUG, "%s\n", cmd ? cmd->buf : 0); if (cmd) return atcmd_submit(gu->gsmd, cmd); else @@ -867,7 +1000,7 @@ [GSMD_MSG_PIN] = &usock_rcv_pin, [GSMD_MSG_PHONE] = &usock_rcv_phone, [GSMD_MSG_NETWORK] = &usock_rcv_network, - [GSMD_MSG_SMS] = &usock_rcv_sms, + [GSMD_MSG_SMS] = &usock_rcv_sms, //[GSMD_MSG_PHONEBOOK] = &usock_rcv_phonebook, }; Index: gsm/src/gsmd/vendor_ti.c =================================================================== --- gsm.orig/src/gsmd/vendor_ti.c 2007-07-31 13:58:37.000000000 +0200 +++ gsm/src/gsmd/vendor_ti.c 2007-07-31 14:23:32.000000000 +0200 @@ -277,7 +277,7 @@ static int ticalypso_initsettings(struct gsmd *g) { - int rc; + int rc = 0; struct gsmd_atcmd *cmd; /* use +CTZR: to report time zone changes */ Index: gsm/src/libgsmd/libgsmd_sms.c =================================================================== --- gsm.orig/src/libgsmd/libgsmd_sms.c 2007-07-31 13:58:37.000000000 +0200 +++ gsm/src/libgsmd/libgsmd_sms.c 2007-07-31 14:23:32.000000000 +0200 @@ -83,19 +83,33 @@ return 0; } -int lgsmd_sms_send(struct lgsm_handle *lh, - const struct lgsm_sms *sms) +#ifndef MIN +# define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +int lgsmd_sms_send(struct lgsm_handle *lh, + const struct lgsm_sms *sms) { /* FIXME: only support PDU mode */ struct gsmd_msg_hdr *gmh; - struct gsmd_sms *gs; + struct gsmd_sms_send *gss; int rc; gmh = lgsm_gmh_fill(GSMD_MSG_SMS, - GSMD_SMS_SEND, sizeof(*gs)); + GSMD_SMS_SEND, sizeof(*gss)); if (!gmh) return -ENOMEM; - gs = (struct gsmd_sms *) gmh->data; + gss = (struct gsmd_sms_send *) gmh->data; + + gss->addr.type = + GSMD_TOA_NPI_ISDN | + GSMD_TOA_TON_UNKNOWN | + GSMD_TOA_RESERVED; + strncpy(gss->addr.number, sms->addr, sizeof(gss->addr.number)); + + gss->payload.length = + MIN(strlen(sms->data), sizeof(gss->payload.data)); + memcpy(gss->payload.data, sms->data, gss->payload.length); rc = lgsm_send(lh, gmh); if (rc < gmh->len + sizeof(*gmh)) { @@ -108,7 +122,7 @@ return 0; } -int lgsmd_sms_write(struct lgsm_handle *lh, +int lgsmd_sms_write(struct lgsm_handle *lh, const struct lgsm_sms_write *sms_write) { /* FIXME: only support PDU mode */