/[projects]/smsdaemon/SmsPdu.cpp
ViewVC logotype

Contents of /smsdaemon/SmsPdu.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 177 - (show annotations) (download)
Fri Dec 12 10:58:11 2008 UTC (15 years, 5 months ago) by torben
File size: 7303 byte(s)
Prevent a potential crash in ParseUdh

1 /* using http://sourceforge.net/projects/libserial/
2 */
3
4
5 #include "SmsPdu.h"
6
7 #include <string>
8 #include <sstream>
9
10 #include <time.h>
11 #include <stdlib.h>
12
13 #include "Logger.h"
14 #include "Util.h"
15
16
17 using namespace std;
18
19 namespace SmsPdu
20 {
21
22
23
24 string SwitchChars(string input)
25 {
26 for (unsigned int i=1; i<input.length(); i+=2)
27 {
28 char tmp = input[i];
29 input[i] = input[i-1];
30 input[i-1] = tmp;
31 }
32 return input;
33 }
34
35 string EncodePhonenr(string input)
36 {
37 if ( input.at(0) == '+' )
38 input.erase(0,1);
39
40 if ( (input.length() % 2) == 1)
41 input.append("F");
42 return SwitchChars(input);
43 }
44
45 string DecodePhonenr(string input)
46 {
47 input = SwitchChars(input);
48 int last = input.length() -1;
49
50 if (input.at(last) == 'F')
51 input.erase(last,1);
52 return input;
53 }
54
55
56
57
58 string HexformatVector(vector<unsigned char> vec)
59 {
60 ostringstream os;
61
62 for (unsigned int i=0; i<vec.size(); ++i)
63 {
64 os.width(2);
65 os.fill('0');
66 os << hex << uppercase << static_cast<unsigned int>(vec.at(i));
67 }
68
69
70 return os.str();
71 }
72
73 vector<unsigned char> HexDecodeString(string str)
74 {
75 vector<unsigned char> vec;
76 for (unsigned int i=0; i<str.length(); i+=2)
77 vec.push_back( strtol( str.substr(i,2).c_str(), 0, 16 ));
78
79 return vec;
80 }
81
82 std::string Decode8to7bit(vector<unsigned char> input, int shift_start)
83 {
84 string result;
85
86 int shift = shift_start;
87 for (unsigned int i=0; i<input.size(); ++i)
88 {
89 unsigned char current = input.at(i);
90 unsigned char prev = (i>0) ? input.at(i-1) : 0;
91
92 current <<= shift;
93
94 prev >>= (8-shift);
95
96 unsigned char byte = current | prev;
97 byte &= 0x7F;
98
99 result.append(1, byte);
100
101 if (shift == 6)
102 result.append(1, input.at(i) >> 1);
103
104 shift = (shift+1) % 7;
105
106 }
107
108 return result;
109 }
110
111
112
113
114 vector<unsigned char> Encode7to8bit(std::string str, int shift_start)
115 {
116 vector<unsigned char> buf;
117
118 int shift = shift_start;
119 for (unsigned int i=0; i<str.size(); ++i)
120 {
121 unsigned char current = str.at(i) & 0x7F;
122 unsigned char next = ( (i+1)<str.size()) ? str.at(i+1) : 0;
123 next &= 0x7F;
124
125 current >>= shift;
126 next <<= (7-shift);
127
128 unsigned char byte = current | next;
129 buf.push_back(byte);
130
131 if (shift == 6)
132 i++;
133
134 shift = (shift+1) % 7;
135
136 }
137
138 return buf;
139 }
140
141 vector<PduInfo> CreateSmsPdu(string to, string message, bool allowMultipart)
142 {
143 bool multipart = allowMultipart && message.length() > 160;
144
145 const unsigned char UDHI = multipart ? 0x40 : 0;
146
147 unsigned char csms_ref = rand() % 128;
148
149 int part_count;
150
151 const int PDU_LEN = 153;
152
153 if (multipart)
154 {
155 if (message.length() > 800)
156 {
157 Logger::logMessage("Trying to send multipart sms > 800 bytes !!!");
158 message = message.substr(0,800);
159 }
160
161 part_count = message.length() / PDU_LEN;
162 if (message.length() % PDU_LEN)
163 part_count++;
164 }
165 else
166 {
167 part_count = 1;
168 }
169
170 vector<PduInfo> result;
171 for (int partnr = 0; partnr < part_count; ++partnr)
172 {
173 vector<unsigned char> pdu;
174
175 pdu.push_back(0x00); // use SMSC from phone
176 pdu.push_back( 0x01|UDHI ); // first octet -- no timeout
177 pdu.push_back(0x00); // TP-MR message reference
178 pdu.push_back(to.length() ); //length of phone nr
179 pdu.push_back(0x81); // type of address (international nr + ISDN/telephone range) - else try 0x81
180
181
182 vector<unsigned char> phone = HexDecodeString( EncodePhonenr(to ));
183 pdu.insert( pdu.end(), phone.begin(), phone.end());
184
185 pdu.push_back(0x00); // Protocol identifier
186 pdu.push_back(0x00); // Data coding scheme
187
188 int shift_start = 0;
189 string message_part;
190 if (multipart)
191 {
192 message_part = message.substr(0, PDU_LEN);
193 message.erase(0, PDU_LEN-1);
194
195 pdu.push_back( message_part.length()+ 7 ); //UserDataLength
196 pdu.push_back( 0x06 ); // UDH Len
197 pdu.push_back( 0x00 ); // UDH Element Identifier
198 pdu.push_back( 0x03 ); // UDH element length
199 pdu.push_back( csms_ref ); // csms_ref reference
200 pdu.push_back( part_count );
201 pdu.push_back( partnr+1 );
202 pdu.push_back( 0x00);
203 //shift_start = 6;
204 }
205 else
206 {
207 if (message.length() > 160)
208 {
209 message_part = message.substr(0,160); //truncate to 160
210 Logger::logMessage("Truncated message");
211 }
212 else
213 {
214 message_part = message;
215 }
216
217 pdu.push_back( message_part.length() ); //UserDataLength
218 }
219
220 vector<unsigned char> userData = Encode7to8bit(message_part, shift_start);
221
222 pdu.insert( pdu.end(), userData.begin(), userData.end());
223
224 PduInfo info;
225 info.len = pdu.size()-1;
226 info.pdu = HexformatVector(pdu);
227 result.push_back(info);
228
229 }
230 return result;
231 }
232
233 typedef vector<unsigned char>::iterator char_it;
234
235 string DecodeRawPhonenr(char_it start, char_it end)
236 {
237 ostringstream os;
238
239 for (char_it it = start; it != end; ++it)
240 {
241 os.width(2);
242 os.fill('0');
243 os << hex << (int)(*it);
244 }
245 return DecodePhonenr(os.str());
246 }
247
248 string DecodeTimestamp(char_it start, char_it end)
249 {
250 string stamp = DecodeRawPhonenr(start,end);
251
252 ostringstream os;
253
254 os << stamp.substr(0,2) << "/"; //year
255 os << stamp.substr(2,2) << "/"; //month
256 os << stamp.substr(4,2) << ","; //day
257 os << stamp.substr(6,2) << ":"; //hour
258 os << stamp.substr(8,2) << ":"; //minute
259 os << stamp.substr(10,2) ; //second
260
261 int timezone = strtol(stamp.substr(12,2).c_str(), 0, 16);
262
263
264 if (timezone > 127)
265 os << "-";
266 else
267 os << "+";
268
269 os.width(2);
270 os.fill('0');
271 os << (timezone & 0x7F);
272
273 return os.str();
274 }
275
276
277
278 SMS ParseSmsPdu(std::string pdu_str)
279 {
280 SmsPart part = ParseSmsPduWorker(pdu_str);
281
282
283 SMS sms;
284 sms.SetMessage(part.message);
285 sms.SetSender(part.sender);
286 return sms;
287 }
288
289 void ParseUdh(vector<unsigned char>& udh, SmsPart& part)
290 {
291 if (udh.size() == 0)
292 {
293 Logger::logMessage("ParseUdh(): empty udh");
294 return;
295 }
296
297 if (udh[0] != 0)
298 {
299 Logger::logMessage("unknown UDH type");
300 return;
301 }
302
303 if (udh.size() < 5)
304 {
305 Logger::logMessage("UDH to short to be multipart");
306 return;
307 }
308
309 part.group = udh[2];
310 part.count = udh[3];
311 part.id = udh[4];
312 }
313
314
315 SmsPart ParseSmsPduWorker(std::string pdu_str)
316 {
317
318 vector<unsigned char> pdu = HexDecodeString(pdu_str);
319
320 vector<unsigned char>::iterator it = pdu.begin();
321
322 it += (*it++); // Skip smsc info
323
324 unsigned char deliver_first_octet = (*it++);
325
326 bool UDHI = (deliver_first_octet & 0x40) > 0;
327
328 unsigned char sender_len = (*it++);
329 if ( (sender_len % 2) == 1)
330 sender_len++;
331
332 ++it; //ignore Type-Of-Address
333
334 string sender = DecodeRawPhonenr( it, it+(sender_len/2) );
335
336 it += (sender_len/2);
337 ++it; //protocol identifier
338 ++it; //Data encoding
339
340 string timestamp = DecodeTimestamp(it, it+7);
341 it += 7;
342
343
344 unsigned char data_len = (*it++);
345
346
347 SmsPart part;
348 part.group = -1;
349
350 int shift_start = 0;
351
352 if (UDHI)
353 {
354 int udh_len = (*it++);
355
356 vector<unsigned char> udh;
357 for (int i=0; i<udh_len; i++)
358 {
359 udh.push_back (*it++);
360 }
361 ParseUdh(udh,part);
362
363 data_len -= udh_len;
364
365 shift_start = udh_len+1; //make the 8to7bit decode start with the right shift level
366 }
367
368
369 vector<unsigned char> user_data;
370 user_data.insert(user_data.end(), it, it+data_len);
371
372 string message = Decode8to7bit(user_data, shift_start).substr(0,data_len);
373
374 message = Util::str_trim(message);
375
376
377 part.message = message;
378 part.sender = sender;
379
380 return part;
381 }
382
383 }

  ViewVC Help
Powered by ViewVC 1.1.20