aboutsummaryrefslogtreecommitdiff
path: root/src/mm-sms-part.c
diff options
context:
space:
mode:
authorAleksander Morgado <aleksander@lanedo.com>2012-09-07 20:18:16 +0200
committerAleksander Morgado <aleksander@lanedo.com>2012-09-14 07:05:22 +0200
commit3c814d74caeef9218bf678e21e56fa054ad67703 (patch)
treede5361d94b033702c21b380c2b6137d5ac1b3ca0 /src/mm-sms-part.c
parent3332ec0c688ce302ba276f5aa0a31d62452cec8b (diff)
sms-part: create proper SUBMIT PDUs for multipart SMS messages
If the SMS part is from a multipart message we'll need to create a PDU with a proper User Data Header. This patch is based on a previous implementation by: Roberto Majadas <roberto.majadas@openshine.com>
Diffstat (limited to 'src/mm-sms-part.c')
-rw-r--r--src/mm-sms-part.c122
1 files changed, 83 insertions, 39 deletions
diff --git a/src/mm-sms-part.c b/src/mm-sms-part.c
index f8493bb5..62debf59 100644
--- a/src/mm-sms-part.c
+++ b/src/mm-sms-part.c
@@ -715,40 +715,19 @@ mm_sms_part_get_submit_pdu (MMSmsPart *part,
{
guint8 *pdu;
guint len, offset = 0;
- MMModemCharset best_cs = MM_MODEM_CHARSET_GSM;
- guint ucs2len = 0, gsm_unsupported = 0;
- guint textlen = 0;
+ guint shift = 0;
+ guint8 *udl_ptr;
g_return_val_if_fail (part->number != NULL, NULL);
g_return_val_if_fail (part->text != NULL, NULL);
- /* FIXME: support multiple fragments. */
-
- textlen = mm_charset_get_encoded_len (part->text, MM_MODEM_CHARSET_GSM, &gsm_unsupported);
- if (textlen > 160) {
- g_set_error_literal (error,
- MM_CORE_ERROR,
- MM_CORE_ERROR_UNSUPPORTED,
- "Cannot encode message to fit into an SMS.");
- return NULL;
- }
-
- /* If there are characters that are unsupported in the GSM charset, try
- * UCS2. If the UCS2 encoded string is too long to fit in an SMS, then
- * just use GSM and suck up the unconverted chars.
- */
- if (gsm_unsupported > 0) {
- ucs2len = mm_charset_get_encoded_len (part->text, MM_MODEM_CHARSET_UCS2, NULL);
- if (ucs2len <= 140) {
- best_cs = MM_MODEM_CHARSET_UCS2;
- textlen = ucs2len;
- }
- }
+ 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,
@@ -766,14 +745,29 @@ mm_sms_part_get_submit_pdu (MMSmsPart *part,
if (out_msgstart)
*out_msgstart = offset;
- if (part->validity > 0)
+ /* ----------- First BYTE ----------- */
+
+ if (part->validity > 0) {
+ mm_dbg (" adding validity to PDU...");
pdu[offset] = 1 << 4; /* TP-VP present; format RELATIVE */
- else
+ } else
pdu[offset] = 0; /* TP-VP not present */
+
+ /* Concatenation sequence only found in multipart SMS */
+ if (part->concat_sequence) {
+ mm_dbg (" adding UDHI to PDU...");
+ pdu[offset] |= 0x40; /* UDHI */
+ }
+
+ /* TODO: Request status only in last part */
pdu[offset++] |= 0x01; /* TP-MTI = SMS-SUBMIT */
+ /* ----------- 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,
@@ -784,23 +778,56 @@ mm_sms_part_get_submit_pdu (MMSmsPart *part,
}
offset += len;
- /* TP-PID */
+ /* ----------- TP-PID (1 byte) ----------- */
+
pdu[offset++] = 0x00;
- /* TP-DCS */
- if (best_cs == MM_MODEM_CHARSET_UCS2)
+ /* ----------- TP-DCS (1 byte) ----------- */
+
+ if (part->encoding == MM_SMS_ENCODING_UCS2) {
+ mm_dbg (" using UCS2 encoding...");
pdu[offset++] = 0x08;
- else
+ } else {
+ mm_dbg (" using GSM7 encoding...");
pdu[offset++] = 0x00; /* GSM */
+ }
+
+ /* ----------- TP-Validity-Period (1 byte): 4 days ----------- */
+ /* Only if TP-VPF was set in first byte */
- /* TP-Validity-Period: 4 days */
if (part->validity > 0)
pdu[offset++] = validity_to_relative (part->validity);
- /* TP-User-Data-Length */
- pdu[offset++] = textlen;
+ /* ----------- 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 (best_cs == MM_MODEM_CHARSET_GSM) {
+ if (part->encoding == MM_SMS_ENCODING_GSM7) {
guint8 *unpacked, *packed;
guint32 unlen = 0, packlen = 0;
@@ -814,7 +841,15 @@ mm_sms_part_get_submit_pdu (MMSmsPart *part,
goto error;
}
- packed = gsm_pack (unpacked, unlen, 0, &packlen);
+ /* 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);
@@ -828,11 +863,12 @@ mm_sms_part_get_submit_pdu (MMSmsPart *part,
memcpy (&pdu[offset], packed, packlen);
g_free (packed);
offset += packlen;
- } else if (best_cs == MM_MODEM_CHARSET_UCS2) {
+ } else if (part->encoding == MM_SMS_ENCODING_UCS2) {
GByteArray *array;
- array = g_byte_array_sized_new (textlen / 2);
- if (!mm_modem_charset_byte_array_append (array, part->text, FALSE, best_cs)) {
+ /* 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,
@@ -841,6 +877,14 @@ mm_sms_part_get_submit_pdu (MMSmsPart *part,
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);