aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAleksander Morgado <aleksander@lanedo.com>2013-07-18 14:45:58 +0200
committerAleksander Morgado <aleksander@lanedo.com>2013-10-25 19:47:18 +0200
commitdf986c076dec33128c2ba202062ce4338cef3ad2 (patch)
treeac8894f7bf0f881c9200c65284e6968c7449f9e1 /src
parente90ff4155c63735581d0a213fdf3ae53c02bfc26 (diff)
sms: split SMS part handling into common and 3GPP-specific
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am6
-rw-r--r--src/mm-broadband-modem-mbim.c9
-rw-r--r--src/mm-broadband-modem-qmi.c9
-rw-r--r--src/mm-broadband-modem.c11
-rw-r--r--src/mm-sms-mbim.c3
-rw-r--r--src/mm-sms-part-3gpp.c1160
-rw-r--r--src/mm-sms-part-3gpp.h54
-rw-r--r--src/mm-sms-part.c1124
-rw-r--r--src/mm-sms-part.h25
-rw-r--r--src/mm-sms-qmi.c5
-rw-r--r--src/mm-sms.c7
-rw-r--r--src/tests/test-sms-part.c20
12 files changed, 1252 insertions, 1181 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 7ed067d1..1ed6df91 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -30,7 +30,9 @@ libmodem_helpers_la_SOURCES = \
mm-charsets.c \
mm-charsets.h \
mm-sms-part.h \
- mm-sms-part.c
+ mm-sms-part.c \
+ mm-sms-part-3gpp.h \
+ mm-sms-part-3gpp.c
# Additional QMI support in libmodem-helpers
if WITH_QMI
@@ -191,8 +193,6 @@ ModemManager_SOURCES = \
mm-base-modem-at.c \
mm-base-modem.h \
mm-base-modem.c \
- mm-sms-part.h \
- mm-sms-part.c \
mm-sms.h \
mm-sms.c \
mm-sms-list.h \
diff --git a/src/mm-broadband-modem-mbim.c b/src/mm-broadband-modem-mbim.c
index f7dbd9b8..4c5d6eac 100644
--- a/src/mm-broadband-modem-mbim.c
+++ b/src/mm-broadband-modem-mbim.c
@@ -36,6 +36,7 @@
#include "mm-iface-modem.h"
#include "mm-iface-modem-3gpp.h"
#include "mm-iface-modem-messaging.h"
+#include "mm-sms-part-3gpp.h"
static void iface_modem_init (MMIfaceModem *iface);
static void iface_modem_3gpp_init (MMIfaceModem3gpp *iface);
@@ -2407,10 +2408,10 @@ add_sms_part (MMBroadbandModemMbim *self,
MMSmsPart *part;
GError *error = NULL;
- part = mm_sms_part_new_from_binary_pdu (pdu->message_index,
- pdu->pdu_data,
- pdu->pdu_data_size,
- &error);
+ part = mm_sms_part_3gpp_new_from_binary_pdu (pdu->message_index,
+ pdu->pdu_data,
+ pdu->pdu_data_size,
+ &error);
if (part) {
mm_dbg ("Correctly parsed PDU (%d)", pdu->message_index);
mm_iface_modem_messaging_take_part (MM_IFACE_MODEM_MESSAGING (self),
diff --git a/src/mm-broadband-modem-qmi.c b/src/mm-broadband-modem-qmi.c
index c3f1e216..d05d7189 100644
--- a/src/mm-broadband-modem-qmi.c
+++ b/src/mm-broadband-modem-qmi.c
@@ -40,6 +40,7 @@
#include "mm-sim-qmi.h"
#include "mm-bearer-qmi.h"
#include "mm-sms-qmi.h"
+#include "mm-sms-part-3gpp.h"
static void iface_modem_init (MMIfaceModem *iface);
static void iface_modem_3gpp_init (MMIfaceModem3gpp *iface);
@@ -6858,10 +6859,10 @@ add_new_read_sms_part (MMIfaceModemMessaging *self,
MMSmsPart *part;
GError *error = NULL;
- part = mm_sms_part_new_from_binary_pdu (index,
- (guint8 *)data->data,
- data->len,
- &error);
+ part = mm_sms_part_3gpp_new_from_binary_pdu (index,
+ (guint8 *)data->data,
+ data->len,
+ &error);
if (part) {
mm_dbg ("Correctly parsed PDU (%d)",
index);
diff --git a/src/mm-broadband-modem.c b/src/mm-broadband-modem.c
index 893dcdef..b2184ac6 100644
--- a/src/mm-broadband-modem.c
+++ b/src/mm-broadband-modem.c
@@ -42,6 +42,7 @@
#include "mm-broadband-bearer.h"
#include "mm-bearer-list.h"
#include "mm-sms-list.h"
+#include "mm-sms-part-3gpp.h"
#include "mm-sim.h"
#include "mm-log.h"
#include "mm-modem-helpers.h"
@@ -5575,7 +5576,7 @@ sms_part_ready (MMBroadbandModem *self,
{
MMSmsPart *part;
gint rv, status, tpdu_len;
- gchar pdu[SMS_MAX_PDU_LEN + 1];
+ gchar pdu[MM_SMS_PART_3GPP_MAX_PDU_LEN + 1];
const gchar *response;
GError *error = NULL;
@@ -5593,7 +5594,7 @@ sms_part_ready (MMBroadbandModem *self,
return;
}
- rv = sscanf (response, "+CMGR: %d,,%d %" G_STRINGIFY (SMS_MAX_PDU_LEN) "s",
+ rv = sscanf (response, "+CMGR: %d,,%d %" G_STRINGIFY (MM_SMS_PART_3GPP_MAX_PDU_LEN) "s",
&status, &tpdu_len, pdu);
if (rv != 3) {
error = g_error_new (MM_CORE_ERROR,
@@ -5605,7 +5606,7 @@ sms_part_ready (MMBroadbandModem *self,
return;
}
- part = mm_sms_part_new_from_pdu (ctx->idx, pdu, &error);
+ part = mm_sms_part_3gpp_new_from_pdu (ctx->idx, pdu, &error);
if (part) {
mm_dbg ("Correctly parsed PDU (%d)", ctx->idx);
mm_iface_modem_messaging_take_part (MM_IFACE_MODEM_MESSAGING (self),
@@ -5715,7 +5716,7 @@ cds_received (MMAtSerialPort *port,
if (!pdu)
return;
- part = mm_sms_part_new_from_pdu (SMS_PART_INVALID_INDEX, pdu, &error);
+ part = mm_sms_part_3gpp_new_from_pdu (SMS_PART_INVALID_INDEX, pdu, &error);
if (part) {
mm_dbg ("Correctly parsed non-stored PDU");
mm_iface_modem_messaging_take_part (MM_IFACE_MODEM_MESSAGING (self),
@@ -6082,7 +6083,7 @@ sms_pdu_part_list_ready (MMBroadbandModem *self,
MM3gppPduInfo *info = l->data;
MMSmsPart *part;
- part = mm_sms_part_new_from_pdu (info->index, info->pdu, &error);
+ part = mm_sms_part_3gpp_new_from_pdu (info->index, info->pdu, &error);
if (part) {
mm_dbg ("Correctly parsed PDU (%d)", info->index);
mm_iface_modem_messaging_take_part (MM_IFACE_MODEM_MESSAGING (self),
diff --git a/src/mm-sms-mbim.c b/src/mm-sms-mbim.c
index c1e51f57..436f5b5e 100644
--- a/src/mm-sms-mbim.c
+++ b/src/mm-sms-mbim.c
@@ -29,6 +29,7 @@
#include "mm-sms-mbim.h"
#include "mm-base-modem.h"
#include "mm-log.h"
+#include "mm-sms-part-3gpp.h"
G_DEFINE_TYPE (MMSmsMbim, mm_sms_mbim, MM_TYPE_SMS)
@@ -154,7 +155,7 @@ sms_send_next_part (SmsSendContext *ctx)
}
/* Get PDU */
- pdu = mm_sms_part_get_submit_pdu ((MMSmsPart *)ctx->current->data, &pdulen, &msgstart, &error);
+ pdu = mm_sms_part_3gpp_get_submit_pdu ((MMSmsPart *)ctx->current->data, &pdulen, &msgstart, &error);
if (!pdu) {
g_simple_async_result_take_error (ctx->result, error);
sms_send_context_complete_and_free (ctx);
diff --git a/src/mm-sms-part-3gpp.c b/src/mm-sms-part-3gpp.c
new file mode 100644
index 00000000..d78881a4
--- /dev/null
+++ b/src/mm-sms-part-3gpp.c
@@ -0,0 +1,1160 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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:
+ *
+ * Copyright (C) 2011 - 2012 Red Hat, Inc.
+ * Copyright (C) 2012 Google, Inc.
+ */
+
+#include <ctype.h>
+#include <string.h>
+
+#include <glib.h>
+
+#include <ModemManager.h>
+#define _LIBMM_INSIDE_MM
+#include <libmm-glib.h>
+
+#include "mm-sms-part-3gpp.h"
+#include "mm-charsets.h"
+#include "mm-log.h"
+
+#define PDU_SIZE 200
+
+#define SMS_TP_MTI_MASK 0x03
+#define SMS_TP_MTI_SMS_DELIVER 0x00
+#define SMS_TP_MTI_SMS_SUBMIT 0x01
+#define SMS_TP_MTI_SMS_STATUS_REPORT 0x02
+
+#define SMS_NUMBER_TYPE_MASK 0x70
+#define SMS_NUMBER_TYPE_UNKNOWN 0x00
+#define SMS_NUMBER_TYPE_INTL 0x10
+#define SMS_NUMBER_TYPE_ALPHA 0x50
+
+#define SMS_NUMBER_PLAN_MASK 0x0f
+#define SMS_NUMBER_PLAN_TELEPHONE 0x01
+
+#define SMS_TP_MMS 0x04
+#define SMS_TP_SRI 0x20
+#define SMS_TP_UDHI 0x40
+#define SMS_TP_RP 0x80
+
+#define SMS_DCS_CODING_MASK 0xec
+#define SMS_DCS_CODING_DEFAULT 0x00
+#define SMS_DCS_CODING_8BIT 0x04
+#define SMS_DCS_CODING_UCS2 0x08
+
+#define SMS_DCS_CLASS_VALID 0x10
+#define SMS_DCS_CLASS_MASK 0x03
+
+#define SMS_TIMESTAMP_LEN 7
+#define SMS_MIN_PDU_LEN (7 + SMS_TIMESTAMP_LEN)
+
+static char sms_bcd_chars[] = "0123456789*#abc\0\0";
+
+static void
+sms_semi_octets_to_bcd_string (char *dest, const guint8 *octets, int num_octets)
+{
+ int i;
+
+ for (i = 0 ; i < num_octets; i++) {
+ *dest++ = sms_bcd_chars[octets[i] & 0xf];
+ *dest++ = sms_bcd_chars[(octets[i] >> 4) & 0xf];
+ }
+ *dest++ = '\0';
+}
+
+static gboolean
+char_to_bcd (char in, guint8 *out)
+{
+ guint32 z;
+
+ if (isdigit (in)) {
+ *out = in - 0x30;
+ return TRUE;
+ }
+
+ for (z = 10; z < 16; z++) {
+ if (in == sms_bcd_chars[z]) {
+ *out = z;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+static gsize
+sms_string_to_bcd_semi_octets (guint8 *buf, gsize buflen, const char *string)
+{
+ guint i;
+ guint8 bcd;
+ gsize addrlen, slen;
+
+ addrlen = slen = strlen (string);
+ if (addrlen % 2)
+ addrlen++;
+ g_return_val_if_fail (buflen >= addrlen, 0);
+
+ for (i = 0; i < addrlen; i += 2) {
+ if (!char_to_bcd (string[i], &bcd))
+ return 0;
+ buf[i / 2] = bcd & 0xF;
+
+ if (i >= slen - 1) {
+ /* PDU address gets padded with 0xF if string is odd length */
+ bcd = 0xF;
+ } else if (!char_to_bcd (string[i + 1], &bcd))
+ return 0;
+ buf[i / 2] |= bcd << 4;
+ }
+ return addrlen / 2;
+}
+
+/* len is in semi-octets */
+static char *
+sms_decode_address (const guint8 *address, int len)
+{
+ guint8 addrtype, addrplan;
+ char *utf8;
+
+ addrtype = address[0] & SMS_NUMBER_TYPE_MASK;
+ addrplan = address[0] & SMS_NUMBER_PLAN_MASK;
+ address++;
+
+ if (addrtype == SMS_NUMBER_TYPE_ALPHA) {
+ guint8 *unpacked;
+ guint32 unpacked_len;
+ unpacked = gsm_unpack (address, (len * 4) / 7, 0, &unpacked_len);
+ utf8 = (char *)mm_charset_gsm_unpacked_to_utf8 (unpacked,
+ unpacked_len);
+ g_free(unpacked);
+ } else if (addrtype == SMS_NUMBER_TYPE_INTL &&
+ addrplan == SMS_NUMBER_PLAN_TELEPHONE) {
+ /* International telphone number, format as "+1234567890" */
+ utf8 = g_malloc (len + 3); /* '+' + digits + possible trailing 0xf + NUL */
+ utf8[0] = '+';
+ sms_semi_octets_to_bcd_string (utf8 + 1, address, (len + 1) / 2);
+ } else {
+ /*
+ * All non-alphanumeric types and plans are just digits, but
+ * don't apply any special formatting if we don't know the
+ * format.
+ */
+ utf8 = g_malloc (len + 2); /* digits + possible trailing 0xf + NUL */
+ sms_semi_octets_to_bcd_string (utf8, address, (len + 1) / 2);
+ }
+
+ return utf8;
+}
+
+static char *
+sms_decode_timestamp (const guint8 *timestamp)
+{
+ /* YYMMDDHHMMSS+ZZ */
+ char *timestr;
+ int quarters, hours;
+
+ timestr = g_malloc0 (16);
+ sms_semi_octets_to_bcd_string (timestr, timestamp, 6);
+ quarters = ((timestamp[6] & 0x7) * 10) + ((timestamp[6] >> 4) & 0xf);
+ hours = quarters / 4;
+ if (timestamp[6] & 0x08)
+ timestr[12] = '-';
+ else
+ timestr[12] = '+';
+ timestr[13] = (hours / 10) + '0';
+ timestr[14] = (hours % 10) + '0';
+ /* TODO(njw): Change timestamp rep to something that includes quarter-hours */
+ return timestr;
+}
+
+static MMSmsEncoding
+sms_encoding_type (int dcs)
+{
+ MMSmsEncoding scheme = MM_SMS_ENCODING_UNKNOWN;
+
+ switch ((dcs >> 4) & 0xf) {
+ /* General data coding group */
+ case 0: case 1:
+ case 2: case 3:
+ switch (dcs & 0x0c) {
+ case 0x08:
+ scheme = MM_SMS_ENCODING_UCS2;
+ break;
+ case 0x00:
+ /* fallthrough */
+ /* reserved - spec says to treat it as default alphabet */
+ case 0x0c:
+ scheme = MM_SMS_ENCODING_GSM7;
+ break;
+ case 0x04:
+ scheme = MM_SMS_ENCODING_8BIT;
+ break;
+ }
+ break;
+
+ /* Message waiting group (default alphabet) */
+ case 0xc:
+ case 0xd:
+ scheme = MM_SMS_ENCODING_GSM7;
+ break;
+
+ /* Message waiting group (UCS2 alphabet) */
+ case 0xe:
+ scheme = MM_SMS_ENCODING_UCS2;
+ break;
+
+ /* Data coding/message class group */
+ case 0xf:
+ switch (dcs & 0x04) {
+ case 0x00:
+ scheme = MM_SMS_ENCODING_GSM7;
+ break;
+ case 0x04:
+ scheme = MM_SMS_ENCODING_8BIT;
+ break;
+ }
+ break;
+
+ /* Reserved coding group values - spec says to treat it as default alphabet */
+ default:
+ scheme = MM_SMS_ENCODING_GSM7;
+ break;
+ }
+
+ return scheme;
+}
+
+static char *
+sms_decode_text (const guint8 *text, int len, MMSmsEncoding encoding, int bit_offset)
+{
+ char *utf8;
+ guint8 *unpacked;
+ guint32 unpacked_len;
+
+ if (encoding == MM_SMS_ENCODING_GSM7) {
+ mm_dbg ("Converting SMS part text from GSM7 to UTF8...");
+ unpacked = gsm_unpack ((const guint8 *) text, len, bit_offset, &unpacked_len);
+ utf8 = (char *) mm_charset_gsm_unpacked_to_utf8 (unpacked, unpacked_len);
+ mm_dbg (" Got UTF-8 text: '%s'", utf8);
+ g_free (unpacked);
+ } else if (encoding == MM_SMS_ENCODING_UCS2) {
+ mm_dbg ("Converting SMS part text from UCS-2BE to UTF8...");
+ utf8 = g_convert ((char *) text, len, "UTF8", "UCS-2BE", NULL, NULL, NULL);
+ mm_dbg (" Got UTF-8 text: '%s'", utf8);
+ } else {
+ g_warn_if_reached ();
+ utf8 = g_strdup ("");
+ }
+
+ return utf8;
+}
+
+static guint
+relative_to_validity (guint8 relative)
+{
+ if (relative <= 143)
+ return (relative + 1) * 5;
+
+ if (relative <= 167)
+ return 720 + (relative - 143) * 30;
+
+ return (relative - 166) * 1440;
+}
+
+static guint8
+validity_to_relative (guint validity)
+{
+ if (validity == 0)
+ return 167; /* 24 hours */
+
+ if (validity <= 720) {
+ /* 5 minute units up to 12 hours */
+ if (validity % 5)
+ validity += 5;
+ return (validity / 5) - 1;
+ }
+
+ if (validity > 720 && validity <= 1440) {
+ /* 12 hours + 30 minute units up to 1 day */
+ if (validity % 30)
+ validity += 30; /* round up to next 30 minutes */
+ validity = MIN (validity, 1440);
+ return 143 + ((validity - 720) / 30);
+ }
+
+ if (validity > 1440 && validity <= 43200) {
+ /* 2 days up to 1 month */
+ if (validity % 1440)
+ validity += 1440; /* round up to next day */
+ validity = MIN (validity, 43200);
+ return 167 + ((validity - 1440) / 1440);
+ }
+
+ /* 43200 = 30 days in minutes
+ * 10080 = 7 days in minutes
+ * 635040 = 63 weeks in minutes
+ * 40320 = 4 weeks in minutes
+ */
+ if (validity > 43200 && validity <= 635040) {
+ /* 5 weeks up to 63 weeks */
+ if (validity % 10080)
+ validity += 10080; /* round up to next week */
+ validity = MIN (validity, 635040);
+ return 196 + ((validity - 40320) / 10080);
+ }
+
+ return 255; /* 63 weeks */
+}
+
+MMSmsPart *
+mm_sms_part_3gpp_new_from_pdu (guint index,
+ const gchar *hexpdu,
+ GError **error)
+{
+ gsize pdu_len;
+ guint8 *pdu;
+ MMSmsPart *part;
+
+ /* Convert PDU from hex to binary */
+ pdu = (guint8 *) mm_utils_hexstr2bin (hexpdu, &pdu_len);
+ if (!pdu) {
+ g_set_error_literal (error,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_FAILED,
+ "Couldn't convert 3GPP PDU from hex to binary");
+ return NULL;
+ }
+
+ part = mm_sms_part_3gpp_new_from_binary_pdu (index, pdu, pdu_len, error);
+ g_free (pdu);
+
+ return part;
+}
+
+MMSmsPart *
+mm_sms_part_3gpp_new_from_binary_pdu (guint index,
+ const guint8 *pdu,
+ gsize pdu_len,
+ GError **error)
+{
+ MMSmsPart *sms_part;
+ guint8 pdu_type;
+ guint offset;
+ guint smsc_addr_size_bytes;
+ guint tp_addr_size_digits;
+ guint tp_addr_size_bytes;
+ guint8 validity_format = 0;
+ gboolean has_udh = FALSE;
+ /* The following offsets are OPTIONAL, as STATUS REPORTs may not have
+ * them; we use '0' to indicate their absence */
+ guint tp_pid_offset = 0;
+ guint tp_dcs_offset = 0;
+ guint tp_user_data_len_offset = 0;
+ MMSmsEncoding user_data_encoding = MM_SMS_ENCODING_UNKNOWN;
+
+ /* Create the new MMSmsPart */
+ sms_part = mm_sms_part_new (index, MM_SMS_PDU_TYPE_UNKNOWN);
+
+ if (index != SMS_PART_INVALID_INDEX)
+ mm_dbg ("Parsing PDU (%u)...", index);
+ else
+ mm_dbg ("Parsing PDU...");
+
+#define PDU_SIZE_CHECK(required_size, check_descr_str) \
+ if (pdu_len < required_size) { \
+ g_set_error (error, \
+ MM_CORE_ERROR, \
+ MM_CORE_ERROR_FAILED, \
+ "PDU too short, %s: %" G_GSIZE_FORMAT " < %u", \
+ check_descr_str, \
+ pdu_len, \
+ required_size); \
+ mm_sms_part_free (sms_part); \
+ return NULL; \
+ }
+
+ offset = 0;
+
+ /* ---------------------------------------------------------------------- */
+ /* SMSC, in address format, precedes the TPDU
+ * First byte represents the number of BYTES for the address value */
+ PDU_SIZE_CHECK (1, "cannot read SMSC address length");
+ smsc_addr_size_bytes = pdu[offset++];
+ if (smsc_addr_size_bytes > 0) {
+ PDU_SIZE_CHECK (offset + smsc_addr_size_bytes, "cannot read SMSC address");
+ /* SMSC may not be given in DELIVER PDUs */
+ mm_sms_part_take_smsc (sms_part,
+ sms_decode_address (&pdu[1], 2 * (smsc_addr_size_bytes - 1)));
+ mm_dbg (" SMSC address parsed: '%s'", mm_sms_part_get_smsc (sms_part));
+ offset += smsc_addr_size_bytes;
+ } else
+ mm_dbg (" No SMSC address given");
+
+
+ /* ---------------------------------------------------------------------- */
+ /* TP-MTI (1 byte) */
+ PDU_SIZE_CHECK (offset + 1, "cannot read TP-MTI");
+
+ pdu_type = (pdu[offset] & SMS_TP_MTI_MASK);
+ switch (pdu_type) {
+ case SMS_TP_MTI_SMS_DELIVER:
+ mm_dbg (" Deliver type PDU detected");
+ mm_sms_part_set_pdu_type (sms_part, MM_SMS_PDU_TYPE_DELIVER);
+ break;
+ case SMS_TP_MTI_SMS_SUBMIT:
+ mm_dbg (" Submit type PDU detected");
+ mm_sms_part_set_pdu_type (sms_part, MM_SMS_PDU_TYPE_SUBMIT);
+ break;
+ case SMS_TP_MTI_SMS_STATUS_REPORT:
+ mm_dbg (" Status report type PDU detected");
+ mm_sms_part_set_pdu_type (sms_part, MM_SMS_PDU_TYPE_STATUS_REPORT);
+ break;
+ default:
+ mm_sms_part_free (sms_part);
+ g_set_error (error,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_FAILED,
+ "Unhandled message type: 0x%02x",
+ pdu_type);
+ return NULL;
+ }
+
+ /* Delivery report was requested? */
+ if (pdu[offset] & 0x20)
+ mm_sms_part_set_delivery_report_request (sms_part, TRUE);
+
+ /* PDU with validity? (only in SUBMIT PDUs) */
+ if (pdu_type == SMS_TP_MTI_SMS_SUBMIT)
+ validity_format = pdu[offset] & 0x18;
+
+ /* PDU with user data header? */
+ if (pdu[offset] & 0x40)
+ has_udh = TRUE;
+
+ offset++;
+
+ /* ---------------------------------------------------------------------- */
+ /* TP-MR (1 byte, in STATUS_REPORT and SUBMIT PDUs */
+ if (pdu_type == SMS_TP_MTI_SMS_STATUS_REPORT ||
+ pdu_type == SMS_TP_MTI_SMS_SUBMIT) {
+ PDU_SIZE_CHECK (offset + 1, "cannot read message reference");
+
+ mm_dbg (" message reference: %u", (guint)pdu[offset]);
+ mm_sms_part_set_message_reference (sms_part, pdu[offset]);
+ offset++;
+ }
+
+
+ /* ---------------------------------------------------------------------- */
+ /* TP-DA or TP-OA or TP-RA
+ * First byte represents the number of DIGITS in the number.
+ * Round the sender address length up to an even number of
+ * semi-octets, and thus an integral number of octets.
+ */
+ PDU_SIZE_CHECK (offset + 1, "cannot read number of digits in number");
+ tp_addr_size_digits = pdu[offset++];
+ tp_addr_size_bytes = (tp_addr_size_digits + 1) >> 1;
+
+ PDU_SIZE_CHECK (offset + tp_addr_size_bytes, "cannot read number");
+ mm_sms_part_take_number (sms_part,
+ sms_decode_address (&pdu[offset],
+ tp_addr_size_digits));
+ mm_dbg (" Number parsed: '%s'", mm_sms_part_get_number (sms_part));
+ offset += (1 + tp_addr_size_bytes); /* +1 due to the Type of Address byte */
+
+ /* ---------------------------------------------------------------------- */
+ /* Get timestamps and indexes for TP-PID, TP-DCS and TP-UDL/TP-UD */
+
+ if (pdu_type == SMS_TP_MTI_SMS_DELIVER) {
+ PDU_SIZE_CHECK (offset + 9,
+ "cannot read PID/DCS/Timestamp"); /* 1+1+7=9 */
+
+ /* ------ TP-PID (1 byte) ------ */
+ tp_pid_offset = offset++;
+
+ /* ------ TP-DCS (1 byte) ------ */
+ tp_dcs_offset = offset++;
+
+ /* ------ Timestamp (7 bytes) ------ */
+ mm_sms_part_take_timestamp (sms_part,
+ sms_decode_timestamp (&pdu[offset]));
+ offset += 7;
+
+ tp_user_data_len_offset = offset;
+ } else if (pdu_type == SMS_TP_MTI_SMS_SUBMIT) {
+ PDU_SIZE_CHECK (offset + 2 + !!validity_format,
+ "cannot read PID/DCS/Validity"); /* 1+1=2 */
+
+ /* ------ TP-PID (1 byte) ------ */
+ tp_pid_offset = offset++;
+
+ /* ------ TP-DCS (1 byte) ------ */
+ tp_dcs_offset = offset++;
+
+ /* ----------- TP-Validity-Period (1 byte) ----------- */
+ if (validity_format) {
+ switch (validity_format) {
+ case 0x10:
+ mm_dbg (" validity available, format relative");
+ mm_sms_part_set_validity_relative (sms_part,
+ relative_to_validity (pdu[offset]));
+ offset++;
+ break;
+ case 0x08:
+ /* TODO: support enhanced format; GSM 03.40 */
+ mm_dbg (" validity available, format enhanced (not implemented)");
+ /* 7 bytes for enhanced validity */
+ offset += 7;
+ break;
+ case 0x18:
+ /* TODO: support absolute format; GSM 03.40 */
+ mm_dbg (" validity available, format absolute (not implemented)");
+ /* 7 bytes for absolute validity */
+ offset += 7;
+ break;
+ default:
+ /* Cannot happen as we AND with the 0x18 mask */
+ g_assert_not_reached();
+ }
+ }
+
+ tp_user_data_len_offset = offset;
+ }
+ else if (pdu_type == SMS_TP_MTI_SMS_STATUS_REPORT) {
+ /* We have 2 timestamps in status report PDUs:
+ * first, the timestamp for when the PDU was received in the SMSC
+ * second, the timestamp for when the PDU was forwarded by the SMSC
+ */
+ PDU_SIZE_CHECK (offset + 15, "cannot read Timestamps/TP-STATUS"); /* 7+7+1=15 */
+
+ /* ------ Timestamp (7 bytes) ------ */
+ mm_sms_part_take_timestamp (sms_part,
+ sms_decode_timestamp (&pdu[offset]));
+ offset += 7;
+
+ /* ------ Discharge Timestamp (7 bytes) ------ */
+ mm_sms_part_take_discharge_timestamp (sms_part,
+ sms_decode_timestamp (&pdu[offset]));
+ offset += 7;
+
+ /* ----- TP-STATUS (1 byte) ------ */
+ mm_dbg (" delivery state: %u", (guint)pdu[offset]);
+ mm_sms_part_set_delivery_state (sms_part, pdu[offset]);
+ offset++;
+
+ /* ------ TP-PI (1 byte) OPTIONAL ------ */
+ if (offset < pdu_len) {
+ guint next_optional_field_offset = offset + 1;
+
+ /* TP-PID? */
+ if (pdu[offset] & 0x01)
+ tp_pid_offset = next_optional_field_offset++;
+
+ /* TP-DCS? */
+ if (pdu[offset] & 0x02)
+ tp_dcs_offset = next_optional_field_offset++;
+
+ /* TP-UserData? */
+ if (pdu[offset] & 0x04)
+ tp_user_data_len_offset = next_optional_field_offset;
+ }
+ } else
+ g_assert_not_reached ();
+
+ if (tp_pid_offset > 0) {
+ PDU_SIZE_CHECK (tp_pid_offset + 1, "cannot read TP-PID");
+ mm_dbg (" PID: %u", (guint)pdu[tp_pid_offset]);
+ }
+
+ /* Grab user data encoding and message class */
+ if (tp_dcs_offset > 0) {
+ PDU_SIZE_CHECK (tp_dcs_offset + 1, "cannot read TP-DCS");
+
+ /* Encoding given in the 'alphabet' bits */
+ user_data_encoding = sms_encoding_type(pdu[tp_dcs_offset]);
+ switch (user_data_encoding) {
+ case MM_SMS_ENCODING_GSM7:
+ mm_dbg (" user data encoding is GSM7");
+ break;
+ case MM_SMS_ENCODING_UCS2:
+ mm_dbg (" user data encoding is UCS2");
+ break;
+ case MM_SMS_ENCODING_8BIT:
+ mm_dbg (" user data encoding is 8bit");
+ break;
+ default:
+ mm_dbg (" user data encoding is unknown");
+ break;
+ }
+ mm_sms_part_set_encoding (sms_part, user_data_encoding);
+
+ /* Class */
+ if (pdu[tp_dcs_offset] & SMS_DCS_CLASS_VALID)
+ mm_sms_part_set_class (sms_part,
+ pdu[tp_dcs_offset] & SMS_DCS_CLASS_MASK);
+ }
+
+ if (tp_user_data_len_offset > 0) {
+ guint tp_user_data_size_elements;
+ guint tp_user_data_size_bytes;
+ guint tp_user_data_offset;
+ guint bit_offset;
+
+ PDU_SIZE_CHECK (tp_user_data_len_offset + 1, "cannot read TP-UDL");
+ tp_user_data_size_elements = pdu[tp_user_data_len_offset];
+ mm_dbg (" user data length: %u elements", tp_user_data_size_elements);
+
+ if (user_data_encoding == MM_SMS_ENCODING_GSM7)
+ tp_user_data_size_bytes = (7 * (tp_user_data_size_elements + 1 )) / 8;
+ else
+ tp_user_data_size_bytes = tp_user_data_size_elements;
+ mm_dbg (" user data length: %u bytes", tp_user_data_size_bytes);
+
+ tp_user_data_offset = tp_user_data_len_offset + 1;
+ PDU_SIZE_CHECK (tp_user_data_offset + tp_user_data_size_bytes, "cannot read TP-UD");
+
+ bit_offset = 0;
+ if (has_udh) {
+ guint udhl, end;
+
+ udhl = pdu[tp_user_data_offset] + 1;
+ end = tp_user_data_offset + udhl;
+
+ PDU_SIZE_CHECK (tp_user_data_offset + udhl, "cannot read UDH");
+
+ for (offset = tp_user_data_offset + 1; (offset + 1) < end;) {
+ guint8 ie_id, ie_len;
+
+ ie_id = pdu[offset++];
+ ie_len = pdu[offset++];
+
+ switch (ie_id) {
+ case 0x00:
+ if (offset + 2 >= end)
+ break;
+ /*
+ * Ignore the IE if one of the following is true:
+ * - it claims to be part 0 of M
+ * - it claims to be part N of M, N > M
+ */
+ if (pdu[offset + 2] == 0 ||
+ pdu[offset + 2] > pdu[offset + 1])
+ break;
+
+ mm_sms_part_set_concat_reference (sms_part, pdu[offset]);
+ mm_sms_part_set_concat_max (sms_part, pdu[offset + 1]);
+ mm_sms_part_set_concat_sequence (sms_part, pdu[offset + 2]);
+ break;
+ case 0x08:
+ if (offset + 3 >= end)
+ break;
+ /* Concatenated short message, 16-bit reference */
+ if (pdu[offset + 3] == 0 ||
+ pdu[offset + 3] > pdu[offset + 2])
+ break;
+
+ mm_sms_part_set_concat_reference (sms_part, (pdu[offset] << 8) | pdu[offset + 1]);
+ mm_sms_part_set_concat_max (sms_part,pdu[offset + 2]);
+ mm_sms_part_set_concat_sequence (sms_part, pdu[offset + 3]);
+ break;
+ }
+
+ offset += ie_len;
+ }
+
+ /*
+ * Move past the user data headers to prevent it from being
+ * decoded into garbage text.
+ */
+ tp_user_data_offset += udhl;
+ tp_user_data_size_bytes -= udhl;
+ if (user_data_encoding == MM_SMS_ENCODING_GSM7) {
+ /*
+ * Find the number of bits we need to add to the length of the
+ * user data to get a multiple of 7 (the padding).
+ */
+ bit_offset = (7 - udhl % 7) % 7;
+ tp_user_data_size_elements -= (udhl * 8 + bit_offset) / 7;
+ } else
+ tp_user_data_size_elements -= udhl;
+ }
+
+ switch (user_data_encoding) {
+ case MM_SMS_ENCODING_GSM7:
+ case MM_SMS_ENCODING_UCS2:
+ /* Otherwise if it's 7-bit or UCS2 we can decode it */
+ mm_dbg ("Decoding SMS text with '%u' elements", tp_user_data_size_elements);
+ mm_sms_part_take_text (sms_part,
+ sms_decode_text (&pdu[tp_user_data_offset],
+ tp_user_data_size_elements,
+ user_data_encoding,
+ bit_offset));
+ g_warn_if_fail (mm_sms_part_get_text (sms_part) != NULL);
+ break;
+
+ default:
+ {
+ GByteArray *raw;
+
+ mm_dbg ("Skipping SMS text: Unknown encoding (0x%02X)", user_data_encoding);
+
+ PDU_SIZE_CHECK (tp_user_data_offset + tp_user_data_size_bytes, "cannot read user data");
+
+ /* 8-bit encoding is usually binary data, and we have no idea what
+ * actual encoding the data is in so we can't convert it.
+ */
+ raw = g_byte_array_sized_new (tp_user_data_size_bytes);
+ g_byte_array_append (raw, &pdu[tp_user_data_offset], tp_user_data_size_bytes);
+ mm_sms_part_take_data (sms_part, raw);
+ break;
+ }
+ }
+ }
+
+ return sms_part;
+}
+
+/**
+ * mm_sms_part_3gpp_encode_address:
+ *
+ * @address: the phone number to encode
+ * @buf: the buffer to encode @address in
+ * @buflen: the size of @buf
+ * @is_smsc: if %TRUE encode size as number of octets of address infromation,
+ * otherwise if %FALSE encode size as number of digits of @address
+ *
+ * Returns: the size in bytes of the data added to @buf
+ **/
+guint
+mm_sms_part_3gpp_encode_address (const gchar *address,
+ guint8 *buf,
+ gsize buflen,
+ gboolean is_smsc)
+{
+ gsize len;
+
+ g_return_val_if_fail (address != NULL, 0);
+ g_return_val_if_fail (buf != NULL, 0);
+ g_return_val_if_fail (buflen >= 2, 0);
+
+ /* Handle number type & plan */
+ buf[1] = 0x80; /* Bit 7 always 1 */
+ if (address[0] == '+') {
+ buf[1] |= SMS_NUMBER_TYPE_INTL;
+ address++;
+ }
+ buf[1] |= SMS_NUMBER_PLAN_TELEPHONE;
+
+ len = sms_string_to_bcd_semi_octets (&buf[2], buflen, address);
+
+ if (is_smsc)
+ buf[0] = len + 1; /* addr length + size byte */
+ else
+ buf[0] = strlen (address); /* number of digits in address */
+
+ return len ? len + 2 : 0; /* addr length + size byte + number type/plan */
+}
+
+/**
+ * mm_sms_part_3gpp_get_submit_pdu:
+ *
+ * @part: the SMS message part
+ * @out_pdulen: on success, the size of the returned PDU in bytes
+ * @out_msgstart: on success, the byte index in the returned PDU where the
+ * message starts (ie, skipping the SMSC length byte and address, if present)
+ * @error: on error, filled with the error that occurred
+ *
+ * Constructs a single-part SMS message with the given details, preferring to
+ * use the UCS2 character set when the message will fit, otherwise falling back
+ * to the GSM character set.
+ *
+ * Returns: the constructed PDU data on success, or %NULL on error
+ **/
+guint8 *
+mm_sms_part_3gpp_get_submit_pdu (MMSmsPart *part,
+ guint *out_pdulen,
+ guint *out_msgstart,
+ GError **error)
+{
+ guint8 *pdu;
+ guint len, offset = 0;
+ guint shift = 0;
+ guint8 *udl_ptr;
+
+ g_return_val_if_fail (mm_sms_part_get_number (part) != NULL, NULL);
+ g_return_val_if_fail (mm_sms_part_get_text (part) != NULL || mm_sms_part_get_data (part) != NULL, NULL);
+
+ mm_dbg ("Creating PDU for part...");
+
+ /* Build up the PDU */
+ pdu = g_malloc0 (PDU_SIZE);
+
+ if (mm_sms_part_get_smsc (part)) {
+ mm_dbg (" adding SMSC to PDU...");
+ len = mm_sms_part_3gpp_encode_address (mm_sms_part_get_smsc (part), pdu, PDU_SIZE, TRUE);
+ if (len == 0) {
+ g_set_error (error,
+ MM_MESSAGE_ERROR,
+ MM_MESSAGE_ERROR_INVALID_PDU_PARAMETER,
+ "Invalid SMSC address '%s'", mm_sms_part_get_smsc (part));
+ goto error;
+ }
+ offset += len;
+ } else {
+ /* No SMSC, use default */
+ pdu[offset++] = 0x00;
+ }
+
+ if (out_msgstart)
+ *out_msgstart = offset;
+
+ /* ----------- First BYTE ----------- */
+ pdu[offset] = 0;
+
+ /* TP-VP present; format RELATIVE */
+ if (mm_sms_part_get_validity_relative (part) > 0) {
+ mm_dbg (" adding validity to PDU...");
+ pdu[offset] |= 0x10;
+ }
+
+ /* Concatenation sequence only found in multipart SMS */
+ if (mm_sms_part_get_concat_sequence (part)) {
+ mm_dbg (" adding UDHI to PDU...");
+ pdu[offset] |= 0x40; /* UDHI */
+ }
+
+ /* Delivery report requested in singlepart messages or in the last PDU of
+ * multipart messages */
+ if (mm_sms_part_get_delivery_report_request (part) &&
+ (!mm_sms_part_get_concat_sequence (part) ||
+ mm_sms_part_get_concat_max (part) == mm_sms_part_get_concat_sequence (part))) {
+ mm_dbg (" requesting delivery report...");
+ pdu[offset] |= 0x20;
+ }
+
+ /* TP-MTI = SMS-SUBMIT */
+ pdu[offset++] |= 0x01;
+
+
+ /* ----------- TP-MR (1 byte) ----------- */
+
+ pdu[offset++] = 0x00; /* TP-Message-Reference: filled by device */
+
+ /* ----------- Destination address ----------- */
+
+ len = mm_sms_part_3gpp_encode_address (mm_sms_part_get_number (part), &pdu[offset], PDU_SIZE - offset, FALSE);
+ if (len == 0) {
+ g_set_error (error,
+ MM_MESSAGE_ERROR,
+ MM_MESSAGE_ERROR_INVALID_PDU_PARAMETER,
+ "Invalid number '%s'", mm_sms_part_get_number (part));
+ goto error;
+ }
+ offset += len;
+
+ /* ----------- TP-PID (1 byte) ----------- */
+
+ pdu[offset++] = 0x00;
+
+ /* ----------- TP-DCS (1 byte) ----------- */
+ pdu[offset] = 0x00;
+
+ if (mm_sms_part_get_class (part) >= 0 && mm_sms_part_get_class (part) <= 3) {
+ mm_dbg (" using class %d...", mm_sms_part_get_class (part));
+ pdu[offset] |= SMS_DCS_CLASS_VALID;
+ pdu[offset] |= mm_sms_part_get_class (part);
+ }
+
+ switch (mm_sms_part_get_encoding (part)) {
+ case MM_SMS_ENCODING_UCS2:
+ mm_dbg (" using UCS2 encoding...");
+ pdu[offset] |= SMS_DCS_CODING_UCS2;
+ break;
+ case MM_SMS_ENCODING_GSM7:
+ mm_dbg (" using GSM7 encoding...");
+ pdu[offset] |= SMS_DCS_CODING_DEFAULT; /* GSM */
+ break;
+ default:
+ mm_dbg (" using 8bit encoding...");
+ pdu[offset] |= SMS_DCS_CODING_8BIT;
+ break;
+ }
+ offset++;
+
+ /* ----------- TP-Validity-Period (1 byte): 4 days ----------- */
+ /* Only if TP-VPF was set in first byte */
+
+ if (mm_sms_part_get_validity_relative (part) > 0)
+ pdu[offset++] = validity_to_relative (mm_sms_part_get_validity_relative (part));
+
+ /* ----------- TP-User-Data-Length ----------- */
+ /* Set to zero initially, and keep a ptr for easy access later */
+ udl_ptr = &pdu[offset];
+ pdu[offset++] = 0;
+
+ /* Build UDH */
+ if (mm_sms_part_get_concat_sequence (part)) {
+ mm_dbg (" adding UDH header in PDU... (reference: %u, max: %u, sequence: %u)",
+ mm_sms_part_get_concat_reference (part),
+ mm_sms_part_get_concat_max (part),
+ mm_sms_part_get_concat_sequence (part));
+ pdu[offset++] = 0x05; /* udh len */
+ pdu[offset++] = 0x00; /* mid */
+ pdu[offset++] = 0x03; /* data len */
+ pdu[offset++] = (guint8)mm_sms_part_get_concat_reference (part);
+ pdu[offset++] = (guint8)mm_sms_part_get_concat_max (part);
+ pdu[offset++] = (guint8)mm_sms_part_get_concat_sequence (part);
+
+ /* if a UDH is present and the data encoding is the default 7-bit
+ * alphabet, the user data must be 7-bit word aligned after the
+ * UDH. This means up to 6 bits of zeros need to be inserted at the
+ * start of the message.
+ *
+ * In our case the UDH is 6 bytes long, 48bits. The next multiple of
+ * 7 is therefore 49, so we only need to include one bit of padding.
+ */
+ shift = 1;
+ }
+
+ if (mm_sms_part_get_encoding (part) == MM_SMS_ENCODING_GSM7) {
+ guint8 *unpacked, *packed;
+ guint32 unlen = 0, packlen = 0;
+
+ unpacked = mm_charset_utf8_to_unpacked_gsm (mm_sms_part_get_text (part), &unlen);
+ if (!unpacked || unlen == 0) {
+ g_free (unpacked);
+ g_set_error_literal (error,
+ MM_MESSAGE_ERROR,
+ MM_MESSAGE_ERROR_INVALID_PDU_PARAMETER,
+ "Failed to convert message text to GSM");
+ goto error;
+ }
+
+ /* Set real data length, in septets
+ * If we had UDH, add 7 septets
+ */
+ *udl_ptr = mm_sms_part_get_concat_sequence (part) ? (7 + unlen) : unlen;
+ mm_dbg (" user data length is '%u' septets (%s UDH)",
+ *udl_ptr,
+ mm_sms_part_get_concat_sequence (part) ? "with" : "without");
+
+ packed = gsm_pack (unpacked, unlen, shift, &packlen);
+ g_free (unpacked);
+ if (!packed || packlen == 0) {
+ g_free (packed);
+ g_set_error_literal (error,
+ MM_MESSAGE_ERROR,
+ MM_MESSAGE_ERROR_INVALID_PDU_PARAMETER,
+ "Failed to pack message text to GSM");
+ goto error;
+ }
+
+ memcpy (&pdu[offset], packed, packlen);
+ g_free (packed);
+ offset += packlen;
+ } else if (mm_sms_part_get_encoding (part) == MM_SMS_ENCODING_UCS2) {
+ GByteArray *array;
+
+ /* Try to guess a good value for the array */
+ array = g_byte_array_sized_new (strlen (mm_sms_part_get_text (part)) * 2);
+ if (!mm_modem_charset_byte_array_append (array, mm_sms_part_get_text (part), FALSE, MM_MODEM_CHARSET_UCS2)) {
+ g_byte_array_free (array, TRUE);
+ g_set_error_literal (error,
+ MM_MESSAGE_ERROR,
+ MM_MESSAGE_ERROR_INVALID_PDU_PARAMETER,
+ "Failed to convert message text to UCS2");
+ goto error;
+ }
+
+ /* Set real data length, in octets
+ * If we had UDH, add 6 octets
+ */
+ *udl_ptr = mm_sms_part_get_concat_sequence (part) ? (6 + array->len) : array->len;
+ mm_dbg (" user data length is '%u' octets (%s UDH)",
+ *udl_ptr,
+ mm_sms_part_get_concat_sequence (part) ? "with" : "without");
+
+ memcpy (&pdu[offset], array->data, array->len);
+ offset += array->len;
+ g_byte_array_free (array, TRUE);
+ } else if (mm_sms_part_get_encoding (part) == MM_SMS_ENCODING_8BIT) {
+ const GByteArray *data;
+
+ data = mm_sms_part_get_data (part);
+
+ /* Set real data length, in octets
+ * If we had UDH, add 6 octets
+ */
+ *udl_ptr = mm_sms_part_get_concat_sequence (part) ? (6 + data->len) : data->len;
+ mm_dbg (" binary user data length is '%u' octets (%s UDH)",
+ *udl_ptr,
+ mm_sms_part_get_concat_sequence (part) ? "with" : "without");
+
+ memcpy (&pdu[offset], data->data, data->len);
+ offset += data->len;
+ } else
+ g_assert_not_reached ();
+
+ if (out_pdulen)
+ *out_pdulen = offset;
+ return pdu;
+
+error:
+ g_free (pdu);
+ return NULL;
+}
+
+gchar **
+mm_sms_part_3gpp_util_split_text (const gchar *text,
+ MMSmsEncoding *encoding)
+{
+ guint gsm_unsupported = 0;
+ gchar **out;
+ guint n_chunks;
+ guint i;
+ guint j;
+ gsize in_len;
+
+ if (!text)
+ return NULL;
+
+ in_len = strlen (text);
+
+ /* Some info about the rules for splitting.
+ *
+ * The User Data can be up to 140 bytes in the SMS part:
+ * 0) If we only need one chunk, it can be of up to 140 bytes.
+ * If we need more than one chunk, these have to be of 140 - 6 = 134
+ * bytes each, as we need place for the UDH header.
+ * 1) If we're using GSM7 encoding, this gives us up to 160 characters,
+ * as we can pack 160 characters of 7bits each into 140 bytes.
+ * 160 * 7 = 140 * 8 = 1120.
+ * If we only have 134 bytes allowed, that would mean that we can pack
+ * up to 153 input characters:
+ * 134 * 8 = 1072; 1072/7=153.14
+ * 2) If we're using UCS2 encoding, we can pack up to 70 characters in
+ * 140 bytes (each with 2 bytes), or up to 67 characters in 134 bytes.
+ *
+ * This method does the split of the input string into N strings, so that
+ * each of the strings can be placed in a SMS part.
+ */
+
+ /* Check if we can do GSM encoding */
+ mm_charset_get_encoded_len (text,
+ MM_MODEM_CHARSET_GSM,
+ &gsm_unsupported);
+ if (gsm_unsupported > 0) {
+ /* If cannot do it in GSM encoding, do it in UCS-2 */
+ GByteArray *array;
+
+ *encoding = MM_SMS_ENCODING_UCS2;
+
+ /* Guess more or less the size of the output array to avoid multiple
+ * allocations */
+ array = g_byte_array_sized_new (in_len * 2);
+ if (!mm_modem_charset_byte_array_append (array,
+ text,
+ FALSE,
+ MM_MODEM_CHARSET_UCS2)) {
+ g_byte_array_unref (array);
+ return NULL;
+ }
+
+ /* Our bytearray has it in UCS-2 now.
+ * UCS-2 is a fixed-size encoding, which means that the text has exactly
+ * 2 bytes for each unicode point. We can now split this array into
+ * chunks of 67 UCS-2 characters (134 bytes).
+ *
+ * Note that UCS-2 covers unicode points between U+0000 and U+FFFF, which
+ * means that there is no direct relationship between the size of the
+ * input text in UTF-8 and the size of the text in UCS-2. A 3-byte UTF-8
+ * encoded character will still be represented with 2 bytes in UCS-2.
+ */
+ if (array->len <= 140) {
+ out = g_new (gchar *, 2);
+ out[0] = g_strdup (text);
+ out[1] = NULL;
+ } else {
+ n_chunks = array->len / 134;
+ if (array->len % 134 != 0)
+ n_chunks++;
+
+ out = g_new0 (gchar *, n_chunks + 1);
+ for (i = 0, j = 0; i < n_chunks; i++, j += 134) {
+ out[i] = sms_decode_text (&array->data[j],
+ MIN (array->len - j, 134),
+ MM_SMS_ENCODING_UCS2,
+ 0);
+ }
+ }
+ g_byte_array_unref (array);
+ } else {
+ /* Do it with GSM encoding */
+ *encoding = MM_SMS_ENCODING_GSM7;
+
+ if (in_len <= 160) {
+ out = g_new (gchar *, 2);
+ out[0] = g_strdup (text);
+ out[1] = NULL;
+ } else {
+ n_chunks = in_len / 153;
+ if (in_len % 153 != 0)
+ n_chunks++;
+
+ out = g_new0 (gchar *, n_chunks + 1);
+ for (i = 0, j = 0; i < n_chunks; i++, j += 153) {
+ out[i] = g_strndup (&text[j], 153);
+ }
+ }
+ }
+
+ return out;
+}
+
+GByteArray **
+mm_sms_part_3gpp_util_split_data (const guint8 *data,
+ gsize data_len)
+{
+ GByteArray **out;
+
+ /* Some info about the rules for splitting.
+ *
+ * The User Data can be up to 140 bytes in the SMS part:
+ * 0) If we only need one chunk, it can be of up to 140 bytes.
+ * If we need more than one chunk, these have to be of 140 - 6 = 134
+ * bytes each, as we need place for the UDH header.
+ */
+
+ if (data_len <= 140) {
+ out = g_new0 (GByteArray *, 2);
+ out[0] = g_byte_array_append (g_byte_array_sized_new (data_len),
+ data,
+ data_len);
+ } else {
+ guint n_chunks;
+ guint i;
+ guint j;
+
+ n_chunks = data_len / 134;
+ if (data_len % 134 != 0)
+ n_chunks ++;
+
+ out = g_new0 (GByteArray *, n_chunks + 1);
+ for (i = 0, j = 0; i < n_chunks; i++, j+= 134) {
+ out[i] = g_byte_array_append (g_byte_array_sized_new (134),
+ &data[j],
+ MIN (data_len - j, 134));
+ }
+ }
+
+ return out;
+}
diff --git a/src/mm-sms-part-3gpp.h b/src/mm-sms-part-3gpp.h
new file mode 100644
index 00000000..82709a2f
--- /dev/null
+++ b/src/mm-sms-part-3gpp.h
@@ -0,0 +1,54 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * 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:
+ *
+ * Copyright (C) 2011 - 2012 Red Hat, Inc.
+ * Copyright (C) 2013 Google, Inc.
+ */
+
+#ifndef MM_SMS_PART_3GPP_H
+#define MM_SMS_PART_3GPP_H
+
+#include <glib.h>
+#include <ModemManager-enums.h>
+
+#include "mm-sms-part.h"
+
+#define MM_SMS_PART_3GPP_MAX_PDU_LEN 344
+
+MMSmsPart *mm_sms_part_3gpp_new_from_pdu (guint index,
+ const gchar *hexpdu,
+ GError **error);
+
+MMSmsPart *mm_sms_part_3gpp_new_from_binary_pdu (guint index,
+ const guint8 *pdu,
+ gsize pdu_len,
+ GError **error);
+
+guint8 *mm_sms_part_3gpp_get_submit_pdu (MMSmsPart *part,
+ guint *out_pdulen,
+ guint *out_msgstart,
+ GError **error);
+
+/* For testcases only */
+
+guint mm_sms_part_3gpp_encode_address (const gchar *address,
+ guint8 *buf,
+ gsize buflen,
+ gboolean is_smsc);
+
+gchar **mm_sms_part_3gpp_util_split_text (const gchar *text,
+ MMSmsEncoding *encoding);
+
+GByteArray **mm_sms_part_3gpp_util_split_data (const guint8 *data,
+ gsize data_len);
+
+#endif /* MM_SMS_PART_3GPP_H */
diff --git a/src/mm-sms-part.c b/src/mm-sms-part.c
index 77fa3b82..9dde8ed7 100644
--- a/src/mm-sms-part.c
+++ b/src/mm-sms-part.c
@@ -27,294 +27,6 @@
#include "mm-charsets.h"
#include "mm-log.h"
-#define PDU_SIZE 200
-
-#define SMS_TP_MTI_MASK 0x03
-#define SMS_TP_MTI_SMS_DELIVER 0x00
-#define SMS_TP_MTI_SMS_SUBMIT 0x01
-#define SMS_TP_MTI_SMS_STATUS_REPORT 0x02
-
-#define SMS_NUMBER_TYPE_MASK 0x70
-#define SMS_NUMBER_TYPE_UNKNOWN 0x00
-#define SMS_NUMBER_TYPE_INTL 0x10
-#define SMS_NUMBER_TYPE_ALPHA 0x50
-
-#define SMS_NUMBER_PLAN_MASK 0x0f
-#define SMS_NUMBER_PLAN_TELEPHONE 0x01
-
-#define SMS_TP_MMS 0x04
-#define SMS_TP_SRI 0x20
-#define SMS_TP_UDHI 0x40
-#define SMS_TP_RP 0x80
-
-#define SMS_DCS_CODING_MASK 0xec
-#define SMS_DCS_CODING_DEFAULT 0x00
-#define SMS_DCS_CODING_8BIT 0x04
-#define SMS_DCS_CODING_UCS2 0x08
-
-#define SMS_DCS_CLASS_VALID 0x10
-#define SMS_DCS_CLASS_MASK 0x03
-
-#define SMS_TIMESTAMP_LEN 7
-#define SMS_MIN_PDU_LEN (7 + SMS_TIMESTAMP_LEN)
-
-static char sms_bcd_chars[] = "0123456789*#abc\0\0";
-
-static void
-sms_semi_octets_to_bcd_string (char *dest, const guint8 *octets, int num_octets)
-{
- int i;
-
- for (i = 0 ; i < num_octets; i++) {
- *dest++ = sms_bcd_chars[octets[i] & 0xf];
- *dest++ = sms_bcd_chars[(octets[i] >> 4) & 0xf];
- }
- *dest++ = '\0';
-}
-
-static gboolean
-char_to_bcd (char in, guint8 *out)
-{
- guint32 z;
-
- if (isdigit (in)) {
- *out = in - 0x30;
- return TRUE;
- }
-
- for (z = 10; z < 16; z++) {
- if (in == sms_bcd_chars[z]) {
- *out = z;
- return TRUE;
- }
- }
- return FALSE;
-}
-
-static gsize
-sms_string_to_bcd_semi_octets (guint8 *buf, gsize buflen, const char *string)
-{
- guint i;
- guint8 bcd;
- gsize addrlen, slen;
-
- addrlen = slen = strlen (string);
- if (addrlen % 2)
- addrlen++;
- g_return_val_if_fail (buflen >= addrlen, 0);
-
- for (i = 0; i < addrlen; i += 2) {
- if (!char_to_bcd (string[i], &bcd))
- return 0;
- buf[i / 2] = bcd & 0xF;
-
- if (i >= slen - 1) {
- /* PDU address gets padded with 0xF if string is odd length */
- bcd = 0xF;
- } else if (!char_to_bcd (string[i + 1], &bcd))
- return 0;
- buf[i / 2] |= bcd << 4;
- }
- return addrlen / 2;
-}
-
-/* len is in semi-octets */
-static char *
-sms_decode_address (const guint8 *address, int len)
-{
- guint8 addrtype, addrplan;
- char *utf8;
-
- addrtype = address[0] & SMS_NUMBER_TYPE_MASK;
- addrplan = address[0] & SMS_NUMBER_PLAN_MASK;
- address++;
-
- if (addrtype == SMS_NUMBER_TYPE_ALPHA) {
- guint8 *unpacked;
- guint32 unpacked_len;
- unpacked = gsm_unpack (address, (len * 4) / 7, 0, &unpacked_len);
- utf8 = (char *)mm_charset_gsm_unpacked_to_utf8 (unpacked,
- unpacked_len);
- g_free(unpacked);
- } else if (addrtype == SMS_NUMBER_TYPE_INTL &&
- addrplan == SMS_NUMBER_PLAN_TELEPHONE) {
- /* International telphone number, format as "+1234567890" */
- utf8 = g_malloc (len + 3); /* '+' + digits + possible trailing 0xf + NUL */
- utf8[0] = '+';
- sms_semi_octets_to_bcd_string (utf8 + 1, address, (len + 1) / 2);
- } else {
- /*
- * All non-alphanumeric types and plans are just digits, but
- * don't apply any special formatting if we don't know the
- * format.
- */
- utf8 = g_malloc (len + 2); /* digits + possible trailing 0xf + NUL */
- sms_semi_octets_to_bcd_string (utf8, address, (len + 1) / 2);
- }
-
- return utf8;
-}
-
-static char *
-sms_decode_timestamp (const guint8 *timestamp)
-{
- /* YYMMDDHHMMSS+ZZ */
- char *timestr;
- int quarters, hours;
-
- timestr = g_malloc0 (16);
- sms_semi_octets_to_bcd_string (timestr, timestamp, 6);
- quarters = ((timestamp[6] & 0x7) * 10) + ((timestamp[6] >> 4) & 0xf);
- hours = quarters / 4;
- if (timestamp[6] & 0x08)
- timestr[12] = '-';
- else
- timestr[12] = '+';
- timestr[13] = (hours / 10) + '0';
- timestr[14] = (hours % 10) + '0';
- /* TODO(njw): Change timestamp rep to something that includes quarter-hours */
- return timestr;
-}
-
-static MMSmsEncoding
-sms_encoding_type (int dcs)
-{
- MMSmsEncoding scheme = MM_SMS_ENCODING_UNKNOWN;
-
- switch ((dcs >> 4) & 0xf) {
- /* General data coding group */
- case 0: case 1:
- case 2: case 3:
- switch (dcs & 0x0c) {
- case 0x08:
- scheme = MM_SMS_ENCODING_UCS2;
- break;
- case 0x00:
- /* fallthrough */
- /* reserved - spec says to treat it as default alphabet */
- case 0x0c:
- scheme = MM_SMS_ENCODING_GSM7;
- break;
- case 0x04:
- scheme = MM_SMS_ENCODING_8BIT;
- break;
- }
- break;
-
- /* Message waiting group (default alphabet) */
- case 0xc:
- case 0xd:
- scheme = MM_SMS_ENCODING_GSM7;
- break;
-
- /* Message waiting group (UCS2 alphabet) */
- case 0xe:
- scheme = MM_SMS_ENCODING_UCS2;
- break;
-
- /* Data coding/message class group */
- case 0xf:
- switch (dcs & 0x04) {
- case 0x00:
- scheme = MM_SMS_ENCODING_GSM7;
- break;
- case 0x04:
- scheme = MM_SMS_ENCODING_8BIT;
- break;
- }
- break;
-
- /* Reserved coding group values - spec says to treat it as default alphabet */
- default:
- scheme = MM_SMS_ENCODING_GSM7;
- break;
- }
-
- return scheme;
-}
-
-static char *
-sms_decode_text (const guint8 *text, int len, MMSmsEncoding encoding, int bit_offset)
-{
- char *utf8;
- guint8 *unpacked;
- guint32 unpacked_len;
-
- if (encoding == MM_SMS_ENCODING_GSM7) {
- mm_dbg ("Converting SMS part text from GSM7 to UTF8...");
- unpacked = gsm_unpack ((const guint8 *) text, len, bit_offset, &unpacked_len);
- utf8 = (char *) mm_charset_gsm_unpacked_to_utf8 (unpacked, unpacked_len);
- mm_dbg (" Got UTF-8 text: '%s'", utf8);
- g_free (unpacked);
- } else if (encoding == MM_SMS_ENCODING_UCS2) {
- mm_dbg ("Converting SMS part text from UCS-2BE to UTF8...");
- utf8 = g_convert ((char *) text, len, "UTF8", "UCS-2BE", NULL, NULL, NULL);
- mm_dbg (" Got UTF-8 text: '%s'", utf8);
- } else {
- g_warn_if_reached ();
- utf8 = g_strdup ("");
- }
-
- return utf8;
-}
-
-static guint
-relative_to_validity (guint8 relative)
-{
- if (relative <= 143)
- return (relative + 1) * 5;
-
- if (relative <= 167)
- return 720 + (relative - 143) * 30;
-
- return (relative - 166) * 1440;
-}
-
-static guint8
-validity_to_relative (guint validity)
-{
- if (validity == 0)
- return 167; /* 24 hours */
-
- if (validity <= 720) {
- /* 5 minute units up to 12 hours */
- if (validity % 5)
- validity += 5;
- return (validity / 5) - 1;
- }
-
- if (validity > 720 && validity <= 1440) {
- /* 12 hours + 30 minute units up to 1 day */
- if (validity % 30)
- validity += 30; /* round up to next 30 minutes */
- validity = MIN (validity, 1440);
- return 143 + ((validity - 720) / 30);
- }
-
- if (validity > 1440 && validity <= 43200) {
- /* 2 days up to 1 month */
- if (validity % 1440)
- validity += 1440; /* round up to next day */
- validity = MIN (validity, 43200);
- return 167 + ((validity - 1440) / 1440);
- }
-
- /* 43200 = 30 days in minutes
- * 10080 = 7 days in minutes
- * 635040 = 63 weeks in minutes
- * 40320 = 4 weeks in minutes
- */
- if (validity > 43200 && validity <= 635040) {
- /* 5 weeks up to 63 weeks */
- if (validity % 10080)
- validity += 10080; /* round up to next week */
- validity = MIN (validity, 635040);
- return 196 + ((validity - 40320) / 10080);
- }
-
- return 255; /* 63 weeks */
-}
-
struct _MMSmsPart {
guint index;
MMSmsPduType pdu_type;
@@ -465,839 +177,3 @@ mm_sms_part_new (guint index,
return sms_part;
}
-
-MMSmsPart *
-mm_sms_part_new_from_pdu (guint index,
- const gchar *hexpdu,
- GError **error)
-{
- gsize pdu_len;
- guint8 *pdu;
- MMSmsPart *part;
-
- /* Convert PDU from hex to binary */
- pdu = (guint8 *) mm_utils_hexstr2bin (hexpdu, &pdu_len);
- if (!pdu) {
- g_set_error_literal (error,
- MM_CORE_ERROR,
- MM_CORE_ERROR_FAILED,
- "Couldn't convert PDU from hex to binary");
- return NULL;
- }
-
- part = mm_sms_part_new_from_binary_pdu (index, pdu, pdu_len, error);
- g_free (pdu);
-
- return part;
-}
-
-MMSmsPart *
-mm_sms_part_new_from_binary_pdu (guint index,
- const guint8 *pdu,
- gsize pdu_len,
- GError **error)
-{
- MMSmsPart *sms_part;
- guint8 pdu_type;
- guint offset;
- guint smsc_addr_size_bytes;
- guint tp_addr_size_digits;
- guint tp_addr_size_bytes;
- guint8 validity_format = 0;
- gboolean has_udh = FALSE;
- /* The following offsets are OPTIONAL, as STATUS REPORTs may not have
- * them; we use '0' to indicate their absence */
- guint tp_pid_offset = 0;
- guint tp_dcs_offset = 0;
- guint tp_user_data_len_offset = 0;
- MMSmsEncoding user_data_encoding = MM_SMS_ENCODING_UNKNOWN;
-
- /* Create the new MMSmsPart */
- sms_part = mm_sms_part_new (index, MM_SMS_PDU_TYPE_UNKNOWN);
-
- if (index != SMS_PART_INVALID_INDEX)
- mm_dbg ("Parsing PDU (%u)...", index);
- else
- mm_dbg ("Parsing PDU...");
-
-#define PDU_SIZE_CHECK(required_size, check_descr_str) \
- if (pdu_len < required_size) { \
- g_set_error (error, \
- MM_CORE_ERROR, \
- MM_CORE_ERROR_FAILED, \
- "PDU too short, %s: %" G_GSIZE_FORMAT " < %u", \
- check_descr_str, \
- pdu_len, \
- required_size); \
- mm_sms_part_free (sms_part); \
- return NULL; \
- }
-
- offset = 0;
-
- /* ---------------------------------------------------------------------- */
- /* SMSC, in address format, precedes the TPDU
- * First byte represents the number of BYTES for the address value */
- PDU_SIZE_CHECK (1, "cannot read SMSC address length");
- smsc_addr_size_bytes = pdu[offset++];
- if (smsc_addr_size_bytes > 0) {
- PDU_SIZE_CHECK (offset + smsc_addr_size_bytes, "cannot read SMSC address");
- /* SMSC may not be given in DELIVER PDUs */
- mm_sms_part_take_smsc (sms_part,
- sms_decode_address (&pdu[1], 2 * (smsc_addr_size_bytes - 1)));
- mm_dbg (" SMSC address parsed: '%s'", mm_sms_part_get_smsc (sms_part));
- offset += smsc_addr_size_bytes;
- } else
- mm_dbg (" No SMSC address given");
-
-
- /* ---------------------------------------------------------------------- */
- /* TP-MTI (1 byte) */
- PDU_SIZE_CHECK (offset + 1, "cannot read TP-MTI");
-
- pdu_type = (pdu[offset] & SMS_TP_MTI_MASK);
- switch (pdu_type) {
- case SMS_TP_MTI_SMS_DELIVER:
- mm_dbg (" Deliver type PDU detected");
- mm_sms_part_set_pdu_type (sms_part, MM_SMS_PDU_TYPE_DELIVER);
- break;
- case SMS_TP_MTI_SMS_SUBMIT:
- mm_dbg (" Submit type PDU detected");
- mm_sms_part_set_pdu_type (sms_part, MM_SMS_PDU_TYPE_SUBMIT);
- break;
- case SMS_TP_MTI_SMS_STATUS_REPORT:
- mm_dbg (" Status report type PDU detected");
- mm_sms_part_set_pdu_type (sms_part, MM_SMS_PDU_TYPE_STATUS_REPORT);
- break;
- default:
- mm_sms_part_free (sms_part);
- g_set_error (error,
- MM_CORE_ERROR,
- MM_CORE_ERROR_FAILED,
- "Unhandled message type: 0x%02x",
- pdu_type);
- return NULL;
- }
-
- /* Delivery report was requested? */
- if (pdu[offset] & 0x20)
- mm_sms_part_set_delivery_report_request (sms_part, TRUE);
-
- /* PDU with validity? (only in SUBMIT PDUs) */
- if (pdu_type == SMS_TP_MTI_SMS_SUBMIT)
- validity_format = pdu[offset] & 0x18;
-
- /* PDU with user data header? */
- if (pdu[offset] & 0x40)
- has_udh = TRUE;
-
- offset++;
-
- /* ---------------------------------------------------------------------- */
- /* TP-MR (1 byte, in STATUS_REPORT and SUBMIT PDUs */
- if (pdu_type == SMS_TP_MTI_SMS_STATUS_REPORT ||
- pdu_type == SMS_TP_MTI_SMS_SUBMIT) {
- PDU_SIZE_CHECK (offset + 1, "cannot read message reference");
-
- mm_dbg (" message reference: %u", (guint)pdu[offset]);
- mm_sms_part_set_message_reference (sms_part, pdu[offset]);
- offset++;
- }
-
-
- /* ---------------------------------------------------------------------- */
- /* TP-DA or TP-OA or TP-RA
- * First byte represents the number of DIGITS in the number.
- * Round the sender address length up to an even number of
- * semi-octets, and thus an integral number of octets.
- */
- PDU_SIZE_CHECK (offset + 1, "cannot read number of digits in number");
- tp_addr_size_digits = pdu[offset++];
- tp_addr_size_bytes = (tp_addr_size_digits + 1) >> 1;
-
- PDU_SIZE_CHECK (offset + tp_addr_size_bytes, "cannot read number");
- mm_sms_part_take_number (sms_part,
- sms_decode_address (&pdu[offset],
- tp_addr_size_digits));
- mm_dbg (" Number parsed: '%s'", mm_sms_part_get_number (sms_part));
- offset += (1 + tp_addr_size_bytes); /* +1 due to the Type of Address byte */
-
- /* ---------------------------------------------------------------------- */
- /* Get timestamps and indexes for TP-PID, TP-DCS and TP-UDL/TP-UD */
-
- if (pdu_type == SMS_TP_MTI_SMS_DELIVER) {
- PDU_SIZE_CHECK (offset + 9,
- "cannot read PID/DCS/Timestamp"); /* 1+1+7=9 */
-
- /* ------ TP-PID (1 byte) ------ */
- tp_pid_offset = offset++;
-
- /* ------ TP-DCS (1 byte) ------ */
- tp_dcs_offset = offset++;
-
- /* ------ Timestamp (7 bytes) ------ */
- mm_sms_part_take_timestamp (sms_part,
- sms_decode_timestamp (&pdu[offset]));
- offset += 7;
-
- tp_user_data_len_offset = offset;
- } else if (pdu_type == SMS_TP_MTI_SMS_SUBMIT) {
- PDU_SIZE_CHECK (offset + 2 + !!validity_format,
- "cannot read PID/DCS/Validity"); /* 1+1=2 */
-
- /* ------ TP-PID (1 byte) ------ */
- tp_pid_offset = offset++;
-
- /* ------ TP-DCS (1 byte) ------ */
- tp_dcs_offset = offset++;
-
- /* ----------- TP-Validity-Period (1 byte) ----------- */
- if (validity_format) {
- switch (validity_format) {
- case 0x10:
- mm_dbg (" validity available, format relative");
- mm_sms_part_set_validity_relative (sms_part,
- relative_to_validity (pdu[offset]));
- offset++;
- break;
- case 0x08:
- /* TODO: support enhanced format; GSM 03.40 */
- mm_dbg (" validity available, format enhanced (not implemented)");
- /* 7 bytes for enhanced validity */
- offset += 7;
- break;
- case 0x18:
- /* TODO: support absolute format; GSM 03.40 */
- mm_dbg (" validity available, format absolute (not implemented)");
- /* 7 bytes for absolute validity */
- offset += 7;
- break;
- default:
- /* Cannot happen as we AND with the 0x18 mask */
- g_assert_not_reached();
- }
- }
-
- tp_user_data_len_offset = offset;
- }
- else if (pdu_type == SMS_TP_MTI_SMS_STATUS_REPORT) {
- /* We have 2 timestamps in status report PDUs:
- * first, the timestamp for when the PDU was received in the SMSC
- * second, the timestamp for when the PDU was forwarded by the SMSC
- */
- PDU_SIZE_CHECK (offset + 15, "cannot read Timestamps/TP-STATUS"); /* 7+7+1=15 */
-
- /* ------ Timestamp (7 bytes) ------ */
- mm_sms_part_take_timestamp (sms_part,
- sms_decode_timestamp (&pdu[offset]));
- offset += 7;
-
- /* ------ Discharge Timestamp (7 bytes) ------ */
- mm_sms_part_take_discharge_timestamp (sms_part,
- sms_decode_timestamp (&pdu[offset]));
- offset += 7;
-
- /* ----- TP-STATUS (1 byte) ------ */
- mm_dbg (" delivery state: %u", (guint)pdu[offset]);
- mm_sms_part_set_delivery_state (sms_part, pdu[offset]);
- offset++;
-
- /* ------ TP-PI (1 byte) OPTIONAL ------ */
- if (offset < pdu_len) {
- guint next_optional_field_offset = offset + 1;
-
- /* TP-PID? */
- if (pdu[offset] & 0x01)
- tp_pid_offset = next_optional_field_offset++;
-
- /* TP-DCS? */
- if (pdu[offset] & 0x02)
- tp_dcs_offset = next_optional_field_offset++;
-
- /* TP-UserData? */
- if (pdu[offset] & 0x04)
- tp_user_data_len_offset = next_optional_field_offset;
- }
- } else
- g_assert_not_reached ();
-
- if (tp_pid_offset > 0) {
- PDU_SIZE_CHECK (tp_pid_offset + 1, "cannot read TP-PID");
- mm_dbg (" PID: %u", (guint)pdu[tp_pid_offset]);
- }
-
- /* Grab user data encoding and message class */
- if (tp_dcs_offset > 0) {
- PDU_SIZE_CHECK (tp_dcs_offset + 1, "cannot read TP-DCS");
-
- /* Encoding given in the 'alphabet' bits */
- user_data_encoding = sms_encoding_type(pdu[tp_dcs_offset]);
- switch (user_data_encoding) {
- case MM_SMS_ENCODING_GSM7:
- mm_dbg (" user data encoding is GSM7");
- break;
- case MM_SMS_ENCODING_UCS2:
- mm_dbg (" user data encoding is UCS2");
- break;
- case MM_SMS_ENCODING_8BIT:
- mm_dbg (" user data encoding is 8bit");
- break;
- default:
- mm_dbg (" user data encoding is unknown");
- break;
- }
- mm_sms_part_set_encoding (sms_part, user_data_encoding);
-
- /* Class */
- if (pdu[tp_dcs_offset] & SMS_DCS_CLASS_VALID)
- mm_sms_part_set_class (sms_part,
- pdu[tp_dcs_offset] & SMS_DCS_CLASS_MASK);
- }
-
- if (tp_user_data_len_offset > 0) {
- guint tp_user_data_size_elements;
- guint tp_user_data_size_bytes;
- guint tp_user_data_offset;
- guint bit_offset;
-
- PDU_SIZE_CHECK (tp_user_data_len_offset + 1, "cannot read TP-UDL");
- tp_user_data_size_elements = pdu[tp_user_data_len_offset];
- mm_dbg (" user data length: %u elements", tp_user_data_size_elements);
-
- if (user_data_encoding == MM_SMS_ENCODING_GSM7)
- tp_user_data_size_bytes = (7 * (tp_user_data_size_elements + 1 )) / 8;
- else
- tp_user_data_size_bytes = tp_user_data_size_elements;
- mm_dbg (" user data length: %u bytes", tp_user_data_size_bytes);
-
- tp_user_data_offset = tp_user_data_len_offset + 1;
- PDU_SIZE_CHECK (tp_user_data_offset + tp_user_data_size_bytes, "cannot read TP-UD");
-
- bit_offset = 0;
- if (has_udh) {
- guint udhl, end;
-
- udhl = pdu[tp_user_data_offset] + 1;
- end = tp_user_data_offset + udhl;
-
- PDU_SIZE_CHECK (tp_user_data_offset + udhl, "cannot read UDH");
-
- for (offset = tp_user_data_offset + 1; (offset + 1) < end;) {
- guint8 ie_id, ie_len;
-
- ie_id = pdu[offset++];
- ie_len = pdu[offset++];
-
- switch (ie_id) {
- case 0x00:
- if (offset + 2 >= end)
- break;
- /*
- * Ignore the IE if one of the following is true:
- * - it claims to be part 0 of M
- * - it claims to be part N of M, N > M
- */
- if (pdu[offset + 2] == 0 ||
- pdu[offset + 2] > pdu[offset + 1])
- break;
-
- mm_sms_part_set_concat_reference (sms_part, pdu[offset]);
- mm_sms_part_set_concat_max (sms_part, pdu[offset + 1]);
- mm_sms_part_set_concat_sequence (sms_part, pdu[offset + 2]);
- break;
- case 0x08:
- if (offset + 3 >= end)
- break;
- /* Concatenated short message, 16-bit reference */
- if (pdu[offset + 3] == 0 ||
- pdu[offset + 3] > pdu[offset + 2])
- break;
-
- mm_sms_part_set_concat_reference (sms_part, (pdu[offset] << 8) | pdu[offset + 1]);
- mm_sms_part_set_concat_max (sms_part,pdu[offset + 2]);
- mm_sms_part_set_concat_sequence (sms_part, pdu[offset + 3]);
- break;
- }
-
- offset += ie_len;
- }
-
- /*
- * Move past the user data headers to prevent it from being
- * decoded into garbage text.
- */
- tp_user_data_offset += udhl;
- tp_user_data_size_bytes -= udhl;
- if (user_data_encoding == MM_SMS_ENCODING_GSM7) {
- /*
- * Find the number of bits we need to add to the length of the
- * user data to get a multiple of 7 (the padding).
- */
- bit_offset = (7 - udhl % 7) % 7;
- tp_user_data_size_elements -= (udhl * 8 + bit_offset) / 7;
- } else
- tp_user_data_size_elements -= udhl;
- }
-
- switch (user_data_encoding) {
- case MM_SMS_ENCODING_GSM7:
- case MM_SMS_ENCODING_UCS2:
- /* Otherwise if it's 7-bit or UCS2 we can decode it */
- mm_dbg ("Decoding SMS text with '%u' elements", tp_user_data_size_elements);
- mm_sms_part_take_text (sms_part,
- sms_decode_text (&pdu[tp_user_data_offset],
- tp_user_data_size_elements,
- user_data_encoding,
- bit_offset));
- g_warn_if_fail (sms_part->text != NULL);
- break;
-
- default:
- {
- GByteArray *raw;
-
- mm_dbg ("Skipping SMS text: Unknown encoding (0x%02X)", user_data_encoding);
-
- PDU_SIZE_CHECK (tp_user_data_offset + tp_user_data_size_bytes, "cannot read user data");
-
- /* 8-bit encoding is usually binary data, and we have no idea what
- * actual encoding the data is in so we can't convert it.
- */
- raw = g_byte_array_sized_new (tp_user_data_size_bytes);
- g_byte_array_append (raw, &pdu[tp_user_data_offset], tp_user_data_size_bytes);
- mm_sms_part_take_data (sms_part, raw);
- break;
- }
- }
- }
-
- return sms_part;
-}
-
-/**
- * mm_sms_part_encode_address:
- *
- * @address: the phone number to encode
- * @buf: the buffer to encode @address in
- * @buflen: the size of @buf
- * @is_smsc: if %TRUE encode size as number of octets of address infromation,
- * otherwise if %FALSE encode size as number of digits of @address
- *
- * Returns: the size in bytes of the data added to @buf
- **/
-guint
-mm_sms_part_encode_address (const gchar *address,
- guint8 *buf,
- gsize buflen,
- gboolean is_smsc)
-{
- gsize len;
-
- g_return_val_if_fail (address != NULL, 0);
- g_return_val_if_fail (buf != NULL, 0);
- g_return_val_if_fail (buflen >= 2, 0);
-
- /* Handle number type & plan */
- buf[1] = 0x80; /* Bit 7 always 1 */
- if (address[0] == '+') {
- buf[1] |= SMS_NUMBER_TYPE_INTL;
- address++;
- }
- buf[1] |= SMS_NUMBER_PLAN_TELEPHONE;
-
- len = sms_string_to_bcd_semi_octets (&buf[2], buflen, address);
-
- if (is_smsc)
- buf[0] = len + 1; /* addr length + size byte */
- else
- buf[0] = strlen (address); /* number of digits in address */
-
- return len ? len + 2 : 0; /* addr length + size byte + number type/plan */
-}
-
-/**
- * mm_sms_part_get_submit_pdu:
- *
- * @part: the SMS message part
- * @out_pdulen: on success, the size of the returned PDU in bytes
- * @out_msgstart: on success, the byte index in the returned PDU where the
- * message starts (ie, skipping the SMSC length byte and address, if present)
- * @error: on error, filled with the error that occurred
- *
- * Constructs a single-part SMS message with the given details, preferring to
- * use the UCS2 character set when the message will fit, otherwise falling back
- * to the GSM character set.
- *
- * Returns: the constructed PDU data on success, or %NULL on error
- **/
-guint8 *
-mm_sms_part_get_submit_pdu (MMSmsPart *part,
- guint *out_pdulen,
- guint *out_msgstart,
- GError **error)
-{
- guint8 *pdu;
- guint len, offset = 0;
- guint shift = 0;
- guint8 *udl_ptr;
-
- g_return_val_if_fail (part->number != NULL, NULL);
- g_return_val_if_fail (part->text != NULL || part->data != NULL, NULL);
-
- mm_dbg ("Creating PDU for part...");
-
- /* Build up the PDU */
- pdu = g_malloc0 (PDU_SIZE);
-
- if (part->smsc) {
- mm_dbg (" adding SMSC to PDU...");
- len = mm_sms_part_encode_address (part->smsc, pdu, PDU_SIZE, TRUE);
- if (len == 0) {
- g_set_error (error,
- MM_MESSAGE_ERROR,
- MM_MESSAGE_ERROR_INVALID_PDU_PARAMETER,
- "Invalid SMSC address '%s'", part->smsc);
- goto error;
- }
- offset += len;
- } else {
- /* No SMSC, use default */
- pdu[offset++] = 0x00;
- }
-
- if (out_msgstart)
- *out_msgstart = offset;
-
- /* ----------- First BYTE ----------- */
- pdu[offset] = 0;
-
- /* TP-VP present; format RELATIVE */
- if (part->validity_relative > 0) {
- mm_dbg (" adding validity to PDU...");
- pdu[offset] |= 0x10;
- }
-
- /* Concatenation sequence only found in multipart SMS */
- if (part->concat_sequence) {
- mm_dbg (" adding UDHI to PDU...");
- pdu[offset] |= 0x40; /* UDHI */
- }
-
- /* Delivery report requested in singlepart messages or in the last PDU of
- * multipart messages */
- if (part->delivery_report_request &&
- (!part->concat_sequence ||
- part->concat_max == part->concat_sequence)) {
- mm_dbg (" requesting delivery report...");
- pdu[offset] |= 0x20;
- }
-
- /* TP-MTI = SMS-SUBMIT */
- pdu[offset++] |= 0x01;
-
-
- /* ----------- TP-MR (1 byte) ----------- */
-
- pdu[offset++] = 0x00; /* TP-Message-Reference: filled by device */
-
- /* ----------- Destination address ----------- */
-
- len = mm_sms_part_encode_address (part->number, &pdu[offset], PDU_SIZE - offset, FALSE);
- if (len == 0) {
- g_set_error (error,
- MM_MESSAGE_ERROR,
- MM_MESSAGE_ERROR_INVALID_PDU_PARAMETER,
- "Invalid number '%s'", part->number);
- goto error;
- }
- offset += len;
-
- /* ----------- TP-PID (1 byte) ----------- */
-
- pdu[offset++] = 0x00;
-
- /* ----------- TP-DCS (1 byte) ----------- */
- pdu[offset] = 0x00;
-
- if (part->class >= 0 && part->class <= 3) {
- mm_dbg (" using class %d...", part->class);
- pdu[offset] |= SMS_DCS_CLASS_VALID;
- pdu[offset] |= part->class;
- }
-
- if (part->encoding == MM_SMS_ENCODING_UCS2) {
- mm_dbg (" using UCS2 encoding...");
- pdu[offset] |= SMS_DCS_CODING_UCS2;
- } else if (part->encoding == MM_SMS_ENCODING_GSM7) {
- mm_dbg (" using GSM7 encoding...");
- pdu[offset] |= SMS_DCS_CODING_DEFAULT; /* GSM */
- } else {
- mm_dbg (" using 8bit encoding...");
- pdu[offset] |= SMS_DCS_CODING_8BIT;
- }
- offset++;
-
- /* ----------- TP-Validity-Period (1 byte): 4 days ----------- */
- /* Only if TP-VPF was set in first byte */
-
- if (part->validity_relative > 0)
- pdu[offset++] = validity_to_relative (part->validity_relative);
-
- /* ----------- TP-User-Data-Length ----------- */
- /* Set to zero initially, and keep a ptr for easy access later */
- udl_ptr = &pdu[offset];
- pdu[offset++] = 0;
-
- /* Build UDH */
- if (part->concat_sequence) {
- mm_dbg (" adding UDH header in PDU... (reference: %u, max: %u, sequence: %u)",
- part->concat_reference,
- part->concat_max,
- part->concat_sequence);
- pdu[offset++] = 0x05; /* udh len */
- pdu[offset++] = 0x00; /* mid */
- pdu[offset++] = 0x03; /* data len */
- pdu[offset++] = (guint8)part->concat_reference;
- pdu[offset++] = (guint8)part->concat_max;
- pdu[offset++] = (guint8)part->concat_sequence;
-
- /* if a UDH is present and the data encoding is the default 7-bit
- * alphabet, the user data must be 7-bit word aligned after the
- * UDH. This means up to 6 bits of zeros need to be inserted at the
- * start of the message.
- *
- * In our case the UDH is 6 bytes long, 48bits. The next multiple of
- * 7 is therefore 49, so we only need to include one bit of padding.
- */
- shift = 1;
- }
-
- if (part->encoding == MM_SMS_ENCODING_GSM7) {
- guint8 *unpacked, *packed;
- guint32 unlen = 0, packlen = 0;
-
- unpacked = mm_charset_utf8_to_unpacked_gsm (part->text, &unlen);
- if (!unpacked || unlen == 0) {
- g_free (unpacked);
- g_set_error_literal (error,
- MM_MESSAGE_ERROR,
- MM_MESSAGE_ERROR_INVALID_PDU_PARAMETER,
- "Failed to convert message text to GSM");
- goto error;
- }
-
- /* Set real data length, in septets
- * If we had UDH, add 7 septets
- */
- *udl_ptr = part->concat_sequence ? (7 + unlen) : unlen;
- mm_dbg (" user data length is '%u' septets (%s UDH)",
- *udl_ptr,
- part->concat_sequence ? "with" : "without");
-
- packed = gsm_pack (unpacked, unlen, shift, &packlen);
- g_free (unpacked);
- if (!packed || packlen == 0) {
- g_free (packed);
- g_set_error_literal (error,
- MM_MESSAGE_ERROR,
- MM_MESSAGE_ERROR_INVALID_PDU_PARAMETER,
- "Failed to pack message text to GSM");
- goto error;
- }
-
- memcpy (&pdu[offset], packed, packlen);
- g_free (packed);
- offset += packlen;
- } else if (part->encoding == MM_SMS_ENCODING_UCS2) {
- GByteArray *array;
-
- /* Try to guess a good value for the array */
- array = g_byte_array_sized_new (strlen (part->text) * 2);
- if (!mm_modem_charset_byte_array_append (array, part->text, FALSE, MM_MODEM_CHARSET_UCS2)) {
- g_byte_array_free (array, TRUE);
- g_set_error_literal (error,
- MM_MESSAGE_ERROR,
- MM_MESSAGE_ERROR_INVALID_PDU_PARAMETER,
- "Failed to convert message text to UCS2");
- goto error;
- }
-
- /* Set real data length, in octets
- * If we had UDH, add 6 octets
- */
- *udl_ptr = part->concat_sequence ? (6 + array->len) : array->len;
- mm_dbg (" user data length is '%u' octets (%s UDH)",
- *udl_ptr,
- part->concat_sequence ? "with" : "without");
-
- memcpy (&pdu[offset], array->data, array->len);
- offset += array->len;
- g_byte_array_free (array, TRUE);
- } else if (part->encoding == MM_SMS_ENCODING_8BIT) {
- /* Set real data length, in octets
- * If we had UDH, add 6 octets
- */
- *udl_ptr = part->concat_sequence ? (6 + part->data->len) : part->data->len;
- mm_dbg (" binary user data length is '%u' octets (%s UDH)",
- *udl_ptr,
- part->concat_sequence ? "with" : "without");
-
- memcpy (&pdu[offset], part->data->data, part->data->len);
- offset += part->data->len;
- } else
- g_assert_not_reached ();
-
- if (out_pdulen)
- *out_pdulen = offset;
- return pdu;
-
-error:
- g_free (pdu);
- return NULL;
-}
-
-gchar **
-mm_sms_part_util_split_text (const gchar *text,
- MMSmsEncoding *encoding)
-{
- guint gsm_unsupported = 0;
- gchar **out;
- guint n_chunks;
- guint i;
- guint j;
- gsize in_len;
-
- if (!text)
- return NULL;
-
- in_len = strlen (text);
-
- /* Some info about the rules for splitting.
- *
- * The User Data can be up to 140 bytes in the SMS part:
- * 0) If we only need one chunk, it can be of up to 140 bytes.
- * If we need more than one chunk, these have to be of 140 - 6 = 134
- * bytes each, as we need place for the UDH header.
- * 1) If we're using GSM7 encoding, this gives us up to 160 characters,
- * as we can pack 160 characters of 7bits each into 140 bytes.
- * 160 * 7 = 140 * 8 = 1120.
- * If we only have 134 bytes allowed, that would mean that we can pack
- * up to 153 input characters:
- * 134 * 8 = 1072; 1072/7=153.14
- * 2) If we're using UCS2 encoding, we can pack up to 70 characters in
- * 140 bytes (each with 2 bytes), or up to 67 characters in 134 bytes.
- *
- * This method does the split of the input string into N strings, so that
- * each of the strings can be placed in a SMS part.
- */
-
- /* Check if we can do GSM encoding */
- mm_charset_get_encoded_len (text,
- MM_MODEM_CHARSET_GSM,
- &gsm_unsupported);
- if (gsm_unsupported > 0) {
- /* If cannot do it in GSM encoding, do it in UCS-2 */
- GByteArray *array;
-
- *encoding = MM_SMS_ENCODING_UCS2;
-
- /* Guess more or less the size of the output array to avoid multiple
- * allocations */
- array = g_byte_array_sized_new (in_len * 2);
- if (!mm_modem_charset_byte_array_append (array,
- text,
- FALSE,
- MM_MODEM_CHARSET_UCS2)) {
- g_byte_array_unref (array);
- return NULL;
- }
-
- /* Our bytearray has it in UCS-2 now.
- * UCS-2 is a fixed-size encoding, which means that the text has exactly
- * 2 bytes for each unicode point. We can now split this array into
- * chunks of 67 UCS-2 characters (134 bytes).
- *
- * Note that UCS-2 covers unicode points between U+0000 and U+FFFF, which
- * means that there is no direct relationship between the size of the
- * input text in UTF-8 and the size of the text in UCS-2. A 3-byte UTF-8
- * encoded character will still be represented with 2 bytes in UCS-2.
- */
- if (array->len <= 140) {
- out = g_new (gchar *, 2);
- out[0] = g_strdup (text);
- out[1] = NULL;
- } else {
- n_chunks = array->len / 134;
- if (array->len % 134 != 0)
- n_chunks++;
-
- out = g_new0 (gchar *, n_chunks + 1);
- for (i = 0, j = 0; i < n_chunks; i++, j += 134) {
- out[i] = sms_decode_text (&array->data[j],
- MIN (array->len - j, 134),
- MM_SMS_ENCODING_UCS2,
- 0);
- }
- }
- g_byte_array_unref (array);
- } else {
- /* Do it with GSM encoding */
- *encoding = MM_SMS_ENCODING_GSM7;
-
- if (in_len <= 160) {
- out = g_new (gchar *, 2);
- out[0] = g_strdup (text);
- out[1] = NULL;
- } else {
- n_chunks = in_len / 153;
- if (in_len % 153 != 0)
- n_chunks++;
-
- out = g_new0 (gchar *, n_chunks + 1);
- for (i = 0, j = 0; i < n_chunks; i++, j += 153) {
- out[i] = g_strndup (&text[j], 153);
- }
- }
- }
-
- return out;
-}
-
-GByteArray **
-mm_sms_part_util_split_data (const guint8 *data,
- gsize data_len)
-{
- GByteArray **out;
-
- /* Some info about the rules for splitting.
- *
- * The User Data can be up to 140 bytes in the SMS part:
- * 0) If we only need one chunk, it can be of up to 140 bytes.
- * If we need more than one chunk, these have to be of 140 - 6 = 134
- * bytes each, as we need place for the UDH header.
- */
-
- if (data_len <= 140) {
- out = g_new0 (GByteArray *, 2);
- out[0] = g_byte_array_append (g_byte_array_sized_new (data_len),
- data,
- data_len);
- } else {
- guint n_chunks;
- guint i;
- guint j;
-
- n_chunks = data_len / 134;
- if (data_len % 134 != 0)
- n_chunks ++;
-
- out = g_new0 (GByteArray *, n_chunks + 1);
- for (i = 0, j = 0; i < n_chunks; i++, j+= 134) {
- out[i] = g_byte_array_append (g_byte_array_sized_new (134),
- &data[j],
- MIN (data_len - j, 134));
- }
- }
-
- return out;
-}
diff --git a/src/mm-sms-part.h b/src/mm-sms-part.h
index d44ed5bc..d5b373c5 100644
--- a/src/mm-sms-part.h
+++ b/src/mm-sms-part.h
@@ -29,25 +29,12 @@ typedef enum {
typedef struct _MMSmsPart MMSmsPart;
-#define SMS_MAX_PDU_LEN 344
#define SMS_PART_INVALID_INDEX G_MAXUINT
MMSmsPart *mm_sms_part_new (guint index,
MMSmsPduType type);
-MMSmsPart *mm_sms_part_new_from_pdu (guint index,
- const gchar *hexpdu,
- GError **error);
-MMSmsPart *mm_sms_part_new_from_binary_pdu (guint index,
- const guint8 *pdu,
- gsize pdu_len,
- GError **error);
void mm_sms_part_free (MMSmsPart *part);
-guint8 *mm_sms_part_get_submit_pdu (MMSmsPart *part,
- guint *out_pdulen,
- guint *out_msgstart,
- GError **error);
-
guint mm_sms_part_get_index (MMSmsPart *part);
void mm_sms_part_set_index (MMSmsPart *part,
guint index);
@@ -129,16 +116,4 @@ void mm_sms_part_set_concat_sequence (MMSmsPart *part,
gboolean mm_sms_part_should_concat (MMSmsPart *part);
-/* For testcases only */
-guint mm_sms_part_encode_address (const gchar *address,
- guint8 *buf,
- gsize buflen,
- gboolean is_smsc);
-
-gchar **mm_sms_part_util_split_text (const gchar *text,
- MMSmsEncoding *encoding);
-
-GByteArray **mm_sms_part_util_split_data (const guint8 *data,
- gsize data_len);
-
#endif /* MM_SMS_PART_H */
diff --git a/src/mm-sms-qmi.c b/src/mm-sms-qmi.c
index 85ca5166..0e13e410 100644
--- a/src/mm-sms-qmi.c
+++ b/src/mm-sms-qmi.c
@@ -28,6 +28,7 @@
#include "mm-iface-modem-messaging.h"
#include "mm-sms-qmi.h"
#include "mm-base-modem.h"
+#include "mm-sms-part-3gpp.h"
#include "mm-log.h"
G_DEFINE_TYPE (MMSmsQmi, mm_sms_qmi, MM_TYPE_SMS);
@@ -173,7 +174,7 @@ sms_store_next_part (SmsStoreContext *ctx)
}
/* Get PDU */
- pdu = mm_sms_part_get_submit_pdu ((MMSmsPart *)ctx->current->data, &pdulen, &msgstart, &error);
+ pdu = mm_sms_part_3gpp_get_submit_pdu ((MMSmsPart *)ctx->current->data, &pdulen, &msgstart, &error);
if (!pdu) {
/* 'error' should already be set */
g_simple_async_result_take_error (ctx->result, error);
@@ -332,7 +333,7 @@ sms_send_generic (SmsSendContext *ctx)
GError *error = NULL;
/* Get PDU */
- pdu = mm_sms_part_get_submit_pdu ((MMSmsPart *)ctx->current->data, &pdulen, &msgstart, &error);
+ pdu = mm_sms_part_3gpp_get_submit_pdu ((MMSmsPart *)ctx->current->data, &pdulen, &msgstart, &error);
if (!pdu) {
g_simple_async_result_take_error (ctx->result, error);
sms_send_context_complete_and_free (ctx);
diff --git a/src/mm-sms.c b/src/mm-sms.c
index 25a44775..e07273d6 100644
--- a/src/mm-sms.c
+++ b/src/mm-sms.c
@@ -30,6 +30,7 @@
#include "mm-iface-modem.h"
#include "mm-iface-modem-messaging.h"
#include "mm-sms.h"
+#include "mm-sms-part-3gpp.h"
#include "mm-base-modem-at.h"
#include "mm-base-modem.h"
#include "mm-log.h"
@@ -123,7 +124,7 @@ generate_submit_pdus (MMSms *self,
g_assert (!(text != NULL && data != NULL));
if (text) {
- split_text = mm_sms_part_util_split_text (text, &encoding);
+ split_text = mm_sms_part_3gpp_util_split_text (text, &encoding);
if (!split_text) {
g_set_error (error,
MM_CORE_ERROR,
@@ -134,7 +135,7 @@ generate_submit_pdus (MMSms *self,
n_parts = g_strv_length (split_text);
} else if (data) {
encoding = MM_SMS_ENCODING_8BIT;
- split_data = mm_sms_part_util_split_data (data, data_len);
+ split_data = mm_sms_part_3gpp_util_split_data (data, data_len);
g_assert (split_data != NULL);
/* noop within the for */
for (n_parts = 0; split_data[n_parts]; n_parts++);
@@ -703,7 +704,7 @@ sms_get_store_or_send_command (MMSmsPart *part,
/* AT+CMGW=<length>[, <stat>]<CR> PDU can be entered. <CTRL-Z>/<ESC> */
- pdu = mm_sms_part_get_submit_pdu (part, &pdulen, &msgstart, error);
+ pdu = mm_sms_part_3gpp_get_submit_pdu (part, &pdulen, &msgstart, error);
if (!pdu)
/* 'error' should already be set */
return FALSE;
diff --git a/src/tests/test-sms-part.c b/src/tests/test-sms-part.c
index 33287e28..2e393138 100644
--- a/src/tests/test-sms-part.c
+++ b/src/tests/test-sms-part.c
@@ -23,7 +23,7 @@
#define _LIBMM_INSIDE_MM
#include <libmm-glib.h>
-#include "mm-sms-part.h"
+#include "mm-sms-part-3gpp.h"
#include "mm-log.h"
/* If defined will print debugging traces */
@@ -58,7 +58,7 @@ common_test_part_from_hexpdu (const gchar *hexpdu,
MMSmsPart *part;
GError *error = NULL;
- part = mm_sms_part_new_from_pdu (0, hexpdu, &error);
+ part = mm_sms_part_3gpp_new_from_pdu (0, hexpdu, &error);
g_assert_no_error (error);
g_assert (part != NULL);
@@ -356,7 +356,7 @@ test_pdu_insufficient_data (void)
};
hexpdu = mm_utils_bin2hexstr (pdu, sizeof (pdu));
- part = mm_sms_part_new_from_pdu (0, hexpdu, &error);
+ part = mm_sms_part_3gpp_new_from_pdu (0, hexpdu, &error);
g_assert (part == NULL);
/* We don't care for the specific error type */
g_assert (error != NULL);
@@ -464,7 +464,7 @@ common_test_address_encode (const gchar *address,
guint8 buf[20];
gsize enclen;
- enclen = mm_sms_part_encode_address (address, buf, sizeof (buf), smsc);
+ enclen = mm_sms_part_3gpp_encode_address (address, buf, sizeof (buf), smsc);
g_assert_cmpuint (enclen, ==, expected_size);
g_assert_cmpint (memcmp (buf, expected, expected_size), ==, 0);
}
@@ -531,7 +531,7 @@ common_test_create_pdu (const gchar *smsc,
MMSmsEncoding encoding = MM_SMS_ENCODING_UNKNOWN;
/* Detect best encoding */
- mm_sms_part_util_split_text (text, &encoding);
+ mm_sms_part_3gpp_util_split_text (text, &encoding);
mm_sms_part_set_text (part, text);
mm_sms_part_set_encoding (part, encoding);
}
@@ -540,10 +540,10 @@ common_test_create_pdu (const gchar *smsc,
if (class >= 0)
mm_sms_part_set_class (part, class);
- pdu = mm_sms_part_get_submit_pdu (part,
- &len,
- &msgstart,
- &error);
+ pdu = mm_sms_part_3gpp_get_submit_pdu (part,
+ &len,
+ &msgstart,
+ &error);
trace_pdu (pdu, len);
@@ -716,7 +716,7 @@ common_test_text_split (const gchar *text,
MMSmsEncoding out_encoding = MM_SMS_ENCODING_UNKNOWN;
guint i;
- out = mm_sms_part_util_split_text (text, &out_encoding);
+ out = mm_sms_part_3gpp_util_split_text (text, &out_encoding);
g_assert (out != NULL);
g_assert (out_encoding != MM_SMS_ENCODING_UNKNOWN);