summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/gsmd/sms.h5
-rw-r--r--include/gsmd/usock.h42
-rw-r--r--include/libgsmd/sms.h1
-rw-r--r--src/gsmd/sms_cb.c42
-rw-r--r--src/gsmd/sms_pdu.c29
-rw-r--r--src/libgsmd/libgsmd_sms.c14
-rw-r--r--src/util/event.c100
7 files changed, 202 insertions, 31 deletions
diff --git a/include/gsmd/sms.h b/include/gsmd/sms.h
index b48ce5d..c5ee0d8 100644
--- a/include/gsmd/sms.h
+++ b/include/gsmd/sms.h
@@ -8,10 +8,13 @@
int sms_cb_init(struct gsmd *gsmd);
int sms_cb_network_init(struct gsmd *gsmd);
-#define MAX_PDU_SIZE 180
+#define SMS_MAX_PDU_SIZE 180
+#define CBM_MAX_PDU_SIZE 88
+#define CBM_MAX_PDU_PAGES 15
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);
+int cbs_pdu_to_msg(struct gsmd_cbm *dst, u_int8_t *src, int pdulen, int len);
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);
diff --git a/include/gsmd/usock.h b/include/gsmd/usock.h
index 18ffa5e..ce5c25e 100644
--- a/include/gsmd/usock.h
+++ b/include/gsmd/usock.h
@@ -365,6 +365,48 @@ struct gsmd_sms_storage {
struct __gsmd_sms_storage mem[3];
} __attribute__ ((packed));
+/* Refer to GSM 03.41 subclause 9.3.1 - note: this indicates display mode too */
+enum gsmd_geographical_scope {
+ GSMD_SCOPE_CELL_WIDE_OPER = 0,
+ GSMD_SCOPE_PLMN_WIDE,
+ GSMD_SCOPE_LOC_AREA_WIDE,
+ GSMD_SCOPE_CELL_WIDE,
+};
+
+enum gsmd_language {
+ GSMD_LANG_GERMAN = 0,
+ GSMD_LANG_ENGLISH,
+ GSMD_LANG_ITALIAN,
+ GSMD_LANG_FRENCH,
+ GSMD_LANG_SPANISH,
+ GSMD_LANG_DUTCH,
+ GSMD_LANG_SWEDISH,
+ GSMD_LANG_DANISH,
+ GSMD_LANG_PORTUGUESE,
+ GSMD_LANG_FINNISH,
+ GSMD_LANG_NORWEGIAN,
+ GSMD_LANG_GREEK,
+ GSMD_LANG_TURKISH,
+ GSMD_LANG_HUNGARIAN,
+ GSMD_LANG_POLISH,
+ GSMD_LANG_UNSPECIFIED,
+};
+
+/* Refer to GSM 03.41 subclause 9.3 */
+struct gsmd_cbm {
+ struct {
+ enum gsmd_geographical_scope scope;
+ int msg_code;
+ int update_num;
+ } serial;
+ u_int16_t msg_id;
+ enum gsmd_language language;
+ u_int8_t coding_scheme;
+ int pages;
+ int page;
+ u_int8_t data[82];
+};
+
/* Refer to GSM 07.07 subclause 8.12 */
struct gsmd_phonebook_readrg {
u_int8_t index1;
diff --git a/include/libgsmd/sms.h b/include/libgsmd/sms.h
index 69363e7..3ada62d 100644
--- a/include/libgsmd/sms.h
+++ b/include/libgsmd/sms.h
@@ -90,6 +90,7 @@ extern int packing_7bit_character(const char *src, struct lgsm_sms *dest);
/* Packing of 7-bit characters, refer to GSM 03.38 subclause 6.1.2.1.1 */
extern int unpacking_7bit_character(const struct gsmd_sms *src, char *dest);
+extern int cbm_unpacking_7bit_character(const char *src, char *dest);
/* Refer to 3GPP TS 11.11 Annex B */
extern int packing_UCS2_80(char *src, char *dest);
diff --git a/src/gsmd/sms_cb.c b/src/gsmd/sms_cb.c
index 1ae337e..0ffe563 100644
--- a/src/gsmd/sms_cb.c
+++ b/src/gsmd/sms_cb.c
@@ -67,7 +67,7 @@ static int sms_list_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp)
struct gsmd_ucmd *ucmd;
struct gsmd_sms_list msg;
int i, idx, stat, len, cr;
- u_int8_t pdu[MAX_PDU_SIZE];
+ u_int8_t pdu[SMS_MAX_PDU_SIZE];
if (cmd->ret && cmd->ret != -255)
return 0;
@@ -86,7 +86,7 @@ static int sms_list_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp)
msg.stat = stat;
msg.is_last = (cmd->ret == 0);
for (i = 0; resp[cr] >= '0' && resp[cr + 1] >= '0' &&
- i < MAX_PDU_SIZE; i ++) {
+ i < SMS_MAX_PDU_SIZE; i ++) {
if (sscanf(resp + cr, "%2hhX", &pdu[i]) < 1) {
gsmd_log(GSMD_DEBUG, "malformed input (%i)\n", i);
return -EINVAL;
@@ -115,7 +115,7 @@ static int sms_read_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp)
struct gsmd_ucmd *ucmd;
struct gsmd_sms_list msg;
int i, stat, len, cr;
- u_int8_t pdu[MAX_PDU_SIZE];
+ u_int8_t pdu[SMS_MAX_PDU_SIZE];
if (cmd->ret)
return 0;
@@ -134,7 +134,7 @@ static int sms_read_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp)
msg.stat = stat;
msg.is_last = 1;
for (i = 0; resp[cr] >= '0' && resp[cr + 1] >= '0' &&
- i < MAX_PDU_SIZE; i ++) {
+ i < SMS_MAX_PDU_SIZE; i ++) {
if (sscanf(resp + cr, "%2hhX", &pdu[i]) < 1) {
gsmd_log(GSMD_DEBUG, "malformed input (%i)\n", i);
return -EINVAL;
@@ -475,7 +475,7 @@ static int cmti_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[MAX_PDU_SIZE];
+ u_int8_t pdu[SMS_MAX_PDU_SIZE];
const char *comma = strchr(param, ',');
char *cr;
int i;
@@ -502,7 +502,8 @@ static int cmt_parse(char *buf, int len, const char *param, struct gsmd *gsmd)
}
cr ++;
- for (i = 0; cr[0] >= '0' && cr[1] >= '0' && i < MAX_PDU_SIZE; i ++) {
+ for (i = 0; cr[0] >= '0' && cr[1] >= '0' && i < SMS_MAX_PDU_SIZE;
+ i ++) {
if (sscanf(cr, "%2hhX", &pdu[i]) < 1) {
gsmd_log(GSMD_DEBUG, "malformed input (%i)\n", i);
talloc_free(ucmd);
@@ -531,11 +532,6 @@ static int cbmi_parse(char *buf, int len, const char *param, struct gsmd *gsmd)
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);
-
aux = (struct gsmd_evt_auxdata *) ucmd->buf;
if (sscanf(param, "\"%2[A-Z]\",%i", memstr, &aux->u.cbm.index) < 2) {
talloc_free(ucmd);
@@ -551,20 +547,20 @@ static int cbmi_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[MAX_PDU_SIZE];
+ u_int8_t pdu[CBM_MAX_PDU_SIZE];
char *cr;
int i;
struct gsmd_evt_auxdata *aux;
- struct gsmd_sms_list *msg;
+ struct gsmd_cbm *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));
+ sizeof(struct gsmd_cbm));
if (!ucmd)
return -ENOMEM;
aux = (struct gsmd_evt_auxdata *) ucmd->buf;
- msg = (struct gsmd_sms_list *) aux->data;
+ msg = (struct gsmd_cbm *) aux->data;
len = strtoul(param, &cr, 10);
if (cr[0] != '\n') {
@@ -573,7 +569,8 @@ static int cbm_parse(char *buf, int len, const char *param, struct gsmd *gsmd)
}
cr ++;
- for (i = 0; cr[0] >= '0' && cr[1] >= '0' && i < MAX_PDU_SIZE; i ++) {
+ for (i = 0; cr[0] >= '0' && cr[1] >= '0' && i < CBM_MAX_PDU_SIZE;
+ i ++) {
if (sscanf(cr, "%2hhX", &pdu[i]) < 1) {
gsmd_log(GSMD_DEBUG, "malformed input (%i)\n", i);
talloc_free(ucmd);
@@ -583,7 +580,7 @@ static int cbm_parse(char *buf, int len, const char *param, struct gsmd *gsmd)
}
aux->u.cbm.inlined = 1;
- if (sms_pdu_to_msg(msg, pdu, len, i)) {
+ if (cbs_pdu_to_msg(msg, pdu, len, i)) {
gsmd_log(GSMD_DEBUG, "malformed PDU\n");
talloc_free(ucmd);
return -EINVAL;
@@ -617,7 +614,7 @@ static int cdsi_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[MAX_PDU_SIZE];
+ u_int8_t pdu[SMS_MAX_PDU_SIZE];
char *cr;
int i;
struct gsmd_evt_auxdata *aux;
@@ -639,7 +636,8 @@ static int cds_parse(char *buf, int len, const char *param, struct gsmd *gsmd)
}
cr ++;
- for (i = 0; cr[0] >= '0' && cr[1] >= '0' && i < MAX_PDU_SIZE; i ++) {
+ for (i = 0; cr[0] >= '0' && cr[1] >= '0' && i < SMS_MAX_PDU_SIZE;
+ i ++) {
if (sscanf(cr, "%2hhX", &pdu[i]) < 1) {
gsmd_log(GSMD_DEBUG, "malformed input (%i)\n", i);
talloc_free(ucmd);
@@ -714,11 +712,5 @@ int sms_cb_network_init(struct gsmd *gsmd)
*/
ret |= gsmd_simplecmd(gsmd, "AT+CNMI=2,1,2,1,0");
- /* Store into ME/TA and notify */
- ret |= gsmd_simplecmd(gsmd, "AT+CSBS=1");
-
- /* Store into ME/TA and notify */
- ret |= gsmd_simplecmd(gsmd, "AT+CSDS=2");
-
return ret;
}
diff --git a/src/gsmd/sms_pdu.c b/src/gsmd/sms_pdu.c
index c9b9327..665fdcb 100644
--- a/src/gsmd/sms_pdu.c
+++ b/src/gsmd/sms_pdu.c
@@ -26,6 +26,7 @@
#include <gsmd/gsmd.h>
#include <gsmd/usock.h>
+#include <gsmd/sms.h>
static int sms_number_bytelen(u_int8_t type, u_int8_t len)
{
@@ -50,7 +51,7 @@ static int sms_data_bytelen(u_int8_t data_coding_scheme, u_int8_t len)
return 0;
}
-static int sms_address2ascii(struct gsmd_addr *dst, u_int8_t *src)
+static int sms_address2ascii(struct gsmd_addr *dst, const u_int8_t *src)
{
int i;
@@ -80,7 +81,7 @@ static int sms_address2ascii(struct gsmd_addr *dst, u_int8_t *src)
}
int sms_pdu_to_msg(struct gsmd_sms_list *dst,
- u_int8_t *src, int pdulen, int len)
+ const u_int8_t *src, int pdulen, int len)
{
int i, vpf;
if (len < 1 || len < 1 + src[0] + pdulen || pdulen < 1)
@@ -200,7 +201,7 @@ int sms_pdu_to_msg(struct gsmd_sms_list *dst,
}
/* 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)
+int sms_pdu_make_smssubmit(char *dest, const struct gsmd_sms_submit *src)
{
/* FIXME: ALPHANUMERIC encoded addresses can be longer than 13B */
u_int8_t header[15 + GSMD_ADDR_MAXLEN];
@@ -259,3 +260,25 @@ int sms_pdu_make_smssubmit(char *dest, struct gsmd_sms_submit *src)
return pos + len;
}
+
+/* Refer to GSM 03.41 subclause 9.3 */
+int cbs_pdu_to_msg(struct gsmd_cbm *dst, u_int8_t *src, int pdulen, int len)
+{
+ if (len != pdulen || len != CBM_MAX_PDU_SIZE)
+ return 1;
+
+ dst->serial.scope = (src[0] >> 6) & 3;
+ dst->serial.msg_code = ((src[0] << 4) | (src[1] >> 4)) & 0x3ff;
+ dst->serial.update_num = src[1] & 0xf;
+
+ dst->msg_id = (src[2] << 8) | src[3];
+
+ dst->language = src[4] & 0xf;
+ dst->coding_scheme = ((src[4] >> 4) & 3) << 2;
+
+ dst->pages = src[5] & 0xf;
+ dst->page = src[5] >> 4;
+
+ memcpy(dst->data, src + 6, len - 6);
+ return 0;
+}
diff --git a/src/libgsmd/libgsmd_sms.c b/src/libgsmd/libgsmd_sms.c
index 72723c0..22d7dbf 100644
--- a/src/libgsmd/libgsmd_sms.c
+++ b/src/libgsmd/libgsmd_sms.c
@@ -283,6 +283,20 @@ int unpacking_7bit_character(const struct gsmd_sms *src, char *dest)
return i;
}
+int cbm_unpacking_7bit_character(const char *src, char *dest)
+{
+ int i;
+ u_int8_t ch = 1;
+
+ for (i = 0; i < 93 && ch; i ++)
+ *(dest ++) = ch =
+ ((src[(i * 7 + 7) >> 3] << (7 - ((i * 7 + 7) & 7))) |
+ (src[(i * 7) >> 3] >> ((i * 7) & 7))) & 0x7f;
+ *dest = '\0';
+
+ return i;
+}
+
/* Refer to 3GPP TS 11.11 Annex B */
int packing_UCS2_80(char *src, char *dest)
{
diff --git a/src/util/event.c b/src/util/event.c
index f98c7da..a206bbc 100644
--- a/src/util/event.c
+++ b/src/util/event.c
@@ -34,10 +34,104 @@ static int incall_handler(struct lgsm_handle *lh, int evt, struct gsmd_evt_auxda
return 0;
}
-static int insms_handler(struct lgsm_handle *lh, int evt, struct gsmd_evt_auxdata *aux)
+static int insms_handler(struct lgsm_handle *lh, int evt,
+ struct gsmd_evt_auxdata *aux)
{
- printf("EVENT: Incoming SMS stored at location %i\n", aux->u.sms.index);
+ struct gsmd_sms_list *sms;
+ char payload[GSMD_SMS_DATA_MAXLEN];
+ if (aux->u.sms.inlined) {
+ sms = (struct gsmd_sms_list *) aux->data;
+ printf("EVENT: Incoming SMS from/to %s%s, at %i%i-%i%i-%i%i "
+ "%i%i:%i%i:%i%i, GMT%c%i\n",
+ ((sms->addr.type & __GSMD_TOA_TON_MASK) ==
+ GSMD_TOA_TON_INTERNATIONAL) ? "+" : "",
+ sms->addr.number,
+ sms->time_stamp[0] & 0xf,
+ sms->time_stamp[0] >> 4,
+ sms->time_stamp[1] & 0xf,
+ sms->time_stamp[1] >> 4,
+ sms->time_stamp[2] & 0xf,
+ sms->time_stamp[2] >> 4,
+ sms->time_stamp[3] & 0xf,
+ sms->time_stamp[3] >> 4,
+ sms->time_stamp[4] & 0xf,
+ sms->time_stamp[4] >> 4,
+ sms->time_stamp[5] & 0xf,
+ sms->time_stamp[5] >> 4,
+ (sms->time_stamp[6] & 8) ? '-' : '+',
+ (((sms->time_stamp[6] << 4) |
+ (sms->time_stamp[6] >> 4)) & 0x3f) >> 2);
+ if (sms->payload.coding_scheme == ALPHABET_DEFAULT) {
+ unpacking_7bit_character(&sms->payload, payload);
+ printf("\"%s\"\n", payload);
+ } else if (sms->payload.coding_scheme == ALPHABET_8BIT)
+ printf("8-bit encoded data\n");
+ else if (sms->payload.coding_scheme == ALPHABET_UCS2)
+ printf("Unicode-16 encoded text\n");
+ } else
+ printf("EVENT: Incoming SMS stored at location %i\n",
+ aux->u.sms.index);
+ return 0;
+}
+
+static int incbm_handler(struct lgsm_handle *lh, int evt,
+ struct gsmd_evt_auxdata *aux)
+{
+ struct gsmd_cbm *msg;
+ char payload[95];
+ static const char *scope_name[] = {
+ [GSMD_SCOPE_CELL_WIDE_OPER] = "immediate-display cell",
+ [GSMD_SCOPE_PLMN_WIDE] = "PLMN",
+ [GSMD_SCOPE_LOC_AREA_WIDE] = "Location Area",
+ [GSMD_SCOPE_CELL_WIDE] = "cell",
+ };
+ static const char *lang_name[] = {
+ [GSMD_LANG_GERMAN] = "German",
+ [GSMD_LANG_ENGLISH] = "English",
+ [GSMD_LANG_ITALIAN] = "Italian",
+ [GSMD_LANG_FRENCH] = "French",
+ [GSMD_LANG_SPANISH] = "Spanish",
+ [GSMD_LANG_DUTCH] = "Dutch",
+ [GSMD_LANG_SWEDISH] = "Swedish",
+ [GSMD_LANG_DANISH] = "Danish",
+ [GSMD_LANG_PORTUGUESE] = "Portuguese",
+ [GSMD_LANG_FINNISH] = "Finnish",
+ [GSMD_LANG_NORWEGIAN] = "Norwegian",
+ [GSMD_LANG_GREEK] = "Greek",
+ [GSMD_LANG_TURKISH] = "Turkish",
+ [GSMD_LANG_HUNGARIAN] = "Hungarian",
+ [GSMD_LANG_POLISH] = "Polish",
+ [GSMD_LANG_UNSPECIFIED] = "an unspecified language",
+ };
+ if (aux->u.cbm.inlined) {
+ msg = (struct gsmd_cbm *) aux->data;
+ printf("EVENT: Incoming %s-wide Cell Broadcast message in "
+ "%s (page %i of %i)\n",
+ scope_name[msg->serial.scope],
+ lang_name[msg->language],
+ msg->page, msg->pages);
+
+ if (msg->coding_scheme == ALPHABET_DEFAULT) {
+ cbm_unpacking_7bit_character(msg->data, payload);
+ printf("\"%s\"\n", payload);
+ } else if (msg->coding_scheme == ALPHABET_8BIT)
+ printf("8-bit encoded data\n");
+ else if (msg->coding_scheme == ALPHABET_UCS2)
+ printf("Unicode-16 encoded text\n");
+ } else
+ printf("EVENT: Incoming Cell Broadcast message stored at "
+ "location %i\n", aux->u.cbm.index);
+ return 0;
+}
+static int inds_handler(struct lgsm_handle *lh, int evt,
+ struct gsmd_evt_auxdata *aux)
+{
+ if (aux->u.ds.inlined)
+ printf("EVENT: Incoming Status Report\n");
+ else
+ printf("EVENT: Incoming Status Report stored at location %i\n",
+ aux->u.ds.index);
return 0;
}
@@ -139,6 +233,8 @@ int event_init(struct lgsm_handle *lh)
rc = lgsm_evt_handler_register(lh, GSMD_EVT_IN_CALL, &incall_handler);
rc |= lgsm_evt_handler_register(lh, GSMD_EVT_IN_CLIP, &clip_handler);
rc |= lgsm_evt_handler_register(lh, GSMD_EVT_IN_SMS, &insms_handler);
+ rc |= lgsm_evt_handler_register(lh, GSMD_EVT_IN_CBM, &incbm_handler);
+ rc |= lgsm_evt_handler_register(lh, GSMD_EVT_IN_DS, &inds_handler);
rc |= lgsm_evt_handler_register(lh, GSMD_EVT_OUT_COLP, &colp_handler);
rc |= lgsm_evt_handler_register(lh, GSMD_EVT_NETREG, &netreg_handler);
rc |= lgsm_evt_handler_register(lh, GSMD_EVT_SIGNAL, &sigq_handler);
personal git repositories of Harald Welte. Your mileage may vary