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

Annotation of /smsdaemon/SmsPdu.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 178 - (hide annotations) (download)
Fri Dec 12 12:13:05 2008 UTC (15 years, 5 months ago) by torben
File size: 8232 byte(s)
Completed modemtransceivers multipart concatenate function

1 torben 59 /* using http://sourceforge.net/projects/libserial/
2     */
3    
4    
5 torben 60 #include "SmsPdu.h"
6    
7 torben 59 #include <string>
8     #include <sstream>
9    
10 torben 60 #include <time.h>
11     #include <stdlib.h>
12 torben 59
13 torben 157 #include "Logger.h"
14 torben 158 #include "Util.h"
15 torben 59
16 torben 178 #include "Exceptions.h"
17     #include <list>
18     #include <vector>
19     #include <algorithm>
20 torben 59
21 torben 178
22 torben 59 using namespace std;
23    
24     namespace SmsPdu
25     {
26    
27    
28 torben 68
29 torben 69 string SwitchChars(string input)
30 torben 59 {
31 torben 69 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 torben 59 }
39    
40 torben 69 string EncodePhonenr(string input)
41     {
42 torben 73 if ( input.at(0) == '+' )
43     input.erase(0,1);
44    
45 torben 69 if ( (input.length() % 2) == 1)
46     input.append("F");
47     return SwitchChars(input);
48     }
49 torben 61
50 torben 69 string DecodePhonenr(string input)
51     {
52     input = SwitchChars(input);
53     int last = input.length() -1;
54 torben 68
55 torben 69 if (input.at(last) == 'F')
56     input.erase(last,1);
57     return input;
58     }
59 torben 59
60 torben 68
61    
62    
63 torben 69 string HexformatVector(vector<unsigned char> vec)
64 torben 59 {
65 torben 69 ostringstream os;
66 torben 59
67 torben 69 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 torben 59
74    
75 torben 69 return os.str();
76     }
77 torben 61
78 torben 69 vector<unsigned char> HexDecodeString(string str)
79 torben 68 {
80 torben 69 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 torben 68
84 torben 69 return vec;
85     }
86 torben 68
87 torben 73 std::string Decode8to7bit(vector<unsigned char> input, int shift_start)
88 torben 69 {
89     string result;
90 torben 68
91 torben 70 int shift = shift_start;
92 torben 69 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 torben 68
97 torben 69 current <<= shift;
98 torben 68
99 torben 69 prev >>= (8-shift);
100 torben 68
101 torben 69 unsigned char byte = current | prev;
102     byte &= 0x7F;
103 torben 68
104 torben 69 result.append(1, byte);
105 torben 68
106 torben 69 if (shift == 6)
107     result.append(1, input.at(i) >> 1);
108 torben 61
109 torben 69 shift = (shift+1) % 7;
110 torben 68
111 torben 69 }
112 torben 68
113 torben 69 return result;
114     }
115 torben 68
116 torben 59
117 torben 69
118    
119 torben 73 vector<unsigned char> Encode7to8bit(std::string str, int shift_start)
120 torben 59 {
121 torben 69 vector<unsigned char> buf;
122 torben 59
123 torben 73 int shift = shift_start;
124 torben 69 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 torben 59
130 torben 69 current >>= shift;
131     next <<= (7-shift);
132 torben 59
133 torben 69 unsigned char byte = current | next;
134     buf.push_back(byte);
135 torben 59
136 torben 69 if (shift == 6)
137     i++;
138 torben 59
139 torben 69 shift = (shift+1) % 7;
140    
141     }
142    
143     return buf;
144 torben 59 }
145    
146 torben 69 vector<PduInfo> CreateSmsPdu(string to, string message, bool allowMultipart)
147     {
148     bool multipart = allowMultipart && message.length() > 160;
149 torben 59
150 torben 69 const unsigned char UDHI = multipart ? 0x40 : 0;
151 torben 59
152 torben 69 unsigned char csms_ref = rand() % 128;
153 torben 59
154 torben 69 int part_count;
155 torben 59
156 torben 69 const int PDU_LEN = 153;
157 torben 61
158 torben 69 if (multipart)
159     {
160     if (message.length() > 800)
161     {
162 torben 157 Logger::logMessage("Trying to send multipart sms > 800 bytes !!!");
163 torben 69 message = message.substr(0,800);
164     }
165 torben 61
166 torben 69 part_count = message.length() / PDU_LEN;
167     if (message.length() % PDU_LEN)
168     part_count++;
169     }
170     else
171 torben 65 {
172 torben 69 part_count = 1;
173 torben 65 }
174    
175 torben 69 vector<PduInfo> result;
176     for (int partnr = 0; partnr < part_count; ++partnr)
177     {
178     vector<unsigned char> pdu;
179 torben 59
180 torben 69 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 torben 59
186 torben 73
187     vector<unsigned char> phone = HexDecodeString( EncodePhonenr(to ));
188 torben 69 pdu.insert( pdu.end(), phone.begin(), phone.end());
189 torben 60
190 torben 69 pdu.push_back(0x00); // Protocol identifier
191     pdu.push_back(0x00); // Data coding scheme
192 torben 60
193 torben 73 int shift_start = 0;
194 torben 69 string message_part;
195     if (multipart)
196     {
197     message_part = message.substr(0, PDU_LEN);
198 torben 136 message.erase(0, PDU_LEN-1);
199 torben 60
200 torben 69 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 torben 73 //shift_start = 6;
209 torben 63 }
210     else
211     {
212 torben 69 if (message.length() > 160)
213     {
214     message_part = message.substr(0,160); //truncate to 160
215 torben 157 Logger::logMessage("Truncated message");
216 torben 69 }
217     else
218     {
219     message_part = message;
220     }
221    
222     pdu.push_back( message_part.length() ); //UserDataLength
223 torben 63 }
224 torben 60
225 torben 73 vector<unsigned char> userData = Encode7to8bit(message_part, shift_start);
226 torben 69
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 torben 60 }
235 torben 69 return result;
236     }
237 torben 60
238 torben 69 typedef vector<unsigned char>::iterator char_it;
239 torben 60
240 torben 69 string DecodeRawPhonenr(char_it start, char_it end)
241     {
242     ostringstream os;
243 torben 60
244 torben 69 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 torben 60
253 torben 69 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 torben 60 }
280 torben 59
281 torben 69
282 torben 178 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 torben 176
305 torben 178 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 torben 69 SMS ParseSmsPdu(std::string pdu_str)
329     {
330 torben 176 SmsPart part = ParseSmsPduWorker(pdu_str);
331 torben 69
332 torben 178 return ConcatenateParts(part);
333 torben 176
334     }
335    
336     void ParseUdh(vector<unsigned char>& udh, SmsPart& part)
337     {
338 torben 177 if (udh.size() == 0)
339     {
340 torben 176 Logger::logMessage("ParseUdh(): empty udh");
341     return;
342     }
343    
344 torben 177 if (udh[0] != 0)
345     {
346 torben 176 Logger::logMessage("unknown UDH type");
347     return;
348     }
349 torben 177
350     if (udh.size() < 5)
351     {
352     Logger::logMessage("UDH to short to be multipart");
353     return;
354     }
355 torben 176
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 torben 69 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 torben 70
373     bool UDHI = (deliver_first_octet & 0x40) > 0;
374    
375 torben 69 unsigned char sender_len = (*it++);
376     if ( (sender_len % 2) == 1)
377     sender_len++;
378    
379     ++it; //ignore Type-Of-Address
380    
381 torben 142 string sender = DecodeRawPhonenr( it, it+(sender_len/2) );
382 torben 69
383     it += (sender_len/2);
384     ++it; //protocol identifier
385     ++it; //Data encoding
386    
387 torben 142 string timestamp = DecodeTimestamp(it, it+7);
388 torben 69 it += 7;
389    
390 torben 70
391 torben 69 unsigned char data_len = (*it++);
392    
393 torben 176
394     SmsPart part;
395     part.group = -1;
396    
397 torben 70 int shift_start = 0;
398 torben 176
399 torben 70 if (UDHI)
400     {
401     int udh_len = (*it++);
402 torben 176
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 torben 70 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 torben 69 vector<unsigned char> user_data;
417     user_data.insert(user_data.end(), it, it+data_len);
418    
419 torben 142 string message = Decode8to7bit(user_data, shift_start).substr(0,data_len);
420 torben 78
421 torben 142 message = Util::str_trim(message);
422 torben 176
423 torben 69
424 torben 176 part.message = message;
425     part.sender = sender;
426 torben 69
427 torben 176 return part;
428 torben 69 }
429    
430 torben 59 }

  ViewVC Help
Powered by ViewVC 1.1.20