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

Contents of /smsdaemon/SmsPdu.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 196 - (show annotations) (download)
Thu Dec 18 06:53:29 2008 UTC (15 years, 4 months ago) by torben
File size: 8213 byte(s)
Make pretty

astyle -t -b -N

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

  ViewVC Help
Powered by ViewVC 1.1.20