summaryrefslogtreecommitdiff
path: root/src/gsmd
diff options
context:
space:
mode:
authorlaforge <laforge@99fdad57-331a-0410-800a-d7fa5415bdb3>2007-08-16 04:18:54 +0000
committerlaforge <laforge@99fdad57-331a-0410-800a-d7fa5415bdb3>2007-08-16 04:18:54 +0000
commit66ddffab0a8fe2f517d83859ffb20467acd0cbe6 (patch)
treef207a43dddc8205763309e8b9b3bb5043f96647e /src/gsmd
parent00361c2946aef3975e302d5a5957ae239da21de8 (diff)
From 294d27e78680d497da22e3a8ad679f50d1ba29e5 Mon Sep 17 00:00:00 2001
From: Andrzej Zaborowski <balrog@zabor.org> Date: Wed, 11 Jul 2007 16:11:10 +0200 Subject: [PATCH] SMS support in gsmd and in libgsmd. This adds the proper support for sms related calls in libgsmd and their implementation in gsmd. I assumed that conversion between data coding schemes is to be done on the client side because the {packing,unpacking}* calls were exported. TEXT mode support is non-functional, but the code only has to be filled in the right places to make it work, if it is ever needed. I had been lucky to be able to test with the different kinds of messages with exotic formats because I just got a bunch of network messages today (urging to top-up the credit). I tried to not modify the libgsmd api, although I would prefer to have a totally different api, possibly with synchronous calls that just return the result of an operation, for a exmaple a whole list of messages, rather than the client waiting for an unknown number of events each with one message. git-svn-id: http://svn.openmoko.org/trunk/src/target/gsm@2710 99fdad57-331a-0410-800a-d7fa5415bdb3
Diffstat (limited to 'src/gsmd')
-rw-r--r--src/gsmd/Makefile.am3
-rw-r--r--src/gsmd/sms_cb.c17
-rw-r--r--src/gsmd/sms_pdu.c259
-rw-r--r--src/gsmd/usock.c260
4 files changed, 455 insertions, 84 deletions
diff --git a/src/gsmd/Makefile.am b/src/gsmd/Makefile.am
index 49d96e3..6b25812 100644
--- a/src/gsmd/Makefile.am
+++ b/src/gsmd/Makefile.am
@@ -6,7 +6,8 @@ sbin_PROGRAMS = gsmd
gsmd_CFLAGS = -D PLUGINDIR=\"$(plugindir)\"
gsmd_SOURCES = gsmd.c atcmd.c select.c machine.c vendor.c unsolicited.c log.c \
- usock.c talloc.c timer.c operator_cache.c ext_response.c
+ usock.c talloc.c timer.c operator_cache.c ext_response.c \
+ sms_pdu.c
gsmd_LDADD = -ldl
gsmd_LDFLAGS = -Wl,--export-dynamic
diff --git a/src/gsmd/sms_cb.c b/src/gsmd/sms_cb.c
index 330317c..22bf613 100644
--- a/src/gsmd/sms_cb.c
+++ b/src/gsmd/sms_cb.c
@@ -184,18 +184,29 @@ static const struct gsmd_unsolocit gsm0705_unsolicit[] = {
{ "+CDS", &cds_parse }, /* SMS Status Index (stored in ME/TA) */
};
-
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_TEXT) {
+ 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_TEXT) ?
+ GSMD_SMS_FMT_TEXT : GSMD_SMS_FMT_PDU);
+ atcmd = atcmd_fill(buffer, strlen(buffer) + 1, NULL, gu, 0);
if (!atcmd)
return -ENOMEM;
diff --git a/src/gsmd/sms_pdu.c b/src/gsmd/sms_pdu.c
new file mode 100644
index 0000000..1ec3202
--- /dev/null
+++ b/src/gsmd/sms_pdu.c
@@ -0,0 +1,259 @@
+/* Convert raw PDUs to and from gsmd format.
+ *
+ * Copyright (C) 2007 OpenMoko, Inc.
+ * Written by Andrzej Zaborowski <andrew@openedhand.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "gsmd.h"
+
+#include <gsmd/gsmd.h>
+#include <gsmd/usock.h>
+
+static int sms_number_bytelen(u_int8_t type, u_int8_t len)
+{
+ switch (type & __GSMD_TOA_TON_MASK) {
+ case GSMD_TOA_TON_ALPHANUMERIC:
+ return (len + 1) >> 1;
+ default:
+ return (len + 1) >> 1;
+ }
+}
+
+static int sms_data_bytelen(u_int8_t data_coding_scheme, u_int8_t len)
+{
+ switch (data_coding_scheme) { /* Get length in bytes */
+ case ALPHABET_DEFAULT:
+ return (len * 7 + 7) >> 3;
+ case ALPHABET_8BIT:
+ return len;
+ case ALPHABET_UCS2:
+ return len * 2;
+ }
+ return 0;
+}
+
+static int sms_address2ascii(struct gsmd_addr *dst, u_int8_t *src)
+{
+ int i;
+
+ if (src[0] > GSMD_ADDR_MAXLEN)
+ return 1;
+
+ /* The Type-of-address field */
+ dst->type = src[1];
+
+ switch (dst->type & __GSMD_TOA_TON_MASK) {
+ case GSMD_TOA_TON_ALPHANUMERIC:
+ for (i = 0; ((i * 7 + 3) >> 2) < src[0]; i ++)
+ dst->number[i] =
+ ((src[2 + ((i * 7 + 7) >> 3)] <<
+ (7 - ((i * 7 + 7) & 7))) |
+ (src[2 + ((i * 7) >> 3)] >>
+ ((i * 7) & 7))) & 0x7f;
+ break;
+ default:
+ for (i = 0; i < src[0]; i ++)
+ dst->number[i] = '0' +
+ ((src[2 + (i >> 1)] >> ((i << 2) & 4)) & 0xf);
+ }
+ dst->number[i] = 0;
+
+ return 0;
+}
+
+int sms_pdu_to_msg(struct gsmd_sms_list *dst,
+ u_int8_t *src, int pdulen, int len)
+{
+ int i, vpf;
+ if (len < 1 || len < 1 + src[0] + pdulen || pdulen < 1)
+ return 1;
+
+ /* Skip SMSC number and its Type-of-address */
+ len -= 1 + src[0];
+ src += 1 + src[0];
+
+ /* TP-UDHI */
+ dst->payload.has_header = !!(src[0] & GSMD_SMS_TP_UDHI_WITH_HEADER);
+
+ /* TP-VPF */
+ vpf = (src[0] >> 3) & 3;
+
+ /* TP-MTI */
+ switch (src[0] & 3) {
+ case GSMD_SMS_TP_MTI_DELIVER:
+ if (len < 3)
+ return 1;
+ i = sms_number_bytelen(src[2], src[1]);
+ if (len < 13 + i)
+ return 1;
+
+ if (sms_address2ascii(&dst->addr, src + 1))
+ return 1;
+
+ len -= 3 + i;
+ src += 3 + i;
+
+ /* TP-DCS */
+ switch (src[1] >> 4) {
+ case 0x0 ... 3: /* General Data Coding indication */
+ case 0xc: /* Message Waiting indication: Discard */
+ /* FIXME: support compressed data */
+ dst->payload.coding_scheme = src[1] & 0xc;
+ break;
+ case 0xd: /* Message Waiting indication: Store */
+ dst->payload.coding_scheme = ALPHABET_DEFAULT;
+ break;
+ case 0xe: /* Message Waiting indication: Store */
+ dst->payload.coding_scheme = ALPHABET_UCS2;
+ break;
+ case 0xf: /* Data coding/message class */
+ dst->payload.coding_scheme = (src[1] & 4) ?
+ ALPHABET_8BIT : ALPHABET_DEFAULT;
+ break;
+ default:
+ return 1;
+ }
+
+ /* TP-SCTS */
+ memcpy(dst->time_stamp, src + 2, 7);
+
+ /* Skip TP-PID */
+ len -= 9;
+ src += 9;
+ break;
+ case GSMD_SMS_TP_MTI_SUBMIT:
+ if (len < 4)
+ return 1;
+ i = sms_number_bytelen(src[3], src[2]);
+ if (len < 8 + i)
+ return 1;
+
+ if (sms_address2ascii(&dst->addr, src + 2))
+ return 1;
+
+ len -= 4 + i;
+ src += 4 + i;
+
+ /* TP-DCS */
+ switch (src[1] >> 4) {
+ case 0x0 ... 3: /* General Data Coding indication */
+ case 0xc: /* Message Waiting indication: Discard */
+ /* FIXME: compressed data */
+ dst->payload.coding_scheme = src[1] & 0xc;
+ break;
+ case 0xd: /* Message Waiting indication: Store */
+ dst->payload.coding_scheme = ALPHABET_DEFAULT;
+ break;
+ case 0xe: /* Message Waiting indication: Store */
+ dst->payload.coding_scheme = ALPHABET_UCS2;
+ break;
+ case 0xf: /* Data coding/message class */
+ dst->payload.coding_scheme = (src[1] & 4) ?
+ ALPHABET_8BIT : ALPHABET_DEFAULT;
+ break;
+ default:
+ return 1;
+ }
+
+ /* Skip TP-PID and TP-Validity-Period */
+ len -= vpf ? 3 : 2;
+ src += vpf ? 3 : 2;
+
+ memset(dst->time_stamp, 0, 7);
+ break;
+ default:
+ /* Unknown PDU type */
+ return 1;
+ }
+
+ /* TP-UDL */
+ dst->payload.length = src[0];
+ i = sms_data_bytelen(dst->payload.coding_scheme, src[0]);
+
+ /* TP-UD */
+ if (len < 1 + i || i > GSMD_SMS_DATA_MAXLEN)
+ return 1;
+ memcpy(dst->payload.data, src + 1, i);
+ dst->payload.data[i] = 0;
+
+ return 0;
+}
+
+/* Refer to GSM 03.40 subclause 9.2.3.3, for SMS-SUBMIT */
+int sms_pdu_make_smssubmit(char *dest, struct gsmd_sms_submit *src)
+{
+ /* FIXME: ALPHANUMERIC encoded addresses can be longer than 13B */
+ u_int8_t header[15 + GSMD_ADDR_MAXLEN];
+ int pos = 0, i, len;
+
+ /* SMSC Length octet. If omitted or zero, use SMSC stored in the
+ * phone. One some phones this can/has to be omitted. */
+ 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 |
+ (src->payload.has_header ? GSMD_SMS_TP_UDHI_WITH_HEADER :
+ 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 */
+ header[pos ++] = src->payload.coding_scheme;
+
+ /* TP-Validity-Period, if present, would go here */
+
+ header[pos ++] = src->payload.length;
+ len = sms_data_bytelen(src->payload.coding_scheme,
+ src->payload.length);
+
+ if (dest) {
+ for (i = 0; i < pos; i ++) {
+ sprintf(dest, "%02X", header[i]);
+ dest += 2;
+ }
+ for (i = 0; i < len; i ++) {
+ sprintf(dest, "%02X", src->payload.data[i]);
+ dest += 2;
+ }
+ }
+
+ return pos + len;
+}
diff --git a/src/gsmd/usock.c b/src/gsmd/usock.c
index db073a4..be8aee8 100644
--- a/src/gsmd/usock.c
+++ b/src/gsmd/usock.c
@@ -434,17 +434,46 @@ static int usock_rcv_network(struct gsmd_user *gu, struct gsmd_msg_hdr *gph,
static int sms_list_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_sms_list msg;
+ int i, idx, stat, len, cr;
+ u_int8_t pdu[180];
+
+ if (cmd->ret && cmd->ret != -255)
+ return 0;
- ucmd = gsmd_ucmd_fill(strlen(resp)+1, GSMD_MSG_SMS,
- GSMD_SMS_LIST, 0);
+ /* FIXME: TEXT mode */
+ if (
+ sscanf(resp, "+CMGL: %i,%i,,%i\n%n",
+ &idx, &stat, &len, &cr) < 3 &&
+ sscanf(resp, "+CMGL: %i,%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 < 180; 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));
- /* FIXME: implementation */
- strcpy(ucmd->buf, resp);
-
usock_cmd_enqueue(ucmd, gu);
return 0;
@@ -452,17 +481,45 @@ static int sms_list_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp)
static int sms_read_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_sms_list msg;
+ int i, stat, len, cr;
+ u_int8_t pdu[180];
- /* FIXME: implementation */
+ 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 < 180; 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(strlen(resp)+1, GSMD_MSG_SMS,
- GSMD_SMS_READ, 0);
+ ucmd = gsmd_ucmd_fill(sizeof(msg), GSMD_MSG_SMS,
+ GSMD_SMS_READ, cmd->id);
if (!ucmd)
return -ENOMEM;
-
- strcpy(ucmd->buf, resp);
+ memcpy(ucmd->buf, &msg, sizeof(msg));
usock_cmd_enqueue(ucmd, gu);
@@ -471,15 +528,21 @@ static int sms_read_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp)
static int sms_send_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp)
{
- struct gsmd_user *gu = ctx;
- struct gsmd_ucmd *ucmd;
-
- ucmd = gsmd_ucmd_fill(strlen(resp)+1, GSMD_MSG_SMS,
- GSMD_SMS_SEND, 0);
+ struct gsmd_user *gu = ctx;
+ struct gsmd_ucmd *ucmd;
+ int msgref;
+
+ if (cmd->ret == 0) {
+ 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;
-
- strcpy(ucmd->buf, resp);
+ *(int *) ucmd->buf = msgref;
usock_cmd_enqueue(ucmd, gu);
@@ -488,15 +551,21 @@ static int sms_send_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp)
static int sms_write_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp)
{
- struct gsmd_user *gu = ctx;
- struct gsmd_ucmd *ucmd;
-
- ucmd = gsmd_ucmd_fill(strlen(resp)+1, GSMD_MSG_SMS,
- GSMD_SMS_WRITE, 0);
- if (!ucmd)
- return -ENOMEM;
+ struct gsmd_user *gu = ctx;
+ struct gsmd_ucmd *ucmd;
+ int result;
- strcpy(ucmd->buf, resp);
+ 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);
@@ -505,113 +574,144 @@ static int sms_write_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp)
static int sms_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;
+ int *result;
- ucmd = gsmd_ucmd_fill(strlen(resp)+1, GSMD_MSG_SMS,
- GSMD_SMS_DELETE, 0);
+ ucmd = gsmd_ucmd_fill(sizeof(int), GSMD_MSG_SMS,
+ GSMD_SMS_DELETE, cmd->id);
if (!ucmd)
return -ENOMEM;
- strcpy(ucmd->buf, resp);
+ result = (int *) ucmd->buf;
+ *result = cmd->ret;
usock_cmd_enqueue(ucmd, gu);
return 0;
}
+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_submit *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);
+ /* FIXME: should we set <mem1> to "SM"/"ME" before that? */
+ 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);
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))
return -EINVAL;
index = (int *) ((void *)gph + sizeof(*gph));
- sprintf(buf, "%d", *index);
-
- atcmd_len = 1 + strlen("AT+CMGR=") + strlen(buf);
- cmd = atcmd_fill("AT+CMGR=", atcmd_len,
+ /* FIXME: should we set <mem1> to "SM"/"ME" before that? */
+ atcmd_len = sprintf(buf, "AT+CMGR=%i", *index);
+
+ cmd = atcmd_fill(buf, atcmd_len + 1,
&sms_read_cb, gu, gph->id);
if (!cmd)
return -ENOMEM;
- sprintf(cmd->buf, "AT+CMGR=%s", buf);
break;
-#if 0
+
case GSMD_SMS_SEND:
- /* FIXME: only support PDU mode!! */
- if(len < sizeof(*gph) + sizeof(*gs))
+ if (len < sizeof(*gph) + sizeof(*gss))
return -EINVAL;
- gs = (struct gsmd_sms *) ((void *)gph + sizeof(*gph));
+ 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;
- sprintf(buf, "%d", *index);
-
- atcmd_len = 1 + strlen("AT+CMGR=") + 1;
- cmd = atcmd_fill("AT+CMGR=", atcmd_len,
- &sms_send_cb, gu, gph->id);
- if (!cmd)GSMD_SMS_WRITE
+ cmd = atcmd_fill(buf, atcmd_len, &sms_send_cb, gu, gph->id);
+ if (!cmd)
return -ENOMEM;
- sprintf(cmd->buf, "AT+CMGR=%d", index);
break;
+
case GSMD_SMS_WRITE:
- /* FIXME: only support PDU mode!! */
- if(len < sizeof(*gph) + sizeof(*gsw))
+ if (len < sizeof(*gph) + sizeof(*gsw))
return -EINVAL;
- &index = (int *) ((void *)gph + sizeof(*gph));
-
- atcmd_len = 1 + strlen("AT+CMGR=") + 1;
- cmd = atcmd_fill("AT+CMGR=", atcmd_len,
- &sms_write_cb, gu, gph->id);
+ gsw = (struct gsmd_sms_write *) ((void *) gph + sizeof(*gph));
+ if (gsw->stat > 4)
+ return -EINVAL;
+
+ /* FIXME: should we set <mem2> to "SM"/"ME" before that? */
+ 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);
if (!cmd)
return -ENOMEM;
- sprintf(cmd->buf, "AT+CMGR=%d", index);
break;
-#endif
- case GSMD_SMS_DELETE:
+
+ case GSMD_SMS_DELETE:
if(len < sizeof(*gph) + sizeof(*gsd))
return -EINVAL;
gsd = (struct gsmd_sms_delete *) ((void *)gph + sizeof(*gph));
-
- sprintf(buf, "%d,%d", gsd->index, gsd->delflg);
-
- atcmd_len = 1 + strlen("AT+CMGR=") + strlen(buf);
- cmd = atcmd_fill("AT+CMGD=", atcmd_len,
+
+ 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);
if (!cmd)
return -ENOMEM;
- sprintf(cmd->buf, "AT+CMGD=%s", buf);
break;
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 +967,7 @@ static usock_msg_handler *pcmd_type_handlers[__NUM_GSMD_MSGS] = {
[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,
};
personal git repositories of Harald Welte. Your mileage may vary