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

Contents of /smsdaemon/SmsPdu.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 73 - (show annotations) (download)
Fri Jun 13 09:09:36 2008 UTC (15 years, 11 months ago) by torben
File size: 6643 byte(s)
Fixed a bug in CreateSmsPdu() so it now uses EncodePhonenr() correctly

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.at(0) == '+' )
40 input.erase(0,1);
41
42 if ( (input.length() % 2) == 1)
43 input.append("F");
44 return SwitchChars(input);
45 }
46
47 string DecodePhonenr(string input)
48 {
49 input = SwitchChars(input);
50 int last = input.length() -1;
51
52 if (input.at(last) == 'F')
53 input.erase(last,1);
54 return input;
55 }
56
57
58
59
60 string HexformatVector(vector<unsigned char> vec)
61 {
62 ostringstream os;
63
64 for (unsigned int i=0; i<vec.size(); ++i)
65 {
66 os.width(2);
67 os.fill('0');
68 os << hex << uppercase << static_cast<unsigned int>(vec.at(i));
69 }
70
71
72 return os.str();
73 }
74
75 vector<unsigned char> HexDecodeString(string str)
76 {
77 vector<unsigned char> vec;
78 for (unsigned int i=0; i<str.length(); i+=2)
79 vec.push_back( strtol( str.substr(i,2).c_str(), 0, 16 ));
80
81 return vec;
82 }
83
84 std::string Decode8to7bit(vector<unsigned char> input, int shift_start)
85 {
86 string result;
87
88 int shift = shift_start;
89 for (unsigned int i=0; i<input.size(); ++i)
90 {
91 unsigned char current = input.at(i);
92 unsigned char prev = (i>0) ? input.at(i-1) : 0;
93
94 current <<= shift;
95
96 prev >>= (8-shift);
97
98 unsigned char byte = current | prev;
99 byte &= 0x7F;
100
101 result.append(1, byte);
102
103 if (shift == 6)
104 result.append(1, input.at(i) >> 1);
105
106 shift = (shift+1) % 7;
107
108 }
109
110 return result;
111 }
112
113
114
115
116 vector<unsigned char> Encode7to8bit(std::string str, int shift_start)
117 {
118 vector<unsigned char> buf;
119
120 int shift = shift_start;
121 for (unsigned int i=0; i<str.size(); ++i)
122 {
123 unsigned char current = str.at(i) & 0x7F;
124 unsigned char next = ( (i+1)<str.size()) ? str.at(i+1) : 0;
125 next &= 0x7F;
126
127 current >>= shift;
128 next <<= (7-shift);
129
130 unsigned char byte = current | next;
131 buf.push_back(byte);
132
133 if (shift == 6)
134 i++;
135
136 shift = (shift+1) % 7;
137
138 }
139
140 return buf;
141 }
142
143 vector<PduInfo> CreateSmsPdu(string to, string message, bool allowMultipart)
144 {
145 bool multipart = allowMultipart && message.length() > 160;
146
147 const unsigned char UDHI = multipart ? 0x40 : 0;
148
149 srand(time(0));
150 unsigned char csms_ref = rand() % 128;
151
152 int part_count;
153
154 const int PDU_LEN = 153;
155
156 if (multipart)
157 {
158 if (message.length() > 800)
159 {
160 Common::instance()->logMessage("Trying to send multipart sms > 800 bytes !!!");
161 message = message.substr(0,800);
162 }
163
164 part_count = message.length() / PDU_LEN;
165 if (message.length() % PDU_LEN)
166 part_count++;
167 }
168 else
169 {
170 part_count = 1;
171 }
172
173 vector<PduInfo> result;
174 for (int partnr = 0; partnr < part_count; ++partnr)
175 {
176 vector<unsigned char> pdu;
177
178 pdu.push_back(0x00); // use SMSC from phone
179 pdu.push_back( 0x01|UDHI ); // first octet -- no timeout
180 pdu.push_back(0x00); // TP-MR message reference
181 pdu.push_back(to.length() ); //length of phone nr
182 pdu.push_back(0x81); // type of address (international nr + ISDN/telephone range) - else try 0x81
183
184
185 vector<unsigned char> phone = HexDecodeString( EncodePhonenr(to ));
186 pdu.insert( pdu.end(), phone.begin(), phone.end());
187
188 pdu.push_back(0x00); // Protocol identifier
189 pdu.push_back(0x00); // Data coding scheme
190
191 int shift_start = 0;
192 string message_part;
193 if (multipart)
194 {
195 message_part = message.substr(0, PDU_LEN);
196 message.erase(0, PDU_LEN);
197
198 pdu.push_back( message_part.length()+ 7 ); //UserDataLength
199 pdu.push_back( 0x06 ); // UDH Len
200 pdu.push_back( 0x00 ); // UDH Element Identifier
201 pdu.push_back( 0x03 ); // UDH element length
202 pdu.push_back( csms_ref ); // csms_ref reference
203 pdu.push_back( part_count );
204 pdu.push_back( partnr+1 );
205 pdu.push_back( 0x00);
206 //shift_start = 6;
207 }
208 else
209 {
210 if (message.length() > 160)
211 {
212 message_part = message.substr(0,160); //truncate to 160
213 Common::instance()->logMessage("Truncated message");
214 }
215 else
216 {
217 message_part = message;
218 }
219
220 pdu.push_back( message_part.length() ); //UserDataLength
221 }
222
223 vector<unsigned char> userData = Encode7to8bit(message_part, shift_start);
224
225 pdu.insert( pdu.end(), userData.begin(), userData.end());
226
227 PduInfo info;
228 info.len = pdu.size()-1;
229 info.pdu = HexformatVector(pdu);
230 result.push_back(info);
231
232 }
233 return result;
234 }
235
236 typedef vector<unsigned char>::iterator char_it;
237
238 string DecodeRawPhonenr(char_it start, char_it end)
239 {
240 ostringstream os;
241
242 for (char_it it = start; it != end; ++it)
243 {
244 os.width(2);
245 os.fill('0');
246 os << hex << (int)(*it);
247 }
248 return DecodePhonenr(os.str());
249 }
250
251 string DecodeTimestamp(char_it start, char_it end)
252 {
253 string stamp = DecodeRawPhonenr(start,end);
254
255 ostringstream os;
256
257 os << stamp.substr(0,2) << "/"; //year
258 os << stamp.substr(2,2) << "/"; //month
259 os << stamp.substr(4,2) << ","; //day
260 os << stamp.substr(6,2) << ":"; //hour
261 os << stamp.substr(8,2) << ":"; //minute
262 os << stamp.substr(10,2) ; //second
263
264 int timezone = strtol(stamp.substr(12,2).c_str(), 0, 16);
265
266
267 if (timezone > 127)
268 os << "-";
269 else
270 os << "+";
271
272 os.width(2);
273 os.fill('0');
274 os << (timezone & 0x7F);
275
276 return os.str();
277 }
278
279
280 SMS ParseSmsPdu(std::string pdu_str)
281 {
282 SMS result;
283
284 vector<unsigned char> pdu = HexDecodeString(pdu_str);
285
286 vector<unsigned char>::iterator it = pdu.begin();
287
288 it += (*it++); // Skip smsc info
289
290 unsigned char deliver_first_octet = (*it++);
291
292 bool UDHI = (deliver_first_octet & 0x40) > 0;
293
294 unsigned char sender_len = (*it++);
295 if ( (sender_len % 2) == 1)
296 sender_len++;
297
298 ++it; //ignore Type-Of-Address
299
300 result.sender = DecodeRawPhonenr( it, it+(sender_len/2) );
301
302 it += (sender_len/2);
303 ++it; //protocol identifier
304 ++it; //Data encoding
305
306 result.timestamp = DecodeTimestamp(it, it+7);
307 it += 7;
308
309
310 unsigned char data_len = (*it++);
311
312 int shift_start = 0;
313 if (UDHI)
314 {
315 int udh_len = (*it++);
316 cout << "UDH_LEN:" << udh_len << endl;
317 it += udh_len; //just ignore the User Data Header
318 data_len -= udh_len;
319
320 shift_start = udh_len+1; //make the 8to7bit decode start with the right shift level
321 }
322 cout << hex<< (int)(*it) << endl;;
323
324
325 vector<unsigned char> user_data;
326 user_data.insert(user_data.end(), it, it+data_len);
327
328 result.message = Decode8to7bit(user_data, shift_start);
329
330
331 return result;
332 }
333
334 }

  ViewVC Help
Powered by ViewVC 1.1.20