Index: sms_message.cc |
diff --git a/sms_message.cc b/sms_message.cc |
index 5f4001bcb08500819efb6cada55ceae95971dfb1..b9f7dcba47316f0c4cd35d5b4cde0371de990486 100644 |
--- a/sms_message.cc |
+++ b/sms_message.cc |
@@ -8,9 +8,12 @@ |
#include "utilities.h" |
-static const uint8_t INTL_E164_NUMBER_FORMAT = 0x91; |
-static const uint8_t SMSC_TIMESTAMP_LEN = 7; |
-static const size_t MIN_PDU_LEN = 7 + SMSC_TIMESTAMP_LEN; |
+static const uint8_t kIntlE164NumberFormat = 0x91; |
+static const uint8_t kAlphaFormat = 0xd0; |
+static const uint8_t kDataCodingSchemeGsm7 = 0; |
+static const uint8_t kDataCodingSchemeUcs2 = 8; |
+static const uint8_t kSmscTimestampLen = 7; |
+static const size_t kMinPduLen = 7 + kSmscTimestampLen; |
static char NibbleToChar(uint8_t nibble) { |
switch (nibble) { |
@@ -58,8 +61,8 @@ SmsMessage* SmsMessage::CreateMessage(const uint8_t* pdu, size_t pdu_len) { |
utilities::DumpHex(pdu, pdu_len); |
// Make sure the PDU is of a valid size |
- if (pdu_len < MIN_PDU_LEN) { |
- LOG(INFO) << "PDU too short: " << pdu_len << " vs. " << MIN_PDU_LEN; |
+ if (pdu_len < kMinPduLen) { |
+ LOG(INFO) << "PDU too short: " << pdu_len << " vs. " << kMinPduLen; |
return NULL; |
} |
@@ -73,7 +76,7 @@ SmsMessage* SmsMessage::CreateMessage(const uint8_t* pdu, size_t pdu_len) { |
// 1 octet - type of sender address (value 0x91 is international E.164) |
// variable - sender address |
// 1 octet - protocol identifier (value = 0) |
- // 1 octet - data coding scheme (value = 0) |
+ // 1 octet - data coding scheme (value 0 is GSM7, 8 is UCS2) |
// 7 octets - SMSC timestamp |
// 1 octet - user data length in septets |
// variable - user data (body of message) |
@@ -86,9 +89,9 @@ SmsMessage* SmsMessage::CreateMessage(const uint8_t* pdu, size_t pdu_len) { |
uint8_t smsc_addr_num_octets = pdu[0]; |
uint8_t variable_length_items = smsc_addr_num_octets; |
- if (pdu_len < variable_length_items + MIN_PDU_LEN) { |
+ if (pdu_len < variable_length_items + kMinPduLen) { |
LOG(INFO) << "PDU too short: " << pdu_len << " vs. " |
- << variable_length_items + MIN_PDU_LEN; |
+ << variable_length_items + kMinPduLen; |
return NULL; |
} |
@@ -99,29 +102,29 @@ SmsMessage* SmsMessage::CreateMessage(const uint8_t* pdu, size_t pdu_len) { |
// and thus an integral number of octets |
uint8_t sender_addr_num_octets = (sender_addr_num_digits + 1) >> 1; |
variable_length_items += sender_addr_num_octets; |
- if (pdu_len < variable_length_items + MIN_PDU_LEN) { |
+ if (pdu_len < variable_length_items + kMinPduLen) { |
LOG(INFO) << "PDU too short: " << pdu_len << " vs. " |
- << variable_length_items + MIN_PDU_LEN; |
+ << variable_length_items + kMinPduLen; |
return NULL; |
} |
uint8_t tp_pid_offset = msg_start_offset + 3 + sender_addr_num_octets; |
- uint8_t user_data_offset = tp_pid_offset + 2 + SMSC_TIMESTAMP_LEN; |
+ uint8_t user_data_offset = tp_pid_offset + 2 + kSmscTimestampLen; |
uint8_t user_data_num_septets = pdu[user_data_offset]; |
variable_length_items += (7 * (user_data_num_septets + 1 )) / 8; |
- if (pdu_len < variable_length_items + MIN_PDU_LEN) { |
+ if (pdu_len < variable_length_items + kMinPduLen) { |
LOG(INFO) << "PDU too short: " << pdu_len << " vs. " |
- << variable_length_items + MIN_PDU_LEN; |
+ << variable_length_items + kMinPduLen; |
return NULL; |
} |
- // wow do some validity checks on the values of several fields in the PDU |
+ // now do some validity checks on the values of several fields in the PDU |
// smsc number format must be international, E.164 |
- if (pdu[1] != INTL_E164_NUMBER_FORMAT) { |
+ if (pdu[1] != kIntlE164NumberFormat) { |
LOG(INFO) << "Invalid SMSC address format: " << std::hex << (int)pdu[1] |
- << " vs. " << std::hex << INTL_E164_NUMBER_FORMAT; |
+ << " vs. " << std::hex << kIntlE164NumberFormat; |
return NULL; |
} |
// we only handle SMS-DELIVER messages, with more-messages-to-send false |
@@ -130,6 +133,14 @@ SmsMessage* SmsMessage::CreateMessage(const uint8_t* pdu, size_t pdu_len) { |
<< (int)pdu[msg_start_offset] << " vs. 0x04"; |
return NULL; |
} |
+ // we only handle E164 and ALPHA sender address formats |
+ uint8_t sender_addr_type = pdu[msg_start_offset + 2]; |
+ if (sender_addr_type != kIntlE164NumberFormat && |
+ sender_addr_type != kAlphaFormat) { |
+ LOG(INFO) << "Unhandled sender address format: " << std::hex << |
+ sender_addr_type; |
+ return NULL; |
+ } |
// we only handle the basic protocol identifier |
if (pdu[tp_pid_offset] != 0) { |
LOG(INFO) << "Unhandled protocol identifier: " << std::hex |
@@ -137,23 +148,38 @@ SmsMessage* SmsMessage::CreateMessage(const uint8_t* pdu, size_t pdu_len) { |
return NULL; |
} |
// for data coding scheme, we only handle the default alphabet, i.e. GSM7 |
- if (pdu[tp_pid_offset+1] != 0) { |
+ uint8_t dcs = pdu[tp_pid_offset+1] & 0x0ec; |
+ if (dcs != kDataCodingSchemeGsm7 && dcs != kDataCodingSchemeUcs2) { |
LOG(INFO) << "Unhandled data coding scheme: " << std::hex |
- << (int)pdu[tp_pid_offset+1] << " vs. 0x00"; |
+ << (int)pdu[tp_pid_offset+1]; |
return NULL; |
} |
std::string smsc_addr = SemiOctetsToBcdString(&pdu[2], |
smsc_addr_num_octets-1); |
- std::string sender_addr = SemiOctetsToBcdString(&pdu[msg_start_offset+3], |
- sender_addr_num_octets); |
+ std::string sender_addr; |
+ if (sender_addr_type == kIntlE164NumberFormat) |
+ sender_addr = SemiOctetsToBcdString(&pdu[msg_start_offset+3], |
+ sender_addr_num_octets); |
+ else { |
+ uint8_t *bytes = new uint8_t[sender_addr_num_octets+1]; |
+ bytes[0] = (sender_addr_num_digits * 4) / 7; |
+ memcpy(&bytes[1], &pdu[msg_start_offset+3], sender_addr_num_octets); |
+ sender_addr = utilities::Gsm7ToUtf8String(bytes); |
+ delete [] bytes; |
+ } |
+ |
std::string sc_timestamp = SemiOctetsToBcdString(&pdu[tp_pid_offset+2], |
- SMSC_TIMESTAMP_LEN-1); |
- std::string msg_text = utilities::Gsm7ToUtf8String(&pdu[user_data_offset]); |
+ kSmscTimestampLen-1); |
+ std::string msg_text; |
+ if (dcs == kDataCodingSchemeGsm7) |
+ msg_text = utilities::Gsm7ToUtf8String(&pdu[user_data_offset]); |
+ else |
+ msg_text = utilities::Ucs2ToUtf8String(&pdu[user_data_offset]); |
// The last two semi-octets of the timestamp indicate an offset from |
// GMT, and are handled differently than the first 12 semi-octets. |
- uint8_t toff_octet = pdu[tp_pid_offset+1+SMSC_TIMESTAMP_LEN]; |
+ uint8_t toff_octet = pdu[tp_pid_offset+1+kSmscTimestampLen]; |
sc_timestamp += (toff_octet & 0x8) ? '-' : '+'; |
uint8_t offset_in_hours = |
((toff_octet & 0x7) << 4 | (toff_octet & 0xf0) >> 4) / 4; |