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

Contents of /smsdaemon/SmsPdu.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 70 - (show annotations) (download)
Fri Jun 13 07:56:57 2008 UTC (15 years, 11 months ago) by torben
File size: 6479 byte(s)
Enable correct parsing of concatenated pdu's

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 "common.h"
14 #include "util.h"
15
16 #include <iostream>
17
18 using namespace std;
19
20
21 namespace SmsPdu
22 {
23
24
25
26 string SwitchChars(string input)
27 {
28 for (unsigned int i=1; i<input.length(); i+=2)
29 {
30 char tmp = input[i];
31 input[i] = input[i-1];
32 input[i-1] = tmp;
33 }
34 return input;
35 }
36
37 string EncodePhonenr(string input)
38 {
39 if ( (input.length() % 2) == 1)
40 input.append("F");
41 return SwitchChars(input);
42 }
43
44 string DecodePhonenr(string input)
45 {
46 input = SwitchChars(input);
47 int last = input.length() -1;
48
49 if (input.at(last) == 'F')
50 input.erase(last,1);
51 return input;
52 }
53
54
55
56
57 string HexformatVector(vector<unsigned char> vec)
58 {
59 ostringstream os;
60
61 for (unsigned int i=0; i<vec.size(); ++i)
62 {
63 os.width(2);
64 os.fill('0');
65 os << hex << uppercase << static_cast<unsigned int>(vec.at(i));
66 }
67
68
69 return os.str();
70 }
71
72 vector<unsigned char> HexDecodeString(string str)
73 {
74 vector<unsigned char> vec;
75 for (unsigned int i=0; i<str.length(); i+=2)
76 vec.push_back( strtol( str.substr(i,2).c_str(), 0, 16 ));
77
78 return vec;
79 }
80
81 std::string Decode8to7bit(vector<unsigned char> input, int shift_start = 0)
82 {
83 string result;
84
85 int shift = shift_start;
86 for (unsigned int i=0; i<input.size(); ++i)
87 {
88 unsigned char current = input.at(i);
89 unsigned char prev = (i>0) ? input.at(i-1) : 0;
90
91 current <<= shift;
92
93 prev >>= (8-shift);
94
95 unsigned char byte = current | prev;
96 byte &= 0x7F;
97
98 result.append(1, byte);
99
100 if (shift == 6)
101 result.append(1, input.at(i) >> 1);
102
103 shift = (shift+1) % 7;
104
105 }
106
107 return result;
108 }
109
110
111
112
113 vector<unsigned char> Encode7to8bit(std::string str)
114 {
115 vector<unsigned char> buf;
116
117 int shift = 0;
118 for (unsigned int i=0; i<str.size(); ++i)
119 {
120 unsigned char current = str.at(i) & 0x7F;
121 unsigned char next = ( (i+1)<str.size()) ? str.at(i+1) : 0;
122 next &= 0x7F;
123
124 current >>= shift;
125 next <<= (7-shift);
126
127 unsigned char byte = current | next;
128 buf.push_back(byte);
129
130 if (shift == 6)
131 i++;
132
133 shift = (shift+1) % 7;
134
135 }
136
137 return buf;
138 }
139
140 vector<PduInfo> CreateSmsPdu(string to, string message, bool allowMultipart)
141 {
142 bool multipart = allowMultipart && message.length() > 160;
143
144 const unsigned char UDHI = multipart ? 0x40 : 0;
145
146 srand(time(0));
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 Common::instance()->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 string phone = 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 string message_part;
189 if (multipart)
190 {
191 message_part = message.substr(0, PDU_LEN);
192 message.erase(0, PDU_LEN);
193
194 pdu.push_back( message_part.length()+ 7 ); //UserDataLength
195 pdu.push_back( 0x06 ); // UDH Len
196 pdu.push_back( 0x00 ); // UDH Element Identifier
197 pdu.push_back( 0x03 ); // UDH element length
198 pdu.push_back( csms_ref ); // csms_ref reference
199 pdu.push_back( part_count );
200 pdu.push_back( partnr+1 );
201 pdu.push_back( 0x00);
202
203 }
204 else
205 {
206 if (message.length() > 160)
207 {
208 message_part = message.substr(0,160); //truncate to 160
209 Common::instance()->logMessage("Truncated message");
210 }
211 else
212 {
213 message_part = message;
214 }
215
216 pdu.push_back( message_part.length() ); //UserDataLength
217 }
218
219 vector<unsigned char> userData = Encode7to8bit(message_part);
220
221 pdu.insert( pdu.end(), userData.begin(), userData.end());
222
223 PduInfo info;
224 info.len = pdu.size()-1;
225 info.pdu = HexformatVector(pdu);
226 result.push_back(info);
227
228 }
229 return result;
230 }
231
232 typedef vector<unsigned char>::iterator char_it;
233
234 string DecodeRawPhonenr(char_it start, char_it end)
235 {
236 ostringstream os;
237
238 for (char_it it = start; it != end; ++it)
239 {
240 os.width(2);
241 os.fill('0');
242 os << hex << (int)(*it);
243 }
244 return DecodePhonenr(os.str());
245 }
246
247 string DecodeTimestamp(char_it start, char_it end)
248 {
249 string stamp = DecodeRawPhonenr(start,end);
250
251 ostringstream os;
252
253 os << stamp.substr(0,2) << "/"; //year
254 os << stamp.substr(2,2) << "/"; //month
255 os << stamp.substr(4,2) << ","; //day
256 os << stamp.substr(6,2) << ":"; //hour
257 os << stamp.substr(8,2) << ":"; //minute
258 os << stamp.substr(10,2) ; //second
259
260 int timezone = strtol(stamp.substr(12,2).c_str(), 0, 16);
261
262
263 if (timezone > 127)
264 os << "-";
265 else
266 os << "+";
267
268 os.width(2);
269 os.fill('0');
270 os << (timezone & 0x7F);
271
272 return os.str();
273 }
274
275
276 SMS ParseSmsPdu(std::string pdu_str)
277 {
278 SMS result;
279
280 vector<unsigned char> pdu = HexDecodeString(pdu_str);
281
282 vector<unsigned char>::iterator it = pdu.begin();
283
284 it += (*it++); // Skip smsc info
285
286 unsigned char deliver_first_octet = (*it++);
287
288 bool UDHI = (deliver_first_octet & 0x40) > 0;
289
290 unsigned char sender_len = (*it++);
291 if ( (sender_len % 2) == 1)
292 sender_len++;
293
294 ++it; //ignore Type-Of-Address
295
296 result.sender = DecodeRawPhonenr( it, it+(sender_len/2) );
297
298 it += (sender_len/2);
299 ++it; //protocol identifier
300 ++it; //Data encoding
301
302 result.timestamp = DecodeTimestamp(it, it+7);
303 it += 7;
304
305
306 unsigned char data_len = (*it++);
307
308 int shift_start = 0;
309 if (UDHI)
310 {
311 int udh_len = (*it++);
312 cout << "UDH_LEN:" << udh_len << endl;
313 it += udh_len; //just ignore the User Data Header
314 data_len -= udh_len;
315
316 shift_start = udh_len+1; //make the 8to7bit decode start with the right shift level
317 }
318 cout << hex<< (int)(*it) << endl;;
319
320
321 vector<unsigned char> user_data;
322 user_data.insert(user_data.end(), it, it+data_len);
323
324 result.message = Decode8to7bit(user_data, shift_start);
325
326
327 return result;
328 }
329
330 }

  ViewVC Help
Powered by ViewVC 1.1.20