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>
This commit is contained in:
@@ -715,40 +715,19 @@ mm_sms_part_get_submit_pdu (MMSmsPart *part,
|
|||||||
{
|
{
|
||||||
guint8 *pdu;
|
guint8 *pdu;
|
||||||
guint len, offset = 0;
|
guint len, offset = 0;
|
||||||
MMModemCharset best_cs = MM_MODEM_CHARSET_GSM;
|
guint shift = 0;
|
||||||
guint ucs2len = 0, gsm_unsupported = 0;
|
guint8 *udl_ptr;
|
||||||
guint textlen = 0;
|
|
||||||
|
|
||||||
g_return_val_if_fail (part->number != NULL, NULL);
|
g_return_val_if_fail (part->number != NULL, NULL);
|
||||||
g_return_val_if_fail (part->text != NULL, NULL);
|
g_return_val_if_fail (part->text != NULL, NULL);
|
||||||
|
|
||||||
/* FIXME: support multiple fragments. */
|
mm_dbg ("Creating PDU for part...");
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Build up the PDU */
|
/* Build up the PDU */
|
||||||
pdu = g_malloc0 (PDU_SIZE);
|
pdu = g_malloc0 (PDU_SIZE);
|
||||||
|
|
||||||
if (part->smsc) {
|
if (part->smsc) {
|
||||||
|
mm_dbg (" adding SMSC to PDU...");
|
||||||
len = mm_sms_part_encode_address (part->smsc, pdu, PDU_SIZE, TRUE);
|
len = mm_sms_part_encode_address (part->smsc, pdu, PDU_SIZE, TRUE);
|
||||||
if (len == 0) {
|
if (len == 0) {
|
||||||
g_set_error (error,
|
g_set_error (error,
|
||||||
@@ -766,14 +745,29 @@ mm_sms_part_get_submit_pdu (MMSmsPart *part,
|
|||||||
if (out_msgstart)
|
if (out_msgstart)
|
||||||
*out_msgstart = offset;
|
*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 */
|
pdu[offset] = 1 << 4; /* TP-VP present; format RELATIVE */
|
||||||
else
|
} else
|
||||||
pdu[offset] = 0; /* TP-VP not present */
|
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 */
|
pdu[offset++] |= 0x01; /* TP-MTI = SMS-SUBMIT */
|
||||||
|
|
||||||
|
/* ----------- TP-MR (1 byte) ----------- */
|
||||||
|
|
||||||
pdu[offset++] = 0x00; /* TP-Message-Reference: filled by device */
|
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);
|
len = mm_sms_part_encode_address (part->number, &pdu[offset], PDU_SIZE - offset, FALSE);
|
||||||
if (len == 0) {
|
if (len == 0) {
|
||||||
g_set_error (error,
|
g_set_error (error,
|
||||||
@@ -784,23 +778,56 @@ mm_sms_part_get_submit_pdu (MMSmsPart *part,
|
|||||||
}
|
}
|
||||||
offset += len;
|
offset += len;
|
||||||
|
|
||||||
/* TP-PID */
|
/* ----------- TP-PID (1 byte) ----------- */
|
||||||
|
|
||||||
pdu[offset++] = 0x00;
|
pdu[offset++] = 0x00;
|
||||||
|
|
||||||
/* TP-DCS */
|
/* ----------- TP-DCS (1 byte) ----------- */
|
||||||
if (best_cs == MM_MODEM_CHARSET_UCS2)
|
|
||||||
pdu[offset++] = 0x08;
|
if (part->encoding == MM_SMS_ENCODING_UCS2) {
|
||||||
else
|
mm_dbg (" using UCS2 encoding...");
|
||||||
pdu[offset++] = 0x00; /* GSM */
|
pdu[offset++] = 0x08;
|
||||||
|
} 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)
|
if (part->validity > 0)
|
||||||
pdu[offset++] = validity_to_relative (part->validity);
|
pdu[offset++] = validity_to_relative (part->validity);
|
||||||
|
|
||||||
/* TP-User-Data-Length */
|
/* ----------- TP-User-Data-Length ----------- */
|
||||||
pdu[offset++] = textlen;
|
/* Set to zero initially, and keep a ptr for easy access later */
|
||||||
|
udl_ptr = &pdu[offset];
|
||||||
|
pdu[offset++] = 0;
|
||||||
|
|
||||||
if (best_cs == MM_MODEM_CHARSET_GSM) {
|
/* 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;
|
guint8 *unpacked, *packed;
|
||||||
guint32 unlen = 0, packlen = 0;
|
guint32 unlen = 0, packlen = 0;
|
||||||
|
|
||||||
@@ -814,7 +841,15 @@ mm_sms_part_get_submit_pdu (MMSmsPart *part,
|
|||||||
goto error;
|
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);
|
g_free (unpacked);
|
||||||
if (!packed || packlen == 0) {
|
if (!packed || packlen == 0) {
|
||||||
g_free (packed);
|
g_free (packed);
|
||||||
@@ -828,11 +863,12 @@ mm_sms_part_get_submit_pdu (MMSmsPart *part,
|
|||||||
memcpy (&pdu[offset], packed, packlen);
|
memcpy (&pdu[offset], packed, packlen);
|
||||||
g_free (packed);
|
g_free (packed);
|
||||||
offset += packlen;
|
offset += packlen;
|
||||||
} else if (best_cs == MM_MODEM_CHARSET_UCS2) {
|
} else if (part->encoding == MM_SMS_ENCODING_UCS2) {
|
||||||
GByteArray *array;
|
GByteArray *array;
|
||||||
|
|
||||||
array = g_byte_array_sized_new (textlen / 2);
|
/* Try to guess a good value for the array */
|
||||||
if (!mm_modem_charset_byte_array_append (array, part->text, FALSE, best_cs)) {
|
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_byte_array_free (array, TRUE);
|
||||||
g_set_error_literal (error,
|
g_set_error_literal (error,
|
||||||
MM_MESSAGE_ERROR,
|
MM_MESSAGE_ERROR,
|
||||||
@@ -841,6 +877,14 @@ mm_sms_part_get_submit_pdu (MMSmsPart *part,
|
|||||||
goto error;
|
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);
|
memcpy (&pdu[offset], array->data, array->len);
|
||||||
offset += array->len;
|
offset += array->len;
|
||||||
g_byte_array_free (array, TRUE);
|
g_byte_array_free (array, TRUE);
|
||||||
|
Reference in New Issue
Block a user