Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(312)

Side by Side Diff: sms_message.cc

Issue 6612044: Added an SmsMessage class, and code for parsing a PDU to an SMS message. (Closed) Base URL: ssh://git@gitrw.chromium.org:9222/cromo.git@master
Patch Set: Created 9 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « sms_message.h ('k') | sms_message_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "sms_message.h"
6
7 #include <glog/logging.h>
8
9 #include "utilities.h"
10
11 static const uint8_t INTL_E164_NUMBER_FORMAT = 0x91;
12 static const uint8_t SMSC_TIMESTAMP_LEN = 7;
13 static const size_t MIN_PDU_LEN = 7 + SMSC_TIMESTAMP_LEN;
14
15 static char NibbleToChar(uint8_t nibble) {
16 switch (nibble) {
17 case 0: return '0';
18 case 1: return '1';
19 case 2: return '2';
20 case 3: return '3';
21 case 4: return '4';
22 case 5: return '5';
23 case 6: return '6';
24 case 7: return '7';
25 case 8: return '8';
26 case 9: return '9';
27 case 10: return '*';
28 case 11: return '#';
29 case 12: return 'a';
30 case 13: return 'b';
31 case 14: return 'c';
32 case 0xff: return '\0'; // padding nibble
33 }
34 return '\0';
35 }
36
37 // Convert an array of octets into a BCD string. Each octet consists
38 // of two nibbles which are converted to hex characters. Those hex
39 // characters are the digits of the BCD string. The lower nibble is
40 // the more significant digit.
41 static std::string SemiOctetsToBcdString(const uint8_t* octets,
42 int num_octets) {
43 std::string bcd;
44
45 for (int i = 0; i < num_octets; ++i) {
46 char first = NibbleToChar(octets[i] & 0xf);
47 char second = NibbleToChar((octets[i] >> 4) & 0xf);
48
49 if (first != '\0')
50 bcd += first;
51 if (second != '\0')
52 bcd += second;
53 }
54 return bcd;
55 }
56
57 SmsMessage* SmsMessage::CreateMessage(const uint8_t* pdu, size_t pdu_len) {
58 utilities::DumpHex(pdu, pdu_len);
59
60 // Make sure the PDU is of a valid size
61 if (pdu_len < MIN_PDU_LEN) {
62 LOG(INFO) << "PDU too short: " << pdu_len << " vs. " << MIN_PDU_LEN;
63 return NULL;
64 }
65
66 // Format of message:
67 //
68 // 1 octet - length of SMSC information in octets, including type field
69 // 1 octet - type of address of SMSC (value 0x91 is international E.164)
70 // variable - SMSC address
71 // 1 octet - first octet of SMS-DELIVER (value = 0x04)
72 // 1 octet - length of sender address in decimal digits (semi-octets)
73 // 1 octet - type of sender address (value 0x91 is international E.164)
74 // variable - sender address
75 // 1 octet - protocol identifier (value = 0)
76 // 1 octet - data coding scheme (value = 0)
77 // 7 octets - SMSC timestamp
78 // 1 octet - user data length in septets
79 // variable - user data (body of message)
80
81 // Do a bunch of validity tests first so we can bail out early
82 // if we're not able to handle the PDU. We first check the validity
83 // of all length fields and make sure the PDU length is consistent
84 // with those values.
85
86 uint8_t smsc_addr_num_octets = pdu[0];
87 uint8_t variable_length_items = smsc_addr_num_octets;
88
89 if (pdu_len < variable_length_items + MIN_PDU_LEN) {
90 LOG(INFO) << "PDU too short: " << pdu_len << " vs. "
91 << variable_length_items + MIN_PDU_LEN;
92 return NULL;
93 }
94
95 // where in the PDU the actual SMS protocol message begins
96 uint8_t msg_start_offset = 1 + smsc_addr_num_octets;
97 uint8_t sender_addr_num_digits = pdu[msg_start_offset + 1];
98 // round the sender address length up to an even number of semi-octets,
99 // and thus an integral number of octets
100 uint8_t sender_addr_num_octets = (sender_addr_num_digits + 1) >> 1;
101 variable_length_items += sender_addr_num_octets;
102 if (pdu_len < variable_length_items + MIN_PDU_LEN) {
103 LOG(INFO) << "PDU too short: " << pdu_len << " vs. "
104 << variable_length_items + MIN_PDU_LEN;
105 return NULL;
106 }
107
108 uint8_t tp_pid_offset = msg_start_offset + 3 + sender_addr_num_octets;
109 uint8_t user_data_offset = tp_pid_offset + 2 + SMSC_TIMESTAMP_LEN;
110 uint8_t user_data_num_septets = pdu[user_data_offset];
111 variable_length_items += (7 * (user_data_num_septets + 1 )) / 8;
112
113 if (pdu_len < variable_length_items + MIN_PDU_LEN) {
114 LOG(INFO) << "PDU too short: " << pdu_len << " vs. "
115 << variable_length_items + MIN_PDU_LEN;
116 return NULL;
117 }
118
119 // wow do some validity checks on the values of several fields in the PDU
120
121 // smsc number format must be international, E.164
122 if (pdu[1] != INTL_E164_NUMBER_FORMAT) {
123 LOG(INFO) << "Invalid SMSC address format: " << std::hex << (int)pdu[1]
124 << " vs. " << std::hex << INTL_E164_NUMBER_FORMAT;
125 return NULL;
126 }
127 // we only handle SMS-DELIVER messages, with more-messages-to-send false
128 if ((pdu[msg_start_offset] & 0x07) != 0x04) {
129 LOG(INFO) << "Unhandled message type: " << std::hex
130 << (int)pdu[msg_start_offset] << " vs. 0x04";
131 return NULL;
132 }
133 // we only handle the basic protocol identifier
134 if (pdu[tp_pid_offset] != 0) {
135 LOG(INFO) << "Unhandled protocol identifier: " << std::hex
136 << (int)pdu[tp_pid_offset] << " vs. 0x00";
137 return NULL;
138 }
139 // for data coding scheme, we only handle the default alphabet, i.e. GSM7
140 if (pdu[tp_pid_offset+1] != 0) {
141 LOG(INFO) << "Unhandled data coding scheme: " << std::hex
142 << (int)pdu[tp_pid_offset+1] << " vs. 0x00";
143 return NULL;
144 }
145
146 std::string smsc_addr = SemiOctetsToBcdString(&pdu[2],
147 smsc_addr_num_octets-1);
148 std::string sender_addr = SemiOctetsToBcdString(&pdu[msg_start_offset+3],
149 sender_addr_num_octets);
150 std::string sc_timestamp = SemiOctetsToBcdString(&pdu[tp_pid_offset+2],
151 SMSC_TIMESTAMP_LEN-1);
152 std::string msg_text = utilities::Gsm7ToUtf8String(&pdu[user_data_offset]);
153
154 // The last two semi-octets of the timestamp indicate an offset from
155 // GMT, and are handled differently than the first 12 semi-octets.
156 uint8_t toff_octet = pdu[tp_pid_offset+1+SMSC_TIMESTAMP_LEN];
157 sc_timestamp += (toff_octet & 0x8) ? '-' : '+';
158 uint8_t offset_in_hours =
159 ((toff_octet & 0x7) << 4 | (toff_octet & 0xf0) >> 4) / 4;
160 sc_timestamp += (char)((offset_in_hours / 10) + '0');
161 sc_timestamp += (char)((offset_in_hours % 10) + '0');
162
163 return new SmsMessage(smsc_addr, sender_addr, sc_timestamp, msg_text);
164 }
OLDNEW
« no previous file with comments | « sms_message.h ('k') | sms_message_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698