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

Contents of /smsdaemon/SmsPdu.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 77 - (show annotations) (download)
Fri Jun 13 21:15:00 2008 UTC (15 years, 11 months ago) by torben
File size: 6562 byte(s)
Fixed a bug in PDU decide wich resultet in appended garbage.

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
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 srand(time(0));
148 unsigned char csms_ref = rand() % 128;
149
150 int part_count;
151
152 const int PDU_LEN = 153;
153
154 if (multipart)
155 {
156 if (message.length() > 800)
157 {
158 Common::instance()->logMessage("Trying to send multipart sms > 800 bytes !!!");
159 message = message.substr(0,800);
160 }
161
162 part_count = message.length() / PDU_LEN;
163 if (message.length() % PDU_LEN)
164 part_count++;
165 }
166 else
167 {
168 part_count = 1;
169 }
170
171 vector<PduInfo> result;
172 for (int partnr = 0; partnr < part_count; ++partnr)
173 {
174 vector<unsigned char> pdu;
175
176 pdu.push_back(0x00); // use SMSC from phone
177 pdu.push_back( 0x01|UDHI ); // first octet -- no timeout
178 pdu.push_back(0x00); // TP-MR message reference
179 pdu.push_back(to.length() ); //length of phone nr
180 pdu.push_back(0x81); // type of address (international nr + ISDN/telephone range) - else try 0x81
181
182
183 vector<unsigned char> phone = HexDecodeString( EncodePhonenr(to ));
184 pdu.insert( pdu.end(), phone.begin(), phone.end());
185
186 pdu.push_back(0x00); // Protocol identifier
187 pdu.push_back(0x00); // Data coding scheme
188
189 int shift_start = 0;
190 string message_part;
191 if (multipart)
192 {
193 message_part = message.substr(0, PDU_LEN);
194 message.erase(0, PDU_LEN);
195
196 pdu.push_back( message_part.length()+ 7 ); //UserDataLength
197 pdu.push_back( 0x06 ); // UDH Len
198 pdu.push_back( 0x00 ); // UDH Element Identifier
199 pdu.push_back( 0x03 ); // UDH element length
200 pdu.push_back( csms_ref ); // csms_ref reference
201 pdu.push_back( part_count );
202 pdu.push_back( partnr+1 );
203 pdu.push_back( 0x00);
204 //shift_start = 6;
205 }
206 else
207 {
208 if (message.length() > 160)
209 {
210 message_part = message.substr(0,160); //truncate to 160
211 Common::instance()->logMessage("Truncated message");
212 }
213 else
214 {
215 message_part = message;
216 }
217
218 pdu.push_back( message_part.length() ); //UserDataLength
219 }
220
221 vector<unsigned char> userData = Encode7to8bit(message_part, shift_start);
222
223 pdu.insert( pdu.end(), userData.begin(), userData.end());
224
225 PduInfo info;
226 info.len = pdu.size()-1;
227 info.pdu = HexformatVector(pdu);
228 result.push_back(info);
229
230 }
231 return result;
232 }
233
234 typedef vector<unsigned char>::iterator char_it;
235
236 string DecodeRawPhonenr(char_it start, char_it end)
237 {
238 ostringstream os;
239
240 for (char_it it = start; it != end; ++it)
241 {
242 os.width(2);
243 os.fill('0');
244 os << hex << (int)(*it);
245 }
246 return DecodePhonenr(os.str());
247 }
248
249 string DecodeTimestamp(char_it start, char_it end)
250 {
251 string stamp = DecodeRawPhonenr(start,end);
252
253 ostringstream os;
254
255 os << stamp.substr(0,2) << "/"; //year
256 os << stamp.substr(2,2) << "/"; //month
257 os << stamp.substr(4,2) << ","; //day
258 os << stamp.substr(6,2) << ":"; //hour
259 os << stamp.substr(8,2) << ":"; //minute
260 os << stamp.substr(10,2) ; //second
261
262 int timezone = strtol(stamp.substr(12,2).c_str(), 0, 16);
263
264
265 if (timezone > 127)
266 os << "-";
267 else
268 os << "+";
269
270 os.width(2);
271 os.fill('0');
272 os << (timezone & 0x7F);
273
274 return os.str();
275 }
276
277
278 SMS ParseSmsPdu(std::string pdu_str)
279 {
280 SMS result;
281
282 vector<unsigned char> pdu = HexDecodeString(pdu_str);
283
284 vector<unsigned char>::iterator it = pdu.begin();
285
286 it += (*it++); // Skip smsc info
287
288 unsigned char deliver_first_octet = (*it++);
289
290 bool UDHI = (deliver_first_octet & 0x40) > 0;
291
292 unsigned char sender_len = (*it++);
293 if ( (sender_len % 2) == 1)
294 sender_len++;
295
296 ++it; //ignore Type-Of-Address
297
298 result.sender = DecodeRawPhonenr( it, it+(sender_len/2) );
299
300 it += (sender_len/2);
301 ++it; //protocol identifier
302 ++it; //Data encoding
303
304 result.timestamp = DecodeTimestamp(it, it+7);
305 it += 7;
306
307
308 unsigned char data_len = (*it++);
309
310 int shift_start = 0;
311 if (UDHI)
312 {
313 int udh_len = (*it++);
314 it += udh_len; //just ignore the User Data Header
315 data_len -= udh_len;
316
317 shift_start = udh_len+1; //make the 8to7bit decode start with the right shift level
318 }
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).substr(0,data_len);
325
326
327 return result;
328 }
329
330 }

  ViewVC Help
Powered by ViewVC 1.1.20